pax_global_header00006660000000000000000000000064151022323710014506gustar00rootroot0000000000000052 comment=7c03e1f084873cd1b3422c7ff7aec6ee681b3b38 openvdb-13.0.0/000077500000000000000000000000001510223237100132245ustar00rootroot00000000000000openvdb-13.0.0/.github/000077500000000000000000000000001510223237100145645ustar00rootroot00000000000000openvdb-13.0.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001510223237100167475ustar00rootroot00000000000000openvdb-13.0.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000012101510223237100214330ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: bug assignees: '' --- ### Environment **Operating System:** (e.g. Windows 2019, macOS-10.15, Linux CentOS 7.4) **Version / Commit SHA:** (e.g VDB 7.2, SHA: 1a2b3c4d5e...) **Other:** (e.g compiler, C++ standard etc.) ### Describe the bug (A clear and concise description of what the bug is.) ### To Reproduce Steps to reproduce the behavior: 1. Build with '...' 2. Run function '....' 3. See error ### Expected behavior (A clear and concise description of what you expected to happen.) ### Additional context (Add any other context about the problem here.) openvdb-13.0.0/.github/ISSUE_TEMPLATE/build---installation.md000066400000000000000000000011641510223237100232230ustar00rootroot00000000000000--- name: Build / Installation about: Describe a problem with installation title: "[BUILD]" labels: '' assignees: '' --- ### Environment **Operating System:** (e.g. Windows 2019, macOS-10.15, Linux CentOS 7.4) **Version / Commit SHA:** (e.g VDB 7.2, SHA: 1a2b3c4d5e...) **CMake Version:** (e.g. 3.18) **Compiler:** (e.g. gcc 10, msvc 2019) ### Describe the problem (A clear and concise description of the encountered issue.) ### To Reproduce Steps to reproduce the behavior: 1. Checkout repo '...' 2. Run CMake '....' 3. Build with '....' 4. See error ### Additional context (Add any other context about the problem here.) openvdb-13.0.0/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011071510223237100224730ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: "[REQUEST]" labels: enhancement assignees: '' --- ### Is your feature request related to a problem? Please describe. (A clear and concise description of what the problem is) ### Describe the solution you'd like (A clear and concise description of what you want to happen.) ### Describe alternatives you've considered (A clear and concise description of any alternative solutions or features you've considered.) ### Additional context (Add any other context or screenshots about the feature request here.) openvdb-13.0.0/.github/workflows/000077500000000000000000000000001510223237100166215ustar00rootroot00000000000000openvdb-13.0.0/.github/workflows/ax.yml000066400000000000000000000140611510223237100177560ustar00rootroot00000000000000 name: AX on: push: branches: - 'master' - 'feature/**' - 'pr/**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'nanovdb/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' pull_request: branches: - '**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'nanovdb/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' schedule: # run this workflow every day 7am UTC - cron: '0 7 * * *' workflow_dispatch: inputs: type: description: 'The type of CI to run (all, mac, linux, grammar)' required: true default: 'all' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true defaults: run: shell: bash jobs: linux-ax: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'linux' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: > linux-ax:${{ matrix.config.image }}-cxx:${{ matrix.config.cxx }}-${{ matrix.config.build }} container: image: aswf/ci-openvdb:${{ matrix.config.image }} env: CXX: ${{ matrix.config.cxx }} CCACHE_DIR: /tmp/ccache strategy: matrix: # Only test unified builds (core+ax). weekly CI should test standalone config: - { image: '2026', cxx: 'clang++', build: 'Release', cmake: '' } - { image: '2026', cxx: 'g++', build: 'Release', cmake: '' } - { image: '2026', cxx: 'clang++', build: 'Debug', cmake: '' } - { image: '2025-clang19.1', cxx: 'clang++', build: 'Release', cmake: '' } - { image: '2024-clang16.2', cxx: 'clang++', build: 'Release', cmake: '' } # Needed to test LLVM 15.X - { image: '2023-clang15', cxx: 'clang++', build: 'Release', cmake: '-DDISABLE_DEPENDENCY_VERSION_CHECKS=ON' } fail-fast: false steps: - uses: actions/checkout@v3 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 # 2026 images are broken with gtest/glfw installs - name: deps if: contains(matrix.config.image, '2026') run: ./ci/install_gtest.sh latest - name: timestamp id: timestamp run: echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: ccache # don't use ccache for debug builds if: matrix.config.build == 'Release' id: ccache uses: actions/cache@v3 with: path: /tmp/ccache key: linux-ax${{ matrix.config.image }}-${{ matrix.config.cxx }}-${{ steps.timestamp.outputs.timestamp }} restore-keys: linux-ax${{ matrix.config.image }}-${{ matrix.config.cxx }}- - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components='core,python,axcore,axbin,axtest' --cargs=\" ${{ matrix.config.cmake }} -DOPENVDB_AX_TEST_CMD_DOWNLOADS=ON -DUSE_EXPLICIT_INSTANTIATION=OFF \" - name: test run: cd build && ctest -V - name: test_doxygen_examples run: ./ci/extract_test_examples.sh # Keep ccache light by stripping out any caches not accessed in the last day - name: ccache_clean if: matrix.config.build == 'Release' run: ccache --evict-older-than 1d macos-ax: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'mac' runs-on: ${{ matrix.config.runner }} name: macos-cxx:${{ matrix.config.cxx }}-llvm:${{ matrix.config.llvm }}-${{ matrix.config.build }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: - { runner: 'macos-15', cxx: 'clang++', build: 'Release', llvm: '21' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '21' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '20' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '19' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '18' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '17' } - { runner: 'macos-14', cxx: 'clang++', build: 'Release', llvm: '16' } fail-fast: false steps: - uses: actions/checkout@v3 - name: install_deps run: | ./ci/install_macos.sh ${{ matrix.config.llvm }} ./ci/install_tbb_macos.sh - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components="core,python,axcore,axbin,axtest" --cargs=\" -DOPENVDB_AX_TEST_CMD_DOWNLOADS=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install -DLLVM_DIR=/opt/homebrew/opt/llvm@${{ matrix.config.llvm }}/lib/cmake/llvm \" - name: test run: cd build && ctest -V - name: test_doxygen_examples run: ./ci/extract_test_examples.sh gen-grammar: if: | github.event_name == 'workflow_dispatch' && github.event.inputs.type == 'grammar' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} container: image: aswf/ci-openvdb:2025-clang19.1 steps: - uses: actions/checkout@v3 - name: build run: ./ci/build.sh -v --components=axgr --target=openvdb_ax_grammar --cargs=\"-DOPENVDB_AX_GRAMMAR_NO_LINES=ON\" - name: upload grammar uses: actions/upload-artifact@v4 with: name: ax_grammar path: ./build/openvdb_ax/openvdb_ax/openvdb_ax/grammar retention-days: 5 openvdb-13.0.0/.github/workflows/build.yml000066400000000000000000000146561510223237100204570ustar00rootroot00000000000000 name: Build on: push: branches: - 'master' - 'feature/**' - 'pr/**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'openvdb_ax/**' - 'nanovdb/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' pull_request: branches: - '**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'openvdb_ax/**' - 'nanovdb/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' schedule: # run this workflow every day 7am UTC - cron: '0 7 * * *' workflow_dispatch: inputs: type: description: 'The type of CI to run (all, linux, win, mac)' required: true default: 'all' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true defaults: run: shell: bash jobs: linux-vfx: # VFX platform jobs. These are run on the appropriate CentOS images from # the provided ASWF docker containers if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'linux' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: > linux:${{ matrix.config.image }}-abi:${{ matrix.config.abi }}-cxx:${{ matrix.config.cxx }}-type:${{ matrix.config.build }} container: image: aswf/ci-openvdb:${{ matrix.config.image }} env: CXX: ${{ matrix.config.cxx }} CCACHE_DIR: /tmp/ccache strategy: matrix: config: - { cxx: clang++, image: '2026', abi: '13', build: 'Release', cmake: '-DOPENVDB_USE_FUTURE_ABI_13=ON' } - { cxx: g++, image: '2026', abi: '13', build: 'Release', cmake: '-DOPENVDB_USE_FUTURE_ABI_13=ON' } - { cxx: clang++, image: '2026', abi: '13', build: 'Debug', cmake: '-DOPENVDB_USE_FUTURE_ABI_13=ON' } - { cxx: clang++, image: '2025-clang19.1', abi: '12', build: 'Release', cmake: '' } - { cxx: clang++, image: '2024-clang17.2', abi: '11', build: 'Release', cmake: '-DDISABLE_DEPENDENCY_VERSION_CHECKS=ON' } fail-fast: false steps: - uses: actions/checkout@v3 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 # 2026 images are broken with gtest/glfw installs - name: deps if: contains(matrix.config.image, '2026') run: | ./ci/install_gtest.sh latest ./ci/install_glfw.sh latest - name: timestamp id: timestamp run: echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: ccache # don't use ccache for debug builds if: matrix.config.build == 'Release' id: ccache uses: actions/cache@v3 with: path: /tmp/ccache key: linux-vfx${{ matrix.config.image }}-abi${{ matrix.config.abi }}-${{ matrix.config.cxx }}-${{ steps.timestamp.outputs.timestamp }} restore-keys: linux-vfx${{ matrix.config.image }}-abi${{ matrix.config.abi }}-${{ matrix.config.cxx }}- - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components=\"core,python,bin,view,render,test\" --cargs=\" ${{ matrix.config.cmake }} -DOPENVDB_CXX_STRICT=ON -DOPENVDB_ABI_VERSION_NUMBER=${{ matrix.config.abi }} \" - name: test # Skip Debug on commits as they take a while. if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || matrix.config.build == 'Release' run: | cd build && ctest -V cd - && ./ci/test_install.sh # Keep ccache light by stripping out any caches not accessed in the last day - name: ccache_clean if: matrix.config.build == 'Release' run: ccache --evict-older-than 1d windows: # Windows CI. Tests a dynamic build with MD. if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'win' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'windows-2022-8c-32g-300h') || 'windows-latest' }} name: windows env: VCPKG_DEFAULT_TRIPLET: x64-windows strategy: fail-fast: false steps: - uses: actions/checkout@v3 - name: path shell: pwsh run: | # note: system path must be modified in a previous step to it's use echo "$Env:VCPKG_INSTALLATION_ROOT\installed\x64-windows\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "${{github.workspace}}\build\openvdb\openvdb\Release" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: install shell: powershell run: .\ci\install_windows.ps1 - name: install_numpy shell: powershell run: .\ci\install_windows_numpy.ps1 - name: build run: > ./ci/build.sh -v --config='Release' --components='core,bin,view,render,python,test' --cargs=\' -A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF -DMSVC_COMPRESS_PDB=ON -DUSE_EXR=ON -DUSE_PNG=ON -DVCPKG_TARGET_TRIPLET=${VCPKG_DEFAULT_TRIPLET} -DCMAKE_TOOLCHAIN_FILE=\"${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake\" \' - name: size # Print the build directy size (monitor if we're hitting runner limits) run: du -h build - name: test run: cd build && ctest -V -C Release macos: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'mac' runs-on: ${{ matrix.config.image }} name: ${{ matrix.config.image }} env: CXX: clang++ strategy: matrix: config: - { image: macos-14 } - { image: macos-15 } steps: - uses: actions/checkout@v3 - name: install run: | ./ci/install_macos.sh ./ci/install_tbb_macos.sh - name: build run: > ./ci/build.sh -v --build-type=Release --components=\"core,python,bin,view,render,test\" --cargs=\' -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \' - name: test run: cd build && ctest -V openvdb-13.0.0/.github/workflows/docs.yml000066400000000000000000000114151510223237100202760ustar00rootroot00000000000000 name: Docs on: push: branches: - 'master' - 'feature/**' - 'pr/**' paths-ignore: - 'CHANGES' - 'openvdb_maya/**' - 'pendingchanges/**' - '**.md' pull_request: branches: - '**' paths-ignore: - 'CHANGES' - 'openvdb_maya/**' - 'pendingchanges/**' - '**.md' workflow_dispatch: inputs: deploy: description: 'Deploy to openvdb-website (docs/coverage)?' required: true default: 'none' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: doxygen: runs-on: ubuntu-latest env: CXX: g++ container: image: aswf/ci-openvdb:2026 steps: - uses: actions/checkout@v4 - name: install_doxygen run: ./ci/install_doxygen.sh 1_8_11 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 - name: install_latex run: ./ci/install_texlive.sh - name: build run: > ./ci/build.sh -v --build-type=Release --components="core,python,doc" --cargs=\" -DUSE_BLOSC=OFF -DOPENVDB_CORE_STATIC=OFF -DOPENVDB_PYTHON_WRAP_ALL_GRID_TYPES=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON \" - name: pre_deploy # Overwrite global SSH configuration # https://github.com/peaceiris/actions-gh-pages/issues/719 # https://linuxhint.com/ssh-stricthostkeychecking/ run: > echo "Host * StrictHostKeyChecking no UserKnownHostsFile=/dev/null " > /etc/ssh/ssh_config - name: deploy # only deploy documentation on a manual workflow dispatch if: | github.repository_owner == 'AcademySoftwareFoundation' && github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'docs' uses: peaceiris/actions-gh-pages@v3 with: deploy_key: ${{ secrets.PRIVATE_KEY }} publish_dir: /usr/local/share/doc/OpenVDB/html destination_dir: documentation/doxygen external_repository: AcademySoftwareFoundation/openvdb-website publish_branch: master full_commit_message: "Automatic doxygen documentation update - Deployed from: AcademySoftwareFoundation/openvdb ${{ github.sha }} Signed-off-by: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>" ############################################################################# ################################ Coverage ################################### ############################################################################# linux-coverage: if: | github.repository_owner == 'AcademySoftwareFoundation' && github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'coverage' runs-on: ubuntu-latest container: image: aswf/ci-openvdb:2025-clang19.1 env: CXX: g++ steps: - uses: actions/checkout@v3 - name: install_gcovr run: pip install gcovr - name: build run: > ./ci/build.sh -v --build-type=coverage --components="core,axcore,test,axtest" --cargs=\"-DOPENVDB_CORE_STATIC=OFF -DOPENVDB_AX_STATIC=OFF\" - name: test_and_gcov run: | cd build ctest -V make gcov_html cd - - name: zip_large_html # The index.function list is > 100mb. Just zip it and provide it as a # download (could instead use LFS to host but not really worth it). run: | cd build/gcov_html tar -czvf index.functions.html.tar.gz index.functions.html sed -i -e 's/index.functions.html/index.functions.html.tar.gz/g' index.html sed -i -e 's/List of functions/Download function index/g' index.html rm index.functions.html cd - - name: pre_deploy # Overwrite global SSH configuration # https://github.com/peaceiris/actions-gh-pages/issues/719 # https://linuxhint.com/ssh-stricthostkeychecking/ run: > echo "Host * StrictHostKeyChecking no UserKnownHostsFile=/dev/null " > /etc/ssh/ssh_config - name: deploy uses: peaceiris/actions-gh-pages@v3 with: deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} publish_dir: ./build/gcov_html destination_dir: documentation/code_coverage external_repository: AcademySoftwareFoundation/openvdb-website publish_branch: master full_commit_message: "Automatic code coverage update - Deployed from: AcademySoftwareFoundation/openvdb ${{ github.sha }} Signed-off-by: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>" openvdb-13.0.0/.github/workflows/houdini.yml000066400000000000000000000152741510223237100210140ustar00rootroot00000000000000 name: Houdini on: push: branches: - 'master' - 'feature/**' - 'pr/**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'nanovdb/**' - 'openvdb_maya/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' pull_request: branches: - '**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'nanovdb/**' - 'openvdb_maya/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' schedule: # run this workflow every day 7am UTC - cron: '0 7 * * *' workflow_dispatch: # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true defaults: run: shell: bash jobs: checksecret: # Check that valid github secrets have been set. This isn't needed to retrieve # the cache, but ensures that the job doens't start with an empty cache name: Verify Houdini Secrets runs-on: ubuntu-latest outputs: HOUDINI_SECRETS: ${{ steps.check.outputs.HOUDINI_SECRETS }} steps: - id: check env: HOUDINI_CLIENT_ID: ${{ secrets.HOUDINI_CLIENT_ID }} HOUDINI_SECRET_KEY: ${{ secrets.HOUDINI_SECRET_KEY }} run: echo "HOUDINI_SECRETS=${{ env.HOUDINI_CLIENT_ID != '' && env.HOUDINI_SECRET_KEY != '' }}" >> $GITHUB_OUTPUT - name: Skip Next Jobs if: steps.check.outputs.HOUDINI_SECRETS != 'true' run: echo "HOUDINI_CLIENT_ID and HOUDINI_SECRET_KEY GitHub Action Secrets needs to be set to install Houdini builds" linux-vfx-houdini: needs: [checksecret] if: > ${{ needs.checksecret.outputs.HOUDINI_SECRETS == 'true' || github.repository_owner == 'AcademySoftwareFoundation' }} runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: hou:${{ matrix.config.hou_hash }}-vfx:${{ matrix.config.image }}-cxx:${{ matrix.config.cxx }}-build:${{ matrix.config.build }} container: image: aswf/ci-base:${{ matrix.config.image }} env: CXX: ${{ matrix.config.cxx }} CCACHE_DIR: /tmp/ccache strategy: matrix: config: - { cxx: clang++, image: '2026', hou_hash: '21_0', build: 'Release', components: 'core,hou,bin,view,render,python,test,axcore,axbin,axtest' } - { cxx: clang++, image: '2026', hou_hash: '21_0', build: 'Debug', components: 'core,hou,bin,view,render,python,test,axcore,axbin,axtest' } - { cxx: g++, image: '2026', hou_hash: '21_0', build: 'Release', components: 'core,hou,bin,view,render,python,test,axcore,axbin,axtest' } - { cxx: clang++, image: '2024', hou_hash: '20_5', build: 'Release', components: 'core,hou,bin,view,render,python,test,axcore,axbin,axtest' } - { cxx: g++, image: '2024', hou_hash: '20_5', build: 'Release', components: 'core,hou,bin,view,render,python,test,axcore,axbin,axtest' } fail-fast: false steps: - uses: actions/checkout@v3 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 - name: install_gtest run: ./ci/install_gtest.sh latest - name: timestamp id: timestamp run: echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: ccache # don't use ccache for debug builds if: matrix.config.build == 'Release' id: ccache uses: actions/cache@v3 with: path: /tmp/ccache key: linux-vfx-hou${{ matrix.config.hou_hash }}-${{ matrix.config.image }}-${{ matrix.config.cxx }}-${{ steps.timestamp.outputs.timestamp }} restore-keys: linux-vfx-hou${{ matrix.config.hou_hash }}-${{ matrix.config.image }}-${{ matrix.config.cxx }}- - name: fetch_houdini uses: actions/cache/restore@v3 with: path: hou key: dummy-houdini${{ matrix.config.hou_hash }}-${{ steps.timestamp.outputs.timestamp }} restore-keys: vdb-v5-houdini${{ matrix.config.hou_hash }}- - name: validate_houdini run: test -f "hou/hou.tar.gz" # Make sure that the unpacked install is NOT in the root of the OpenVDB checkout # otherwise CMake's install RPATHs wil not work correctly. - name: install_houdini run: | mkdir $HOME/houdini_install cp hou/hou.tar.gz $HOME/houdini_install/hou.tar.gz cd $HOME/houdini_install && tar -xzf hou.tar.gz && cd - - name: build run: | ./ci/build.sh -v \ --build-type="${{ matrix.config.build }}" \ --components="${{ matrix.config.components }}" \ --cargs=\" \ -DHOUDINI_ROOT=$HOME/houdini_install/hou \ -DOPENVDB_BUILD_HOUDINI_ABITESTS=OFF \ -DOPENVDB_HOUDINI_INSTALL_PREFIX=/tmp \ -DDISABLE_CMAKE_SEARCH_PATHS=ON \ -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON \ \" - name: test if: matrix.config.build == 'Release' run: cd build && ctest -V # Keep ccache light by stripping out any caches not accessed in the last day - name: ccache_clean if: matrix.config.build == 'Release' run: ccache --evict-older-than 1d macos-houdini: needs: [checksecret] if: > ${{ needs.checksecret.outputs.HOUDINI_SECRETS == 'true' || github.repository_owner == 'AcademySoftwareFoundation' }} runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: fetch_houdini uses: actions/cache/restore@v3 with: path: hou key: dummy-houdini restore-keys: vdb-v5-houdini-macos- - name: validate_houdini run: test -f "hou/hou.tar.gz" # Make sure that the unpacked install is NOT in the root of the OpenVDB checkout # otherwise CMake's install RPATHs wil not work correctly. - name: install_houdini run: | mkdir $HOME/houdini_install cp hou/hou.tar.gz $HOME/houdini_install/hou.tar.gz cd $HOME/houdini_install && tar -xzf hou.tar.gz && cd - - name: install_deps run: ./ci/install_macos.sh 20 - name: build run: | ./ci/build.sh -v \ --build-type=Release \ --components="core,hou,bin,view,render,test,axcore,axbin" \ --cargs=\" \ -DHOUDINI_ROOT=$HOME/houdini_install/hou \ -DOPENVDB_BUILD_HOUDINI_ABITESTS=OFF \ -DOPENVDB_HOUDINI_INSTALL_PREFIX=/tmp \ -DDISABLE_CMAKE_SEARCH_PATHS=ON \ -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON \ -DUSE_EXPLICIT_INSTANTIATION=OFF \ -DLLVM_DIR=/opt/homebrew/opt/llvm@20/lib/cmake/llvm \ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \ \" - name: test run: cd build && ctest -V openvdb-13.0.0/.github/workflows/nanovdb.yml000066400000000000000000000144631510223237100210030ustar00rootroot00000000000000 name: NanoVDB on: push: branches: - 'master' - 'feature/**' - 'pr/**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'openvdb_ax/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' pull_request: branches: - '**' paths-ignore: - 'CHANGES' - 'CODEOWNERS' - 'doc/**' - 'openvdb_ax/**' - 'openvdb_maya/**' - 'openvdb_houdini/**' - 'fvdb/**' - 'pendingchanges/**' - '**.md' schedule: # run this workflow every day 7am UTC - cron: '0 7 * * *' workflow_dispatch: inputs: type: description: 'The type of CI to run (all, linux, win, mac)' required: true default: 'all' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: linux-nanovdb: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'linux' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: > linux-nanovdb:cxx:${{ matrix.config.cxx }}-${{ matrix.config.build }} container: image: aswf/ci-openvdb:${{ matrix.config.image }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: - { cxx: g++, image: '2024-clang17.2', build: 'Release' } - { cxx: g++, image: '2024-clang17.2', build: 'Debug' } - { cxx: clang++, image: '2024-clang17.2', build: 'Release' } - { cxx: clang++, image: '2024-clang17.2', build: 'Debug' } fail-fast: false steps: - uses: actions/checkout@v3 - name: setup_cuda_12 run: | echo "/usr/local/cuda-12/bin" >> $GITHUB_PATH echo "LD_LIBRARY_PATH=/usr/local/cuda-12/lib64:$LD_LIBRARY_PATH" >> $GITHUB_ENV - name: build # NOTE: CMAKE_POSITION_INDEPENDENT_CODE set to fix default behaviour change in clang 14 # https://github.com/AcademySoftwareFoundation/aswf-docker/issues/228 run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components=core,nano,nanotest,nanoexam,nanobench,nanotool --cargs=\' -DUSE_EXPLICIT_INSTANTIATION=OFF -DNANOVDB_USE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES="80" -DNANOVDB_USE_OPENVDB=ON -DCMAKE_INSTALL_PREFIX=`pwd` -DUSE_BLOSC=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON \' - name: test run: cd build && sudo ctest -V -E ".*cuda.*|.*mgpu.*" windows-nanovdb: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'win' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'windows-2022-8c-32g-300h') || 'windows-latest' }} env: VCPKG_DEFAULT_TRIPLET: 'x64-windows' visual_studio: "Visual Studio 17 2022" cuda: "12.4.0" strategy: fail-fast: false steps: - uses: actions/checkout@v3 - name: path run: | # note: system path must be modified in a previous step to it's use echo "$Env:VCPKG_INSTALLATION_ROOT\installed\x64-windows\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "${{github.workspace}}\build\openvdb\openvdb\Release" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: install_cuda shell: powershell run: .\ci\install_windows_cuda.ps1 - name: install shell: powershell run: .\ci\install_windows.ps1 - name: build # nvcc doesn't set _WIN32 when run in bash so we need to set it manually shell: bash run: > ./ci/build.sh -v --config=Release --components=core,nano,nanotest,nanoexam,nanobench,nanotool --cargs=\' -A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF -DMSVC_COMPRESS_PDB=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DNANOVDB_USE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES="80" -DCMAKE_CUDA_FLAGS="-D_WIN32" -DNANOVDB_USE_OPENVDB=ON -DVCPKG_TARGET_TRIPLET=${VCPKG_DEFAULT_TRIPLET} -DCMAKE_TOOLCHAIN_FILE=\"${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake\" \' - name: test shell: bash run: cd build && ctest -V -E ".*cuda.*|.*mgpu.*" macos-nanovdb: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'mac' runs-on: ${{ matrix.config.runner }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: - { runner: 'macos-14', cxx: 'clang++', build: 'Release' } - { runner: 'macos-14', cxx: 'clang++', build: 'Debug' } fail-fast: false steps: - uses: actions/checkout@v3 - name: install_deps run: | ./ci/install_macos.sh ./ci/install_tbb_macos.sh - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components=core,nano,nanotest,nanoexam,nanobench,nanotool --cargs=\'-DUSE_EXPLICIT_INSTANTIATION=OFF -DNANOVDB_USE_CUDA=OFF -DNANOVDB_USE_OPENVDB=ON -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \' - name: test run: cd build && ctest -V -E ".*cuda.*|.*mgpu.*" nanovdb-lite: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'linux' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} container: image: aswf/ci-openvdb:2024-clang17.2 steps: - uses: actions/checkout@v3 - name: install_gtest run: ./ci/install_gtest.sh latest - name: build_and_test run: | cd nanovdb/nanovdb sudo mkdir .build cd .build sudo cmake -DUSE_EXPLICIT_INSTANTIATION=OFF -DNANOVDB_BUILD_UNITTESTS=ON -DNANOVDB_USE_OPENVDB=OFF -DNANOVDB_USE_CUDA=OFF ../ sudo make -j8 install sudo ctest -V openvdb-13.0.0/.github/workflows/weekly.yml000066400000000000000000000666671510223237100206710ustar00rootroot00000000000000# This workflow runs once a week and tests a variety of configurations, # dependencies and other specific or expensive checkes (sanitizers). # It also contains the Houdini Cache jobs which update the CI cache # with new Houdini releases. name: Weekly on: schedule: # run this workflow Sunday 00:00 UTC - cron: '0 0 * * 0' workflow_dispatch: inputs: type: description: 'The type of CI to run (all, houdini, latest, extra, ax, blosc, abi)' required: true default: 'all' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true defaults: run: shell: bash jobs: ############################################################################# ################################## Houdini ################################## ############################################################################# # Check that valid github secrets have been set for the ability to # download Houdini and cache it. The secrets are used in download_houdini.py checksecret: name: Verify Houdini Secrets runs-on: ubuntu-latest outputs: HOUDINI_SECRETS: ${{ steps.check.outputs.HOUDINI_SECRETS }} steps: - id: check env: HOUDINI_CLIENT_ID: ${{ secrets.HOUDINI_CLIENT_ID }} HOUDINI_SECRET_KEY: ${{ secrets.HOUDINI_SECRET_KEY }} run: echo "HOUDINI_SECRETS=${{ env.HOUDINI_CLIENT_ID != '' && env.HOUDINI_SECRET_KEY != '' }}" >> $GITHUB_OUTPUT - name: Skip Next Jobs if: steps.check.outputs.HOUDINI_SECRETS != 'true' run: echo "HOUDINI_CLIENT_ID and HOUDINI_SECRET_KEY GitHub Action Secrets needs to be set to install Houdini builds" # Explicitly error on the ASWF repo, we expect this secret to always exist - name: Error ASWF if: steps.check.outputs.HOUDINI_SECRETS != 'true' && github.repository_owner == 'AcademySoftwareFoundation' run: exit 1 # download the latest production version of Houdini X, strip out headers, # libraries and binaries required for building OpenVDB and put it into # the GitHub Actions cache linux_houdini: needs: [checksecret] if: | (needs.checksecret.outputs.HOUDINI_SECRETS == 'true') && (github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'houdini') runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: linux-houdini:${{ matrix.config.hou_hash }} env: CXX: clang++ HOUDINI_CLIENT_ID: ${{ secrets.HOUDINI_CLIENT_ID }} HOUDINI_SECRET_KEY: ${{ secrets.HOUDINI_SECRET_KEY }} strategy: matrix: config: - { houdini_version: '21.0', platform: 'linux_x86_64_gcc11.2', hou_hash: '21_0' } - { houdini_version: '20.5', platform: 'linux_x86_64_gcc11.2', hou_hash: '20_5' } fail-fast: false container: image: aswf/ci-base:2024 steps: - uses: actions/checkout@v3 - name: timestamp id: timestamp run: echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: download_houdini run: ./ci/download_houdini.sh ${{ matrix.config.houdini_version }} ${{ matrix.config.platform }} --prod - name: install_houdini run: | mkdir $HOME/houdini_install cp hou/hou.tar.gz $HOME/houdini_install/hou.tar.gz cd $HOME/houdini_install && tar -xzf hou.tar.gz && cd - - name: write_houdini_cache uses: actions/cache/save@v3 with: path: hou key: vdb-v5-houdini${{ matrix.config.hou_hash }}-${{ steps.timestamp.outputs.timestamp }} macos_houdini: needs: [checksecret] if: | (needs.checksecret.outputs.HOUDINI_SECRETS == 'true') && (github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'houdini') # Note that macos-14 (current macos-latest) switches to M1. We could instead test # the arm build here instead of the x86 one. runs-on: macos-latest name: macos-houdini env: HOUDINI_CLIENT_ID: ${{ secrets.HOUDINI_CLIENT_ID }} HOUDINI_SECRET_KEY: ${{ secrets.HOUDINI_SECRET_KEY }} steps: - uses: actions/checkout@v3 - name: timestamp id: timestamp run: echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - name: download_houdini run: ./ci/download_houdini.sh 21.0 macosx_arm64_clang15.0_14 --prod - name: install_houdini run: | mkdir $HOME/houdini_install cp hou/hou.tar.gz $HOME/houdini_install/hou.tar.gz cd $HOME/houdini_install && tar -xzf hou.tar.gz && cd - - name: write_houdini_cache uses: actions/cache/save@v3 with: path: hou key: vdb-v5-houdini-macos-${{ steps.timestamp.outputs.timestamp }} ############################################################################# ########################### Core Library Extras ############################# ############################################################################# # Extra configuration tests for the OpenVDB Core library. These test a # variety of options with newer compilers. linux-extra: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'extra' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: linux-extra:${{ matrix.config.name }} container: image: aswf/ci-openvdb:${{ matrix.config.image }} env: CXX: clang++ strategy: matrix: config: - { name: 'all', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DUSE_BLOSC=ON -DUSE_ZLIB=ON -DUSE_EXR=ON -DUSE_PNG=ON' } - { name: 'lite', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DUSE_BLOSC=OFF -DUSE_ZLIB=OFF -DUSE_EXR=OFF -DUSE_PNG=OFF -DOPENVDB_USE_DELAYED_LOADING=OFF' } - { name: 'half', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DUSE_BLOSC=OFF -DUSE_IMATH_HALF=ON' } - { name: 'sse', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DOPENVDB_SIMD=SSE42' } - { name: 'avx', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DOPENVDB_SIMD=AVX' } - { name: 'pygrid', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DOPENVDB_PYTHON_WRAP_ALL_GRID_TYPES=ON' } - { name: 'asan', image: '2026', build: 'asan', components: 'core,test', cmake: '-DDISABLE_DEPENDENCY_VERSION_CHECKS=ON -DNANOVDB_USE_OPENVDB=ON -DOPENVDB_AX_STATIC=OFF -DOPENVDB_CORE_STATIC=OFF -DUSE_BLOSC=OFF' } # We never called blosc_destroy(), so disable blosc to silence these errors - { name: 'ubsan', image: '2026', build: 'ubsan', components: 'core,test', cmake: '-DDISABLE_DEPENDENCY_VERSION_CHECKS=ON -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" ' } - { name: 'c++20', image: '2026', build: 'Release', components: 'core,test', cmake: '-DCMAKE_CXX_STANDARD=20' } - { name: 'conf', image: '2026', build: 'Release', components: 'core,python,bin,view,render,test', cmake: '-DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON' } fail-fast: false steps: - uses: actions/checkout@v3 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 # 2026 images are broken with gtest/glfw/exr installs - name: deps if: contains(matrix.config.image, '2026') run: | ./ci/install_gtest.sh latest ./ci/install_glfw.sh latest ./ci/install_imath.sh v3.2.2 ./ci/install_exr.sh v3.2.2 - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components="${{ matrix.config.components }}" --cargs=\"-DOPENVDB_CXX_STRICT=ON ${{ matrix.config.cmake }}\" - name: test run: cd build && ctest -V # Test latest dependencies, latest compilers and options latest: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'latest' runs-on: ${{ matrix.config.runson }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: # llvm-17 is currently the default which has symbol issues with the python module - { runson: ubuntu-latest, cxx: g++, cmake: '-DOPENVDB_PYTHON_USE_AX=OFF' } # Disable the clang job for now. See https://github.com/actions/runner-images/issues/8659 # - { runson: ubuntu-latest, cxx: clang++, cmake: '' } # @todo gcc on macos - { runson: macos-latest, cxx: '', cmake: '-DLLVM_DIR=/opt/homebrew/opt/llvm@20/lib/cmake/llvm' } fail-fast: false steps: - uses: actions/checkout@v3 - name: install_deps run: | if [ "$RUNNER_OS" == "Linux" ]; then sudo apt-get -q install -y libboost-dev libboost-iostreams-dev libtbb-dev libblosc-dev libgtest-dev libgmock-dev python3-numpy ./ci/install_nanobind.sh 2.5.0 elif [ "$RUNNER_OS" == "macOS" ]; then ./ci/install_macos.sh 20 ./ci/install_tbb_macos.sh else echo "$RUNNER_OS not supported"; exit 1 fi - name: build run: > ./ci/build.sh -v --build-type=Release --components=\"core,axcore,python,bin,render,test,axbin\" --cargs=\' -DCMAKE_CXX_STANDARD=20 -DOPENVDB_USE_DELAYED_LOADING=OFF -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install ${{ matrix.config.cmake }} \' - name: test run: cd build && ctest -V windows: # Windows CI. Tests static and dynamic builds with MT and MD respectively. if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'win' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'windows-2022-8c-32g-300h') || 'windows-latest' }} name: windows-vc:${{ matrix.config.vc }}-type:${{ matrix.config.build }} env: VCPKG_DEFAULT_TRIPLET: ${{ matrix.config.vc }} strategy: matrix: config: # static build of blosc from vcpkg does not build internal sources. # USE_STATIC_DEPENDENCIES is required for IlmBase/OpenEXR defines and # Boost as both shared and static libs are installed. # USE_EXPLICIT_INSTANTIATION is disabled for debug static libraries # due to disk space constraints - { vc: 'x64-windows-static', components: 'core,bin,view,render,test', build: 'Release', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON' } - { vc: 'x64-windows', components: 'core,bin,view,render,python,test', build: 'Release', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF' } - { vc: 'x64-windows', components: 'core,bin,view,render,python,test', build: 'Debug', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF' } fail-fast: false steps: - uses: actions/checkout@v3 - name: path shell: pwsh run: | # note: system path must be modified in a previous step to it's use echo "$Env:VCPKG_INSTALLATION_ROOT\installed\${{ matrix.config.vc }}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "${{github.workspace}}\build\openvdb\openvdb\${{ matrix.config.build }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: install shell: powershell run: .\ci\install_windows.ps1 - name: install_numpy if: matrix.config.vc == 'x64-windows' shell: powershell run: .\ci\install_windows_numpy.ps1 - name: build run: > ./ci/build.sh -v --config=${{ matrix.config.build }} --components=${{ matrix.config.components }} --cargs=\' ${{ matrix.config.cmake }} -DMSVC_COMPRESS_PDB=ON -DUSE_EXR=ON -DUSE_PNG=ON -DVCPKG_TARGET_TRIPLET=${VCPKG_DEFAULT_TRIPLET} -DCMAKE_TOOLCHAIN_FILE=\"${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake\" \' - name: size # Print the build directy size (monitor if we're hitting runner limits) run: du -h build - name: test # Always run tests on weekly builds but skip Debug on commits as they take a while. # https://github.community/t/distinct-job-for-each-schedule/17811/2 if: contains(github.event.schedule, '0 7 * * 1') || matrix.config.build == 'Release' run: cd build && ctest -V -C ${{ matrix.config.build }} ############################################################################# ############################ AX Library Extras ############################## ############################################################################# linux-ax: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'ax' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: > linux-ax:${{ matrix.config.image }}-cxx:${{ matrix.config.cxx }}-${{ matrix.config.build }} container: image: aswf/ci-openvdb:${{ matrix.config.image }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: - { image: '2025-clang18.1', cxx: 'clang++', build: 'Release', components: 'core,axcore,axbin,axtest', cmake: '' } # @note LLVM 17 builds are incompatible with the vdb python plugin on linux - { image: '2024-clang17.2', cxx: 'clang++', build: 'Release', components: 'core,axcore,axbin,axtest', cmake: '-DOPENVDB_PYTHON_USE_AX=OFF' } fail-fast: false steps: - uses: actions/checkout@v3 - name: nanobind run: ./ci/install_nanobind.sh 2.5.0 - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components=${{ matrix.config.components }} --cargs=\" ${{ matrix.config.cmake }} -DOPENVDB_AX_TEST_CMD_DOWNLOADS=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DOPENVDB_CXX_STRICT=ON -DOPENVDB_BUILD_VDB_TOOL=OFF \" - name: clean if: matrix.config.components == 'core' run: rm -rf build - name: build if: matrix.config.components == 'core' run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components="bin,axcore,axbin,axtest,python" --cargs=\" ${{ matrix.config.cmake }} -DOPENVDB_AX_TEST_CMD_DOWNLOADS=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DOPENVDB_CXX_STRICT=ON -DOPENVDB_BUILD_VDB_TOOL=OFF \" - name: test run: cd build && ctest -V - name: test_doxygen_examples run: ./ci/extract_test_examples.sh macos-ax: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'ax' runs-on: ${{ matrix.config.runner }} name: macos-cxx:${{ matrix.config.cxx }}-llvm:${{ matrix.config.llvm }}-${{ matrix.config.build }} env: CXX: ${{ matrix.config.cxx }} strategy: matrix: config: - { runner: 'macos-latest', cxx: 'clang++', build: 'Release', llvm: '20' } fail-fast: false steps: - uses: actions/checkout@v3 - name: install_deps run: | ./ci/install_macos.sh ${{ matrix.config.llvm }} ./ci/install_tbb_macos.sh - name: build run: > ./ci/build.sh -v --build-type=${{ matrix.config.build }} --components="core,python,bin,axcore,axbin,axtest" --cargs=\" -DOPENVDB_AX_TEST_CMD_DOWNLOADS=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install -DLLVM_DIR=/opt/homebrew/opt/llvm@${{ matrix.config.llvm }}/lib/cmake/llvm \" - name: test run: cd build && ctest -V - name: test_doxygen_examples run: ./ci/extract_test_examples.sh windows-ax: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'ax' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'windows-2022-8c-32g-300h') || 'windows-latest' }} name: ${{ matrix.config.vc }}-${{ matrix.config.crt }}-${{ matrix.config.build }}-llvm${{ matrix.config.llvm }} env: VCPKG_DEFAULT_TRIPLET: ${{ matrix.config.vc }} # Export this with '' avoid bash treating \ as escape VDB_INSTALL_PREFIX: '${{ github.workspace }}\\install' strategy: matrix: config: # static build of blosc from vcpkg does not build internal sources. # USE_STATIC_DEPENDENCIES is required for IlmBase/OpenEXR defines and # Boost as both shared and static libs are installed. # @todo We don't currently run the axtests with shared builds of ax # due to symbol issues using LLVM as a static lib (which is the only # option on Windows). # @note currently only test static builds with MT as building LLVM as # a shared lib on windows is a bit dicey - { vc: 'x64-windows-static', llvm: '18.1.0', crt: 'MultiThreaded', components: 'core,axcore,axbin,axtest', build: 'Release', cmake: '-DOPENVDB_CORE_SHARED=OFF -DOPENVDB_AX_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON' } - { vc: 'x64-windows-static', llvm: '18.1.0', crt: 'MultiThreadedDebug', components: 'core,axcore,axbin,axtest', build: 'Debug', cmake: '-DOPENVDB_CORE_SHARED=OFF -DOPENVDB_AX_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON' } - { vc: 'x64-windows', llvm: '18.1.0', crt: 'MultiThreadedDLL', components: 'core,axcore,axbin', build: 'Release', cmake: '-DOPENVDB_CORE_STATIC=OFF -DOPENVDB_AX_STATIC=OFF' } - { vc: 'x64-windows-static', llvm: '15.0.0', crt: 'MultiThreaded', components: 'core,axcore,axbin,axtest', build: 'Release', cmake: '-DOPENVDB_CORE_SHARED=OFF -DOPENVDB_AX_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON' } fail-fast: false steps: - uses: actions/checkout@v3 - name: llvm run: ./ci/install_llvm_windows.sh ${{ matrix.config.llvm }} ${{ matrix.config.crt }} - name: install shell: powershell run: | vcpkg update vcpkg install tbb gtest - name: build run: > ./ci/build.sh -v --config=${{ matrix.config.build }} --components="${{ matrix.config.components }}" --cargs=\' -A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_USE_DELAYED_LOADING=OFF -DUSE_BLOSC=OFF \ -DUSE_ZLIB=OFF \ -DVCPKG_TARGET_TRIPLET=${VCPKG_DEFAULT_TRIPLET} -DCMAKE_TOOLCHAIN_FILE=\"${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake\" -DMSVC_COMPRESS_PDB=ON -DOPENVDB_AX_TEST_CMD_DOWNLOADS=OFF -DUSE_EXPLICIT_INSTANTIATION=OFF -DLLVM_DIR=\"${HOME}\\llvm_install\\lib\\cmake\\llvm\" -DCMAKE_INSTALL_PREFIX=\"${VDB_INSTALL_PREFIX}\" ${{ matrix.config.cmake }} \' - name: runtime_path shell: pwsh run: | # note: system path must be modified in a previous step to it's use echo "$Env:VCPKG_INSTALLATION_ROOT\installed\${{ matrix.config.vc }}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "$Env:VDB_INSTALL_PREFIX\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: test run: cd build && ctest -V -C ${{ matrix.config.build }} ############################################################################# ################################## Blosc #################################### ############################################################################# windows-nanovdb: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'win' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'windows-2022-8c-32g-300h') || 'windows-latest' }} env: VCPKG_DEFAULT_TRIPLET: ${{ matrix.config.vc }} visual_studio: "Visual Studio 17 2022" cuda: "12.4.0" strategy: matrix: config: # static build of blosc from vcpkg does not build internal sources. # USE_STATIC_DEPENDENCIES is required for IlmBase/OpenEXR defines and # Boost as both shared and static libs are installed. - { vc: 'x64-windows-static', build: 'Release', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' } - { vc: 'x64-windows-static', build: 'Debug', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_SHARED=OFF -DUSE_STATIC_DEPENDENCIES=ON -DBLOSC_USE_EXTERNAL_SOURCES=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug' } - { vc: 'x64-windows', build: 'Release', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF' } - { vc: 'x64-windows', build: 'Debug', cmake: '-A x64 -G \"Visual Studio 17 2022\" -DOPENVDB_CORE_STATIC=OFF' } fail-fast: false steps: - uses: actions/checkout@v3 - name: path shell: powershell run: | # note: system path must be modified in a previous step to it's use echo "$Env:VCPKG_INSTALLATION_ROOT\installed\${{ matrix.config.vc }}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "${{github.workspace}}\build\openvdb\openvdb\${{ matrix.config.build }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: install_cuda shell: powershell run: .\ci\install_windows_cuda.ps1 - name: install shell: powershell run: .\ci\install_windows.ps1 - name: build shell: bash run: > ./ci/build.sh -v --config=${{ matrix.config.build }} --components=core,nano,nanotest,nanoexam,nanobench,nanotool --cargs=\' ${{ matrix.config.cmake }} -DMSVC_COMPRESS_PDB=ON -DUSE_EXPLICIT_INSTANTIATION=OFF -DNANOVDB_USE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES="80" -DNANOVDB_USE_OPENVDB=ON -DVCPKG_TARGET_TRIPLET=${VCPKG_DEFAULT_TRIPLET} -DCMAKE_TOOLCHAIN_FILE=\"${VCPKG_INSTALLATION_ROOT}\\scripts\\buildsystems\\vcpkg.cmake\" \' - name: test shell: bash run: cd build && ctest -V -E ".*cuda.*|.*mgpu.*" ############################################################################# ################################## Blosc #################################### ############################################################################# linux-blosc: if: | github.event_name != 'workflow_dispatch' || github.event.inputs.type == 'all' || github.event.inputs.type == 'blosc' runs-on: ${{ (github.repository_owner == 'AcademySoftwareFoundation' && 'ubuntu-22.04-8c-32g-300h') || 'ubuntu-latest' }} name: linux-blosc:${{ matrix.blosc }} container: image: aswf/ci-openvdb:2025-clang19.1 strategy: matrix: blosc: ['1.21.0', 'latest'] fail-fast: false steps: - uses: actions/checkout@v3 - name: install_blosc run: sudo ./ci/install_blosc.sh ${{ matrix.blosc }} - name: build run: > sudo ./ci/build.sh -v --build-type=Release --components=\"core,test\" - name: test run: cd build && sudo ctest -V ############################################################################# ################################## ABI ###################################### ############################################################################# linux-abi-checker: if: | github.event_name == 'workflow_dispatch' && (github.event.inputs.type == 'all' || github.event.inputs.type == 'abi') runs-on: ubuntu-22.04 env: # The 'abicheck' build type sets these, but older versions of the library # may not have this build type. See OpenVDBCXX.cmake CXXFLAGS: "-gdwarf-4 -g3 -ggdb -Og" steps: - name: Enable Node 16 run: | echo "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true" >> $GITHUB_ENV - uses: actions/checkout@v3 with: fetch-depth: 0 fetch-tags: true # Compute the latest major version - that is used as our baseline # note: For CI forks, make sure you have your tags synced - name: get_major_version run: | LATEST_VERSION_TAG=$(git tag --merged | sort --version-sort | tail -n1) echo "Computed latest VDB tag: ${LATEST_VERSION_TAG}" VDB_MAJOR_VERSION=$(echo ${LATEST_VERSION_TAG} | cut -f1 -d '.' | tr -d -c 0-9) echo "Using major version: ${VDB_MAJOR_VERSION}" echo "VDB_MAJOR_VERSION=${VDB_MAJOR_VERSION}" >> "$GITHUB_ENV" - name: install_deps run: sudo apt-get -q install -y libboost-iostreams-dev libtbb-dev libblosc-dev elfutils - name: install_abi_checker run: sudo apt-get -q install -y abi-dumper abi-compliance-checker - name: build_new run: > ./ci/build.sh -v --build-dir=build_new --build-type=abicheck --target=openvdb_shared --components=\"core\" --cargs=\'-DUSE_EXPLICIT_INSTANTIATION=OFF -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON\' - name: checkout_baseline run: git checkout v${VDB_MAJOR_VERSION}.0.0 - name: build_old run: > ./ci/build.sh -v --build-dir=build_old --build-type=abicheck --target=openvdb_shared --components=\"core\" --cargs=\'-DUSE_EXPLICIT_INSTANTIATION=OFF -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON\' - name: abi_dump run: | abi-dumper build_new/openvdb/openvdb/libopenvdb.so -o ABI-NEW.dump -lver 1 abi-dumper build_old/openvdb/openvdb/libopenvdb.so -o ABI-OLD.dump -lver 2 # Replace the version namespace in the latest ABI dump with the baseline # version we're comparing against. We should probably instead build the # latest with the baseline version number but no CMake/defines allow us to # do this. - name: replace_symbols run: sed -i -E 's/openvdb([^v]*)v[0-9]*_[0-9]/openvdb\1v'${VDB_MAJOR_VERSION}'_0/g' ABI-NEW.dump - name: abi_check # -strict treats warnings as errors # -extended checks all member data # we check everything _not_ in openvdb::**::internal namespace run: > abi-compliance-checker -l OPENVDB -old ABI-OLD.dump -new ABI-NEW.dump -skip-internal-symbols "\d(openvdb.*internal)" -skip-internal-types "(openvdb.*internal)::" -strict -extended - name: upload_report uses: actions/upload-artifact@v4 if: always() with: name: abi_report path: ./compat_reports/OPENVDB/2_to_1/compat_report.html retention-days: 5 openvdb-13.0.0/.github/workflows/whitespace.yml000066400000000000000000000022551510223237100215040ustar00rootroot00000000000000 name: Whitespace on: push: paths-ignore: - 'pendingchanges/**' - 'tsc/meetings/**' pull_request: paths-ignore: - 'pendingchanges/**' - 'tsc/meetings/**' # Allow subsequent pushes to the same PR or REF to cancel any previous jobs. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: # Search the git repository for any trailing spaces excluding meeting notes and auto-generated wlt files trailingspaces: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: test run: | set +e git grep -n -I -E '^.+[ ]+$' -- ':!tsc/meetings/*' ':!pendingchanges/*' ':!*.wlt' test $? -eq 1 # Search for any tabs excluding meeting notes, image files and a few others spacesnottabs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: test run: | set +e git grep -n " " -- ':!*/whitespace.yml' ':!tsc/meetings/*' ':!*.svg' ':!*.cmd' ':!*.png' ':!pendingchanges/*' ':!*.wlt' ':!*.jpg' ':!*.gif' ':!*.mp4' ':!*.pt' ':!*.pth' ':!*.nvdb' ':!*.npz' test $? -eq 1 openvdb-13.0.0/.gitignore000066400000000000000000000000231510223237100152070ustar00rootroot00000000000000/build/* .DS_Store openvdb-13.0.0/CHANGES000066400000000000000000006301251510223237100142260ustar00rootroot00000000000000OpenVDB Version History ======================= Version 13.0.0 - November 3, 2025 This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 11 for Houdini 20.5 and 12 for Houdini 21.0. Support for reading .vdb files written prior to VDB 1.0 has been removed. To read older .vdb files, please use VDB 12.x or older and re-write them, so that they use the newer file format and can be read in VDB 13+. Highlights: - OpenVDB now includes in-memory support for Half Grids and the file format has been extended to add I/O serialization for half grids. More work is planned on adapting algorithms when using Half Grids for better performance and improved precision. - NanoVDB is no longer limited to static applications, such as rendering, but can increasingly be applied to problems that involve dynamic topology, such as level set tracking, grid building, morphology operations and merging of grids. This is due to the fact that we keep adding more and more tools to NanoVDB that facilitates tree modification. However, unlike OpenVDB, these operations generate new NanoVDB grids (as oppose to in-palace modifications in OpenVDB), yet are typically much faster since they are performed on the GPU. Many of these exciting new features are the foundation of fVDB. OpenVDB: New features: - Added native registration of HalfGrid type. - Added customization of the output transformation attribute for points::pca(). Can be output as a quaternion or as a combined affine transform with the scale/stretch ommitted. - Added support for input quaternions attributes and affine transformations (that include scale) in points::rasterizeSdf() for ellipsoidal rasterizations. API Changes: - Added LeafBuffer::storage() for direct const access to the raw data buffer when using the bool LeafNode. - Removed Grid::evalMinMax(), use tools::minMax for superior threaded performance. - Removed points::rasterize() that took a custom filter and interrupter. - Removed LeafNode() TopologyCopy constructor in favor of using explicit mask/buffer constructors. - Removed ValueAccessor NodeT0, NodeT1, NodeT2 aliases, use NodeTypeAtLevel instead. - Add InternalNode::setValueMaskUnsafe() to write a value mask directly. - LegacyFrustum and RootNodeMask have been removed. These classes were only used for reading old .vdb files, which is no longer supported. - io::writeCompressedValues() now takes a const ValueT* source buffer for improved const-correctness. Bug Fixes: - Fix a bug in the LevelSetRayIntersector class where two of the methods were incorrectly adjusting the time even when an intersection was not found. - Fixed an assertion in math::Quat where a vector length check was using too small a tolerance. - Fixed a bug in the unit tests where detecting if assertions were enabled was using NDEBUG rather than OpenVDB assertions. Build: - Removed the unnecessary USE_NUMPY build option for the OpenVDB Python module. All functions which take numpy arrays are now always generated (numpy is not required at compile time for this support). - Bumped minimum supported CMake version to 3.24, and new future minimum to 4.0.0. - Bumped minimum supported OpenEXR and Imath versions to 3.2, and new future minimum to 3.3. - Bumped minimum supported Boost version to 1.82, and new future minimum to 1.85. - Bumped minimum supported Python version to 3.11 - Bumped minimum supported Log4cplus version to 2.0 - Bumped minimum supported Houdini version to 20.5 - Bumped minimum supported GLFW version to 3.3 - Bumped future minimum for TBB to 2021 (oneapi). - Bumped future minimum for nanobind to 2.5.0. OpenVDB AX: New: - Added support for LLVM 21. NanoVDB: Highlights: - NanoVDB is no longer limited to static applications, such as rendering, but can increasingly be applied to problems that involve dynamic topology, such as level set tracking, grid building, morphology operations and merging of grids. This is due to the fact that we keep adding more and more tools to NanoVDB that facilitates tree modification. However, unlike OpenVDB, these operations generate new NanoVDB grids (as oppose to in-palace modifications in OpenVDB), yet are typically much faster since they are performed on the GPU. Many of these exciting new features are the foundation of fVDB. New features: - Added nanovdb/tools/cuda/DilateGrid.cuh, which performs topology dilation on the GPU. - Added nanovdb/tools/cuda/MergeGrids.cuh, which merges the topology of two grids on the GPU. - Added nanovdb/tools/cuda/CoarsenGrid.cuh, which performs topological coarsening of grids on the GPU. - Added nanovdb/tools/cuda/RefineGrid.cuh, which performs topological refinement of grids on the GPU. - Added nanovdb/tools/cuda/PruneGrid.cuh, which prunes the topology of a grid using a sidecar mask on the GPU. - Added nanovdb/util/cuda/Injection.cuh, which facilitates sidecar data copying - on the GPU - in the overlap of two grids with different topology. - Added Mat classes and other math types to NanoVDB. - Major rewrite of nanovdb::NanoToOpenVDB, which now allows nanovdb::IndexGrids and blind (or sidecar) data to be converted into an openvdb grid. - Added support for LevelSet, FogVolume, and Staggered grid semantics. Added toGridClass and toSemantic to map Grid Blind data semantic to Grid class and vice versa. Improvements: - Improvements to mGPU grid building and introduction of a separate test executable for mGPU tests - Added stand-alone function nanovdb::writeUncompressedGrid that allows nanovdb::IndexGrids and blind (or sidecar) data to be written directly to a stream. - nanovdb_print now (optionally) prints the blind data count per grid. - Extended nanovdb::GridBlindDataSemantic with nanovdb::GridClass types to support conversion between IndexGrid and regular grids. - Improvements and bugfixes to PNanoVDB. API Changes: - Removed nanovdb::ValueIndexMask and nanovdb::ValueOnIndexMask since they are no longer used by fVDB (or elsewhere). - NanoVDB version is now 32.9.0, so the ABI of the grid is preserved but not the API. However, the API changes are very minor! Bug Fixes: - Several fixes for compiler warnings. - Fixed error in nanovdb/io/IO.h related to missing throws. Houdini: - Remove support for openvdb_houdini::Interrupter, use openvdb_houdini::HoudiniInterrupter instead. - Remove input-stealing via duplicateSourceStealable(), SideFX have since introduced verbification and compiled SOPs to provide zero-copy node evaluation. Version 12.1.1 - September 30, 2025 OpenVDB AX: Fixes: - Fixed an issue which was causing host specific optimization passes to be omitted when using LLVM 16 and higher. Houdini: - Fixed a compilation issue with the OpenVDB Activate SOP with Houdini 21 [Reported by @callen128] Version 12.1.0 - August 8, 2025 OpenVDB: New features: - New level set constructor tools::createLevelSetCapsule creates a grid containing a narrow-band level set representation of a capsule (tube with constant radius and sphere caps). - New level set constructor tools::createLevelSetTaperedCapsule creates a grid containing a narrow-band level set representation of a tapered capsule (tube with sphere caps and different radii at both ends, or equivalently the convex hull of two spheres with possibly different centers and radii). - New level set constructor tools::createLevelSetTubeComplex creates a grid containing a narrow-band level set representation of a tube complex (a collection of capsules or tapered capsules defined by endpoint coordinates and segment indices). - New level set constructor tools::createLevelSetDilatedMesh creates a grid containing a narrow-band level set representation of a dilated surface mesh (dilated by a radius in all directions). - New class tools::ConvexVoxelizer, used by the above methods, which can be inherited to implement a convex level set constructor. - Introduced anisotropic surfacing tools in points/PointRasterizeSDF.h and principal component analysis (PCA) methods in points/PrincipalComponentAnalysis.h. The latter tool analyses point neighborhoods and computes affine transformations representing elliptical distributions. The prior tool takes rotational and stretch point attributes (optionally computed from the prior PCA methods) and generates anisotropic surfaces. Improvements: - Significantly improved the performance of all LeafNode ValueIterators, up to 5x on some platforms and up to 10x when delay loading is enabled. Construction of a ValueIterator from a leaf node now requests the leaf buffers ahead of iteration to avoid potentially expensive API calls. - Improved the performance of PointRasterizeSDF.h tools with larger radii with better bound computation approximations. - Significant performance improvement to delay loaded files - the warning logic which checks the underlying mapped file for the last modified time has been removed, resulting in performance gains upwards of 10x when loading in node data buffers. Note that the check that was removed is entirely redundant on Windows and would only print a warning on other system. [Contributed by jjtParadox] - Added OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION and OPENVDB_HAS_MEMBER_FUNCTION macros to help determine the presence and compatibility of interface member functions at compile time. - Added OPENVDB_ASSUME macros to mimic builtin assume and C++23 assume attributes. - Improved read and write of PLY files with vdb_tool so they support Vec3d and 64 bit attributes. Changed vdb_tool version number from 10.6.1 to 10.7.0. API Changes: - Mat3 and Mat4 functions have been marked [[nodiscard]] where it may be confusing if they are operating in place or returning a result, in particular tranpose, invert, adjoint, and timesDiagonal. - Re-worked the API in PointRasterizeSDF.h with the addition of anisotropic surfacing kernels. The new API exposes more concise free functions which take structs of parameters. The old API remains supported but is deprecated. - Deprecated providing a filter or interrupter as arguments to points::rasterize. These can instead be implemented on user transfer schemes. - Transfer schemes provided to points::rasterize can now optionally implement a rasterizePoints callback that takes a range of points per voxel. Fixes: - Fixed a bug in points::rasterizeSpheres and points::rasterizeSmoothSpheres which could cause sections of the generated surface to incorrectly be marked as negative interior values. - Fixed a bug in points::rasterizeSmoothSpheres which could result in incomplete surface reconstruction with significantly larger search distances. - Fixed some precision issues in various Matrix methods. - Fixed bugs in vdb_tool that prevented build with newer namespaces in nanovdb. OpenVDB AX: Improvements: - Added support for LLVM versions greater than 15. Upgraded CI to test with LLVM versions 16, 17, 18, 19 and 20. - As of this release, LLVM 15 is the minimum required version for OpenVDB AX. Note that there is an issue with LLVM 17 symbols which makes it incompatible with the OpenVDB Python plugin. AS such, LLVM version 18 and greater are the recommended LLVM versions to use, with LLVM 18 being the new future minimum version. - Significant performance improvement to the compilation of AX kernels when using LLVM 18 and greater. - Significant backend refactoring to AX IR generation to support newer versions of LLVM. In particular, parts of the codegen::Function and codegen::FunctionBuilder API require new usage from LLVM 16 due to the LLVM opaque pointer changes. If you're not using the OpenVDB AX Function codegen API then no client changes should be necessary. - Migrated OpenVDB AX unit tests from cppunit to gtest [Contributed by Tim Straubinger] Fixes: - Fixed a case of undefined behaviour when explicitly casting variables to the same type as their storage type e.g: double a; double b = double(a); - Fixed an AX compiler error which would produce invalid IR when using 64bit integer variables for matrix array offsetting e.g: int64 a = 0; mat4f b = 1; float c = b[a,a]; NanoVDB: - Added nanovdb::openToIndexVDB, which can convert an OpenVDB grid into a NanoVDB IndexGrid. - Added new options "--index" and "--onIndex" to the command-line tool nanovdb_convert so it can produce IndexGrids. - Fixed memory leak in DeviceBuffer. - Added constructor for DeviceBuffer from an existing HostBuffer. - Added VoxelBlockManager, an acceleration structure for sequential access and stencil ops over active voxels. - Added helper functions for kernel launches with shared memory. - Added support for CUDA 13.0. - Fix warnings and compilation errors for GCC and Clang. - Fixed inconsistent usage of util::cuda::mallocAsync/freeAsync that affected vGPUs. - Added support for custom memory resources in PointsToGrid. - Fixed race condition in split/mergeGridHandles. - Fixed offset bug in nanovdb::tools::cuda::IndexToGrid related to non-POD build types. [Contributed by Andreas Henne] Houdini: - Define OP_InputIdx and OP_OutputIdx for Houdini 21.0 compatibility - Add Houdini 21 style camera interface to support LOP cameras - Include env flag for avoiding stream writing (was backported to 19.5) Version 12.0.1 - April 3, 2025 OpenVDB: New features: - Added read and write support for OFF (Object File Format) files to vdb_tool Build: - Fixed a build issue with vdb_render on Windows with newer versions of glew not including glu.h by default - Fixed issues with newer versions of clang refusing to accept older ::template syntax NanoVDB: New features: - Added support for multiple GPUs to DeviceBuffer - Added a UnifiedBuffer class that wraps CUDA unified memory - Added example for multiGPU sparse convolution - Added CUDA utility functions for device queries - Added functions to independently stop and compute the elapsed time for timer classes Improvements: - Replaced CUB's CachingDeviceAllocator with the default asynchronous stream ordered allocator in PointsToGrid for improved performance Bug fix: - Map is now properly transposed when converting NanoVDB to OpenVDB. - Fixed ostream specializations being hidden within the nanovdb namespace - Fixed a call to a non-existent method in GridBuild.h Version 12.0.0 - October 31, 2024 OpenVDB is now licensed under the Apache 2.0 license, instead of the MPL 2.0 license. This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 10 for Houdini 20.0 and 11 for Houdini 20.5. GCC 9 is no longer supported. OpenVDB: New features: - Added fillet() method in tools::LevelSetFilter to round off concave edges to create smoother transition between surfaces. Improvements: - Added openvdb::assertAbort to replace cassert and a OPENVDB_ENABLE_ASSERTS cmake argument/compile define to toggle assertions in OpenVDB code, independantly of NDEBUG. Asserts are no longer enabled by default in when NDEBUG is absent (e.g. Debug builds). - Removed last traces of Boost when OPENVDB_USE_DELAYED_LOADING is OFF [Reported by Brian McKinnon] - RootNode code cleanup to eliminate redundant key conversion and to create map values in-place. - Add RootNode::deleteChildOrTile() to delete a child or tile of the root node. - ValueAccessors are now defined and created in the Tree class instead of in the Grid class so that custom Tree implementations may define and create their own ValueAccessors if desired. - Added support for PDAL to vdb_tool [Contributed by Tom Matterson] - LeafManager and NodeManager now use Index64 for leaf counts internally. - Added RootNode::probeChild() const. - Added RootNode::probeChild() and RootNode::probeConstChild(). - Added RootNode::probe() and RootNode::probeConst() to query key presence, child node, value and active state. - Added InternalNode::probeChild() const. - Added InternalNode::probeChild() and probeChildConst() with coord access and optionally value and active state. - Added InternalNode::probeChild() and probeChildConst() with index access and optionally value and active state. - Added InternalNode::isValueOff(), LeafNode::isValueOff(), LeafNodeBool::isValueOff(), LeafNodeMask::isValueOff(). - Added LeafNodeMask::probeValue(Index,val), LeafNodeBool::probeValue(Index,val). - Added RootNode::getValueUnsafe(), RootNode::getChildUnsafe(), RootNode::getConstChildUnsafe(). - Added InternalNode::getValueUnsafe(), InternalNode::getChildUnsafe(), InternalNode::getConstChildUnsafe(). - Added InternalNode::setActiveStateUnsafe(), InternalNode::setValueOnlyUnsafe(), InternalNode::setValueOnUnsafe(), InternalNode::setValueOffUnsafe(). - Added InternalNode::setChildUnsafe(), InternalNode::resetChildUnsafe(), InternalNode::stealChildUnsafe(), InternalNode::deleteChildUnsafe(). - For LeafNode, LeafNodeBool and LeafNodeMask - added LeafNode::getValueUnsafe(), LeafNode::setActiveStateunsafe(), LeafNode::setValueOnlyUnsafe(), LeafNode::setValueOnUnsafe(), LeafNode::setValueOffUnsafe(). ABI changes: - Tree::leafCount(), Tree::unallocatedLeafCount(), Tree::nonLeafCount() and Tree::nodeCount() now use Index64 in their return types instead of Index32. API Changes: - RootNode::tileCount(), RootNode::activeTileCount() and RootNode::inactiveTileCount() are now public. - RootNode::hasKey() and RootNode::coordToKey() are now public. - RootNode::leafCount(), RootNode::nonLeafCount() and RootNode::nodeCount() now use Index64 instead of Index32. The Index32 variant is deprecated. - InternalNode::leafCount(), InternalNode::nonLeafCount() and InternalNode::nodeCount() now use Index64 instead of Index32. The Index32 variant is deprecated. - LeafNode::leafCount() and LeafNode::nonLeafCount() now use Index64 instead of Index32. The Index32 variant is deprecated. Bug Fixes: - Fix potential crash reading corrupt .vdb files with invalid blosc or zip chunks. [Fix thanks to Matthias Ueberheide] - Fix a bug in RootNode::setOrigin() where the origin was updated before the error was thrown potentially leaving the root in an invalid state. - Fixed a thread sanitizer issue which could cause undefined behaviour in VolumeToSpheres::fillWithSpheres [Reported by Jérémie Dumas] - Fixed an occurance of undefined behaviour in tools::activate (though this would typically not have manifested with any unintended behaviour) NanoVDB: Bug fix: - nanovdb::readGrids works with raw grid buffer. Improvements: - Restructure files location and namespace to be more align with OpenVDB. The namespaces touched by the restructuring are: io, cuda, util, tools, and math. - Add two scripts updateFiles.sh and updateFiles.py to update the files using NanoVDB. The script updateFiles.py works on both Windows and Linux. For a more complete list of changes, see API Changes (details). - cuda::PointsToGrid supports target density. - Add support for NanoVDB Grid of type UInt8. - Add ability to use externally managed CUDA buffer. - Add create methods for CudaDeviceBuffer and exceptions. - Improve GridValidator logic, e.g. include check for grid count. - Add operator > and >= for class Coord according to lexicographical order. - Add toCodec to convert string to Codec enumeration type. - Add nanovdb::strlen(). - Add strncpy util. - Add NANOVDB_DISABLE_SYNC_CUDA_MALLOC that maps cudaMallocAsync and cudaFreeAsync to cudaMalloc and cudaFree respectively. - Add guard to UINT64_C. - Remove use of cudaMallocAsync in PointsToGrid.cuh. - Align PNanoVDB blind metadata to NanoVDB. API Changes: - Change mapToGridType to toGridType. - Change mapToMagic to toMagic. - Change CpuTimer.h to Timer.h. API Changes (details): - These APIs are now under the math namespace: Ray, DDA, HDDA, Vec3, Vec4, BBox, ZeroCrossing, TreeMarcher, PointTreeMarcher, BoxStencil, CurvatureStencil, GradStencil, WenoStencil, AlignUp, Min, Max, Abs, Clamp, Sqrt, Sign, Maximum, Delta, RoundDown, pi, isApproxZero, Round, createSampler, SampleFromVoxels. - These APIs are now under the tools namespace: createNanoGrid, StatsMode, createLevelSetSphere, createFogVolumeSphere, createFogVolumeSphere, createFogVolumeSphere, createFogVolumeTorus, createLevelSetBox, CreateNanoGrid, updateGridStats, evalChecksum, validateChecksum, checkGrid, Extrema. - These APIs are now under the util namespace: is_floating_point, findLowestOn, findHighestOn, Range, streq, strcpy, strcat, empty, Split, invoke, forEach, reduce, prefixSum, is_same, is_specialization, PtrAdd, PtrDiff. - Move nanovdb::build to nanovdb::tools::build. - Rename nanovdb::BBoxR to nanovdb::Vec3dBBox. - Rename nanovdb::BBox to nanovdb::Vec3dBbox. - Move nanovdb::cudaCreateNodeManager to nanovdb::cuda::createNodeManager. - Move and rename nanovdb::cudaVoxelsToGrid to nanovdb::cuda::voxelsToGrid. - Move and rename nanovdb::cudaPointsToGrid to nanovdb::cuda::pointsToGrid. - Move nanovdb::DitherLUT to nanovdb::math::DitherLUT. - Move and rename nanovdb::PackedRGBA8 to nanovdb::math::Rgba8. - Move nanovdb::Rgba8 to nanovdb::math::Rgba8. - Move and rename nanovdb::CpuTimer to nanovdb::util::Timer. - Move nanovdb::GpuTimer to nanovdb::util::cuda::Timer. - Move and rename nanovdb::CountOn to nanovdb::util::countOn. - Move util/GridHandle.h to GridHandle.h. - Move util/BuildGrid.h to tools/GridBuilder.h. - Move util/GridBuilder.h to tools/GridBuilder.h. - Move util/IO.h to io/IO.h. - Move util/CSampleFromVoxels.h to math/CSampleFromVoxels.h. - Move util/DitherLUT.h to math/DitherLUT.h. - Move util/HDDA.h to math/HDDA.h. - Move util/Ray.h to math/Ray.h. - Move util/SampleFromVoxels.h to math/SampleFromVoxels.h. - Move util/Stencils.h to nanovdb/math/Stencils.h. - Move util/CreateNanoGrid.h to tools/CreateNanoGrid.h. - Move and rename util/Primitives.h to tools/CreatePrimitives.h. - Move util/GridChecksum.h to tools/GridChecksum.h. - Move util/GridStats.h to tools/GridStats.h. - Move util/GridChecksum.h to tools/GridChecksum.h. - Move util/GridValidator.h to tools/GridValidator.h. - Move util/NanoToOpenVDB.h to tools/NanoToOpenVDB.h. - Move util/cuda/CudaGridChecksum.cuh to tools/cuda/CudaGridChecksum.cuh. - Move util/cuda/CudaGridStats.cuh to tools/cuda/CudaGridStats.cuh. - Move util/cuda/CudaGridValidator.cuh to tools/cuda/CudaGridValidator.cuh. - Move util/cuda/CudaIndexToGrid.cuh to tools/cuda/CudaIndexToGrid.cuh. - Move and rename util/cuda/CudaPointsToGrid.cuh to tools/cuda/PointsToGrid.cuh. - Move util/cuda/CudaSignedFloodFill.cuh to tools/cuda/CudaSignedFloodFill.cuh. - Move and rename util/cuda/CudaDeviceBuffer.h to cuda/DeviceBuffer.h. - Move and rename util/cuda/CudaGridHandle.cuh to cuda/GridHandle.cuh. - Move and rename util/cuda/CudaUtils.h to util/cuda/Util.h. - Move and consolidate util/cuda/GpuTimer.h to util/cuda/Timer.h. Houdini: - When OPENVDB_ENABLE_RPATH is ON, the location of libopenvdb_houdini is now added to the rpath of all Houdini dsos. Python: - OpenVDB Python bindings are now implemented using nanobind instead of pybind11 - The OpenVDB Python module has been changed from pyopenvdb to openvdb - Added Python bindings for NanoVDB Build: - Fixed an issue with OpenVDB AX's CMake on Windows where the static and shared library targets would have the same name [Reported by Nicholas Yue] - USE_EXPLICIT_INSTANTIATION is now disabled on Windows by default due to OOM linker issues. - Jemalloc is now the preferred allocator of choice on all platforms when CONCURRENT_MALLOC is set to Auto. - Fixed an issue with the Blosc CMake FindPackage for the OpenVDB Windows static library. Version 11.0.0 - November 1, 2023 This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 9 for Houdini 19.5 and 10 for Houdini 20.0. OpenEXR 2 and Python 2 are no longer supported. OpenVDB: Improvements: - Removed use of boost::any in favor of std::any. [Contributed by Brian McKinnon] Bug Fixes: - Fix potential crash reading corrupt .vdb files with invalid blosc or zip chunks. [Contributed by Matthias Ueberheide] NanoVDB: Highlights: - Several new tools to generate and modify NanoVDB grids on the GPU. - New file format that supports streaming of raw grid buffers. New Features: - New memory efficient GridClass::IndexGrid that separates values from tree - 4 new GridTypes (Index, OnIndex, IndexMask, OnIndexMask) used by IndexGrid - Added createNanoGrid that replaces older conversion methods in GridBuilder.h, IndexGridBuilder.h and OpenToNanoVDB.h - Added cudaPointsToGrid that constructs a point device grid from a list of points. - Added cudaVoxelsToGrid that constructs a voxel device grid from a list of voxels. - Added cuda/CudaUtils.h with several cuda utility functions. - Added GpuTimer for timing of kernels in a specific cuda stream. - Added cudaIndexToGrid that converts IndexGrids into regular Grids. - Added cudaSignedFloodFill that performs signed-flood filling on the GPU. - Added cudaAddBlindData that adds blind data to an existing grid on the GPU. - Added cudaGridChecksum that computes checksums of device grids. - Added cudaGridHandle that handles grids on the GPU. - Added cudaNodeManager that constructs a NodeManager on the GPU. - Added build type Points and GridType::PointIndex for point grids. - Added GridType::Vec3u16 and GridType::Vec3u8 for compressed coordinates. - Added PrefixSum.h for concurrent computation of prefix sum on the CPU. API Changes: - Version 32.6.0 (ABI is unchanged). - Transition from C++11 to C++17 - Vec3R is deprecated, please use Vec3d instead. - nanoToOpenVDB now takes the index of a NanoVDB in a GridHandle. - GridData, InternalData and LeafData are now public. - GridMetaData can be copied. - Improvements to GridBuilder.h that allows construction of grids on CPU. - GridHandle's move c-tor now requires the GridBuffer to contain a valid grid. - Moved CudaDeviceBuffer.h to cuda/CudaDeviceBuffer.h. - New API for acceleration of custom random-access with ValueAccessors. - Added BitFlags class for convenient bit-mask operations. - Added Vec2/3::min/maxComponentAtomic GPU methods. - Added BBox::expandAtomic and BBox::intersectAtomic. - Added Coord::expandAtomic. - Added Map constructors. - Added Mask::DenseIterator, Mask::setOnAtomic, and Mask::setOffAtomic. - InternalNode::ChildIterator is now const-correct. - Added several new NanoVDB Build Traits. - Syncing PNanoVDB.h with NanoVDB.h. Build: - Support for OpenEXR 2.X has been removed. - Better support for building with external package configurations with CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON. Python: - Removed Python 2 support. [Contributed by Matthew Cong] - Removed explicit bindings for Math types. [Contributed by Matthew Cong] - Improved type casting for TypedMetadata. [Contributed by Matthew Cong] Version 10.1.0 - October 11, 2023 Highlights: - OpenVDB Python bindings are now implemented using pybind11 instead of Boost.Python. [Contributed by Matthew Cong] OpenVDB: New features: - Added points::replicate() for the replication of PointDataGrid points and attributes. Improvements: - Upgraded OpenVDBs internal half representation to IMath 3.1.6. Brings conversion support using F16C instructions (if enabled using -mf16c) and the removal of the exponent lookup table in favor of bit shifting. - OpenVDBs copy of Half.h is no longer built with an internal lookup table, but explicitly selects the non-LUT version and disables the creation of the LUT. This is required to avoid symbol conflicts with different namespaced OpenVDB builds. - Removed boost::uuid from Archive, instead std::random_device is used directly to generate UUID-like objects. - Moved all cases of file static/global variables which relied on non-trivial construction into function scopes as static locals. These would previously initialize themselves on start-up in a non-deterministic, compiler-dictated order(static-initialization-order-fiasco). This order is now defined by the program's execution. - Fixed the constants used in openvdb::math::Coord::hash() and nanovdb::Coord::hash() to correctly be prime numbers (note that this changes the result of these methods). [Contributed by Benedikt Mersch] - Updated tools::meshToVolume to take two new optional arguments to provide an interior test oracle and an interior testing method. These allow the default outside-flood-fill to be replaced if the actual sidedness can be known. [Contributed by Tomas Skrivan] - LevelSetRebuild now includes example code that demonstrates the intended use of the new meshToVolume interior testing parameters for the resampling of level sets, where the original grid is used as the true sign value. However, due to differences between polygonalization and trilinear interpolation, this behaviour is disabled and exists as a reference. - Introduced openvdb::TupleList to wrap std::tuple and provide interface interop methods with openvdb::TypeList. - Added OPENVDB_FORCE_INLINE, OPENVDB_LIKELY and OPENVDB_UNLIKELY macros. - Introduced openvdb::make_index_sequence to solve clang compilations issues with compiler built-in index_sequence implementations. API changes: - Significant infrastructural change to the ValueAccessor header and implementation. All ValueAccessor specializations have been consolidated into a single class which supports all possible ValueAccessor configurations using index_sequences. Backward compatible declarations have been provided. The new ValueAccessor implementation is marked as final. - PagedArray iterators no longer derive from std::iterator (but remains standard compliant). Bug Fixes: - Internal counters in tree::RangeIterator were limited to 32bit precision. They are now extended to size_t. [Reported by SpaceX] - Fixed a bug when compiling with -fvisibility=hidden and GCC 11 which would cause a crash in openvdb::initialize(). - Fixed a bug with LeafManager which wouldn't correctly initialize its LeafNode array for single level Tree configurations i.e. RootNode (bug introduced in 7.2.0). [Reported by @lanwatch] - Fixed a bug with LeafNodeBool Topology constructor with designated on/off values which wouldn't apply them correctly. [Reported by @hozhaoea] OpenVDB AX: Improvements: - Added support for LLVM 15. Bug Fixes: - Fixed a bug in AX on older X86 hardware which could cause a crash when accessing point attributes with half compression (bug introduced in 9.1.0). - Fixed an incorrect option in the `vdb_ax` command line tool where the default optimization level was set to NONE instead of O3 (issue introduced in 10.0.0). Houdini: Improvements: - Added Preserve Holes option to VDB From Polygons that uses the fast winding oracle to not collapse holes in polygonal geometry. Bug Fixes: - Fix a bug in the projection mode of the Advect Points SOP that was causing a segfault. Build: - Fixed a build issue where Boost was not being pulled in when OPENVDB_USE_DELAYED_LOADING was set to OFF. - Fixed a build issue with AX on 32-bit platforms. [Reported by Mathieu Malaterre] - Fixed a compilation issue with the min() and max() methods on Stencils in openvdb/math/Stencils.h. [Reported by Samuel Mauch] - Fixed a compilation error that would be encountered when attempting to enable the SSE4.2 or AVX SIMD options on non-x86 based platforms. - Improved support for compiling with C++20. [Contributed by Denys Maletskyy and Jérémie Dumas] - OpenVDB's CMake no longer modifies the BUILD_SHARED_LIBS variable. [Reported by Maksim Shabunin] - Fix int-in-bool-context GCC9+ warnings by switching to use constexpr if. Version 10.0.1 - November 30, 2022 Bug Fixes: - Fix uninitialized point flags in tools::VolumeToMesh which could result in non-deterministic results (bug introduced in 10.0.0). Build: - Fixed CXX standard requirement for VDB components in FindOpenVDB.cmake Version 10.0.0 - October 27, 2022 This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 8 for Houdini 19.0 and 9 for Houdini 19.5. Highlights: - Introducing OpenVDBLink, which provides a Mathematica interface to OpenVDB. This link ports over access to various grid containers including level sets, fog volumes, vector grids, integer grids, Boolean grids, and mask grids. Construction, modification, combinations, visualisations, queries, import, export, etc. can be achieved over grids too. Any Mathematica 3D region that's ConstantRegionQ and BoundedRegionQ can be represented as a level set grid, providing a more seamless integration with OpenVDB. - Introducing a new command-line tool, dubbed vdb_tool, that can combine any number of the high-level tools available in openvdb/tools. For instance, it can convert a sequence of polygon meshes and particles to level sets, perform a large number of operations on these level set surfaces and export them as adaptive polygon meshes. OpenVDB: Improvements: - Significantly improved the performance of all ValueAccessor methods which access LeafNode value buffer data. This improvement applies to any type which is delay load compatible (all default types except for bool and mask grids) and improves the performance of many OpenVDB tools. - Improved the performance of volumeToMesh by 10-15%. ABI changes: - ABI change to openvdb::RootNode, which now has a new member that defines the origin of the node. For now this origin is set to a default value of (0,0,0), but in the near future we will allow for offsets to improve access performance and reduce the memory footprints. - Removed deprecated virtual methods from AttributeArray. API changes: - Removed PagedArray::push_back(). - Removed Tree visitor methods from Tree, RootNode, InternalNode and LeafNode classes - visit(), visit2(), visitActiveBBox(). - Removed LeafManager::getNodes(). - Removed tools::dilateVoxels() and tools::erodeVoxels() in favor of tools::dilateActiveValues() and tools::erodeActiveValues(). - Removed tools::FindActiveValues::any() and tools::FindActiveValues::none(). - StringGrid and StringTrees have been removed. Bug Fixes: - Fixed an issue with tools::topologyToLevelSet which would previously ignore active tiles in the input topology. [Reported by Tobias Rittig] - Fixed a bug with ValueAccessor::addLeaf and ValueAccessor::addTile which wouldn't add the provided leaf nodes to the underlying tree. This bug did NOT affect the specialized accessors which are used by the default tree configuration. [Contributed by Andrey Zakirov] - Fixed a bug where ValueAccessor::probeNode and ValueAccessor:probeConstNode would return a nullptr if the NodeT type was not explicitly being cached by the accessor but the node existed in the tree. - Fixed a bug on Windows where math::Abs could truncate 64bit integer values. [Contributed by Edward Lam] - Fixed an occurrence of undefined behaviour with math::floatToInt32 and math::doubleToInt64. [Reported by VojtÄ›ch Bubník] - Fixed bugs in the sum merge that produced incorrect merged grids when deep-copying the input nodes or when non-zero background grids were being used. - Fixed a bug in FastSweeping where voxels/tiles are left with min/max float values. - Fixed a bug in math/Tuple.h that prevented compilation with VS2017. OpenVDB AX: Improvements: - Major updates to the command line interface of the vdb_ax binary, exposing more controls such as tile streaming, value iterator types and attribute bindings. OpenVDB Houdini: New Features: - Add convex hull activation for VDB Activate SOP (requires 19.5). Improvements: - Improved SDF activation to use dynamic node manager. Bug Fixes: - Fixed a bug in VDB Visualize SOP where color values that exceed the range wrap around instead of being clamped. NanoVDB: New Features: - Added nanovdb::IndexGrid that allows for arbitrary voxel values and even multiple channels to be associated with NanoVDB grids. They are more flexible and memory efficient than regular grids at a small cost of random-access performance. IndexGrids are constructed with the new nanovdb::IndexGridBuilder and accessed with the new nanovdb::ChannelAccessor. - Added iterators to all tree node classes for visiting inactive, active, or all values and child nodes. - NanoVDB.h now includes standalone implementations of reading and writing uncompressed nanovdb grids buffers. - Added Stats::getExtrema, which computes the min/max values of all voxels in a NanoVDB grid that intersects with a user-defined bounding-box. - Added nanovdb::Mask::countOn(int) which is essential to the new nanovdb::IndexGrid. - Added RootNode::probeChild and InternalNode::probeChild. Improvements: - Added a new much improved nanovdb::NodeManager, that is both faster and more memory efficient, and that works on both the CPU and GPU. Note, it uses a handle for allocation (just like nanovdb::Grid) and replaces the old nanovdb::LeafManager which is now deprecated. - NanoToOpenVDB is extended to work with grids templated on Fp4, Fp8, Fp16, FpN, bool and ValueMask. - Renamed RootNode::findTile to RootNode::probeTile and made it public. - Made Mask::getWord return both a const and non-const reference. - Improved unit-tests to use explicit 32B alignment (see alignment bug-fix below). - PNanoVDB.h (a C99 port of NanoVDB.h) has been updated. Bug Fixes: - Fixed a bug in nanovdb::HostBuffer that could produce crashes due to misaligned CPU memory allocations. - Fixed bug related to uninitialized memory in nanovdb::Grid which could confuse CRC32 checksum validation. - Fixed bugs related to the use of intrinsic functions for fast bit-counting in nanovdb. - Fixed a potential security vulnerability in NanoVDB.h related to buffer overflow exploits. Build: - Added OPENVDB_USE_DELAYED_LOAD flag that enables delayed loading and defaults to on. - Add a placeholder to inject the specific revision and URL used to build OpenVDB, useful for 3rd party build scripts to publish their exact versions. - Fixed an issue where OPENVDB_AX_DLL was not being defined on shared library builds of AX, resulting in symbols not being exported. [Reported by Ray Molenkamp] - Fixed an issue where setting Tbb_INCLUDE_DIR could cause CMake failures. - Updated FindTBB.cmake to support newer library ABI suffixing in TBB 2021.5. - Updated FindBlosc.cmake to better handle cases where blosc is built with external sources. - Resolved LLVM deprecation warnings in AX and added support for LLVM 14. - On Windows (MSVC), OpenVDB is now built with extra compiler options to ensure stricter C++ conformance: /permissive- /Zc:throwingNew /Zc:inline. - On Windows (MSVC), the _USE_MATH_DEFINES macro is no longer defined when including (or any dependent headers). If you were relying on this in your own project for M_PI, M_PI_2, etc. you can add -D_USE_MATH_DEFINES to your own project compiler options. See https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants for more info. Version 9.1.0 - June 9, 2022 Bug Fixes: - Minor fix to move assignment operator in nanovdb/util/HostBuffer.h. This could potentially be a problem on Windows debug builds (unconfirmed). - Minor fix to range in openvdb/tools/LevelSetSphere.h. This could result in data races for multi-threaded execution (unconfirmed) [Reported by Tommy Hinks] - Fixed a bug with Tree::combineExtended which wouldn't propagate the resulting active state when a destination tile overlapped a source child node. [Reported by @frapit] - Fix unit tests failures with Blosc versions >= 1.19.0. - Fixed a regression in ax::run which wouldn't propagate exceptions - Fixed a bug where ax::ast::parse could return a partially constructed but invalid AST on failure - Fixed AX logger exit handling in ax::Compiler::compile and ax::ast::parse - Fixed an issue which could result in significant compilation times when instantiating TypeList<>::Unique<> New features: - Added support for AMD's HIP API in NanoVDB [Contributed by Blender Foundation] - Added bindings mechanism to AX to allow differing data and AX attribute names (@) in Point and Volume executables. - Added support for OpenVDB AX on Windows. - Added tools::memUsageIfLoaded() which returns the memory consumption of a deserialized VDB tree, useful if delay-loading is enabled. - Added points::rasterizeSpheres() and points::rasterizeSmoothSpheres() variants, new kernels and improved performance for OpenVDB points to surface rasterization. - Added points::rasterizeTrilinear() for OpenVDB points, fast staggered or colocated trilinear rasterization for scalar and vector attributes. - Exposed TypeList declarations in openvdb.h which denote the default set of types supported by OpenVDB. - Added points::FrustumRasterizer for efficient rasterization of OpenVDB points to frustum volumes with optional motion blur. Improvements: - Added a --thread [n] argument to the vdb_ax binary. - Added a --copy-file-metadata option to vdb_ax. This behaviour is now off by default. - Added support for multiple input files with the vdb_ax binary using -i. Positional arguments as input files are deprecated. - Added tools::minMax() which supports multithreaded evaluation of active minimum and maximum values. Grid::evalMinMax() has been deprecated. - Significant performance improvements to AX point kernels, primarily due to providing AX access to attribute buffers for superior code generation. - vdb_print now prints both the in-core memory and total memory usage for VDB grids. - Improved build support for MinGW [Contributed by Mehdi Chinoune] - Added a new foreach method to TypeList for iterating over types without constructing them. - Added TypeList::Transform declaration for transforming TypeLists into new types. - Moved Grid::apply implementation to TypeList::apply to allow for other polymorphic types to invoke it. - Minor updates to NanoVDB to remove compiler warnings. Build: - Regenerated AX grammar with Flex 2.6.4 and Bison 3.8.2. - Improved locating NumPy in CMake when multiple python versions are installed. - Fixed an issue which could report Python as missing when using CMake 3.18 and later on some systems. [Reported by Sam James] - Changed the way boost_python and boost_numpy are located. Both components must match the major/minor version of python in use. This can be circumvented by providing Boost_PYTHON_VERSION or Boost_PYTHON_VERSION_MAJOR. - Relocated OpenVDB binaries to a new openvdb_cmd root directory. - FindTBB.cmake now prioritises newer TBB installations. - Added option to compress PDB data in MSVC debug builds. Houdini: - Added Attribute Bindings to AX SOP to allow differently named AX attributes (@) and target point attributes/volumes. - Fix race condition in OpenVDB Merge SOP that could cause crashes or merged VDBs to not be deleted. - VDB Activate SOP no longer stops at the first non-VDB primitive, but instead just skips such primitives. - Added VDB Rasterize Frustum SOP for efficient rasterization of OpenVDB points into frustum volumes with optional motion blur. Version 9.0.0 - October 29, 2021 This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 7 for Houdini 18.5 and 8 for Houdini 19.0. Official release of NanoVDB, which for the first time offers GPU support for static sparse volumes in OpenVDB. New features: - Faster build times from support for explicit template instantiation, which is enabled by default for most of the tools. - Added support for OpenEXR 3 and TBB 2021. - Added transient data to the RootNode, InternalNode, and LeafNode. Improvements: - Added tools::countActiveLeafVoxels(), tools::countInactiveVoxels(), tools::countInactiveLeafVoxels() and tools::activeTiles() to perform multi-threaded counting. The Tree methods now use these implementations. - Moved from the deprecated TBB task scheduler to TBB arenas. Various methods now respect the TBB arena state they were invoked from. - Introduced a new thread/Threading.h header to consolidate calls to third-party threading methods. - Minor performance improvements to dilation calls in fast sweeping algorithms. - Added hsvtogrb() and rgbtohsv() AX helper functions for converting hue, saturation and value inputs to RGB values and vice-versa. - PointDataGrid conversion can now be performed using 32-bit float arrays. - Improved support for size_t grid types on systems where size_t is a unique type. [Contributed by Brecht Van Lommel] - Add support for dilation in one direction and extending a field in one direction in fast sweeping algorithms. - Added PNG support to vdb_render which can be enabled with during CMake with -DUSE_PNG=ON. - Explicit template instantiation has been enabled by default for most of the tools. This pre-compiles template instantiations into the core library to reduce the time spent compiling code in downstream libraries or applications. - Added a python binding for OpenVDB AX which allows you to invoke accelerated AX code from the python module. Bug Fixes: - Fixed a bug where ax::run() would crash if it could not parse a single statement. ABI changes: - Added transient data to the RootNode, InternalNode, and LeafNode. API changes: - DynamicNodeManager can now set one grain size for threading across leaf nodes and another for threading across non-leaf nodes. - StringGrid and StringTrees are deprecated. - The NullInterrupter is now a virtual base class to help reduce compile-time instantiation cost. Houdini: - Fix crash in VDB Combine in Copy B mode if the second input has more VDBs than the first. - VDB Vector Merge SOP is now VDB Vector From Scalar SOP to distinguish it from the VDB Merge SOP. It keeps the same internal name so this is merely a label change. - Add option to pass in OPENVDB_DSO_NAMES to CMake to configure which Houdini DSOs are compiled. - VDB Activate SOP now has an option for the expansion pattern to use for dilation. - The label for Voxels to Expand is now Expand Voxels to match Houdini. - Fix bug to allow VDB LOD SOPs to be chained together. - SOP Extrapolate supports dilation in one direction and extending a field in one (domain) direction. - The default OpenVDB ABI is now 8 for Houdini versions > 18.5. - VDB Visualize Tree SOP is now multi-threaded and provides slicing and color remapping. - A new HoudiniInterrupter has been added that derives from the NullInterrupter and the Interrupter is now deprecated. All the SOPs have been updated to use the new HoudiniInterrupter. - Add a sanitizer in SOP OpenVDB Extrapolate when expanding a narrow-band level-set with a dilation value of 0, which will result in no operation. Build: - Added support for TBB 2021. - Enabled the OPENVDB_FUTURE_DEPRECATION variable by default to warn on upcoming deprecations. - Introduced a OPENVDB_DOXYGEN_INTERNAL CMake variable which is ON by default and removes the majority of internal namespaces from the generated doxygen. - Improved the doxygen deprecation listings, folder layouts and fixes issues when using later versions of doxygen. - Build fixes for MinGW on Windows. [Contributed by Brecht Sanders] - Added support for OpenEXR 3. [Contributed by Cary Phillips] - Added an OPENVDB_NAMESPACE_SUFFIX CMake string option which provides the ability to customise the VDB namespace. - The Python Module now appends the base directory defined by Python_SITELIB to the default install path (typically dist-packages or site-packages). [Contributed by Ignacio Vizzo] - As of this release, VFX Reference Platform 2019 is no longer supported. CMake now issues deprecation warnings for 2020 VFX Reference Platform version dependencies. - Build fixes for OpenVDB AX with C++17 and greater. - Bumped the new blosc version future minimum to 1.17.0. - OpenEXR is now optional for vdb_render. It can be enabled with -DUSE_EXR=ON. Version 8.2.0 - November 24, 2021 Improvements: - Added tools::countActiveLeafVoxels(), tools::countInactiveVoxels(), tools::countInactiveLeafVoxels() and tools::activeTiles() to perform multi-threaded counting. The Tree methods now use these implementations. - Moved from the deprecated TBB task scheduler to TBB arenas. Various methods now respect the TBB arena state they were invoked from. - Introduced a new thread/Threading.h header to consolidate calls to third-party threading methods. - Minor performance improvements to dilation calls in fast sweeping algorithms. - Added hsvtogrb() and rgbtohsv() AX helper functions for converting hue, saturation and value inputs to RGB values and vice-versa. - PointDataGrid conversion can now be performed using 32-bit float arrays. - Improved support for size_t grid types on systems where size_t is a unique type. [Contributed by Brecht Van Lommel] - Minor performance improvements to dilation calls in fast sweeping algorithms. - Add support for dilation in one direction and extending a field in one direction in fast sweeping algorithms. API changes: - DynamicNodeManager can now set one grain size for threading across leaf nodes and another for threading across non-leaf nodes. Houdini: - Fix crash in VDB Combine in Copy B mode if the second input has more VDBs than the first. - VDB Vector Merge SOP is now VDB Vector From Scalar SOP to distinguish it from the VDB Merge SOP. It keeps the same internal name so this is merely a label change. - Add option to pass in OPENVDB_DSO_NAMES to CMake to configure which Houdini DSOs are compiled. - VDB Activate SOP now has an option for the expansion pattern to use for dilation. - The label for Voxels to Expand is now Expand Voxels to match Houdini. - Fix bug to allow VDB LOD SOPs to be chained together. - SOP Extrapolate supports dilation in one direction and extending a field in one (domain) direction. - The default OpenVDB ABI is now 8 for Houdini versions > 18.5. - VDB Visualize Tree SOP is now multi-threaded and provides slicing and color remapping. - Add a sanitizer in SOP OpenVDB Extrapolate when expanding a narrow-band level-set with a dilation value of 0, which will result in no operation. Build: - Added support for TBB 2021. - Enabled the OPENVDB_FUTURE_DEPRECATION variable by default to warn on upcoming deprecations. - Introduced a OPENVDB_DOXYGEN_INTERNAL CMake variable which is ON by default and removes the majority of internal namespaces from the generated doxygen. - Improved the doxygen deprecation listings, folder layouts and fixes issues when using later versions of doxygen. - Build fixes for MinGW on Windows. [Contributed by Brecht Sanders] - Added support for OpenEXR 3. [Contributed by Cary Phillips] - Added an OPENVDB_NAMESPACE_SUFFIX CMake string option which provides the ability to customise the VDB namespace. - The Python Module now appends the base directory defined by Python_SITELIB to the default install path (typically dist-packages or site-packages). [Contributed by Ignacio Vizzo] Version 8.1.0 - June 11, 2021 As of this release, support for grid ABI=5 has been removed. New features: - Added tools::erodeActiveValues() to match the existing tools::dilateActiveValues(). New erosion tools support all tile policies and edge/vertex neighbor patterns. - Added support for automatic filtering of active tiles in tools::Filter by setting tools::Filter::setProcessTiles. Active tiles are densified on demand, only when necessary. - Added tools::visitNodesDepthFirst and tools::DepthFirstNodeVisitor which visit nodes in a tree or sub-tree in single-threaded depth-first order. - Significant performance improvements to AX volume kernels, primarily due to improved vectorization. Performance scales depending on the available host CPU instruction set and scalability of the AX kernel. Trivial assignments profile upwards of 3x faster on AVX. - Introduced Active Tile Streaming for volumes kernels. AX can now dynamically expand and collapse active nodes at all levels of a VDB tree on demand, switching on or off by checking the spatial access pattern of AX programs. - Added tools::countActiveVoxels() for multi-threaded counting of active voxels, optionally by bounding box. The Tree::activeVoxelCount() method now uses this implementation. - Added tools::memUsage() for multi-threaded counting of bytes of memory used. The Tree::memUsage() method now uses this implementation. Improvements: - Significant performance improvements to large dilations with tools::dilateActiveValues(). Performance gains will improve relative to increases in the inputs size and dilation scheme. - Added an optional argument to Tree::topologyUnion() which preserves active tiles on the destination tree should they overlap leaf nodes from the source tree. - Reduced the time spent in the hot path of openvdb::initialize() and openvdb::uninitialize() by leveraging atomics with double-checked locks. [Contributed by Ben FrantzDale]. - Extended tree::DynamicNodeManager to allow for use with a const tree. - Replace tbb::mutex with std::mutex and tbb::atomic with std::atomic as these have now been removed in TBB 2021. [Contributed by Ben FrantzDale]. - Significant performance improvements to tools::activate and tools::deactivate through use of the DynamicNodeManager to parallelize tile processing. - Added degree() and radians() AX helper functions for converting radians to degrees and vice versa, respectively. - Added adjoint(), cofactor() and inverse() AX matrix functions. - Added sort(), argsort(), isfinite(), isinf() and isnan() AX utility and math functions. - Added Vec4 argument support to normalize() AX function. - Removed unused int16 AX modulo function signatures. - Refactored the backend AX representation of strings with SSO support and heap allocation. - Added new methods on the VolumeExecutable to control active tile streaming and node execution levels - The deletepoint() AX function is now natively supported by the PointExecutable - Added tools::SumMergeOp that uses a parallel breadth-first algorithm to accelerate summing grids. - vdb_view: Fixed a bug which wouldn't reset the camera speed on focus - vdb_view: Improved the drawing of PointDataGrids - vdb_view: Improved the exception handling of BufferObjects and added support for drawing an array without index values Bug Fixes: - Fix a memory leak in AttributeArray when delayed-loading is disabled. - Fixed a crash in OpenVDB AX when declaring arrays with non-scalar elements (unsupported) i.e. {"foo", 1, 2}, {1, {1,2}, 3} etc. - Fixed a bug in OpenVDB AX which would cause an error when multiplying a vec3 by a mat4. - In OpenVDB AX, improved the error message produced when attempting to use a matrix literal (i.e. {1,2,3...}) in a binary expression (this is invalid but would previously print out bad IR). - Fixed a non-deterministic failure in the TestStreamCompression unit test. - Use copy-by-reference for the operator in a DynamicNodeManager to fix a performance regression. - tools::deactivate now also works with a MaskTree. - Fixed a memory leak in the OpenVDB AX parser - Fixed an occurrence of undefined behavior in the OpenVDB AX visitor - Fixed some memory leaks in the OpenVDB and OpenVDB AX unit tests - Fixed a bug in AX which could cause string allocations in loops to overflow the stack - Fixed a bug where the ValueOff iterator for the AX VolumeExecutable could remove child branches of a VDB tree. - Fixed a crash in the AX Houdini SOP with an empty PointDataGrid input. - Fixed all cases where PointIndex and PointData aliases were used instead of a templated type. [Reported by Karl Marrett] - Fixed a crash when calling openvdb::points::pointOffsets with an empty PointDataGrid input. - Add missing 8-bit and 16-bit attribute type registration. API changes: - Restructured the internals of Morphology.h and moved tools::activate() and tools::deactivate() to a new header, Activate.h. - Deprecated tools::dilateVoxels() and tools::erodeVoxels() in favour of new morphology methods. - The openvdb::tools::Film class no longer has a saveExr method in any build configuration. Sample code for saving exrs from this object can be found in the command line render tool. - Added ability to run tools::activate and tools::deactivate single-threaded. Houdini: - Updated the VDB Activate SOP and others to use the multi-threaded implementation for voxel dilation, providing a significant performance increase. - Introduced the VDB AX SOP which provides an interface for running OpenVDB AX code in Houdini on VDB grids. - Updated the VDB Smooth SOP to support the filtering of active tiles. - Fixed a parameter warning in VDB AX SOP. - Transfer Surface Attributes in Convert VDB SOP could use uninitialized memory. - VDB Activate SOP now uses the multi-threaded tools::deactivate for much faster performance. - Improved the formatting and updated the OpenVDB AX SOPs help card. - The AX SOP utilizes the new Active Tile Streaming feature for Volumes. Grids will only be densified in areas where unique values are created. - VDB Activate SOP dilation will affect tiles, changing its behavior from previous versions, but producing a more expected result. - VDB Activate SOP has a world space dilation option. - Introduced the VDB Merge SOP that merges multiple grids in parallel and is faster and more convenient to use than the VDB Combine SOP. - Fix a bug where the VDB Rebuild SDF was not preserving metadata from the input grid. - Fix a bug in VDB Resample SOP where input transform was not being used for voxel size and voxel scale transform modes. - Added Extrapolate SOP, which wraps the tools leveraging the Fast Sweeping algorithm (tools::dilateSdf, tools::maskSdf, tools::fogToSdf, tools::sdfToSdf, tools::sdfToExt, tools::fogToExt, tools::sdfToSdfAndExt, tools::fogToSdfAndExt). Build: - Dependency on OpenEXR's Half implementation has been removed from the core library by naturalizing the implementation into openvdb::math. This is fully bitwise compatible, but may require switching Half references to math::Half. The USE_IMATH_HALF build configuration can be used to switch back to OpenEXR based half. - Blosc, Log4cplus, IlmBase, OpenEXR and TBB find modules now configure release and debug library variants. [Reported by Matthew Cong] - Fixed an issue where FindBlosc wouldn't add zstd as a dep in non static builds BLOSC_USE_EXTERNAL_SOURCES. - Fixed Log4cplus interface language and missing interface libraries on Win32. - Removed Jemalloc and Tbbmalloc logic from the core library builds. - The variable CMAKE_MSVC_RUNTIME_LIBRARY is no longer set by the OpenVDB CMake. If CMAKE_MSVC_RUNTIME_LIBRARY is not explicitly provided, OpenVDB configures the static library with /MT(d) and the dynamic library with /MD(d). [Reported by Jérémie Dumas] - Added support for ABI=9 and a CMake option OPENVDB_USE_FUTURE_ABI_9 to use it without errors. - The value of CONCURRENT_MALLOC is now respected when building the vdb_ax command line binary. - Added an option OPENVDB_ENABLE_UNINSTALL to allow the toggling of the uninstall build target. [Contributed by Jérémie Dumas] - Improved the behavior of locating static zlib libraries when USE_STATIC_DEPENDENCIES is enabled. - Fixed an issue where extra hboost libraries could not be found when building against Houdini 18.5 on Windows. - Build fixes to OpenVDB AX for LLVM 12. - Re-introduced the OPENVDB_DEPRECATED macro with an additional option that takes a message. Added support to disable deprecations throughout OpenVDB by defining OPENVDB_NO_DEPRECATION_WARNINGS - Added an optional OPENVDB_TESTS variable to easily build a subset of the unit tests. - Fixed various incorrect RPATH directory paths in CMake (introduced in 8.0.1) [Contributed by Ignacio Vizzo]. - Removed some unnecessary CMake for vdb_view - The Windows defines NOMINMAX and _USE_MATH_DEFINES are now provided in Platform.h. - Moved the logic from PlatformConfig.h into Platform.h. - The version.h header is now an auto generated header (version.h.in) populated by CMake. The OpenVDB Version and ABI defines are computed from the installation settings. Importantly, the value of OPENVDB_ABI_VERSION_NUMBER now always matches the version used at build time. - Added OPENVDB_USE_HALF, OPENVDB_USE_BLOSC and OPENVDB_USE_ZLIB as publicly available defines in version.h. These will be defined depending on the settings used to build OpenVDB. Version 8.0.1 - February 5, 2021 Bug fixes: - Fixed a bug in the new CSG intersection merge algorithm where data outside of the intersection region was not being removed. Build: - Fixed various incorrect RPATH directory paths in CMake - Dropped the minimum boost requirement back to 1.61. - Documentation installed by the doc target is now installed to the share/doc/OpenVDB prefix Houdini: - VDB Combine SOP no longer attempts to invoke SDF CSG operations on bool grids because unary negation is undefined on bools in the template expansion. Version 8.0.0 - December 23, 2020 This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 6 for Houdini 18.0 and 7 for Houdini 18.5. Official release of OpenVDB AX, a new C++ library that implements a domain specific JIT (just-in-time) compiled expression language, providing users with a new way of interacting with OpenVDB data. AX is tailored towards writing highly parallelizable and customizable OpenVDB volume and point kernel operations. See the documentation for more: https://www.openvdb.org/documentation/openvdbax.html New features: - Added tools::anyActiveVoxels and tools::anyActiveTiles that check if respectively active voxels or tiles in a tree intersect a given CoordBBox. - Added tools::activeTiles that returns a vector containing all the active tiles in a tree that intersects a given CoordBBox. Improvements: - Made LeafManager class non-virtual. Bug fixes: - Fixed a determinism bug in NodeManager when using non-thread-safe functor members. - Fix GridTransformer construction to use correct rotate-scale-translate order when recomposing matrix components. [Contributed by Tom Cnops]. - OpenVDB AX: Fixed a potential code generation crash in binary, ternary or comma operators when errors occurred in first operand. ABI changes: - Grid::isTreeUnique() is now virtual as of ABI=8 so that it can be accessed from the GridBase. - Private method RootNode::getChildCount() has been removed as of ABI=8. - Mark map classes and functions as final for ABI=8 where beneficial to allow devirtualization optimization. - As of ABI 8, Vector, Matrix and Quaternion types now satisfy the Trivial Type requirement. Their empty constructors and copy constructors have been removed (and are left to the compiler to define). - As of ABI 8, removed an unnecessary specialization of NodeUnion and CopyTraits from NodeUnion.h. Replaced std::is_pod usage with std::is_trivially_copyable which allows more types to benefit from the union storage. - As of ABI 8, PointDataGrids use the union NodeUnion specialization, reducing the memory footprint of their topology by 50%. API changes: - Removed a number of deprecated point, volume and AX methods. Houdini: - VDB to Spheres SOP doesn't reset the radius when in worldspace mode. VDB Write likewise should not reset the compression values. Build: - As of this release, VFX Reference Platform 2018 is no longer supported. CMake now issues deprecation warnings for 2019 VFX Reference Platform version dependencies, with the exception that OpenEXR/IlmBase 2.2 is still supported. - Added a missing header include to resolve an undefined size_t build error on GCC10. - Improved the python module's linkage with the CMake 3.15 Python::Module target. Explicitly linking with the Development target could result in crashes, particularly on macOS. [Reported by Alexander Hagen] - Removed OPENVDB_DEPRECATED macro in favor of C++14 [[deprecated]] attribute. Version 7.2.3 - March 16, 2021 Bug fixes: - Use copy-by-reference for the operator in a DynamicNodeManager to fix a performance regression. Version 7.2.2 - February 4, 2021 Bug fixes: - Fixed a bug in the new CSG intersection merge algorithm where data outside of the intersection region was not being removed. - Fix GridTransformer construction to use correct rotate-scale-translate order when recomposing matrix components. [Contributed by Tom Cnops]. Houdini: - VDB Combine SOP no longer attempts to invoke SDF CSG operations on bool grids because unary negation is undefined on bools in the template expansion. - VDB to Spheres SOP doesn't reset the radius when in worldspace mode. VDB Write likewise should not reset the compression values. Version 7.2.1 - December 23, 2020 Bug fixes: - Fixed a determinism bug in NodeManager when using non-thread-safe functor members. Build: - Added a missing header include to resolve an undefined size_t build error on GCC10. Version 7.2.0 - December 9, 2020 New features: - Added tree::DynamicNodeManager that lazily caches the nodes at each level of the tree to allow for efficient threading of topology-changing top-down workflows. - Added tools::CsgUnionOp, tools::CsgIntersectionOp and tools::CsgDifferenceOp that use a parallel breadth-first algorithm to accelerate CSG union, intersection and difference operations. - Added tools::TreeToMerge which provides methods to steal or deep-copy from a tree based on the tag dispatch class used in its construction. - Pre-release of OpenVDB AX, an open source C++ library that provides a powerful and easy way of interacting with OpenVDB volume and point data. Improvements: - util::CpuTimer now uses C++11 chrono instead of TBB. - Threaded the construction of LeafManager and NodeManager linear arrays. - tools::csgUnion, tools::csgIntersection and tools::csgDifference now use the new parallel breadth-first algorithms for much faster performance. - Extended tree::NodeManager to allow for use with a const tree. - Added math::Abs, math::cwiseAdd, math::cwiseLessThan and math::cwiseGreaterThan methods for Matrix types. Matrix grids can now be instantiated. Houdini: - Fixed a bug in the OpenVDB Points Convert SOP where the auto voxel transform was ignoring the contents of packed geometry. - Fixed a bug in the OpenVDB Points Convert SOP where points representing packed geometry were also being converted. - Fixed a bug where a Houdini SOP's verb would not be correctly associated with the corresponding node if the node's internal name was changed. - Fixed bug where OpenVDB Convert SOP could revert the name attribute. Bug fixes: - Fixed a bug which could cause recursive compile time instantiations of TypeList objects, manifesting in longer compile times. - Deprecated util::PagedArray::push_back due to a race condition. Instead use util::PagedArray::ValueBuffer::push_back which is faster and thread-safe. - Fixed various cases of undefined behavior in some LevelSetUtil methods [Reported by fkemmler] API changes: - Deprecated tree::LeafManager::getNodes. This method is no longer used when constructing a NodeManager from a LeafManager. - Deprecated Tree::visitActiveBBox, Tree::visit and Tree::visit2 methods in favor of using a tree::DynamicNodeManager. - Removed tools::CsgVisitorBase, tools::CsgVisitorUnion, tools::CsgVisitorIntersection and tools::CsgVisitorDifference. The CSG tools now use the parallel breath-first algorithms. - Moved openvdb::TypeList from Types.h into its own header TypeList.h Build: - Removed the Makefiles. - Re-organised the repository layout such that each independent library is able to be configured against an existing installation of OpenVDB without ambiguous include paths. - Upgraded CMake minimum version support to 3.12. - Removed OPENVDB_STATIC_SPECIALIZATION macro which is no longer required. - Fixed various compiler warnings for GCC 9.1. - Moved to CMake doxygen commands and removed the doxygen-config files for doxygen documentation. - Added USE_ZLIB compiler flag that enables zlib compression and defaults to on. - Added the OPENVDB_STATICLIB define to all static builds to fix builds on Windows which use the multithread/DLL-specific version of the CRT. [Reported by Tobias Rittig] - Core library unit tests use GoogleTest instead of CppUnit. Version 7.1.0 - August 13, 2020 As of this release, support for grid ABI=4 has been removed. New features: - Added a novel parallel sparse FastSweeping class that outperforms our existing techniques for computing signed distance fields in addition to supporting velocity extension. - Added tools::fogToSdf which converts a scalar (fog) volume into a signed distance field. - Added tools::sdfToSdf which re-normalizes a signed distance field; - Added tools::fogToExt which extends an arbitrary field (e.g. velocity) off the iso-surface of a scalar (fog) volume. - Added tools::sdfToExt which extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added tools::fogToSdfAndExt which computes a signed distance and extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added tools::fogToSdfAndExt which re-normalizes a signed distance and extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added tools::dilateSdf which dilates a signed distance field. - Added tools::maskSdf which extends an existing signed distance into a user-defined mask. - Added Grid::isTreeUnique() to tell if the tree is shared with another grid. - Added PointDataLeafNode::stealAttributeSet() and AttributeSet::removeAttribute() for releasing ownership of attribute data. - Added AttributeSet::Descriptor::groupIndexCollision() for detecting group index collisions when attempting to merge two Descriptors. - Added RootNode::childCount(), InternalNode::childCount() and LeafNode::childCount() to count the number of immediate child nodes that exist below the current node. Improvements: - Added GroupWriteHandle::setUnsafe() for faster performance when the group array is known to be in-core and non-uniform. - Add support for default value metadata when creating AttributeArrays or appending to an AttributeSet. - Added new group inspection methods to the AttributeSet::Descriptor. - Introduced a StringMetaCache class for convenient string attribute metadata lookup and performed some minor optimizations. - Removed redundant floor in points::floatingPointToFixedPoint. - Add gitignore to repository root. - Removed some logic for compilers older than Visual Studio 2019. - Add a new Houdini ABI test binary. - Fixed an indexing typo in tools::Filter. [Contributed by Yuanming Hu] - Removed redundant null pointer checks. [Contributed by Kuba Roth] - Added support for vdb_view on Windows. Requires GLEW. - Removed support for GLFW 2. - vdb_view now uses OPENVDB_LOG_FATAL when catching exceptions. - vdb_view, vdb_print and vdb_render now use std::terminate() when catching an unknown exception. - Removed Boost::thread as a dependency of vdb_view in favour of std::thread. - Removed usage of boost/integer.hpp and boost/math/constants/constants.hpp, the latter in favour of new openvdb math constants for pi - Removed usage of boost/mpl/*.hpp methods in favour of new template meta-programming methods on the openvdb::TypeList struct. This now supports get, front, back, contains, index, unique, popback, popfront and range removal of types. - Changed the tree::NodeChain implementation to use an openvdb::TypeList rather than a boost::mpl::vector and updated all usage of tree::NodeChain accordingly. Bug fixes: - Fixed a bug where grids with no active values might return true when the method evalActiveVoxelBoundingBox is called. The correct behavior is to only return true if the grid contains any active values. - Fixed a sign propagation bug in tools::traceExteriorBoundaries() used by tools::meshToVolume(). This could cause values to not be propagated across node boundaries, leading to voxels incorrectly being marked as inside the isosurface. [Contributed by Tristan Barback] - Fixed a rotation order bug in tools::local_util::decompose() that caused it to fail to decompose some matrices. - Fixed a bug where math::Quat::inverse() was not marked as const. [Contributed by Michael Tao] - Fixed a bug in the unit test for util::CpuTimer on Windows by using a more accurate sleep implementation. - Fixed a bug where the requested uniform value of an AttributeArray was not being applied on attribute creation if the default attribute value was not the default value for that value type. - Fixed a compiler error when using C++17 by changing std::unexpected() to std::terminate(). [Contributed by Mark Sisson] API changes: - Removed a number of deprecated point methods. - points::StringIndexType is now deprecated, use Index instead. - PointPartitioner::voxelOffsets() now returns a std::unique_ptr instead of a boost::scoped_array. - Renamed AttributeSet::Descriptor::nextUnusedGroupOffset() to AttributeSet::Descriptor::unusedGroupOffset() to allow for providing an optional group offset hint. Houdini: - Platonic SOP is now verbified. - Extend all SOP references to support VDB Points. - Combine SOP will not error in flatten-all mode if second has no grids. - Changed the label (but not the opname) of Resize Narrow Band SOP to match the corresponding native Houdini SOP. The new label is Activate SDF. - Fixed a bug by using GEO_Detail::getBBox() instead of GEO_Detail::computeQuickBounds() as the latter was incorrectly using the point of the VDB when computing bounding box. SOPs affected include Clip, Fill, Points Group, Rasterize Points, Read, Remove Divergence. [Contributed by Kuba Roth] - OpenVDB from Polygons SOP now always displays the vector UI, as otherwise it might be stuck hidden if the input hasn't cooked. - OpenVDB from Polygons and OpenVDB from Particles SOPs no longer require input geometry to have been cooked to offer a choice of attributes, the user may now also type in a value. Build: - Improved the CMake build for the OpenVDB Houdini library on Windows. [Reported by Ian Woodward] - Remove some logic for compilers older than Visual Studio 2019. - Fixed a bug in the CMake FindIlmBase/OpenEXR modules which could cause compilers on UNIX systems to fail to find stdlib.h if IlmBase/OpenEXR headers were installed to /usr/include. - CMake now checks the minimum supported MSVC compiler for Windows. - CMake now only requires a CXX compiler. - Improved the Windows README instructions and various MSVC warnings. - Remove CMake warning when using GLFW 3.2+ on Debian. - Various fixes to unary minus on unsigned compiler warnings. - The defines _CRT_NONSTDC_NO_WARNINGS and _CRT_SECURE_NO_WARNINGS are now enabled by default with MSVC. - New CMake option OPENVDB_BUILD_PYTHON_UNITTESTS to disable or enable the python module tests and fixed the required environment for them on Windows. The python interpreter is no longer required by default if the tests are disabled. - Improved the CMake user messages when locating python and numpy. - The python module extension is now .pyd on Windows. - Fixed some build issues with the Houdini plugin on Windows. - Standardized the library components install paths for the OpenVDB Houdini shared library. - Added a USE_PKGCONFIG option to CMake to optionally disable use of pkg-config. [Contributed by Kartik Shrivastava] - Standardized the dependency search paths in FindPackage modules using GNU install paths. - Added better library type detection of dependencies through FindPackage modules on UNIX. - Added missing TBB, OpenEXR and IlmBase defines for static builds on Windows through the relevant FindPackage modules. - Improved the logic in FindOpenVDB for static builds. - Fixed a compiler warning on Apple Clang 11.0 where the AttributeArray move constructor was being implicitly deleted despite being marked default. - Added an option BLOSC_USE_EXTERNAL_SOURCES to FindBlosc to include blosc dependencies as interface libraries. - Added a root CMake option USE_STATIC_DEPENDENCIES to force CMake to only locate static libraries on UNIX. On Windows, if enabled, located libraries are assumed to be static. - Added support for CMAKE_MSVC_RUNTIME_LIBRARY for compilers that target the MSVC ABI. Requires CMake 3.15 or greater. - Fixed an issue where OPENVDB_OPENEXR_STATICLIB was not being defined and OPENEXR_DLL was being defined when linking against static builds of OpenEXR/IlmBase on Windows. - Improved the behaviour of boost implicit linking with the Boost::disable_autolinking target. - Added support for importing pyopenvdb and openvdb_houdini through the FindOpenVDB CMake module - Removed the OPENVDB_2_ABI_COMPATIBLE and OPENVDB_3_ABI_COMPATIBLE macros. - Fixed a few GCC compiler warnings by adding override keywords. [Contributed by Edward Lam] - jemalloc/tbbmalloc are no longer linked into library artifacts of the OpenVDB CMake build. The CONCURRENT_MALLOC CMake option now only applies to the executables. - Introduced a new OpenVDB::openvdb_je interface target through the FindOpenVDB CMake module which adds Jemalloc as a link time dependency. - CMake build fix for the vdb_render binary on Windows when building statically and using OpenEXR 2.5 Version 7.0.0 - December 6, 2019 Some changes in this release (see "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 18.0. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 5 for Houdini 17.0 and 17.5 and 6 for Houdini 18.0. As of this release, a C++14 compiler is required and the oldest supported Houdini version is 17.0. New features: - LevelSetMeasure can now compute multiple types of curvatures (averge and total Gaussian and mean curvature) as well as Euler characteristic and genus of level set surfaces. - Most stencil classes now have an intersection method that detcts the axial directions of zero-crossings (as oppose to the existing boolean intersection test). - The CurvatureStencil can now compute Gaussian and principal curvatures (in addition to mean curvature). - Added Tree::nodeCount, which counts the number and type of nodes in a tree very efficiently. - Added new RootNode::addChild() and InternalNode::addChild() methods to allow the insertion of child nodes directly. Improvements: - The minimum ABI for OpenVDB is now always enforced through CMake separately from other minimum dependency version variables. - Added support for CMake 3.12 compatible Xxx_ROOT variables. - Replaced the CMake USE_SYSTEM_LIBRARY_PATHS option with DISABLE_CMAKE_SEARCH_PATHS and removed the hard coded list of SYSTEM_LIBRARY_PATHS in favor of using CMake's default search procedure. SYSTEM_LIBRARY_PATHS can still be used as a global list of paths for all dependency searches. - Improvements to OpenVDB's CMake module setup order in regards to CMake policy, minimum version and project calls. - Replaced occurrences of boost::scoped_array with std::unique_ptr. - Added an OPENVDB_SIMD option to CMake to optionally define SSE4.2 and AVX compiler flags, this is switched off by default. - Made various small changes to improve Visual Studio compatiblity and deprecate some logic for compilers older than Visual Studio 2017. - Standardized CMake install locations using GNUInstallDirs. Importantly, this changes the default library installation folder from lib to lib64 on some 64-bit systems, or to lib/multiarch-tuple on Debian [Contributed by David Aguilar] - Added SIMD intrinsics to a few common NodeMask methods. [Contributed by Konstantin] Bug fixes: - Fixed a bug in FindJemalloc.cmake where paths were not being handled correctly. - Fixed a Windows build issue in openvdb_render. - Fixed a non deterministic threading bug in tools::meshToVolume() during polygon voxelization which could result in different distance values. ABI changes: - OpFactory destructor is now virtual as of ABI=7 - Added new virtual methods for copying const grids and replacing the metadata and/or the transform - GridBase::copyGridReplacingMetadata, GridBase::copyGridReplacingTransform and GridBase::copyGridReplacingMetadataAndTransform. - AttributeArray copy constructor is now thread-safe. API changes: - VolumeToMesh::pointList() and VolumeToMesh::polygonPoolList() now return a std::unique_ptr instead of a boost::scoped_array. - AttributeArray::copyUncompressed() is now deprecated. Python: - Removed the requirement of CMake 3.14 for NumPy usage. - Added support for Boost versions 1.65 and later when building the Python module with NumPy support through CMake. - Improved CMake Python3 support. - The Python Module is now disabled by default in CMake. Houdini: - Fixed a bug in the Points Convert SOP during conversion from Houdini geometry to OpenVDB Points, where point group information could end up corrupted or cause a crash with non-contiguous point offsets (mesh inputs). - Threaded the population of point group memberships during conversion from Houdini geometry to OpenVDB Points - Added logic to the Rasterize Points SOP to suppress the output of non-finite attribute values due to subnormal input densities. - Introduced a position compression option to the Scatter SOP for VDB Points and default to 16-bit fixed point. Version 6.2.1 - September 30, 2019 Bug fixes: - Fixed a crash that arose from an inadvertent ABI change of an I/O class with the 6.2.0 release. The crash occured when attempting to write out a point data grid using an I/O routine from a different version of OpenVDB than the one with which the grid was authored and when one of those OpenVDB versions was 6.2.0. Version 6.2.0 - September 18, 2019 New features: - Added tools::FindActiveValues, which counts the active values in a tree that intersect a given bounding box. - Added io::DelayedLoadMetadata, which stores mask offsets and compression sizes on write to accelerate delayed load reading. Improvements: - LeafNode::modifyValue() and LeafNode::modifyValueAndActiveState() now modify voxel values in place for improved performance. - Added math::isInfinite() and math::isNan() to resolve Visual Studio compatibility issues with integer types. - Made minor performance improvements to moving and filtering VDB points. - Improved performance related to a mutex contention when appending multiple AttributeArrays in parallel through various point operations. - Significantly improved the performance of createLevelSetSphere() using threading. - Improved directory and file path lookups of some CMake commands in the root CMakeLists.txt [Reported by Daniel Elliott] - Improved CMake support for GLFW versions 3.1 and later. - FindOpenVDB.cmake now correctly propagates CXX version requirements. - Added CMake support for linking against Jemalloc and TBB malloc and enabled Jemalloc by default for Linux and non-Maya builds and TBB malloc for all other builds. - Added a USE_COLORED_OUTPUT option to CMake to display compiler output in color. - Added an OPENVDB_CODE_COVERAGE option to CMake. - CMake now automatically detects and configures the CXX11 ABI requirement for Houdini builds. - CMake now issues deprecation warnings for 2017 VFX Reference Platform version dependencies. In particular, C++11-only compilers are now deprecated; OpenVDB 7.0 will require a C++14-compatible compiler. Bug fixes: - Replaced std::vector with std::deque as the underlying container for util::PagedArray, to address a rare crash when reading from multiple threads while writing from another thread. - Fixed a bug that could cause an empty CoordBBox to report nonzero volume. - Fixed a bug in tools::computeScalarPotential() that could produce a corrupt result due to invalid memory access. [Reported by Edwin Braun] - Partially reverted tools::ClosestSurfacePoint's distance calculations to their pre-OpenVDB 5.0 behavior to address a bug in the fillWithSpheres() tool that caused generated spheres to sometimes extend outside the target volume. - CMake now correctly sets rpaths for the unit test binary. - Addressed a Valgrind warning by allocating the AttributeArray registry using a Meyers singleton. [Contributed by Autodesk] ABI changes: - ABI versions 3 and older are now deprecated, and support for them will be removed in a future release. Until then, define the macro OPENVDB_USE_DEPRECATED_ABI (or set the CMake OPENVDB_USE_DEPRECATED_ABI option to ON) to suppress deprecation messages when compiling OpenVDB or dependent code. API changes: - Changed points::RandomLeafFilter::LeafMap from a std::map to a std::unordered_map. - Removed the TableT template argument from util::PagedArray. The table type is now hardcoded to std::deque. - The minimum supported version of GLFW is now 3.1. Python: - CMake now always produces a .so for the Python module on Unix and Linux platforms. - Fixed a compile-time error when building the Python module for Python 3. [Reported by yurivict] Houdini: - OpenVDB SOPs are now displayed in an ASWF sub-menu of the VDB tab menu. - Added API documentation and examples. - Added openvdb_houdini::GEOvdbApply(), which invokes a functor on a VDB primitive if the resolved grid type is a member of a given type list. - Fixed a regression in the Fill SOP that caused it to modify VDBs in the input detail. - The Combine SOP no longer crashes in Copy B mode when the destination is not a VDB. - Added a houdini_utils::OpFactory::addSpareData() method and addOperatorSpareData() and getOperatorSpareData() functions to manage spare data associated with operator types. - Added an opsparedata HScript command and hou.NodeType.spareData() and hou.NodeType.spareDataDict() methods to retrieve spare data associated with operator types. - Added a pythonrc.py startup script to set the tab menu visibility of nodes and their native Houdini equivalents, based on an OPENVDB_OPHIDE_POLICY environment variable. - Added a houdini_utils::OpFactory::setInvisible() method to hide nodes from tab menus. - Added an OpenVDBOpFactory::setNativeName() method to pair OpenVDB nodes with their native Houdini equivalents. - Added a houdini_utils::OpPolicy::getTabSubMenuPath() method to allow OpPolicy subclasses to provide their own tab sub-menu path. - OpenVDB nodes now override OP_Operator::getVersion() to return a version string of the form "vdb6.2.0 houdini18.0.222". Version 6.1.0 - May 8, 2019 As of this release, the oldest supported Houdini version is 16.5. New features: - Added new QuatTraits, MatTraits and ValueTraits type traits to complement VecTraits and added an IsSpecializationOf helper metafunction. - Added support for Vec4s, Vec4d and Vec4i metadata. - Added a generic TypeList class. - Added GridBase::apply(), which invokes a functor on a grid if the resolved grid type is a member of a given type list. - Added util::printTime(), which outputs nicely formatted time information. - Added a std::hash template specialization. - Added CoordBBox::moveMin() and CoordBBox::moveMax() to move a CoordBBox. Improvements: - util::CpuTimer now makes use of util::printTime() for nicer output, and its API has been improved. - Significantly improved the performance of point data grid string attribute generation. - AttributeArray::copy() and the copy assignment operator for AttributeArrays are now thread-safe. - The command-line tools (vdb_print, etc.) now include the library ABI version in their -version output. - Further improved the responsiveness of the mesh to volume converter to interrupt requests. - The CMake build system has been significantly improved to support a wider range of build options and use cases. This includes better dependency handling and status reporting, find module installation for external use, more robust handling of different platform configurations and the introduction of dependency and build documentation. Bug fixes: - Fixed a bug in tools::clip() that caused some grid metadata to be discarded. - Added a check to points::setGroup to compare the maximum index of the provided PointIndexTree to the size of the membership vector. - Fixed a race condition introduced in ABI 6 when moving points in point data grids, due to non-const access to an AttributArray triggering a copy-on-write. - Fixed a bug that caused the mesh to volume converter to consume unlimited memory when it encountered NaNs in vertex positions. - Fixed a rounding error bug in point conversion when using single-precision floating-point. - Addressed some type conversion issues and other issues reported by GCC 6. - Fixed a crash in tools::extractActiveVoxelSegmentMasks() when the first leaf node had no active voxels. [Reported by Rick Hankins] - Fixed a bug in tools::segmentActiveVoxels() and tools::segmentSDF() where inactive leaf nodes were only pruned when there was more than one segment. - Fixed a crash in point moving when using group filters. - Fixed a bug where the stride of existing attributes was being ignored during copy-construction of an AttributeSet. - Fixed a bug that caused AttributeArray equality operators to fail for attributes with non-constant strides. API changes: - Moved the CopyConstness metafunction from TreeIterator.h to Types.h. Houdini: - The Points Convert SOP now reports NaN Positions as warnings when converting from Houdini Points to VDB Points. - Fixed a bug where the Points Convert SOP was incorrectly ignoring point attributes with the same name as an existing point group. - The Transform SOP now supports frustum transforms by applying the transformation to the internal affine map. - Changed the labels (but not the opnames) of several SOPs to match the corresponding native Houdini SOPs. The new labels are Morph SDF, Project Non-Divergent, Rebuild SDF, Renormalize SDF, Reshape SDF, Segment by Connectivity, Smooth SDF, Topology to SDF, and Visualize Tree. - Added a houdini_utils::OpPolicy::getFirstName() method to allow OpPolicy subclasses to provide their own first name scheme. - Added a houdini_utils::OpPolicy::getLabelName() method to allow OpPolicy subclasses to provide their own label naming scheme for tab menus. - Added type lists for sets of commonly used grid types, including ScalarGridTypes, Vec3GridTypes, AllGridTypes, etc. - The Vector Merge SOP now copies metadata from the representative scalar grid. - Deprecated SOP_NodeVDB::duplicateSourceStealable(), houdini_utils::getNodeChain() and houdini_utils::OP_EvalScope. Python: - Added limited support for point data grids, comprising I/O and metadata functionality for now. - Added support for Mat4s and Mat4d metadata, in the form of nested Python lists (e.g., [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]]). Version 6.0.0 - December 18, 2018 Some changes in this release (see "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 17. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 3 for Houdini 15, 15.5 and 16, 4 for Houdini 16.5 and 5 for Houdini 17.0 New features: - Added support to the ParticlesToLevelSet tool for fast rasterization of particles into boolean mask grids. - Added convenience functions particlesToSdf(), particleTrailsToSdf(), particlesToMask() and particleTrailsToMask() for common particle rasterization use cases. - Added batch copying of AttributeArray values that significantly outperforms the older method that relied on a virtual function. Improvements: - Improved the responsiveness of the mesh to volume converter to interrupt requests. - Attempts to use a partially deserialized AttributeArray now errors. - Updated point deletion to use faster batch copying for ABI=6+. - Methods relating to in-memory Blosc compression for AttributeArrays now do nothing and have been marked deprecated resulting in memory savings for ABI=6+. Bug fixes: - Fixed various signed/unsigned casting issues to resolve compiler warnings when moving points in point data grids. ABI changes: - Added new virtual functions to AttributeArray. - Changed the order and size of member variables in AttributeArray and TypedAttributeArray. API changes: - Removed a number of methods that were deprecated in version 5.0.0 or earlier. - Removed the experimental ValueAccessor::newSetValue method. - Deprecated AttributeArray methods relating to in-memory Blosc compression. Houdini: - The Convert and To Polygons SOPs now correctly transfer vertex attributes when the output is a polygon soup. - Added an option to the Visualize SOP to display leaf nodes as points. - Renamed the Visualize SOP's "leafmode", "internalmode", "tilemode" and "voxelmode" parameters to "leafstyle", "internalstyle", etc. and converted them from ordinal to string-valued. - Made various improvements to viewport rendering of point data grids. - Added a ParmFactory::setInvisible() method to allow parameters to be marked as hidden. This is useful for multi-parms, whose child parameters cannot be made obsolete. - Removed the option to use in-memory Blosc compression from the Points Convert SOP as this feature has now been deprecated. - Made various small changes for Houdini 17 compatibility. Version 5.2.0 - August 13, 2018 New features: - Added tools to advect points stored in point data grids through velocity fields. [Contributed by Dan Bailey] - For point data grids, voxel data can now be prefetched independently of position or other attributes. [Contributed by Dan Bailey] - Added tools to sample voxel values onto points stored in point data grids. [Contributed by Double Negative] Improvements: - The UniformPointScatter tool now generates points in "points per volume" mode even when the product of the density and the voxel volume is less than one, and the point count now varies continuously with the density. - Added a min/max sphere count argument to the fillWithSpheres() tool. (The previous version, now deprecated, supported only a maximum sphere count.) - Added a method to tools::LevelSetTracker to enable and disable trimming of voxels outside the narrow band. Previously, trimming was always enabled, which caused dense SDFs to be converted to narrow-band level sets. - Added state() methods to point data index filters to improve optimization opportunities. [Contributed by Dan Bailey] - Added active and inactive value mask point data index filters. [Contributed by Dan Bailey] - Replaced include/exclude group list parameters with filter functors in various point data functions. [Contributed by Dan Bailey] - Refactored and simplified the point count API. [Contributed by Dan Bailey] - Computing cumulative per-leaf point offsets is now parallelized. [Contributed by Dan Bailey] - Made various small changes for Visual Studio 2017 compatibility. [Contributed by Edward Lam] Bug fixes: - Fixed a bug that could cause an infinite loop when iterating over an empty root node. - Fixed namespace-related bugs in math::Tuple::isZero() and math::Mat::isZero() that led to compile-time errors. - Fixed type conversion bugs in the vector-to-vector math::rotation() function that made it impossible for it to return a single-precision rotation matrix, and modified the function to accept Vec3 arguments of any value type. - Fixed a bug in the mesh to volume converter that made it uninterruptible in certain cases even though an interrupter was provided. [Reported by Doug Epps] Houdini: - Added an option to the From Particles SOP to output an interior mask grid. - Added options to the Metadata SOP to set the grid name and to propagate metadata to primitive attributes and vice-versa. - Modified GU_PrimVDB::convertVolumesToVDBs() to set the output VDBs' grid names to the names of the volume primitives. - Added an option to the Offset Level Set, Renormalize Level Set, Smooth Level Set, and Resize Narrow Band SOPs to enable and disable trimming of voxels outside the narrow band. Previously, trimming was always enabled, which caused dense SDFs to be converted to narrow-band level sets. - Fixed a bug in the Resample SOP that prevented it from reading a reference VDB from the second input. - Added an option to the Scatter SOP to scatter points only on an isosurface of a signed distance field. - The Scatter SOP now generates points in Point Density mode even when the product of the density and the voxel volume is less than one, and the point count now varies continuously with the density. - Added a minimum sphere count option to the To Spheres SOP. - Added enable/disable toggles to the To Spheres SOP's minimum and maximum radius parameters and eliminated the world space radius parameters. The remaining minimum and maximum parameters, formerly the voxel space radii, are now used in both world unit and voxel unit modes. - Added transform and rotation order options to the Transform SOP. - Added support to the Advect Points SOP for advecting points stored in point data grids. [Contributed by Dan Bailey] - Added support to the Sample Points SOP for sampling onto points stored in point data grids. [Contributed by Double Negative] Version 5.1.0 - April 10, 2018 New features: - Added an option to points::deleteFromGroups() to delete the groups as well as the points. [Contributed by Nick Avramoussis] - Added a header_test Makefile target that checks library header files for dependencies on missing or indirectly included headers. [Contributed by Dan Bailey] - Added support for Mat3s and Mat3d point data typed attributes. [Contributed by Dan Bailey] Improvements: - Added per-test timings to vdb_test to help in identifying performance regressions. - zeroVal() now returns a zero matrix instead of an identity matrix for Mat4s and Mat4d, and it is now also defined (and returns a zero matrix) for Mat3s and Mat3d. Python: - Fixed a bug introduced in version 3.2.0 that caused boolean and integer values added to a grid's metadata to be stored as floating-point values. Houdini: - Added options to the Clip SOP to expand or shrink the clipping region and, when clipping to a camera frustum, to set the near and far clipping planes. - Added output grid naming options to the Points Convert SOP. - Added a Keep Original Geometry toggle to the Points Convert SOP and improved the efficiency of point unpacking. [Contributed by Dan Bailey] - Added an option to the Points Delete SOP to delete point groups. [Contributed by Nick Avramoussis] - Fixed a rare crash when extracting points from a point data primitive. [Contributed by Jeff Lait] - Added a SOP_NodeVDB::evalStdString() method that facilitates string parameter evaluation in expressions, e.g., matchGroup(*gdp, evalStdString("group", time)). - Removed the deprecated openvdb_houdini::validateGeometry() function. Use convertGeometry() instead. - Added a SOP_NodeVDB::matchGroup() overload that eliminates the need to const_cast the GU_Detail. [Contributed by Jeff Lait] - Grid transforms are now more aggressively simplified, making it less likely to produce nonuniform voxels erroneously. [Contributed by Jeff Lait] - Fixed a bug when copying and pasting a Create SOP that could cause the Voxel Size toggle to change state. - Added a houdini_utils::OpFactory::setVerb() method to register compilable SOPs. - Made SOP_NodeVDB::cookMySop() final (that is, non-overridable) to facilitate the implementation of compilable SOPs. Override SOP_NodeVDB::cookVDBSop() instead. (In most cases, it suffices to rename cookMySop to cookVDBSop.) - Renamed some parameters on the following SOPs to match the equivalent native Houdini nodes: Advect, Advect Points, Analysis, Combine, Filter, Fracture, From Particles, From Polygons, Morph Level Set, Occlusion Mask, Offset Level Set, Points Group, Resample, Resize Narrow Band, Smooth Level Set, Topology To Level Set, Vector Merge, and Visualize. - Added SOP_VDBCacheOptions, a convenience base class for compilable SOPs. [Contributed by Jeff Lait] - Converted most SOPs into compilable SOPs. Version 5.0.0 - November 6, 2017 Some changes in this release (see "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 16. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 3 for Houdini 15, 15.5 and 16 and 4 for Houdini 16.5. New features: - Added a getLibraryAbiVersionString() function, which returns a string such as "5.0.0abi3". - Added a WeakPtr type alias for ABI compatibility. - Metadata fields of unregistered types are no longer discarded after being read from a .vdb file, and although their values are not printable, they can be written back to disk. - Added a DESTDIR_LIB_DIR Makefile variable for Linux multiarch support. [Contributed by Mathieu Malaterre] - Added tools to create potential flow fields, as described in the 2017 SIGGRAPH OpenVDB course. [Contributed by Double Negative] - Added tools to create mask grids from point data grids and to compute point counts. [Contributed by Dan Bailey] - Added tools to scatter OpenVDB points randomly throughout a volume. [Contributed by Nick Avramoussis] Improvements: - Significantly improved the performance of point data grid group filters. [Contributed by Double Negative] Bug fixes: - Fixed bugs in tools::ClosestSurfacePoint's distance calculations that caused searches to produce incorrect results. - Fixed a locking issue that affected multithreaded access to PointDataLeafNodes when delayed loading was in effect. [Contributed by Dan Bailey] ABI changes: - Made tree::InternalNode's destructor non-virtual. - The fix for a delayed-loading race condition in the LeafBuffer class that was only partially rolled out in the previous release is now enabled on all platforms. - Replaced a points::AttributeArray bit flag with an atomic integer to address a threading issue during delayed loading. [Contributed by Dan Bailey] - Deprecated the OPENVDB_2_ABI_COMPATIBLE and OPENVDB_3_ABI_COMPATIBLE macros in favor of a new OPENVDB_ABI_VERSION_NUMBER macro. The new macro defaults to the library major version number but can be set at compile time to an earlier version number to disable ABI changes since that version. (Older ABIs will not be supported indefinitely, however.) For example, compile OpenVDB and any dependent code with "-DOPENVDB_ABI_VERSION_NUMBER=4" to use the 4.x ABI. API changes: - Replaced tools::ClosestSurfacePoint::initialize() with tools::ClosestSurfacePoint::create(), which returns a newly-allocated and properly initialized object. - Removed methods that were deprecated in version 4.0.0 or earlier, including io::File::readGridPartial(), points::initialize(), points::uninitialize() and util::PagedArray::pop_back(). - Deprecated IllegalValueException in favor of ValueError. - Changed the naming scheme for the library namespace from openvdb::vX_Y_Z to openvdb::vX_YabiN, where X, Y, Z and N are the major, minor, patch and ABI version numbers, respectively. The abiN suffix is added only when the library is built using an older ABI version. Python: - Reimplemented NumPy support for Boost 1.65 compatibility. Houdini: - Fixed bugs that caused the Ray SOP's closest surface point searches to produce incorrect results. - Changed the VdbPrimCIterator::FilterFunc type from boost::function to std::function. - Changed the houdini_utils::OpPolicyPtr type from boost:shared_ptr to std::shared_ptr. - Debug-level log messages generated by OpenVDB are no longer forwarded to Houdini's error manager. - Fixed a bug in the Read SOP that made it impossible to select among grids of the same name in a file. - Added houdini_utils::ParmFactory::setAttrChoiceList(), a convenience method for the creation of menus of attributes. - Added a Potential Flow SOP. [Contributed by Double Negative] - Added point data grid support to the Scatter SOP. [Contributed by Nick Avramoussis] - Added mask and point count output options to the Points Convert SOP. [Contributed by Dan Bailey] Version 4.0.2 - July 28, 2017 New features: - Added tools::compActiveLeafVoxels(), which composites active voxel values from a source tree into a destination tree. It is threaded and faster than existing tools that merge trees, however it operates only on leaf nodes. - Added a vdb_test -f option that reads a list of tests to be run from a text file. - Added functions for deleting points from point data grids based on group membership. [Contributed by Double Negative] - Enabled display of point data grids in vdb_view. [Contributed by Nick Avramoussis] - Added a view mode indicator to vdb_view. - Added isFinite(), isInfinite(), isNan(), and isZero() methods to math::Mat and added isZero() to math::Tuple. - Added tools::interiorMask(), which constructs a boolean mask grid from the active voxels of an input grid or, if the input grid is a level set, from the interior voxels of the level set. - Added begin() and end() iterator methods (and related methods) to math::CoordBBox, so that it can be used in range-based for loops. - tools::clip() now accepts either a box, a mask grid or a camera frustum as the clipping region. The latter is new in this version. Improvements: - Moved the isFinite(), isInfinite() and isNan() methods from math::Vec3 et al. to math::Tuple. Bug fixes: - Fixed a delayed-loading race condition that could result in crashes. [Reported by Dan Bailey] To preserve ABI compatibility, this fix is currently enabled only on platforms for which the alignment of a tbb::atomic is the same as for a uint32_t. On other platforms, warnings will be logged during OpenVDB initialization, and it is recommended to disable delayed loading in that case (for example, by defining the environment variable OPENVDB_DISABLE_DELAYED_LOAD). - Fixed a delayed-loading memory leak in the PointDataLeafNode. [Contributed by Double Negative] - Changed the random number seeding mechanism for .vdb file UUIDs to avoid duplicate IDs. [Reported by Jason Lefley] - Fixed an off-by-one bug in the resampler that produced grid patterns of missing interior voxels for scale factors greater than one. Houdini: - As of Houdini 16.0.549, houdini_utils::OpFactory can generate help cards for operators automatically. New OpFactory::setDocumentation() and ParmFactory::setDocumentation() methods allow one to add custom help text in wiki markup format. - Added help cards for all SOPs. Houdini 16.0.578 or later is required. [Contributed by Dan Bailey and SideFX] - The Extended Operator Info window in Houdini 16 now renders correctly for OpenVDB SOPs, instead of displaying a Python stack trace. [Contributed by Dan Bailey] - Added a Points Delete SOP for deleting points from point data grids based on group membership. [Contributed by Double Negative] - Added a Mantra VRAY procedural and a delayed load SHOP for rendering point data grids. Houdini 16 is required. [Contributed by Double Negative] - Replaced the Combine SOP's "A/B Pairs" and "Flatten" toggles with a menu of collation options that include flattening only A grids and flattening groups of A grids independently. - Added a slider to the Remove Divergence SOP to set the error tolerance for the pressure solver. - Added value type conversion options (for VDB output) to the Convert SOP. - Added a Densify SOP that replaces active tiles with leaf voxels. - Fixed a bug in the Rasterize Points SOP that capped density values to one instead of to the particles' densities. - The Convert and To Polygons SOPs now accept grids of any type as surface masks, not just level set or SDF grids. - Added an option to the Clip SOP to clip to a camera frustum. Version 4.0.1 - March 8, 2017 New features: - Added functions to util/logging.h to simplify configuration of the logging system (via command-line arguments, in particular). - Added LeafManager::activeLeafVoxelCount(), a faster, threaded alternative to Tree::activeLeafVoxelCount(). - Added a -shuffle option that causes vdb_test to run unit tests in random order, which can help to identify unintended dependencies between tests. - Added vdb_lod, a command-line tool to generate volume mipmaps for level-of-detail effects. - Added methods to compute the median value of active, inactive or all voxels in leaf nodes. Improvements: - Added a Metadata::str() specialization for StringMetadata that eliminates the overhead of writing to a string stream. - Made various minor improvements to util::PagedArray. - Added an install_lib build target to the Makefile. [Contributed by Double Negative] - Added documentation and Cookbook examples for OpenVDB Points. [Contributed by Double Negative] - Registration of OpenVDB Points grid and attribute types is now handled in openvdb::initialize(), and openvdb::points::initialize() and openvdb::points::uninitialize() are therefore deprecated. - Extended multi-pass I/O to handle a variable number of passes per leaf node. [Contributed by Double Negative] - Addressed a name conflict between macros in util/NodeMasks.h and symbols in the Eigen library. [Reported by Trevor Thomson] Bug fixes: - tools::fillWithSpheres() and tools::ClosestSurfacePoint now correctly handle isosurfaces outside the input volume's narrow band. - tools::MultiResGrid now supports all standard grid types, including BoolGrid and MaskGrid. - LeafNode::fill() now correctly clips the fill region to the node's bounding box. - Grid::denseFill() no longer densifies all existing active tiles, and it now correctly handles both active and inactive fill values. - Fixed a bug that caused tools::copyToDense() to only partially populate the output array when delayed loading was in effect. [Reported by Stuart Levy] - Fixed an issue with duplicate registration of PointDataGrid attribute types. [Reported by SideFX] - Fixed an uninitialized memory bug in tools::meshToVolume(). [Reported by SideFX] - Fixed a thread race condition in math::QuantizedUnitVec that could cause it to produce incorrect results. [Contributed by Jeff Lait] - Fixed a dangling pointer bug in tools::ParticleAtlas. [Contributed by SideFX] - Grid operators (divergence, gradient, etc.) now produce correct results even for grids with active tile values. - Fixed a bug when writing an out-of-core points::AttributeArray that could cause corruption of the metadata associated with the array. [Contributed by Double Negative] Python: - Added functions getLoggingLevel(), setLoggingLevel(), and setProgramName(), to allow configuration of the logging system. Houdini: - Fixed a crash in the Ray SOP when the user selected an isosurface outside the target volume's narrow band. - The LOD SOP now supports all standard grid types, including boolean grids. - Added houdini_utils::ParmFactory::setGroupChoiceList(), a convenience method for the creation of menus of primitive groups. - Made various small changes for Houdini 16 compatibility. [Contributed by SideFX] - The Create SOP now supports matching the new grids' transform, voxel size, and topology to a reference grid. If the topology is being matched, it can optionally be resampled to a different voxel size. - Added some support for point data grids to the Clip, Topology To Level Set and Visualize SOPs. [Contributed by Double Negative] - Compression is no longer enabled by default in the Points Convert SOP for normals and colors, because they are not guaranteed to have a [0, 1] range. [Contributed by Double Negative] - Added a 16-bit truncation compression option to the Points Convert SOP. [Contributed by Double Negative] - Fixed a build issue with the GR_PrimVDBPoints render hook plugin that could cause hython to report a DSO error. [Reported by Double Negative] - Added an install_lib build target to the Makefile. - Rewrote the Remove Divergence SOP to actually remove divergence from vector fields on collocated grids, and added support for stationary and moving obstacles and an option to output a pressure field. - The Analysis SOP now produces correct results for grids with active tile values. - Added a sparse/dense toggle to the Fill SOP. - Added openvdb_houdini::startLogForwarding(), stopLogForwarding() and isLogForwarding(), which control the forwarding of log messages to Houdini's error manager. Forwarding of library warnings and error messages is now enabled by default for SOPs when OpenVDB is built with log4cplus. Version 4.0.0 - November 15, 2016 Highlights: - Incorporated Double Negative's OpenVDB Points library. See https://github.com/dneg/openvdb_points_dev for details. - Introduced some C++11 constructs. A C++11-compatible compiler is now required. - Blosc-compressed .vdb files are now as much as 20% smaller. - Vector-valued grids are now constructed and destroyed much faster. This change and other changes in this release (see "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones in Houdini 15, 15.5 and 16. To disable these changes and preserve ABI compatibility, define the macro OPENVDB_3_ABI_COMPATIBLE when compiling OpenVDB or any code that depends on OpenVDB. New features: - Added an option to the point scattering tools to specify how far each point may be displaced from the center of its host voxel or tile. - Added a toggle to tools::clip() to invert the clipping mask. - Custom leaf node implementations may now optimize their file layout by inheriting from io::MultiPass. Voxel data for grids with such leaf nodes will be written and read in multiple passes, allowing blocks of related data to be stored contiguously. [Contributed by Double Negative] - Added Tree::unallocatedLeafCount(), which returns the number of leaf nodes with unallocated data buffers (typically due to delayed loading). Improvements: - Vector-valued grids are now constructed and destroyed much faster. - Changed math::Coord's data representation to facilitate C++11 uniform initialization. - Delayed loading from io::Files is now faster due to the use of seeks instead of reads. [Contributed by Double Negative] - Made many small changes to address type conversion and other warnings reported by newer compilers, including Clang 3.8. - Improved Blosc compression ratios and write times by increasing the block size. [Contributed by Dan Bailey] Bug fixes: - Fixed a bug that caused topology operations (union, intersection and difference) on MaskGrids to sometimes produce incorrect results. (MaskGrids are used internally in a number of tools.) - Changed GridBase::copyGrid() and Grid::copy() to close const-correctness holes. - tools::fillWithSpheres() now returns an empty list of spheres instead of crashing when the user selects an isosurface that lies outside the bounding volume's narrow band. - Fixed a null pointer dereference when copying grids that were loaded with io::File::readGridPartial(). [Reported by Nick Avramoussis] ABI changes: - Added a NodeUnion template specialization for non-POD value types that significantly expedites construction and destruction of vector-valued grids. - Changed math::Coord's internal data representation. - Replaced occurrences of boost::shared_ptr with std::shared_ptr. - Changed GridBase::copyGrid() and Grid::copy() to close const-correctness holes. - Added virtual function Tree::unallocatedLeafCount(). API changes: - Introduced some C++11 constructs. A C++11-compatible compiler is now required. - Added a parameter to the point scattering tools to control the displacement of each point from the center of its host voxel or tile. The default behavior, as before, is to allow each point to be placed (randomly) anywhere within its voxel or tile. - Renamed LeafManager::getPreFixSum() to LeafManager::getPrefixSum(). - Made LeafNode::Buffer a top-level class and renamed it to LeafBuffer. [Contributed by Double Negative] - Deprecated io::File::readGridPartial() in favor of delayed loading. - tools::ClosestSurfacePoint::initialize() now returns a boolean indicating whether initialization was successful. - Dropped the CopyPolicy enum and added GridBase::copyGridWithNewTree() and Grid::copyWithNewTree() in order to close const-correctness holes that allowed newly-constructed, non-const grids to share their trees with existing const grids. (Where that behavior is still required, use a ConstPtrCast.) Python: - Fixed a build issue with Python 3 and NumPy. [Contributed by Jonathan Scruggs] Houdini: - Certain changes in this release (see "ABI changes" above) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini 15, 15.5 and 16. To disable these changes and preserve ABI compatibility, define the macro OPENVDB_3_ABI_COMPATIBLE when compiling OpenVDB or any code that depends on OpenVDB. - Introduced some C++11 constructs that are incompatible with versions of Houdini older than 15.0. - Fixed a bug in the Rasterize Points SOP that caused vector-valued attributes to be transferred as scalars. [Contributed by Double Negative] - Added a toggle to the Clip SOP to invert the clipping mask. - Added a slider to the Scatter SOP to specify how far each point may be displaced from the center of its host voxel or tile. Version 3.2.0 - August 10, 2016 Highlights: - New features: tool to produce and store a sequences of progressively lower resolution grids (mipmaps), an acceleration structure for fast range and nearest-neighbor searches on particles, arbitrary volume and level set specific segmentation tools, a new binary mask grid type and an efficient point to level set conversion scheme. - Optimizations: Faster volume to mesh conversion and threaded grid destruction, morphological dilation, csg operations and fracture tool. - New Houdini nodes: Segment, LOD and Topology To Level Set. New features: - Added tools::MultiResGrid a tool to produce and store a sequences of progressively lower resolution grids (mipmaps). - Added tools::ParticleAtlas an acceleration structure for fast range and nearest-neighbor searches on particles, points with radius. - Added tools::segmentActiveVoxels(), which operates on grids of arbitrary type and separates connected components of a grid's active voxels into distinct grids or trees. - Added tools::segmentSDF(), which separates disjoint signed-distance-field surfaces into distinct grids or trees. - Added tools::extractActiveVoxelSegmentMasks(), which constructs a mask for each connected component of a grid's active voxels. - Added threaded level-set CSG tools csgUnionCopy(), csgIntersectionCopy() and csgDifferenceCopy(), which, unlike the existing CSG tools, produce new grids rather than modifying their input grids. These new tools are faster and use less memory than the existing tools (if only because the input grids never need to be deep-copied). - Added a threaded dilateActiveValues() tool with tile value support. - Added tools::PointsToMask, which activates voxels that intersect points from a given list. - Added a new MaskGrid type that uses a single bit-field to represent both voxel values and states for the leafnode to reduce memory usage. - Added tools::topologyToLevelSet(), which generates a level set from the implicit boundary between active and inactive voxels in an input grid of arbitrary type. - Added tools::LevelSetPlatonic a new tool that produces narrow-band level sets of the five Platonic solids. - Added tools::extractIsosurfaceMask() which masks voxels that intersect the implicit surface defined by the given isovalue. - Added tree::LeafManager::getPreFixSum() for user-managed external buffers. - Added tools::Dense::print(). - Added the math::CoordBBox::Iterator class to conveniently iterate over coordinates covered a CoordBBox. - Added bit-wise operations, a component-wise constructor, and a getCornerPoints() method to the CoordBBox class. - Added a new LeafManager constructor to create the structure from an existing array of leafnodes. - Added the templated math::MinMax class to compute the extrema of arbitrary value types. - Added sparseFill and denseFill methods to the Grid, Tree and RootNode classes. Improvements: - Complete overhaul of the VolumeToMesh tool brings significant performance improvements and enhanced region masking, tile support and bool volume surfacing. - Improved the performance, parallel scaling and memory usage, of tools::LevelSetFracture and updated to use the new segmentSDF scheme. - Improved the performance of tools::LevelSetAdvection by up to five times. - Improved the performance of Tree::voxelizeActiveTiles by means of multithreading. - Improved the performance of tools::meshToVolume(), particularly for large narrow-band widths and for signed distance fields with dense interior regions. - Threaded the Tree destructor and the Tree::clear() method. - Added a parameter to tools::signedFloodFill() and to tools::signedFloodFillWithValues() to constrain the flood fill to specific levels of the tree. - Added active tile count to Tree::print. - Improved the API of tools::Dense with non-const access methods. - Added LeafManager::reduce and similar methods to NodeManager. [Contributed by Brett Tully] - Improved constructors of math::Mat3 and math::Mat4. - Added math::Mat3::cofactor(). - Added math::Mat3::setRows, math::Mat4::setRows, math::Mat3::setColumns Mat3::setColumns, and math::Mat4::setColumns. - Added util::NodeMask::isConstant method for faster bit processing. - For better robustness, tools::Prune now uses the median of voxel values when replacing voxels with a tile. - Added a toggle to tools::PointPartitioner to select between cell-centered and node-centered transforms. Bug fixes: - Fixed a bug in tools::LevelSetAdvection that could cause non-deterministic behavior. [Reported by Jeff Lait] - Fixed a bug that allowed for unexpected implicit conversion between grids of different value types. - Fixed a bug whereby the origins of leaf nodes with value type bool were ignored during equality comparisons. - tools::GridTransformer now correctly handles affine transforms with shear and/or reflection. - Fixed a bug in tools::meshToVolume() that could produce incorrect distances for large narrow-band widths. - Fixed a bug in tools::meshToVolume() that produced different results on machines with different core counts. - Fixed a threading bug in tools::compReplace() that could cause crashes. - Resolved a floating-point exception in math::QuantizedUnitVec::pack() caused by calling the method with a zero-length vector. [Contributed by Rick Hankins] - Fixed a potential threading bug in io::Queue. [Contributed by Josip Sumecki] - Fixed a possible division-by-zero bug in openvdb/tools/LevelSetAdvect.h. [Contributed by Rick Hankins] - Corrected the outer product method to not return the transpose result. [Contributed by Gergely Klar] - Fixed a memory overallocation issue in tools::VolumeAdvect. - Fix bug in tools::VolumeToMesh failing to clear its state when exiting early. [Contributed by Edward Lam] - Fixed bug in tools::PointIndexIterator::worldSpaceSearchAndUpdate that resulted in missing point indices. [Reported by Rick Hankins] - Fixed Windows build issues in unit tests. [Contributed by Edward Lam and Steven Caron] - Fixed isApproxZero() so that it works correctly when tolerance is zero. [Reported by Joshua Olson] - Fixed bugs in tree::NodeUnion that could cause crashes. - Fixed memory leak in a tools::meshToVolume sub-tool (expandNarrowband). [Reported by Kévin Dietrich] - Fixed parameter type inconsistencies in math/Stencils.h and tools/RayIntersector.h. [Contributed by Kévin Dietrich and Nick Avramoussis] - Fixed a bug in the VolumeToMesh tool that produced artifacts for adaptive surface extraction on clipped level sets. [Reported by Jeff Lait] - Corrected empty grid background value in tools::meshToVolume(). [Contributed by Jeff Lait] - Fixed a bug in tools::volumeToMesh that could produce NaNs. [Reported by Rick Hankins] - Fixed a bug in the "Advect Points SOP" that could cause a crash when the input grids were of incorrect type. [Reported by SideFX] API changes: - Deprecated math::Mat3::setBasis and math::Mat4::setBasis. - Renamed math::GudonovsNormSqrd to math::GodunovsNormSqrd [Contributed by Branislav Radjenovic] - Renamed ValueType to PosType in the PointArray interface. - Deprecated tree::Tree::addLeaf(LeafNode&) and added tree::Tree::addLeaf(LeafNode*). Python: - Updated the Python module for Python 3 compatibility. - Updated the Python module for Boost 1.60 compatibility, to address "no to_python (by-value) converter found" exceptions. Maya: - Fixed bugs related to data ownership, and improved error checking. [Contributed by Crawford Doran] - Updated the Read and Write DAG nodes to support file sequences and subframe evaluation. Houdini: - Added a Segment SOP that separates a grid's connected components into distinct grids. - Added a LOD SOP that produces a sequences of progressively lower resolution grids. - Added a Topology To Level Set SOP that generates a narrow-band signed distance field / level set from the interface between active and inactive voxels in an arbitrary grid. - Revamped the From Particles SOP UI and added a more efficient level set conversion method that supports Houdini 15 packed points. - Updated the Rasterize Points SOP with support for frustum transforms, sub region masking and orientation logic that matches the native Copy SOP's orientation. - Updated the Platonic SOP with support for all five Platonic solids. - Added hooks for registering SOP_NodeVDB text callbacks for different grid types. [Contributed by Nick Avramoussis] - The Resample and Combine SOPs now correctly handle affine transforms with shear and/or reflection. - Removed the StaggeredBoxSampler code path in SOP_OpenVDB_Advect because it introduces bias. [Contributed by Fredrik Salomonsson] - Fixed a bug in the Ray SOP whereby the distance attribute was created with the wrong data type. [Contributed by Nick Avramoussis] - The From Polygon SOP now allows the user to either specify the voxel count along an axis or the voxel size in world units (the only option in the past). Version 3.1.0 - October 1, 2015 Highlights: - New features: advection of arbitrary volumes, general-purpose preconditioned linear solver and Poisson solver, segmentation of topologically-enclosed regions of a volume, new and faster bitmask operators, concurrent paged array, volume diagnostics - Optimizations: threaded grid constructors and topology operations; faster mesh to volume conversion, SDF to fog volume conversion and grid pruning; faster, unbounded particle partitioning - New Houdini nodes: Advect, Diagnostics, Rasterize Points, Remap, Remove Divergence, Sort Points New features: - Added tools::VolumeAdvection, for sparse advection of non-level-set volumes. - Added a preconditioned conjugate gradient solver. - Added a Poisson solver for functions sampled on grids. - Added tools::extractEnclosedRegion, which detects topologically-enclosed (watertight) exterior regions (cavities) that can result from CSG union operations between level sets with concavities that are capped. (See the unit test TestPoissonSolver::testSolveWithSegmentDomain for an example in which this tool is used to identify regions of trapped fluid when solving for pressure in a volume of incompressible fluid.) - Added util::PagedArray, a concurrent, dynamic linear array data structure with fast O(1) value access (both random and sequential). - Added tools::Sampler, which provides a unified API for both staggered and non-staggered interpolation of various orders. - Added equality and inequality operators to Metadata and MetaMap. - Added tools::CheckLevelSet and tools::CheckFogVolume, which perform various tests on symmetric, narrow-band level sets and fog volumes, respectively, to diagnose potential issues. - Added support for value accessors that aren't registered with their trees. (Bypassing accessor registration can improve performance in rare cases but should be used with caution, since the accessor will be left in an invalid state if the tree topology is modified.) - Added a tree::stealNodes() method that transfers ownership of all nodes of a certain type and inserts them into a linear array. - Added a tools::createLevelSetBox() factory function for level-set grids. - Added tools::Dense::offsetToCoord(). - Added LeafNode::Buffer::data(), which provides direct access to a leaf node's voxel value array, avoiding out-of-core overhead. Use with caution. - Added a util::NodeMask::foreach() method for efficient evaluation of complex bitwise operations. - Added a bitwise difference method to util::NodeMask. - Added a -version flag to vdb_print, vdb_render and vdb_view. Improvements: - Deep, conversion and topology copy Grid constructors are now threaded and up to five times faster. - Grid::topologyUnion(), Grid::topologyIntersection() and Grid::topologyDifference() are now much faster due to threading. - Significantly improved the performance, parallel scaling and memory usage of the tools::meshToVolume(), and implemented a more robust inside/outside sign classification scheme. - Reimplemented tools::PointPartitioner for improved performance, concurrency and memory usage. The tool is now unbounded in the sense that points may be distributed anywhere in index space. - Significantly improved the performance of tools::sdfToFogVolume(). - Significantly improved the performance of the tools::sdfInteriorMask() and added support for both grid and tree inputs. - Made various optimizations and improvements to tools::LevelSetMorphing. - Aggregated tools::DiscreteField and tools::EnrightField (formerly in tools/LevelSetAdvect.h) and tools::VelocitySampler and tools::VelocityIntegrator (formerly in tools/PointAdvect.h) into a single header, tools/VelocityFields.h. - Modified tools::signedFloodFill() to accept grids of any signed scalar value type, not just floating-point grids. - tools::prune() is now faster, and it employs an improved compression technique on trees with floating-point values. Bug fixes: - Fixed a build issue that could result in spurious "Blosc encoding is not supported" errors unless OPENVDB_USE_BLOSC was #defined when compiling client code. - Added NaN and inf checks to tools::PointPartitioner. - Fixed a vdb_view issue whereby the frame buffer size did not necessarily match the window size. [Contributed by Rafael Campos] - Fixed a roundoff issue in tools::LevelSetTracker that could result in NaNs. - Changed tools::CheckNormGrad to check the magnitude of the gradient rather than the square of the magnitude. - Fixed parameter type inconsistencies in math/Ray.h and tools/RayIntersector.h. [Contributed by Kévin Dietrich] - Fixed incorrect handling of signed values in tools::clip() (and the Clip SOP). API changes: - Removed the math::Hermite class since it was no longer used and caused build issues for some. - Refactored the LevelSetAdvection, LevelSetFilter, LevelSetMeasure and LevelSetTracker tools. - Extended the API of tools::Diagnose and disabled copy construction. - Extended and unified the API of various Samplers. - Added an optional template argument to the ValueAccessor class to allow for unregistered accessors. Houdini: - Added a Rasterize Points SOP that produces density volumes and transfers arbitrary point attributes using a weighted-average scheme. The node incorporates a VOP subnetwork for procedural modeling, and its accompanying creation script defines a default network with VEX procedures for cloud and velocity field modeling. (See the creation script file header for installation details.) - Merged the Advect Level Set SOP into a new Advect SOP that supports advection of arbitrary volumes, not just level sets. - Added a Remove Divergence SOP that eliminates divergence from a velocity field. - Added a Diagnostics SOP that can identify various problems with level sets, fog volumes and other grids. - Added a Sort Points SOP that spatially reorders a list of points so that points that are close together in space are also close together in the list. This can improve CPU cache coherency and performance for random-access operations. - Added a Remap SOP that maps voxel values in an input range to values in an output range through a user-defined transfer function. - Added an option to the Convert SOP to activate interior voxels. [Contributed by SESI] - The To Spheres SOP can now optionally output a pscale attribute. - Added openvdb_houdini::SOP_NodeVDB::duplicateSourceStealable(), which in conjunction with the Unload flag can help to minimize deep copying of grids between nodes. The Advect, Convert, Fill, Filter, Fracture, Noise, Offset Level Set, Prune, Remap, Remove Divergence, Renormalize Level Set, Resize Narrow Band, Smooth Level Set and Transform SOPs all have this optimization enabled, meaning that they can potentially steal, rather than copy, data from upstream nodes that have the Unload flag enabled. [Contributed by Double Negative] - Redesigned the UI of the Visualize SOP and added toggles to draw with or without color, to use the grid name as the attribute name for points with values, and to attach grid index coordinates to points. - Added toggles to the Filter, Rebuild Level Set, Resize Narrow Band, Smooth Level Set and To Spheres SOPs to specify units in either world space or index space. - Fixed an issue whereby grids generated by the Rebuild Level Set SOP did not always display as surfaces in the viewport. - The Metadata SOP now sets appropriate viewport visualization options when the grid class is changed. Version 3.0.0 - January 14, 2015 - The io::File class now supports delayed loading of .vdb files, meaning that memory is not allocated for voxel values until the values are actually accessed. (This feature is enabled by default.) Until a grid has been fully loaded, its source .vdb file must not be modified or deleted, so for safety, io::File::open() automatically makes private copies of source files that are smaller than a user-specified limit (see io::File::setCopyMaxBytes()). The limit can be set to zero to disable copying, but if it cannot be guaranteed that a file will not be modified, then it is best not to enable delayed loading for that file. - .vdb files can now optionally be compressed with the Blosc LZ4 codec. Blosc compresses almost as well as ZLIB, but it is much faster. - Added tools::PointPartitioner, a tool for fast spatial sorting of points stored in an external array, and tools::PointIndexGrid, an acceleration structure for fast range and nearest-neighbor searches. - Added tree::NodeManager, which linearizes a tree to facilitate efficient multithreading across all tree levels. - Added tools::prune() (and other variants), which replaces and outperforms Tree::prune(). - Added tools::signedFloodFill(), which replaces and outperforms Tree::signedFloodFill(). - Added tools::changeBackground (and other variants), which replaces and outperforms Tree::setBackground(). - Added a fast but approximate narrow-band level set dilation method, a fast narrow-band level set erosion method, and a masked normalization method to tools::LevelSetTracker. - Added tools::Diagnose, which performs multithreaded diagnostics on grids to identify issues like values that are NaNs or out-of-range. It optionally generates a boolean grid of all values that fail user-defined tests. - Added optional alpha masks to tools::LevelSetMorphing. - Fixed an intermittent crash in tools::LevelSetMorphing. - Added tools::topologyToLevelSet(), which generates a level set from the implicit boundary between active and inactive voxels in an arbitrary input grid. [DWA internal] - Improved the performance of point scattering (by orders of magnitude) and added a DenseUniformPointScatter class as well as support for fractional numbers of particles per voxel. - Added edge-adjacent (6+12=18 neighbors) and vertex-adjacent (6+12+8=26 neighbors) dilation algorithms to tools::Morphology::dilateVoxels(). The default dilation pattern is still face-adjacent (6 neighbors). - Improved the performance and memory footprint of the ParticlesToLevelSet tool for large numbers (tens to hundreds of millions) of particles. - Added Tree::getNodes(), which allows for fast construction of linear arrays of tree nodes for use in multithreaded code such as the LeafManager or NodeManager. - Added math::Extrema and tools::extrema() to efficiently compute minimum and maximum values in a grid. - Added support for material color grids to all level set shaders, and added an option to vdb_render that allows one to specify a reference grid to be used for material color lookups. - Added openvdb::getLibraryVersionString() and OPENVDB_LIBRARY_VERSION_STRING. - Modified the mesh to volume converter to always set the grid background value to the exterior narrow-band width, and added finite value checks to narrow band parameters. - tools::volumeToMesh() now compiles for all grid types but throws an exception if the input grid does not have a scalar value type. - Added an io::File::readGrid() overload and readBuffers() overloads to the grid, tree and node classes that allow one to specify a bounding box against which to clip a grid while reading it. For large grids, clipping while reading can result in significantly lower memory usage than clipping after reading. - Added Grid::clipGrid(), which clips a grid against a world-space bounding box, and Grid::clip() and Tree::clip(), which clip against an index-space bounding box. - Added tools::clip(), which clips a grid either against a bounding box or against the active voxels of a mask grid. - io::File::readGridPartial() allocates the nodes of a grid's tree as before, but it now allocates leaf nodes without data buffers. (This feature is mainly for internal use; partially-read grids should be used with care if at all, and they should be treated as read-only.) - Grid names retrieved using an io::File::NameIterator now always uniquely identify grids; they no longer generate 'more than one grid named "x"' warnings when there are multiple grids of the same name in a file (for files written starting with this version of the OpenVDB library). - Fixed a bug in Tree::ValueOffIter that could cause depth-bounded iterators to return incorrect values. - Eliminated a recursive call in TreeValueIteratorBase::advance() that could cause crashes on systems with a limited stack size. - Fixed memory leaks in RootNode::topologyDifference() and RootNode::topologyIntersection(). - Fixed a memory leak in io::Queue when the queue was full and a write task could not be added within the timeout interval. - Fixed a potential division by zero crash in tools::compDiv() with integer-valued grids. - Fixed kernel normalization in tools::Filter so that it is correct for integer-valued grids. - Fixed a bug in LeafNode::Buffer::getValue() whereby Visual C++ would return a reference to a temporary. [Contributed by SESI] - Fixed a bug in tools::ParticlesToLevelSet related to attribute transfer when leaf nodes are produced without active values. - Added util/CpuTimer.h and removed the more simplistic CpuTimer from unittest/util.h. - Eliminated the use of getopt() for command-line argument parsing in vdb_test. - openvdb::initialize() now properly initializes log4cplus if it is enabled, eliminating "No appenders could be found" errors. - Fixed a bug in the QuantizedUnitVec::pack() method that caused quantization artifacts. - Added convenience class tools::AlphaMask to tools/Interpolation.h - Added constructors and methods to both math::RandInt and math::Rand01 to set and reset the random seed value. - Added convenience methods for transforming bounding boxes to math::Transform. - vdb_view is now compatible with both GLFW 2 and GLFW 3. - Made many small changes to address type conversion and other warnings reported by newer compilers like GCC 4.8 and ICC 14. - Replaced the HALF_INCL_DIR and HALF_LIB_DIR Makefile variables with ILMBASE_INCL_DIR and ILMBASE_LIB_DIR and added ILMBASE_LIB, to match OpenEXR's library organization. [Contributed by Double Negative] - Eliminated most local (function-scope) static variables, because Visual C++ doesn't guarantee thread-safe initialization of local statics. [Contributed by SESI] - Fixed a bug in readString() related to empty strings. [Contributed by Fabio Piparo] - Fixed a bug in the tools::VolumeToMesh simplification scheme that was creating visual artifacts. API changes: - The addition of a GridBase::readBuffers() virtual function overload and the GridBase::clip(), GridBase::readNonresidentBuffers() and Tree::clipUnallocatedNodes() virtual functions changes the grid ABI so that it is incompatible with earlier versions of the OpenVDB library (such as the ones in Houdini 12.5 and 13). Define the macro OPENVDB_2_ABI_COMPATIBLE when compiling OpenVDB to disable these changes and preserve ABI compatibility. - All shaders now have a template argument to specify the type of an optional material color grid, but the default type mimics the old, uniform color behavior. - Removed a deprecated io::Stream::write() overload. - The point counts in the UniformPointScatter and NonUniformPointScatter tools are now specified and returned as Index64. - math::RandInt has an extra template argument to specify the integer type. The RandomInt typedef is unchanged. - io::readData(), io::HalfReader::read() and io::HalfWriter::write() now take a uint32_t argument indicating the type of compression instead of a bool indicating whether compression is enabled. - Removed io::Archive::isCompressionEnabled() and io::Archive::setCompressionEnabled() and renamed io::Archive::compressionFlags() and io::Archive::setCompressionFlags() to io::Archive::compression() and io::Archive::setCompression(). - Internal and leaf node classes are now required to provide "PartialCreate" constructors that optionally bypass the allocation of voxel buffers. Leaf node classes must now also provide allocate() and isAllocated() methods to manage the allocation of their buffers. - Removed pruneInactive() and pruneLevelSet() methods from the Tree and various node classes. These methods have been replaced by the much faster pruning functions found in tools/Prune.h. - Removed signedFloodFill() methods from the Grid, Tree and various node classes. These methods have been replaced by the much faster functions found in tools/SignedFloodFill.h. - Removed Grid::setBackground() and Tree::setBackground() (use the faster changeBackground() tool instead), and removed the default argument from RootNode::setBackground(). Python: - Added grid methods convertToPolygons() and convertToQuads(), which convert volumes to meshes, and createLevelSetFromPolygons(), which converts meshes to volumes. NumPy is required. Maya: - Added an adaptive polygonal surface extraction node. Houdini: - Added a new Resize Narrow Band SOP that can efficiently adjust the width of a level set's narrow band. This allows, for example, for a level set to be created quickly from points or polygons with a very narrow band that is then quickly resized to a desired width. - Fixed bugs in the Smooth Level Set and Reshape Level Set SOPs that caused them to ignore the selected discretization scheme. - Added a Morph Level Set SOP. - Added a From Points SOP to very quickly generate a level set from a point cloud, ignoring any radius attribute. [DWA internal] - Added a Voxel Scale mode to the Resample SOP. - Improved the performance and memory footprint of the From Particles SOP for large numbers (tens to hundreds of millions) of particles. - The Scatter SOP now accepts fractional numbers of particles per voxel. - Improved the performance of the Scatter SOP by more than an order of magnitude. - The Clip SOP now has a toggle to choose explicitly between a mask grid or a bounding box as the clipping region. As a consequence, the mask grid can now be unnamed. - Added the OpenVDB library version number to the Extended Operator Information for all SOPs. - SOPs are now linked with an rpath to the directory containing the OpenVDB library. - Like the native Houdini file SOP, the Read SOP now allows missing frames to be reported either as errors or as warnings. - The Read SOP now has an optional input for geometry, the bounding box of which can be used to clip grids as they are read. For large grids, clipping while reading can result in significantly lower memory usage than clipping after reading. - The From Polygons and Convert SOPs now default to using the polygon soup mesh representation, which uses less memory. Version 2.3.0 - April 23, 2014 - Added tools::extractSparseTree(), which selectively extracts and transforms data from a dense grid to produce a sparse tree, and tools::extractSparseTreeWithMask(), which copies data from the index-space intersection of a sparse tree and a dense input grid. - Added copy constructors to the Grid, Tree, RootNode, InternalNode and LeafNode classes, and an assignment operator overload to RootNode, that allow the source and destination to have different value types. - Modified Tree::combine2() to permit combination of trees with different value types. - Added CanConvertType and RootNode::SameConfiguration metafunctions, which perform compile-time tests for value type and tree type compatibility, and a RootNode::hasCompatibleValueType() method, which does runtime checking. - Added optional support for logging using log4cplus. See logging.h and the INSTALL file for details. - Added VolumeRayIntersector::hits(), which returns all the hit segments along a ray. This is generally more efficient than repeated calls to VolumeRayIntersector::march(). - Added member class Ray::TimeSpan and method Ray::valid(), and deprecated method Ray::test(). - Fixed a bug in VolumeHDDA that could cause rendering artifacts when a ray's start time was zero. [Contributed by Mike Farnsworth] - Added tools::compositeToDense(), which composites data from a sparse tree into a dense array, using a sparse alpha mask. Over, Add, Sub, Min, Max, Mult, and Set are supported operations. - Added tools::transformDense(), which applies a functor to the value of each voxel of a dense grid within a given bounding box. - Improved the performance of node iterators. API changes: - Collected the digital differential analyzer code from math/Ray.h and tools/RayIntersector.h into a new header file, math/DDA.h. - Rewrote VolumeHDDA and made several changes to its API. (VolumeHDDA is used internally by VolumeRayIntersector, whose API is unchanged.) - Tree::combine2(), RootNode::combine2(), InternalNode::combine2(), LeafNode::combine2() and CombineArgs all now require an additional template argument, which determines the type of the other tree. - Assignment operators for LeafManager::LeafRange::Iterator, BaseMaskIterator, NodeMask and RootNodeMask now return references to the respective objects. - Removed a number of methods that were deprecated in version 2.0.0 or earlier. Houdini: - Added a Clip SOP, which does volumetric clipping. - Added an Occlusion Mask SOP, which generates a mask of the voxels inside a camera frustum that are occluded by objects in an input grid. - The Combine SOP now applies the optional signed flood fill only to level set grids, since that operation isn't meaningful for other grids. - The Filter SOP now processes all grid types, not just scalar grids. Version 2.2.0 - February 20, 2014 - Added a simple, multithreaded volume renderer, and added volume rendering support to the vdb_render command-line renderer. - Added an option to the LevelSetRayIntersector and to vdb_render to specify the isovalue of the level set. - Added methods to the LevelSetRayIntersector to return the time of intersection along a world or index ray and to return the level set isovalue. - Improved the performance of the VolumeRayIntersector and added support for voxel dilation to account for interpolation kernels. - Added a section to the Cookbook on interpolation using BoxSampler, GridSampler, DualGridSampler, et al. - Added a section to the Overview on grids and grid metadata. - Modified tools::DualGridSampler so it is more consistent with tools::GridSampler. - tools::cpt(), tools::curl(), tools::laplacian(), tools::meanCurvature() and tools::normalize() now output grids with appropriate vector types (covariant, contravariant, etc.). - Added tools::transformVectors(), which applies an affine transformation to the voxel values of a vector-valued grid in accordance with the grid's Vector Type and World Space/Local Space metadata setting. - Added tools::compDiv(), which combines grids by dividing the values of corresponding voxels. - Fixed a bug in the mean curvature computation that could produce NaNs in regions with constant values. - Added a Grid::topologyDifference() method. - Added exp() and sum() methods to math::Vec2, math::Vec3 and math::Vec4. - Improved tools::fillWithSpheres() for small volumes that are just a few voxels across. - Improved the accuracy of the mesh to volume converter. - Fixed a bug in the mesh to volume converter that caused incorrect sign classifications for narrow-band level sets. - Fixed a bug in NonlinearFrustumMap::applyIJT() that resulted in incorrect values when computing the gradient of a grid with a frustum transform. - Fixed a file I/O bug whereby some .vdb files could not be read correctly if they contained grids with more than two distinct inactive values. - Fixed an off-by-one bug in the numbering of unnamed grids in .vdb files. The first unnamed grid in a file is now retrieved using the name "[0]", instead of "[1]". - Fixed a build issue reported by Clang 3.2 in tools/GridOperators.h. - Fixed a memory leak in tools::Film. - Added library and file format version number constants to the Python module. - Improved convergence in the volume renderer. [Contributed by Jerry Tessendorf and Mark Matthews] - Made various changes for compatibility with Houdini 13 and with C++11 compilers. [Contributed by SESI] API changes: - tools::VolumeRayIntersector::march() no longer returns an int to distinguish tile vs. voxel hits. Instead, it now returns false if no intersection is detected and true otherwise. Also, t0 and t1 might now correspond to the first and last hits of multiple adjacent leaf nodes and/or active tiles. - tools::DualGridSampler is no longer templated on the target grid type, and the value accessor is now passed as an argument. - The .vdb file format has changed slightly. Tools built with older versions of OpenVDB should be recompiled to ensure that they can read files in the new format. Houdini: - Added topology union, intersection and difference operations to the Combine SOP. These operations combine the active voxel topologies of grids that may have different value types. - Added a Divide operation to the Combine SOP. - Added support for boolean grids to the Combine, Resample, Scatter, Prune and Visualize SOPs. - The Fill SOP now accepts a vector as the fill value, and it allows the fill region bounds to be specified either in index space (as before), in world space, or using the bounds of geometry connected to an optional new reference input. - Added a toggle to the Offset Level Set SOP to specify the offset in either world or voxel units. - Added a toggle to the Transform and Resample SOPs to apply the transform to the voxel values of vector-valued grids, in accordance with those grids' Vector Type and World Space/Local Space metadata settings. - Added a Vector Type menu to the Vector Merge SOP. - Removed masking options from the Renormalize SOP (since masking is not supported yet). - Reimplemented the Vector Merge SOP for better performance and interruptibility and to fix a bug in the handling of tile values. Version 2.1.0 - December 12, 2013 - Added a small number of Maya nodes, primarily for conversion of geometry to and from OpenVDB volumes and for visualization of volumes. - Added an initial implementation of level set morphing (with improvements to follow soon). - Added tools::LevelSetMeasure, which efficiently computes the surface area, volume and average mean-curvature of narrow-band level sets, in both world and voxel units. Those quantities are now exposed as intrinsic attributes on the Houdini VDB primitive and can be queried using the native Measure SOP. - tools::Dense now supports the XYZ memory layout used by Houdini and Maya in addition to the ZYX layout used in OpenVDB trees. - Improved the performance of masking in the level set filter tool and added inversion and scaling of the mask input, so that any scalar-valued volume can be used as a mask, not just volumes with a [0, 1] range. - Added optional masking to the non-level-set filters, to the grid operators (CPT, curl, divergence, gradient, Laplacian, mean curvature, magnitude, and normalize) and to the Analysis and Filter SOPs. - Added more narrow band controls to the Rebuild Level Set SOP. - Improved the accuracy of the level set rebuild tool. - Added tools::activate() and tools::deactivate(), which set the active states of tiles and voxels whose values are equal to or approximately equal to a given value, and added a Deactivate Background Voxels toggle to the Combine SOP. - Added math::BBox::applyMap() and math::BBox::applyInverseMap(), which allow for transformation of axis-aligned bounding boxes. - Added a position shader to the level set ray-tracer (primarily for debugging purposes). - Added an io::Queue class that manages a concurrent queue for asynchronous serialization of grids to files or streams. - Fixed a bug in io::Archive whereby writing unnamed, instanced grids (i.e., grids sharing a tree) to a file rendered the file unreadable. - Fixed a bug in the volume to mesh converter that caused it to generate invalid polygons when the zero crossing lay between active and inactive regions. - Fixed a bug in the point scatter tool (and the Scatter SOP) whereby the last voxel always remained empty. - Fixed a bug in the Read SOP that caused grids with the same name to be renamed with a numeric suffix (e.g., "grid[1]", "grid[2]", etc.). - Fixed some unit test failures on 64-bit Itanium machines. API changes: - The Filter tool is now templated on a mask grid, and threading is controlled using a grain size, for consistency with most of the other level set tools. - The level set filter tool is now templated on a mask grid. - All shaders now take a ray direction instead of a ray. Version 2.0.0 - October 31, 2013 - Added a Python module with functions for basic manipulation of grids (but no tools, yet). - Added ray intersector tools for efficient, hierarchical intersection of rays with level-set and generic volumes. - Added a Ray class and a hierarchical Digital Differential Analyzer for fast ray traversal. - Added a fully multithreaded level set ray tracer and camera classes that mimic Houdini's cameras. - Added a simple, command-line renderer (currently for level sets only). - Implemented a new meshing scheme that produces topologically robust two-manifold meshes and is twice as fast as the previous scheme. - Implemented a new, topologically robust (producing two-manifold meshes) level-set-based seamless fracture scheme. The new scheme eliminates visible scarring seen in the previous implementation by subdividing internal, nonplanar quads near fracture seams. In addition, fracture seam points are now tagged, allowing them to be used to drive pre-fracture dynamics such as local surface buckling. - Improved the performance of Tree::evalActiveVoxelBoundingBox() and Tree::activeVoxelCount(), and significantly improved the performance of Tree::evalLeafBoundingBox() (by about 30x). - Added a tool (and a Houdini SOP) that fills a volume with adaptively-sized overlapping or non-overlapping spheres. - Added a Ray SOP that can be used to perform geometry projections using level-set ray intersections or closest-point queries. - Added a tool that performs accelerated closest surface point queries from arbitrary points in world space to narrow-band level sets. - Increased the speed of masked level set filtering by 20% for the most common cases. - Added math::BoxStencil, with support for trilinear interpolation and gradient computation. - Added Tree::topologyIntersection(), which intersects a tree's active values with those of another tree, and Tree::topologyDifference(), which performs topological subtraction of one tree's active values from another's. In both cases, the ValueTypes of the two trees need not be the same. - Added Tree::activeTileCount(), which returns the number of active tiles in a tree. - Added math::MinIndex() and math::MaxIndex(), which find the minimum and maximum components of a vector without any branching. - Added math::BBox::minExtent(), which returns a bounding box's shortest axis. - The default math::BBox constructor now generates an invalid bounding box rather than an empty bounding box positioned at the origin. The new behavior is consistent with math::CoordBBox. [Thanks to Rick Hankins for suggesting this fix.] - Added CoordBBox::reset(), which resets a bounding box to its initial, invalid state. - Fixed a bug in the default ScaleMap constructor that left some data used in the inverse uninitialized. - Added MapBase::applyJT(), which applies the Jacobian transpose to a vector (the Jacobian transpose takes a range-space vector to a domain-space vector, e.g., world to index), and added MapBase::inverseMap(), which returns a new map representing the inverse of the original map (except for NonlinearFrustumMap, which does not currently have a defined inverse map). Note: Houdini 12.5 uses an earlier version of OpenVDB, and maps created with that version lack virtual table entries for these new methods, so do not call these methods from Houdini 12.5. - Reimplemented math::RandomInt using Boost.Random instead of rand() (which is not thread-safe), and deprecated math::randUniform() and added math::Random01 to replace it. - Modified tools::copyFromDense() and tools::copyToDense() to allow for implicit type conversion (e.g., between a Dense and a FloatTree) and fixed several bugs in tools::CopyFromDense. - Fixed bugs in math::Stats and math::Histogram that could produce NaNs or other incorrect behavior if certain methods were called on populations of size zero. - Renamed tolerance to math::Tolerance and negative() to math::negative() and removed math::toleranceValue(). - Implemented a closest point on line segment algorithm, math::closestPointOnSegmentToPoint(). - Fixed meshing issues relating to masking and automatic partitioning. - Grid::merge() and Tree::merge() now accept an optional MergePolicy argument that specifies one of three new merging schemes. (The old merging scheme, which is no longer available, used logic for each tree level that was inconsistent with the other levels and that could result in active tiles being replaced with nodes having only inactive values.) - Renamed LeafNode::coord2offset(), LeafNode::offset2coord() and LeafNode::offset2globalCoord() to coordToOffset(), offsetToLocalCoord() and offsetToGlobalCoord(), respectively, and likewise for InternalNode. [Thanks to Rick Hankins for suggesting this change.] - Replaced Tree methods setValueOnMin(), setValueOnMax() and setValueOnSum() with tools::setValueOnMin(), tools::setValueOnMax() and tools::setValueOnSum() (and a new tools::setValueOnMult()) and added Tree::modifyValue() and Tree::modifyValueAndActiveState(), which modify voxel values in place via user-supplied functors. Similarly, replaced ValueAccessor::setValueOnSum() with ValueAccessor::modifyValue() and ValueAccessor::modifyValueAndActiveState(), and added a modifyValue() method to all value iterators. - Removed LeafNode::addValue() and LeafNode::scaleValue(). - Added convenience classes Tree3 and Tree5 for custom tree configurations. - Added an option to the From Particles SOP to generate an alpha mask, which can be used to constrain level set filtering so as to preserve surface details. - The mesh to volume converter now handles point-degenerate polygons. - Fixed a bug in the Level Set Smooth, Level Set Renormalize and Level Set Offset SOPs that caused the group name to be ignored. - Fixed various OS X and Windows build issues. [Contributions from SESI and DD] Version 1.2.0 - June 28, 2013 - Level set filters now accept an optional alpha mask grid. - Implemented sharp feature extraction for level set surfacing. This enhances the quality of the output mesh and reduces aliasing artifacts. - Added masking options to the meshing tools, as well as a spatial multiplier for the adaptivity threshold, automatic partitioning, and the ability to preserve edges and corners when mesh adaptivity is applied. - The mesh to volume attribute transfer scheme now takes surface orientation into account, which improves accuracy in proximity to edges and corners. - Added a foreach() method to tools::LeafManager that, like tools::foreach(), applies a user-supplied functor to each leaf node in parallel. - Rewrote the particle to level set converter, simplifying the API, improving performance (especially when particles have a fixed radius), adding the capability to transfer arbitrary point attributes, and fixing a velocity trail bug. - Added utility methods Sign(), SignChange(), isApproxZero(), Cbrt() and ZeroCrossing() to math/Math.h. - Added a probeNode() method to the value accessor and to tree nodes that returns a pointer to the node that contains a given voxel. - Deprecated LeafNode::addValue() and LeafNode::scaleValue(). - Doubled the speed of the mesh to volume converter (which also improves the performance of the fracture and level set rebuild tools) and improved its inside/outside voxel classification near edges and corners. - tools::GridSampler now accepts either a grid, a tree or a value accessor, and it offers faster index-based access methods and much better performance in cases where many instances are allocated. - Extended tools::Dense to make it more compatible with existing tools. - Fixed a crash in io::Archive whenever the library was unloaded from memory and then reloaded. [Contributed by Ollie Harding] - Fixed a bug in GU_PrimVDB::buildFromPrimVolume(), seen during the conversion from Houdini volumes to OpenVDB grids, that could cause signed flood fill to be applied to non-level set grids, resulting in active tiles with incorrect values. - Added a Prune SOP with several pruning schemes. Version 1.1.1 - May 10 2013 - Added a simple dense grid class and tools to copy data from dense voxel arrays into OpenVDB grids and vice-versa. - Starting with Houdini 12.5.396, plugins built with this version of OpenVDB can coexist with native Houdini OpenVDB nodes. - The level set fracture tool now smooths seam line edges during mesh extraction, eliminating staircase artifacts. - Significantly improved the performance of the util::leafTopologyIntersection() and util::leafTopologyDifference() utilities and added a LeafNode::topologyDifference() method. - Added convenience functions that provide simplified interfaces to the mesh to volume and volume to mesh converters. - Added a tools::accumulate() function that is similar to tools::foreach() but can be used to accumulate the results of computations over the values of a grid. - Added tools::statistics(), tools::opStatistics() and tools::histogram(), which efficiently compute statistics (mean, variance, etc.) and histograms of grid values (using math::Stats and math::Histogram). - Modified CoordBBox to adhere to TBB's splittable type requirements, so that, for example, a CoordBBox can be used as a blocked iteration range. - Added Tree::addTile(), Tree::addLeaf() and Tree::stealNode(), for fine control over tree construction. - Addressed a numerical stability issue when performing Gaussian filtering of level set grids. - Changed the return type of CoordBBox::volume() to reduce the risk of overflow. - When the input mesh is self-intersecting, the mesh to volume converter now produces a level set with a monotonic gradient field. - Fixed a threading bug in the mesh to volume converter that caused it to produce different results for the same input. - Fixed a bug in the particle to level set converter that prevented particles with zero velocity from being rasterized in Trail mode. - Added an optional input to the Create SOP into which to merge newly-created grids. - Fixed a bug in the Resample SOP that caused it to produce incorrect narrow-band widths when resampling level set grids. - Fixed a bug in the To Polygons SOP that caused intermittent crashes when the optional reference input was connected. - Fixed a bug in the Advect Level Set SOP that caused a crash when the velocity input was connected but empty. - The Scatter and Sample Point SOPs now warn instead of erroring when given empty grids. - Fixed a crash in vdb_view when stepping through multiple grids after changing render modes. - vdb_view can now render fog volumes and vector fields, and it now features interactively adjustable clipping planes that enable one to view the interior of a volume. Version 1.1.0 - April 4 2013 - The resampleToMatch() tool, the Resample SOP and the Combine SOP now use level set rebuild to correctly and safely resample level sets. Previously, scaling a level set would invalidate the signed distance field, leading to holes and other artifacts. - Added a mask-based topological erosion tool, and rewrote and simplified the dilation tool. - The LevelSetAdvection tool can now advect forward or backward in time. - Tree::pruneLevelSet() now replaces each pruned node with a tile having the inside or outside background value, instead of arbitrarily selecting one of the node's tile or voxel values. - When a grid is saved to a file with saveFloatAsHalf() set to true, the grid's background value is now also quantized to 16 bits. (Not quantizing the background value caused a mismatch with the values of background tiles.) - As with tools::foreach(), it is now possible to specify whether functors passed to tools::transformValues() should be shared across threads. - tree::LeafManager can now be instantiated with a const tree, although buffer swapping with const trees is disabled. - Added a Grid::signedFloodFill() overload that allows one to specify inside and outside values. - Fixed a bug in Grid::setBackground() so that now only the values of inactive voxels change. - Fixed Grid::topologyUnion() so that it actually unions tree topology, instead of just the active states of tiles and voxels. The previous behavior broke multithreaded code that relied on input and output grids having compatible tree topology. - math::Transform now includes an isIdentity() predicate and methods to pre- and postmultiply by a matrix. - Modified the node mask classes to permit octree-like tree configurations (i.e., with a branching factor of two) and to use 64-bit operations instead of 32-bit operations. - Implemented a new, more efficient closest point on triangle algorithm. - Implemented a new vertex normal scheme in the volume to mesh converter, and resolved some overlapping polygon issues. - The volume to mesh converter now meshes not just active voxels but also active tiles. - Fixed a bug in the mesh to volume converter that caused unsigned distance field conversion to produce empty grids. - Fixed a bug in the level set fracture tool whereby the cutter overlap toggle was ignored. - Fixed an infinite loop bug in vdb_view. - Updated vdb_view to use the faster and less memory-intensive OpenVDB volume to mesh converter instead of marching cubes, and rewrote the shader to be OpenGL 3.2 and GLSL 1.2 compatible. - Given multiple input files or a file containing multiple grids, vdb_view now displays one grid at a time. The left and right arrow keys cycle between grids. - The To Polygons SOP now has an option to associate the input grid's name with each output polygon. Version 1.0.0 - March 14 2013 - tools::levelSetRebuild() now throws an exception when given a non-scalar or non-floating-point grid. - The tools in tools/GridOperators.h are now interruptible, as is the Analysis SOP. - Added a leaf node iterator and a TBB-compatible range class to the LeafManager. - Modified the VolumeToMesh tool to handle surface topology issues around fracture seam lines. - Modified the Makefile to allow vdb_view to compile on OS X systems (provided that GLFW is available). - Fixed a bug in the Create SOP that resulted in "invalid parameter name" warnings. - The Combine SOP now optionally resamples the A grid into the B grid's index space (or vice-versa) if the A and B transforms differ. - The Vector Split and Vector Merge SOPs now skip inactive voxels by default, but they can optionally be made to include inactive voxels, as they did before. - The LevelSetFracture tool now supports custom rotations for each cutter instance, and the Fracture SOP now uses quaternions to generate uniformly-distributed random rotations. Version 0.104.0 - February 15 2013 - Added a tool and a SOP to rebuild a level set from any scalar volume. - .vdb files are now saved using a mask-based compression scheme that is an order of magnitude faster than ZLIB and produces comparable file sizes for level set and fog volume grids. (ZLIB compression is still enabled by default for other classes of grids). - The Filter and LevelSetFilter tools now include a Gaussian filter, and mean (box) filtering is now 10-50x faster. - The isosurface meshing tool is now more robust (to level sets with one voxel wide narrow bands, for example). - Mesh to volume conversion is on average 1.5x faster and up to 5.5x faster for high-resolution meshes where the polygon/voxel size ratio is small. - Added createLevelSet() and createLevelSetSphere() factory functions for level set grids. - tree::ValueAccessor is now faster for trees of height 2, 3 and 4 (the latter is the default), and it now allows one to specify, via a template argument, the number of node levels to be cached, which can also improve performance in special cases. - Added a toggle to tools::foreach() to specify whether or not the functor should be shared across threads. - Added Mat4s and Mat4d metadata types. - Added explicit pre- and postmultiplication methods to the Transform, Map and Mat4 classes and deprecated the old accumulation methods. - Modified NonlinearFrustumMap to be more compatible with Houdini's frustum transform. - Fixed a GridTransformer bug that caused it to translate the output grid incorrectly in some cases. - Fixed a bug in the tree-level LeafIterator that resulted in intermittent crashes in tools::dilateVoxels(). - The Hermite data type and Hermite grids are no longer supported. - Added tools/GridOperators.h, which includes new, cleaner implementations of the Cpt, Curl, Divergence, Gradient, Laplacian, Magnitude, MeanCurvature and Normalize tools. - Interrupt support has been improved in several tools, including tools::ParticlesToLevelSet. - Simplified the API of the Stencil class and added an intersects() method to test for intersection with a specified isovalue. - Renamed voxelDimensions to voxelSize in transform classes and elsewhere. - Deprecated houdini_utils::ParmFactory::setChoiceList() in favor of houdini_utils::ParmFactory::setChoiceListItems(), which requires a list of token, label string pairs. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Fixed a bug in houdini_utils::getNodeChain() that caused the Offset Level Set, Smooth Level Set and Renormalize Level Set SOPs to ignore frame changes. [Contributed by SESI] - The From Particles SOP now provides the option to write into an existing grid. - Added a SOP to edit grid metadata. - The Fracture SOP now supports multiple cutter objects. - Added a To Polygons SOP that complements the Fracture SOP and allows for elimination of seam lines, generation of correct vertex normals and grouping of polygons when surfacing fracture fragments, using the original level set or mesh as a reference. Version 0.103.1 - January 15 2013 - tree::ValueAccessor read operations are now faster for four-level trees. (Preliminary benchmark tests suggest a 30-40% improvement.) - For vector-valued grids, tools::compMin() and tools::compMax() now compare vector magnitudes instead of individual components. - Migrated grid sampling code to a new file, Interpolation.h, and deprecated old files and classes. - Added a level-set fracture tool and a Fracture SOP. - Added tools::sdfInteriorMask(), which creates a mask of the interior region of a level set grid. - Fixed a bug in the mesh to volume converter that produced unexpected nonzero values for voxels at the intersection of two polygons, and another bug that produced narrow-band widths that didn't respect the background value when the half-band width was less than three voxels. - houdini_utils::ParmFactory can now correctly generate ramp multi-parms. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - The Convert SOP can now convert between signed distance fields and fog volumes and from volumes to meshes. [Contributed by SESI] - For level sets, the From Mesh and From Particles SOPs now match the reference grid's narrow-band width. - The Scatter SOP can now optionally scatter points in the interior of a level set. Version 0.103.0 - December 21 2012 - The mesh to volume converter is now 60% faster at generating level sets with wide bands, and the From Mesh SOP is now interruptible. - Fixed a threading bug in the recently-added compReplace() tool that caused it to produce incorrect output. - Added a probeConstLeaf() method to the Tree, ValueAccessor and node classes. - The Houdini VDB primitive doesn't create a "name" attribute unnecessarily (i.e., if its grid's name is empty), but it now correctly allows the name to be changed to the empty string. - Fixed a crash in the Vector Merge SOP when fewer than three grids were merged. - The From Particles SOP now features a "maximum half-width" parameter to help avoid runaway computations. Version 0.102.0 - December 13 2012 - Added tools::compReplace(), which copies the active values of one grid into another, and added a "Replace A With Active B" mode to the Combine SOP. - Grid::signedFloodFill() no longer enters an infinite loop when filling an empty grid. - Fixed a bug in the particle to level set converter that sometimes produced level sets with holes, and fixed a bug in the SOP that could result in random output. - Fixed an issue in the frustum preview feature of the Create SOP whereby rendering very large frustums could cause high CPU usage. - Added streamline support to the constrained advection scheme in the Advect Points SOP. - Added an Advect Level Set SOP. Version 0.101.1 - December 11 2012 (DWA internal release) - Partially reverted the Houdini VDB primitive's grid accessor methods to their pre-0.98.0 behavior. A primitive's grid can once again be accessed by shared pointer, but now also by reference. Accessor methods for grid metadata have also been added, and the primitive now ensures that metadata and transforms are never shared. - Fixed an intermittent crash in the From Particles SOP. Version 0.101.0 - December 6 2012 (DWA internal release) - Partially reverted the Grid's tree and transform accessor methods to their pre-0.98.0 behavior, eliminating copy-on-write but preserving their return-by-reference semantics. These methods are now supplemented with a suite of shared pointer accessors. - Restructured the mesh to volume converter for a 40% speedup and to be more robust to non-manifold geometry, to better preserve sharp features, to support arbitrary tree configurations and to respect narrow-band limits. - Added a getNodeBoundingBox() method to RootNode, InternalNode and LeafNode that returns the index space spanned by a node. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Renamed the Reshape Level Set SOP to Offset Level Set. - Fixed a crash in the Convert SOP and added support for conversion of empty grids. Version 0.100.0 - November 30 2012 (DWA internal release) - Greatly improved the performance of the level set to fog volume converter. - Improved the performance of the median filter and of level set CSG operations. - Reintroduced Tree::pruneLevelSet(), a specialized pruneInactive() for level-set grids. - Added utilities to the houdini_utils library to facilitate the collection of a chain of adjacent nodes of a particular type so that they can be cooked in a single step. (For example, adjacent xform SOPs could be collapsed by composing their transformation matrices into a single matrix.) - Added pruning and flood-filling options to the Convert SOP. - Reimplemented the Filter SOP, omitting level-set-specific filters and adding node chaining (to reduce memory usage when applying several filters in sequence). - Added a toggle to the Read SOP to read grid metadata and transforms only. - Changed the attribute transfer scheme on the From Mesh and From Particles SOPs to allow for custom grid names and vector type metadata. Version 0.99.0 - November 21 2012 - Added Grid methods that return non-const Tree and Transform references without triggering deep copies, as well as const methods that return const shared pointers. - Added Grid methods to populate a grid's metadata with statistics like the active voxel count, and to retrieve that metadata. By default, statistics are now computed and added to grids whenever they are written to .vdb files. - Added io::File::readGridMetadata() and io::File::readAllGridMetadata() methods to read just the grid metadata and transforms from a .vdb file. - Fixed numerical precision issues in the csgUnion, csgIntersection and csgDifference tools, and added toggles to optionally disable postprocess pruning. - Fixed an issue in vdb_view with the ordering of GL vertex buffer calls. [Contributed by Bill Katz] - Fixed an intermittent crash in the ParticlesToLevelSet tool, as well as a race condition that could cause data corruption. - The ParticlesToLevelSet tool and From Particles SOP can now transfer arbitrary point attribute values from the input particles to output voxels. - Fixed a bug in the Convert SOP whereby the names of primitives were lost during conversion, and another bug that resulted in an arithmetic error when converting an empty grid. - Fixed a bug in the Combine SOP that caused the Operation selection to be lost. Version 0.98.0 - November 16 2012 - Tree and Transform objects (and Grid objects in the context of Houdini SOPs) are now passed and accessed primarily by reference rather than by shared pointer. See the online documentation for details about this important API change. [Contributed by SESI] - Reimplemented CoordBBox to address several off-by-one bugs related to bounding box dimensions. - Fixed an off-by-one bug in Grid::evalActiveVoxelBoundingBox(). - Introduced the LeafManager class, which will eventually replace the LeafArray class. LeafManager supports dynamic buffers stored as a structure of arrays (SOA), unlike LeafArray, which supports only static buffers stored as an array of structures (AOS). - Improved the performance of the LevelSetFilter and LevelSetTracker tools by rewriting them to use the new LeafManager class. - Added Tree and ValueAccessor setValueOnly() methods, which change the value of a voxel without changing its active state, and Tree and ValueAccessor probeLeaf() methods that return the leaf node that contains a given voxel (unless the voxel is represented by a tile). - Added a LevelSetAdvection tool that propagates and tracks narrow-band level sets. - Introduced a new GridSampler class that supports world-space (or index-space) sampling of grid values. - Changed the interpretation of the NonlinearFrustumMap's taper parameter to be the ratio of the near and far plane depths. - Added a ParmFactory::setChoiceList() overload that accepts (token, label) string pairs, and a setDefault() overload that accepts an STL string. - Fixed a crash in the Combine SOP in Copy B mode. - Split the Level Set Filter SOP into three separate SOPs, Level Set Smooth, Level Set Reshape and Level Set Renormalize. When two or more of these nodes are connected in sequence, they interact to reduce memory usage: the last node in the sequence performs all of the operations in one step. - The Advect Points SOP can now output polyline streamlines that trace the paths of the points. - Added an option to the Analysis SOP to specify names for output grids. - Added camera-derived frustum transform support to the Create SOP. Version 0.97.0 - October 18 2012 - Added a narrow-band level set interface tracking tool (up to fifth-order in space but currently only first-order in time, with higher temporal orders to be added soon). - Added a level set filter tool to perform unrestricted surface smoothing (e.g., Laplacian flow), filtering (e.g., mean value) and morphological operations (e.g., morphological opening). - Added adaptivity to the level set meshing tool for faster mesh extraction with fewer polygons, without postprocessing. - Added a ValueAccessor::touchLeaf() method that creates (if necessary) and returns the leaf node containing a given voxel. It can be used to preallocate leaf nodes over which to run parallel algorithms. - Fixed a bug in Grid::merge() whereby active tiles were sometimes lost. - Added LeafManager, which is similar to LeafArray but supports a dynamic buffer count and allocates buffers more efficiently. Useful for temporal integration (e.g., for level set propagation and interface tracking), LeafManager is meant to replace LeafArray, which will be deprecated in the next release. - Added a LeafNode::fill() method to efficiently populate leaf nodes with constant values. - Added a Tree::visitActiveBBox() method that applies a functor to the bounding boxes of all active tiles and leaf nodes and that can be used to improve the performance of ray intersection tests, rendering of bounding boxes, etc. - Added a Tree::voxelizeActiveTiles() method to densify active tiles. While convenient and fast, this can produce large dense grids, so use it with caution. - Repackaged Tree::pruneLevelSet() as a Tree::pruneOp()-compatible functor. LevelSetPrune is a specialized pruneInactive() for level-set grids and is used in interface tracking. - Added a GridBase::pruneGrid() method. - Added a Grid:hasUniformVoxels() method. - Renamed tools::dilate() to tools::dilateVoxels() and improved its performance. The new name reflects the fact that the current implementation ignores active tiles. - Added a tools::resampleToMatch() function that resamples an input grid into an output grid with a different transform such that, after resampling, the input and output grids coincide, but the output grid's transform is preserved. - Significantly improved the performance of depth-bounded value iterators (ValueOnIter, ValueAllIter, etc.) when the depth bound excludes leaf nodes. - Exposed the value buffers inside leaf nodes with LeafNode::buffer(). This allows for very fast access (const and non-const) to voxel values using linear array offsets instead of (i,j,k) coordinates. - In openvdb_houdini/UT_VDBTools.h, added operators for use with processTypedGrid() that resample grids in several different ways. - Added a policy mechanism to houdini_utils::OpFactory that allows for customization of operator names, icons, and Help URLs. - Renamed many of the Houdini SOPs to make the names more consistent. - Added an Advect Points SOP. - Added a Level Set Filter SOP that allows for unrestricted surface deformations, unlike the older Filter SOP, which restricts surface motion to the initial narrow band. - Added staggered vector sampling to the Sample Points SOP. - Added a minimum radius threshold to the particle voxelization tool and SOP. - Merged the Composite and CSG SOPs into a single Combine SOP. - Added a tool and a SOP to efficiently generate narrow-band level set representations of spheres. - In the Visualize SOP, improved the performance of tree topology generation, which is now enabled by default. Version 0.96.0 - September 24 2012 - Fixed a memory corruption bug in the mesh voxelizer tool. - Temporarily removed the optional clipping feature from the level set mesher. - Added "Staggered Vector Field" to the list of grid classes in the Create SOP. Version 0.95.0 - September 20 2012 - Added a quad meshing tool for higher-quality level set meshing and updated the Visualizer SOP to use it. - Fixed a precision error in the mesh voxelizer and improved the quality of inside/outside voxel classification. Output grids are now also tagged as either level sets or fog volumes. - Modified the GridResampler to use the signed flood fill optimization only on grids that are tagged as level sets. - Added a quaternion class to the math library and a method to return the trace of a Mat3. - Fixed a bug in the ValueAccessor copy constructor that caused the copy to reference the original. - Fixed a bug in RootNode::setActiveState() that caused a crash when marking a (virtual) background voxel as inactive. - Added a Tree::pruneLevelSet() method that is similar to but faster than pruneInactive() for level set grids. - Added fast leaf node voxel access methods that index by linear offset (as returned by ValueIter::pos()) instead of by (i, j, k) coordinates. - Added a Tree::touchLeaf() method that can be used to preallocate a static tree topology over which to safely perform multithreaded processing. - Added a grain size argument to the LeafArray class for finer control of parallelism. - Modified the Makefile to make it easier to omit the doc, vdb_test and vdb_view targets. - Added utility functions (in houdini/UT_VDBUtils.h) to convert between Houdini and OpenVDB matrix and vector types. [Contributed by SESI] - Added accessors to GEO_PrimVDB that make it easier to directly access voxel data and that are used by the HScript volume expression functions in Houdini 12.5. [Contributed by SESI] - As of Houdini 12.1.77, the native transform SOP operates on OpenVDB primitives. [Contributed by SESI] - Added a Convert SOP that converts OpenVDB grids to Houdini volumes and vice-versa. Version 0.94.1 - September 7 2012 - Fixed bugs in RootNode and InternalNode setValue*() and fill() methods that could cause neighboring voxels to become inactive. - Fixed a bug in Tree::hasSameTopology() that caused false positives when only active states and not values differed. - Added a Tree::hasActiveTiles() method. - For better cross-platform consistency, substituted bitwise AND operations for right shifts in the ValueAccessor hash key computation. - vdb_view no longer aborts when asked to surface a vector-valued grid--but it still doesn't render the surface. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Added an option to the MeshVoxelizer SOP to convert both open and closed surfaces to unsigned distance fields. - The Filter SOP now allows multiple filters to be applied in user-specified order. Version 0.94.0 - August 30 2012 - Added a method to union just the active states of voxels from one grid with those of another grid of a possibly different type. - Fixed an incorrect scale factor in the Laplacian diffusion filter. - Fixed a bug in Tree::merge that could leave a tree with invalid value accessors. - Added TreeValueIteratorBase::setActiveState() and deprecated setValueOn(). - Removed tools/FastSweeping.h. It will be replaced with a much more efficient implementation in the near future. - ZLIB compression of .vdb files is now optional, but enabled by default. [Contributed by SESI] - Made various changes for Clang and Visual C++ compatibility. [Contributed by SESI] - The MeshVoxelizer SOP can now transfer arbitrary point and primitive attribute values from the input mesh to output voxels. Version 0.93.0 - August 24 2012 - Renamed symbols in math/Operators.h to avoid ambiguities that GCC 4.4 reports as errors. - Simplified the API for the stencil version of the closest-point transform operator. - Added logic to io::Archive::readGrid() to set the grid name metadata from the descriptor if the metadata doesn't already exist. - Added guards to prevent nesting of openvdb_houdini::Interrupter::start() and end() calls. Version 0.92.0 - August 23 2012 - Added a Laplacian diffusion filter. - Fixed a bug in the initialization of the sparse contour tracer that caused mesh-to-volume conversion to fail in certain cases. - Fixed a bug in the curvature stencil that caused mean curvature filtering to produce wrong results. - Increased the speed of the GridTransformer by as much as 20% for fog volumes. - Added optional pruning to the Resample SOP. - Modified the PointSample SOP to allow it to work with ungrouped, anonymous grids. - Fixed a crash in the LevelSetNoise SOP. Version 0.91.0 - August 16 2012 - tools::GridTransformer and tools::GridResampler now correctly (but not yet efficiently) process tiles in sparse grids. - Added an optional CopyPolicy argument to GridBase::copyGrid() and to Grid::copy() that specifies whether and how the grid's tree should be copied. - Added a GridBase::newTree() method that replaces a grid's tree with a new, empty tree of the correct type. - Fixed a crash in Tree::setValueOff() when the new value was equal to the background value. - Fixed bugs in Tree::prune() that could result in output tiles with incorrect active states. - Added librt to the link dependencies to address build failures on Ubuntu systems. - Made various small changes to the Makefile and the source code that should help with Mac OS X compatibility. - The Composite and Resample SOPs now correctly copy the input grid's metadata to the output grid. Version 0.90.1 - August 7 2012 - Fixed a bug in the BBox::getCenter() method. - Added missing header files to various files. - io::File::NameIterator::gridName() now returns a unique name of the form "name[1]", "name[2]", etc. if a file contains multiple grids with the same name. - Fixed a bug in the Writer SOP that caused grid names to be discarded. - The Resample SOP now correctly sets the background value of the output grid. Version 0.90.0 - August 3 2012 (initial public release) - Added a basic GL viewer for OpenVDB files. - Greatly improved the performance of two commonly-used Tree methods, evalActiveVoxelBoundingBox() and memUsage(). - Eliminated the GridMap class. File I/O now uses STL containers of grid pointers instead. - Refactored stencil-based tools (Gradient, Laplacian, etc.) and rewrote some of them for generality and better performance. Most now behave correctly for grids with nonlinear index-to-world transforms. - Added a library of index-space finite difference operators. - Added a "Hermite" grid type that compactly stores each voxel's upwind normals and can be used to convert volumes to and from polygonal meshes. - Added a tool (and a Houdini SOP) to scatter points randomly throughout a volume. openvdb-13.0.0/CMakeLists.txt000066400000000000000000000607661510223237100160030ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ CMake Configuration for OpenVDB The OpenVDB CMake build system generates targets depending on the enabled components. It is designed for out of source CMake generation (a build location for CMake to write to will be required). For example, from the root of the repository: mkdir build cd build cmake ../ Depending on the components you choose to build, a number of optional and required dependencies are expected. See the dependency documentation for more information: https://www.openvdb.org/documentation/doxygen/dependencies.html And the documentation on building OpenVDB for more in depth installation instructions: https://www.openvdb.org/documentation/doxygen/build.html This CMakeLists file provides most available options for configuring the build and installation of all OpenVDB components. By default the core library and the vdb_print binary are enabled. Note that various packages have inbuilt CMake module support. See the CMake documentation for more ZLib, Doxygen, OpenGL, Boost and Python controls: https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html OpenVDB's CMake supports building the various components of against a prior installation of OpenVDB. #]=======================================================================] # note: cmake_minimum_required must be called before project commands to # ensure policy scope is set up correctly cmake_minimum_required(VERSION 3.24) # CMP0091 allows for MSVC ABI targetting via CMAKE_MSVC_RUNTIME_LIBRARY # from CMake 3.15 and above. Must come before project(). if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) endif() ###### Version set(OpenVDB_MAJOR_VERSION 13) set(OpenVDB_MINOR_VERSION 0) set(OpenVDB_PATCH_VERSION 0) set(OpenVDB_VERSION "${OpenVDB_MAJOR_VERSION}.${OpenVDB_MINOR_VERSION}.${OpenVDB_PATCH_VERSION}") project(OpenVDB LANGUAGES CXX VERSION ${OpenVDB_VERSION}) ###### OpenVDB Build/Component Options include(CMakeDependentOption) include(GNUInstallDirs) # Components option(OPENVDB_BUILD_CORE "Enable the core OpenVDB library. Both static and shared versions are enabled by default" ON) option(OPENVDB_BUILD_BINARIES "Enable the vdb binaries. Only vdb_print is enabled by default" ON) option(OPENVDB_BUILD_PYTHON_MODULE "Build the pyopenvdb Python module" OFF) option(OPENVDB_BUILD_UNITTESTS "Build the OpenVDB unit tests" OFF) option(OPENVDB_BUILD_DOCS "Build the OpenVDB documentation" OFF) option(OPENVDB_BUILD_HOUDINI_PLUGIN "Build the Houdini plugin" OFF) option(OPENVDB_BUILD_HOUDINI_ABITESTS "Build the Houdini ABI tests" OFF) option(OPENVDB_BUILD_MAYA_PLUGIN "Build the Maya plugin" OFF) option(OPENVDB_BUILD_AX "Build the OpenVDB AX library. Turns ON if USE_AX is ON." ${USE_AX}) option(OPENVDB_BUILD_AX_UNITTESTS "Build the OpenVDB AX unit tests" OFF) option(OPENVDB_BUILD_NANOVDB "Build the NanoVDB library. Turns ON if USE_NANOVDB is ON." ${USE_NANOVDB}) # Global options option(OPENVDB_ENABLE_RPATH "Build with RPATH information" ON) option(OPENVDB_ENABLE_ASSERTS "Build with asserts in OpenVDB code enabled" OFF) option(OPENVDB_USE_DELAYED_LOADING "Build the core OpenVDB library with delayed-loading." ON) option(OPENVDB_CXX_STRICT "Enable or disable pre-defined compiler warnings" OFF) cmake_dependent_option(OPENVDB_INSTALL_CMAKE_MODULES "Install the provided OpenVDB CMake modules when building the core library" ON "OPENVDB_BUILD_CORE" OFF) option(USE_CCACHE "Build using Ccache if found on the path" ON) # Disable this on Windows due to linker OOM issues: # LNK1248: image size (XXX) exceeds maximum allowable size (FFFFFFFF) # https://github.com/AcademySoftwareFoundation/openvdb/issues/1718 # https://github.com/AcademySoftwareFoundation/openvdb/issues/1624 cmake_dependent_option(USE_EXPLICIT_INSTANTIATION "Use explicit instantiation for all supported classes and methods against a pre-defined list of OpenVDB trees. This makes the core library larger and slower to compile, but speeds up the compilation of all dependent code by bypassing the expensive template instantation." ON "NOT WIN32" OFF) option(OPENVDB_FUTURE_DEPRECATION "Generate messages for upcoming deprecation" ON) option(OPENVDB_ENABLE_UNINSTALL "Adds a CMake uninstall target." ON) option(USE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF) # Component dependency options cmake_dependent_option(USE_PKGCONFIG "Use pkg-config to search for dependent libraries." ON "NOT WIN32" OFF) option(USE_HOUDINI [=[ Build the library against a Houdini installation. Turns on automatically if OPENVDB_BUILD_HOUDINI_PLUGIN is enabled. When enabled, you do not need to provide dependency locations for TBB, Blosc, Imath and OpenEXR. Boost must be provided. Imath/OpenEXR can optionally be provided.]=] OFF) option(USE_MAYA [=[ Build the library against a Maya installation. Turns on automatically if OPENVDB_BUILD_MAYA_PLUGIN is enabled. When enabled, you do not need to provide dependency locations for TBB. All other dependencies must be provided.]=] OFF) option(USE_TBB [=[ Use TBB in building the NanoVDB library.]=] ON) option(USE_BLOSC [=[ Use blosc while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located openvdb build configuration to decide on blosc support. You may set this to on to force blosc to be used if you know it to be required.]=] ON) option(USE_ZLIB [=[ Use zlib while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located openvdb build configuration to decide on zlib support. ZLib can only be disabled if Blosc is also disabled. ]=] ON) option(USE_LOG4CPLUS [=[ Use log4cplus while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located openvdb build configuration to decide on log4cplus support. You may set this to on to force log4cplus to be used if you know it to be required.]=] OFF) option(USE_EXR [=[ Use OpenEXR while building openvdb components. If enabled, this also switches USE_IMATH_HALF to ON unless it too was provided and set to OFF.]=] OFF) option(USE_IMATH_HALF [=[ Use the definiton of half floating point types from the Imath library. If OFF, the embedded definition provided by OpenVDB is used. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located openvdb build configuration to select the correct half support. You may set this to on to force Imath half to be used if you know it to be required.]=] ${USE_EXR}) option(USE_PNG "Use PNG while building openvdb components." OFF) option(USE_AX "Use OpenVDB AX while building openvdb components." ${OPENVDB_BUILD_AX}) option(USE_NANOVDB "Use NanoVDB while building openvdb components." ${OPENVDB_BUILD_NANOVDB}) cmake_dependent_option(OPENVDB_DISABLE_BOOST_IMPLICIT_LINKING "Disable the implicit linking of Boost libraries on Windows" ON "WIN32" OFF) option(USE_STATIC_DEPENDENCIES [=[ Only search for and use static libraries. If OFF the shared versions of requried libraries are prioritised, falling back to static libraries. Forcing individual static dependencies can be enabled by setting XXX_USE_STATIC_LIBS to ON, where XXX is the package name. On Windows this behaviour is less strict, with any located libraries assumed to be static. This has no effect for any packages found with Xxx_DIR (i.e. CMake CONFIG mode).]=] OFF) option(DISABLE_DEPENDENCY_VERSION_CHECKS [=[ Disable minimum version checks for OpenVDB dependencies. It is strongly recommended that this remains disabled. Consider updating your dependencies where possible if encountering minimum requirement CMake errors.]=] OFF) option(DISABLE_CMAKE_SEARCH_PATHS [=[ Disable CMakes default system search paths when locating dependencies. When enabled, CMake will fall back to its default system search routine if it cannot find a dependency with the provided settings. When disabled, only paths provided through the Xxx_ROOT, supported XXX_INCLUDEDIR/XXX_LIBRARYDIR variables or the SYSTEM_LIBRARY_PATHS list will be searched.]=] OFF) set(SYSTEM_LIBRARY_PATHS "" CACHE STRING [=[ A global list of library paths to additionally use into when searching for dependencies.]=]) set(MSVC_MP_THREAD_COUNT "" CACHE STRING [=[ The number of threads to use when invoking MSVC builds with cmake --build. CMake defaults to 1. Note that cmake --parallel and CMAKE_BUILD_PARALLEL_LEVEL only change the number of PROJECTS that are built in parallel, NOT the number of TU's ]=]) option(MSVC_COMPRESS_PDB "Whether to attempt to compress PDB symbol data in MSVC debug builds." OFF) set(_CONCURRENT_MALLOC_OPTIONS None Auto Jemalloc Tbbmalloc) if(NOT CONCURRENT_MALLOC) set(CONCURRENT_MALLOC Auto CACHE STRING "Explicitly link the OpenVDB executables against a particular concurrent malloc library. Options are: None Auto Jemalloc Tbbmalloc. Although not required, it is strongly recommended to use a concurrent memory allocator. Has no effect if OPENVDB_BUILD_BINARIES and OPENVDB_BUILD_UNITTESTS are false. Auto is the default and implies Jemalloc, unless USE_MAYA is ON or Jemalloc is unavailable, in which case Tbbmalloc is used. Note that this is not linked into library builds and defers this choice to downstream applications via explicit CMake targets." FORCE ) elseif(NOT ${CONCURRENT_MALLOC} IN_LIST _CONCURRENT_MALLOC_OPTIONS) message(WARNING "Unrecognized value for CONCURRENT_MALLOC, using Auto instead.") set(CONCURRENT_MALLOC Auto CACHE STRING FORCE) endif() set(_OPENVDB_SIMD_OPTIONS None SSE42 AVX) if(NOT OPENVDB_SIMD) set(OPENVDB_SIMD None CACHE STRING "Choose whether to enable SIMD compiler flags or not, options are: None SSE42 AVX. Although not required, it is strongly recommended to enable SIMD. AVX implies SSE42. None is the default." FORCE ) elseif(NOT ${OPENVDB_SIMD} IN_LIST _OPENVDB_SIMD_OPTIONS) message(WARNING "Unrecognized or unsupported value for OPENVDB_SIMD, " "using None instead.") set(OPENVDB_SIMD None CACHE STRING FORCE) endif() if(USE_BLOSC AND NOT USE_ZLIB) message(WARNING "ZLib can only be disabled if Blosc is also disabled. Enabling ZLib.") endif() if(USE_NANOVDB) if(OPENVDB_BUILD_CORE AND NOT OPENVDB_BUILD_NANOVDB) message(FATAL_ERROR "Invalid CMake build configuration: OPENVDB_BUILD_CORE: [ON] OPENVDB_BUILD_NANOVDB: [OFF] USE_NANOVDB: [ON] If you are rebuilding the core library and using sub components, building these sub components must also be enabled (i.e. -DOPENVDB_BUILD_NANOVDB=ON).") endif() endif() if(USE_AX) if(OPENVDB_BUILD_CORE AND NOT OPENVDB_BUILD_AX) message(FATAL_ERROR "Invalid CMake build configuration: OPENVDB_BUILD_CORE: [ON] OPENVDB_BUILD_AX: [OFF] USE_AX: [ON] If you are rebuilding the core library and using sub components, building these sub components must also be enabled (i.e. -DOPENVDB_BUILD_AX=ON).") endif() endif() if(OPENVDB_BUILD_HOUDINI_PLUGIN OR OPENVDB_BUILD_HOUDINI_ABITESTS) set(USE_HOUDINI ON) endif() if(OPENVDB_BUILD_MAYA_PLUGIN) set(USE_MAYA ON) endif() if(USE_MAYA AND USE_HOUDINI) # @todo technically this is possible so long as library versions match # exactly but it's difficult to validate and dangerous message(FATAL_ERROR "Cannot build both Houdini and Maya plugins against " "the same core dependencies. Plugins must be compiled separately to " "ensure the required DCC dependencies are met.") endif() ###### Deprecated options if(OPENVDB_CODE_COVERAGE) message(FATAL_ERROR "The OPENVDB_CODE_COVERAGE option has been removed. Choose instead the unique" "build type -DCMAKE_BUILD_TYPE=coverage") endif() if(OPENVDB_BUILD_HOUDINI_SOPS) message(FATAL_ERROR "The OPENVDB_BUILD_HOUDINI_SOPS option has been removed. Use OPENVDB_BUILD_HOUDINI_PLUGIN.") endif() if(DEFINED USE_SYSTEM_LIBRARY_PATHS) message(FATAL_ERROR "The USE_SYSTEM_LIBRARY_PATHS option has been removed. Use DISABLE_CMAKE_SEARCH_PATHS.") endif() # Various root level CMake options which are marked as advanced mark_as_advanced( CONCURRENT_MALLOC DISABLE_CMAKE_SEARCH_PATHS DISABLE_DEPENDENCY_VERSION_CHECKS OPENVDB_BUILD_HOUDINI_ABITESTS OPENVDB_CXX_STRICT OPENVDB_ENABLE_RPATH OPENVDB_USE_DELAYED_LOADING OPENVDB_FUTURE_DEPRECATION OPENVDB_SIMD SYSTEM_LIBRARY_PATHS USE_CCACHE USE_COLORED_OUTPUT USE_HOUDINI USE_IMATH_HALF USE_LOG4CPLUS USE_MAYA MSVC_COMPRESS_PDB ) ######################################################################### # Configure MINIMUM and FUTURE_MINIMUM version variables include(cmake/config/OpenVDBVersions.cmake) if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_CMAKE_VERSION) if(CMAKE_VERSION VERSION_LESS ${FUTURE_MINIMUM_CMAKE_VERSION}) message(DEPRECATION "Support for CMake versions < ${FUTURE_MINIMUM_CMAKE_VERSION} " "is deprecated and will be removed.") endif() endif() foreach(DEPRECATED_ABI ${OPENVDB_DEPRECATED_ABI_LIST}) option(OPENVDB_USE_DEPRECATED_ABI_${DEPRECATED_ABI} "Bypass minimum ABI requirement checks" OFF) mark_as_advanced(OPENVDB_USE_DEPRECATED_ABI_${DEPRECATED_ABI}) endforeach() option(OPENVDB_USE_FUTURE_ABI_${FUTURE_OPENVDB_ABI_VERSION} "Bypass future ABI check" OFF) mark_as_advanced(OPENVDB_USE_FUTURE_ABI_${FUTURE_OPENVDB_ABI_VERSION}) ######################################################################### enable_testing() # Add our cmake modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Add cmake modules to installation command if(SKBUILD) set(OPENVDB_INSTALL_BINDIR openvdb/${CMAKE_INSTALL_BINDIR}) set(OPENVDB_INSTALL_LIBDIR openvdb/${CMAKE_INSTALL_LIBDIR}) set(OPENVDB_INSTALL_INCLUDEDIR openvdb/${CMAKE_INSTALL_INCLUDEDIR}) if(OPENVDB_BUILD_NANOVDB) set(NANOVDB_INSTALL_BINDIR nanovdb/${CMAKE_INSTALL_BINDIR}) set(NANOVDB_INSTALL_LIBDIR nanovdb/${CMAKE_INSTALL_LIBDIR}) set(NANOVDB_INSTALL_INCLUDEDIR nanovdb/${CMAKE_INSTALL_INCLUDEDIR}) set(NANOVDB_INSTALL_DOCDIR nanovdb/${CMAKE_INSTALL_DOCDIR}) endif() else() set(OPENVDB_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}) set(OPENVDB_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) set(OPENVDB_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) if(OPENVDB_BUILD_NANOVDB) set(NANOVDB_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}) set(NANOVDB_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) set(NANOVDB_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(NANOVDB_INSTALL_DOCDIR ${CMAKE_INSTALL_DOCDIR}) endif() endif() if(OPENVDB_INSTALL_CMAKE_MODULES) set(OPENVDB_CMAKE_MODULES cmake/FindBlosc.cmake cmake/FindJemalloc.cmake cmake/FindLog4cplus.cmake cmake/FindOpenEXR.cmake cmake/FindOpenVDB.cmake cmake/FindTBB.cmake cmake/OpenVDBGLFW3Setup.cmake cmake/OpenVDBHoudiniSetup.cmake cmake/OpenVDBMayaSetup.cmake cmake/OpenVDBUtils.cmake ) install(FILES ${OPENVDB_CMAKE_MODULES} DESTINATION ${OPENVDB_INSTALL_LIBDIR}/cmake/OpenVDB) endif() # Configure component dependencies by loading the Houdini/Maya setup # scripts. These also find the Houdini/Maya installations if(USE_HOUDINI) include(OpenVDBHoudiniSetup) endif() if(USE_MAYA) include(OpenVDBMayaSetup) endif() if(OPENVDB_BUILD_DOCS) add_subdirectory(doc) endif() if(NOT OPENVDB_BUILD_AX AND OPENVDB_BUILD_AX_GRAMMAR) # only re-generate the AX grammar set(OPENVDB_AX_SHARED OFF CACHE BOOL "" FORCE) set(OPENVDB_AX_STATIC OFF CACHE BOOL "" FORCE) add_subdirectory(openvdb_ax/openvdb_ax) endif() # Early exit if there's nothing to build if(NOT ( OPENVDB_BUILD_CORE OR OPENVDB_BUILD_BINARIES OR OPENVDB_BUILD_AX OR OPENVDB_BUILD_AX_UNITTESTS OR OPENVDB_BUILD_PYTHON_MODULE OR OPENVDB_BUILD_UNITTESTS OR OPENVDB_BUILD_HOUDINI_PLUGIN OR OPENVDB_BUILD_HOUDINI_ABITESTS OR OPENVDB_BUILD_MAYA_PLUGIN OR OPENVDB_BUILD_NANOVDB) ) return() endif() ######################################################################### # ccache setup if(USE_CCACHE) find_program(CCACHE_PATH ccache) if(CCACHE_PATH) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH}) message(STATUS "Using ccache: ${CCACHE_PATH}") endif() endif() ######################################################################### # Configure general CMake and CXX settings include(cmake/config/OpenVDBCXX.cmake) ######################################################################### # Configure malloc library. Use Jemalloc if available, tbbmalloc otherwise if(CONCURRENT_MALLOC STREQUAL "Auto") find_package(Jemalloc QUIET) if(NOT TARGET Jemalloc::jemalloc) message(WARNING "Unable to find Jemalloc, attempting to fall back to TBB malloc. It is recommended to use Jemalloc for optimum performance.") set(CONCURRENT_MALLOC "Tbbmalloc") else() set(CONCURRENT_MALLOC "Jemalloc") endif() endif() # Configure SIMD. AVX implies SSE 4.2. if(OPENVDB_SIMD STREQUAL "AVX") if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") add_compile_options("$<$:-mavx>") add_compile_options("$<$:-msse4.2>") endif() add_compile_definitions("$<$:OPENVDB_USE_AVX>") add_compile_definitions("$<$:OPENVDB_USE_SSE42>") elseif(OPENVDB_SIMD STREQUAL "SSE42") if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") add_compile_options("$<$:-msse4.2>") endif() add_compile_definitions("$<$:OPENVDB_USE_SSE42>") endif() ######################################################################### # Configure our cmake modules to only search for static libraries if(USE_STATIC_DEPENDENCIES) set(BLOSC_USE_STATIC_LIBS ON) set(OPENEXR_USE_STATIC_LIBS ON) set(TBB_USE_STATIC_LIBS ON) set(LOG4CPLUS_USE_STATIC_LIBS ON) set(JEMALLOC_USE_STATIC_LIBS ON) set(GTEST_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON) # @todo glfw needs custom support. # set(GLFW_USE_STATIC_LIBS ON) endif() # Configure OpenVDB Library and ABI versions set(NEEDS_OPENVDB OFF) if(OPENVDB_BUILD_AX OR OPENVDB_BUILD_BINARIES OR OPENVDB_BUILD_UNITTESTS OR OPENVDB_BUILD_HOUDINI_PLUGIN OR OPENVDB_BUILD_MAYA_PLUGIN OR OPENVDB_BUILD_PYTHON_MODULE OR OPENVDB_BUILD_HOUDINI_ABITESTS) set(NEEDS_OPENVDB ON) endif() if(NOT OPENVDB_BUILD_CORE AND NEEDS_OPENVDB) # Find VDB installation and determine lib/abi versions. This resets the # version and ABI numbers find_package(OpenVDB REQUIRED) # Check ABI version was found and explicitly error if attempting to build against # an incompatible Houdini version if(OpenVDB_ABI AND OPENVDB_HOUDINI_ABI) if(NOT ${OpenVDB_ABI} EQUAL ${OPENVDB_HOUDINI_ABI}) message(FATAL_ERROR "Located OpenVDB installation is not ABI compatible with " "Houdini Version ${Houdini_VERSION}. Requires ABI ${OPENVDB_HOUDINI_ABI}, found " "ABI ${OpenVDB_ABI}.") endif() endif() endif() message(STATUS "Configuring for OpenVDB Version ${OpenVDB_VERSION}") # Locate openvdb_ax if necessary if(NOT OPENVDB_BUILD_AX AND (OPENVDB_BUILD_AX_UNITTESTS OR USE_AX)) find_package(OpenVDB REQUIRED COMPONENTS openvdb_ax) endif() # Locate nanovdb if necessary if(NOT OPENVDB_BUILD_NANOVDB AND USE_NANOVDB) find_package(OpenVDB REQUIRED COMPONENTS nanovdb) endif() # Locate Python and nanobind if necessary if(OPENVDB_BUILD_PYTHON_MODULE OR (OPENVDB_BUILD_NANOVDB AND NANOVDB_BUILD_PYTHON_MODULE)) find_package(Python ${MINIMUM_PYTHON_VERSION} REQUIRED COMPONENTS Development Interpreter) if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_PYTHON_VERSION) if(Python_VERSION VERSION_LESS ${FUTURE_MINIMUM_PYTHON_VERSION}) message(DEPRECATION "Support for Python versions < ${FUTURE_MINIMUM_GLFW_VERSION} " "is deprecated and will be removed.") endif() endif() find_package(nanobind REQUIRED CONFIG) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(nanobind FOUND_VAR nanobind_FOUND REQUIRED_VARS NB_DIR VERSION_VAR nanobind_VERSION) if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_NANOBIND_VERSION) if(nanobind_VERSION VERSION_LESS ${FUTURE_MINIMUM_NANOBIND_VERSION}) message(DEPRECATION "Support for nanobind versions < ${FUTURE_MINIMUM_NANOBIND_VERSION} " "is deprecated and will be removed.") endif() endif() if(NOT DEFINED VDB_PYTHON_INSTALL_DIRECTORY) if(DEFINED Python_SITELIB) get_filename_component(Python_PACKAGES_DIR ${Python_SITELIB} NAME) else() set(Python_PACKAGES_DIR "site-packages") endif() set(VDB_PYTHON_INSTALL_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/${Python_PACKAGES_DIR} CACHE STRING "The directory to install the openvdb and nanovdb Python modules." ) endif() endif() # Validate the OpenVDB ABI Version. If OpenVDB_ABI is not set, we're either building # the core library OR the ABI hasn't been deduced from a VDB installation. Use the # value from OPENVDB_ABI_VERSION_NUMBER, falling back to the lib major version number if(NOT OpenVDB_ABI) if(OPENVDB_ABI_VERSION_NUMBER) set(OpenVDB_ABI ${OPENVDB_ABI_VERSION_NUMBER}) else() set(OpenVDB_ABI ${OpenVDB_MAJOR_VERSION}) endif() endif() # From the deduced ABI, check against the required ABI for Houdini (if set). # Forcefully set the ABI to the required value if necessary - do this after to # explicitly warn the user if their chosen value is different. if(OPENVDB_HOUDINI_ABI AND (NOT "${OpenVDB_ABI}" EQUAL "${OPENVDB_HOUDINI_ABI}")) message(WARNING "CMake will explicitly set the value of OPENVDB_ABI_VERSION_NUMBER to " "${OPENVDB_HOUDINI_ABI} to match the ABI of the target Houdini Version.") set(OpenVDB_ABI ${OPENVDB_HOUDINI_ABI}) endif() # Validate ABI value if outside supported range if(OpenVDB_ABI LESS MINIMUM_OPENVDB_ABI_VERSION) message(FATAL_ERROR "OpenVDB ABI versions earlier than ${MINIMUM_OPENVDB_ABI_VERSION} are " "no longer supported.") endif() if(OpenVDB_ABI IN_LIST OPENVDB_DEPRECATED_ABI_LIST) if(NOT OPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI}) message(FATAL_ERROR "OpenVDB ABI versions earlier than ${OpenVDB_MAJOR_VERSION} " "are deprecated. Set CMake option OPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI} to ON to " "suppress this error.") endif() message(DEPRECATION "OpenVDB ABI versions earlier than ${OpenVDB_MAJOR_VERSION} " "are deprecated and will soon be removed.") # global target definition add_definitions(-DOPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI}) endif() if(OpenVDB_ABI EQUAL FUTURE_OPENVDB_ABI_VERSION) if(NOT OPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI}) message(FATAL_ERROR "OpenVDB ABI version ${OpenVDB_ABI} contains changes to ABI that are still " "in active development and have not been finalized. Set CMake option " "OPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI} to ON to suppress this error.") endif() message(WARNING "OpenVDB ABI version ${OpenVDB_ABI} contains changes to ABI that are still " "in active development and have not been finalized.") # global target definition add_definitions(-DOPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI}) endif() message(STATUS "Configuring for OpenVDB ABI Version ${OpenVDB_ABI}") # Always force set as we may need to change it if it's incompatible with Houdini set(OPENVDB_ABI_VERSION_NUMBER ${OpenVDB_ABI} CACHE STRING [=[ Build for compatibility with version N of the OpenVDB Grid ABI, where N is 6, 7, 8 etc. (some newer features will be disabled). If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the installed vdb_print binary to determine the ABI number. You may set this to force a given ABI number.]=] FORCE) ########################################################################## if(OPENVDB_BUILD_CORE) add_subdirectory(openvdb/openvdb) endif() if(OPENVDB_BUILD_AX) add_subdirectory(openvdb_ax/openvdb_ax) endif() if(OPENVDB_BUILD_PYTHON_MODULE) add_subdirectory(openvdb/openvdb/python) endif() if(OPENVDB_BUILD_BINARIES) add_subdirectory(openvdb_cmd) endif() if(OPENVDB_BUILD_UNITTESTS) add_subdirectory(openvdb/openvdb/unittest) endif() # Tests the vdb_ax binary so needs to come after openvdb_cmd if(OPENVDB_BUILD_AX_UNITTESTS) add_subdirectory(openvdb_ax/openvdb_ax/test) endif() if(OPENVDB_BUILD_HOUDINI_PLUGIN) add_subdirectory(openvdb_houdini/openvdb_houdini) endif() if(OPENVDB_BUILD_HOUDINI_ABITESTS) add_subdirectory(openvdb_houdini/openvdb_houdini/abitest) endif() if(OPENVDB_BUILD_MAYA_PLUGIN) add_subdirectory(openvdb_maya/openvdb_maya) endif() if(OPENVDB_BUILD_NANOVDB) add_subdirectory(nanovdb/nanovdb) endif() ########################################################################## if(OPENVDB_ENABLE_UNINSTALL) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/Uninstall.cmake ) endif() openvdb-13.0.0/CODEOWNERS000066400000000000000000000050271510223237100146230ustar00rootroot00000000000000# See https://help.github.com/articles/about-codeowners/ # for more info about CODEOWNERS file # It uses the same pattern rule for gitignore file # https://git-scm.com/docs/gitignore#_pattern_format # Admin/General /.github/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones /ci/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones /cmake/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones /doc/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones /pendingchanges/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones /tsc/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones CODEOWNERS @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones LICENSE @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones CHANGES @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones *.md @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones # Core OpenVDB Library /openvdb/ @kmuseth /openvdb/openvdb/points/ @danrbailey @idclip # OpenVDB AX /openvdb_ax/ @idclip @richhones # NanoVDB /nanovdb/ @kmuseth # OpenVDB Houdini - Default /openvdb_houdini/ @kmuseth # OpenVDB Houdini - VDB Primitive and SideFX Utils /openvdb_houdini/openvdb_houdini/GEO_PrimVDB.* @jmlait /openvdb_houdini/openvdb_houdini/GU_PrimVDB.* @jmlait /openvdb_houdini/openvdb_houdini/GEO_VDBTranslator.* @jmlait /openvdb_houdini/openvdb_houdini/GT_GEOPrimCollectVDB.* @jmlait /openvdb_houdini/openvdb_houdini/SOP_VDBVerbUtils.* @jmlait /openvdb_houdini/openvdb_houdini/UT_VDBUtils.* @jmlait # OpenVDB Houdini - VDB Points /openvdb_houdini/openvdb_houdini/PointUtils.* @danrbailey @idclip /openvdb_houdini/openvdb_houdini/*_OpenVDB_Points_* @danrbailey @idclip /openvdb_houdini/openvdb_houdini/GR_PrimVDBPoints.* @danrbailey @idclip openvdb-13.0.0/CODE_OF_CONDUCT.md000066400000000000000000000002531510223237100160230ustar00rootroot00000000000000All participants agree to abide by LF Projects Code of Conduct (as defined in the [charter](tsc/charter.md)) available at https://lfprojects.org/policies/code-of-conduct/ openvdb-13.0.0/CONTRIBUTING.md000066400000000000000000000141101510223237100154520ustar00rootroot00000000000000# Overview This project aims to be governed in a transparent, accessible way for the benefit of the community. All participation in this project is open and not bound to corporate affiliation. Participants are all bound to the [Code of Conduct](CODE_OF_CONDUCT.md). # Project roles ## Contributor The contributor role is the starting role for anyone participating in the project and wishing to contribute code. ### Process for becoming a contributor * Review the [coding standards](https://www.openvdb.org/documentation/doxygen/codingStyle.html) to ensure your contribution is in line with the project's coding and styling guidelines. * Have a signed CLA on file ( see [below](#contributor-license-agreements) ) * Submit your code as a PR with the appropriate [DCO sign-off](#commit-sign-off). * Have your submission approved by the [committer(s)](#committer) and merged into the codebase. ### Legal Requirements OpenVDB is a project of the Academy Software Foundation and follows the open source software best practice policies of the Linux Foundation. #### License OpenVDB is licensed under the [Apache License, version 2.0](LICENSE.md) license. Contributions to OpenVDB should abide by that standard license. #### Contributor License Agreements Developers who wish to contribute code to be considered for inclusion in OpenVDB must first complete a **Contributor License Agreement**. OpenVDB uses [EasyCLA](https://lfcla.com/) for managing CLAs, which automatically checks to ensure CLAs are signed by a contributor before a commit can be merged. * If you are an individual writing the code on your own time and you're SURE you are the sole owner of any intellectual property you contribute, you can [sign the CLA as an individual contributor](https://docs.linuxfoundation.org/lfx/easycla/contributors/individual-contributor). * If you are writing the code as part of your job, or if there is any possibility that your employers might think they own any intellectual property you create, then you should use the [Corporate Contributor Licence Agreement](https://docs.linuxfoundation.org/lfx/easycla/contributors/corporate-contributor). The OpenVDB CLAs are the standard forms used by Linux Foundation projects and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/master/process/contributing.md#contributor-license-agreement-cla). You can review the text of the CLAs in the [TSC directory](tsc/). #### Commit Sign-Off Every commit must be signed off. That is, every commit log message must include a “`Signed-off-by`â€� line (generated, for example, with “`git commit --signoff`â€�), indicating that the committer wrote the code and has the right to release it under the [Apache License, version 2.0](LICENSE.md) license. See the [TAC documentation on contribution sign off](https://github.com/AcademySoftwareFoundation/tac/blob/master/process/contributing.md#contribution-sign-off) for more information on this requirement. ## Maintainer The maintainer role is the equivalent of the "Committer" role in the charter. This role enables the participant to commit code directly to the repository, but also comes with the obligation to be a responsible leader in the community. ### Process for becoming a maintainer * Show your experience with the codebase through contributions and engagement on the community channels. * Request to become a maintainer. * Have the majority of maintainers approve you becoming a maintainer. * Your name and email is added to the MAINTAINERS.md file for the project. ### Maintainer responsibilities * Monitor email aliases. * Monitor Slack (delayed response is perfectly acceptable). * Triage GitHub issues and perform pull request reviews for other committers and the community. * Make sure that ongoing PRs are moving forward at the right pace or close them. * Remain an active contributor to the project in general and the code base in particular. ### When does a maintainer lose maintainer status? If a maintainer is no longer interested or cannot perform the maintainer duties listed above, they should volunteer to be moved to emeritus status. In extreme cases this can also occur by a vote of the maintainers per the voting process below. ## Technical Steering Committee (TSC) member The Technical Steering Committee (TSC) oversees the overall technical direction of OpenVDB, as defined in the [charter](charter.md). TSC voting members consist of maintainers that have been nominated by the TSC, with a supermajority of voting members required to have a maintainer elected to be a TSC voting member. TSC voting members term and succession is defined in the [charter](charter.md). All meetings of the TSC are open to participation by any member of the OpenVDB community. Meeting times are listed in the [ASWF technical community calendar](https://lists.aswf.io/g/tac/calendar). ## Current TSC members * Ken Museth (Chair), Nvidia * Andre Pradhana, Nvidia * Jeff Lait, SideFX * Nick Avramoussis, WETA FX * Dan Bailey, ILM * Richard Jones, ILM * Gregory Hurst, United Therapeutics # Release Process Project releases will occur on a scheduled basis as agreed to by the TSC. # Conflict resolution and voting In general, we prefer that technical issues and committer status/TSC membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the TSC can be called in to decide an issue. If the TSC themselves cannot decide an issue, the issue will be resolved by voting. The voting process is a simple majority in which each TSC receives one vote. # Communication This project, just like all of open source, is a global community. In addition to the [Code of Conduct](CODE_OF_CONDUCT.md), this project will: * Keep all communication on open channels ( mailing list, forums, chat ). * Be respectful of time and language differences between community members ( such as scheduling meetings, email/issue responsiveness, etc ). * Ensure tools are able to be used by community members regardless of their region. If you have concerns about communication challenges for this project, please contact the [TSC](mailto:openvdb-tsc-private@lists.aswf.io). openvdb-13.0.0/LICENSE000066400000000000000000000236751510223237100142460ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS openvdb-13.0.0/MAINTAINERS.md000066400000000000000000000010221510223237100153130ustar00rootroot00000000000000 # OpenVDB Committers The current OpenVDB maintainers are: | Name | Email | | ---------------- | ----------------- | Jeff Lait | jlait@sidefx.com | Dan Bailey | danbailey@ilm.com | Nick Avramoussis | navramoussis@wetafx.co.nz | Ken Museth | ken.museth@gmail.com | Andre Pradhana | andre.pradhana@gmail.com | Richard Jones | richardj@ilm.com | Gregory Hurst | tbd | Jonathan Swartz | tbd openvdb-13.0.0/RE-LICENSE_NOTE.txt000066400000000000000000000014701510223237100162020ustar00rootroot00000000000000The following copyright holders agree that all of their contributions originally submitted to this project under the Mozilla Public License Version 2.0, are hereby relicensed to the Apache License, Version 2.0, and are submitted pursuant to the Developer Certificate of Origin, version 1.1: Ken Museth Mehdi Chinoune DreamWorks Animation Side Effects Software Inc. Blender Foundation NVIDIA Corporation United Therapeutics Corporation Digital Domain 3.0, Inc. Double Negative Ubisoft Entertainment SA Adobe Inc. Mathieu Malaterre Brecht Sanders Ignacio Vizzo Ben FrantzDale Sebastian Gaida Alessio Quaglino Benedikt Mersch David Aguilar Brian Sharpe Kartik Shrivastava Michael Lackner Lucas Baraya Kuba Roth Tom Cnops Walt Disney Pictures (Walt Disney Animation Studios) The Linux Foundation Industrial Light & Magic (ILM) openvdb-13.0.0/README.md000066400000000000000000000135071510223237100145110ustar00rootroot00000000000000![OpenVDB](doc/img/banner.png) | OpenVDB | AX | Nano | Houdini | License | CII | | :----: | :----: | :----: | :----: | :-----: | :-: | | [![core](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/build.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/build.yml) | [![ax](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/ax.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/ax.yml) | [![nano](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/nanovdb.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/nanovdb.yml) | [![hou](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/houdini.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/houdini.yml) | [![License](https://img.shields.io/github/license/AcademySoftwareFoundation/openvdb)](LICENSE) | [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2774/badge)](https://bestpractices.coreinfrastructure.org/projects/2774) | ------------------------------------------------------------------------------- [Website](https://www.openvdb.org) | [Discussion Forum](https://github.com/AcademySoftwareFoundation/openvdb/discussions) | [Documentation](https://www.openvdb.org/documentation/doxygen) | [Releases](https://github.com/AcademySoftwareFoundation/openvdb/releases) | [License](https://www.apache.org/licenses/LICENSE-2.0) | [Slack](https://slack.aswf.io/) OpenVDB is an open source C++ library comprising a novel hierarchical data structure and a large suite of tools for the efficient storage and manipulation of sparse volumetric data discretized on three-dimensional grids. It was developed by DreamWorks Animation for use in volumetric applications typically encountered in feature film production. ### Development Repository This GitHub repository hosts the trunk of the OpenVDB development. This implies that it is the newest public version with the latest features and bug fixes. However, it also means that it has not undergone a lot of testing and is generally less stable than the [production releases](https://github.com/AcademySoftwareFoundation/openvdb/releases). ### License OpenVDB is released under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), which is a free, open source software license developed and maintained by the Apache Software Foundation. The trademarks of any contributor to this project may not be used in association with the project without the contributor's express permission. NOTE: OpenVDB has completed re-licensing from [Mozilla Public License Version 2.0](https://www.mozilla.org/MPL/2.0/) to [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). Please see the file RE-LICENSE_NOTE.txt for more details. ### Contributing OpenVDB welcomes contributions to the OpenVDB project. Please refer to the [contribution guidelines](CONTRIBUTING.md) for details on how to make a contribution. ------------------------------------------------------------------------------- ### Developer Quick Start The following provides basic installation examples for the core OpenVDB library. Other components, such as the python module, OpenVDB AX, NanoVDB and various executables, may require additional dependencies. See the [build documentation](https://www.openvdb.org/documentation/doxygen/build.html) for help with installations. ##### Linux/MacOS ```bash # Linux # @note If your distribution does not have required versions, consider using # apt pinning. See the dependency documentation for more details. apt-get install -y libboost-iostreams-dev apt-get install -y libtbb-dev apt-get install -y libblosc-dev # MacOS # @note We are using homebrew in this example to install requried dependencies # https://brew.sh/ brew install boost brew install tbb brew install c-blosc ``` ```bash git clone git@github.com:AcademySoftwareFoundation/openvdb.git cd openvdb mkdir build cd build cmake .. make -j4 && make install ``` ##### Windows Note that the following commands have only been tested for 64bit systems/libraries. It is recommended to set the `VCPKG_DEFAULT_TRIPLET` environment variable to `x64-windows` to use 64-bit libraries by default. You will also require [Visual Studio](https://visualstudio.microsoft.com/downloads/) (for the MSVC C++ runtime and compiler toolchains), [CMake](https://cmake.org/download/) and optionally [vcpkg](https://github.com/microsoft/vcpkg) for the installation of OpenVDB's dependencies. ```bash vcpkg install zlib:x64-windows vcpkg install blosc:x64-windows vcpkg install tbb:x64-windows vcpkg install boost-iostreams:x64-windows vcpkg install boost-any:x64-windows vcpkg install boost-algorithm:x64-windows vcpkg install boost-interprocess:x64-windows ``` ```bash git clone git@github.com:AcademySoftwareFoundation/openvdb.git cd openvdb mkdir build cd build cmake -DCMAKE_TOOLCHAIN_FILE=\scripts\buildsystems\vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows -A x64 .. cmake --build . --parallel 4 --config Release --target install ``` #### Building OpenVDB AX and NanoVDB OpenVDB AX depends on the core OpenVDB library. NanoVDB can be built with and without OpenVDB support. Note that NanoVDB has its own build instructions, see the [NanoVDB build documentation](https://www.openvdb.org/documentation/doxygen/NanoVDB_HowToBuild.html) for details. The following variables can be passed to the `cmake` configure command. There are more optional VDB components, see the [build documentation](https://www.openvdb.org/documentation/doxygen/build.html) for a complete list. | Option | Details | | :---- | :----- | | `-D OPENVDB_BUILD_AX=ON` | to enable OpenVDB AX | | `-D OPENVDB_BUILD_NANOVDB=ON` | to enable NanoVDB | | `-D NANOVDB_USE_OPENVDB=ON` | to use OpenVDB in NanoVDB | openvdb-13.0.0/ci/000077500000000000000000000000001510223237100136175ustar00rootroot00000000000000openvdb-13.0.0/ci/build.sh000077500000000000000000000152021510223237100152550ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -e CI_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) # print versions bash --version if [ ! -z "$CXX" ]; then $CXX -v; fi cmake --version CMAKE_VERSION=$(cmake --version | head -n1 | cut -d' ' -f3) ################################################ OPTS_ARGS+=("t:") ## See --target OPTS_ARGS+=("j:") ## Thread usage OPTS_ARGS+=("c:") ## See --cargs OPTS_ARGS+=("v") ## See --verbose OPTL_ARGS+=("components:") ## Specify cmake component(s) to enable OPTL_ARGS+=("config:") ## Specify cmake configuration during the build step OPTL_ARGS+=("target:") ## Specify target(s) to build OPTL_ARGS+=("build-dir:") ## Build directory OPTL_ARGS+=("cargs:") ## args to pass directly to cmake generation step OPTL_ARGS+=("build-type:") ## Release, Debug, etc. OPTL_ARGS+=("verbose") ## Verbose build output # Defaults declare -A PARMS PARMS[--components]=core,bin PARMS[--target]=install PARMS[--build-dir]=build if [[ $RUNNER_NAME == *"8c-32g-300h"* ]]; then if [[ $CXX == "g++" ]]; then # GCC hits memory limits on runners, reduce threads PARMS[-j]=6 else # ASWF github actions runners have 8 threads PARMS[-j]=8 fi else # Github actions runners have 2 threads # https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners if [[ $CXX == "g++" ]]; then # GCC hits memory limits on runners, build in serial PARMS[-j]=1 else PARMS[-j]=2 fi fi # Available options for --components declare -A COMPONENTS COMPONENTS['core']='OPENVDB_BUILD_CORE' COMPONENTS['python']='OPENVDB_BUILD_PYTHON_MODULE' COMPONENTS['test']='OPENVDB_BUILD_UNITTESTS' # @todo split out vdb tool from this... COMPONENTS['bin']='OPENVDB_BUILD_VDB_PRINT,OPENVDB_BUILD_VDB_LOD,OPENVDB_BUILD_VDB_TOOL,OPENVDB_BUILD_VDB_TOOL_UNITTESTS' COMPONENTS['view']='OPENVDB_BUILD_VDB_VIEW' COMPONENTS['render']='OPENVDB_BUILD_VDB_RENDER' COMPONENTS['hou']='OPENVDB_BUILD_HOUDINI_PLUGIN' COMPONENTS['doc']='OPENVDB_BUILD_DOCS' COMPONENTS['axcore']='OPENVDB_BUILD_AX' COMPONENTS['axgr']='OPENVDB_BUILD_AX_GRAMMAR' COMPONENTS['axbin']='OPENVDB_BUILD_AX_BINARIES' COMPONENTS['axtest']='OPENVDB_BUILD_AX_UNITTESTS' COMPONENTS['nano']='OPENVDB_BUILD_NANOVDB' COMPONENTS['nanotest']='NANOVDB_BUILD_UNITTESTS' COMPONENTS['nanoexam']='NANOVDB_BUILD_EXAMPLES' COMPONENTS['nanobench']='NANOVDB_BUILD_BENCHMARK' COMPONENTS['nanotool']='NANOVDB_BUILD_TOOLS' ################################################ HAS_PARM() { if [ -z "${PARMS[$1]}" ]; then return 1 else return 0; fi } # Format to string and replace spaces with commas LARGS_STR="${OPTL_ARGS[@]}" LARGS_STR=${LARGS_STR// /,} SARGS_STR="${OPTS_ARGS[@]}" SARGS_STR=${SARGS_STR// /,} # Parse all arguments and store them in an array, split by whitespace. Error if unsupported ARGS="$(eval getopt --options=$SARGS_STR --longoptions=$LARGS_STR -- "$@")" eval set -- "$ARGS" # split into associative array while true; do case "$1" in -v|--verbose) # options which dont take an argument PARMS["$1"]="ON"; shift ;; -[a-z]*|--[a-z]*) # all other arguments (key/values) PARMS["$1"]="$2"; shift 2 ;; --) shift; break ;; esac done ################################################ # extract arguments if HAS_PARM -t; then TARGET=${PARMS[-t]}; fi if HAS_PARM --target; then if [ -z $TARGET ]; then TARGET=${PARMS[--target]} else TARGET+=","${PARMS[--target]}; fi fi if HAS_PARM -c; then CMAKE_EXTRA=${PARMS[-c]}; fi if HAS_PARM --cargs; then if [ -z $CMAKE_EXTRA ]; then CMAKE_EXTRA=${PARMS[--cargs]} else CMAKE_EXTRA+=" "${PARMS[--cargs]}; fi fi BUILD_DIR=${PARMS[--build-dir]} # handle whitespace eval "CMAKE_EXTRA=($CMAKE_EXTRA)" if HAS_PARM -v || HAS_PARM --verbose; then # Using CMAKE_VERBOSE_MAKEFILE as well as `cmake --verbose` to # support older versions of CMake. CMAKE_EXTRA+=("-DCMAKE_VERBOSE_MAKEFILE=ON") fi if HAS_PARM --build-type; then CMAKE_EXTRA+=("-DCMAKE_BUILD_TYPE=${PARMS[--build-type]}") build_type="${PARMS[--build-type]}" debug="Debug" # Ignore case - if the build-type is Debug, we enable asserts if [ "${build_type,,}" = "${debug,,}" ]; then CMAKE_EXTRA+=("-DOPENVDB_ENABLE_ASSERTS=ON") fi fi # Available components. If a component is not provided it is # explicitly set to OFF. IN_COMPONENTS=${PARMS[--components]} IFS=', ' read -r -a IN_COMPONENTS <<< "$IN_COMPONENTS" for comp in "${IN_COMPONENTS[@]}"; do if [ -z ${COMPONENTS[$comp]} ]; then echo "Invalid component passed to build \"$comp\""; exit -1 fi done # Build Components command for comp in "${!COMPONENTS[@]}"; do setting="OFF" for in in "${IN_COMPONENTS[@]}"; do if [[ $comp == "$in" ]]; then setting="ON"; break fi done OPENVDB_TOGGLES="${COMPONENTS[$comp]}" OPENVDB_TOGGLES=(${OPENVDB_TOGGLES//,/ }) for toggle in "${!OPENVDB_TOGGLES[@]}"; do CMAKE_EXTRA+=("-D${OPENVDB_TOGGLES[$toggle]}=$setting") done done ################################################ # github actions runners have 8 threads # https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners export CMAKE_BUILD_PARALLEL_LEVEL=${PARMS[-j]} echo "Build using ${CMAKE_BUILD_PARALLEL_LEVEL} threads" # NOTE: --parallel only effects the number of projects build, not t-units. # We support this with out own MSVC_MP_THREAD_COUNT option for MSVC. # Alternatively it is mentioned that the following should work: # cmake --build . -- /p:CL_MPcount=8 # However it does not seem to for our project. # https://gitlab.kitware.com/cmake/cmake/-/issues/20564 CMAKE_BUILD_CMD="cmake --build . --parallel ${PARMS[-j]} --target $TARGET --verbose" if HAS_PARM --config; then CMAKE_BUILD_CMD+=" --config ${PARMS[--config]}" fi ################################################ mkdir -p ${BUILD_DIR} cd ${BUILD_DIR} # Report the cmake commands set -x # Note: # - OPENVDB_BUILD_BINARIES is always ON, but each binary will be toggled depending on the provided comps # - always enabled the python tests with OPENVDB_BUILD_PYTHON_UNITTESTS if the python module is in use, # regardless of the 'test' component being enabled or not (see the OPENVDB_BUILD_PYTHON_UNITTESTS option). cmake \ -DOPENVDB_USE_DEPRECATED_ABI_11=ON \ -DOPENVDB_USE_DEPRECATED_ABI_12=ON \ -DOPENVDB_TOOL_USE_NANO=OFF \ -DOPENVDB_BUILD_BINARIES=ON \ -DOPENVDB_BUILD_PYTHON_UNITTESTS=ON \ -DMSVC_MP_THREAD_COUNT=${PARMS[-j]} \ "${CMAKE_EXTRA[@]}" \ .. $CMAKE_BUILD_CMD openvdb-13.0.0/ci/build_sonar.sh000077500000000000000000000011721510223237100164600ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex wget -q https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip unzip build-wrapper-linux-x86.zip mkdir build cd build cmake \ -DCMAKE_CXX_COMPILER=g++ \ -DOPENVDB_ABI_VERSION_NUMBER=6 \ -DUSE_BLOSC=ON \ -DOPENVDB_CXX_STRICT=ON \ -DOPENVDB_BUILD_UNITTESTS=ON \ -DOPENVDB_BUILD_BINARIES=OFF \ -DOPENVDB_CORE_STATIC=OFF \ -DOPENVDB_BUILD_PYTHON_MODULE=OFF \ -DOPENVDB_CODE_COVERAGE=ON \ .. ../build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw_output make -j2 openvdb-13.0.0/ci/download_houdini.py000077500000000000000000000166041510223237100175310ustar00rootroot00000000000000#!/usr/bin/env python3 # # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # # Python script to download the latest Houdini builds # using the SideFX download API: # # https://www.sidefx.com/docs/api/download/index.html # # Authors: Dan Bailey, SideFX import time import sys import re import shutil import json import base64 import requests import hashlib import os import argparse import copy # For progress bar printing try: from tqdm import tqdm has_tqdm = True except: has_tqdm = False pass # Code that provides convenient Python wrappers to call into the API: def service( access_token_url, client_id, client_secret_key, endpoint_url, access_token=None, access_token_expiry_time=None): if (access_token is None or access_token_expiry_time is None or access_token_expiry_time < time.time()): access_token, access_token_expiry_time = ( get_access_token_and_expiry_time( access_token_url, client_id, client_secret_key)) return _Service( endpoint_url, access_token, access_token_expiry_time) class _Service(object): def __init__( self, endpoint_url, access_token, access_token_expiry_time): self.endpoint_url = endpoint_url self.access_token = access_token self.access_token_expiry_time = access_token_expiry_time def __getattr__(self, attr_name): return _APIFunction(attr_name, self) class _APIFunction(object): def __init__(self, function_name, service): self.function_name = function_name self.service = service def __getattr__(self, attr_name): # This isn't actually an API function, but a family of them. Append # the requested function name to our name. return _APIFunction( "{0}.{1}".format(self.function_name, attr_name), self.service) def __call__(self, *args, **kwargs): return call_api_with_access_token( self.service.endpoint_url, self.service.access_token, self.function_name, args, kwargs) #--------------------------------------------------------------------------- # Code that implements authentication and raw calls into the API: def get_access_token_and_expiry_time( access_token_url, client_id, client_secret_key): """Given an API client (id and secret key) that is allowed to make API calls, return an access token that can be used to make calls. """ response = requests.post( access_token_url, headers={ "Authorization": u"Basic {0}".format( base64.b64encode( "{0}:{1}".format( client_id, client_secret_key ).encode() ).decode('utf-8') ), }) if response.status_code != 200: raise AuthorizationError(response.status_code, response.text) response_json = response.json() access_token_expiry_time = time.time() - 2 + response_json["expires_in"] return response_json["access_token"], access_token_expiry_time class AuthorizationError(Exception): """Raised from the client if the server generated an error while generating an access token. """ def __init__(self, http_code, message): super(AuthorizationError, self).__init__(message) self.http_code = http_code def call_api_with_access_token( endpoint_url, access_token, function_name, args, kwargs): """Call into the API using an access token that was returned by get_access_token. """ response = requests.post( endpoint_url, headers={ "Authorization": "Bearer " + access_token, }, data=dict( json=json.dumps([function_name, args, kwargs]), )) if response.status_code == 200: return response.json() raise APIError(response.status_code, response.text) class APIError(Exception): """Raised from the client if the server generated an error while calling into the API. """ def __init__(self, http_code, message): super(APIError, self).__init__(message) self.http_code = http_code if __name__ == "__main__": parser = argparse.ArgumentParser(description='Download a Houdini Installation') parser.add_argument('version', type=str, help='Major.Minor version of Houdini to download') parser.add_argument('platform', type=str, help='Platform target') parser.add_argument('--prod', action='store_true', help='Only download production builds') parser.add_argument('--list', action='store_true', help='Just list the available builds and exit.') args = parser.parse_args() version = args.version platform = args.platform only_production = args.prod user_client_id = os.getenv('HOUDINI_CLIENT_ID') user_client_secret_key = os.getenv('HOUDINI_SECRET_KEY') if not re.match('[0-9][0-9]\.[0-9]$', version): raise IOError('Invalid Houdini Version "%s", expecting in the form "major.minor" such as "16.0"' % version) service = service( access_token_url="https://www.sidefx.com/oauth2/application_token", client_id=user_client_id, client_secret_key=user_client_secret_key, endpoint_url="https://www.sidefx.com/api/", ) releases_list = service.download.get_daily_builds_list( product='houdini', version=version, platform=platform, only_production=only_production) print('Available builds:') for rel in releases_list: rel = copy.deepcopy(rel) if 'third_party_libraries' in rel: # Don't print these del rel['third_party_libraries'] print(rel) if args.list: sys.exit(0) print('Selecting build: ' + releases_list[0]['build']) latest_release = service.download.get_daily_build_download( product='houdini', version=version, platform=platform, build=releases_list[0]['build']) print(latest_release) # Can't do this procedurally as latest_release['filename'] can contain # multiple periods and may have multiple trailing extensions... extension = '' if 'linux' in platform: extension = 'tar.gz' elif 'macos' in platform: extension = 'dmg' elif 'win64' in platform: extension = 'exe' assert(extension in latest_release['filename']) # Download the file and save it as hou.extension local_filename = 'hou.' + extension print('Writing to "' + local_filename + '"') response = requests.get(latest_release['download_url'], stream=True) if response.status_code == 200: response.raw.decode_content = True if has_tqdm: file_size = int(response.headers.get('Content-Length', 0)) desc = "(Unknown total file size)" if file_size == 0 else "" with tqdm.wrapattr(response.raw, "read", total=file_size, desc=desc) as r_raw: with open(local_filename, 'wb') as f: shutil.copyfileobj(r_raw, f) else: with open(local_filename, 'wb') as f: shutil.copyfileobj(response.raw, f) else: raise Exception('Error downloading file!') # Verify the file checksum is matching file_hash = hashlib.md5() with open(local_filename, 'rb') as f: for chunk in iter(lambda: f.read(4096), b''): file_hash.update(chunk) if file_hash.hexdigest() != latest_release['hash']: raise Exception('Checksum does not match!') openvdb-13.0.0/ci/download_houdini.sh000077500000000000000000000102211510223237100175000ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex HOUDINI_MAJOR="$1" PLATFORM="$2" OTHER_ARGS="$3" if [[ $PLATFORM =~ "linux" ]]; then pip3 install --user requests elif [[ $PLATFORM =~ "macos" ]]; then # Tell the homebrew install of pip3 that we don't care about installing directly through pip3 pip3 install --user requests --break-system-packages fi python3 ci/download_houdini.py $HOUDINI_MAJOR $PLATFORM $OTHER_ARGS if [[ $PLATFORM =~ "linux" ]]; then # create dir hierarchy mkdir -p hou/bin mkdir -p hou/houdini mkdir -p hou/toolkit mkdir -p hou/dsolib # unpack hou.tar.gz and cleanup tar -xzf hou.tar.gz rm -rf hou.tar.gz cd houdini* tar -xzf houdini.tar.gz # copy required files into hou dir cp houdini_setup* ../hou/. # report library names ls -al dsolib/ # copy required libraries mv toolkit/cmake ../hou/toolkit/. mv toolkit/include ../hou/toolkit/. mv dsolib/libHoudini* ../hou/dsolib/. mv dsolib/libopenvdb_sesi* ../hou/dsolib/. mv dsolib/libblosc* ../hou/dsolib/. mv dsolib/libhboost* ../hou/dsolib/. mv dsolib/libz* ../hou/dsolib/. mv dsolib/libbz2* ../hou/dsolib/. mv dsolib/libtbb* ../hou/dsolib/. mv dsolib/libjemalloc* ../hou/dsolib/. mv dsolib/liblzma* ../hou/dsolib/. mv dsolib/libIex* ../hou/dsolib/. mv dsolib/libImath* ../hou/dsolib/. mv dsolib/libIlmThread* ../hou/dsolib/. cd .. elif [[ $PLATFORM =~ "macos" ]]; then # Exract files by mounting the downloaded dmg (we only really want to # expand Houdini.framework) hdiutil attach hou.dmg pkgutil --expand-full /Volumes/Houdini/Houdini.pkg Houdini hdiutil detach /Volumes/Houdini rm hou.dmg # Move the required Frameworks and delete the extracted src mkdir -p hou/Frameworks mv Houdini/Framework.pkg/Payload/Houdini.framework hou/Frameworks/Houdini.framework rm -rf Houdini # Report library names ls -al hou/Frameworks/Houdini.framework/Libraries # Remove unused resources cd hou/Frameworks/Houdini.framework/Resources/ rm -rf $(ls | grep -e toolkit -v) cd - # Handle libraries. On some versions of MacOS with older versions of ld, # ld will complain (error) if shared libraries contain missing files which # are referenced with LC_LOAD_DYLIB or LC_RPATH entries (even though they # are not explicitly required at link time). We still want to delete these # unused libs as they occupt ~1-2GB. To handle this, we generate a unique # list of libs that our direct dependencies reference and create an empty # shared dylib in their place. cd hou/Frameworks/Houdini.framework/Libraries # Remove any folders here, they aren't needed rm -rf $(ls -p | grep /) # Remove any library that does not match the -e patterns (inverse grep with -v) unused_libraries=$(ls | \ grep -e libHoudini \ -e libopenvdb_sesi \ -e libblosc \ -e libhboost \ -e libz \ -e libbz2 \ -e libtbb \ -e libjemalloc \ -e liblzma \ -e libIex \ -e libImath \ -e libIlmThread \ -v) rm -rf ${unused_libraries} # Create an empty valid shared lib echo '' | clang -x c -shared -o libempty.dylib - # Generate a unique list of libs that our remaining libs reference for i in $(ls); do otool -LX $i >> libnames; done sort -u libnames | grep @rpath | cut -f1 -d' ' | xargs > rpaths # Recreate unused libraries that have been deleted as empty shared dylibs # to keep ld happy for libpath in $(cat rpaths); do libpath=${libpath#"@rpath/"} echo "Checking $libpath" if [ ! -f $libpath ]; then echo "Creating empty library at $libpath" mkdir -p $(dirname $libpath) cp libempty.dylib $libpath fi done rm libempty.dylib cd - fi # write hou into hou.tar.gz and cleanup tar -czvf hou.tar.gz hou # move hou.tar.gz into hou subdirectory rm -rf hou/* mv hou.tar.gz hou # inspect size of tarball ls -lart hou/hou.tar.gz openvdb-13.0.0/ci/download_vdb_caches.py000077500000000000000000000047561510223237100201600ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 import os import sys import time import threading import zipfile import argparse try: from urllib.request import urlretrieve except ImportError: from urllib import urlretrieve parser = argparse.ArgumentParser(description='VDB files to download') parser.add_argument('--files', '-f', type=str, nargs='+', help='files to download i.e. bunny.vdb fire.vdb') args = parser.parse_args() vdbs = [ 'armadillo.vdb', 'boat_points.vdb', 'buddha.vdb', 'bunny.vdb', 'bunny_cloud.vdb', 'bunny_points.vdb', 'crawler.vdb', 'cube.vdb', 'dragon.vdb', 'emu.vdb', 'explosion.vdb', 'fire.vdb', 'icosahedron.vdb', 'iss.vdb', 'smoke1.vdb', 'smoke2.vdb', 'space.vdb', 'sphere.vdb', 'sphere_points.vdb', 'torus.vdb', 'torus_knot.vdb', 'utahteapot.vdb', 'venusstatue.vdb', 'waterfall_points.vdb' ] if args.files: vdbs = list(set(vdbs) & set(args.files)) if not vdbs: raise RuntimeError('No valid VDBs specified for download') # forma urls in the form: # 'https://artifacts.aswf.io/io/aswf/openvdb/models/buddha.vdb/1.0.0/buddha.vdb-1.0.0.zip' vdb_urls = [] for vdb in vdbs: url = 'https://artifacts.aswf.io/io/aswf/openvdb/models/' + \ vdb +'/1.0.0/' + vdb + '-1.0.0.zip' vdb_urls.append(url) def download(link, filelocation): urlretrieve(link, filelocation) # Init downloads downloads = dict() for url in vdb_urls: zip_filename = os.path.basename(url) print('Initiating download "' + url + '"') download_thread = threading.Thread(target=download, args=(url,zip_filename)) download_thread.start() downloads[zip_filename] = download_thread sys.stdout.flush() # Process files while downloads: zip_file = None while not zip_file: time.sleep(1) for file, thread in downloads.items(): if not thread.is_alive(): thread.join() zip_file = file break # Remove the entry del downloads[zip_file] try: # Extract the downloaded zip print('Extracting "' + zip_file + '"...') sys.stdout.flush() with zipfile.ZipFile(zip_file, 'r') as zip_ref: zip_ref.extractall() print('Cleaning up "' + zip_file + '"...') sys.stdout.flush() if os.path.isfile(zip_file): os.remove(zip_file) except Exception as e: print(e) pass openvdb-13.0.0/ci/extract_test_examples.sh000077500000000000000000000066121510223237100205720ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 ################################################################################# # This script extracts all code blocks from AX documentation which are NOT # # marked as cpp/sh/unparsed and attempts to parse or compile them through the # # vdb_ax command line binary. Code blocks can be marked with a preceding # # notation to determine compilation mode: # # = points # # = volumes # # = all # # If not marked, code is only parsed (though ideally all code blocks should be # # compiled) # ################################################################################# set -e ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../" VDB_AX=$ROOT/build/openvdb_cmd/vdb_ax/vdb_ax DOCS=() DOCS+=($ROOT/doc/ax/ax.txt) DOCS+=($ROOT/doc/ax/axcplusplus.txt) DOCS+=($ROOT/doc/ax/axexamples.txt) # DOCS+=($ROOT/doc/ax/axfunctionlist.txt) do not test this file DOCS+=($ROOT/doc/ax/doc.txt) uncompiled=0 for DOC in "${DOCS[@]}"; do echo "Checking doxygen code in '$DOC...'" # Make sure the file exists if [ ! -f $DOC ]; then echo "Could not find '$DOC.'" exit -1 fi # Extract all code segments from doxygen documentation in between @code and @endcode data=$(sed -n '/@code.* *$/,/^ *@endcode *$/p' $DOC) str="" compile="" skip=false count=0 # For each extracted line, rebuild each code segment from @code and @endcode and # run it through a vdb_ax binary if necessary while IFS= read -r line; do # If the code is marked as unparsed, c++ or shell, skip if [[ "$line" == "@code{.unparsed}" ]]; then skip=true elif [[ "$line" == "@code{.cpp}" ]]; then skip=true elif [[ "$line" == "@code{.sh}" ]]; then skip=true elif [[ $line == @code* ]]; then str="" compile="none" elif [[ $line == "@code"* ]]; then str="" compile="volumes" elif [[ $line == "@code"* ]]; then str="" compile="points" elif [[ $line == "@code"* ]]; then str="" compile="" elif [[ $line == @endcode ]]; then echo -e "\nTesting [$count]:" if [ "$skip" = true ]; then echo "Skipping the following unparsed/c++/shell code:" echo -e "$str" | sed 's/^/ /' else # parse if [ "$compile" = "none" ]; then $VDB_AX analyze -s "$str" -v uncompiled=$((uncompiled+1)) else $VDB_AX analyze -s "$str" --try-compile $compile -v fi fi skip=false count=$((count+1)) str="" compile="none" else str+="$line"$'\n' fi done <<< "$data" done echo "" echo "Extract test examples completed successfully" if [ $uncompiled -gt 0 ]; then echo " with $uncompiled uncompiled tests" fi openvdb-13.0.0/ci/install_blosc.sh000077500000000000000000000015601510223237100170100ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex BLOSC_VERSION="$1" INSTALL_ROOT="$2" CMAKE_EXTRA=() if [ ! -z "${INSTALL_ROOT}" ]; then CMAKE_EXTRA+=("-DCMAKE_INSTALL_PREFIX=${INSTALL_ROOT}") fi git clone https://github.com/Blosc/c-blosc.git cd c-blosc if [ "$BLOSC_VERSION" != "latest" ]; then git checkout tags/v${BLOSC_VERSION} -b v${BLOSC_VERSION} fi mkdir build cd build # On MacOS there's a bug between blosc 1.14-1.20 where unistd isn't included # in zlib-1.2.8/gzlib.c. Provide -DPREFER_EXTERNAL_ZLIB to use the installed # version of zlib. # https://github.com/Blosc/python-blosc/issues/229 cmake \ -DPREFER_EXTERNAL_ZLIB=ON \ -DBUILD_STATIC=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_FUZZERS=OFF \ -DBUILD_BENCHMARKS=OFF \ "${CMAKE_EXTRA[@]}" \ .. make -j8 make install openvdb-13.0.0/ci/install_cppunit.sh000077500000000000000000000004711510223237100173700ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex CURL_VERSION="$1" wget -O cppunit.tar.gz https://dev-www.libreoffice.org/src/cppunit-${CURL_VERSION}.tar.gz tar -xzf cppunit.tar.gz cd cppunit-${CURL_VERSION} ./configure make -j8 make install openvdb-13.0.0/ci/install_doxygen.sh000077500000000000000000000006231510223237100173620ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex DOXYGEN_VERSION="$1" git clone https://github.com/doxygen/doxygen.git cd doxygen if [ "$DOXYGEN_VERSION" != "latest" ]; then git checkout Release_${DOXYGEN_VERSION} -b v${DOXYGEN_VERSION} fi mkdir build cd build cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ../. make -j8 make install openvdb-13.0.0/ci/install_exr.sh000077500000000000000000000005711510223237100165050ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex EXR_VERSION="$1" git clone https://github.com/AcademySoftwareFoundation/openexr.git cd openexr if [ "$EXR_VERSION" != "latest" ]; then git checkout tags/${EXR_VERSION} -b ${EXR_VERSION} fi mkdir build cd build cmake .. make -j$(nproc) sudo make install openvdb-13.0.0/ci/install_glfw.sh000077500000000000000000000005261510223237100166460ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex GLFW_VERSION="$1" git clone https://github.com/glfw/glfw.git cd glfw if [ "$GLFW_VERSION" != "latest" ]; then git checkout tags/${GLFW_VERSION} -b ${GLFW_VERSION} fi mkdir build cd build cmake .. make -j8 make install openvdb-13.0.0/ci/install_gtest.sh000077500000000000000000000005641510223237100170370ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex GTEST_VERSION="$1" git clone https://github.com/google/googletest.git cd googletest if [ "$GTEST_VERSION" != "latest" ]; then git checkout tags/${GTEST_VERSION} -b ${GTEST_VERSION} fi mkdir build cd build cmake .. make -j$(nproc) sudo make install openvdb-13.0.0/ci/install_imath.sh000077500000000000000000000005751510223237100170150ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex IMATH_VERSION="$1" git clone https://github.com/AcademySoftwareFoundation/Imath.git cd Imath if [ "$IMATH_VERSION" != "latest" ]; then git checkout tags/${IMATH_VERSION} -b ${IMATH_VERSION} fi mkdir build cd build cmake .. make -j$(nproc) sudo make install openvdb-13.0.0/ci/install_llvm_windows.sh000066400000000000000000000033361510223237100204320ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex LLVM_VER="$1" LLVM_CRT="$2" # Legacy define for older versions of LLVM LLVM_LEGACY_CRT_DEFINE="" if [[ "${LLVM_CRT}" == "MultiThreaded" ]]; then LLVM_LEGACY_CRT_DEFINE="MT" elif [[ "${LLVM_CRT}" == "MultiThreadedDebug" ]]; then LLVM_LEGACY_CRT_DEFINE="MTd" elif [[ "${LLVM_CRT}" == "MultiThreadedDLL" ]]; then LLVM_LEGACY_CRT_DEFINE="MD" elif [[ "${LLVM_CRT}" == "MultiThreadedDebugDLL" ]]; then LLVM_LEGACY_CRT_DEFINE="MDd" fi git clone -b llvmorg-${LLVM_VER} --depth 1 https://github.com/llvm/llvm-project.git llvm cd llvm mkdir .build cd .build cmake -B . -S ../llvm -A x64 -G "Visual Studio 17 2022" -Thost=x64 \ -DCMAKE_INSTALL_PREFIX="${HOME}/llvm_install" \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_ENABLE_ASSERTIONS=OFF \ -DLLVM_ENABLE_PROJECTS="" \ -DLLVM_ENABLE_RUNTIMES="" \ -DLLVM_ENABLE_UNWIND_TABLES=OFF \ -DLLVM_TARGETS_TO_BUILD="host" \ -DLLVM_INCLUDE_BENCHMARKS=OFF \ -DLLVM_INCLUDE_EXAMPLES=OFF \ -DLLVM_INCLUDE_TESTS=OFF \ -DLLVM_INCLUDE_DOCS=OFF \ -DLLVM_INCLUDE_TOOLS=OFF \ -DLLVM_INCLUDE_UTILS=OFF \ -DLLVM_BUILD_BENCHMARKS=OFF \ -DLLVM_BUILD_EXAMPLES=OFF \ -DLLVM_BUILD_TESTS=OFF \ -DLLVM_BUILD_DOCS=OFF \ -DLLVM_BUILD_TOOLS=OFF \ -DLLVM_BUILD_UTILS=OFF \ -DLLVM_ENABLE_BINDINGS=OFF \ -DLLVM_ENABLE_OCAMLDOC=OFF \ -DLLVM_PARALLEL_COMPILE_JOBS=4 \ -DLLVM_PARALLEL_LINK_JOBS=4 \ -DCMAKE_MSVC_RUNTIME_LIBRARY=${LLVM_CRT} \ -DLLVM_USE_CRT_RELEASE=${LLVM_LEGACY_CRT_DEFINE} cmake --build . --parallel 4 --config Release --target install cd .. du -h .build -d0 du -h ${HOME}/llvm_install -d0 rm -rf .build openvdb-13.0.0/ci/install_macos.sh000077500000000000000000000031021510223237100170020ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -x # Remove Python3 symlinks in /usr/local/bin as workaround to brew update issues # https://github.com/actions/setup-python/issues/577 rm /usr/local/bin/2to3* || : rm /usr/local/bin/idle3* || : rm /usr/local/bin/pydoc* || : rm /usr/local/bin/python3* || : brew update brew install bash gnu-getopt # for CI scripts brew install boost brew install c-blosc brew install cmake brew install glfw brew install googletest brew install jq # for trivial parsing of brew json brew install openexr brew install nanobind # also installs the dependent python version brew install robin-map # required for nanobind brew install numpy # only for python tests brew install zlib brew install jemalloc # Alias python version installed by nanobind to path py_version=$(brew info nanobind --json | \ jq -cr '.[].dependencies[] | select(. | startswith("python"))') echo "Using python $py_version" # export for subsequent action steps (note, not exported for this env) echo "Python_ROOT_DIR=/usr/local/opt/$py_version" >> $GITHUB_ENV echo "/usr/local/opt/$py_version/bin" >> $GITHUB_PATH # use bash echo "/usr/local/opt/bash/bin" >> $GITHUB_PATH echo "/opt/homebrew/opt/bash/bin" >> $GITHUB_PATH # use gnu-getopt echo "/usr/local/opt/gnu-getopt/bin" >> $GITHUB_PATH echo "/opt/homebrew/opt/gnu-getopt/bin" >> $GITHUB_PATH LLVM_VERSION=$1 if [ ! -z "$LLVM_VERSION" ]; then if [ "$LLVM_VERSION" == "latest" ]; then brew install llvm else brew install llvm@$LLVM_VERSION fi fi openvdb-13.0.0/ci/install_nanobind.sh000077500000000000000000000011051510223237100174710ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex PYBIND11_VERSION="$1" INSTALL_ROOT="$2" CMAKE_EXTRA=() if [ ! -z "${INSTALL_ROOT}" ]; then CMAKE_EXTRA+=("-DCMAKE_INSTALL_PREFIX=${INSTALL_ROOT}") fi git clone --recurse-submodules https://github.com/wjakob/nanobind.git cd nanobind if [ "$PYBIND11_VERSION" != "latest" ]; then git checkout tags/v${PYBIND11_VERSION} -b v${PYBIND11_VERSION} fi mkdir build cd build cmake \ -DNB_TEST=OFF \ "${CMAKE_EXTRA[@]}" \ .. make -j8 sudo make install openvdb-13.0.0/ci/install_tbb_macos.sh000077500000000000000000000002201510223237100176270ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -x brew update brew install tbb openvdb-13.0.0/ci/install_texlive.sh000077500000000000000000000014751510223237100173730ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex # Download the TeX Live installer wget https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz # Extract tar xzf install-tl-unx.tar.gz rm install-tl-unx.tar.gz cd install-tl-* # Run the installer with no docs or source installation ./install-tl --no-interaction --no-doc-install --no-src-install --scheme=minimal # Export the texlive PATH to GITHUB_PATH TEXLIVE_PATH=/usr/local/texlive/2025/bin/x86_64-linux export PATH=${TEXLIVE_PATH}:${PATH} echo "${TEXLIVE_PATH}" >> $GITHUB_PATH # Install the required packages tlmgr install latex-bin dvips collection-fontsrecommended collection-latexrecommended # Validate that installing dvips and latex has been successful dvips --version latex --version openvdb-13.0.0/ci/install_windows.ps1000066400000000000000000000014751510223237100174730ustar00rootroot00000000000000# Enable verbose and stop on error $ErrorActionPreference = "Stop" $VerbosePreference = "Continue" # Required dependencies $vcpkgPackages = @( "zlib", "libpng", "openexr", "tbb", "gtest", "cppunit", "blosc", "glfw3", "glew", "python3", "jemalloc", "boost-iostreams", "boost-interprocess", "boost-algorithm", "nanobind" ) # Update vcpkg vcpkg update # Allow the vcpkg command to fail once so we can retry with the latest try { vcpkg install $vcpkgPackages } catch { Write-Host "vcpkg install failed, retrying with latest ports..." # Retry the installation with updated ports Push-Location $env:VCPKG_INSTALLATION_ROOT git pull Pop-Location vcpkg update vcpkg install $vcpkgPackages } Write-Host "vcpkg install completed successfully" openvdb-13.0.0/ci/install_windows_cuda.ps1000066400000000000000000000203341510223237100204620ustar00rootroot00000000000000# Download and install CUDA on windows. Based off the scripts by: # https://github.com/ptheywood/cuda-cmake-github-actions ## ------------------- ## Constants ## ------------------- # Dictionary of known cuda versions and thier download URLS, which do not follow a consistent pattern :( $CUDA_KNOWN_URLS = @{ "8.0.44" = "http://developer.nvidia.com/compute/cuda/8.0/Prod/network_installers/cuda_8.0.44_win10_network-exe"; "8.0.61" = "http://developer.nvidia.com/compute/cuda/8.0/Prod2/network_installers/cuda_8.0.61_win10_network-exe"; "9.0.176" = "http://developer.nvidia.com/compute/cuda/9.0/Prod/network_installers/cuda_9.0.176_win10_network-exe"; "9.1.85" = "http://developer.nvidia.com/compute/cuda/9.1/Prod/network_installers/cuda_9.1.85_win10_network"; "9.2.148" = "http://developer.nvidia.com/compute/cuda/9.2/Prod2/network_installers2/cuda_9.2.148_win10_network"; "10.0.130" = "http://developer.nvidia.com/compute/cuda/10.0/Prod/network_installers/cuda_10.0.130_win10_network"; "10.1.105" = "http://developer.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.105_win10_network.exe"; "10.1.168" = "http://developer.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.168_win10_network.exe"; "10.1.243" = "http://developer.download.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.243_win10_network.exe"; "10.2.89" = "http://developer.download.nvidia.com/compute/cuda/10.2/Prod/network_installers/cuda_10.2.89_win10_network.exe"; "11.0.1" = "http://developer.download.nvidia.com/compute/cuda/11.0.1/network_installers/cuda_11.0.1_win10_network.exe"; "11.0.2" = "http://developer.download.nvidia.com/compute/cuda/11.0.2/network_installers/cuda_11.0.2_win10_network.exe"; "11.0.3" = "http://developer.download.nvidia.com/compute/cuda/11.0.3/network_installers/cuda_11.0.3_win10_network.exe"; "11.1.0" = "https://developer.download.nvidia.com/compute/cuda/11.1.0/network_installers/cuda_11.1.0_win10_network.exe"; "11.1.1" = "https://developer.download.nvidia.com/compute/cuda/11.1.1/network_installers/cuda_11.1.1_win10_network.exe"; "11.2.0" = "https://developer.download.nvidia.com/compute/cuda/11.2.0/network_installers/cuda_11.2.0_win10_network.exe"; "11.2.1" = "https://developer.download.nvidia.com/compute/cuda/11.2.1/network_installers/cuda_11.2.1_win10_network.exe"; "11.2.2" = "https://developer.download.nvidia.com/compute/cuda/11.2.2/network_installers/cuda_11.2.2_win10_network.exe"; "11.3.0" = "https://developer.download.nvidia.com/compute/cuda/11.3.0/network_installers/cuda_11.3.0_win10_network.exe"; "11.6.2" = "https://developer.download.nvidia.com/compute/cuda/11.6.2/network_installers/cuda_11.6.2_windows_network.exe"; "12.4.0" = "https://developer.download.nvidia.com/compute/cuda/12.4.0/network_installers/cuda_12.4.0_windows_network.exe" } # @todo - change this to be based on _MSC_VER intead, or invert it to be CUDA keyed instead? $VISUAL_STUDIO_MIN_CUDA = @{ "2022" = "12.4"; "2019" = "10.1"; "2017" = "10.0"; # Depends on which version of 2017! 9.0 to 10.0 depending on version "2015" = "8.0"; # might support older, unsure. } # cuda_runtime.h is in nvcc <= 10.2, but cudart >= 11.0 # @todo - make this easier to vary per CUDA version. $CUDA_PACKAGES_IN = @( "nvcc"; "visual_studio_integration"; "curand_dev"; "nvrtc_dev"; "cudart"; "thrust"; ) ## ------------------- ## Select CUDA version ## ------------------- # Get the cuda version from the environment as env:cuda. $CUDA_VERSION_FULL = $env:cuda # Make sure CUDA_VERSION_FULL is set and valid, otherwise error. # Validate CUDA version, extracting components via regex $cuda_ver_matched = $CUDA_VERSION_FULL -match "^(?[1-9][0-9]*)\.(?[0-9]+)\.(?[0-9]+)$" if(-not $cuda_ver_matched){ Write-Output "Invalid CUDA version specified, .. required. '$CUDA_VERSION_FULL'." exit 1 } $CUDA_MAJOR=$Matches.major $CUDA_MINOR=$Matches.minor $CUDA_PATCH=$Matches.patch ## --------------------------- ## Visual studio support check ## --------------------------- # Exit if visual studio is too new for the cuda version. $VISUAL_STUDIO = $env:visual_studio.trim() if ($VISUAL_STUDIO.length -ge 4) { $VISUAL_STUDIO_YEAR = $VISUAL_STUDIO.Substring($VISUAL_STUDIO.Length-4) if ($VISUAL_STUDIO_YEAR.length -eq 4 -and $VISUAL_STUDIO_MIN_CUDA.containsKey($VISUAL_STUDIO_YEAR)){ $MINIMUM_CUDA_VERSION = $VISUAL_STUDIO_MIN_CUDA[$VISUAL_STUDIO_YEAR] if ([version]$CUDA_VERSION_FULL -lt [version]$MINIMUM_CUDA_VERSION) { Write-Output "Error: Visual Studio $($VISUAL_STUDIO_YEAR) requires CUDA >= $($MINIMUM_CUDA_VERSION)" exit 1 } } } else { Write-Output "Warning: Unknown Visual Studio Version. CUDA version may be insufficient." } ## ------------------------------------------------ ## Select CUDA packages to install from environment ## ------------------------------------------------ $CUDA_PACKAGES = "" # for CUDA >= 11 cudart is a required package. # if([version]$CUDA_VERSION_FULL -ge [version]"11.0") { # if(-not $CUDA_PACKAGES_IN -contains "cudart") { # $CUDA_PACKAGES_IN += 'cudart' # } # } Foreach ($package in $CUDA_PACKAGES_IN) { # Make sure the correct package name is used for nvcc. if($package -eq "nvcc" -and [version]$CUDA_VERSION_FULL -lt [version]"9.1"){ $package="compiler" } elseif($package -eq "compiler" -and [version]$CUDA_VERSION_FULL -ge [version]"9.1") { $package="nvcc" } $CUDA_PACKAGES += " $($package)_$($CUDA_MAJOR).$($CUDA_MINOR)" } echo "$($CUDA_PACKAGES)" ## ----------------- ## Prepare download ## ----------------- # Select the download link if known, otherwise have a guess. $CUDA_REPO_PKG_REMOTE="" if($CUDA_KNOWN_URLS.containsKey($CUDA_VERSION_FULL)){ $CUDA_REPO_PKG_REMOTE=$CUDA_KNOWN_URLS[$CUDA_VERSION_FULL] } else{ # Guess what the url is given the most recent pattern (at the time of writing, 10.1) Write-Output "note: URL for CUDA ${$CUDA_VERSION_FULL} not known, estimating." $CUDA_REPO_PKG_REMOTE="http://developer.download.nvidia.com/compute/cuda/$($CUDA_MAJOR).$($CUDA_MINOR)/Prod/network_installers/cuda_$($CUDA_VERSION_FULL)_win10_network.exe" } $CUDA_REPO_PKG_LOCAL="cuda_$($CUDA_VERSION_FULL)_win10_network.exe" ## ------------ ## Install CUDA ## ------------ # Get CUDA network installer Write-Output "Downloading CUDA Network Installer for $($CUDA_VERSION_FULL) from: $($CUDA_REPO_PKG_REMOTE)" Invoke-WebRequest $CUDA_REPO_PKG_REMOTE -OutFile $CUDA_REPO_PKG_LOCAL | Out-Null if(Test-Path -Path $CUDA_REPO_PKG_LOCAL){ Write-Output "Downloading Complete" } else { Write-Output "Error: Failed to download $($CUDA_REPO_PKG_LOCAL) from $($CUDA_REPO_PKG_REMOTE)" exit 1 } # Invoke silent install of CUDA (via network installer) Write-Output "Installing CUDA $($CUDA_VERSION_FULL). Subpackages $($CUDA_PACKAGES)" Start-Process -Wait -FilePath .\"$($CUDA_REPO_PKG_LOCAL)" -ArgumentList "-s $($CUDA_PACKAGES)" # Check the return status of the CUDA installer. if (!$?) { Write-Output "Error: CUDA installer reported error. $($LASTEXITCODE)" exit 1 } # Store the CUDA_PATH in the environment for the current session, to be forwarded in the action. $CUDA_PATH = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$($CUDA_MAJOR).$($CUDA_MINOR)" $CUDA_PATH_VX_Y = "CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)" # Set environmental variables in this session $env:CUDA_PATH = "$($CUDA_PATH)" $env:CUDA_PATH_VX_Y = "$($CUDA_PATH_VX_Y)" Write-Output "CUDA_PATH $($CUDA_PATH)" Write-Output "CUDA_PATH_VX_Y $($CUDA_PATH_VX_Y)" # PATH needs updating elsewhere, anything in here won't persist. # Append $CUDA_PATH/bin to path. # Set CUDA_PATH as an environmental variable # If executing on github actions, emit the appropriate echo statements to update environment variables if (Test-Path "env:GITHUB_ACTIONS") { # Set paths for subsequent steps, using $env:CUDA_PATH echo "Adding CUDA to CUDA_PATH, CUDA_PATH_X_Y and PATH" echo "CUDA_PATH=$env:CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append echo "$env:CUDA_PATH_VX_Y=$env:CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append echo "$env:CUDA_PATH/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append } openvdb-13.0.0/ci/install_windows_numpy.ps1000066400000000000000000000006371510223237100207220ustar00rootroot00000000000000# Enable verbose and stop on error $ErrorActionPreference = "Stop" $VerbosePreference = "Continue" # Install numpy for tests & "$env:VCPKG_INSTALLATION_ROOT\installed\$env:VCPKG_DEFAULT_TRIPLET\tools\python3\python.exe" -m ensurepip --upgrade & "$env:VCPKG_INSTALLATION_ROOT\installed\$env:VCPKG_DEFAULT_TRIPLET\tools\python3\python.exe" -m pip install numpy Write-Host "pip numpy install completed successfully" openvdb-13.0.0/ci/test_install.sh000077500000000000000000000013251510223237100166640ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -e # Various tests to test the FindOpenVDB CMake modules and # general VDB installation # 1) Test basic CMakeLists is able to build vdb_print with # the expected VDB installation cmakelists=" cmake_minimum_required(VERSION 3.24) project(TestInstall LANGUAGES CXX) find_package(OpenVDB REQUIRED COMPONENTS openvdb) add_executable(test_vdb_print \"../openvdb_cmd/vdb_print/main.cc\") target_link_libraries(test_vdb_print OpenVDB::openvdb) " mkdir tmp cd tmp echo -e "$cmakelists" > CMakeLists.txt cmake -DCMAKE_MODULE_PATH=/usr/local/lib64/cmake/OpenVDB/ . cmake --build . --config Release --target test_vdb_print openvdb-13.0.0/ci/test_sonar.sh000077500000000000000000000024221510223237100163370ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 set -ex SONAR_VERSION=3.3.0.1492 wget -q https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VERSION}-linux.zip unzip sonar-scanner-cli-${SONAR_VERSION}-linux.zip mkdir coverage cd coverage for g in $(find ../build -name "*.gcno" -type f); do gcov -p -l -o $(dirname "$g") $(echo "$g" | sed -e 's/\/build\//\//' -e 's/\.gcno/\.cc/' -e 's/\/CMakeFiles.*\.dir\//\//') done cd .. sonar-scanner-${SONAR_VERSION}-linux/bin/sonar-scanner -X \ -Dsonar.projectKey=openvdb \ -Dsonar.links.homepage=https://www.openvdb.org/ \ -Dsonar.links.scm=https://github.com/AcademySoftwareFoundation/openvdb \ -Dsonar.links.issue=https://jira.aswf.io/projects/OVDB \ -Dsonar.sources=openvdb \ -Dsonar.exclusions=openvdb/cmd/**,openvdb/unittest/**,openvdb/viewer/**,openvdb/python/** \ -Dsonar.binaries=build/openvdb/unittest/vdb_test \ -Dsonar.tests=openvdb/unittest \ -Dsonar.sourceEncoding=UTF-8 \ -Dsonar.organization=danrbailey-github \ -Dsonar.cfamily.build-wrapper-output=build/bw_output \ -Dsonar.cfamily.gcov.reportsPath=coverage \ -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.login=$SONAR_TOKEN openvdb-13.0.0/cmake/000077500000000000000000000000001510223237100143045ustar00rootroot00000000000000openvdb-13.0.0/cmake/CPM.cmake000066400000000000000000000017011510223237100157240ustar00rootroot00000000000000# SPDX-License-Identifier: MIT # # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors set(CPM_DOWNLOAD_VERSION 0.40.2) set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d") if(CPM_SOURCE_CACHE) set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") elseif(DEFINED ENV{CPM_SOURCE_CACHE}) set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") else() set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") endif() # Expand relative path. This is important if the provided path contains a tilde (~) get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} ) include(${CPM_DOWNLOAD_LOCATION}) openvdb-13.0.0/cmake/FindBlosc.cmake000066400000000000000000000361571510223237100171650ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindBlosc --------- Find Blosc include dirs and libraries Use this module by invoking find_package with the form:: find_package(Blosc [version] [EXACT] # Minimum or EXACT version e.g. 1.5.0 [REQUIRED] # Fail with error if Blosc is not found ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``Blosc::blosc`` This module defines IMPORTED target Blosc::Blosc, if Blosc has been found. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Blosc_FOUND`` True if the system has the Blosc library. ``Blosc_VERSION`` The version of the Blosc library which was found. ``Blosc_INCLUDE_DIRS`` Include directories needed to use Blosc. ``Blosc_RELEASE_LIBRARIES`` Libraries needed to link to the release version of Blosc. ``Blosc_RELEASE_LIBRARY_DIRS`` Blosc release library directories. ``Blosc_DEBUG_LIBRARIES`` Libraries needed to link to the debug version of Blosc. ``Blosc_DEBUG_LIBRARY_DIRS`` Blosc debug library directories. Deprecated - use [RELEASE|DEBUG] variants: ``Blosc_LIBRARIES`` Libraries needed to link to Blosc. ``Blosc_LIBRARY_DIRS`` Blosc library directories. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``Blosc_INCLUDE_DIR`` The directory containing ``blosc.h``. ``Blosc_LIBRARY`` The path to the Blosc library. may include target_link_libraries() debug/optimized keywords ``Blosc_LIBRARY_RELEASE`` The path to the Blosc release library. ``Blosc_LIBRARY_DEBUG`` The path to the Blosc debug library. Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``Blosc_ROOT`` Preferred installation prefix. ``BLOSC_INCLUDEDIR`` Preferred include directory e.g. /include ``BLOSC_LIBRARYDIR`` Preferred library directory e.g. /lib ``BLOSC_DEBUG_SUFFIX`` Suffix of the debug version of blosc. Defaults to "_d", OR the empty string for VCPKG_TOOLCHAIN ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``BLOSC_USE_STATIC_LIBS`` Only search for static blosc libraries ``BLOSC_USE_EXTERNAL_SOURCES`` Set to ON if Blosc has been built using external sources for LZ4, snappy, zlib and zstd. Default is OFF. ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) mark_as_advanced( Blosc_INCLUDE_DIR Blosc_LIBRARY ) set(_FIND_BLOSC_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_BLOSC_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _BLOSC_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV BLOSC_ROOT from CMake 3.12 if(Blosc_ROOT) set(_BLOSC_ROOT ${Blosc_ROOT}) elseif(DEFINED ENV{Blosc_ROOT}) set(_BLOSC_ROOT $ENV{Blosc_ROOT}) elseif(BLOSC_ROOT) set(_BLOSC_ROOT ${BLOSC_ROOT}) elseif(DEFINED ENV{BLOSC_ROOT}) set(_BLOSC_ROOT $ENV{BLOSC_ROOT}) endif() # Additionally try and use pkconfig to find blosc if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() if(PKG_CONFIG_FOUND) pkg_check_modules(PC_Blosc QUIET blosc) endif() endif() # ------------------------------------------------------------------------ # Search for blosc include DIR # ------------------------------------------------------------------------ set(_BLOSC_INCLUDE_SEARCH_DIRS "") list(APPEND _BLOSC_INCLUDE_SEARCH_DIRS ${BLOSC_INCLUDEDIR} ${_BLOSC_ROOT} ${PC_Blosc_INCLUDE_DIRS} ${SYSTEM_LIBRARY_PATHS} ) # Look for a standard blosc header file. find_path(Blosc_INCLUDE_DIR blosc.h ${_FIND_BLOSC_ADDITIONAL_OPTIONS} PATHS ${_BLOSC_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include ) if(EXISTS "${Blosc_INCLUDE_DIR}/blosc.h") file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h" _blosc_version_major_string REGEX "#define BLOSC_VERSION_MAJOR +[0-9]+ " ) string(REGEX REPLACE "#define BLOSC_VERSION_MAJOR +([0-9]+).*$" "\\1" _blosc_version_major_string "${_blosc_version_major_string}" ) string(STRIP "${_blosc_version_major_string}" Blosc_VERSION_MAJOR) file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h" _blosc_version_minor_string REGEX "#define BLOSC_VERSION_MINOR +[0-9]+ " ) string(REGEX REPLACE "#define BLOSC_VERSION_MINOR +([0-9]+).*$" "\\1" _blosc_version_minor_string "${_blosc_version_minor_string}" ) string(STRIP "${_blosc_version_minor_string}" Blosc_VERSION_MINOR) file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h" _blosc_version_release_string REGEX "#define BLOSC_VERSION_RELEASE +[0-9]+ " ) string(REGEX REPLACE "#define BLOSC_VERSION_RELEASE +([0-9]+).*$" "\\1" _blosc_version_release_string "${_blosc_version_release_string}" ) string(STRIP "${_blosc_version_release_string}" Blosc_VERSION_RELEASE) unset(_blosc_version_major_string) unset(_blosc_version_minor_string) unset(_blosc_version_release_string) set(Blosc_VERSION ${Blosc_VERSION_MAJOR}.${Blosc_VERSION_MINOR}.${Blosc_VERSION_RELEASE}) endif() # ------------------------------------------------------------------------ # Search for blosc lib DIR # ------------------------------------------------------------------------ set(_BLOSC_LIBRARYDIR_SEARCH_DIRS "") list(APPEND _BLOSC_LIBRARYDIR_SEARCH_DIRS ${BLOSC_LIBRARYDIR} ${_BLOSC_ROOT} ${PC_Blosc_LIBRARY_DIRS} ${SYSTEM_LIBRARY_PATHS} ) set(Blosc_LIB_COMPONENTS "") # NOTE: Search for debug version first (see vcpkg hack) list(APPEND BLOSC_BUILD_TYPES DEBUG RELEASE) foreach(BUILD_TYPE ${BLOSC_BUILD_TYPES}) set(_BLOSC_LIB_NAME blosc) set(_BLOSC_CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH}) if(VCPKG_TOOLCHAIN) # Blosc is installed very strangely in VCPKG (debug/release libs have the # same name, static build uses external deps, dll doesn't) and blosc itself # comes with almost zero downstream CMake support for us to detect settings. # We should not support external package managers in our own modules like # this, but there doesn't seem to be a work around if(NOT DEFINED BLOSC_DEBUG_SUFFIX) set(BLOSC_DEBUG_SUFFIX "") endif() if(BUILD_TYPE STREQUAL RELEASE) if(EXISTS ${Blosc_LIBRARY_DEBUG}) get_filename_component(_BLOSC_DEBUG_DIR ${Blosc_LIBRARY_DEBUG} DIRECTORY) list(APPEND CMAKE_IGNORE_PATH ${_BLOSC_DEBUG_DIR}) endif() endif() endif() if(BUILD_TYPE STREQUAL DEBUG) if(NOT DEFINED BLOSC_DEBUG_SUFFIX) set(BLOSC_DEBUG_SUFFIX _d) endif() set(_BLOSC_LIB_NAME "${_BLOSC_LIB_NAME}${BLOSC_DEBUG_SUFFIX}") endif() find_library(Blosc_LIBRARY_${BUILD_TYPE} ${_BLOSC_LIB_NAME} ${_FIND_BLOSC_ADDITIONAL_OPTIONS} PATHS ${_BLOSC_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib ) list(APPEND Blosc_LIB_COMPONENTS ${Blosc_LIBRARY_${BUILD_TYPE}}) set(CMAKE_IGNORE_PATH ${_BLOSC_CMAKE_IGNORE_PATH}) endforeach() if(Blosc_LIBRARY_DEBUG AND Blosc_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(Blosc_LIBRARY optimized ${Blosc_LIBRARY_RELEASE} debug ${Blosc_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE}) endif() # FIXME: This probably should be set for both cases set(Blosc_LIBRARIES optimized ${Blosc_LIBRARY_RELEASE} debug ${Blosc_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Blosc_LIBRARY_RELEASE AND NOT Blosc_LIBRARY_DEBUG) set(Blosc_LIBRARY_DEBUG ${Blosc_LIBRARY_RELEASE}) set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE}) set(Blosc_LIBRARIES ${Blosc_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Blosc_LIBRARY_DEBUG AND NOT Blosc_LIBRARY_RELEASE) set(Blosc_LIBRARY_RELEASE ${Blosc_LIBRARY_DEBUG}) set(Blosc_LIBRARY ${Blosc_LIBRARY_DEBUG}) set(Blosc_LIBRARIES ${Blosc_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if("${Blosc_LIBRARY_RELEASE}" STREQUAL "${Blosc_LIBRARY_DEBUG}") set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE} ) set(Blosc_LIBRARIES ${Blosc_LIBRARY_RELEASE} ) endif() if(Blosc_LIBRARY) set(Blosc_FOUND TRUE) else() set(Blosc_FOUND FALSE) endif() # ------------------------------------------------------------------------ # Cache and set Blosc_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Blosc FOUND_VAR Blosc_FOUND REQUIRED_VARS Blosc_LIBRARY Blosc_INCLUDE_DIR VERSION_VAR Blosc_VERSION ) if(NOT Blosc_FOUND) if(Blosc_FIND_REQUIRED) message(FATAL_ERROR "Unable to find Blosc") endif() return() endif() # Partition release/debug lib vars set(Blosc_RELEASE_LIBRARIES ${Blosc_LIBRARY_RELEASE}) get_filename_component(Blosc_RELEASE_LIBRARY_DIRS ${Blosc_RELEASE_LIBRARIES} DIRECTORY) set(Blosc_DEBUG_LIBRARIES ${Blosc_LIBRARY_DEBUG}) get_filename_component(Blosc_DEBUG_LIBRARY_DIRS ${Blosc_DEBUG_LIBRARIES} DIRECTORY) set(Blosc_LIBRARIES ${Blosc_RELEASE_LIBRARIES}) set(Blosc_LIBRARY_DIRS ${Blosc_RELEASE_LIBRARY_DIRS}) set(Blosc_INCLUDE_DIRS ${Blosc_INCLUDE_DIR}) set(Blosc_INCLUDE_DIRS ${Blosc_INCLUDE_DIR}) # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static # lib is in use. If win32, we can't mark the import .libs as shared, so # these are always marked as UNKNOWN. Otherwise, infer from extension. set(BLOSC_LIB_TYPE UNKNOWN) if(BLOSC_USE_STATIC_LIBS) set(BLOSC_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_BLOSC_EXT ${Blosc_LIBRARY_RELEASE} EXT) if(_BLOSC_EXT STREQUAL ".a") set(BLOSC_LIB_TYPE STATIC) elseif(_BLOSC_EXT STREQUAL ".so" OR _BLOSC_EXT STREQUAL ".dylib") set(BLOSC_LIB_TYPE SHARED) endif() endif() get_filename_component(Blosc_LIBRARY_DIRS ${Blosc_LIBRARY_RELEASE} DIRECTORY) if(NOT TARGET Blosc::blosc) add_library(Blosc::blosc ${BLOSC_LIB_TYPE} IMPORTED) set_target_properties(Blosc::blosc PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_Blosc_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${Blosc_INCLUDE_DIRS}") # Standard location set_target_properties(Blosc::blosc PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${Blosc_LIBRARY}") # Release location if(EXISTS "${Blosc_LIBRARY_RELEASE}") set_property(TARGET Blosc::blosc APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(Blosc::blosc PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${Blosc_LIBRARY_RELEASE}") endif() # Debug location if(EXISTS "${Blosc_LIBRARY_DEBUG}") set_property(TARGET Blosc::blosc APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(Blosc::blosc PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" IMPORTED_LOCATION_DEBUG "${Blosc_LIBRARY_DEBUG}") endif() # Blosc may optionally be compiled with external sources for # lz4, snappy and zlib . Add them as interface libs if requested # (there doesn't seem to be a way to figure this out automatically). # We assume they live along side blosc if(BLOSC_USE_EXTERNAL_SOURCES) set_target_properties(Blosc::blosc PROPERTIES INTERFACE_LINK_DIRECTORIES "\$<\$:${Blosc_RELEASE_LIBRARY_DIRS}>;\$<\$:${Blosc_DEBUG_LIBRARY_DIRS}>") set(BLOSC_EXTERNAL_LIBRARIES lz4 snappy zlib zstd) foreach(BLOSC_EXTERNAL_LIB ${BLOSC_EXTERNAL_LIBRARIES}) foreach(BUILD_TYPE ${BLOSC_BUILD_TYPES}) set(_BLOSC_CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH}) if(VCPKG_TOOLCHAIN) if(BUILD_TYPE STREQUAL RELEASE) list(APPEND CMAKE_IGNORE_PATH ${Blosc_DEBUG_LIBRARY_DIRS}) else() list(APPEND CMAKE_IGNORE_PATH ${Blosc_RELEASE_LIBRARY_DIRS}) endif() endif() find_library(${BLOSC_EXTERNAL_LIB}_LIBRARY_${BUILD_TYPE} ${BLOSC_EXTERNAL_LIB} ${_FIND_BLOSC_ADDITIONAL_OPTIONS} PATHS ${_BLOSC_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib) if(NOT ${BLOSC_EXTERNAL_LIB}_LIBRARY_${BUILD_TYPE}) if(BUILD_TYPE STREQUAL DEBUG) find_library(${BLOSC_EXTERNAL_LIB}_LIBRARY_${BUILD_TYPE} "${BLOSC_EXTERNAL_LIB}d" ${_FIND_BLOSC_ADDITIONAL_OPTIONS} PATHS ${_BLOSC_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib) endif() endif() set(CMAKE_IGNORE_PATH ${_BLOSC_CMAKE_IGNORE_PATH}) endforeach() if(${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG AND ${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(${BLOSC_EXTERNAL_LIB}_LIBRARY optimized ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE} debug ${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(${BLOSC_EXTERNAL_LIB}_LIBRARY ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE}) endif() # FIXME: This probably should be set for both cases set(${BLOSC_EXTERNAL_LIB}_LIBRARIES optimized ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE} debug ${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE AND NOT ${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG) set(${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE}) set(${BLOSC_EXTERNAL_LIB}_LIBRARY ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE}) set(${BLOSC_EXTERNAL_LIB}_LIBRARIES ${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG AND NOT ${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE) set(${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE ${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}) set(${BLOSC_EXTERNAL_LIB}_LIBRARY ${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}) set(${BLOSC_EXTERNAL_LIB}_LIBRARIES ${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}) endif() target_link_libraries(Blosc::blosc INTERFACE $<$:${${BLOSC_EXTERNAL_LIB}_LIBRARY_RELEASE}> $<$:${${BLOSC_EXTERNAL_LIB}_LIBRARY_DEBUG}>) endforeach() endif() endif() openvdb-13.0.0/cmake/FindJemalloc.cmake000066400000000000000000000122371510223237100176420ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindJemalloc ----------- Find Jemalloc include dirs and libraries Use this module by invoking find_package with the form:: find_package(Jemalloc [version] [EXACT] # Minimum or EXACT version [REQUIRED] # Fail with error if Jemalloc is not found ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``Jemalloc::jemalloc`` This module defines IMPORTED target Jemalloc::jemalloc, if Jemalloc has been found. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Jemalloc_FOUND`` True if the system has the Jemalloc library. ``Jemalloc_VERSION`` The version of the Jemalloc library which was found. ``Jemalloc_LIBRARIES`` Libraries needed to link to Jemalloc. ``Jemalloc_LIBRARY_DIRS`` Jemalloc library directories. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``Jemalloc_LIBRARY`` The path to the Jemalloc library. Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``Jemalloc_ROOT`` Preferred installation prefix. ``JEMALLOC_LIBRARYDIR`` Preferred library directory e.g. /lib ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``JEMALLOC_USE_STATIC_LIBS`` Only search for static jemalloc libraries ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) mark_as_advanced( Jemalloc_LIBRARY ) set(_FIND_JEMALLOC_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_JEMALLOC_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _JEMALLOC_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV JEMALLOC_ROOT from CMake 3.12 if(Jemalloc_ROOT) set(_JEMALLOC_ROOT ${Jemalloc_ROOT}) elseif(DEFINED ENV{Jemalloc_ROOT}) set(_JEMALLOC_ROOT $ENV{Jemalloc_ROOT}) elseif(JEMALLOC_ROOT) set(_JEMALLOC_ROOT ${JEMALLOC_ROOT}) elseif(DEFINED ENV{JEMALLOC_ROOT}) set(_JEMALLOC_ROOT $ENV{JEMALLOC_ROOT}) endif() # Additionally try and use pkconfig to find jemalloc if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() pkg_check_modules(PC_Jemalloc QUIET jemalloc) # ------------------------------------------------------------------------ # Search for Jemalloc lib DIR # ------------------------------------------------------------------------ set(_JEMALLOC_LIBRARYDIR_SEARCH_DIRS "") list(APPEND _JEMALLOC_LIBRARYDIR_SEARCH_DIRS ${JEMALLOC_LIBRARYDIR} ${_JEMALLOC_ROOT} ${PC_Jemalloc_LIBDIR} ${SYSTEM_LIBRARY_PATHS} ) # Library suffix handling set(_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(MSVC) if(JEMALLOC_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") else() list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_dll.lib") endif() else() if(JEMALLOC_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() endif() # Build suffix directories set(JEMALLOC_PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib ) find_library(Jemalloc_LIBRARY jemalloc ${_FIND_JEMALLOC_ADDITIONAL_OPTIONS} PATHS ${_JEMALLOC_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${JEMALLOC_PATH_SUFFIXES} ) # Reset library suffix set(CMAKE_FIND_LIBRARY_SUFFIXES ${_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) unset(_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) # ------------------------------------------------------------------------ # Cache and set Jemalloc_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Jemalloc FOUND_VAR Jemalloc_FOUND REQUIRED_VARS Jemalloc_LIBRARY VERSION_VAR Jemalloc_VERSION ) if(Jemalloc_FOUND) # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static # lib is in use. If win32, we can't mark the import .libs as shared, so # these are always marked as UNKNOWN. Otherwise, infer from extension. set(JEMALLOC_LIB_TYPE UNKNOWN) if(JEMALLOC_USE_STATIC_LIBS) set(JEMALLOC_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_JEMALLOC_EXT ${Jemalloc_LIBRARY} EXT) if(_JEMALLOC_EXT STREQUAL ".a") set(JEMALLOC_LIB_TYPE STATIC) elseif(_JEMALLOC_EXT STREQUAL ".so" OR _JEMALLOC_EXT STREQUAL ".dylib") set(JEMALLOC_LIB_TYPE SHARED) endif() endif() set(Jemalloc_LIBRARIES ${Jemalloc_LIBRARY}) get_filename_component(Jemalloc_LIBRARY_DIRS ${Jemalloc_LIBRARY} DIRECTORY) if(NOT TARGET Jemalloc::jemalloc) add_library(Jemalloc::jemalloc ${JEMALLOC_LIB_TYPE} IMPORTED) set_target_properties(Jemalloc::jemalloc PROPERTIES IMPORTED_LOCATION "${Jemalloc_LIBRARIES}" INTERFACE_COMPILE_OPTIONS "${PC_Jemalloc_CFLAGS_OTHER}" ) endif() elseif(Jemalloc_FIND_REQUIRED) message(FATAL_ERROR "Unable to find Jemalloc") endif() openvdb-13.0.0/cmake/FindLog4cplus.cmake000066400000000000000000000263711510223237100177740ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindLog4cplus ------------- Find Log4cplus include dirs and libraries Use this module by invoking find_package with the form:: find_package(Log4cplus [version] [EXACT] # Minimum or EXACT version [REQUIRED] # Fail with error if Log4cplus is not found ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``Log4cplus::Log4cplus`` This module defines IMPORTED target Log4cplus::log4cplus, if Log4cplus has been found. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Log4cplus_FOUND`` True if the system has the Log4cplus library. ``Log4cplus_VERSION`` The version of the Log4cplus library which was found. ``Log4cplus_INCLUDE_DIRS`` Include directories needed to use Log4cplus. ``Log4cplus_RELEASE_LIBRARIES`` Libraries needed to link to the release version of Log4cplus. ``Log4cplus_RELEASE_LIBRARY_DIRS`` Log4cplus release library directories. ``Log4cplus_DEBUG_LIBRARIES`` Libraries needed to link to the debug version of Log4cplus. ``Log4cplus_DEBUG_LIBRARY_DIRS`` Log4cplus debug library directories. Deprecated - use [RELEASE|DEBUG] variants: ``Log4cplus_LIBRARIES`` Libraries needed to link to Log4cplus. ``Log4cplus_LIBRARY_DIRS`` Log4cplus library directories. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``Log4cplus_INCLUDE_DIR`` The directory containing ``log4cplus/version.h``. ``Log4cplus_LIBRARY`` The path to the Log4cplus library. may include target_link_libraries() debug/optimized keywords. ``Log4cplus_LIBRARY_RELEASE`` The path to the Log4cplus release library. ``Log4cplus_LIBRARY_DEBUG`` The path to the Log4cplus debug library. Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``Log4cplus_ROOT`` Preferred installation prefix. ``LOG4CPLUS_INCLUDEDIR`` Preferred include directory e.g. /include ``LOG4CPLUS_LIBRARYDIR`` Preferred library directory e.g. /lib ``LOG4CPLUS_DEBUG_SUFFIX`` Suffix of the debug version of the log4cplus lib. Defaults to "D". ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``LOG4CPLUS_USE_STATIC_LIBS`` Only search for static log4cplus libraries ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) mark_as_advanced( Log4cplus_INCLUDE_DIR Log4cplus_LIBRARY ) set(_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _LOG4CPLUS_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV LOG4CPLUS_ROOT from CMake 3.12 if(Log4cplus_ROOT) set(_LOG4CPLUS_ROOT ${Log4cplus_ROOT}) elseif(DEFINED ENV{Log4cplus_ROOT}) set(_LOG4CPLUS_ROOT $ENV{Log4cplus_ROOT}) elseif(LOG4CPLUS_ROOT) set(_LOG4CPLUS_ROOT ${LOG4CPLUS_ROOT}) elseif(DEFINED ENV{LOG4CPLUS_ROOT}) set(_LOG4CPLUS_ROOT $ENV{LOG4CPLUS_ROOT}) endif() # Additionally try and use pkconfig to find log4cplus if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() if(PKG_CONFIG_FOUND) pkg_check_modules(PC_Log4cplus QUIET log4cplus) endif() endif() # ------------------------------------------------------------------------ # Search for Log4cplus include DIR # ------------------------------------------------------------------------ set(_LOG4CPLUS_INCLUDE_SEARCH_DIRS "") list(APPEND _LOG4CPLUS_INCLUDE_SEARCH_DIRS ${LOG4CPLUS_INCLUDEDIR} ${_LOG4CPLUS_ROOT} ${PC_Log4cplus_INCLUDEDIR} ${SYSTEM_LIBRARY_PATHS} ) # Look for a standard log4cplus header file. find_path(Log4cplus_INCLUDE_DIR log4cplus/version.h ${_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS} PATHS ${_LOG4CPLUS_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include ) if(EXISTS "${Log4cplus_INCLUDE_DIR}/log4cplus/version.h") file(STRINGS "${Log4cplus_INCLUDE_DIR}/log4cplus/version.h" _log4cplus_version_string REGEX "#define LOG4CPLUS_VERSION LOG4CPLUS_MAKE_VERSION" ) string(REGEX REPLACE "#define LOG4CPLUS_VERSION LOG4CPLUS_MAKE_VERSION\((.*)\).*$" "\\1" _log4cplus_version_string "${_log4cplus_version_string}" ) string(REGEX REPLACE "[(]([0-9]+),.*[)].*$" "\\1" Log4cplus_MAJOR_VERSION "${_log4cplus_version_string}" ) string(REGEX REPLACE "[(].+, ([0-9]+),.+[)].*$" "\\1" Log4cplus_MINOR_VERSION "${_log4cplus_version_string}" ) string(REGEX REPLACE "[(].*,.*, ([0-9]+)[)].*$" "\\1" Log4cplus_PATCH_VERSION "${_log4cplus_version_string}" ) unset(_log4cplus_version_string) set(Log4cplus_VERSION ${Log4cplus_MAJOR_VERSION}.${Log4cplus_MINOR_VERSION}.${Log4cplus_PATCH_VERSION}) endif() # ------------------------------------------------------------------------ # Search for Log4cplus lib DIR # ------------------------------------------------------------------------ if(NOT DEFINED LOG4CPLUS_DEBUG_SUFFIX) set(LOG4CPLUS_DEBUG_SUFFIX D) endif() set(_LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS "") list(APPEND _LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS ${LOG4CPLUS_LIBRARYDIR} ${_LOG4CPLUS_ROOT} ${PC_Log4cplus_LIBDIR} ${SYSTEM_LIBRARY_PATHS} ) # Library suffix handling set(_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(MSVC) if(LOG4CPLUS_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") endif() else() if(LOG4CPLUS_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() endif() set(Log4cplus_LIB_COMPONENTS "") list(APPEND LOG4CPLUS_BUILD_TYPES RELEASE DEBUG) foreach(BUILD_TYPE ${LOG4CPLUS_BUILD_TYPES}) set(_LOG4CPLUS_LIB_NAME log4cplus) if(BUILD_TYPE STREQUAL DEBUG) set(_LOG4CPLUS_LIB_NAME "${_LOG4CPLUS_LIB_NAME}${LOG4CPLUS_DEBUG_SUFFIX}") endif() find_library(Log4cplus_LIBRARY_${BUILD_TYPE} ${_LOG4CPLUS_LIB_NAME} ${_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS} PATHS ${_LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib ) list(APPEND Log4cplus_LIB_COMPONENTS ${Log4cplus_LIBRARY_${BUILD_TYPE}}) endforeach() # Reset library suffix set(CMAKE_FIND_LIBRARY_SUFFIXES ${_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) unset(_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) if(Log4cplus_LIBRARY_DEBUG AND Log4cplus_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(Log4cplus_LIBRARY optimized ${Log4cplus_LIBRARY_RELEASE} debug ${Log4cplus_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE}) endif() # FIXME: This probably should be set for both cases set(Log4cplus_LIBRARIES optimized ${Log4cplus_LIBRARY_RELEASE} debug ${Log4cplus_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Log4cplus_LIBRARY_RELEASE AND NOT Log4cplus_LIBRARY_DEBUG) set(Log4cplus_LIBRARY_DEBUG ${Log4cplus_LIBRARY_RELEASE}) set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE}) set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Log4cplus_LIBRARY_DEBUG AND NOT Log4cplus_LIBRARY_RELEASE) set(Log4cplus_LIBRARY_RELEASE ${Log4cplus_LIBRARY_DEBUG}) set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_DEBUG}) set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if("${Log4cplus_LIBRARY_RELEASE}" STREQUAL "${Log4cplus_LIBRARY_DEBUG}") set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE} ) set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_RELEASE} ) endif() if(Log4cplus_LIBRARY) set(Log4cplus_FOUND TRUE) else() set(Log4cplus_FOUND FALSE) endif() # ------------------------------------------------------------------------ # Cache and set Log4cplus_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Log4cplus FOUND_VAR Log4cplus_FOUND REQUIRED_VARS Log4cplus_LIBRARY Log4cplus_INCLUDE_DIR VERSION_VAR Log4cplus_VERSION ) if(NOT Log4cplus_FOUND) if(Log4cplus_FIND_REQUIRED) message(FATAL_ERROR "Unable to find Log4cplus") endif() return() endif() # Partition release/debug lib vars set(Log4cplus_RELEASE_LIBRARIES ${Log4cplus_LIBRARY_RELEASE}) get_filename_component(Log4cplus_RELEASE_LIBRARY_DIRS ${Log4cplus_RELEASE_LIBRARIES} DIRECTORY) set(Log4cplus_DEBUG_LIBRARIES ${Log4cplus_LIBRARY_DEBUG}) get_filename_component(Log4cplus_DEBUG_LIBRARY_DIRS ${Log4cplus_DEBUG_LIBRARIES} DIRECTORY) set(Log4cplus_LIBRARIES ${Log4cplus_RELEASE_LIBRARIES}) set(Log4cplus_LIBRARY_DIRS ${Log4cplus_RELEASE_LIBRARY_DIRS}) set(Log4cplus_INCLUDE_DIRS ${Log4cplus_INCLUDE_DIR}) # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static # lib is in use. If win32, we can't mark the import .libs as shared, so # these are always marked as UNKNOWN. Otherwise, infer from extension. set(LOG4CPLUS_LIB_TYPE UNKNOWN) if(LOG4CPLUS_USE_STATIC_LIBS) set(LOG4CPLUS_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_LOG4CPLUS_EXT ${Log4cplus_LIBRARY} EXT) if(_LOG4CPLUS_EXT STREQUAL ".a") set(LOG4CPLUS_LIB_TYPE STATIC) elseif(_LOG4CPLUS_EXT STREQUAL ".so" OR _LOG4CPLUS_EXT STREQUAL ".dylib") set(LOG4CPLUS_LIB_TYPE SHARED) endif() endif() get_filename_component(Log4cplus_LIBRARY_DIRS ${Log4cplus_LIBRARY_RELEASE} DIRECTORY) if(NOT TARGET Log4cplus::log4cplus) add_library(Log4cplus::log4cplus ${LOG4CPLUS_LIB_TYPE} IMPORTED) set_target_properties(Log4cplus::log4cplus PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_Log4cplus_CFLAGS_OTHER}" INTERFACE_INCLUDE_DIRECTORIES "${Log4cplus_INCLUDE_DIRS}") # Standard location set_target_properties(Log4cplus::log4cplus PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX;RC" IMPORTED_LOCATION "${Log4cplus_LIBRARY}") # WIN32 APIs if(WIN32) set_target_properties(Log4cplus::log4cplus PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "ws2_32;advapi32") endif() # Release location if(EXISTS "${Log4cplus_LIBRARY_RELEASE}") set_property(TARGET Log4cplus::log4cplus APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(Log4cplus::log4cplus PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX;RC" IMPORTED_LOCATION_RELEASE "${Log4cplus_LIBRARY_RELEASE}") endif() # Debug location if(EXISTS "${Log4cplus_LIBRARY_DEBUG}") set_property(TARGET Log4cplus::log4cplus APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(Log4cplus::log4cplus PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX;RC" IMPORTED_LOCATION_DEBUG "${Log4cplus_LIBRARY_DEBUG}") endif() endif() openvdb-13.0.0/cmake/FindNCCL.cmake000066400000000000000000000022661510223237100166340ustar00rootroot00000000000000include (FindPackageHandleStandardArgs) if(NCCL_ROOT) set(_NCCL_ROOT ${NCCL_ROOT}) elseif(DEFINED ENV{NCCL_ROOT}) set(_NCCL_ROOT $ENV{NCCL_ROOT}) endif() set(_NCCL_INCLUDE_SEARCH_DIRS "") list(APPEND _NCCL_INCLUDE_SEARCH_DIRS ${_NCCL_ROOT}/include ) find_path(NCCL_INCLUDE_DIR NAMES nccl.h PATHS ${_NCCL_INCLUDE_SEARCH_DIRS} ) set(_NCCL_LIBRARY_SEARCH_DIRS "") list(APPEND _NCCL_LIBRARY_SEARCH_DIRS ${_NCCL_ROOT}/bin ) find_library(NCCL_LIBRARY NAMES nccl PATHS ${_NCCL_LIBRARY_SEARCH_DIRS} ) find_package_handle_standard_args(NCCL REQUIRED_VARS NCCL_INCLUDE_DIR NCCL_LIBRARY) if (NCCL_FOUND) mark_as_advanced(NCCL_INCLUDE_DIR) mark_as_advanced(NCCL_LIBRARY) endif() if (NCCL_FOUND AND NOT TARGET NCCL::NCCL) add_library(NCCL::NCCL SHARED IMPORTED) if(MSVC) string(REPLACE ".lib" ".dll" NCCL_DLL ${NCCL_LIBRARY}) set_property(TARGET NCCL::NCCL PROPERTY IMPORTED_LOCATION ${NCCL_DLL}) set_property(TARGET NCCL::NCCL PROPERTY IMPORTED_IMPLIB ${NCCL_LIBRARY}) else() set_property(TARGET NCCL::NCCL PROPERTY IMPORTED_LOCATION ${NCCL_LIBRARY}) endif() target_include_directories(NCCL::NCCL INTERFACE ${NCCL_INCLUDE_DIR}) endif() openvdb-13.0.0/cmake/FindOpenEXR.cmake000066400000000000000000000362211510223237100173730ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindOpenEXR ----------- Find OpenEXR include dirs and libraries Use this module by invoking find_package with the form:: find_package(OpenEXR [version] [EXACT] # Minimum or EXACT version [REQUIRED] # Fail with error if OpenEXR is not found [COMPONENTS ...] # OpenEXR libraries by their canonical name # e.g. "IlmImf" for "libIlmImf" ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``OpenEXR::IlmImf`` The IlmImf library target. ``OpenEXR::IlmImfUtil`` The IlmImfUtil library target. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``OpenEXR_FOUND`` True if the system has the OpenEXR library. ``OpenEXR_VERSION`` The version of the OpenEXR library which was found. ``OpenEXR_INCLUDE_DIRS`` Include directories needed to use OpenEXR. ``OpenEXR_RELEASE_LIBRARIES`` Libraries needed to link to the release version of OpenEXR. ``OpenEXR_RELEASE_LIBRARY_DIRS`` OpenEXR release library directories. ``OpenEXR_DEBUG_LIBRARIES`` Libraries needed to link to the debug version of OpenEXR. ``OpenEXR_DEBUG_LIBRARY_DIRS`` OpenEXR debug library directories. ``OpenEXR_DEFINITIONS`` Definitions to use when compiling code that uses OpenEXR. ``OpenEXR_{COMPONENT}_FOUND`` True if the system has the named OpenEXR component. Deprecated - use [RELEASE|DEBUG] variants: ``OpenEXR_LIBRARIES`` Libraries needed to link to OpenEXR. ``OpenEXR_LIBRARY_DIRS`` OpenEXR library directories. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``OpenEXR_INCLUDE_DIR`` The directory containing ``OpenEXR/config-auto.h``. ``OpenEXR_{COMPONENT}_LIBRARY`` Individual component libraries for OpenEXR. may include target_link_libraries() debug/optimized keywords. ``OpenEXR_{COMPONENT}_LIBRARY_RELEASE`` Individual component libraries for OpenEXR release ``OpenEXR_{COMPONENT}_LIBRARY_DEBUG`` Individual component libraries for OpenEXR debug Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``OpenEXR_ROOT`` Preferred installation prefix. ``OPENEXR_INCLUDEDIR`` Preferred include directory e.g. /include ``OPENEXR_LIBRARYDIR`` Preferred library directory e.g. /lib ``OPENEXR_DEBUG_SUFFIX`` Suffix of the debug version of openexr libs. Defaults to "_d". ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``OPENEXR_USE_STATIC_LIBS`` Only search for static openexr libraries ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) mark_as_advanced( OpenEXR_INCLUDE_DIR OpenEXR_LIBRARY ) set(_FIND_OPENEXR_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_OPENEXR_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _OPENEXR_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV OPENEXR_ROOT from CMake 3.12 if(OpenEXR_ROOT) set(_OPENEXR_ROOT ${OpenEXR_ROOT}) elseif(DEFINED ENV{OpenEXR_ROOT}) set(_OPENEXR_ROOT $ENV{OpenEXR_ROOT}) elseif(OPENEXR_ROOT) set(_OPENEXR_ROOT ${OPENEXR_ROOT}) elseif(DEFINED ENV{OPENEXR_ROOT}) set(_OPENEXR_ROOT $ENV{OPENEXR_ROOT}) endif() # Additionally try and use pkconfig to find OpenEXR if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() pkg_check_modules(PC_OpenEXR QUIET OpenEXR) endif() # ------------------------------------------------------------------------ # Search for OpenEXR include DIR # ------------------------------------------------------------------------ set(_OPENEXR_INCLUDE_SEARCH_DIRS "") list(APPEND _OPENEXR_INCLUDE_SEARCH_DIRS ${OPENEXR_INCLUDEDIR} ${_OPENEXR_ROOT} ${PC_OpenEXR_INCLUDEDIR} ${SYSTEM_LIBRARY_PATHS} ) # Look for a standard OpenEXR header file. find_path(OpenEXR_INCLUDE_DIR OpenEXRConfig.h ${_FIND_OPENEXR_ADDITIONAL_OPTIONS} PATHS ${_OPENEXR_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/OpenEXR include/OpenEXR OpenEXR ) if(EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h") # Get the EXR version information from the config header file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" _openexr_version_major_string REGEX "#define OPENEXR_VERSION_MAJOR " ) string(REGEX REPLACE "#define OPENEXR_VERSION_MAJOR" "" _openexr_version_major_string "${_openexr_version_major_string}" ) string(STRIP "${_openexr_version_major_string}" OpenEXR_VERSION_MAJOR) file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" _openexr_version_minor_string REGEX "#define OPENEXR_VERSION_MINOR " ) string(REGEX REPLACE "#define OPENEXR_VERSION_MINOR" "" _openexr_version_minor_string "${_openexr_version_minor_string}" ) string(STRIP "${_openexr_version_minor_string}" OpenEXR_VERSION_MINOR) unset(_openexr_version_major_string) unset(_openexr_version_minor_string) set(OpenEXR_VERSION ${OpenEXR_VERSION_MAJOR}.${OpenEXR_VERSION_MINOR}) endif() if(${OpenEXR_VERSION} VERSION_GREATER_EQUAL 3.0) set(_OPENEXR_COMPONENT_LIST OpenEXR OpenEXRUtil Iex IlmThread) else() set(_OPENEXR_COMPONENT_LIST IlmImf IlmImfUtil) endif() if(OpenEXR_FIND_COMPONENTS) set(OPENEXR_COMPONENTS_PROVIDED TRUE) set(_IGNORED_COMPONENTS "") foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) if(NOT ${COMPONENT} IN_LIST _OPENEXR_COMPONENT_LIST) list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) endif() endforeach() if(_IGNORED_COMPONENTS) message(STATUS "Ignoring unknown components of OpenEXR:") foreach(COMPONENT ${_IGNORED_COMPONENTS}) message(STATUS " ${COMPONENT}") endforeach() list(REMOVE_ITEM OpenEXR_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) endif() else() set(OPENEXR_COMPONENTS_PROVIDED FALSE) set(OpenEXR_FIND_COMPONENTS ${_OPENEXR_COMPONENT_LIST}) endif() # ------------------------------------------------------------------------ # Search for OPENEXR lib DIR # ------------------------------------------------------------------------ if(NOT DEFINED OPENEXR_DEBUG_SUFFIX) set(OPENEXR_DEBUG_SUFFIX _d) endif() set(_OPENEXR_LIBRARYDIR_SEARCH_DIRS "") # Append to _OPENEXR_LIBRARYDIR_SEARCH_DIRS in priority order list(APPEND _OPENEXR_LIBRARYDIR_SEARCH_DIRS ${OPENEXR_LIBRARYDIR} ${_OPENEXR_ROOT} ${PC_OpenEXR_LIBDIR} ${SYSTEM_LIBRARY_PATHS} ) set(OpenEXR_LIB_COMPONENTS "") list(APPEND OPENEXR_BUILD_TYPES RELEASE DEBUG) foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) foreach(BUILD_TYPE ${OPENEXR_BUILD_TYPES}) set(_TMP_SUFFIX "") if(BUILD_TYPE STREQUAL DEBUG) set(_TMP_SUFFIX ${OPENEXR_DEBUG_SUFFIX}) endif() set(_OpenEXR_Version_Suffix "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}") set(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(WIN32) if(OPENEXR_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.lib") endif() list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.lib") else() if(OPENEXR_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.a") else() if(APPLE) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.dylib") else() list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.so") endif() endif() list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.a") endif() # Find the lib find_library(OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${COMPONENT} ${_FIND_OPENEXR_ADDITIONAL_OPTIONS} PATHS ${_OPENEXR_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib ) if(EXISTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) list(APPEND OpenEXR_LIB_COMPONENTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) list(APPEND OpenEXR_LIB_COMPONENTS_${BUILD_TYPE} ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) endif() # Reset library suffix set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) unset(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) unset(_OpenEXR_Version_Suffix) unset(_TMP_SUFFIX) endforeach() if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND OpenEXR_${COMPONENT}_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(OpenEXR_${COMPONENT}_LIBRARY optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}) endif() # FIXME: This probably should be set for both cases set(OpenEXR_${COMPONENT}_LIBRARIES optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(OpenEXR_${COMPONENT}_LIBRARY_RELEASE AND NOT OpenEXR_${COMPONENT}_LIBRARY_DEBUG) set(OpenEXR_${COMPONENT}_LIBRARY_DEBUG ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}) set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}) set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND NOT OpenEXR_${COMPONENT}_LIBRARY_RELEASE) set(OpenEXR_${COMPONENT}_LIBRARY_RELEASE ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}) set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}) set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if("${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}") set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} ) set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} ) endif() if(OpenEXR_${COMPONENT}_LIBRARY) set(OpenEXR_${COMPONENT}_FOUND TRUE) else() set(OpenEXR_${COMPONENT}_FOUND FALSE) endif() endforeach() # ------------------------------------------------------------------------ # Cache and set OPENEXR_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenEXR FOUND_VAR OpenEXR_FOUND REQUIRED_VARS OpenEXR_INCLUDE_DIR OpenEXR_LIB_COMPONENTS VERSION_VAR OpenEXR_VERSION HANDLE_COMPONENTS ) if(NOT OpenEXR_FOUND) if(OpenEXR_FIND_REQUIRED) message(FATAL_ERROR "Unable to find OpenEXR") endif() return() endif() # Partition release/debug lib vars set(OpenEXR_RELEASE_LIBRARIES "") set(OpenEXR_RELEASE_LIBRARY_DIRS "") set(OpenEXR_DEBUG_LIBRARIES "") set(OpenEXR_DEBUG_LIBRARY_DIRS "") foreach(LIB ${OpenEXR_LIB_COMPONENTS_RELEASE}) get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY) list(APPEND OpenEXR_RELEASE_LIBRARIES ${LIB}) list(APPEND OpenEXR_RELEASE_LIBRARY_DIRS ${_EXR_LIBDIR}) endforeach() foreach(LIB ${OpenEXR_LIB_COMPONENTS_DEBUG}) get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY) list(APPEND OpenEXR_DEBUG_LIBRARIES ${LIB}) list(APPEND OpenEXR_DEBUG_LIBRARY_DIRS ${_EXR_LIBDIR}) endforeach() list(REMOVE_DUPLICATES OpenEXR_RELEASE_LIBRARY_DIRS) list(REMOVE_DUPLICATES OpenEXR_DEBUG_LIBRARY_DIRS) set(OpenEXR_LIBRARIES ${OpenEXR_RELEASE_LIBRARIES}) set(OpenEXR_LIBRARY_DIRS ${OpenEXR_RELEASE_LIBRARY_DIRS}) # We have to add both include and include/OpenEXR to the include # path in case OpenEXR and IlmBase are installed separately. # # Make sure we get the absolute path to avoid issues where # /usr/include/OpenEXR/../ is picked up and passed to gcc from cmake # which won't correctly compute /usr/include as an implicit system # dir if the path is relative: # # https://github.com/AcademySoftwareFoundation/openvdb/issues/632 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129 set(_OpenEXR_Parent_Dir "") get_filename_component(_OpenEXR_Parent_Dir ${OpenEXR_INCLUDE_DIR}/../ ABSOLUTE) set(OpenEXR_INCLUDE_DIRS) list(APPEND OpenEXR_INCLUDE_DIRS ${_OpenEXR_Parent_Dir} ${OpenEXR_INCLUDE_DIR} ) unset(_OpenEXR_Parent_Dir) # Configure imported target foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static # lib is in use. If win32, we can't mark the import .libs as shared, so # these are always marked as UNKNOWN. Otherwise, infer from extension. set(OpenEXR_${COMPONENT}_LIB_TYPE UNKNOWN) if(OPENEXR_USE_STATIC_LIBS) set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_OpenEXR_${COMPONENT}_EXT ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} EXT) if(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".a") set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC) elseif(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".so" OR ${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".dylib") set(OpenEXR_${COMPONENT}_LIB_TYPE SHARED) endif() endif() set(OpenEXR_${COMPONENT}_DEFINITIONS) # Add the OPENEXR_DLL define if the library is not static on WIN32 if(WIN32) if(NOT OpenEXR_${COMPONENT}_LIB_TYPE STREQUAL STATIC) list(APPEND OpenEXR_${COMPONENT}_DEFINITIONS OPENEXR_DLL) endif() endif() if(NOT TARGET OpenEXR::${COMPONENT}) add_library(OpenEXR::${COMPONENT} ${OpenEXR_${COMPONENT}_LIB_TYPE} IMPORTED) set_target_properties(OpenEXR::${COMPONENT} PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_OpenEXR_CFLAGS_OTHER}" INTERFACE_COMPILE_DEFINITIONS "${OpenEXR_${COMPONENT}_DEFINITIONS}" INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIRS}") # Standard location set_target_properties(OpenEXR::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${OpenEXR_${COMPONENT}_LIBRARY}") # Release location if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}") set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(OpenEXR::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}") endif() # Debug location if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}") set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(OpenEXR::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" IMPORTED_LOCATION_DEBUG "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}") endif() endif() endforeach() openvdb-13.0.0/cmake/FindOpenVDB.cmake000066400000000000000000000625321510223237100173540ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindOpenVDB ----------- Find OpenVDB include dirs, libraries and settings Use this module by invoking find_package with the form:: find_package(OpenVDB [version] [EXACT] # Minimum or EXACT version [REQUIRED] # Fail with error if OpenVDB is not found [COMPONENTS ...] # OpenVDB libraries by their canonical name # e.g. "openvdb" for "libopenvdb", # "pyopenvdb" for the python plugin # "openvdb_ax" for the OpenVDB AX extension # "openvdb_houdini" for the houdini plugin # "nanovdb" for the nanovdb extension ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``OpenVDB::openvdb`` The core openvdb library target. ``OpenVDB::openvdb_je`` The core openvdb library target with jemalloc. ``OpenVDB::pyopenvdb`` The openvdb python library target. ``OpenVDB::openvdb_houdini`` The openvdb houdini library target. ``OpenVDB::openvdb_ax`` The openvdb_ax library target. ``OpenVDB::nanovdb`` The nanovdb library target. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``OpenVDB_FOUND`` True if the system has the OpenVDB library. ``OpenVDB_VERSION`` The version of the OpenVDB library which was found. ``OpenVDB_INCLUDE_DIRS`` Include directories needed to use OpenVDB. ``OpenVDB_LIBRARIES`` Libraries needed to link to OpenVDB. ``OpenVDB_LIBRARY_DIRS`` OpenVDB library directories. ``OpenVDB_DEFINITIONS`` Definitions to use when compiling code that uses OpenVDB. ``OpenVDB_${COMPONENT}_FOUND`` True if the system has the named OpenVDB component. ``OpenVDB_USES_BLOSC`` True if the OpenVDB Library has been built with blosc support ``OpenVDB_USES_ZLIB`` True if the OpenVDB Library has been built with zlib support ``OpenVDB_USES_LOG4CPLUS`` True if the OpenVDB Library has been built with log4cplus support ``OpenVDB_USES_IMATH_HALF`` True if the OpenVDB Library has been built with Imath half support ``OpenVDB_USES_DELAYED_LOADING`` True if the OpenVDB Library has been built with delayed-loading ``OpenVDB_ABI`` Set if this module was able to determine the ABI number the located OpenVDB Library was built against. Unset otherwise. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``OpenVDB_INCLUDE_DIR`` The directory containing ``openvdb/version.h``. ``OpenVDB_${COMPONENT}_INCLUDE_DIR`` Individual component include directories for OpenVDB ``OpenVDB_${COMPONENT}_LIBRARY`` Individual component libraries for OpenVDB Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``OpenVDB_ROOT`` Preferred installation prefix. ``OPENVDB_INCLUDEDIR`` Preferred include directory e.g. /include ``OPENVDB_LIBRARYDIR`` Preferred library directory e.g. /lib ``OPENVDB_${COMPONENT}_ROOT`` Preferred installation prefix of a specific component. ``OPENVDB_${COMPONENT}_INCLUDEDIR`` Preferred include directory of a specific component e.g. /include ``OPENVDB_${COMPONENT}_LIBRARYDIR`` Preferred library directory of a specific component e.g. /lib ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``OPENVDB_USE_STATIC_LIBS`` Only search for static openvdb libraries ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) # Include utility functions for version information include(${CMAKE_CURRENT_LIST_DIR}/OpenVDBUtils.cmake) mark_as_advanced( OpenVDB_INCLUDE_DIR OpenVDB_LIBRARY ) set(_FIND_OPENVDB_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_OPENVDB_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() set(_OPENVDB_COMPONENT_LIST openvdb openvdb_je pyopenvdb openvdb_ax openvdb_houdini nanovdb ) if(OpenVDB_FIND_COMPONENTS) set(OPENVDB_COMPONENTS_PROVIDED TRUE) set(_IGNORED_COMPONENTS "") foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS}) if(NOT ${COMPONENT} IN_LIST _OPENVDB_COMPONENT_LIST) list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) endif() endforeach() if(_IGNORED_COMPONENTS) message(STATUS "Ignoring unknown components of OpenVDB:") foreach(COMPONENT ${_IGNORED_COMPONENTS}) message(STATUS " ${COMPONENT}") endforeach() list(REMOVE_ITEM OpenVDB_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) endif() else() set(OPENVDB_COMPONENTS_PROVIDED FALSE) set(OpenVDB_FIND_COMPONENTS openvdb) endif() # always make sure openvdb is picked up as a component i.e. # find_package(OpenVDB COMPONENTS pyopenvdb) results in both # openvdb and pyopenvdb targets. Also make sure it appears # first in the component lists. list(INSERT OpenVDB_FIND_COMPONENTS 0 openvdb) list(REMOVE_DUPLICATES OpenVDB_FIND_COMPONENTS) # Set _OPENVDB_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV OPENVDB_ROOT from CMake 3.12 if(OpenVDB_ROOT) set(_OPENVDB_ROOT ${OpenVDB_ROOT}) elseif(DEFINED ENV{OpenVDB_ROOT}) set(_OPENVDB_ROOT $ENV{OpenVDB_ROOT}) elseif(OPENVDB_ROOT) set(_OPENVDB_ROOT ${OPENVDB_ROOT}) elseif(DEFINED ENV{OPENVDB_ROOT}) set(_OPENVDB_ROOT $ENV{OPENVDB_ROOT}) endif() # Additionally try and use pkconfig to find OpenVDB if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() pkg_check_modules(PC_OpenVDB QUIET OpenVDB) endif() # This CMake module supports being called from external packages AND from # within the OpenVDB repository for building openvdb components with the # core library build disabled. Determine where we are being called from: # # (repo structure = /cmake/FindOpenVDB.cmake) # (inst structure = /lib/cmake/OpenVDB/FindOpenVDB.cmake) get_filename_component(_DIR_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) if(${_DIR_NAME} STREQUAL "cmake") # Called from root repo for openvdb components elseif(${_DIR_NAME} STREQUAL "OpenVDB") # Set the install variable to track directories if this is being called from # an installed location and from another package. The expected installation # directory structure is: # /lib/cmake/OpenVDB/FindOpenVDB.cmake # /include # /bin get_filename_component(_IMPORT_PREFIX ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) get_filename_component(_IMPORT_PREFIX ${_IMPORT_PREFIX} DIRECTORY) get_filename_component(_IMPORT_PREFIX ${_IMPORT_PREFIX} DIRECTORY) set(_OPENVDB_INSTALL ${_IMPORT_PREFIX}) list(APPEND _OPENVDB_ROOT ${_OPENVDB_INSTALL}) endif() unset(_DIR_NAME) unset(_IMPORT_PREFIX) # ------------------------------------------------------------------------ # Search for OpenVDB include DIR # ------------------------------------------------------------------------ set(_OPENVDB_INCLUDE_SEARCH_DIRS "") list(APPEND _OPENVDB_INCLUDE_SEARCH_DIRS ${OPENVDB_INCLUDEDIR} ${_OPENVDB_ROOT} ${PC_OpenVDB_INCLUDE_DIRS} ${SYSTEM_LIBRARY_PATHS} ) foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS}) # Add in extra component paths set(_VDB_COMPONENT_SEARCH_DIRS ${_OPENVDB_INCLUDE_SEARCH_DIRS}) list(APPEND _VDB_COMPONENT_SEARCH_DIRS ${OPENVDB_${COMPONENT}_ROOT} ${OPENVDB_${COMPONENT}_INCLUDEDIR} ) if(_VDB_COMPONENT_SEARCH_DIRS) list(REMOVE_DUPLICATES _VDB_COMPONENT_SEARCH_DIRS) endif() # Look for a standard header files. if(${COMPONENT} STREQUAL "openvdb") # Look for a standard OpenVDB header file. find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR openvdb/version.h ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include ) elseif(${COMPONENT} STREQUAL "pyopenvdb") find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR pyopenvdb.h ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/python ${CMAKE_INSTALL_INCLUDEDIR}/openvdb ${CMAKE_INSTALL_INCLUDEDIR} include ) elseif(${COMPONENT} STREQUAL "openvdb_ax") # Look for a standard OpenVDB header file. find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR compiler/Compiler.h ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/openvdb_ax ${CMAKE_INSTALL_INCLUDEDIR}/openvdb_ax ${CMAKE_INSTALL_INCLUDEDIR} include ) elseif(${COMPONENT} STREQUAL "openvdb_houdini") # @note Expects both houdini_utils and openvdb_houdini folders # to be located in the same place find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR openvdb_houdini/SOP_NodeVDB.h ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/openvdb ${CMAKE_INSTALL_INCLUDEDIR} include ) elseif(${COMPONENT} STREQUAL "nanovdb") # Look for NanoVDB.h find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR NanoVDB.h ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/nanovdb ${CMAKE_INSTALL_INCLUDEDIR} include ) endif() unset(_VDB_COMPONENT_SEARCH_DIRS) endforeach() set(OpenVDB_INCLUDE_DIR ${OpenVDB_openvdb_INCLUDE_DIR} CACHE PATH "The OpenVDB core include directory") set(_OPENVDB_VERSION_HEADER "${OpenVDB_INCLUDE_DIR}/openvdb/version.h") OPENVDB_VERSION_FROM_HEADER("${_OPENVDB_VERSION_HEADER}" VERSION OpenVDB_VERSION MAJOR OpenVDB_MAJOR_VERSION MINOR OpenVDB_MINOR_VERSION PATCH OpenVDB_PATCH_VERSION ABI OpenVDB_ABI_FROM_HEADER # will be OpenVDB_MAJOR_VERSION prior to 8.1.0 ) if(OpenVDB_VERSION VERSION_LESS 8.1.0) set(_OPENVDB_HAS_NEW_VERSION_HEADER FALSE) # ABI gets computed later else() set(_OPENVDB_HAS_NEW_VERSION_HEADER TRUE) set(OpenVDB_ABI ${OpenVDB_ABI_FROM_HEADER}) endif() unset(OpenVDB_ABI_FROM_HEADER) # ------------------------------------------------------------------------ # Search for OPENVDB lib DIR # ------------------------------------------------------------------------ set(_OPENVDB_LIBRARYDIR_SEARCH_DIRS "") # Append to _OPENVDB_LIBRARYDIR_SEARCH_DIRS in priority order list(APPEND _OPENVDB_LIBRARYDIR_SEARCH_DIRS ${OPENVDB_LIBRARYDIR} ${_OPENVDB_ROOT} ${PC_OpenVDB_LIBRARY_DIRS} ${SYSTEM_LIBRARY_PATHS} ) # Library suffix handling set(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(OPENVDB_PYTHON_PATH_SUFFIXES lib64/python lib64/python3 lib/python lib/python3 ) # Recurse through all the site-packages and dist-packages on the file system file(GLOB PYTHON_SITE_PACKAGES ${CMAKE_INSTALL_FULL_LIBDIR}/python**/*) foreach(_site_package_full_dir ${PYTHON_SITE_PACKAGES}) string(REPLACE ${CMAKE_INSTALL_FULL_LIBDIR} "${CMAKE_INSTALL_LIBDIR}" _site_package_dir ${_site_package_full_dir}) list(APPEND OPENVDB_PYTHON_PATH_SUFFIXES ${_site_package_dir}) endforeach() set(OPENVDB_LIB_PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib ) list(REMOVE_DUPLICATES OPENVDB_PYTHON_PATH_SUFFIXES) list(REMOVE_DUPLICATES OPENVDB_LIB_PATH_SUFFIXES) # Static library setup if(MSVC) if(OPENVDB_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") endif() else() if(OPENVDB_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() endif() set(OpenVDB_LIB_COMPONENTS "") foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS}) message("COMPONENT = " ${COMPONENT}) set(LIB_NAME ${COMPONENT}) # Add in extra component paths set(_VDB_COMPONENT_SEARCH_DIRS ${_OPENVDB_LIBRARYDIR_SEARCH_DIRS}) list(APPEND _VDB_COMPONENT_SEARCH_DIRS ${OPENVDB_${COMPONENT}_ROOT} ${OPENVDB_${COMPONENT}_LIBRARYDIR} ) if(${COMPONENT} STREQUAL "pyopenvdb") set(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") # find non-prefixed find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME} ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${OPENVDB_PYTHON_PATH_SUFFIXES} ) set(CMAKE_FIND_LIBRARY_PREFIXES ${_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_PREFIXES}) elseif(${COMPONENT} STREQUAL "openvdb_je") # alias to the result of openvdb which should be handled first set(OpenVDB_${COMPONENT}_LIBRARY ${OpenVDB_openvdb_LIBRARY}) elseif(${COMPONENT} STREQUAL "nanovdb") # alias to the result of openvdb which should be handled first set(OpenVDB_${COMPONENT}_LIBRARY ${OpenVDB_openvdb_LIBRARY}) else() find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME} ${_FIND_OPENVDB_ADDITIONAL_OPTIONS} PATHS ${_VDB_COMPONENT_SEARCH_DIRS} PATH_SUFFIXES ${OPENVDB_LIB_PATH_SUFFIXES} ) endif() list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY}) if(${COMPONENT} STREQUAL "nanovdb") # nanovdb is headers-only, no lib component if(OpenVDB_${COMPONENT}_INCLUDE_DIR) set(OpenVDB_${COMPONENT}_FOUND TRUE) else() set(OpenVDB_${COMPONENT}_FOUND FALSE) endif() else() if(OpenVDB_${COMPONENT}_LIBRARY) set(OpenVDB_${COMPONENT}_FOUND TRUE) else() set(OpenVDB_${COMPONENT}_FOUND FALSE) endif() endif() unset(_VDB_COMPONENT_SEARCH_DIRS) endforeach() unset(OPENVDB_PYTHON_PATH_SUFFIXES) unset(OPENVDB_LIB_PATH_SUFFIXES) # Reset library suffix set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) unset(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) # ------------------------------------------------------------------------ # Cache and set OPENVDB_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenVDB FOUND_VAR OpenVDB_FOUND REQUIRED_VARS OpenVDB_INCLUDE_DIR OpenVDB_LIB_COMPONENTS VERSION_VAR OpenVDB_VERSION HANDLE_COMPONENTS ) # ------------------------------------------------------------------------ # Determine ABI number # ------------------------------------------------------------------------ # Set the ABI number the library was built against. The old system, # which didn't define the ABI in the build config, uses vdb_print if(NOT _OPENVDB_HAS_NEW_VERSION_HEADER) if(_OPENVDB_INSTALL) OPENVDB_ABI_VERSION_FROM_PRINT( "${_OPENVDB_INSTALL}/bin/vdb_print" ABI OpenVDB_ABI ) else() # Try and find vdb_print from the include path OPENVDB_ABI_VERSION_FROM_PRINT( "${OpenVDB_INCLUDE_DIR}/../bin/vdb_print" ABI OpenVDB_ABI ) endif() endif() if(NOT OpenVDB_FIND_QUIETLY) if(NOT OpenVDB_ABI) message(WARNING "Unable to determine OpenVDB ABI version from OpenVDB " "installation. The library major version \"${OpenVDB_MAJOR_VERSION}\" " "will be inferred. If this is not correct, use " "add_definitions(-DOPENVDB_ABI_VERSION_NUMBER=N)" ) else() message(STATUS "OpenVDB ABI Version: ${OpenVDB_ABI}") endif() endif() # ------------------------------------------------------------------------ # Handle OpenVDB dependencies and interface settings # ------------------------------------------------------------------------ # Handle openvdb_houdini first to configure search paths if(openvdb_houdini IN_LIST OpenVDB_FIND_COMPONENTS) include(OpenVDBHoudiniSetup) endif() # Add standard dependencies find_package(TBB REQUIRED COMPONENTS tbb) # Add deps for pyopenvdb if(pyopenvdb IN_LIST OpenVDB_FIND_COMPONENTS) find_package(Python REQUIRED) endif() # Add deps for openvdb_ax if(openvdb_ax IN_LIST OpenVDB_FIND_COMPONENTS) find_package(LLVM REQUIRED) find_library(found_LLVM LLVM HINTS ${LLVM_LIBRARY_DIRS}) if(found_LLVM) set(LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(_llvm_libs native core executionengine support mcjit passes objcarcopts) set(LLVM_LIBS "${_llvm_libs}") endif() if(NOT OpenVDB_FIND_QUIET) message(STATUS "Found LLVM: ${LLVM_DIR} (found version \"${LLVM_PACKAGE_VERSION}\")") endif() endif() # As the way we resolve optional libraries relies on library file names, use # the configuration options from the main CMakeLists.txt to allow users # to manually identify the requirements of OpenVDB builds if they know them. set(OpenVDB_USES_BLOSC ${USE_BLOSC}) set(OpenVDB_USES_ZLIB ${USE_ZLIB}) set(OpenVDB_USES_LOG4CPLUS ${USE_LOG4CPLUS}) set(OpenVDB_USES_IMATH_HALF ${USE_IMATH_HALF}) set(OpenVDB_USES_DELAYED_LOADING ${OPENVDB_USE_DELAYED_LOADING}) set(OpenVDB_DEFINITIONS) if(WIN32) if(OPENVDB_USE_STATIC_LIBS) list(APPEND OpenVDB_DEFINITIONS OPENVDB_STATICLIB) else() list(APPEND OpenVDB_DEFINITIONS OPENVDB_DLL) endif() # Newer version of OpenVDB define these in Platform.h, but they are also # provided here to maintain backwards compatibility with header include # others list(APPEND OpenVDB_DEFINITIONS _WIN32) list(APPEND OpenVDB_DEFINITIONS NOMINMAX) endif() if(MINGW) list(APPEND OpenVDB_DEFINITIONS _USE_MATH_DEFINES) endif() if(OpenVDB_ABI) # Newer version of OpenVDB defines this in version.h, but it is are also # provided here to maintain backwards compatibility with header include # others list(APPEND OpenVDB_DEFINITIONS OPENVDB_ABI_VERSION_NUMBER=${OpenVDB_ABI}) endif() # Configure deps if(_OPENVDB_HAS_NEW_VERSION_HEADER) OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_IMATH_HALF" OpenVDB_USES_IMATH_HALF) OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_BLOSC" OpenVDB_USES_BLOSC) OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_ZLIB" OpenVDB_USES_ZLIB) OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_DELAYED_LOADING" OpenVDB_USES_DELAYED_LOADING) elseif(NOT OPENVDB_USE_STATIC_LIBS) # Use GetPrerequisites to see which libraries this OpenVDB lib has linked to # which we can query for optional deps. This basically runs ldd/otoll/objdump # etc to track deps. We could use a vdb_config binary tools here to improve # this process include(GetPrerequisites) set(_EXCLUDE_SYSTEM_PREREQUISITES 1) set(_RECURSE_PREREQUISITES 0) set(_OPENVDB_PREREQUISITE_LIST) get_prerequisites(${OpenVDB_openvdb_LIBRARY} _OPENVDB_PREREQUISITE_LIST ${_EXCLUDE_SYSTEM_PREREQUISITES} ${_RECURSE_PREREQUISITES} "" "${SYSTEM_LIBRARY_PATHS}" ) unset(_EXCLUDE_SYSTEM_PREREQUISITES) unset(_RECURSE_PREREQUISITES) # Search for optional dependencies foreach(PREREQUISITE ${_OPENVDB_PREREQUISITE_LIST}) set(_HAS_DEP) get_filename_component(PREREQUISITE ${PREREQUISITE} NAME) string(FIND ${PREREQUISITE} "blosc" _HAS_DEP) if(NOT ${_HAS_DEP} EQUAL -1) set(OpenVDB_USES_BLOSC ON) endif() string(FIND ${PREREQUISITE} "zlib" _HAS_DEP) if(NOT ${_HAS_DEP} EQUAL -1) set(OpenVDB_USES_ZLIB ON) endif() string(FIND ${PREREQUISITE} "log4cplus" _HAS_DEP) if(NOT ${_HAS_DEP} EQUAL -1) set(OpenVDB_USES_LOG4CPLUS ON) endif() string(FIND ${PREREQUISITE} "Half" _HAS_DEP) if(NOT ${_HAS_DEP} EQUAL -1) set(OpenVDB_USES_IMATH_HALF ON) endif() string(FIND ${PREREQUISITE} "boost_iostreams" _HAS_DEP) if(NOT ${_HAS_DEP} EQUAL -1) set(OpenVDB_USES_DELAYED_LOADING ON) endif() endforeach() unset(_OPENVDB_PREREQUISITE_LIST) endif() if(OpenVDB_USES_BLOSC) find_package(Blosc REQUIRED) endif() if(OpenVDB_USES_ZLIB) find_package(ZLIB REQUIRED) endif() if(OpenVDB_USES_LOG4CPLUS) find_package(Log4cplus REQUIRED) endif() if(OpenVDB_USES_IMATH_HALF) find_package(Imath REQUIRED CONFIG) endif() if(OpenVDB_USES_DELAYED_LOADING) find_package(Boost REQUIRED COMPONENTS iostreams) endif() if(UNIX) find_package(Threads REQUIRED) endif() # Set deps. Note that the order here is important. If we're building against # Houdini we must include Imath deps first to ensure the users chosen # namespaced headers are correctly prioritized. Otherwise other include paths # from shared installs (including houdini) may pull in the wrong headers set(_OPENVDB_VISIBLE_DEPENDENCIES "") if(OpenVDB_USES_DELAYED_LOADING) list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES Boost::iostreams) list(APPEND OpenVDB_DEFINITIONS OPENVDB_USE_DELAYED_LOADING) endif() if(OpenVDB_USES_IMATH_HALF) list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES Imath::Imath) endif() if(OpenVDB_USES_LOG4CPLUS) list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES Log4cplus::log4cplus) list(APPEND OpenVDB_DEFINITIONS OPENVDB_USE_LOG4CPLUS) endif() list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES TBB::tbb ) if(UNIX) list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES Threads::Threads ) endif() set(_OPENVDB_HIDDEN_DEPENDENCIES) if(NOT OPENVDB_USE_STATIC_LIBS) if(OpenVDB_USES_BLOSC) list(APPEND _OPENVDB_HIDDEN_DEPENDENCIES Blosc::blosc) endif() if(OpenVDB_USES_ZLIB) list(APPEND _OPENVDB_HIDDEN_DEPENDENCIES ZLIB::ZLIB) endif() endif() if(openvdb_je IN_LIST OpenVDB_FIND_COMPONENTS) find_package(Jemalloc REQUIRED) endif() # ------------------------------------------------------------------------ # Configure imported targets # ------------------------------------------------------------------------ set(OpenVDB_LIBRARIES ${OpenVDB_LIB_COMPONENTS}) set(OpenVDB_INCLUDE_DIRS ${OpenVDB_INCLUDE_DIR}) set(OpenVDB_LIBRARY_DIRS "") foreach(LIB ${OpenVDB_LIB_COMPONENTS}) get_filename_component(_OPENVDB_LIBDIR ${LIB} DIRECTORY) list(APPEND OpenVDB_LIBRARY_DIRS ${_OPENVDB_LIBDIR}) endforeach() list(REMOVE_DUPLICATES OpenVDB_LIBRARY_DIRS) # OpenVDB::openvdb if(NOT TARGET OpenVDB::openvdb) set(OPENVDB_openvdb_LIB_TYPE UNKNOWN) if(OPENVDB_USE_STATIC_LIBS) set(OPENVDB_openvdb_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_OPENVDB_openvdb_EXT ${OpenVDB_openvdb_LIBRARY} EXT) if(_OPENVDB_openvdb_EXT STREQUAL ".a") set(OPENVDB_openvdb_LIB_TYPE STATIC) elseif(_OPENVDB_openvdb_EXT STREQUAL ".so" OR _OPENVDB_openvdb_EXT STREQUAL ".dylib") set(OPENVDB_openvdb_LIB_TYPE SHARED) endif() endif() add_library(OpenVDB::openvdb ${OPENVDB_openvdb_LIB_TYPE} IMPORTED) set_target_properties(OpenVDB::openvdb PROPERTIES IMPORTED_LOCATION "${OpenVDB_openvdb_LIBRARY}" INTERFACE_COMPILE_OPTIONS "${PC_OpenVDB_CFLAGS_OTHER}" INTERFACE_COMPILE_DEFINITIONS "${OpenVDB_DEFINITIONS}" INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_INCLUDE_DIR}" IMPORTED_LINK_DEPENDENT_LIBRARIES "${_OPENVDB_HIDDEN_DEPENDENCIES}" # non visible deps INTERFACE_LINK_LIBRARIES "${_OPENVDB_VISIBLE_DEPENDENCIES}" # visible deps (headers) INTERFACE_COMPILE_FEATURES cxx_std_17 ) endif() # OpenVDB::openvdb_je if(OpenVDB_openvdb_je_LIBRARY) if(NOT TARGET OpenVDB::openvdb_je) add_library(OpenVDB::openvdb_je INTERFACE IMPORTED) target_link_libraries(OpenVDB::openvdb_je INTERFACE OpenVDB::openvdb) target_link_libraries(OpenVDB::openvdb_je INTERFACE Jemalloc::jemalloc) endif() endif() # OpenVDB::pyopenvdb if(OpenVDB_pyopenvdb_LIBRARY) if(NOT TARGET OpenVDB::pyopenvdb) add_library(OpenVDB::pyopenvdb MODULE IMPORTED) set_target_properties(OpenVDB::pyopenvdb PROPERTIES IMPORTED_LOCATION "${OpenVDB_pyopenvdb_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_pyopenvdb_INCLUDE_DIR};${PYTHON_INCLUDE_DIR}" INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;${PYTHON_LIBRARIES}" INTERFACE_COMPILE_FEATURES cxx_std_17 ) endif() endif() # OpenVDB::openvdb_houdini if(OpenVDB_openvdb_houdini_LIBRARY) if(NOT TARGET OpenVDB::openvdb_houdini) add_library(OpenVDB::openvdb_houdini SHARED IMPORTED) set_target_properties(OpenVDB::openvdb_houdini PROPERTIES IMPORTED_LOCATION "${OpenVDB_openvdb_houdini_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_openvdb_houdini_INCLUDE_DIR}" INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;Houdini" INTERFACE_COMPILE_FEATURES cxx_std_17 ) endif() endif() # OpenVDB::openvdb_ax if(OpenVDB_openvdb_ax_LIBRARY) set(OPENVDB_openvdb_ax_LIB_TYPE UNKNOWN) if(OPENVDB_USE_STATIC_LIBS) set(OPENVDB_openvdb_ax_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_OPENVDB_openvdb_ax_EXT ${OpenVDB_openvdb_ax_LIBRARY} EXT) if(_OPENVDB_openvdb_ax_EXT STREQUAL ".a") set(OPENVDB_openvdb_ax_LIB_TYPE STATIC) elseif(_OPENVDB_openvdb_ax_EXT STREQUAL ".so" OR _OPENVDB_openvdb_ax_EXT STREQUAL ".dylib") set(OPENVDB_openvdb_ax_LIB_TYPE SHARED) endif() endif() if(NOT TARGET OpenVDB::openvdb_ax) add_library(OpenVDB::openvdb_ax UNKNOWN IMPORTED) set_target_properties(OpenVDB::openvdb_ax PROPERTIES IMPORTED_LOCATION "${OpenVDB_openvdb_ax_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_openvdb_ax_INCLUDE_DIR}" INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${LLVM_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;${LLVM_LIBS}" INTERFACE_COMPILE_FEATURES cxx_std_17 ) endif() endif() # OpenVDB::nanovdb if(OpenVDB_nanovdb_LIBRARY) if(NOT TARGET OpenVDB::nanovdb) add_library(OpenVDB::nanovdb INTERFACE IMPORTED) set_target_properties(OpenVDB::nanovdb PROPERTIES IMPORTED_LOCATION "${OpenVDB_nanovdb_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_nanovdb_INCLUDE_DIR}" INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;" INTERFACE_COMPILE_FEATURES cxx_std_17 ) endif() endif() unset(_OPENVDB_VISIBLE_DEPENDENCIES) unset(_OPENVDB_HIDDEN_DEPENDENCIES) openvdb-13.0.0/cmake/FindTBB.cmake000066400000000000000000000403051510223237100165200ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: FindTBB ------- Find Tbb include dirs and libraries Use this module by invoking find_package with the form:: find_package(TBB [version] [EXACT] # Minimum or EXACT version [REQUIRED] # Fail with error if Tbb is not found [COMPONENTS ...] # Tbb libraries by their canonical name # e.g. "tbb" for "libtbb" ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``TBB::tbb`` The tbb library target. ``TBB::tbbmalloc`` The tbbmalloc library target. ``TBB::tbbmalloc_proxy`` The tbbmalloc_proxy library target. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Tbb_FOUND`` True if the system has the Tbb library. ``Tbb_VERSION`` ``TBB_VERSION`` The version of the Tbb library which was found. ``Tbb_INCLUDE_DIRS`` Include directories needed to use Tbb. ``Tbb_RELEASE_LIBRARIES`` Libraries needed to link to the release version of Tbb. ``Tbb_RELEASE_LIBRARY_DIRS`` Tbb release library directories. ``Tbb_DEBUG_LIBRARIES`` Libraries needed to link to the debug version of Tbb. ``Tbb_DEBUG_LIBRARY_DIRS`` Tbb debug library directories. ``TBB_{COMPONENT}_FOUND`` True if the system has the named TBB component. Deprecated - use [RELEASE|DEBUG] variants: ``Tbb_LIBRARIES`` Libraries needed to link to Tbb. ``Tbb_LIBRARY_DIRS`` Tbb library directories. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables may also be set: ``Tbb_INCLUDE_DIR`` The directory containing ``tbb/tbb_stddef.h``. ``Tbb_{COMPONENT}_LIBRARY`` Individual component libraries for Tbb. may include target_link_libraries() debug/optimized keywords. ``Tbb_{COMPONENT}_LIBRARY_RELEASE`` Individual component libraries for Tbb release ``Tbb_{COMPONENT}_LIBRARY_DEBUG`` Individual debug component libraries for Tbb debug Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``TBB_ROOT`` Preferred installation prefix. ``TBB_INCLUDEDIR`` Preferred include directory e.g. /include ``TBB_LIBRARYDIR`` Preferred library directory e.g. /lib ``TBB_DEBUG_SUFFIX`` Suffix of the debug version of tbb. Defaults to "_debug". ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``TBB_USE_STATIC_LIBS`` Only search for static tbb libraries ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] cmake_minimum_required(VERSION 3.24) include(GNUInstallDirs) mark_as_advanced( Tbb_INCLUDE_DIR Tbb_LIBRARY ) set(_FIND_TBB_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_TBB_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() set(_TBB_COMPONENT_LIST tbb tbbmalloc tbbmalloc_proxy ) if(TBB_FIND_COMPONENTS) set(_TBB_COMPONENTS_PROVIDED TRUE) set(_IGNORED_COMPONENTS "") foreach(COMPONENT ${TBB_FIND_COMPONENTS}) if(NOT ${COMPONENT} IN_LIST _TBB_COMPONENT_LIST) list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) endif() endforeach() if(_IGNORED_COMPONENTS) message(STATUS "Ignoring unknown components of TBB:") foreach(COMPONENT ${_IGNORED_COMPONENTS}) message(STATUS " ${COMPONENT}") endforeach() list(REMOVE_ITEM TBB_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) endif() else() set(_TBB_COMPONENTS_PROVIDED FALSE) set(TBB_FIND_COMPONENTS ${_TBB_COMPONENT_LIST}) endif() if(TBB_ROOT) set(_TBB_ROOT ${TBB_ROOT}) elseif(DEFINED ENV{TBB_ROOT}) set(_TBB_ROOT $ENV{TBB_ROOT}) endif() # Additionally try and use pkconfig to find Tbb if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() if(PKG_CONFIG_FOUND) pkg_check_modules(PC_Tbb QUIET tbb) endif() endif() # ------------------------------------------------------------------------ # Search for tbb include DIR # ------------------------------------------------------------------------ set(_TBB_INCLUDE_SEARCH_DIRS "") list(APPEND _TBB_INCLUDE_SEARCH_DIRS ${TBB_INCLUDEDIR} ${_TBB_ROOT} ${PC_Tbb_INCLUDE_DIRS} ${SYSTEM_LIBRARY_PATHS} ) if(NOT Tbb_INCLUDE_DIR) # Look for a legacy tbb header file. find_path(Tbb_LEGACY_INCLUDE_DIR tbb/tbb_stddef.h ${_FIND_TBB_ADDITIONAL_OPTIONS} PATHS ${_TBB_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include ) else() set(Tbb_LEGACY_INCLUDE_DIR ${Tbb_INCLUDE_DIR}) endif() # Look for a new tbb header installation # From TBB 2021, tbb_stddef is removed and the directory include/tbb is # simply an alias for include/oneapi/tbb. Try and find the version header # in oneapi/tbb find_path(Tbb_INCLUDE_DIR oneapi/tbb/version.h ${_FIND_TBB_ADDITIONAL_OPTIONS} PATHS ${_TBB_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include ) set(_tbb_legacy_version_file "${Tbb_LEGACY_INCLUDE_DIR}/tbb/tbb_stddef.h") set(_tbb_version_file "${Tbb_INCLUDE_DIR}/oneapi/tbb/version.h") if(EXISTS ${_tbb_legacy_version_file}) if(EXISTS ${_tbb_version_file}) message(WARNING " FindTBB located both an old and new tbb installation. old: ${_tbb_legacy_version_file} new: ${_tbb_version_file} The NEWER versioned installation will be used. You can set TBB_INCLUDEDIR to control FindTBB.cmake search, or explicitly set Tbb_INCLUDE_DIR to the desired location. ") else() set(_tbb_version_file "${_tbb_legacy_version_file}") set(Tbb_INCLUDE_DIR ${Tbb_LEGACY_INCLUDE_DIR} CACHE STRING "" FORCE) endif() endif() if(EXISTS ${_tbb_version_file}) file(STRINGS ${_tbb_version_file} _tbb_version_major_string REGEX "#define TBB_VERSION_MAJOR " ) string(REGEX REPLACE "#define TBB_VERSION_MAJOR" "" _tbb_version_major_string "${_tbb_version_major_string}") string(STRIP "${_tbb_version_major_string}" Tbb_VERSION_MAJOR) file(STRINGS ${_tbb_version_file} _tbb_version_minor_string REGEX "#define TBB_VERSION_MINOR ") string(REGEX REPLACE "#define TBB_VERSION_MINOR" "" _tbb_version_minor_string "${_tbb_version_minor_string}") string(STRIP "${_tbb_version_minor_string}" Tbb_VERSION_MINOR) file(STRINGS ${_tbb_version_file} _tbb_binary_version_string REGEX "#define __TBB_BINARY_VERSION ") string(REGEX REPLACE "#define __TBB_BINARY_VERSION" "" _tbb_binary_version_string "${_tbb_binary_version_string}") string(STRIP "${_tbb_binary_version_string}" Tbb_BINARY_VERSION) unset(_tbb_version_major_string) unset(_tbb_version_minor_string) unset(_tbb_binary_version_string) # Set both for compatibility reasons, TBB's CONFIG files only set the latter set(Tbb_VERSION ${Tbb_VERSION_MAJOR}.${Tbb_VERSION_MINOR}) set(TBB_VERSION ${Tbb_VERSION}) endif() unset(_tbb_version_file) unset(_tbb_legacy_version_file) unset(Tbb_LEGACY_INCLUDE_DIR) # ------------------------------------------------------------------------ # Search for TBB lib DIR # ------------------------------------------------------------------------ set(_TBB_LIBRARYDIR_SEARCH_DIRS "") # Append to _TBB_LIBRARYDIR_SEARCH_DIRS in priority order set(_TBB_LIBRARYDIR_SEARCH_DIRS "") list(APPEND _TBB_LIBRARYDIR_SEARCH_DIRS ${TBB_LIBRARYDIR} ${_TBB_ROOT} ${PC_Tbb_LIBRARY_DIRS} ${SYSTEM_LIBRARY_PATHS} ) # Library suffix handling if(NOT DEFINED TBB_DEBUG_SUFFIX) set(TBB_DEBUG_SUFFIX _debug) endif() set(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(MSVC) if(TBB_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") endif() else() if(TBB_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() endif() set(Tbb_LIB_COMPONENTS "") list(APPEND TBB_BUILD_TYPES RELEASE DEBUG) foreach(COMPONENT ${TBB_FIND_COMPONENTS}) foreach(BUILD_TYPE ${TBB_BUILD_TYPES}) set(_TBB_LIB_NAME ${COMPONENT}) if(BUILD_TYPE STREQUAL DEBUG) set(_TBB_LIB_NAME "${_TBB_LIB_NAME}${TBB_DEBUG_SUFFIX}") endif() find_library(Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${_TBB_LIB_NAME} ${_FIND_TBB_ADDITIONAL_OPTIONS} PATHS ${_TBB_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib) # If we didn't find the library, prepend Tbb_BINARY_VERSION to each possible # component name and try again. As of TBB 2021, TBB decides to version some # of its libraries on some of its platforms... if(NOT Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} AND Tbb_BINARY_VERSION) set(_TBB_LIB_NAME "${COMPONENT}${Tbb_BINARY_VERSION}") if(BUILD_TYPE STREQUAL DEBUG) set(_TBB_LIB_NAME "${_TBB_LIB_NAME}${TBB_DEBUG_SUFFIX}") endif() find_library(Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${_TBB_LIB_NAME} ${_FIND_TBB_ADDITIONAL_OPTIONS} PATHS ${_TBB_LIBRARYDIR_SEARCH_DIRS} PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib) endif() # On Unix, TBB sometimes uses linker scripts instead of symlinks, so parse the linker script # and correct the library name if so if(UNIX AND EXISTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) # Ignore files where the first four bytes equals the ELF magic number file(READ ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}} Tbb_${COMPONENT}_HEX OFFSET 0 LIMIT 4 HEX) if(NOT ${Tbb_${COMPONENT}_HEX} STREQUAL "7f454c46") # Read the first 1024 bytes of the library and match against an "INPUT (file)" regex file(READ ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}} Tbb_${COMPONENT}_ASCII OFFSET 0 LIMIT 1024) if("${Tbb_${COMPONENT}_ASCII}" MATCHES "INPUT \\(([^(]+)\\)") # Extract the directory and apply the matched text (in brackets) get_filename_component(Tbb_${COMPONENT}_DIR "${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}" DIRECTORY) set(Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} "${Tbb_${COMPONENT}_DIR}/${CMAKE_MATCH_1}") endif() endif() endif() if(EXISTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) list(APPEND Tbb_LIB_COMPONENTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) list(APPEND Tbb_LIB_COMPONENTS_${BUILD_TYPE} ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}) endif() endforeach() if(Tbb_${COMPONENT}_LIBRARY_DEBUG AND Tbb_${COMPONENT}_LIBRARY_RELEASE) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(_isMultiConfig OR CMAKE_BUILD_TYPE) set(Tbb_${COMPONENT}_LIBRARY optimized ${Tbb_${COMPONENT}_LIBRARY_RELEASE} debug ${Tbb_${COMPONENT}_LIBRARY_DEBUG}) else() # For single-config generators where CMAKE_BUILD_TYPE has no value, # just use the release libraries set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE}) endif() # FIXME: This probably should be set for both cases set(Tbb_${COMPONENT}_LIBRARIES optimized ${Tbb_${COMPONENT}_LIBRARY_RELEASE} debug ${Tbb_${COMPONENT}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Tbb_${COMPONENT}_LIBRARY_RELEASE AND NOT Tbb_${COMPONENT}_LIBRARY_DEBUG) set(Tbb_${COMPONENT}_LIBRARY_DEBUG ${Tbb_${COMPONENT}_LIBRARY_RELEASE}) set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE}) set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Tbb_${COMPONENT}_LIBRARY_DEBUG AND NOT Tbb_${COMPONENT}_LIBRARY_RELEASE) set(Tbb_${COMPONENT}_LIBRARY_RELEASE ${Tbb_${COMPONENT}_LIBRARY_DEBUG}) set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_DEBUG}) set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if("${Tbb_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${Tbb_${COMPONENT}_LIBRARY_DEBUG}") set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE} ) set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_RELEASE} ) endif() if(Tbb_${COMPONENT}_LIBRARY) set(TBB_${COMPONENT}_FOUND TRUE) else() set(TBB_${COMPONENT}_FOUND FALSE) endif() endforeach() # Reset library suffix set(CMAKE_FIND_LIBRARY_SUFFIXES ${_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) unset(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) # ------------------------------------------------------------------------ # Cache and set TBB_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(TBB FOUND_VAR TBB_FOUND REQUIRED_VARS Tbb_INCLUDE_DIR Tbb_LIB_COMPONENTS VERSION_VAR Tbb_VERSION HANDLE_COMPONENTS ) if(NOT TBB_FOUND) if(TBB_FIND_REQUIRED) message(FATAL_ERROR "Unable to find TBB") endif() return() endif() # Partition release/debug lib vars set(Tbb_RELEASE_LIBRARIES "") set(Tbb_RELEASE_LIBRARY_DIRS "") set(Tbb_DEBUG_LIBRARIES "") set(Tbb_DEBUG_LIBRARY_DIRS "") foreach(LIB ${Tbb_LIB_COMPONENTS_RELEASE}) get_filename_component(_TBB_LIBDIR ${LIB} DIRECTORY) list(APPEND Tbb_RELEASE_LIBRARIES ${LIB}) list(APPEND Tbb_RELEASE_LIBRARY_DIRS ${_TBB_LIBDIR}) endforeach() foreach(LIB ${Tbb_LIB_COMPONENTS_DEBUG}) get_filename_component(_TBB_LIBDIR ${LIB} DIRECTORY) list(APPEND Tbb_DEBUG_LIBRARIES ${LIB}) list(APPEND Tbb_DEBUG_LIBRARY_DIRS ${_TBB_LIBDIR}) endforeach() list(REMOVE_DUPLICATES Tbb_RELEASE_LIBRARY_DIRS) list(REMOVE_DUPLICATES Tbb_DEBUG_LIBRARY_DIRS) set(Tbb_LIBRARIES ${Tbb_RELEASE_LIBRARIES}) set(Tbb_LIBRARY_DIRS ${Tbb_RELEASE_LIBRARY_DIRS}) set(Tbb_INCLUDE_DIRS ${Tbb_INCLUDE_DIR}) # Configure imported targets foreach(COMPONENT ${TBB_FIND_COMPONENTS}) # Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static # lib is in use. If win32, we can't mark the import .libs as shared, so # these are always marked as UNKNOWN. Otherwise, infer from extension. set(TBB_${COMPONENT}_LIB_TYPE UNKNOWN) if(TBB_USE_STATIC_LIBS) set(TBB_${COMPONENT}_LIB_TYPE STATIC) elseif(UNIX) get_filename_component(_TBB_${COMPONENT}_EXT ${Tbb_${COMPONENT}_LIBRARY_RELEASE} EXT) if(_TBB_${COMPONENT}_EXT STREQUAL ".a") set(TBB_${COMPONENT}_LIB_TYPE STATIC) elseif(_TBB_${COMPONENT}_EXT STREQUAL ".so" OR _TBB_${COMPONENT}_EXT STREQUAL ".dylib") set(TBB_${COMPONENT}_LIB_TYPE SHARED) endif() endif() set(Tbb_${COMPONENT}_DEFINITIONS) # Add the TBB linking defines if the library is static on WIN32 if(WIN32) if(${COMPONENT} STREQUAL tbb) if(Tbb_${COMPONENT}_LIB_TYPE STREQUAL STATIC) list(APPEND Tbb_${COMPONENT}_DEFINITIONS __TBB_NO_IMPLICIT_LINKAGE=1) endif() else() # tbbmalloc if(Tbb_${COMPONENT}_LIB_TYPE STREQUAL STATIC) list(APPEND Tbb_${COMPONENT}_DEFINITIONS __TBB_MALLOC_NO_IMPLICIT_LINKAGE=1) endif() endif() endif() if(NOT TARGET TBB::${COMPONENT}) add_library(TBB::${COMPONENT} ${TBB_${COMPONENT}_LIB_TYPE} IMPORTED) set_target_properties(TBB::${COMPONENT} PROPERTIES INTERFACE_COMPILE_OPTIONS "${PC_Tbb_CFLAGS_OTHER}" INTERFACE_COMPILE_DEFINITIONS "${Tbb_${COMPONENT}_DEFINITIONS}" INTERFACE_INCLUDE_DIRECTORIES "${Tbb_INCLUDE_DIR}" INTERFACE_LINK_DIRECTORIES "${Tbb_LIBRARY_DIRS}") # Standard location set_target_properties(TBB::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${Tbb_${COMPONENT}_LIBRARY}") # Release location if(EXISTS "${Tbb_${COMPONENT}_LIBRARY_RELEASE}") set_property(TARGET TBB::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties(TBB::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" IMPORTED_LOCATION_RELEASE "${Tbb_${COMPONENT}_LIBRARY_RELEASE}" MAP_IMPORTED_CONFIG_MINSIZEREL Release MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release) endif() # Debug location if(EXISTS "${Tbb_${COMPONENT}_LIBRARY_DEBUG}") set_property(TARGET TBB::${COMPONENT} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties(TBB::${COMPONENT} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" IMPORTED_LOCATION_DEBUG "${Tbb_${COMPONENT}_LIBRARY_DEBUG}") endif() endif() endforeach() openvdb-13.0.0/cmake/OpenVDBGLFW3Setup.cmake000066400000000000000000000077671510223237100203500ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: OpenVDBGLFW3Setup ----------------- Wraps the call the FindPackage ( glfw3 ) for OpenVDB builds. Provides some extra options for finding the glfw3 installation without polluting the OpenVDB Binaries cmake. Use this module by invoking include with the form:: include ( OpenVDBGLFW3Setup ) IMPORTED Targets ^^^^^^^^^^^^^^^^ ``glfw`` The glfw3 library target. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``glfw3_FOUND`` True if the system has glfw3 installed. ``glfw3_VERSION`` The version of the glfw3 library which was found. Hints ^^^^^ The following variables may be provided to tell this module where to look. ``GLFW3_ROOT`` Preferred installation prefix. ``SYSTEM_LIBRARY_PATHS`` Global list of library paths intended to be searched by and find_xxx call ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] # Find the glfw3 installation and use glfw's CMake to initialize # the glfw lib cmake_minimum_required(VERSION 3.24) set(_FIND_GLFW3_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_GLFW3_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() set(_GLFW3_ROOT_SEARCH_DIR "") if(GLFW3_ROOT) list(APPEND _GLFW3_ROOT_SEARCH_DIR ${GLFW3_ROOT}) else() set(_ENV_GLFW_ROOT $ENV{GLFW3_ROOT}) if(_ENV_GLFW_ROOT) list(APPEND _GLFW3_ROOT_SEARCH_DIR ${_ENV_GLFW_ROOT}) endif() endif() # Additionally try and use pkconfig to find glfw, though we only use # pkg-config to re-direct to the cmake. In other words, glfw's cmake is # expected to be installed if(USE_PKGCONFIG) if(NOT DEFINED PKG_CONFIG_FOUND) find_package(PkgConfig) endif() pkg_check_modules(PC_glfw3 QUIET glfw3) endif() if(PC_glfw3_FOUND) foreach(DIR ${PC_glfw3_LIBRARY_DIRS}) list(APPEND _GLFW3_ROOT_SEARCH_DIR ${DIR}) endforeach() endif() list(APPEND _GLFW3_ROOT_SEARCH_DIR ${SYSTEM_LIBRARY_PATHS}) set(_GLFW3_PATH_SUFFIXES "lib/cmake/glfw3" "cmake/glfw3" "glfw3") # GLFW 3.1 installs CMake modules into glfw instead of glfw3 list(APPEND _GLFW3_PATH_SUFFIXES "lib/cmake/glfw" "cmake/glfw" "glfw") find_path(GLFW3_CMAKE_LOCATION glfw3Config.cmake ${_FIND_GLFW3_ADDITIONAL_OPTIONS} PATHS ${_GLFW3_ROOT_SEARCH_DIR} PATH_SUFFIXES ${_GLFW3_PATH_SUFFIXES} ) if(GLFW3_CMAKE_LOCATION) if(EXISTS "${GLFW3_CMAKE_LOCATION}/glfw3Targets.cmake") include("${GLFW3_CMAKE_LOCATION}/glfw3Targets.cmake") elseif(EXISTS "${GLFW3_CMAKE_LOCATION}/glfwTargets.cmake") include("${GLFW3_CMAKE_LOCATION}/glfwTargets.cmake") endif() endif() if(GLFW3_CMAKE_LOCATION) list(APPEND CMAKE_PREFIX_PATH "${GLFW3_CMAKE_LOCATION}") endif() set(glfw3_FIND_VERSION ${MINIMUM_GLFW_VERSION}) find_package(glfw3 ${MINIMUM_GLFW_VERSION} REQUIRED) if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_GLFW_VERSION) if(glfw3_VERSION VERSION_LESS ${FUTURE_MINIMUM_GLFW_VERSION}) message(DEPRECATION "Support for GLFW versions < ${FUTURE_MINIMUM_GLFW_VERSION} " "is deprecated and will be removed.") endif() endif() unset(glfw3_FIND_VERSION) # GLFW 3.1 does not export INTERFACE_LINK_LIBRARIES so detect this # version and set the property ourselves # @todo investigate how this might apply for Mac OSX if(UNIX) if(glfw3_VERSION VERSION_LESS 3.2) message(WARNING "GLFW 3.1 does not set the INTERFACE_LINK_LIBRARIES property, " "hard-coding to expect a dependency on X11. To use a different " "library dependency, consider upgrading to GLFW 3.2+ where this " "property is set by the CMake find package module for GLFW.") find_package(X11 REQUIRED) set_property(TARGET glfw PROPERTY INTERFACE_LINK_LIBRARIES ${X11_Xrandr_LIB} ${X11_Xxf86vm_LIB} ${X11_Xcursor_LIB} ${X11_Xinerama_LIB} ${X11_Xi_LIB} ${X11_LIBRARIES} ${CMAKE_DL_LIBS} ) endif() endif() openvdb-13.0.0/cmake/OpenVDBHoudiniSetup.cmake000066400000000000000000000311721510223237100211100ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: OpenVDBHoudiniSetup ------------------- Wraps the call the FindPackage ( Houdini ) for OpenVDB builds. This ensures that all dependencies that are included with a Houdini distribution are configured to load from that installation. This CMake searches for the HoudiniConfig.cmake module provided by SideFX to configure the OpenVDB Houdini base and DSO libraries. Users can provide paths to the location of their Houdini Installation by setting HOUDINI_ROOT either as an environment variable or by passing it to CMake. This module also reads the value of $HFS, usually set by sourcing the Houdini Environment. Note that as long as you provide a path to your Houdini Installation you do not need to source the Houdini Environment. Use this module by invoking include with the form:: include ( OpenVDBHoudiniSetup ) Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Houdini_FOUND`` True if the system has Houdini installed. ``Houdini_VERSION`` The version of the Houdini which was found. ``OPENVDB_HOUDINI_ABI`` The ABI version that Houdini uses for it's own OpenVDB installation. ``HOUDINI_INCLUDE_DIR`` The Houdini include directory. ``HOUDINI_LIB_DIR`` The Houdini lib directory. A variety of variables will also be set from HoudiniConfig.cmake. Additionally, the following values are set for all dependent OpenVDB builds, ensuring they link against the correct libraries. This may overwrite user provided values. ``ZLIB_ROOT`` ``ZLIB_LIBRARY`` ``OPENEXR_INCLUDEDIR`` ``OPENEXR_LIBRARYDIR`` ``TBB_INCLUDEDIR`` ``TBB_LIBRARYDIR`` ``BLOSC_INCLUDEDIR`` ``BLOSC_LIBRARYDIR`` ``JEMALLOC_LIBRARYDIR`` Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``ENV{HFS}`` Preferred installation prefix. ``Houdini_ROOT`` Preferred installation prefix. ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] # Find the Houdini installation and use Houdini's CMake to initialize # the Houdini lib cmake_minimum_required(VERSION 3.24) # Include utility functions for version information include(${CMAKE_CURRENT_LIST_DIR}/OpenVDBUtils.cmake) set(_FIND_HOUDINI_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_HOUDINI_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _HOUDINI_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV HOUDINI_ROOT from CMake 3.12 if(Houdini_ROOT) set(_HOUDINI_ROOT ${Houdini_ROOT}) elseif(DEFINED ENV{Houdini_ROOT}) set(_HOUDINI_ROOT $ENV{Houdini_ROOT}) elseif(HOUDINI_ROOT) set(_HOUDINI_ROOT ${HOUDINI_ROOT}) elseif(DEFINED ENV{HOUDINI_ROOT}) set(_HOUDINI_ROOT $ENV{HOUDINI_ROOT}) endif() set(_HOUDINI_ROOT_SEARCH_DIR) if(_HOUDINI_ROOT) list(APPEND _HOUDINI_ROOT_SEARCH_DIR ${_HOUDINI_ROOT}) endif() if(DEFINED ENV{HFS}) list(APPEND _HOUDINI_ROOT_SEARCH_DIR $ENV{HFS}) endif() # ------------------------------------------------------------------------ # Search for Houdini # ------------------------------------------------------------------------ set(_HOUDINI_CMAKE_PATH_SUFFIXES) if(APPLE) list(APPEND _HOUDINI_CMAKE_PATH_SUFFIXES Frameworks/Houdini.framework/Versions/Current/Resources/toolkit/cmake Houdini.framework/Versions/Current/Resources/toolkit/cmake Versions/Current/Resources/toolkit/cmake Current/Resources/toolkit/cmake Resources/toolkit/cmake ) endif() list(APPEND _HOUDINI_CMAKE_PATH_SUFFIXES toolkit/cmake cmake ) find_package(Houdini ${_FIND_HOUDINI_ADDITIONAL_OPTIONS} PATHS ${_HOUDINI_ROOT_SEARCH_DIR} PATH_SUFFIXES ${_HOUDINI_CMAKE_PATH_SUFFIXES} REQUIRED) # Note that passing MINIMUM_HOUDINI_VERSION into find_package(Houdini) doesn't work if(NOT Houdini_FOUND) message(FATAL_ERROR "Unable to locate Houdini Installation.") elseif(MINIMUM_HOUDINI_VERSION) if(Houdini_VERSION VERSION_LESS MINIMUM_HOUDINI_VERSION) message(FATAL_ERROR "Unsupported Houdini Version ${Houdini_VERSION}. Minimum " "supported is ${MINIMUM_HOUDINI_VERSION}." ) endif() endif() set(Houdini_VERSION_MAJOR_MINOR "${Houdini_VERSION_MAJOR}.${Houdini_VERSION_MINOR}") find_package(PackageHandleStandardArgs) find_package_handle_standard_args(Houdini REQUIRED_VARS _houdini_install_root Houdini_FOUND VERSION_VAR Houdini_VERSION ) # ------------------------------------------------------------------------ # Add support for older versions of Houdini # ------------------------------------------------------------------------ if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_HOUDINI_VERSION) if(Houdini_VERSION VERSION_LESS ${FUTURE_MINIMUM_HOUDINI_VERSION}) message(DEPRECATION "Support for Houdini versions < ${FUTURE_MINIMUM_HOUDINI_VERSION} " "is deprecated and will be removed.") endif() endif() # ------------------------------------------------------------------------ # Configure imported Houdini target # ------------------------------------------------------------------------ # Set the relative directory containing Houdini libs and populate an extra list # of Houdini dependencies for _houdini_create_libraries. if(NOT HOUDINI_DSOLIB_DIR) if(APPLE) set(HOUDINI_DSOLIB_DIR Frameworks/Houdini.framework/Versions/Current/Libraries) elseif(UNIX) set(HOUDINI_DSOLIB_DIR dsolib) elseif(WIN32) set(HOUDINI_DSOLIB_DIR custom/houdini/dsolib) endif() endif() set(_HOUDINI_EXTRA_LIBRARIES) set(_HOUDINI_EXTRA_LIBRARY_NAMES) if(APPLE) list(APPEND _HOUDINI_EXTRA_LIBRARIES ${HOUDINI_DSOLIB_DIR}/libHoudiniRAY.dylib ${HOUDINI_DSOLIB_DIR}/libhboost_regex.dylib ${HOUDINI_DSOLIB_DIR}/libhboost_thread.dylib ) list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES HoudiniRAY hboost_regex hboost_thread ) elseif(UNIX) list(APPEND _HOUDINI_EXTRA_LIBRARIES ${HOUDINI_DSOLIB_DIR}/libHoudiniRAY.so ${HOUDINI_DSOLIB_DIR}/libhboost_regex.so ${HOUDINI_DSOLIB_DIR}/libhboost_thread.so ) list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES HoudiniRAY hboost_regex hboost_thread ) elseif(WIN32) #libRAY is already included by houdini for windows builds if(Houdini_VERSION VERSION_LESS 18.5) list(APPEND _HOUDINI_EXTRA_LIBRARIES ${HOUDINI_DSOLIB_DIR}/hboost_regex-mt.lib ${HOUDINI_DSOLIB_DIR}/hboost_thread-mt.lib ) else() list(APPEND _HOUDINI_EXTRA_LIBRARIES ${HOUDINI_DSOLIB_DIR}/hboost_regex-mt-x64.lib ${HOUDINI_DSOLIB_DIR}/hboost_thread-mt-x64.lib ) endif() list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES hboost_regex hboost_thread ) endif() # Additionally link extra deps _houdini_create_libraries( PATHS ${_HOUDINI_EXTRA_LIBRARIES} TARGET_NAMES ${_HOUDINI_EXTRA_LIBRARY_NAMES} TYPE SHARED ) unset(_HOUDINI_EXTRA_LIBRARIES) unset(_HOUDINI_EXTRA_LIBRARY_NAMES) # Set Houdini lib and include directories set(HOUDINI_INCLUDE_DIR ${_houdini_include_dir}) set(HOUDINI_LIB_DIR ${_houdini_install_root}/${HOUDINI_DSOLIB_DIR}) # ------------------------------------------------------------------------ # Configure dependencies # ------------------------------------------------------------------------ # Congfigure dependency hints to point to Houdini. Allow for user overriding # if custom Houdini installations are in use # ZLIB - FindPackage ( ZLIB) only supports a few path hints. We use # ZLIB_ROOT to find the zlib includes and explicitly set the path to # the zlib library if(NOT ZLIB_ROOT) set(ZLIB_ROOT ${HOUDINI_INCLUDE_DIR}) endif() if(NOT ZLIB_LIBRARY) # Full path to zlib library - FindPackage ( ZLIB) find_library(ZLIB_LIBRARY z ${_FIND_HOUDINI_ADDITIONAL_OPTIONS} PATHS ${HOUDINI_LIB_DIR} ) if(NOT EXISTS ${ZLIB_LIBRARY}) message(WARNING "The OpenVDB Houdini CMake setup is unable to locate libz within " "the Houdini installation at: ${HOUDINI_LIB_DIR}. OpenVDB may not build correctly." ) endif() endif() # TBB if(NOT TBB_INCLUDEDIR) set(TBB_INCLUDEDIR ${HOUDINI_INCLUDE_DIR}) endif() if(NOT TBB_LIBRARYDIR) set(TBB_LIBRARYDIR ${HOUDINI_LIB_DIR}) endif() # Blosc if(NOT BLOSC_INCLUDEDIR) set(BLOSC_INCLUDEDIR ${HOUDINI_INCLUDE_DIR}) endif() if(NOT BLOSC_LIBRARYDIR) set(BLOSC_LIBRARYDIR ${HOUDINI_LIB_DIR}) endif() # Jemalloc # * On Mac OSX, linking against Jemalloc < 4.3.0 seg-faults with this error: # malloc: *** malloc_zone_unregister() failed for 0xaddress # As of Houdini 20, it still ships with Jemalloc 3.6.0, so don't expose it # on Mac OSX (https://github.com/jemalloc/jemalloc/issues/420). if(NOT APPLE AND NOT JEMALLOC_LIBRARYDIR) set(JEMALLOC_LIBRARYDIR ${HOUDINI_LIB_DIR}) endif() # OpenEXR if(NOT OPENEXR_INCLUDEDIR) set(OPENEXR_INCLUDEDIR ${HOUDINI_INCLUDE_DIR}) endif() if(NOT OPENEXR_LIBRARYDIR) set(OPENEXR_LIBRARYDIR ${HOUDINI_LIB_DIR}) endif() # Boost - currently must be provided as VDB is not fully configured to # use Houdini's namespaced hboost # Add the required suffix as part of the cmake lib suffix searches if(APPLE) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.dylib") elseif(UNIX) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.so") elseif(WIN32) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.lib") endif() # ------------------------------------------------------------------------ # Configure OpenVDB ABI # ------------------------------------------------------------------------ # Explicitly configure the OpenVDB ABI version depending on the Houdini # version. find_file(_houdini_openvdb_version_file "openvdb/version.h" PATHS ${HOUDINI_INCLUDE_DIR} NO_DEFAULT_PATH) if(_houdini_openvdb_version_file) OPENVDB_VERSION_FROM_HEADER("${_houdini_openvdb_version_file}" ABI OPENVDB_HOUDINI_ABI) endif() unset(_houdini_openvdb_version_file) if(NOT OPENVDB_HOUDINI_ABI) message(WARNING "Unknown version of Houdini, assuming OpenVDB ABI=${OpenVDB_MAJOR_VERSION}, " "but if this not correct, the CMake flag -DOPENVDB_HOUDINI_ABI= can override this value.") set(OPENVDB_HOUDINI_ABI ${OpenVDB_MAJOR_VERSION}) endif() # ------------------------------------------------------------------------ # Configure libstc++ CXX11 ABI # ------------------------------------------------------------------------ if(UNIX AND NOT APPLE) # Assume we're using libstdc++ message(STATUS "Configuring CXX11 ABI for Houdini compatibility...") execute_process(COMMAND echo "#include " COMMAND ${CMAKE_CXX_COMPILER} "-x" "c++" "-E" "-dM" "-" COMMAND grep "-F" "_GLIBCXX_USE_CXX11_ABI" TIMEOUT 10 RESULT_VARIABLE QUERIED_GCC_CXX11_ABI_SUCCESS OUTPUT_VARIABLE _GCC_CXX11_ABI) set(GLIBCXX_USE_CXX11_ABI "UNKNOWN") if(NOT QUERIED_GCC_CXX11_ABI_SUCCESS) string(FIND ${_GCC_CXX11_ABI} "_GLIBCXX_USE_CXX11_ABI 0" GCC_OLD_CXX11_ABI) string(FIND ${_GCC_CXX11_ABI} "_GLIBCXX_USE_CXX11_ABI 1" GCC_NEW_CXX11_ABI) if(NOT (${GCC_OLD_CXX11_ABI} EQUAL -1)) set(GLIBCXX_USE_CXX11_ABI 0) endif() if(NOT (${GCC_NEW_CXX11_ABI} EQUAL -1)) set(GLIBCXX_USE_CXX11_ABI 1) endif() endif() # Try and query the Houdini CXX11 ABI. Allow it to be provided by users to # override this logic should Houdini's CMake ever change if(NOT DEFINED HOUDINI_CXX11_ABI) get_target_property(houdini_interface_compile_options Houdini INTERFACE_COMPILE_OPTIONS) set(HOUDINI_CXX11_ABI "UNKNOWN") if("-D_GLIBCXX_USE_CXX11_ABI=0" IN_LIST houdini_interface_compile_options) set(HOUDINI_CXX11_ABI 0) elseif("-D_GLIBCXX_USE_CXX11_ABI=1" IN_LIST houdini_interface_compile_options) set(HOUDINI_CXX11_ABI 1) endif() endif() message(STATUS " GNU CXX11 ABI : ${GLIBCXX_USE_CXX11_ABI}") message(STATUS " Houdini CXX11 ABI : ${HOUDINI_CXX11_ABI}") if(${HOUDINI_CXX11_ABI} STREQUAL "UNKNOWN") message(WARNING "Unable to determine Houdini CXX11 ABI. Assuming newer ABI " "has been used.") set(HOUDINI_CXX11_ABI 1) endif() if(${GLIBCXX_USE_CXX11_ABI} EQUAL ${HOUDINI_CXX11_ABI}) message(STATUS " Current CXX11 ABI matches Houdini configuration " "(_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI}).") else() message(WARNING "A potential mismatch was detected between the CXX11 ABI " "of libstdc++ and Houdini. The following ABI configuration will be used: " "-D_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI}. See: " "https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html and " "https://vfxplatform.com/#footnote-gcc6 for more information.") endif() add_definitions(-D_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI}) endif() openvdb-13.0.0/cmake/OpenVDBMayaSetup.cmake000066400000000000000000000152241510223237100204000ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: OpenVDBMayaSetup ------------------- Finds the Maya installation and sets up dependencies for OpenVDB builds. This ensures that all dependencies that are included with a Maya distribution are configured to load from that installation. Use this module by invoking include with the form:: include ( OpenVDBMayaSetup ) Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``Maya_FOUND`` True if the system has Maya installed. ``Maya_VERSION`` The version of the Maya which was found. Additionally, the following values are set for all dependent OpenVDB builds, ensuring they link against the correct libraries. This may overwrite user provided values. ``TBB_INCLUDEDIR`` ``TBB_LIBRARYDIR`` Hints ^^^^^ Instead of explicitly setting the cache variables, the following variables may be provided to tell this module where to look. ``Maya_ROOT`` Preferred installation prefix. ``ENV{Maya_ROOT}`` Preferred installation prefix. ``ENV{MAYA_LOCATION}`` Preferred installation prefix. ``DISABLE_CMAKE_SEARCH_PATHS`` Disable CMakes default search paths for find_xxx calls in this module #]=======================================================================] # Find the Maya installation and use Maya's CMake to initialize # the Maya lib cmake_minimum_required(VERSION 3.24) set(_FIND_MAYA_ADDITIONAL_OPTIONS "") if(DISABLE_CMAKE_SEARCH_PATHS) set(_FIND_MAYA_ADDITIONAL_OPTIONS NO_DEFAULT_PATH) endif() # Set _MAYA_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT} # are prioritised over the legacy capitalized XXX_ROOT variables for matching # CMake 3.12 behaviour # @todo deprecate -D and ENV MAYA_ROOT from CMake 3.12 if(Maya_ROOT) set(_MAYA_ROOT ${Maya_ROOT}) elseif(DEFINED ENV{Maya_ROOT}) set(_MAYA_ROOT $ENV{Maya_ROOT}) elseif(MAYA_ROOT) set(_MAYA_ROOT ${MAYA_ROOT}) elseif(DEFINED ENV{MAYA_ROOT}) set(_MAYA_ROOT $ENV{MAYA_ROOT}) endif() set(_MAYA_ROOT_SEARCH_DIR) if(_MAYA_ROOT) list(APPEND _MAYA_ROOT_SEARCH_DIR ${_MAYA_ROOT}) endif() # @todo deprecate MAYA_LOCATION? There may be workflows which set this variable if(DEFINED ENV{MAYA_LOCATION}) list(APPEND _MAYA_ROOT_SEARCH_DIR $ENV{MAYA_LOCATION}) endif() # ------------------------------------------------------------------------ # Search for Maya # ------------------------------------------------------------------------ find_path(Maya_INCLUDE_DIR maya/MTypes.h ${_FIND_MAYA_ADDITIONAL_OPTIONS} PATHS ${_MAYA_ROOT_SEARCH_DIR} PATH_SUFFIXES include ) if(NOT EXISTS "${Maya_INCLUDE_DIR}/maya/MTypes.h") message(FATAL_ERROR "Unable to locate Maya Installation.") endif() # Determine Maya version, including point releases. Currently only works for # Maya 2016 and onwards so there is no -x64 and -x32 suffixes in the version file(STRINGS "${Maya_INCLUDE_DIR}/maya/MTypes.h" _maya_version_string REGEX "#define MAYA_API_VERSION " ) string(REGEX REPLACE ".*#define[ \t]+MAYA_API_VERSION[ \t]+([0-9]+).*$" "\\1" _maya_version_string "${_maya_version_string}" ) string(SUBSTRING ${_maya_version_string} 0 4 Maya_MAJOR_VERSION) string(SUBSTRING ${_maya_version_string} 4 2 Maya_MINOR_VERSION) if(Maya_MINOR_VERSION LESS 50) set(Maya_VERSION ${Maya_MAJOR_VERSION}) else() set(Maya_VERSION ${Maya_MAJOR_VERSION}.5) endif() unset(_maya_version_string) # Find required maya libs set(_MAYA_COMPONENT_LIST OpenMaya OpenMayaFX OpenMayaUI Foundation ) set(Maya_LIBRARY_DIR "") if(APPLE) set(Maya_LIBRARY_DIR ${Maya_INCLUDE_DIR}/../Maya.app/Contents/MacOS/) else() set(Maya_LIBRARY_DIR ${Maya_INCLUDE_DIR}/../lib/) endif() set(Maya_LIB_COMPONENTS "") foreach(COMPONENT ${_MAYA_COMPONENT_LIST}) find_library(Maya_${COMPONENT}_LIBRARY ${COMPONENT} ${_FIND_MAYA_ADDITIONAL_OPTIONS} PATHS ${Maya_LIBRARY_DIR} ) list(APPEND Maya_LIB_COMPONENTS ${Maya_${COMPONENT}_LIBRARY}) endforeach() # ------------------------------------------------------------------------ # Cache and set Maya_FOUND # ------------------------------------------------------------------------ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Maya FOUND_VAR Maya_FOUND REQUIRED_VARS Maya_INCLUDE_DIR Maya_LIB_COMPONENTS VERSION_VAR Maya_VERSION ) if(NOT Maya_FOUND) message(FATAL_ERROR "Unable to locate Maya Installation.") elseif(Maya_VERSION VERSION_LESS MINIMUM_MAYA_VERSION) message(WARNING "Unsupported Maya Version ${Maya_VERSION}. Minimum " "supported is ${MINIMUM_MAYA_VERSION}." ) endif() # ------------------------------------------------------------------------ # Configure dependencies # ------------------------------------------------------------------------ if(NOT TBB_INCLUDEDIR) set(TBB_INCLUDEDIR ${Maya_INCLUDE_DIR}) endif() if(NOT TBB_LIBRARYDIR) set(TBB_LIBRARYDIR ${Maya_LIBRARY_DIR}) endif() # ------------------------------------------------------------------------ # Configure Maya # ------------------------------------------------------------------------ set(Maya_LIBRARIES ${Maya_LIB_COMPONENTS}) set(Maya_INCLUDE_DIRS ${Maya_INCLUDE_DIR}) set(Maya_LIBRARY_DIRS ${Maya_LIBRARY_DIR}) if(APPLE) set(Maya_DEFINITIONS -DMAC_PLUGIN -DREQUIRE_IOSTREAM -DOSMac_ -DOSMac_MachO_ -D_BOOL ) elseif(WIN32) set(Maya_DEFINITIONS -DNOMINMAX -DNT_PLUGIN -DREQUIRE_IOSTREAM -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS ) else() set(Maya_DEFINITIONS -D_BOOL -DFUNCPROTO -DGL_GLEXT_PROTOTYPES=1 -DREQUIRE_IOSTREAM -DUNIX -fno-gnu-keywords -fno-omit-frame-pointer -fno-strict-aliasing -funsigned-char -Wno-comment -Wno-multichar -Wno-strict-aliasing -m64 -DBits64_ -DLINUX -DLINUX_64 ) endif() # Configure imported targets if(NOT TARGET Maya) add_library(Maya INTERFACE) foreach(COMPONENT ${_MAYA_COMPONENT_LIST}) add_library(Maya::${COMPONENT} UNKNOWN IMPORTED) set_target_properties(Maya::${COMPONENT} PROPERTIES IMPORTED_LOCATION "${Maya_${COMPONENT}_LIBRARY}" INTERFACE_COMPILE_OPTIONS "${Maya_DEFINITIONS}" INTERFACE_INCLUDE_DIRECTORIES "${Maya_INCLUDE_DIRS}" ) target_link_libraries(Maya INTERFACE Maya::${COMPONENT}) endforeach() endif() macro(MAYA_SET_LIBRARY_PROPERTIES NAME) if(WIN32) set_target_properties(${NAME} PROPERTIES SUFFIX ".mll" PREFIX "" LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin" ) elseif(APPLE) set_target_properties(${NAME} PROPERTIES SUFFIX ".bundle" PREFIX "" ) else() set_target_properties(${NAME} PROPERTIES PREFIX "" ) endif() endmacro() openvdb-13.0.0/cmake/OpenVDBUtils.cmake000066400000000000000000000113771510223237100175750ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: OpenVDBUtils.cmake ------------------ A utility CMake file which provides helper functions for configuring an OpenVDB installation. Use this module by invoking include with the form:: include ( OpenVDBUtils ) The following functions are provided: ``OPENVDB_GET_VERSION_DEFINE`` OPENVDB_GET_VERSION_DEFINE ( ) Parse the provided version file to retrieve the a given OpenVDB define specified by and store the result in . If the define has a value, the value is stored. If the define has no value but exists, ON is stored. Else, OFF is stored. If the file does not exist, is unmodified. ``OPENVDB_VERSION_FROM_HEADER`` OPENVDB_VERSION_FROM_HEADER ( VERSION [] MAJOR [] MINOR [] PATCH [] ) Parse the provided version file to retrieve the current OpenVDB version information. The file is expected to be a version.h file as found in the following path of an OpenVDB repository: openvdb/version.h If the file does not exist, variables are unmodified. ``OPENVDB_ABI_VERSION_FROM_PRINT`` OPENVDB_ABI_VERSION_FROM_PRINT ( [QUIET] ABI [] ) Retrieve the ABI version that an installation of OpenVDB was compiled for using the provided vdb_print binary. Parses the result of: vdb_print --version If the binary does not exist or fails to launch, variables are unmodified. #]=======================================================================] cmake_minimum_required(VERSION 3.24) function(OPENVDB_GET_VERSION_DEFINE HEADER KEY VALUE) if(NOT EXISTS ${HEADER}) return() endif() file(STRINGS "${HEADER}" details REGEX "^#define[\t ]+${KEY}[\t ]+.*") if(details) # define has a value, extract it and return string(REGEX REPLACE "^.*${KEY}[\t ]+([0-9]*).*$" "\\1" details "${details}") set(${VALUE} ${details} PARENT_SCOPE) return() endif() # try re-searching for single defines file(STRINGS "${HEADER}" details REGEX "^#define[\t ]+${KEY}.*") if(details) set(${VALUE} ON PARENT_SCOPE) else() set(${VALUE} OFF PARENT_SCOPE) endif() endfunction() ######################################################################## ######################################################################## function(OPENVDB_VERSION_FROM_HEADER OPENVDB_VERSION_FILE) cmake_parse_arguments(_VDB "" "VERSION;MAJOR;MINOR;PATCH;ABI" "" ${ARGN}) if(NOT EXISTS ${OPENVDB_VERSION_FILE}) return() endif() OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER" _OpenVDB_MAJOR_VERSION) OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_MINOR_VERSION_NUMBER" _OpenVDB_MINOR_VERSION) OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_PATCH_VERSION_NUMBER" _OpenVDB_PATCH_VERSION) OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_ABI_VERSION_NUMBER" _OpenVDB_ABI_VERSION) if(_VDB_VERSION) set(${_VDB_VERSION} ${_OpenVDB_MAJOR_VERSION}.${_OpenVDB_MINOR_VERSION}.${_OpenVDB_PATCH_VERSION} PARENT_SCOPE ) endif() if(_VDB_MAJOR) set(${_VDB_MAJOR} ${_OpenVDB_MAJOR_VERSION} PARENT_SCOPE) endif() if(_VDB_MINOR) set(${_VDB_MINOR} ${_OpenVDB_MINOR_VERSION} PARENT_SCOPE) endif() if(_VDB_PATCH) set(${_VDB_PATCH} ${_OpenVDB_PATCH_VERSION} PARENT_SCOPE) endif() if(_VDB_ABI) set(${_VDB_ABI} ${_OpenVDB_ABI_VERSION} PARENT_SCOPE) endif() endfunction() ######################################################################## ######################################################################## function(OPENVDB_ABI_VERSION_FROM_PRINT OPENVDB_PRINT) cmake_parse_arguments(_VDB "QUIET" "ABI" "" ${ARGN}) if(NOT EXISTS ${OPENVDB_PRINT}) return() endif() set(_VDB_PRINT_VERSION_STRING "") set(_VDB_PRINT_RETURN_STATUS "") if(${_VDB_QUIET}) execute_process(COMMAND ${OPENVDB_PRINT} "--version" RESULT_VARIABLE _VDB_PRINT_RETURN_STATUS OUTPUT_VARIABLE _VDB_PRINT_VERSION_STRING ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) else() execute_process(COMMAND ${OPENVDB_PRINT} "--version" RESULT_VARIABLE _VDB_PRINT_RETURN_STATUS OUTPUT_VARIABLE _VDB_PRINT_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() if(${_VDB_PRINT_RETURN_STATUS}) return() endif() set(_OpenVDB_ABI) string(REGEX REPLACE ".*abi([0-9]*).*" "\\1" _OpenVDB_ABI ${_VDB_PRINT_VERSION_STRING}) unset(_VDB_PRINT_RETURN_STATUS) unset(_VDB_PRINT_VERSION_STRING) if(_VDB_ABI) set(${_VDB_ABI} ${_OpenVDB_ABI} PARENT_SCOPE) endif() endfunction() openvdb-13.0.0/cmake/Uninstall.cmake000066400000000000000000000021751510223237100172640ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[.rst: Uninstall --------- Adds a custom target to the CMake build generation which allows for calling:: make uninstall to remove an installation of OpenVDB. Relies on the install_manifest existing from a previous run of cmake. #]=======================================================================] cmake_minimum_required(VERSION 3.24) set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") if(NOT EXISTS ${MANIFEST}) message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") endif() file(STRINGS ${MANIFEST} INSTALLED_FILES) foreach(INSTALLED_FILE ${INSTALLED_FILES}) if(EXISTS ${INSTALLED_FILE}) message(STATUS "Uninstalling: ${INSTALLED_FILE}") exec_program( ${CMAKE_COMMAND} ARGS "-E remove ${INSTALLED_FILE}" OUTPUT_VARIABLE stdout RETURN_VALUE RESULT ) if(NOT "${RESULT}" STREQUAL 0) message(FATAL_ERROR "Failed to remove file: '${INSTALLED_FILE}'.") endif() endif() endforeach(INSTALLED_FILE) openvdb-13.0.0/cmake/config/000077500000000000000000000000001510223237100155515ustar00rootroot00000000000000openvdb-13.0.0/cmake/config/OpenVDBCXX.cmake000066400000000000000000000455211510223237100204020ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ CXX and CMAKE_CXX options and definitions for OpenVDB build types #]=======================================================================] cmake_minimum_required(VERSION 3.24) ############################################################################### # General CMake and CXX settings if(FUTURE_MINIMUM_CMAKE_VERSION) if(${CMAKE_VERSION} VERSION_LESS ${FUTURE_MINIMUM_CMAKE_VERSION}) message(DEPRECATION "Support for CMake versions < ${FUTURE_MINIMUM_CMAKE_VERSION} " "is deprecated and will be removed.") endif() endif() if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD ${MINIMUM_CXX_STANDARD} CACHE STRING "The C++ standard whose features are requested to build OpenVDB components." FORCE) elseif(CMAKE_CXX_STANDARD LESS ${MINIMUM_CXX_STANDARD}) message(FATAL_ERROR "Provided C++ Standard is less than the supported minimum." "Required is at least \"${MINIMUM_CXX_STANDARD}\" (found ${CMAKE_CXX_STANDARD})") endif() if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_CXX_STANDARD) if(CMAKE_CXX_STANDARD LESS ${FUTURE_MINIMUM_CXX_STANDARD}) message(DEPRECATION "C++ < 17 is deprecated and will be removed.") endif() endif() # Configure MS Runtime if(WIN32 AND CMAKE_MSVC_RUNTIME_LIBRARY) message(STATUS "CMAKE_MSVC_RUNTIME_LIBRARY set to target ${CMAKE_MSVC_RUNTIME_LIBRARY}") # Configure Boost library varient on Windows if(NOT Boost_USE_STATIC_RUNTIME) set(Boost_USE_STATIC_RUNTIME OFF) if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreaded OR CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebug) set(Boost_USE_STATIC_RUNTIME ON) endif() endif() if(NOT Boost_USE_DEBUG_RUNTIME) set(Boost_USE_DEBUG_RUNTIME OFF) if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebugDLL OR CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebug) set(Boost_USE_DEBUG_RUNTIME ON) endif() endif() endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) if(OPENVDB_ENABLE_RPATH) # Configure rpath for installation base on the following: # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # @todo make relocatable? set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") endif() # For CMake's find Threads module which brings in pthread - This flag # forces the compiler -pthread flag vs -lpthread set(THREADS_PREFER_PTHREAD_FLAG TRUE) ############################################################################### # Compiler version checks if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_CLANG_VERSION) message(FATAL_ERROR "Insufficient clang++ version. Minimum required is " "\"${MINIMUM_CLANG_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\"" ) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_GCC_VERSION) message(FATAL_ERROR "Insufficient g++ version. Minimum required is " "\"${MINIMUM_GCC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\"" ) endif() if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_GCC_VERSION) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_GCC_VERSION) message(DEPRECATION "Support for GCC versions < ${FUTURE_MINIMUM_GCC_VERSION} " "is deprecated and will be removed.") endif() endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_ICC_VERSION) message(FATAL_ERROR "Insufficient ICC version. Minimum required is " "\"${MINIMUM_ICC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\"" ) endif() if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_ICC_VERSION) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_ICC_VERSION) message(DEPRECATION "Support for ICC versions < ${FUTURE_MINIMUM_ICC_VERSION} " "is deprecated and will be removed.") endif() endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_MSVC_VERSION) message(FATAL_ERROR "Insufficient MSVC version. Minimum required is " "\"${MINIMUM_MSVC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\"" ) endif() if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_MSVC_VERSION) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_MSVC_VERSION) message(DEPRECATION "Support for MSVC versions < ${FUTURE_MINIMUM_MSVC_VERSION} " "is deprecated and will be removed.") endif() endif() else() message(WARNING "Unsupported CXX compiler ${CMAKE_CXX_COMPILER_ID}") endif() ############################################################################### # Increase the number of sections that an object file can contain add_compile_options("$<$:/bigobj>") # Enable MSVC options that make it behave like other compilers add_compile_options("$<$:/permissive->") add_compile_options("$<$:/Zc:throwingNew>") add_compile_options("$<$:/Zc:inline>") # Excludes APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets add_compile_definitions("$<$:WIN32_LEAN_AND_MEAN>") # Disable non-secure CRT library function warnings # https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/ # compiler-warning-level-3-c4996?view=vs-2019#unsafe-crt-library-functions add_compile_definitions("$<$:_CRT_SECURE_NO_WARNINGS>") # Disable POSIX function name warnings # https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/ # compiler-warning-level-3-c4996?view=vs-2019#posix-function-names add_compile_definitions("$<$:_CRT_NONSTDC_NO_WARNINGS>") if(MSVC_MP_THREAD_COUNT AND MSVC_MP_THREAD_COUNT GREATER 1) # If a user has explicitly requested a parallel build, configure this during CMake add_compile_options("$<$:/MP${MSVC_MP_THREAD_COUNT}>") # If building with multiple threads with MSVC, delay generation of PDB files # until the end of compilation to speed up their generation (invoke mspdbsrv once). # This assumes /Zi is being used to generate PDBs (CMakes default) add_compile_options("$<$,$>:/Zf>") endif() if(MSVC_COMPRESS_PDB) # /Zi enables PDBs - CMake seems to default to creating PDBs as the defacto way # of handling debug symbols. As these PDBs can be very large, we attempt to compress # them here with various settings. This disable incremental linking and can make # stack traces more confusing. # https://devblogs.microsoft.com/cppblog/shrink-my-program-database-pdb-file/ # First, generate comdats to allow the linker to remove unused data add_compile_options("$<$,$>:/Gy>") # Remove unreferenced packaged functions and data from comdats add_link_options("$<$,$>:/OPT:REF>") # Fold duplicate comdat data (1 iteration) add_link_options("$<$,$>:/OPT:ICF>") # Generally compress the generated pdbs as they are being created add_link_options("$<$,$>:/PDBCOMPRESS>") endif() if(OPENVDB_CXX_STRICT) message(STATUS "Configuring CXX warnings") # Clang/AppleClang add_compile_options("$<$:-Werror>") add_compile_options("$<$:-Wall>") add_compile_options("$<$:-Wextra>") add_compile_options("$<$:-Wconversion>") add_compile_options("$<$:-Wnon-virtual-dtor>") add_compile_options("$<$:-Wover-aligned>") add_compile_options("$<$:-Wimplicit-fallthrough>") add_compile_options("$<$,$,9.3.0>>:-Wimplicit-fallthrough>") # Only check global constructors for libraries (we should really check for # executables too but gtest relies on these types of constructors for its # framework). nanobind also incorporates these constructors so skip it as well. add_compile_options("$<$,EXECUTABLE>,$,nanobind-static>>>,$>:-Wglobal-constructors>") add_compile_options("$<$:-Wno-sign-conversion>") # GNU add_compile_options("$<$:-Werror>") add_compile_options("$<$:-Wall>") add_compile_options("$<$:-Wextra>") add_compile_options("$<$:-Wcast-align>") add_compile_options("$<$:-Wdisabled-optimization>") add_compile_options("$<$:-Woverloaded-virtual>") add_compile_options("$<$:-Wnon-virtual-dtor>") # Disable select warnings for the nanobind static library add_compile_options("$<$,nanobind-static>,$,openvdb_python>,$,nanovdb_python>>>,$>:-pedantic>") add_compile_options("$<$,nanobind-static>,$,openvdb_python>,$,nanovdb_python>>>,$>:-Wcast-qual>") add_compile_options("$<$,nanobind-static>,$,openvdb_python>,$,nanovdb_python>>>,$>:-Wconversion>") add_compile_options("$<$,nanobind-static>,$,openvdb_python>,$,nanovdb_python>>,$>:-Wno-unused-variable>") add_compile_options("$<$,nanobind-static>,$,openvdb_python>,$,nanovdb_python>>,$>:-Wno-unused-but-set-parameter>") else() # NO OPENVDB_CXX_STRICT, suppress some warnings if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") message(STATUS "Suppressing some noisy MSVC CXX warnings, " "set OPENVDB_CXX_STRICT=ON to re-enable them.") endif() # Conversion from int64_t to long add_compile_options("$<$:/wd4244>") # It's not possible to use STL types in DLL interfaces in a portable and # reliable way so disable this warning add_compile_options("$<$:/wd4251>") # Conversion from size_t to uLong add_compile_options("$<$:/wd4267>") # Non dll-interface class used as base for dll-interface class add_compile_options("$<$:/wd4275>") # Truncation from 'int' to 'bool' add_compile_options("$<$:/wd4305>") endif() if(USE_COLORED_OUTPUT) message(STATUS "Enabling colored compiler output") add_compile_options("$<$:-fcolor-diagnostics>") add_compile_options("$<$:-fdiagnostics-color=always>") endif() ############################################################################### # Build Types if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING [=[Choose the type of build. CMake natively supports the following options: None Debug Release RelWithDebInfo MinSizeRel. OpenVDB additionally supports the following sanitizers and tools: coverage tsan asan lsan msan ubsan]=] FORCE) if(CMAKE_BUILD_TYPE EQUAL coverage) # use .gcno extension instead of .cc.gcno # @note This is an undocumented internal cmake var and does not work # with multi config generators set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1) endif() # Note that the thread, address and memory sanitizers are incompatible with each other set(EXTRA_BUILD_TYPES coverage tsan asan lsan msan ubsan abicheck) # Set all build flags to empty (unless they have been provided) # DebugNoInfo - An internal build type only used by the OpenVDB CI. no optimizations, no symbols, asserts enabled set(CMAKE_CXX_FLAGS_DebugNoInfo "" CACHE STRING "Flags used by the C++ compiler during DebugNoInfo builds.") foreach(TYPE ${EXTRA_BUILD_TYPES}) set(CMAKE_CXX_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the C++ compiler during ${TYPE} builds.") set(CMAKE_SHARED_LINKER_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the linker during ${TYPE} builds.") set(CMAKE_EXE_LINKER_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the linker during ${TYPE} builds.") endforeach() # Init generator options - we use generator expressions to allow builds with both # clang and GCC. Sanitizers are currently only configured for clang and GCC. # Coverage # --coverage uses -fprofile-arcs -ftest-coverage (compiling) and -lgcov (linking) # @note consider -fprofile-abs-path from gcc 10 # @todo consider using clang with source analysis: -fprofile-instr-generate -fcoverage-mapping. # https://clang.llvm.org/docs/SourceBasedCodeCoverage.html # note that clang also works with gcov (--coverage) # @note Ideally we'd use no optimisations (-O0) with --coverage, but a complete # run of all unit tests takes upwards of a day without them. Thread usage also # impacts total runtime. -Og implies -O1 but without optimisations "that would # otherwise interfere with debugging". This still massively effects branch # coverage tracking compared to -O0 so we should look to improve the speed of # some of the unit tests and also experiment with clang. add_compile_options("$<$,$>:--coverage;-Og>") add_link_options("$<$,$>:--coverage>") # ThreadSanitizer add_compile_options("$<$,$>:-fsanitize=thread>") add_compile_options("$<$,$>:-g;-O1>") add_link_options("$<$,$>:-fsanitize=thread>") # AddressSanitize add_compile_options("$<$,$>:-fsanitize=address>") add_compile_options("$<$,$>:-fno-omit-frame-pointer;-g;-O1>") add_compile_options("$<$,$>:-fsanitize-address-use-after-scope;-fno-optimize-sibling-calls>") # -fsanitize-address-use-after-scope added in GCC 7 add_compile_options("$<$,$,$,7.0.0>>:-fsanitize-address-use-after-scope>") add_link_options("$<$,$>:-fsanitize=address>") # LeakSanitizer add_compile_options("$<$,$>:-fsanitize=leak>") add_compile_options("$<$,$>:-fno-omit-frame-pointer;-g;-O1>") add_link_options("$<$,$>:-fsanitize=leak>") # MemorySanitizer add_compile_options("$<$,$>:-fsanitize=memory>") add_compile_options("$<$,$>:-fno-omit-frame-pointer;-g;-O2>") add_compile_options("$<$,$>:--fno-optimize-sibling-calls;-fsanitize-memory-track-origins=2>") add_link_options("$<$,$>:-fsanitize=memory>") # UndefinedBehaviour add_compile_options("$<$,$>:-fsanitize=undefined>") add_link_options("$<$,$>:-fsanitize=undefined>") # ABI Check. This build type is expected to work with the abi-dumper/abi-compliance-checker # binaries which expect specific debug information. In particular, for GCC versions >= 11 # we have to explicitly select dwarf versions < 5 as the abi-dumper doesn't support dwarf5 # and will always incorrectly report successful ABI checks # https://github.com/lvc/abi-dumper/issues/33 add_compile_options("$<$:-gdwarf-4;-g3;-ggdb;-Og>") # CMAKE_BUILD_TYPE is ignored for multi config generators i.e. MSVS get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(NOT _isMultiConfig) message(STATUS "CMake Build Type: ${CMAKE_BUILD_TYPE}") endif() if(OPENVDB_ENABLE_ASSERTS) message(STATUS "OpenVDB asserts are ENABLED") endif() # Intialize extra build type targets where possible if(NOT TARGET gcov_html) find_program(GCOVR_PATH gcovr) if(NOT GCOVR_PATH AND CMAKE_BUILD_TYPE STREQUAL "coverage") message(WARNING "Unable to initialize gcovr target. coverage build types will still generate gcno files.") elseif(GCOVR_PATH) # init gcov commands set(GCOVR_HTML_FOLDER_CMD ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/gcov_html) set(GCOVR_HTML_CMD ${GCOVR_PATH} --html --html-details -r ${PROJECT_SOURCE_DIR} --object-directory=${PROJECT_BINARY_DIR} -o gcov_html/index.html ) # Add a custom target which converts .gcda files to a html report using gcovr. # Note that this target does NOT run ctest or any binaries - that is left to # the implementor of the gcov workflow. Typically, the order of operations # would be: # - run CMake with unit tests on # - ctest # - make gcov_html add_custom_target(gcov_html COMMAND ${GCOVR_HTML_FOLDER_CMD} COMMAND ${GCOVR_HTML_CMD} BYPRODUCTS ${PROJECT_BINARY_DIR}/gcov_html/index.html # report directory WORKING_DIRECTORY ${PROJECT_BINARY_DIR} VERBATIM COMMENT "Running gcovr to produce HTML code coverage report." ) # Show info where to find the report add_custom_command(TARGET gcov_html POST_BUILD COMMAND ; COMMENT "Open ./gcov_html/index.html in your browser to view the coverage report." ) endif() endif() openvdb-13.0.0/cmake/config/OpenVDBVersions.cmake000066400000000000000000000064471510223237100215540ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ Current and future version requirements for all OpenVDB dependencies, including compilers, language features and OpenVDB's ABI. #]=======================================================================] cmake_minimum_required(VERSION 3.24) ############################################################################### # Configure minimum version requirements - some are treated specially and fall # outside of the DISABLE_DEPENDENCY_VERSION_CHECKS catch set(MINIMUM_CXX_STANDARD 17) # @note ABI always enforced so the correct deprecation messages are available. # OPENVDB_USE_DEPRECATED_ABI_ should be used to circumvent this math(EXPR MINIMUM_OPENVDB_ABI_VERSION "${OpenVDB_MAJOR_VERSION}-2") math(EXPR FUTURE_OPENVDB_ABI_VERSION "${OpenVDB_MAJOR_VERSION}+1") # List of deprecated but supported OpenVDB ABIs for this version of OpenVDB math(EXPR _PREV_ABI "${OpenVDB_MAJOR_VERSION}-1") set(OPENVDB_DEPRECATED_ABI_LIST ${MINIMUM_OPENVDB_ABI_VERSION} ${_PREV_ABI}) unset(_PREV_ABI) if(NOT DISABLE_DEPENDENCY_VERSION_CHECKS) # @note Currently tracking CY2024 of the VFX platform where available # (that is, our minimum requirements are for the current VFX platform) # minus 2 years to be able to build with legacy ABI) # @Note Compiler versions are not really a hard and fast rule, you just need # a compiler with complete support for our MINIMUM_CXX_STANDARD (currently 17). # What's usually important is that the version of libstdc++ and glibc in use # matches. Compilers other than GCC should provide options to ensure this # targetting e.g. --gcc-toolchain and -fgnuc-version with Clang. set(MINIMUM_GCC_VERSION 11.2.1) set(MINIMUM_CLANG_VERSION 5.0) set(MINIMUM_ICC_VERSION 19) set(MINIMUM_MSVC_VERSION 19.30) # 1928 (Visual Studio 2019 Version 16.8 + 16.9) set(MINIMUM_BOOST_VERSION 1.82) set(MINIMUM_OPENEXR_VERSION 3.2) set(MINIMUM_IMATH_VERSION 3.2) set(MINIMUM_ZLIB_VERSION 1.2.7) set(MINIMUM_TBB_VERSION 2020.3) set(MINIMUM_LLVM_VERSION 15.0.0) set(MINIMUM_BLOSC_VERSION 1.17.0) set(MINIMUM_GLFW_VERSION 3.3) set(MINIMUM_PYTHON_VERSION 3.11) set(MINIMUM_GOOGLETEST_VERSION 1.10) set(MINIMUM_LOG4CPLUS_VERSION 2.0) set(MINIMUM_HOUDINI_VERSION 20.5) # These always promote warnings rather than errors set(MINIMUM_MAYA_VERSION 2017) set(MINIMUM_DOXYGEN_VERSION 1.8.8) endif() # VFX 24 deprecations to transition to MINIMUM_* variables in OpenVDB 14.0.0 # @note At the time of writing, any variables that are commented out don't # have target transitional versions. # set(FUTURE_MINIMUM_GCC_VERSION 11.2.1) # set(FUTURE_MINIMUM_MSVC_VERSION 19.30) # set(FUTURE_MINIMUM_ICC_VERSION 19) # set(FUTURE_MINIMUM_CXX_STANDARD 20) set(FUTURE_MINIMUM_CMAKE_VERSION 4.0) set(FUTURE_MINIMUM_OPENEXR_VERSION 3.3) set(FUTURE_MINIMUM_IMATH_VERSION 3.3) set(FUTURE_MINIMUM_TBB_VERSION 2021) set(FUTURE_MINIMUM_BOOST_VERSION 1.85) #set(FUTURE_MINIMUM_GLFW_VERSION 3.3) #set(FUTURE_MINIMUM_LOG4CPLUS_VERSION 2.0) set(FUTURE_MINIMUM_NANOBIND_VERSION 2.5.0) # set(FUTURE_MINIMUM_BLOSC_VERSION 1.17.0) # set(FUTURE_MINIMUM_PYTHON_VERSION 3.11) # set(FUTURE_MINIMUM_HOUDINI_VERSION 20.0) set(FUTURE_MINIMUM_LLVM_VERSION 18.0.0) openvdb-13.0.0/cmake/scripts/000077500000000000000000000000001510223237100157735ustar00rootroot00000000000000openvdb-13.0.0/cmake/scripts/lsan.supp000066400000000000000000000015711510223237100176450ustar00rootroot00000000000000################################################################################# ## This file is loaded by the Leak/Address Sanitizer build for the unit tests. ## ## It can be used to ignore various errors reported by the sanitizer. This is ## ## especially useful with upstream issues (e.g. boost/tbb). For help defining ## ## suppression rules, see: ## ## https://clang.llvm.org/docs/AddressSanitizer.html ## ## The build is configured with CMAKE_BUILD_TYPE=asan or lsan ## ################################################################################# ##### Upstream ##### # Leaks from TBB init which occur due to tbb teardown issues # https://github.com/oneapi-src/oneTBB/issues/206 # Should be fixed in oneTBB. Ignore them for now leak:tbb::internal::task_stream<3>::initialize* openvdb-13.0.0/cmake/scripts/ubsan.supp000066400000000000000000000021231510223237100200120ustar00rootroot00000000000000################################################################################# ## This file is loaded by the Undefined Behaviour Sanitizer build for the unit ## ## tests. It can be used to ignore various errors reported by the sanitizer. ## ## This is especially useful with upstream issues (e.g. boost/tbb). For help ## ## defining suppression rules, see: ## ## https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html ## ## The build is configured with CMAKE_BUILD_TYPE=ubsan. ## ################################################################################# ##### Upstream ##### # Lots of warnings from TBB, ignore them alignment:tbb/concurrent_hash_map.h vptr:tbb/parallel_reduce.h vptr:tbb/task.h ##### OpenVDB ##### # Some 2s complement tests, ignore the negative shifts # @todo Should address these shift-base:TestMultiResGrid.cc shift-base:openvdb/math/Coord.h ##### OpenVDB AX ##### # Ignore overflows reported from old OpenSimplexNoise signed-integer-overflow:openvdb_ax/math/OpenSimplexNoise.cc openvdb-13.0.0/doc/000077500000000000000000000000001510223237100137715ustar00rootroot00000000000000openvdb-13.0.0/doc/CMakeLists.txt000066400000000000000000000245151510223237100165400ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ CMake Configuration for OpenVDB Documentation #]=======================================================================] cmake_minimum_required(VERSION 3.24) project(OpenVDBDocs LANGUAGES NONE) include(GNUInstallDirs) # If OPENVDB_DOXYGEN_HOUDINI is set, the Houdini documentation is also # built. You can provide this module a value for Houdini_VERSION which will # take into account any conditional compiled blocks. Whilst this doesn't # require you to build the Houdini plugin, building from the root CMake # with OPENVDB_BUILD_DOCS=ON and either OPENVDB_BUILD_HOUDINI_PLUGIN=ON or # USE_HOUDINI=ON will define Houdini_VERSION. If Houdini_VERSION is not set, # all documentation is included. option(OPENVDB_DOXYGEN_AX "Build AX documentation" ON) option(OPENVDB_DOXYGEN_HOUDINI "Build Houdini documentation" ON) option(OPENVDB_DOXYGEN_NANOVDB "Build NanoVDB documentation" ON) option(OPENVDB_DOXYGEN_INTERNAL [=[ Enable documentation of methods and classes which have been explicitly marked as internal ]=] OFF) find_package(Doxygen REQUIRED doxygen) if(MINIMUM_DOXYGEN_VERSION) if(DOXYGEN_VERSION VERSION_LESS MINIMUM_DOXYGEN_VERSION) message(WARNING "The doxygen-config doxyfile has been generated with version " "\"${MINIMUM_DOXYGEN_VERSION}\". Found Doxygen version \"${DOXYGEN_VERSION}\". " "Documentation may contain errors." ) endif() endif() set(DOXY_FILES openvdb/openvdb openvdb/openvdb/io openvdb/openvdb/math openvdb/openvdb/points openvdb/openvdb/points/impl openvdb/openvdb/python/pyopenvdb.h openvdb/openvdb/tools openvdb/openvdb/tools/impl openvdb/openvdb/tree openvdb/openvdb/util doc/build.txt doc/changes.txt doc/codingstyle.txt doc/dependencies.txt doc/doc.txt doc/examplecode.txt doc/faq.txt doc/math.txt doc/points.txt doc/python.txt) set(DOXYGEN_PROJECT_NAME "OpenVDB") set(DOXYGEN_PROJECT_NUMBER "${OpenVDB_VERSION}") set(DOXYGEN_PROJECT_BRIEF "") set(DOXYGEN_FILE_PATTERNS *.h *h.in) # headers only set(DOXYGEN_EXTENSION_MAPPING .in=C) # parse CMake config headers as C set(DOXYGEN_IMAGE_PATH "doc/img") set(DOXYGEN_RECURSIVE NO) set(DOXYGEN_QUIET YES) set(DOXYGEN_GENERATE_HTML YES) set(DOXYGEN_GENERATE_MAN NO) set(DOXYGEN_GENERATE_LATEX NO) set(DOXYGEN_GENERATE_TODOLIST NO) set(DOXYGEN_HTML_COLORSTYLE_HUE 4) set(DOXYGEN_HTML_COLORSTYLE_SAT 222) set(DOXYGEN_HTML_TIMESTAMP NO) # for simpler website diffs set(DOXYGEN_EXTRACT_ALL YES) set(DOXYGEN_EXTRACT_STATIC YES) set(DOXYGEN_EXTRACT_LOCAL_CLASSES NO) # Allow for root directory paths to be listed (e.g. openvdb/io/File.h) # Rather than just the file names (e.g. File.h). This makes it far # easier to navigate the docs set(DOXYGEN_FULL_PATH_NAMES YES) set(DOXYGEN_STRIP_FROM_PATH "${CMAKE_SOURCE_DIR}/openvdb" "${CMAKE_SOURCE_DIR}/openvdb_ax" "${CMAKE_SOURCE_DIR}/nanovdb" "${CMAKE_SOURCE_DIR}/openvdb_houdini" "${CMAKE_SOURCE_DIR}") set(DOXYGEN_STRIP_FROM_INC_PATH "${CMAKE_SOURCE_DIR}/openvdb" "${CMAKE_SOURCE_DIR}/openvdb_ax" "${CMAKE_SOURCE_DIR}/nanovdb" "${CMAKE_SOURCE_DIR}/openvdb_houdini") # Shows which source files generated the respected doxygen docs # at the bottom of each html page. Don't bother listing these. set(DOXYGEN_SHOW_USED_FILES NO) # When doxygen adds the source code for each header (see VERBATIM_HEADERS) # don't remove the actual doxygen comments set(DOXYGEN_STRIP_CODE_COMMENTS NO) # Don't add an alpha index of all classes (it's not particularly useful) set(DOXYGEN_ALPHABETICAL_INDEX NO) set(DOXYGEN_DISTRIBUTE_GROUP_DOC YES) set(DOXYGEN_HIDE_IN_BODY_DOCS YES) set(DOXYGEN_HIDE_SCOPE_NAMES YES) set(DOXYGEN_INLINE_INHERITED_MEMB YES) set(DOXYGEN_MACRO_EXPANSION YES) # @todo use dot with class diagrams for relevant classes set(DOXYGEN_CLASS_DIAGRAMS NO) set(DOXYGEN_ALIASES [[ijk="(i, j, k)"]] [[xyz="(x, y, z)"]] [[const="const"]] "\"vdbnamespace=openvdb::v${OpenVDB_MAJOR_VERSION}_${OpenVDB_MINOR_VERSION}\"" [["hunamespace=houdini_utils"]] [["hvdbnamespace=openvdb_houdini"]] # Use this command to create a link to an OpenVDB class, function, etc. # Usage is "@vdblink{,}", where is a fully namespace- # qualified symbol minus the openvdb and version number namespace components # and is the text of the link. # Example: @vdblink{tree::RootNode,root node} [[vdblink{2}="@link @vdbnamespace::\1 \2@endlink"]] # Deprecated; use the two-argument overload defined above. [[vdblink="@link @vdbnamespace"]] # Use these commands to create links to OpenVDB Houdini symbols. # Usage is "@hulink{,}", where is the name of # a symbol in the houdini_utils namespace and is the text of the link # (and likewise for @hvdblink). # Example: @hulink{ParmFactory::setDefault(),setDefault} # These stub implementations are used when Houdini support is disabled; # see doxygen-config-houdini for the full implementations. [[hulink{2}="\2"]] [[hvdblink{2}="\2"]] ) set(DOXYGEN_PREDEFINED "OPENVDB_VERSION_NAME=v${OpenVDB_MAJOR_VERSION}_${OpenVDB_MINOR_VERSION}" "OPENVDB_ABI_VERSION_NUMBER=${OpenVDB_MAJOR_VERSION}" [[__declspec(x):= __attribute__(x):=]] # Replace the deprecated macros with doxygen deprecated comments. This ensures # that every bit of deprecated C++ is listed in the doxygen deprecated list, # even if it was not properly tagged [["OPENVDB_DEPRECATED=/** \deprecated */"]] [["OPENVDB_DEPRECATED_MESSAGE(x)=/** \deprecated x */"]] "OPENVDB_USE_LOG4CPLUS=") set(DOXYGEN_ENABLED_SECTIONS "") if(OPENVDB_DOXYGEN_INTERNAL) list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_DOCS_INTERNAL") endif() if(OPENVDB_DOXYGEN_HOUDINI) # Append Houdini-specific settings to the Doxygen config file. if(Houdini_VERSION) # Extract the components of the Houdini version number into a list. string(REPLACE "." ";" HOUDINI_VERSION_COMPONENTS ${Houdini_VERSION}) list(GET HOUDINI_VERSION_COMPONENTS 0 HVERS_MAJOR) list(GET HOUDINI_VERSION_COMPONENTS 1 HVERS_MINOR) list(GET HOUDINI_VERSION_COMPONENTS 2 HVERS_PATCH) else() set(HVERS_MAJOR 127) # CMake treats (255 << 24) as a negative number set(HVERS_MINOR 0) set(HVERS_PATCH 0) endif() math(EXPR HVERS_INT "(((${HVERS_MAJOR} << 8) + ${HVERS_MINOR}) << 16) + ${HVERS_PATCH}") # Append Houdini version number macros to the Doxygen config file so that # the generated documentation reflects the API for that version # (i.e, taking into account any conditionally compiled blocks). list(APPEND DOXYGEN_PREDEFINED "UT_MAJOR_VERSION_INT=${HVERS_MAJOR}") list(APPEND DOXYGEN_PREDEFINED "UT_MINOR_VERSION_INT=${HVERS_MINOR}") list(APPEND DOXYGEN_PREDEFINED "UT_VERSION_INT=${HVERS_INT}") list(APPEND DOXYGEN_ALIASES [[hulink{2}="@link @hunamespace::\1 \2@endlink"]] [[hvdblink{2}="@link @hvdbnamespace::\1 \2@endlink"]] # Deprecated; use the two-argument overloads defined above. [[hulink="@link @hunamespace"]] [[hvdblink="@link @hvdbnamespace"]] ) list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_HOUDINI") list(APPEND DOXY_FILES doc/houdini.txt openvdb_houdini/openvdb_houdini/AttributeTransferUtil.h openvdb_houdini/openvdb_houdini/GEO_PrimVDB.h openvdb_houdini/openvdb_houdini/GT_GEOPrimCollectVDB.h openvdb_houdini/openvdb_houdini/GU_PrimVDB.h openvdb_houdini/openvdb_houdini/GU_VDBPointTools.h openvdb_houdini/openvdb_houdini/GeometryUtil.h openvdb_houdini/openvdb_houdini/ParmFactory.h openvdb_houdini/openvdb_houdini/PointUtils.h openvdb_houdini/openvdb_houdini/SOP_NodeVDB.h openvdb_houdini/openvdb_houdini/SOP_VDBVerbUtils.h openvdb_houdini/openvdb_houdini/UT_VDBTools.h openvdb_houdini/openvdb_houdini/UT_VDBUtils.h openvdb_houdini/openvdb_houdini/Utils.h) endif() if(OPENVDB_DOXYGEN_AX) set(DOXYGEN_EXTRA_PACKAGES amsmath) # for math formatting set(DOXYGEN_FORMULA_FONTSIZE 14) list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_AX") list(APPEND DOXY_FILES doc/ax/ax.txt doc/ax/axcplusplus.txt doc/ax/axexamples.txt doc/ax/axfunctionlist.txt doc/ax/doc.txt openvdb_ax/openvdb_ax openvdb_ax/openvdb_ax/ast openvdb_ax/openvdb_ax/codegen openvdb_ax/openvdb_ax/compiler openvdb_ax/openvdb_ax/grammar openvdb_ax/openvdb_ax/grammar/generated openvdb_ax/openvdb_ax/math openvdb_ax/openvdb_ax/test) endif() if(OPENVDB_DOXYGEN_NANOVDB) list(APPEND DOXYGEN_ENABLED_SECTIONS "NANOVDB") list(APPEND DOXY_FILES doc/nanovdb/doc.md doc/nanovdb/FAQ.md doc/nanovdb/SourceTree.md doc/nanovdb/HowToBuild.md doc/nanovdb/HelloWorld.md nanovdb/nanovdb nanovdb/nanovdb/util nanovdb/nanovdb/examples/benchmark nanovdb/nanovdb/examples/ex_bump_pool_buffer nanovdb/nanovdb/examples/ex_collide_level_set nanovdb/nanovdb/examples/ex_make_custom_nanovdb nanovdb/nanovdb/examples/ex_make_funny_nanovdb nanovdb/nanovdb/examples/ex_make_nanovdb_sphere nanovdb/nanovdb/examples/ex_make_typed_grids nanovdb/nanovdb/examples/ex_map_pool_buffer nanovdb/nanovdb/examples/ex_modify_nanovdb_thrust nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_accessor nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_cuda nanovdb/nanovdb/examples/ex_raytrace_fog_volume nanovdb/nanovdb/examples/ex_raytrace_level_set nanovdb/nanovdb/examples/ex_read_nanovdb_sphere nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda nanovdb/nanovdb/examples/ex_util nanovdb/nanovdb/examples/ex_vox_to_nanovdb nanovdb/nanovdb/examples/ex_write_nanovdb_grids nanovdb/nanovdb/unittest) endif() set(DOXYGEN_VERBATIM_VARS DOXYGEN_ALIASES DOXYGEN_PREDEFINED) # Always add to build target (can't use USE_STAMP_FILE as we include # complete directories in DOXY_FILES) doxygen_add_docs(doc ${DOXY_FILES} ALL WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen") # Suppress "Installing..." messages for all but one of the hundreds of generated files. install(FILES ${CMAKE_CURRENT_BINARY_DIR}/html/index.html DESTINATION ${CMAKE_INSTALL_DOCDIR}/html) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} MESSAGE_NEVER) openvdb-13.0.0/doc/ax/000077500000000000000000000000001510223237100144015ustar00rootroot00000000000000openvdb-13.0.0/doc/ax/ax.txt000066400000000000000000002530711510223237100155620ustar00rootroot00000000000000/**
@page ax AX @section axlanguage AX Language Documentation @par Welcome to the AX Language documentation. These docs provide detailed information on the AX language including syntax, data types, available functionality (including OpenVDB specific methods) execution structure and control flow. See the @subpage axcplusplus documentation for the C++ developer documentation. @note Some sections of this document are still to be completed. Please get in touch should you have any questions! @section axcontents Contents - @ref axintro - @ref axprograms - @ref axprogramexample - @ref axexecutionxcontext - @ref axdatatypes - @ref axscalars - @ref axvecmats - @ref axstrings - @ref axtypeprecedence - @ref axoperators - @ref axopbinary - @ref axopassignment - @ref axopbinarithmetic - @ref axopcomparison - @ref axopbinlogical - @ref axopunary - @ref axopunarithmetic - @ref axopunlogical - @ref axopunincdec - @ref axopaccess - @ref axopother - @ref axopprecedence - @ref axtokens - @ref axvaridentifiers - @ref axliterals - @ref axcomments - @ref axkeywords - @ref axreserved - @ref axsyntax - @ref axattribaccess - @ref axexternalaccess - @ref axdecls - @ref axscopes - @ref axbranching - @ref axloops - @ref axfunctions - @ref axuserfunctions - @ref axvexsupport - @ref axexamples @section axintro Introduction @par AX is a fast and portable JIT compiled expression language, designed for writing volume and point kernels represented as OpenVDB grids. It was originally developed by the RNDFX team at DNEG to provide a more consistent way for artists to be able to interface with OpenVDB data across a variety of in house and external digital content creation software, whilst retaining the performance achievable by custom C++ operators. @par The language is predominately inspired by SideFX's VEX language which itself takes elements from C, C++ and the Renderman Shading Language. The design of AX uses concepts from these languages and refrains from deviating from their syntax too significantly. Specifically, it does not aim to change what are already well established and heavily used language syntaxes within the Visual Effects industry; on the contrary, AX aims to provide an interface to which a user with previous or little programming experience can easily transition to. However, it does introduce new concepts where the creators deemed necessary to provide the best and most representative syntax relating to the design for OpenVDB volume and point modification. @section axprograms AX Programs @par AX programs represent a set of statements which read and write to geometry, with each program designed in such a way that it can be executed in a highly parallelized framework to access and update individual geometric components. For example, consider a mesh with point, vertex and primitive attributes. AX programs are designed to run independently across "elements" of input geometry and process "attributes" from a particular element. In this case, the element level would correlate to either points, vertexes or primitives, and a single element would be a unique instance of one of these. These programs are at their most efficient writing to the currently processing element, however do provide varying levels of access to the geometry as a whole. @par Note that native AX only supports the modification of OpenVDB data. Currently, that means that native AX programs can be written and built for execution over OpenVDB Points or OpenVDB Volumes. For any given AX program, the execution context (what it's processing) may change what functionality is available and, more importantly, the behaviour of reading/writing from attributes. See the @ref axexecutionxcontext for details. @par Whilst powerful, AX is not a catch all replacement for all types of VDB operations. Some of this is related to its infancy i.e. missing native support for some useful functions, the foundations of which may be supported by AX but have not yet been exposed. However there may be certain paradigms which AX is better tailored to support than others. Grid reductions, for example, typically require the passing of a state between programs; a design pattern which AX is less equipped to handle. AX kernels can be abstractly thought of as a "foreach()" function (see @ref axprogramexample) and whilst there are ways to achieve reductions, it is an example which would be better suited to a custom C++ implementation. @par For details of extending AX for custom geometry, see the @subpage axcplusplus developer documentation. Note that custom geometry support requires C++ extension. @subsection axprogramexample A Program Example @par Before getting into the technical depths of the language, it's a good idea to observe a small but complete AX program which could be compiled and executed. To begin with, here is a very simple example of a program that reads and writes to a particular attribute: @par @code{.c} // read a floating point attribute from the value of "myattribute" float temp = float@myattribute; // if the value is less than 0, clamp it to 0 if (temp < 0.0f) float@myattribute = 0.0f; @endcode Note that there is no other required logic here to make this a compatible program i.e. feeding this code to the @ref vdbaxbinary "vdb_ax command line binary" will compile and execute over provided OpenVDB files. @par The following explains the above example in relation to OpenVDB data; OpenVDB points and OpenVDB volumes. The example demonstrates reading from a value on some input, either a point attribute or a voxel value, and storing the result in a @ref axdecls "local variable". Importantly, the attribute being accessed has the name @b `myattribute` and the type @b `float`. The first statement: @code{.c} float temp = float@myattribute; @endcode Invokes a @b read from this attribute (see @ref axattribaccess), retrieving the value from the geometry and storing it in the variable @b `temp` to be used in the AX program. The second statement: @code{.c} if (temp > 0.0f) float@myattribute = 0.0f; @endcode Performs a comparison of this value with @b `0.0f` and, if the value is greater than @b `0.0f`, performs a @b write to the geometry in the form of `float@myattribute = 0.0f;` which sets the value of this attribute on the geometry to @b `0.0f`. @par For OpenVDB Points, this kernel is run over every point in an OpenVDB Points Grid. In simple pseudo code: @code{.unparsed} foreach(point in pointgrid) run_ax_kernel(point) done() @endcode Where @b `pointgrid` is a single Point Data Grid. For OpenVDB volumes the kernel is run over each voxel in a provided grid: @code{.unparsed} foreach(grid in grids) foreach(voxel IN grid) run_ax_kernel(voxel) done() done() @endcode @par Where @b `grids` can comprise of any number of OpenVDB volumes. In this program, only a floating point grid with the name @b `myattribute` will be updated. Each voxel in this grid will have it's value compared in the same way as the points example given above. @subsection axexecutionxcontext OpenVDB Execution Context @par AX programs are designed to run over different types of grids, specifically OpenVDB points and OpenVDB volumes, the latter of which is the set of all default supported mathematic volume types in OpenVDB. Programs must be compiled separately for points and volumes, or twice to support both (see the @ref vdbaxbinary "vdb_ax binary"). This is known as compiling for a target Execution Context. There are two main considerations to make when switching between execution contexts: - Certain @ref axfunctions "functions" may not be available under a given context. Some natively supported functions are designed to interface directly with geometry attributes, and a further subset of these are tailored specifically for point attributes @b or voxel values, not both. - Whilst the AX grammar does not change syntactically, @ref axattribaccess "attribute accesses" may be affected. This is due to the fundamental differences of executing over different types of VDBs/geometry. @par Execution over Points AX kernels compiled for OpenVDB Points run @b individually on each point in every active voxel in a points VDB. Attributes that have been accessed in the program are provided such that the program has access to all data available on the currently processing point. Multiple OpenVDB Point grids can be processed by the same AX program, but only a single OpenVDB Points grid can be processed at a time. The default behaviour for AX point programs is to process every point which exists in active OpenVDB voxels. @par Execution over Volumes AX kernels for OpenVDB volumes run individually on every active voxel of VDBs which are @b written to (whilst retaining access to all available VDBs). Volumes can be thought of as only holding a single "attribute". Whilst points hold all attributes within a single VDB points grid (and values for all attributes are are defined for all points in that grid), multiple volume attributes require multiple VDB volumes to be accessed. The location of this access is the world space position of each voxel. Assignment operations determine which volumes will be executed over. @par See the syntax section on @ref axattribaccess "accessing attribute" for more information.

@section axdatatypes Data Types @par AX supports a rich variety of native types to be able to maximise the efficiency of arithmetic operations and facilitate accessing underlying geometry. As AX is designed for OpenVDB, native AX types aim to provide direct access to all supported OpenVDB data types. You may find, however, that some AX types do not exist as OpenVDB volume/point types or refuse to be serialized in some installations of OpenVDB. The table below lists all available types in AX, the exposed @ref axattribaccess "attribute access" syntax and whether or not the attribute syntax is valid for both point and volume execution contexts. Developers installing OpenVDB and OpenVDB AX may wish to read the @ref vdbaxtoaxtypes "type registry documentation" which explains how to enable missing types from OpenVDB. @anchor axdatatypestable @par
CategoryTypeDefinitionAttribute SyntaxPointsVoxels
@ref axscalars `bool` Boolean value, true or false`bool@` @b Yes@b Yes
`int16`*16-bit signed integer value`int16@`@b YesNo
`int32`32-bit signed integer value`int32@, int@, i@`@b Yes@b Yes
`int`Alias for integer type (typically int32)
`int64`64-bit signed integer value`int64@`@b Yes@b Yes
`float`32-bit floating point value`float@ f@ @`@b Yes@b Yes
`double`64-bit floating point value`double@`@b Yes@b Yes
@ref axvecmats "Vectors" `vec2i` 2-element vector of integer values `vec2i@` No No
`vec2f`2-element vector of float values `vec2f@`NoNo
`vec2d`2-element vector of double values `vec2d@`NoNo
`vec3i`3-element vector of integer values`vec3i@`@b Yes@b Yes
`vec3f`3-element vector of float values `vec3f@ v@`@b Yes@b Yes
`vec3d`3-element vector of double values `vec3d@`@b Yes@b Yes
`vec4i`4-element vector of integer values`vec4i@`NoNo
`vec4f`4-element vector of float values `vec4f@`NoNo
`vec4d`4-element vector of double values `vec4d@`NoNo
@ref axvecmats "Matrices" `mat3f` 3x3-matrix of float values `mat3f@` @b Yes No
`mat3d`3x3-matrix of double values`mat3d@`@b YesNo
`mat4f`4x4-matrix of float values `mat4f@`@b YesNo
`mat4d`4x4-matrix of double values`mat4d@`@b YesNo
@ref axstrings "Strings" `string` A string of characters `string@` @b Yes @b Yes
- @b Note* - There is no support for int16 local variables or integer literals. @subsection axscalars Scalars @par AX Supports boolean, integer and floating point scalar types. @b `int` and @b `int32` represent 32-bit integer values and @b `int64` represents a 64-bit value. @b `float` and @b `double` represent 32-bit and 64-bit floating point values respectively. All scalars, excluding bools, are signed; there are no other unsigned scalar types in AX. @par Integer Overflow and Floating Point Truncation Scalars may be cast from one type to another, either explicitly using the @ref axopother "cast" operator or implicitly during @ref axopassignment "assignments" or @ref axopbinarithmetic "binary arthimetic" operations (in which case the order of @ref axtypeprecedence "type precedence" is observed). Data can be truncated (converting floats to integrals) or overflow (conversions from integers of larger bit widths to integers of smaller bit widths) depending on the source and target types. See the below examples: @par This example demonstrates floating point truncation in AX. @code float a = 1.1f; int b = 5.5f; // implict conversion from literal 5.5f. "b" is set to 5 b = a; // implicit conversion from float "a". "b" is set to 1 @endcode @par This example demonstrates integer overflow in AX. @code int64 a = 2147483648l; // one more than can be held in an int (note the last letter "l") int b = a; // implicit conversion. "b" is set to -2147483648 @endcode @par Infinite and NaN values Floating point values have two additional intrinsic states; @b `inf` and @b `nan`. These states can occur during invalid floating point arithmetic. AX performs no checks on arithmetic to catch these values. A typical example of both @b `inf` and @b `nan` values are division by zero expressions: @code float a = 1.0f/0.0f; print(a); // prints "inf" @endcode @code float a = 0.0f/0.0f; print(a); // prints some version of "nan" @endcode @par Generally these values are not desired and can cause problems as they propagate throughout your program. @subsection axvecmats Vectors / Matrices @par All vector and matrix types in AX are implemented as flat arrays of a given size, with all elements stored contiguously in memory. Both container types are represented by @ref axdatatypestable "specific tokens" which tell AX functions and operators how to handle various arithmetic. @par Vectors There is currently support for vectors of sizes 2, 3 and 4 elements. The suffix letter on the vector types denotes the contained elements precision, with the number corresponding to the vector size. For example, @b `vec2i` denotes a vector of two 32-bit integer elements. There are no native types for vectors with @b `bool`, @b `int16` or @b `int64` elements, so these are not supported. @par Matrices Matrices are stored in row major layout (lexographical access order) which matches the representation of a matrix in OpenVDB. Matrix support consists of @b `float` and @b `double` precision elements with dimensions either @b `3x3` or @b `4x4` (total size of 9 and 16 elements respectively). There are no integer or boolean matrix types. Similiar to vectors, the suffix letter on the type denotes the contained elements precision, with the number corresponding to the matrix dimension. A matrix of type @b `mat3d` therefor corresponds to a @b `3x3` matrix (9 elements) with @b `double` precision elements. @par Element Access As elements of all matrix and vector types are stored contiguously, they can be accessed by the @ref axvecaccessop "[] operator". Vector elements can also be accessed by supported @ref axopaccess ". operator" components and matrix elements can be accessed with the @ref axmataccessop "[,] operator". @par Initialization Both matrices and vector declarations can be flat initialized from scalars or component initialized from containers of the same size (see @ref axopassignment "assignments"). However both types can also be represented as temporary containers without declarations using the @ref axvecmatinit "{,} syntax." @par A Note on Operators Most @ref axopbinary "binary operators" only accept vectors of @b equal sizes as valid left and right operands - however there exists valid @ref axopbinarithmetic "arithmetic" for combinations of vectors/matrices with scalars and, importantly, @ref axbinmultop "multiplicative arithmetic" for vectors with matrices, the latter performing matrix projections (transformations) on vector arguments. @subsection axstrings Strings @par Strings are an array of characters stored in a unique AX type which is incompatible with @ref axopaccess "container accesses". As such, string support is currently fairly limited. Characters themselves (users may know this as a @b `char` type) have no frontend type, so a @b `string` type must be used for any number of characters (including the empty string). String literals are represented by enclosing any number of @ref axtokens "supported AX characters" by quotes \" \". @subsection axtypeprecedence Implicit conversion / type precedence @par All operators that perform on two or more types must internally run the operation at a single precision. When mixing different types (e.g. `int + float`) values may need to be converted to another type before the operation is performed. To allow for easier writing of expressions, AX will automatically detect these cases and convert values when necessary. This is known as implicit type conversion and the way in which the target operation type is chosen is known as type precedence. @par When referring to type precedence, we are primarily refering to the conversion of one @b scalar type to another. For vectors, matrices and other containers, this refers to the conversion of their element type e.g. `mat3f` to `mat3d`. The conversion rules for more than the element type (e.g. `int` to `mat4f`) are governed by AX's assignment and operator rules, detailed in the @ref axoperators section of this documentation. @par Type precedence @b only applies to the @b element type of the type in question. Containers (such as vectors or matrices) may change their element type precision (e.g. `vec2i` to `vec2f`). Each scalar type has a ranking which is compared, and the resulting highest rank is chosen as the target type for all values. These rankings are defined as follows: - If any element types are of type `double`, all other element types are converted to `double` - else, if any element types are of type `float`, all other element types are converted to `float` - else, if any element types are of type `int64`, all other element types are converted to `int64` - else, if any element types are of type `int32`, all other element types are converted to `int32` - else, all element types are `bool` @par For example: @par @code{.c} int a = 0; float b = 0.0f; // In the following, the arithmetic a + b chooses floating point precision as // defined by the above type precedence rules (i.e. float(a) + b). The temporary // value created by the arithmetic + will be at float precision. The subsequent // assignment must then convert the final result back an integer, resulting in // an expression equal to: a = int(float(a) + b); a = a + b; // This example shows arithmetic minus with a float scalar and vec4d. Minus is a // supported operator of vec4d, however as the element types do not match // (float vs double), implicit conversion must be observed. With the above rules, // we can determine the following expression: c = double(b) + c. Note that // as the result of "double(b) + c" is a vec4d and the target of the subsequent // assignment ("c") is a vec4d, no further conversion needs to be performed. vec4d c = 0.0; // double element type c = b - c; @endcode @par Strings are not included in this precedence as there are no supported arithmetic binary operations for strings with operand types other than string.

@section axoperators Operators @par The below table lists all available operators supported by AX. Note that not all AX types support all operators and some operators have unique functionality depending on the operand types. @par
Operators
@ref axopbinary @ref axopunary Other
@ref axopassignment @ref axopbinarithmetic @ref axopcomparison @ref axopbinlogical @ref axopunarithmetic @ref axopunlogical @ref axopunincdec @ref axopaccess @ref axopother

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

a + b
a - b
a * b
a / b
a % b
a & b
a | b
a ^ b
a << b
a >> b

a == b
a != b
a < b
a > b
a <= b
a >= b

a && b
a || b

+a
-a
~a

!a

++a
\-\-a
a++
a\-\-

a[]
a[,]
a.b

a(...)
a, b
a ? b : c
{ a,b ... }

@subsection axopbinary Binary Operators @par Binary operators are the most common inbuilt operators for AX types. These operators take two inputs; a left hand side and a right hand side. There exists a number of valid combinations of AX types with different binary operators, as well as different implicit casting schemes depending on the binary operation being performed. @subsubsection axopassignment Assignments @par Assignment operators are the only way to directly modify the value of local and external data (except for @ref axfunctions which take @b references). The assignment operators have the following forms: @par
Operator NameOperator SyntaxReturns
Simple assignment @a `lhs` `=` @a `rhs` Reference to @a `lhs`
Addition assignment @a `lhs` `+=` @a `rhs` Reference to @a `lhs`
Subtraction assignment @a `lhs` `-=` @a `rhs` Reference to @a `lhs`
Multiplication assignment @a `lhs` `*=` @a `rhs` Reference to @a `lhs`
Division assignment @a `lhs` `/=` @a `rhs` Reference to @a `lhs`
Modulo assignment @a `lhs` `%=` @a `rhs` Reference to @a `lhs`
Bitwise AND assignment @a `lhs` `&=` @a `rhs` Reference to @a `lhs`
Bitwise OR assignment @a `lhs` `|=` @a `rhs` Reference to @a `lhs`
Bitwise XOR assignment @a `lhs` `^=` @a `rhs` Reference to @a `lhs`
Bitwise shift left assignment @a `lhs` `<<=` @a `rhs` Reference to @a `lhs`
Bitwise shift right assignment @a `lhs` `>>=` @a `rhs` Reference to @a `lhs`
@par These can be further categorised into two types; direct assignment, which is comprised only of the simple assignment operator, and compound assignments, which is the set of all other assignment operators. @par Direct Assignment Direct assignments replace the contents of the @b `lhs` with a copy of the @b `rhs`: @par
@a `lhs` = @a `rhs`
@par The @b `rhs` side is not modified and the @b `lhs` is not read - only written to. If the @b `rhs` type does not match the @b `lhs` type, the @b `rhs` is first implicitly converted into a new temporary with the @b `lhs` type before being copied into the @b `lhs`. The following combination of AX type categories are supported for direct assignment (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`=` @ref axscalars "scalar" On type mismatch, right hand side is copied and @ref axtypeprecedence "implicitly cast" to the left hand side type.
@ref axvecmats "vector" `=` @ref axscalars "scalar" Each element of the vector is set to the right hand side scalar. i.e.
`a[0] = b; ... a[n-1] = b;`
where `n` is the size of the vector. If the scalar type does not match element type of vector, the scalar is copied and @ref axtypeprecedence "implicitly cast" to that type.
@ref axvecmats "vector" Component wise assignment i.e.
`a[0] = b; ... a[n-1] = b;`
where `n` is the size of the vector. @code{.c} vec3f a = 0, b = 1; a = b; @endcode is equal to: @code{.c} vec3f a = 0, b = 1; for (int i = 0; i < 3; ++i) a[i] = b[i]; @endcode If the right hand side element type does not match the left hand side element type, each element of the right hand side is copied and @ref axtypeprecedence "implicitly cast "to the target left hand side element type. Operand sizes must match.
@ref axvecmats "matrix" `=` @ref axscalars "scalar" Diagonal matrix construction. Each diagonal component of the left hand side matrix is set to to the right hand side scalar. All other components are zero initialized i.e. @code{.c} mat3f a; int dim = 3, b = 1; for (int i = 0; i < dim; ++i) a[i] = (i % (dim+1) == 0) ? b : 0; @endcode Where `a` is the matrix, `dim` is the dimension of the matrix (e.g. 3 for `mat3f`) and `b` is the scalar. If the scalar type does not match element type of matrix, the scalar is copied and @ref axtypeprecedence "implicitly cast" to that type.
@ref axvecmats "matrix" Component wise assignment i.e.
`a[0] = b[0]; ... a[n-1] = b[n-1];`
where `n` is the @b total size of the matrix. @code{.c} mat4f a = 0, b = 1; a = b; @endcode is equal to: @code{.c} mat4f a = 0, b = 1; for (int i = 0; i < 16; ++i) a[i] = b[i]; @endcode If the right hand side element type does not match the left hand side element type, each element of the right hand side is copied and @ref axtypeprecedence "implicitly cast" to the target left hand side element type. Operand sizes must match.
@ref axstrings "string" `=` @ref axstrings "string" Replaces the contents of the left hand side string with a copy of the contents in the right hand side string.
@par @code{.c} float b; vec3f c = 0.0f; // assign components of c (x/y/z) to an floating point literal of value 0.0f int a = 1; // assign a from an integer literal of value 1 c = a; // assign components of c (x/y/z) to the result of float(a) @endcode @par Compound Assignment Compound assignments replace the the contents of the @b `lhs` with the result of a @ref axopbinarithmetic "binary arithmetic" operation of the @b `lhs` with the @b `rhs`: @par
@a `lhs` @b op @a `rhs`
Where @b op is one of :
`+=` `-=` `*=` `/=` `%=` `&=` `|=` `^=` `<<=` `>>= `
@par The behaviour of a given compound assignment (for example `a += b`) is similar to replacing the compound assignment with a @ref axopassignment "direct assignment" followed by a @ref axopbinarithmetic "binary expression" with the same operands and given arithmetic token (i.e. `a = a + b`). However, compound assignments imporantly do @b not evaluate the @b `lhs` twice. This is important when assigning to an expression which is not an attribute or local value. The best example of this is assigning to a @ref axopunincdec "pre-crement" operation: @par @code{.c} int a = 1; ++a += 1; // equal to a = ++a + 1 which is equal to 3 @endcode @par The @b `rhs` side is not modified, however the @b `lhs` is both read from and written to. Note that the arithmetic operation may cast either @b `lhs` or @b `rhs` following the rules of AX's @ref axopbinarithmetic "arithmetic type precedence". See the @ref axopbinarithmetic "arithmetic operations" section for more information on arithmetic type precedence and explanations on the above compound operators. @par @code{.c} int a = 3; a += a; // the same as a = a + a; a will be set to 6 float b = 0; b -= a; // the same as b = b - float(a); a *= b; // the same as a = float(a) * b; Note that although the target type is int, the binary op is performed at float precision @endcode @par Assignment Chains As assignments return a @b reference to the left hand side, all assignment operators can be @b chained. Note however that the return result will be at the type of the left hand side. For example: @par Given @par @code{.c} float a; int b, c; @endcode @par This @par @code{.c} a = b = c = 4.5f; @endcode @par is fundamentally the same as: @par @code{.c} c = 4.5f; // c of type int. 4.5f will be floored (int(4.5)). c becomes 4 b = c; // b becomes 4 a = b; // a becomes float(4) @endcode @par Importantly, @b `a` receives the result of any previous implicit casts to the right hand side of its binary assignment. @subsubsection axopbinarithmetic Arithmetic @par Binary arithmetic operations compute the result of a arithmetic operand token on two inputs and returns the result. The inputs are not modified, however may be copied and @ref axtypeprecedence "implicitly cast" to temporary values if the types do not match. All results are returned as new temporary values. If @b integral is explicitly stated, the operation is only valid on types which have an integer element type and will involve and implicit cast to integer types for floating point operands (the operation may be further restricted for container types). Binary arithmetic operations have the following forms: @par
Operator NameOperator SyntaxReturns
Addition @a `lhs` `+` @a `rhs` The sum of both operands
Subtraction @a `lhs` `-` @a `rhs` The first operand minus the second operand
Multiplication @a `lhs` `*` @a `rhs` The product of both operands
Division @a `lhs` `/` @a `rhs` The first operand divided by the second operand
Modulo @a `lhs` `%` @a `rhs` The @b floored modulo operator. See @ref axbinmultop "Multiplicative operands"
Bitwise AND @a `lhs` `&` @a `rhs` The @b integral bitwise AND result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise OR @a `lhs` `|` @a `rhs` The @b integral bitwise OR result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise XOR @a `lhs` `^` @a `rhs` The @b integral bitwise XOR result of each bit in the first operand applied to the bit at the same location in the second operand
Bitwise shift left @a `lhs` `<<` @a `rhs` The @b integral bitwise left shift of the first operand by the second operand
Bitwise shift right @a `lhs` `>>` @a `rhs` The @b integral bitwise right shift of the first operand by the second operand
@anchor axbinadditiveop @par Additive operands Binary additive operations perform summations on the input arguments. They have the following forms: @par
@a `lhs` @b `+` @a `rhs`
@a `lhs` @b `-` @a `rhs`
@par After @ref axtypeprecedence "implicit conversion", the result of the binary operation with the arithmetic @b `+` (@ref axtokens "plus token") is the sum of the operands, and the result of the binary operation with the arithmetic @b `-` (@ref axtokens "minus token") token is the second operand subtracted from the first operand. The following combination of AX type categories are supported for additive operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`+` `-`@ref axscalars "scalar" Returns the result of the scalar addition or subtraction.
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion") with the left hand side scalar to every element of the right hand side vector or matrix, returning a vector or matrix. @code{.c} vec3f a = 2.0f; int b = 1; vec3f c = b + a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = b + a[i]; @endcode
@ref axvecmats "matrix"
@ref axvecmats "vector" `+` `-` @ref axscalars "scalar" Same as `scalar op vector`
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2, b = 1; vec3f c = a - b; @endcode is equal to: @code{.c} vec3f a = 2, b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = a[i] - b[i]; @endcode
@ref axvecmats "matrix" `+` `-` @ref axscalars "scalar" Same as `scalar op matrix`
@ref axvecmats "matrix" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new matrix with each element holding the corresponding result. Operand sizes must match. @code{.c} mat4f a = 0, b = 1; mat4f c = a - b; @endcode is equal to: @code{.c} mat4f a = 0, b = 1; mat4f c; for (int i = 0; i < 16; ++i) c[i] = a[i] - b[i]; @endcode
@ref axstrings "string" `+` @ref axstrings "string" Performs string concatenation
@note Floating point addition and subtraction is communicative (`a + b = b + a`) but is not @b necessarily associative. i.e. `(a + b) + c` is not necessarily equal to `a + (b + c)`. @par Examples of validity of additive operations: @par @code{.c} int a = 0; vec2f b = 1.0f; vec2i c = 2; mat4d d = 0.0; c + a; // valid vec + scalar c + d; // invalid vec + matrix c - b; // valid vec - scalar @endcode @anchor axbinmultop @par Multiplicative operands The binary multiplicative operands have the following forms: @par
@a `lhs` @b `*` @a `rhs`
@a `lhs` @b `/` @a `rhs`
@a `lhs` @b `%` @a `rhs`
@par After @ref axtypeprecedence "implicit conversion", the result of the binary operation: - with the arithmetic @b `*` (@ref axtokens "asterisk token") is: - the product of the operands - @b OR performs matrix multiplication for vector and matrix types. - with the arithmetic @b `/` (@ref axtokens "forward slash token") is the first operand divided by the second operand. - with the arithmetic @b `%` (@ref axtokens "percentage token") is the @b floored modulo operations .i.e. the expression `d % D` returns the result `D - d * floor(D/d)`. This is in contrast to truncated modulo operations `D - d * (D/d)` where the division is truncated. @warning Floored modulo has been chosen to provide better expected behaviour with signed dividends. In such cases the result will always be positive; in other words, the sign of the result is @b always taken from the divisor. This does however mean that the relationship properties between `%` and `/` differ when either @b `d` or @b `D` is negative. i.e.: `(d/D)*D + (d%D) != d` @note The multiplicative operation @b `*` has important behaviour for vectors and matrix types. @par The following combination of AX type categories are supported for multiplicative operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`* / %`@ref axscalars "scalar" Returns the result of the scalar multiplication, division or remainder of the division respectively.
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion") with the left hand side scalar to every element of the right hand side vector. The scalar is effectively treated as a vector of the same size as the right hand side type. @code{.c} vec3f a = 2.0f; int b = 1; vec3f c = b * a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = b * a[i]; @endcode
`*`@ref axvecmats "matrix" Performs matrix multiplication after diagonal matrix construction from the left hand side scalar. @code{.c} mat3f a = 1; float b = 1; mat3f c = a * b; @endcode is equal to: @code{.c} mat3f a = 1; float b = 1; mat3f tmp = b; // diagonal matrix mat3f c = a * tmp; @endcode
@ref axvecmats "vector" `* / %` @ref axscalars "scalar" Same as `scalar op vector` with the operands reversed (importantly for division and modulus)
@ref axvecmats "vector" Performs per component binary operations (after @ref axtypeprecedence "implicit conversion"), returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2, b = 1; vec3f c = a * b; @endcode is equal to: @code{.c} vec3f a = 2, b = 1; vec3f c; for (int i = 0; i < 3; ++i) c[i] = a[i] * b[i]; @endcode
`*`@ref axvecmats "matrix" Transforms the left hand side vector by the right hand side matrix using matrix multiplication. This is the same as calling the @ref axtransform "transform" function. e.g: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = b * a; @endcode is equal to: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = transform(b, a); @endcode Typically, matrix multiplication requires arguments of the same dimension sizes - that is, a `mat4` can only be applied to a `vec4`. However, it is often useful to be able to directly apply `mat4` transformations to `vec3` types, most often due to positions being represented as `vec3`. `vec3 * mat4` multiplication is supported, where by the `vec3` is extended with a `1` component and the resulting last last component is dropped from the return value: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; // b * a is equal to: vec4f tmp; tmp[0] = b[0]; tmp[1] = b[1]; tmp[2] = b[2]; tmp[3] = 1; tmp = tmp * a; b[0] = tmp[0]; b[1] = tmp[1]; b[2] = tmp[2]; @endcode @b Note: Valid operand sizes and return types match those of the @ref axtransform "transform" function i.e: - `vec3 * mat3 = vec3` - `vec3 * mat4 = vec3` - `vec4 * mat4 = vec4`
@ref axvecmats "matrix" `*` @ref axscalars "scalar" Same as `scalar * matrix`
@ref axvecmats "vector" Transforms the right hand side vector by the left hand side matrix using matrix multiplication. This is the same as calling the @ref axpretransform "pretransform" function. e.g: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = a * b; @endcode is equal to: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; b = pretransform(a, b); @endcode Typically, matrix multiplication requires arguments of the same dimension sizes - that is, a `mat4` can only be applied to a `vec4`. However, it is often useful to be able to directly apply `mat4` transformations to `vec3` types, most often due to positions being represented as `vec3`. `mat4 * vec3` multiplication is supported, where by the `vec3` is extended with a `1` component and the resulting last last component is dropped from the return value: @code{.c} mat4f a = identity4(); vec3f b = { 1, 2, 3 }; // a * b is equal to: vec4f tmp; tmp[0] = b[0]; tmp[1] = b[1]; tmp[2] = b[2]; tmp[3] = 1; tmp = a * tmp; b[0] = tmp[0]; b[1] = tmp[1]; b[2] = tmp[2]; @endcode @b Note: Valid operand sizes and return types match those of the @ref axpretransform "pretransform" function i.e: - `mat3 * vec3 = vec3` - `mat4 * vec3 = vec3` - `mat4 * vec4 = vec4`
@ref axvecmats "matrix" Performs matrix multiplication and returns the matrix product, which is matrix of matchign size and type. Operand sizes must match. e.g: @code{.c} mat4f a = 1, b = 2; mat4f c = a * b; @endcode is equal to: @code{.c} mat4f a = 1, b = 2; mat4f c; for(int i = 0; i < 4; ++i) { for(int j = 0; j < 4; ++j) { for(int k = 0; k < 4; ++k) { c[i,j] += a[i,k] * b[k,j]; } } } @endcode
@note Floating point multiplication is communicative (`a * b = b * a`) but is not @b necessarily associative. i.e. `(a * b) * c` is not necessarily equal to `a * (b * c)`. @anchor axbinbitwiseop @par Bitwise operands Binary bitwise operations have the following forms: @par
@a `lhs` @b `&` @a `rhs`
@a `lhs` `|` @a `rhs`
@a `lhs` @b `^` @a `rhs`
@a `lhs` @b `<<` @a `rhs`
@a `lhs` @b `>>` @a `rhs`
@par These operations only run on @b integral operands. After @ref axtypeprecedence "implicit conversion", the result of the binary operation: - with the @b `&` (@ref axtokens "ampersand token") is the result of the logical AND operation on each pair of the corresponding bits of the input operands. - with the `|` (@ref axtokens "pipe token") is the result of the logical OR operation on each pair of the corresponding bits of the input operands. - with the @b `^` (@ref axtokens "hat token") is the result of the logical XOR operation on each pair of the corresponding bits of the input operands. - with the @b `<<` (@ref axtokens "less than tokens") is the value shifted left with zeros shifted in on the right. - with the @b `>>` (@ref axtokens "greater than tokens") is the value shifted right with zeros shifted in on the left. @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "intergral" `& | ^ << >>` @ref axscalars "intergral" Returns the result of the bitwise operation as described above. If either operand is not an integral type (`bool` `int32` or `int64`), the program is ill formed.
@subsubsection axopcomparison Comparisons / Relational @par Binary comparison and relational operations compute the result of a equality operand token on two inputs and returns the result. The inputs are not modified, however may be copied and @ref axtypeprecedence "implicitly cast" to temporary values if the types do not match. The result type of all comparison operators is of type @b `bool`. Binary comparison operations have the following forms: @par
Operator NameOperator SyntaxReturns
Equal to @a `lhs` `==` @a `rhs` Returns `true` if both operands are equal
Not equal to @a `lhs` `!=` @a `rhs` Returns `true` if operands are not equal
Less than @a `lhs` `<` @a `rhs` Returns `true` the left hand side value is less than the right hand side
Greater than @a `lhs` `>` @a `rhs` Returns `true` the left hand side value is greater than the right hand side
Less than or equal to @a `lhs` `<=` @a `rhs` Returns `true` the left hand side value is less than or equal to the right hand side
Greater than or equal to @a `lhs` `>=` @a `rhs` Returns `true` the left hand side value is greater than or equal to the right hand side
@par The following combination of AX type categories are supported for comparison operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`== != < > <= >=`@ref axscalars "scalar" Returns the result of the scalar comparison.
`== !=` @ref axvecmats "vector" Performs per component comparisons (after @ref axtypeprecedence "implicit conversion") with the lefthand side scalar to every element of the right hand side vector or matrix and perform a logical AND combination on the results of these comparisons. This effectively returns true if every element of the vector or matrix is equal to the scalar. @code{.c} vec3f a = 2.0f; int b = 1; bool c = b == a; @endcode is equal to: @code{.c} vec3f a = 2.0f; int b = 1; bool c = a[0] == b; for (int i = 1; i < 3; ++i) c &= a[i] == b; @endcode
@ref axvecmats "matrix"
@ref axvecmats "vector" `== != < > <= >=` @ref axscalars "scalar" Same as `scalar op vector`
`== !=` @ref axvecmats "vector" Performs binary comparison operations (after @ref axtypeprecedence "implicit conversion") on each pair corresponding components in the vector operands and returns true if all component pairs are equal. Operand sizes must match. @code{.c} vec3f a = 1, b = 2; bool c = a == b; @endcode is equal to: @code{.c} vec3f a = 1, b = 2; bool c = a[0] == b[0]; for (int i = 1; i < 3; ++i) c &= a[i] == b[i]; @endcode
@ref axvecmats "matrix" `== != < > <= >=` @ref axscalars "scalar" Same as `scalar op matrix`
`== !=` @ref axvecmats "matrix" Performs binary comparison operations (after @ref axtypeprecedence "implicit conversion") on each pair corresponding components in the matrix operands and returns true if all component pairs are equal. Operand sizes must match. @code{.c} mat4f a = 1, b = 2; bool c = a == b; @endcode is equal to: @code{.c} mat4f a = 1, b = 2; bool c = a[0] == b[0]; for (int i = 1; i < 16; ++i) c &= a[i] == b[i]; @endcode
@subsubsection axopbinlogical Logical @par Binary logical operations compute and return the result of a boolean operation on two operands. Both operands are implicitly converted to @b `bool` types if they are not already. @warning These operators are short-circuiting; for logical AND, the second operand is only evaluated if the first is @b true. For logical OR, the second operand is only evaluated if the first is @b false. In both cases, the first operand is always evaluated. @par They have the following forms: @par
Operator NameOperator SyntaxReturns
AND @a `lhs` `&&` @a `rhs` Returns true if both operands are true. Otherwise, the result is false. This operator is short-circuiting.
Inclusive OR @a `lhs` `||` @a `rhs` Returns true if either the first or the second operand is true. This operator is short-circuiting.
@par The following combination of AX type categories are supported for comparison operations (if an operation is not listed, it is not supported): @par
Left Operand TypeBinary Op(s)Right Operand TypeDescription
@ref axscalars "scalar"`&& ||`@ref axscalars "scalar" Returns the result of the scalar logical operation. Both scalars are converted to bools if they are not already.
@subsection axopunary Unary Operators @par Unary operators only execute on a single value. The operator token(s) may come before or after the value, precedence of which is defined by AX's @ref axopprecedence "operator precedence". Arithmetic, logical and increment / decrement operators are supported. @subsubsection axopunarithmetic Arithmetic @par Arithmetic unary operators are comprised of arithemtic and bitwise operators. @par
Operator NameOperator SyntaxReturns
Unary plus `+`@a `a` Returns the value of its operand, @b `a`
Unary minus `-`@a `a` Returns the negative representation of @b `a`
Bitwise NOT `~`@a `a` Returns the bitwise NOT (one's complement) value of @b `a`. This operator is only valid on integral element types.
@par The following combination of AX type categories are supported for unary arithmetic operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar"`+ - ~` Returns the result of the scalar unary operations.
@ref axvecmats "vector" Performs per component unary operations, returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2; vec3f b = -a; @endcode is equal to: @code{.c} vec3f a = 2; vec3f b; for (int i = 0; i < 3; ++i) b[i] = -a[i]; @endcode @b Note: The bitwise not `~` operator is only valid on integer vector types; `vec2i`, `vec3i` and `vec4i`.
@ref axvecmats "matrix"`+ -` Performs per component unary operations, returning a new matrix with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3f a = 2; vec3f b = -a; @endcode is equal to: @code{.c} vec3f a = 2; vec3f b; for (int i = 0; i < 3; ++i) b[i] = -a[i]; @endcode
@subsubsection axopunlogical Logical @par Logical unary operators consist of a single operand. @par
Operator NameOperator SyntaxReturns
Logical NOT `!`@a `a` Returns true if the operand is false. Otherwise, returns false.
@par The following combination of AX type categories are supported for logical unary operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar"`!` Returns the result of the scalar logical operation. The scalar operand is converted to a bool if it is not already.
@ref axvecmats "vector" Performs per component unary operations, returning a new vector with each element holding the corresponding result. Operand sizes must match. @code{.c} vec3i a = 2; vec3i b = !a; @endcode is equal to: @code{.c} vec3i a = 2; vec3i b; for (int i = 0; i < 3; ++i) b[i] = !a[i]; @endcode @b Note: The logical not `!` operator is only valid on integer vector types; `vec2i`, `vec3i` and `vec4i`.
@subsubsection axopunincdec Increment / Decrement @par Increment/decrement operators increment or decrement the value of a scalar, or each component of a vector or matrix. They have the following forms: @par
Operator NameOperator SyntaxReturns
Pre-increment `++`@a `a` Returns a reference to the incremented result.
Post-increment@a `a``++` Returns a copy of the incremented result.
Pre-decrement `--`@a `a` Returns a reference to the decremented result.
Post-decrement @a `a``--` Returns a copy of the decremented result.
@par Importantly, pre evaluation returns a reference to the value operand, where as post evaluation returns a copy of the operand. The following combination of AX type categories are supported for logical unary operations (if an operation is not listed, it is not supported): @par
Operand TypeBinary Op(s)Description
@ref axscalars "scalar" `++(pre) (post)++`
`--(pre) (post)--`
Returns the result (reference or copy) of the scalar increment or decrement operation.\n @b Note: boolean incrementation and decrementation is not supported. Only `int32`, `int64`, `float` and `double` types are valid.
@subsection axopaccess Container Access @par Container access operators are valid on AX Vector and matrix types. They have the following forms: @par
Operator NameOperator SyntaxReturns
Dot Component Access `vector` . @a `component` Reference to component @a `component` of @a `vector`
Container Component Access `container` [ @a `exp` ] Reference to component at index @a `exp` of @a `container`
Matrix Component Access `matrix` [ @a `exp1`, `exp2` ] Reference to component in row `exp1`, column `exp2`. Also equal to returning a reference to component at index: `[exp1 * dimension + exp2]` of @a `matrix` where @a `dimension` is the the size of the matrix
@par As data is stored contiguously for both vectors and matrices, the `[]` operator is valid for both types. However the . operator is only valid on vector types, and the `[,]` operator is only valid on matrix types. As return values for these operators are references, any modifications through @ref axopassignment "assignments" will update the stored value in the container. @par . operator The dot operator . is only valid for vector types. It has the form: @par
@a `vector` . @a `component`
@par Where component is one of the below supported component letters. It only provides access for the first three elements of any vector (for @b `vec2` types, only the first 2 components are accessible). Accessing a vector using the dot operator is fundamentally the same as using the `[]` operator with the corresponding integer index. @par @code{.c} vec4i a = { 6, 7, 8, 9 }; int b = a.z; // get the the third elements value (8) @endcode
@f[ A=\begin{bmatrix} a_{0}\quad a_{1}\quad a_{2} \end{bmatrix} @f] | Component | Access Index | Result | |:-----------:|:--------------:|:-------------:| | @b `A.x` | 0 | @f$ a_{0} @f$ | | @b `A.r` | 0 | @f$ a_{0} @f$ | | @b `A.y` | 1 | @f$ a_{1} @f$ | | @b `A.g` | 1 | @f$ a_{1} @f$ | | @b `A.z` | 2 | @f$ a_{2} @f$ | | @b `A.b` | 2 | @f$ a_{2} @f$ |
@par This operator can provide more immediately readability when working with expressions that focus on colour or Cartesian coordinate systems. @anchor axvecaccessop @par [] operator The `[]` operator is valid for both vectors and matrices. It has the form: @par
@a `container` [`exp`]
@par @a `exp` is expected to evaluate to a value which is castable to an integer following the @ref axopassignment "assignment casting" rules and falls within the valid size of the @a `container`. No bounds checking is performed. @par As matrices are also an array of contigous values, they can be accessed in the same way. This can make some operations much simplier; a typical example being iterating through all matrix elements and performing some logic: @par @code{.c} vec3f a = 0; a[0] = 1; // valid a[""] = 1; // invalid - can't cast to int a[1.2f] = 1; // valid - float exp will be clamped to an int a[a[0]] = 1; // valid - use the value of a[0] to index into a // assign each element its actual index value i.e. b[5] = 5; mat4d b; for (int i = 0; i < 16; ++i) b[i] = i; @endcode @anchor axmataccessop @par [,] operator The `[,]` operator is only valid for matrices. It has the form: @par
@a `matrix` [`exp1`, `exp2`]
@par @a `exp1` and @a `exp2` are expected to evaluate to a value which is castable to an integer following the @ref axopassignment "assignment casting" rules and falls within the valid size of the @a `matrix` dimensions. No bounds checking is performed. In general it is more readable to use this operator when accessing specific elements, where @b `exp1` is the row index and @b `exp2` is the column index. The tables below show the different access patterns for @b `3x3` and @b `4x4` matrices. @par @code{.c} mat3f a; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) a[i,j] = i*j; // assign matrix element the product of its index @endcode @par
@f[ A=\begin{bmatrix} a_{00}\quad a_{01}\quad a_{02}\\ a_{10}\quad a_{11}\quad a_{12}\\ a_{20}\quad a_{21}\quad a_{22}\\ \end{bmatrix} @f] @f[ A=\begin{bmatrix} a_{00}\quad a_{01}\quad a_{02}\quad a_{03}\\ a_{10}\quad a_{11}\quad a_{12}\quad a_{13}\\ a_{20}\quad a_{21}\quad a_{22}\quad a_{23}\\ a_{30}\quad a_{31}\quad a_{32}\quad a_{33}\\ \end{bmatrix} @f]
Access [a] Access [a,b] Result Access [a] Access [a,b] Result
A[0] A[0,0] @f$ a_{00} @f$ A[0] A[0,0] @f$ a_{00} @f$
A[1] A[0,1] @f$ a_{01} @f$ A[1] A[0,1] @f$ a_{01} @f$
A[2] A[0,2] @f$ a_{02} @f$ A[2] A[0,2] @f$ a_{02} @f$
A[3] A[1,0] @f$ a_{10} @f$ A[3] A[0,3] @f$ a_{03} @f$
A[4] A[1,1] @f$ a_{10} @f$ A[4] A[1,0] @f$ a_{10} @f$
A[5] A[1,2] @f$ a_{12} @f$ A[5] A[1,1] @f$ a_{11} @f$
A[6] A[2,0] @f$ a_{20} @f$ A[6] A[1,2] @f$ a_{12} @f$
A[7] A[2,1] @f$ a_{21} @f$ A[7] A[1,3] @f$ a_{13} @f$
A[8] A[2,2] @f$ a_{22} @f$ A[8] A[2,0] @f$ a_{20} @f$
A[9] A[2,1] @f$ a_{21} @f$
A[10] A[2,2] @f$ a_{22} @f$
A[11] A[2,3] @f$ a_{23} @f$
A[12] A[3,0] @f$ a_{30} @f$
A[13] A[3,1] @f$ a_{31} @f$
A[14] A[3,2] @f$ a_{32} @f$
A[15] A[3,3] @f$ a_{33} @f$
@subsection axopother Other @par A number of uncategorised operators that are more general are documented in this section. They have the following forms: @par
Operator NameOperator SyntaxReturns
Call / Explicit Cast `a``(...)` Returns the result of a function call or inbuilt explicit cast
Comma `a`,  `b` Returns the value of @b `b` after chained evaluation
Ternary Conditional `a` `?` `b` `:``c` @b `b` if @b `a` is @b true, @b `c` otherwise.
Vector/Matrix Initializer `{`  `a,  ` `b  ``... }` Returns a temporary vector or matrix
@par Call / Explicit Cast The function call operator provides the ability to invoke functions @b or invoke a supported explicit cast. It has the form: @par
`func(a, b, c, ...)`
@par Where @b `func` is a function name @b or a valid explicit cast typename. Explicit casts are only supported for @ref axscalars "scalar types". For example: @code{.c} int a = int(1.1f); vec3f b = 1.0f; a = int(b.x); @endcode @par Whilst explicit casts take only a single argument, the operator itself supports multiple or empty arguments for function calls. Whe multiple arguments are provided, they are parsed from first to last and processed in reverse order. @b However, the order of runtime evaluation is @b unspecified i.e. they may evaluate in any order. Each function parameter is initialized with its corresponding argument after following implicit conversion of assignments where necessary. @par See the @ref axfunctions "function documentation" for more information on functions. @par Comma The Comma operator has the form: @par
`a``,` `b`
@par Where @b `a` and @b `b` are expressions. Chained expressions evaluate each expression in syntactical order (first to last), discarding any return value except for the last expression, which is returned from the entire list. Note that although return values for any expression but the last are discarded, their side effects are still applied before subsequent expression are evaluated. For example: @code{.c} int a = 5; a-=1, a+=2; // a = 6 a = a--, ++a; // exp1: a = a--, exp2: ++a. a = 7 @endcode @note Although you may consider the comma operator as a type of binary operator, it is fundamentally different as the types either side of the operator do @b not interact. Each expression in the comma operator is evaluated independently of all other expressions. @anchor axopternary @par Ternary Conditional The ternary conditional operator can be thought of as an in-line @ref axbranching "if-else statement" that returns a value, where each of the if/else branches has a single expression that will be returned. It has the form: @par
`a` `?` `b` `:``c`
Where @b `a` is the condition, evaluated and converted to @b bool, and @b `b` and @b `c` are expressions of the same or implicit-castable types. @b `b` is evaluated and returned if the condition is @b true, @b `c` is evaluated and returned if the condition is @b false. Only the expression out of @b `b` and @b `c` that is returned will be evaluated. Expressions with no return value (a.k.a @b `void`) are supported as long as @b `b` and @b `c` are both of this type. @par Also supported is the 'Elvis' operator, `a` `?` `:` `c` (or `?:`). Here, @b `a` is evaluated once, and if when converted to @b bool is @b true, @b `a` is returned, otherwise @b `c` is evaluated and returned. In this case, @b `a` and @b `c` must be the same or implicit-castable types, and both implicit-castable to @b bool. @anchor axvecmatinit @par Vector/Matrix Initializer @ref axvecmats "Vectors and matrices" can be represented as local variables (e.g. @b `vec3f`), external attributes or parameters (e.g. @b `vec3f\@attrib`) or as temporary values using the vector/matrix initializer syntax. This operator has the form: @par
`{`  `a,  b  ``... }`
@par Where @b `a` and @b `b` are expressions returning a scalar value. When this operator is invoked with a specific number of arguments, a vector or matrix is implicitly created with a copy of those arguments which can be assigned to an existing container of matching size. Expression in the operator are evaluated from first to last. This operator is only valid with argument lists of sizes 2, 3, 4, 9 and 16, which implicitly represent vec2, vec3, vec4, mat3, and @b mat4 types respectively. For example: @code{.c} vec3f a = { 1.0f, 2.0f, 3.0f }; // right hand side of assignment creates a vec3f vec3f b = dot(a, { a[0], 5.0, 6.0 }); // second argument creates a vec3d @endcode @note In the above examples, the value of `a[0]` is copied into the initializer operator. @par Initialization Type A mixture of arbitrary scalar types can be used in the initializer operator e.g: @code{.c} mat3f a = { true, 0s, 0, 0l, 0.0f, 0.0, false, 1, 2 }; @endcode @par The temporary container evaluates all expressions and uses the @b highest ranking type (as defined by @ref axtypeprecedence "arithmetic type precedence") to infer the element type of the container, implicitly casting all other types to that type where necessary. In the above example, the temporary created forms a @b `mat3d`, before being implicitly cast to a @b `mat3f` due to the assignment. @subsection axopprecedence Operator Precedence @par The below table shows the precedence and associativity of all AX operators. Operators are listed in descending precedence. @par
Precedence Operator Description Associativity
1 () Parenthesis Left-to-right
2 a++ a\-\- Suffix/postfix @ref axopunincdec
type() @ref axopother "Functional cast"
a() @ref axopother "Function call"
a[] . @ref axopaccess
3 ++a \-\-a Prefix @ref axopunincdec Right-to-left
+a -a Unary @ref axopbinarithmetic "plus and minus"
! ~ @ref axopbinlogical NOT and @ref axopunlogical NOT
4 a*b a/b a%b @ref axopbinarithmetic "Multiplication, division, and remainder" Left-to-right
5 a+b a−b @ref axopbinarithmetic "Addition and subtraction"
6 << >> @ref axopbinarithmetic "Bitwise left shift and right shift"
7 < <= For @ref axopcomparison operators < and ≤ respectively
> >= For @ref axopcomparison operators > and ≥ respectively
8 == != For @ref axopcomparison operators = and ≠ respectively
9 & @ref axopbinarithmetic AND
10 ^ @ref axopbinarithmetic XOR (exclusive or)
11 | @ref axopbinarithmetic OR (inclusive or)
12 && @ref axopbinlogical AND
13 || @ref axopbinlogical OR
14 a?b:c @ref axopternary "Ternary operator" Right-to-left
= @ref axopassignment "Direct assignment"
+= -= @ref axopassignment "Compound assignment" by sum and difference
*= /= %= @ref axopassignment "Compound assignment" by product, quotient, and remainder
<<= >>= @ref axopassignment "Compound assignment" by bitwise left shift and right shift
&= ^= |= @ref axopassignment "Compound assignment" by bitwise AND, XOR, and OR
15 , @ref axopother "Comma" Left-to-right
@par Note that associativity of unary operators is redundant (unary prefix operators are always right-to-left and unary postfix operators are always left-to-right). Operators that have the same precedence are bound to their arguments in the direction of their associativity. For example, the expression `a = b = c` is parsed as `a = (b = c)`, and not as `(a = b) = c` because of right-to-left associativity of assignment, but `a + b − c` is parsed `(a + b) − c` and not `a + (b − c)` because of left-to-right associativity of addition and subtraction. @b Note that this is based off the C++ operator precedence.

@section axtokens Tokens @subsection axvaridentifiers Variable Identifiers @subsection axliterals Literals @par Literals can be thought of as constant values that are known at compile time. e.g. @code i@a = 1; // the number 1 is a literal @endcode As AX supports different bit width scalar literals, it also supports suffix literal tokens which, when using with a scalar literal, represent a literal of a specific size. AX also supports implicit casting for all @ref axopassignment "assignment" and @ref axopbinarithmetic "arithmetic" operations, so any literal can be used to assign any scalar a value. @par
TypeLiteral Tokens
`bool`Tokens @b `true` and @b `false`
`int32`No suffix, automatically infered from integral literals
`int64`The letter @b `l` e.g. @code int64 a = 10l; @endcode
`float`The letter @b `f` e.g. @code float a = 0.0f; @endcode
`double`No suffix, automatically infered from floating point literals.
`string`Character strings wrapped in double quotes @b \" @b \"
@par @subsection axcomments Comments @subsection axkeywords Keywords @subsection axreserved Reserved Keywords

@section axsyntax Syntax @subsection axattribaccess Attribute Access @code{.c} float@surface = float@density; @endcode @par Assignment operations determine which volumes will be executed over. Here, the AX program will only execute on the @b surface VDB whilst retaining access to all available VDBs. There exists a number of possible states of both the @b surface and @b density volumes. - Volumes have the same transform and the same topology - Volumes have the same transform, but different topologies - Volumes have different transforms, but the same topology - Volumes have different transforms and different topologies @par Matching Transforms In the simplest case, all volumes processed have the same transform. Active voxels in the @b surface VDB will receive a value sampled (@ref axattribaccess "point sampled") at the corresponding @b index space position in the @b density VDB. As the transforms match, this is guaranteed to be at the same @b world space position. The topology of the @b density VDB does not influence which values are assigned, AX simply queries the @b density VDB at the computed position and uses whatever value is returned. This may be the VDB @b Background value. @par Different Transforms When transforms differ, AX performs coordinate transformations from the source VDB to the target VDB. Using some simple pseudo code, we can represent each voxel's coordinate query: @code{.unparsed} foreach(ActiveVoxel in surface) SurfaceIndexSpaceCoord = ActiveVoxel.indexSpaceCoordinate(); SurfaceWorldSpaceCoord = surface.transformToWorld(SurfaceIndexSpaceCoord); DensityIndexSpaceCoord = density.transformToIndex(SurfaceWorldSpaceCoord); ActiveVoxel = density.getValue(DensityIndexSpaceCoord); @endcode done() --> @subsection axexternalaccess External Parameter Access @subsection axdecls Declarations @subsection axscopes Scopes @subsection axbranching Branching (if / else) @subsection axloops Loops

@section axfunctions Functions @par For a list of all functions, see the @ref axfunctionlist "AX Function List". @par AX supports a variety of mathematical, string, utility and custom function calls which can be used from within an AX program. Native function support is constantly growing and we encourage users who wish to see particular methods exposed and supported natively by AX to contact us. Whilst we can't guarantee to accommodate every function, these requests provide the developers insights into how the language is being used. @par Function Execution Context Some functions depend on the currently processing @ref axexecutionxcontext to work correctly and will fail if called from an "invalid" context. Specifically, there exists functions which operate on OpenVDB points or OpenVDB volume grids and interact with the point or voxel data. Some of these methods are incompatible for the other grid type (for example, @ref axdeletepoint "deleting a point from a Point Data Grid") and will result in the compilation failure of an AX program if an attempt is made it use them. @subsection axuserfunctions User Functions @par User function declarations are not currently supported, but exist on the AX Roadmap as a near future feature.

@section axvexsupport AX VEX Support
*/ openvdb-13.0.0/doc/ax/axcplusplus.txt000066400000000000000000000551751510223237100175420ustar00rootroot00000000000000/**
@page axcplusplus OpenVDB AX @section axcdocs AX C++ Documentation @par The following documentation focuses on the C++ design and API of OpenVDB AX, @b not the front end AX language. For the latter, see the @ref ax "AX Language documentation". For more specific function API information, search for the relevant function doxygen. @note These documents are actively being worked on and are subject to change. See the API doxygen comments or contact us for more information. @section vdbaxcontents Contents - @ref vdbaxapiabi - @ref vdbaxrepo - @ref vdbaxgrammar - @ref vdbaxast - @ref vdbaxastscanners - @ref vdbaxcompilerpipe - @ref vdbaxcompilerlogging - @ref vdbaxcompilerexe - @ref vdbaxcompilercustomdata - @ref vdbaxcodegen - @ref vdbaxcompiler - @ref vdbaxbinary - @ref vdbaxtoaxtypes - @ref vdbaxextend
@section vdbaxapiabi Versioning, API and ABI @par AX is a self contained library which currently has a one way dependency on OpenVDB; any downstream artifact that uses AX will need to build and link against both OpenVDB and OpenVDB AX. There are a few important factors to be aware of with this integration: @par - OpenVDB AX is tied to the OpenVDB library version. There is no explicit OpenVDB AX version. This includes the OpenVDB namespaced API, the shared library version suffix on relevant platforms and the OpenVDB ABI. It *may* be possible to build OpenVDB AX against a different version of OpenVDB however this is not explicitly supported. - There are no ABI compatibility guarantees for OpenVDB AX components i.e. AX components do not support the transfer of themselves as binary representations across dynamic library boundaries to applications where AX has been compiled at a different location in the OpenVDB repository. Support for this may change in the future. @par In general, anything in the public namespace (defined as anything not labelled "internal") comes with standard API guarantees; that is, classes and methods will not change visible behaviour or signatures and deprecations will occur with appropriate replacements (where necessary) prior to removal. However, due to the nature of the project and its infancy, it's encouraged to continue reading below into the relevant AX components. These provide a better description of their intended public consumption and completeness.
@section vdbaxrepo OpenVDB AX Repository @par The AX repository has been laid out using a modular design. Each subdirectory encompasses a set of similar tools with a fairly consistent (one-way) dependency diagram to other tools in the repository. The following provides a short description of each directory, listed in this ad-hoc dependency order (from highest to lowest): @par - @b grammar: Provides the flex/bison lexer/grammar rules for generating the OpenVDB AX language, as well as the pre-generated `.c` files. - @b ast: The definition of an AX Abstract Syntax Tree, its node types and methods to work explicitly with them. - @b compiler: The frontend C++ user interface for building and using AX. - @b codegen: The backend LLVM IR code generation for AX. @par Additional tools include (in no particular order): @par - @b cmd: Command line binary tools for AX. - @b math: Various mathematical methods, typically used by the AX code generators when building native functions. - @b test: Unit testing framework for AX. @subsection vdbaxgrammar The Grammar @par The subdirectory @b grammar contains the rules used to generate an AX abstract syntax tree, as defined by the @ref ax "AX Language specification." These files do not provide an API per-se and are primarily used internally by the @b ast module. The grammar syntax rules are specified in files with .y suffix and the tokenziers are specified by the .l suffix. These files are designed to work with two UNIX tools, GNU Bison and Flex. Together these tools provide a workflow for developers to create develop a wide range of language parsers. It's encouraged to visit the corresponding manuals for more information on their use. @par The AX grammar is defined with a LR parser. In simplest terms, this means that the syntactical rules define a grammar which is parsed bottom-up, left-to-right, deterministically and context free (for the most part). These are fairly typical traits of parsers used to define computer languages. The parser is @b not designed to be interactive, nor reentrant (is not thread safe, each string is parsed sequentially) however such limitations are not imposed by AX and may be removed in the future. Note that the internal function symbols are correctly prefixed (with @b ax), so AX should be compatible with other software that also uses Bison/Flex. @par The .y and .l files are typically not part of the normal build process. Bison and Flex use them to generate compatible C/C++ code, however this code is always pre-generated and provided with the AX repository within the grammar/generated subdirectory. This C/C++ code is compiled into the AX library. Thus, the grammar is provided for two reasons; to demonstrate how the syntactical rules are implemented and to provide expert users the ability to regenerate the C/C++ bindings (see @ref build "the build instructions"). Importantly, AX does not install any of the files in the grammar folder; the parser is accessed through the @b ast module. @subsection vdbaxast The AST @par The @b ast module provides: - The complete implemenation of an @ref AST.h "AX abstract syntax tree" - The openvdb::ax::ast::parse() method - The @vdblink::ax::ast::Visitor AST Visitor@endlink - AST scanners and tools @par All methods in this module are designed to work around an AX AST, which represents the syntactical constructs of the AX language as a hierarchy of C++ objects (nodes). The complete AST hierarchy is visualized by the @vdblink::ax::ast::Node doxygen class graph for an openvdb::ax::ast::Node@endlink, which represents the top most node in the AST. The AST API exists in a nested namespace (`openvdb::ax::ast`) and can be used by clients for more granular control and modifications to an AST. Importantly, the AST API contains the openvdb::ax::ast::parse() method, which invokes the C/C++ functions built by the grammar to iteratively construct an AST from a provided character string. @par A number of other tools are provided by the module to work with an AST such as tools to re-interpret the AST back to AX compatible code, printing of the AST's node hierarchy/layout and scanners which are able to query details from AST branches. All these methods use the @vdblink::ax::ast::Visitor AX visitor framework@endlink, a visitor pattern traversal class strongly influenced by Clang's RecursiveVisitor. Clients can use the AX visitor to implement their own AST analysis or modifications (see @ref vdbaxextend). @subsubsection vdbaxastscanners Scanners @par todo @subsection vdbaxcompilerpipe The Compiler Pipeline @par The @b compiler subdirectory contains the bulk of the C++ API intended to be used directly by clients of OpenVDB AX. It links together the grammar, AST and code generation to produce AX executable objects, forming a pipeline from an initial string of AX code to final execution across some geometry. The following sections detail the core components to the Compiler pipeline. @subsubsection vdbaxcompilerlogging Logging @par Anyone familiar with programming languages will undoubtedly be aware of the huge variety and quantity of feedback that's presented to clients during use. This information, when properly presented, can be invaluable and help to advise users during their usage of the language. AX provides @vdblink::ax::Logger a Logger class@endlink which can be used throughout the Compiler pipeline to store and report this information. By default, this class reports all errors to std::cerr and swallows warnings, but can be customised depending on your needs e.g: @par @code{.cpp} #include // Create a logger which sends errors and warnings to std::cerr openvdb::ax::Logger logs([](const std::string& msg) { std::cerr << msg << std::endl; }, [](const std::string& msg) { std::cerr << msg << std::endl; }); logs.setMaxErrors(5); // stop reporting after 5 errors logs.setWarningsAsErrors(false); // don't count warnings as an error logs.setPrintLines(true); // print code lines logs.setNumberedOutput(true); // number each error/warning reported @endcode @par A @vdblink::ax::Logger Logger@endlink should be passed to the relevant pipeline methods as detailed in the following sections. @subsubsection vdbaxcompilerexe Executables @par The "executable" terminology comes from the binary representation of the compiled function which is invoked. AX executables essentially wrap the generated function calls from the AX codegen with an efficient multi-threaded invoke for the type of geometry being processed. The executable classes are designed to be lightweight to store, modify and copy with a consolidated interface for running and customising execution. @par There are two main types of executables; the @vdblink::ax::VolumeExecutable VolumeExecutable@endlink, designed to work with all OpenVDB Volumes and the @vdblink::ax::PointExecutable PointExecutable@endlink which works with OpenVDB `PointDataGrids`. They are not expected to be created directly; instead these objects are returned by the @vdblink::ax::Compiler AX Compiler@endlink depending on the selected @vdblink::ax::Compiler::compile() Compiler::compile() @endlink function. @note There is no inherent limitation to the design of the `VolumeExecutable` which stops it working on `PointDataGrids` but it's not particular useful in it's current form and can be confusing so it is explicitly disallowed. @par The executables are distinctly detached from the @vdblink::ax::Compiler Compiler@endlink once they have been built and can be safely used no matter previous or subsequent compilations of AX code. There are a variety of settings on the executables to control runtime behaviour - below demonstrates an example of using this API: @par @code{.cpp} using namespace openvdb; ax::Compiler compiler; // compiler FloatGrid a; a.setName("a"); a.tree().setValueOn({0,0,0}, 1.0f); // set single coordinate to active 1.0f const ax::VolumeExecutable::Ptr exe1 = compiler.compile("f@a += 1.0f;"); exe1->execute(a); // run over active leaf voxels in parallel ax::VolumeExecutable::Ptr exe2 = compiler.compile("f@a += 2.0f;"); // set to process all voxels exe2->setValueIterator(ax::VolumeExecutable::IterType::ALL); exe2->execute(a); // run over active and inactive leaf voxels in parallel std::cout << a.tree().getValue({0,0,0}) << std::endl; // prints 4.0f std::cout << a.tree().getValue({1,0,0}) << std::endl; // prints 2.0f @endcode @par Executable Thread Safety The executables are responsible for launching the compiled AX kernels and may internally use multiple threads. Multiple executables of any type can co-exist and be executed concurrently with unique arguments. For example: @par @code{.cpp} FloatGrid a1, a2; // assume both are named "a" auto exe1 = compiler.compile("f@a += 1.0f;"); auto exe2 = compiler.compile("f@a += 2.0f;"); std::thread t1([&]() { exe1->execute(a1); } ); std::thread t2([&]() { exe1->execute(a2); // safe even if exe1::execute is being used by another thread exe2->execute(a2); // safe, can be running alongside another executable }); @endcode @par This is, however, only safe depending on the access pattern of the AX code, the iteration patterns of the executables and the grid data being fed to the `execute` methods. When we talk about the thread safety of these classes we are referring to the invocation of their execution method with the same argument data by multiple threads, @b not how many threads the executables themselves use (which can be configured by the `grainSize()` setting). Importantly, for a given VDB grid or VDB Points attribute "foo": - For The @vdblink::ax::VolumeExecutable VolumeExecutable@endlink it is safe to call @vdblink::ax::VolumeExecutable VolumeExecutable::execute@endlink @b from multiple threads only if: - All relevant AX kernels do not write to grid @b foo. - For The @vdblink::ax::PointExecutable PointExecutable@endlink it is safe to call @vdblink::ax::PointExecutable PointExecutable::execute@endlink @b from multiple threads only if: - All relevant AX kernels do not write to attribute @b foo. - All relevant AX kernels do not create any attributes or groups. - All relevant AX kernels do not modify the @b position "P" attribute. @par For example: @par @code{.cpp} auto exe = compiler.compile("@a = @b"); // Grid a1 and a2 called "a", b called "b". Grid b is given to both threads. // This is safe as we guarantee b is only read from std::thread t1([&]() { GridPtrVec v{a1,b}; exe1->execute(v); } ); std::thread t2([&]() { GridPtrVec v{a2,b}; exe1->execute(v); } ); @endcode @par You can use the tools provided in @ref Scanners.h to query data accesses on AX ASTs to verify access patterns of your data. @subsubsection vdbaxcompilercustomdata Custom Data @par The AX language provides two main tokens to access memory which has not been allocated by AX itself. The first token, @b \@ (the "at" symbol), is designed to provide read/write access to geometry attributes. The second token is the dollar character @b $. This allows read only access to custom data that can be modified in C++ i.e. outside the scope of an AX program. In the same way as the @b \@attribute syntax, the value of this data can change without the need for AX to re-compile the program. It is, however, solely on the C++ clients of AX to make sure that this data is setup correctly when integrating AX into their applications. @par Consider this trivial example: @par @code{.c} f@density = f$my_value; // f$my_value = f@density; NOTE: writing to $ values is disallowed @endcode @par When compiled, this program will attempt to read a single float type value with the storage name "my_value". If the value cannot be found, a zero intialized block of memory (with size of the desired type) is returned. So, with no further setup, this will assign each value of @b density to 0.0f. @par The @vdblink::ax::CustomData CustomData@endlink class provides the intermediary storage for this data between the code generation and the compiler. Clients should use this API to create and modify custom data which will become available to AX programs. Although the data is stored as abstract openvdb::Metadata objects, the values are embedded into AX programs as pointers to their location in memory. In practice this means that accessing data stored in this way is almost as fast as accessing an AX local variable, though certain optimizations, such as constant folding, will not apply. As previously mentioned, this also means that the AX program does not need to be recompiled should this value need to be changed. @par The @vdblink::ax::CustomData CustomData@endlink starts off detached from an executable and thus must be provided when invoking @vdblink::ax::Compiler::compile Compiler::compile()@endlink. It is then tied to the AX executable for its duration. The compiler will validate the types of all accessed data of an AX program and, if it does not exist, the data will be created. Note that multiple executables can access the same @vdblink::ax::CustomData CustomData@endlink instance. @par @code{.cpp} using namespace openvdb; FloatGrid density; density.setName("density"); ax::Compiler compiler; // compiler ax::CustomData::Ptr data(new ax::CustomData); // empty custom data // data provided to compile is now registered with this exe. "m_value" is created ax::VolumeExecutable::Ptr exe = compiler.compile("f@density = f$my_value;", data); exe->execute(density); // my_value doesn't exist, density set to 0.0f // Compiler::compile will have created this assert(data->hasValue>("my_value")); // get the data in its typed storage wrapper TypedMetadata* meta = data->getValue>("my_value"); meta->set(1.0f); // set the value of "my_value" to 1.0f // don't need to re-compile exe->execute(density); // density set to 1.0f @endcode @warning Care should be taken to ensure that modifications to custom data values are peformed outside of any calls to `execute()`. Any attempt to modify the data whilst executables attempt to access it will result in undefined behaviour. @subsubsection vdbaxcodegen Codegen @par todo @subsubsection vdbaxcompiler The Compiler @par The @vdblink::ax::Compiler Compiler@endlink brings together the above components. It is responsible setting up LLVM contexts and modules for a given AX program, invoking the compute generators, binding custom data, performing any necessary AX and LLVM optimisations and finally JIT compiling the program to a callable function. The @vdblink::ax::Compiler::compile() Compiler::compile() @endlink member functions execute the aforementioned steps and, if successful, return a pointer to an executable. @par There are two main ways to invoke compilation; one with an @vdblink::ax::Logger AX Logger@endlink and one without. The prior will either return a valid pointer to a generated executable on success or a `nullptr` on failure. It is guaranteed to never throw a code generation runtime error and expects the caller to either query or setup the state of the logger to handle warnings and errors. The latter internally creates a default logger which swallows warnings and prints all possible errors to `std::cerr`. Note that the latter will throw a runtime error on failure and is thus guaranteed to never return a `nullptr`. @par @code{.cpp} using namespace openvdb; ax::Compiler compiler; std::vector warn, err; // custom logger to collect warnings and errors ax::Logger logger( [&warn]() { warn.emplace_back(msg); }, [&err]() { err.emplace_back(msg); } ); // logger provided, exe could be null if input is invalid auto exe = compiler.compile("f@a = 1.0f;", logger); // print warnings for (cosnt auto& msg : warn) std::cout << msg << std::endl; if (!exe) { for (cosnt auto& msg : err) std::cout << msg << std::endl; } // without logger, divison by zero warning won't be reported exe = compiler.compile("f@a = 1.0f / 0.0f;"); // without logger, invalid AX will cause a runtime error but // also print errors to std::cerr try { exe = compiler.compile("foo"); } catch (...) { std::cerr << "See above error logs..." << std::endl; } @endcode @warning A single instance of the @vdblink::ax::Compiler AX Compiler@endlink uses a uniquely constructed LLVMContext. This context is @b shared between copies of the Compiler, however new Compilers create new LLVMContexts. It is therefor unsafe to invoke concurrent calls to @vdblink::ax::Compiler::compile() Compiler::compile() @endlink on Compilers which share the same underlying LLVMContext. @par @code{.cpp} ax::Compiler C1, C2; // @warning Not safe! // std::thread t1([&]() { C1.compile("@a;") } ); // std::thread t2([&]() { C1.compile("@b;") } ); // the following is safe as C1 and C2 are unique instances std::thread t1([&]() { C1.compile("@a;") } ); std::thread t2([&]() { C2.compile("@a;") } ); @endcode @subsection vdbaxbinary The Command Line Binary @par todo
@section vdbaxtoaxtypes OpenVDB / OpenVDB AX Types @par Whilst OpenVDB AX is primarily designed for OpenVDB, it has its own notion of types. This is so that the actual AX language is able to support arithmetic that OpenVDB geometry would perhaps otherwise not support. For example, AX supports 3x3 and 4x4 matrix types. These types are akin to the `openvdb::math::Mat` types that exist in OpenVDB library - however, historically, these types are not "registered Grid types" by default by OpenVDB. This means that, although you could theoretically create an `openvdb::Mat3dGrid` OpenVDB may not support the reading or writing of these grid types out the box. Whilst this may change in the future, there may exist other examples of types in AX which suffer from the same limitation of existing geometry types in OpenVDB. @par Native OpenVDB types are types which are @b a) registered for serialization and @b b) compilable by the default C++ installation of OpenVDB. This is a bit convoluted, so what does this actually mean in practice? Generally, accessing an @b attribute in AX requires that data to exist on the underlying geometry. As such, reading or writing to a given attribute (for example `bool@myattr`) requires both the AX compiler @b and the underlying geometry to support the given type. As mentioned above, there may be times where this isn't the case. Consider the following: @par @code{.c} vec4i a = {1,2,3,4}; vec4i@attr = a; @endcode @par Now lets assume that a notion of four `int32` values is not supported for serialization of OpenVDB points or volumes (we assume the type can at least be instantiated). Whilst this code may execute, serializing this data to disk may fail due to unregistered OpenVDB types. AX does @b not register any additional OpenVDB types. This choice is left to downstream software. In this example, to allow for serialization of `vec4` types, some variant of the following can be implemented in your application. @warning The choice to register Grid types in OpenVDB is left to the OpenVDB maintainers. There are important consequences to registering custom types - other default installations of OpenVDB will not be able to read your files unless compiled with similar instantiations. @par @code{.cpp} openvdb::initialize(); // standard init of vdb openvdb::ax::initialize(); // standard init of ax // Define a Vec4I grid type from the openvdb::math::Vec4 class. // Use a ValueConverter to ensure the grid has the same configuration as // a standard OpenVDB grid type. using Vec4IGrid = openvdb::BoolGrid::ValueConverter::Type; // register this type Vec4IGrid::registerGrid(); @endcode
@section vdbaxextend Extending OpenVDB AX
*/ openvdb-13.0.0/doc/ax/axexamples.txt000066400000000000000000000223461510223237100173200ustar00rootroot00000000000000/**
@page axexamples AX Code Examples @section axexamplesintro AX Code Examples @par This page demonstrates a range of examples which use AX to manipulate OpenVDB point and volume data and can be used as a quick start demonstration on the capabilities of the software. These examples are constantly being updated but do not cover all aspects of AX! @section axexamplecontents Contents - @ref axexamplepoints - @ref axexamplepointbasic - @ref axexamplepointdelete - @ref axexamplepointdrag - @ref axexamplepointcurlnoise - @ref axexamplepointtransforms - @ref axexamplevolumes - @ref axexamplevolumeclamp - @ref axexamplevolumevel - @ref axexamplevolumeblend @section axexamplepoints Points Examples @par These examples demonstrate how to use AX on OpenVDB points grids. @subsection axexamplepointbasic Basic point attributes @par Below is a small example which demonstrates working with a few point attributes. The @ symbol is the identifier for an AX attribute. The type of each attribute is specified before the @ symbol and the name is specified afterwards. For example: @b `int\@count` would imply an @b integer attribute called @b count. @par In this example there are three point attributes: a @b float attribute @b speed, a @b vec3f float attribute @b velocity and a @b vec3f float attribute @b colour. @par This snippet uses the functions @ref axlength "length" and @ref axfit "fit" to give points a colour between black and white based on their speed. @par @code{.c} // This statement writes to a new float attribute called speed and reads from a // vector float attribute called velocity. The length function is used here to // return the length of the point's velocity vector. float@speed = length(vec3f@velocity); // Points that move faster than this threshold will all be mapped to the same // colour (white). float fast_threshold = 6.f; // Writing a single value to a vector will mean that all components of the // vector are assigned the same value. vec3f@colour = fit(float@speed, 0, fast_threshold, 0, 1); @endcode @par The @b velocity attribute in this example is assumed to exist and have a range of values to produce some visual variance in colour. The attributes @b speed and @b colour do not need to exist before this snippet is run as the attributes are only written to and will be created on the fly. @par @note In Houdini (AX SOP) changing the name of the attribute from @b colour to @b Cd will result in the points being given a colour in the viewport as Cd is a special attribute. @subsection axexamplepointdelete Deleting Points @par This example demonstrates a simple way of removing points from a VDB points grid. It uses a combination of @ref axrand and @ref axdeletepoint to randomly delete roughly half of the points in the input VDB points grid. @par @code{.c} float threshold = 0.5f; // The rand function takes a seed and produces a random value between 0 and 1. // The integer attribute id from the points is used to seed the rand function. // If the value from rand is greater than the threshold (0.5) then delete the point. if (rand(int64@id) > threshold) { deletepoint(); } @endcode @par The @b id attribute in this example is assumed to be a unique @b integer for each point in the VDB points grid such that @ref axrand will receive a different seed value per point producing a good distribution of random values. @subsection axexamplepointdrag Applying Drag @par This example shows something a bit more complex: modifying a point's velocity with a drag force and then moving the point with the modified velocity. @par @code{.c} float dt = 1.0f / (4.0f * 24.0f); // timestep vec3f gravity = {0.0f, -9.81f, 0.0f}; // gravity vec3f dV = {2.0f, 0.0f, 0.0f} - v@v; // drag float lengthV = length(dV); float Re = lengthV * @rad / 1.225f; float C = 0.0f; if (Re > 1000.0f) C = 24.0f / Re; else C = 0.424f; // calculate drag force vec3f drag = 0.5f * 1.2f * C * lengthV * dV * 4.0f * 3.14f * pow(@rad, 2.0f); // update velocity v@v += (gravity - drag / ((4.0f / 3.0f) * 3.14f * pow(@rad, 3.0f))) * dt; // update position v@P += v@v * dt; @endcode @par The final AX command, `v@P += v@v * dt;` writes to the position attribute of the points @b `v\@P`. Whenever position is written to in this way, the AX `PointExecutable` will move (re-bucket) points in PointDataGrids. @subsection axexamplepointcurlnoise Curl Noise @par The following example demonstrates using various native AX functions to calculate a position based curl noise on points in a particular group, and to use that calculation to update point velocities. @par @code{.c} // Only calcualte noise and apply it to points if the current point is NOT in // a group called "escaped". Note that the PointExecutable also has native // support for group based execution. if (!ingroup("escaped")) { // Read custom data float amplitude = $amplitude; float persistence = $persistence; float lacunarity = $lacunarity; vec3f freq = vec3f$frequency; vec3f offset = vec3f$offset; vec3f noise = 0.0f; // Position based curl simplex noise for (int octave = 0; octave < int($octaves); ++octave) { vec3f noisePos = vec3f@P * freq + offset; noise += curlsimplexnoise(noisePos) * amplitude; amplitude *= persistence; freq *= lacunarity; } // Apply noise scaled by the current velocity length vec3f@v += length(vec3f@v) * noise; } @endcode @subsection axexamplepointtransforms Transformations @par AX supports 3x3 and 4x4 matrix types and various transformations. They can be accessed via row, column operators or as a flat array and have defined operators (such as matrix multiplication etc.). The following demonstrates some trivial matrix math on VDB Point positions. @par @code{.c} // get the 4x4 identity matrix. note that scalar->matrix promotion handles // this, so writing 'mat4f transform = 1;' has the same effect. mat4f transform = identity4(); // set the X transform component transform[3,0] = 5; // pre scale the matrix. this is equal to writing: 'transform = scale * transform;' vec3f scale = { 1,2,3 }; prescale(transform, scale); // double the value of the scale Y component transform[5] *= 2; // construct a basic rotation matrix, representing 90 degree rotation around Y float degrees = 90.0f; float rad = radians(degrees); mat3f rotation = { cos(rad), 0.0f, -sin(rad), 0.0f, 1.0f, 0.0f, sin(rad), 0.0f, cos(rad) }; // apply the rotation and transformation to the current points position vec3f@P *= rotation; vec3f@P *= transform; @endcode

@section axexamplevolumes Volume Examples @par These examples demonstrate how to use AX on VDB volume grids. @subsection axexamplevolumeclamp Volume Clamping @par Below is a small example of reading adn writing to voxels within a VDB volume. As with points, the @ symbol specifies an access to a named volume, with the type of each volume preceding it and the name appearing as a suffix. For example: `float@density` would imply a @b float volume called @b density. @par This snippet uses @ref axclamp function to constrain the @b density attribute between zero and one. @par @code{.c} float@density = clamp(float@density, 0.f, 1.f); @endcode @subsection axexamplevolumevel Velocity Update @par AX can be used to read and write to multiple volumes. Here we have a typical example of a eulerian velocity update which takes into account an updated vector force and scalar mass. @par @code{.c} // Access the current timestep - this could instead be provided by the AX // integration and made accessible with custom data (i/e: float$timestep) float dt = 1.0f / 24.0f; // read from the mass grid the corresponding (matching index space) value float mass = float@mass; // safe divide, in case mass is zero float massInverse = 0.0f; if (mass > 0.0f) massInverse = 1.0f / mass; // update the current velocity value by scaling the corresponding force // by the timestep and inverse mass vec3f@vel += dt * massInverse * vec3f@force; @endcode @subsection axexamplevolumeblend Linear Blending @par Here we demonstrate how AX can be used to blend two volumes together. Note that only the volumes which are written to are executed over. In the below code, only @b `\@surface_a` is written to. This means that the final blended result, stored in `surface_a`, will only be updated in `surface_a`'s topology. Should we want a combined blend of @b non @b overlapping areas of both surface a and b, we would need to activate a's topology with respect to b first. @par @code{.c} // time constants for each run. float time = float$time; float maxDuration = 100.0f; // read both surface a and surface b values float a = @surface_a; // source value float b = @surface_b; // target value // calculate the fractional mask value in respect to time float mask = time / maxDuration; // optionally scale the mask by a per index space density. if // $enable_density_mask is true, a density grid is used to vary the blend per // voxel if ($enable_density_mask) mask *= @density; // finally, clamp the mask value and update the level set value in surface a. // Note that this may produce a no longer valid level set and might need to be // rebuilt! mask = clamp(mask, 0.0f, 1.0f); @surface_a = a + (b-a) * mask; @endcode
*/ openvdb-13.0.0/doc/ax/axfunctionlist.txt000066400000000000000000000516771510223237100202340ustar00rootroot00000000000000/**
@page axfunctionlist AX Supported Functions This page holds the full list of functions currently supported by AX. It is usually automatically updated from the most recent output of the @ref vdbaxbinary "vdb_ax binary's" function option. @section axfunccontents Functions
  • @ref axabs "abs"
  • @ref axacos "acos"
  • @ref axacosh "acosh"
  • @ref axaddtogroup "addtogroup"
  • @ref axadjoint "adjoint"
  • @ref axargsort "argsort"
  • @ref axasin "asin"
  • @ref axasinh "asinh"
  • @ref axatan "atan"
  • @ref axatan2 "atan2"
  • @ref axatanh "atanh"
  • @ref axatof "atof"
  • @ref axatoi "atoi"
  • @ref axcbrt "cbrt"
  • @ref axceil "ceil"
  • @ref axclamp "clamp"
  • @ref axcofactor "cofactor"
  • @ref axcos "cos"
  • @ref axcosh "cosh"
  • @ref axcross "cross"
  • @ref axcurlsimplexnoise "curlsimplexnoise"
  • @ref axdegrees "degrees"
  • @ref axdeletepoint "deletepoint"
  • @ref axdeterminant "determinant"
  • @ref axdiag "diag"
  • @ref axdot "dot"
  • @ref axeuclideanmod "euclideanmod"
  • @ref axexp "exp"
  • @ref axexp2 "exp2"
  • @ref axexternal "external"
  • @ref axexternalv "externalv"
  • @ref axfabs "fabs"
  • @ref axfit "fit"
  • @ref axfloor "floor"
  • @ref axfloormod "floormod"
  • @ref axgetcoordx "getcoordx"
  • @ref axgetcoordy "getcoordy"
  • @ref axgetcoordz "getcoordz"
  • @ref axgetvoxelpws "getvoxelpws"
  • @ref axhash "hash"
  • @ref axidentity3 "identity3"
  • @ref axidentity4 "identity4"
  • @ref axingroup "ingroup"
  • @ref axinverse "inverse"
  • @ref axisfinite "isfinite"
  • @ref axisinf "isinf"
  • @ref axisnan "isnan"
  • @ref axlength "length"
  • @ref axlengthsq "lengthsq"
  • @ref axlerp "lerp"
  • @ref axlog "log"
  • @ref axlog10 "log10"
  • @ref axlog2 "log2"
  • @ref axmax "max"
  • @ref axmin "min"
  • @ref axnormalize "normalize"
  • @ref axpolardecompose "polardecompose"
  • @ref axpostscale "postscale"
  • @ref axpow "pow"
  • @ref axprescale "prescale"
  • @ref axpretransform "pretransform"
  • @ref axprint "print"
  • @ref axradians "radians"
  • @ref axrand "rand"
  • @ref axrand32 "rand32"
  • @ref axremovefromgroup "removefromgroup"
  • @ref axround "round"
  • @ref axsign "sign"
  • @ref axsignbit "signbit"
  • @ref axsimplexnoise "simplexnoise"
  • @ref axsin "sin"
  • @ref axsinh "sinh"
  • @ref axsort "sort"
  • @ref axsqrt "sqrt"
  • @ref axtan "tan"
  • @ref axtanh "tanh"
  • @ref axtrace "trace"
  • @ref axtransform "transform"
  • @ref axtranspose "transpose"
  • @ref axtruncatemod "truncatemod"

@anchor axabs @par abs Computes the absolute value of an integer number. @code{.c} int64(int64 n); int32(int32 n); double(double n); float(float n); @endcode @anchor axacos @par acos Computes the principal value of the arc cosine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axacosh @par acosh Computes the inverse hyperbolic cosine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axaddtogroup @par addtogroup Add the current point to the given group name, effectively setting its membership to true. If the group does not exist, it is implicitly created. This function has no effect if the point already belongs to the given group. @code{.c} void(string); @endcode @anchor axadjoint @par adjoint Returns the adjoint of a 3x3 matrix. That is, the transpose of its cofactor matrix. @code{.c} mat3d(mat3d input); mat3f(mat3f input); @endcode @anchor axargsort @par argsort Returns a vector of the indexes that would sort the input vector. @code{.c} vec3i(vec3d v); vec3i(vec3f v); vec3i(vec3i v); vec4i(vec4d v); vec4i(vec4f v); vec4i(vec4i v); @endcode @anchor axasin @par asin Computes the principal value of the arc sine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axasinh @par asinh Computes the inverse hyperbolic sine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axatan @par atan Computes the principal value of the arc tangent of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axatan2 @par atan2 Computes the arc tangent of y/x using the signs of arguments to determine the correct quadrant. @code{.c} double(double y; double x); float(float y; float x); @endcode @anchor axatanh @par atanh Computes the inverse hyperbolic tangent of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axatof @par atof Parses the string input, interpreting its content as a floating point number and returns its value as a double. @code{.c} double(i8* str); @endcode @anchor axatoi @par atoi Parses the string input interpreting its content as an integral number, which is returned as a value of type int. @code{.c} int32(i8* str); @endcode @anchor axcbrt @par cbrt Computes the cubic root of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axceil @par ceil Computes the smallest integer value not less than arg. @code{.c} double(double n); float(float n); @endcode @anchor axclamp @par clamp Clamps the first argument to the minimum second argument value and maximum third argument value @code{.c} double(double in; double min; double max); float(float in; float min; float max); int64(int64 in; int64 min; int64 max); int32(int32 in; int32 min; int32 max); @endcode @anchor axcofactor @par cofactor Returns the cofactor matrix of a 3x3 matrix. That is, the matrix of its cofactors. @code{.c} mat3d(mat3d input); mat3f(mat3f input); @endcode @anchor axcos @par cos Computes the cosine of arg (measured in radians). @code{.c} double(double n); float(float n); @endcode @anchor axcosh @par cosh Computes the hyperbolic cosine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axcross @par cross Returns the length of the given vector @code{.c} vec3d(vec3d a; vec3d b); vec3f(vec3f a; vec3f b); vec3i(vec3i a; vec3i b); @endcode @anchor axcurlsimplexnoise @par curlsimplexnoise Generates divergence-free 3D noise, computed using a curl function on Simplex Noise. @code{.c} vec3d(vec3d pos); vec3d(double pos; double; double); @endcode @anchor axdegrees @par degrees Converts the number of radians to degrees. @code{.c} double(double radians); float(float radians); @endcode @anchor axdeletepoint @par deletepoint Delete the current point from the point set. Note that this does not stop AX execution - any additional AX commands will be executed on the point and it will remain accessible until the end of execution. @code{.c} void(); @endcode @anchor axdeterminant @par determinant Returns the determinant of a matrix. @code{.c} double(mat3d mat); float(mat3f mat); double(mat4d mat); float(mat4f mat); @endcode @anchor axdiag @par diag Create a diagonal matrix from a vector, or return the diagonal components of a matrix as a vector. @code{.c} vec3d(mat3d vec); vec3f(mat3f vec); vec4d(mat4d vec); vec4f(mat4f vec); mat3d(vec3d mat); mat3f(vec3f mat); mat4d(vec4d mat); mat4f(vec4f mat); @endcode @anchor axdot @par dot Computes the dot product of two vectors. @code{.c} double(vec3d a; vec3d b); float(vec3f a; vec3f b); int32(vec3i a; vec3i b); @endcode @anchor axeuclideanmod @par euclideanmod Euclidean modulo, where by the result of the division operator on (dividend / divisor) is floored or ceiled depending on its sign, guaranteeing that the return value is always positive. The remainder is thus calculated with D - d * (d < 0 ? ceil(D/d) : floor(D/d)). This is NOT equal to a%b in AX. See truncatemod(), floormod(). @code{.c} double(double dividend; double divisor); float(float dividend; float divisor); int64(int64 dividend; int64 divisor); int32(int32 dividend; int32 divisor); @endcode @anchor axexp @par exp Computes e (Euler's number, 2.7182818...) raised to the given power arg. @code{.c} double(double n); float(float n); @endcode @anchor axexp2 @par exp2 Computes 2 raised to the given power arg. @code{.c} double(double n); float(float n); @endcode @anchor axexternal @par external Find a custom user parameter with a given name of type 'float' in the Custom data provided to the AX compiler. If the data can not be found, or is not of the expected type 0.0f is returned. @code{.c} float(string str); @endcode @anchor axexternalv @par externalv Find a custom user parameter with a given name of type 'vector float' in the Custom data provided to the AX compiler. If the data can not be found, or is not of the expected type { 0.0f, 0.0f, 0.0f } is returned. @code{.c} vec3f(string str); @endcode @anchor axfabs @par fabs Computes the absolute value of a floating point value arg. @code{.c} double(double n); float(float n); @endcode @anchor axfit @par fit Fit the first argument to the output range by first clamping the value between the second and third input range arguments and then remapping the result to the output range fourth and fifth arguments @code{.c} double(double value; double omin; double omax; double nmin; double nmax); float(float value; float omin; float omax; float nmin; float nmax); double(int64 value; int64 omin; int64 omax; int64 nmin; int64 nmax); double(int32 value; int32 omin; int32 omax; int32 nmin; int32 nmax); @endcode @anchor axfloor @par floor Computes the largest integer value not greater than arg. @code{.c} double(double n); float(float n); @endcode @anchor axfloormod @par floormod Floored modulo, where the result of the division operator on (dividend / divisor) is floored. The remainder is thus calculated with D - d * floor(D/d). This is the implemented modulo % operator of AX. This is equal to the python % implementation. See trucnatemod(), euclideanmod(). @code{.c} double(double dividend; double divisor); float(float dividend; float divisor); int64(int64 dividend; int64 divisor); int32(int32 dividend; int32 divisor); @endcode @anchor axgetcoordx @par getcoordx Returns the current voxel's X index value in index space as an integer. @code{.c} int32(); @endcode @anchor axgetcoordy @par getcoordy Returns the current voxel's Y index value in index space as an integer. @code{.c} int32(); @endcode @anchor axgetcoordz @par getcoordz Returns the current voxel's Z index value in index space as an integer. @code{.c} int32(); @endcode @anchor axgetvoxelpws @par getvoxelpws Returns the current voxel's position in world space as a vector float. @code{.c} vec3f(); @endcode @anchor axhash @par hash Return a hash of the provided string. @code{.c} int64(string str); @endcode @anchor axidentity3 @par identity3 Returns the 3x3 identity matrix @code{.c} mat3f(); @endcode @anchor axidentity4 @par identity4 Returns the 4x4 identity matrix @code{.c} mat4f(); @endcode @anchor axingroup @par ingroup Return whether or not the current point is a member of the given group name. This returns false if the group does not exist. @code{.c} bool(string); @endcode @anchor axinverse @par inverse Return the inverse of a 3x3 matrix.If the matrix is singular, returns the input matrix. @code{.c} mat3d(mat3d input); mat3f(mat3f input); @endcode @anchor axisfinite @par isfinite Returns whether the value is finite i.e. not infinite or NaN. For matrix and vector types will return false if any element is not finite. @code{.c} bool(vec2d); bool(vec2f); bool(vec3d); bool(vec3f); bool(vec4d); bool(vec4f); bool(mat3f); bool(mat3d); bool(mat4f); bool(mat4d); bool(double arg); bool(float arg); @endcode @anchor axisinf @par isinf Returns whether the value is inf. For matrix and vector types will return true if any element is inf. @code{.c} bool(vec2d); bool(vec2f); bool(vec3d); bool(vec3f); bool(vec4d); bool(vec4f); bool(mat3f); bool(mat3d); bool(mat4f); bool(mat4d); bool(double arg); bool(float arg); @endcode @anchor axisnan @par isnan Returns whether the value is NaN (not-a-number). @code{.c} bool(vec2d); bool(vec2f); bool(vec3d); bool(vec3f); bool(vec4d); bool(vec4f); bool(mat3f); bool(mat3d); bool(mat4f); bool(mat4d); bool(double arg); bool(float arg); @endcode @anchor axlength @par length Returns the length of the given vector @code{.c} double(vec2d v); float(vec2f v); double(vec2i v); double(vec3d v); float(vec3f v); double(vec3i v); double(vec4d v); float(vec4f v); double(vec4i v); @endcode @anchor axlengthsq @par lengthsq Returns the squared length of the given vector @code{.c} double(vec2d v); float(vec2f v); int32(vec2i v); double(vec3d v); float(vec3f v); int32(vec3i v); double(vec4d v); float(vec4f v); int32(vec4i v); @endcode @anchor axlerp @par lerp Performs bilinear interpolation between the values. If the amount is outside the range 0 to 1, the values will be extrapolated linearly. If amount is 0, the first value is returned. If it is 1, the second value is returned. This implementation is guaranteed to be monotonic. @code{.c} double(double a; double b; double amount); float(float a; float b; float amount); @endcode @anchor axlog @par log Computes the natural (base e) logarithm of arg. @code{.c} double(double n); float(float n); @endcode @anchor axlog10 @par log10 Computes the common (base-10) logarithm of arg. @code{.c} double(double n); float(float n); @endcode @anchor axlog2 @par log2 Computes the binary (base-2) logarithm of arg. @code{.c} double(double n); float(float n); @endcode @anchor axmax @par max Returns the larger of the given values. @code{.c} double(double a; double b); float(float a; float b); int64(int64 a; int64 b); int32(int32 a; int32 b); @endcode @anchor axmin @par min Returns the smaller of the given values. @code{.c} double(double a; double b); float(float a; float b); int64(int64 a; int64 b); int32(int32 a; int32 b); @endcode @anchor axnormalize @par normalize Returns the normalized result of the given vector. @code{.c} vec3d(vec3d v); vec3f(vec3f v); vec3d(vec3i v); vec4d(vec4d v); vec4f(vec4f v); vec4d(vec4i v); @endcode @anchor axpolardecompose @par polardecompose Decompose an invertible 3x3 matrix into its orthogonal (unitary) matrix and symmetric matrix components. If the determinant of the unitary matrix is 1 it is a rotation, otherwise if it is -1 there is some part reflection. @code{.c} bool(mat3d input; mat3d unitary; mat3d symmetric); bool(mat3f input; mat3f unitary; mat3f symmetric); @endcode @anchor axpostscale @par postscale Post-scale a given matrix by the provided vector. @code{.c} void(mat4d transform; vec3d vec); void(mat4f transform; vec3f vec); @endcode @anchor axpow @par pow Computes the value of the first argument raised to the power of the second argument. @code{.c} double(double base; double exp); float(float base; float exp); double(double base; int32 exp); @endcode @anchor axprescale @par prescale Pre-scale a given matrix by the provided vector. @code{.c} void(mat4d transform; vec3d vec); void(mat4f transform; vec3f vec); @endcode @anchor axpretransform @par pretransform Return the transformed vector by transpose of this matrix. This function is equivalent to pre-multiplying the matrix. @code{.c} vec3d(mat3d vec; vec3d mat); vec3f(mat3f vec; vec3f mat); vec3d(mat4d vec; vec3d mat); vec3f(mat4f vec; vec3f mat); vec4d(mat4d vec; vec4d mat); vec4f(mat4f vec; vec4f mat); @endcode @anchor axprint @par print Prints the input to the standard output stream. Warning: This will be run for every element. @code{.c} void(double n); void(float n); void(int64 n); void(int32 n); void(string n); void(vec2i n); void(vec2f n); void(vec2d n); void(vec3i n); void(vec3f n); void(vec3d n); void(vec4i n); void(vec4f n); void(vec4d n); void(mat3f n); void(mat3d n); void(mat4f n); void(mat4d n); @endcode @anchor axradians @par radians Converts the number of degrees to radians. @code{.c} double(double degrees); float(float degrees); @endcode @anchor axrand @par rand Creates a random number based on the provided seed. The number will be in the range of 0 to 1. The same number is produced for the same seed. Note that if rand is called without a seed the previous state of the random number generator is advanced for the currently processing element. This state is determined by the last call to rand() with a given seed. If rand is not called with a seed, the generator advances continuously across different elements which can produce non-deterministic results. It is important that rand is always called with a seed at least once for deterministic results. @code{.c} double(); double(double seed); double(int64 seed); @endcode @anchor axrand32 @par rand32 Creates a random number based on the provided 32 bit seed. The number will be in the range of 0 to 1. The same number is produced for the same seed. NOTE: This function does not share the same random number generator as rand(). rand32() may provide a higher throughput on some architectures, but will produce different results to rand(). NOTE: If rand32 is called without a seed the previous state of the random number generator is advanced for the currently processing element. This state is determined by the last call to rand32() with a given seed. If rand32 is not called with a seed, the generator advances continuously across different elements which can produce non-deterministic results. It is important that rand32 is always called with a seed at least once for deterministic results. @code{.c} double(); double(double seed); double(int32 seed); @endcode @anchor axremovefromgroup @par removefromgroup Remove the current point from the given group name, effectively setting its membership to false. This function has no effect if the group does not exist. @code{.c} void(string); @endcode @anchor axround @par round Computes the nearest integer value to arg (in floating-point format), rounding halfway cases away from zero. @code{.c} double(double n); float(float n); @endcode @anchor axsign @par sign Implements signum, determining if the input is negative, zero or positive. Returns -1 for a negative number, 0 for the number zero, and +1 for a positive number. Note that this function does not check the sign of floating point +/-0.0 values. See signbit(). @code{.c} int32(double n); int32(float n); int32(int64 n); int32(int32 n); @endcode @anchor axsignbit @par signbit Determines if the given floating point number input is negative. Returns true if arg is negative, false otherwise. Will return true for -0.0, false for +0.0 @code{.c} bool(double n); bool(float n); @endcode @anchor axsimplexnoise @par simplexnoise Compute simplex noise at coordinates x, y and z. Coordinates which are not provided will be set to 0. @code{.c} double(double x); double(double x; double y); double(double x; double y; double z); double(vec3d pos); @endcode @anchor axsin @par sin Computes the sine of arg (measured in radians). @code{.c} double(double n); float(float n); @endcode @anchor axsinh @par sinh Computes the hyperbolic sine of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axsort @par sort Returns the sorted result of the given vector. @code{.c} vec3d(vec3d v); vec3f(vec3f v); vec3i(vec3i v); vec4d(vec4d v); vec4f(vec4f v); vec4i(vec4i v); @endcode @anchor axsqrt @par sqrt Computes the square root of arg. @code{.c} double(double n); float(float n); @endcode @anchor axtan @par tan Computes the tangent of arg (measured in radians). @code{.c} double(double n); float(float n); @endcode @anchor axtanh @par tanh Computes the hyperbolic tangent of the input. @code{.c} double(double arg); float(float arg); @endcode @anchor axtrace @par trace Return the trace of a matrix, the sum of the diagonal elements. @code{.c} double(mat3d mat); float(mat3f mat); double(mat4d mat); float(mat4f mat); @endcode @anchor axtransform @par transform Return the transformed vector by the provided matrix. This function is equivalent to post-multiplying the matrix, i.e. vec * mult. @code{.c} vec3d(vec3d vec; mat3d mat); vec3f(vec3f vec; mat3f mat); vec3d(vec3d vec; mat4d mat); vec3f(vec3f vec; mat4f mat); vec4d(vec4d vec; mat4d mat); vec4f(vec4f vec; mat4f mat); @endcode @anchor axtranspose @par transpose Returns the transpose of a matrix @code{.c} mat3d(mat3d mat); mat3f(mat3f mat); mat4d(mat4d mat); mat4f(mat4f mat); @endcode @anchor axtruncatemod @par truncatemod Truncated modulo, where the result of the division operator on (dividend / divisor) is truncated. The remainder is thus calculated with D - d * trunc(D/d). This is equal to the C/C++ % implementation. This is NOT equal to a%b in AX. See floormod(), euclideanmod(). @code{.c} double(double dividend; double divisor); float(float dividend; float divisor); int64(int64 dividend; int64 divisor); int32(int32 dividend; int32 divisor); @endcode
*/ openvdb-13.0.0/doc/ax/doc.txt000066400000000000000000000034741510223237100157170ustar00rootroot00000000000000/**
@page openvdbax OpenVDB AX @section axoverview Overview @par OpenVDB AX is an open source C++ library that provides a powerful and easy way of interacting with OpenVDB volume and point data. The software strives to provide a concise, fast, highly parallalisable and portable solution to performing custom manipulation of OpenVDB data via an expression language: AX. AX expressions are JIT-compiled and used in combination with a multi-threaded execution framework, specifically designed for VDB, that in many cases rival custom C++ operators. @b OpenVDB AX is maintained by the Academy Software Foundation (ASWF). It was originally developed at DNEG primarily by: - Nick Avramoussis - Richard Jones Other notable contributors include: - Francisco Gochez - Matthew Warner - Dan Bailey - Todd Keeler - James Bird - Harry Biddle @subsection docs Documentation @par The doxygen documentation provide information on both AX as a language and the developer documentation for OpenVDB AX as a C++ API. There are two main sections: @par - The @subpage ax "AX Language Documentation" provides useful information for front-end users looking for documentation on the AX Language. - The @subpage axcplusplus "OpenVDB AX Documentation" provides API and other C++ specific software information for developers. @par Some additional quick links to useful subsections of the documentation are also provided: @par - @subpage axexamples "Code Examples" for examples of OpenVDB AX in action. - @subpage axfunctionlist "AX Functions" for a list of all available AX functions. - @subpage build "Building OpenVDB" and @subpage dependencies "OpenVDB Dependencies" for information on building OpenVDB and OpenVDB AX.
*/ openvdb-13.0.0/doc/ax/gen_function_docs000077500000000000000000000042071510223237100200200ustar00rootroot00000000000000#!/bin/bash BINARY=$1 if [ -z $BINARY ]; then BINARY=vdb_ax fi echo $BINARY # Generates a doxygen function.txt file using the available vdb_ax binary # Add the doxygen header for the functions file echo -n "/**
@page axfunctionlist AX Supported Functions This page holds the full list of functions currently supported by AX. It is usually automatically updated from the most recent output of the @ref vdbaxbinary \"vdb_ax binary's\" function option. @section axfunccontents Functions
    " > functions.txt # 1) Create the contents list (reference links to each function) # Get all the function names $BINARY functions --list-names > tmp.txt # Remove commans tr -d , < tmp.txt > tmp2.txt # Add new lines between names tr ' ' '\n' < tmp2.txt > tmp.txt # Remove empty lines (created by the vdb_ax binary wrapping output) sed '/^$/d' tmp.txt > tmp2.txt # Append doxygen references to each funciton sed -e 's/^\(.*\)/\t
  • @ref ax\1 \"\1\"<\/li>/' tmp2.txt >> functions.txt # End the function list and add a line break echo -n "

" >> functions.txt # 2) Add all function descriptions and signatures from the binary # First add a new line - this is for the next sed call which looks for a new # line followed by the function name echo "" > tmp.txt $BINARY functions --list >> tmp.txt echo "" >> tmp.txt # look for functions such: # \n # functionname # | # and wrap the name in anchors and paragraphs sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n\([a-z0-9]\+\)\n|/\n@anchor ax\1\n@par \1/g' tmp.txt # Remove all "| -" which exist before the function help sed -i 's/| - //g' tmp.txt # Replace |\n with @code{.c} sed -i -e ':a' -e 'N' -e '$!ba' -e 's/|\n/@code{.c}\n/g' tmp.txt # Append semicolons to functions sed -i 's/| - \(.*\)/\1;/g' tmp.txt # Replace ;\n\n with ;\n:@endcode\n\n sed -i -e ':a' -e 'N' -e '$!ba' -e 's/;\n\n/;\n@endcode\n\n/g' tmp.txt # Remove left over pipes sed -i -e ':a' -e 'N' -e '$!ba' -e 's/| //g' tmp.txt # Combine cat tmp.txt >> functions.txt echo -n "
*/" >> functions.txt # cleanup rm tmp.txt tmp2.txt openvdb-13.0.0/doc/ax/gen_function_houdini_docs000077500000000000000000000051611510223237100215370ustar00rootroot00000000000000#!/bin/bash BINARY=$1 if [ -z $BINARY ]; then BINARY=vdb_ax fi # Generates a houdini html function file using the available vdb_ax binary # Add the header for the file echo -n " Function || Description || Signatures || " > functions.txt # Echo out the full descriptions echo "" > tmp.txt $BINARY functions --list >> tmp.txt echo "" >> tmp.txt # Get a list of names names=$($BINARY functions --list-names) names="${names//$'\n'/}" # For each line in the full function file, see which function we're processing # and update each signature with the function name found="" new_data="" while IFS= read -r line; do # Scan for a function switch for name in $names; do name="${name//$','/}" if [[ "$name" == "$line" ]]; then found=$name break fi done # If processing a function signature, add the function name if [[ $line == "| -"*"("* ]]; then line=$(sed 's/(/'" $found"'(/g' <<<"$line") fi new_data+=$line"\n" done < tmp.txt echo -e "$new_data" > tmp.txt # look for functions such: # \n # functionname # | # and wrap the name in code and format the end sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n\([a-z0-9]\+\)\n|/\n

\1<\/code><\/p> |/g' tmp.txt # # Remove all "| -" which exist before the function help sed -i 's/| - /\t/g' tmp.txt # Replace pipes with tabs sed -i -e ':a' -e 'N' -e '$!ba' -e 's/| /\t/g' tmp.txt # # # Replace |\n with " |\n" sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n|\n/ |\n/g' tmp.txt # # add usage sig sed -i 's/| - \(.*\)/\t\t

\1<\/code><\/div>/g' tmp.txt # Format parms sed -i 's/\(void\)/\1<\/span>/g' tmp.txt sed -i 's/\(bool\)/\1<\/span>/g' tmp.txt sed -i 's/\(int32\)/\1<\/span>/g' tmp.txt sed -i 's/\(int64\)/\1<\/span>/g' tmp.txt sed -i 's/\(float\)/\1<\/span>/g' tmp.txt sed -i 's/\(double\)/\1<\/span>/g' tmp.txt sed -i 's/\(string\)/\1<\/span>/g' tmp.txt sed -i 's/\(vec[234][ifd]\)/\1<\/span>/g' tmp.txt sed -i 's/\(mat[234][ifd]\)/\1<\/span>/g' tmp.txt sed -i 's/ \([a-z]\+\)(/ \1<\/span>(/g' tmp.txt # Combine cat tmp.txt >> functions.txt # cleanup rm tmp.txt openvdb-13.0.0/doc/build.txt000066400000000000000000001032401510223237100156310ustar00rootroot00000000000000/** @page build Building OpenVDB @section buildContents Contents - @ref buildIntroduction - @ref buildCmakeStructure - @ref buildDependencies - @ref buildMixingDepInstalls - @ref buildBloscSupport - @ref buildZLibSupport - @ref buildVCPKG - @ref buildComponents - @ref buildGuide - @ref buildBuildTypes - @ref buildBuildHouMaya - @ref buildBuildHou - @ref buildBuildMaya - @ref buildBuildStandalone - @ref buildUsingOpenVDB - @ref buildTroubleshooting ------------------------------------------------------------------------------ @section buildIntroduction Introduction [CMake](https://cmake.org/) is a cross-platform family of tools designed to help build software. CMake doesn't *actually* build the project but instead generates the files required for your toolchain, for example makefiles that serve as input to [GNU Make](https://www.gnu.org/software/make/). CMake support ensures a high level of flexibility and pre-compile verification to the build process, making it much easier to control and customize the installation process for a wider range of platforms. CMake also makes it easier to automatically find and handle dependencies. If you're completely new to CMake, you may find it useful to read over the brief [introduction to CMake](https://cmake.org/runningcmake/) and the CMake structure section below. However the [build guide](@ref buildGuide) runs through the build process step by step. @section buildCmakeStructure CMake Structure CMake will configure a set of build files which represent the commands and dependencies for the OpenVDB components you wish to install. Finding and handling these dependencies on different platforms comprises the majority of the complexity involved in writing CMake. In general, software which uses CMake is expected to provide their own configuration files which dependent software will locate and use. Not all of OpenVDB's dependencies provide CMake support and therefore do not deploy with CMake configurations that OpenVDB can use. OpenVDB provides a set of `FindModules` in the `cmake` folder for finding these various dependencies e.g. `FindBlosc.cmake`. These are designed such that they can theoretically be used by any project that needs to locate the given library and are invoked by the `find_package()` call. For more information on FindModules and locating packages with CMake, see the following CMake documentation: - [Using Packages with CMake](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#using-packages) - [Calling find_package()](https://cmake.org/cmake/help/latest/command/find_package.html) The other type of file provided by OpenVDB are `OpenVDBSetupX.cmake` includes. These are primarily designed to configure the building of OpenVDB components against supported DCC's (Houdini/Maya) by locating their installations and setting various CMake variables for subsequent `find_package()` dependency calls. They also represent packages which already provide their own CMake modules, but additionally provide the same input variable interface as OpenVDB's other `Find` Modules. @subsection buildDependencies Locating Dependencies Each CMake FindModule provides a description of the possible inputs which can be provided to help drive the search for OpenVDB dependencies (as well as the resulting outputs). They have been homogenized such that these variables follow a set convention, typically followed by most CMake projects. For a given FindModule e.g. `FindBlosc.cmake`: - FindXxx.cmake provides the module interface where Xxx becomes the library name - Invoked with the called `find_package( Xxx )` . - @b Inputs - The following variables can be used to help drive the search path on first runs of CMake (i.e. these variables are not [cached](https://cmake.org/cmake/help/latest/command/set.html#set-cache-entry)). They are listed in priority order. Note that the prefix is always capitalized. - @b Xxx_ROOT - Preferred installation prefix. The given dependency is expected to follow a folder structure `Xxx_ROOT/include` and `Xxx_ROOT/lib` exist. Note that unlike the above, this is the case matching name of the find package .i.e. Blosc_ROOT, TBB_ROOT etc. - @b XXX_INCLUDEDIR / @b XXX_LIBRARYDIR - Preferred include and library directories - @b SYSTEM_LIBRARY_PATHS - A list of paths appended to all include and lib searches. - @b XXX_USE_STATIC_LIBS - Only search for static libraries for the given dependency. If OFF, the shared library is prioritized, falling back to the static library. This is OFF by default. - @b DISABLE_CMAKE_SEARCH_PATHS - The above variables are custom to the OpenVDB project. CMake itself implements its own search system to try and find the given libraries and packages. When ON, this variable disables CMake's inbuilt search, guaranteeing that only the above user provided paths are searched. See [CMakes Search Procedure](https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure) for more information. This is OFF by default (and thus CMake's search is enabled). . - @b Outputs The following variables are always set if the project is found: - @b Xxx_FOUND - True if the headers and library was found and exists - @b Xxx_VERSION - The library version - @b Xxx_INCLUDE_DIRS - A list of paths to all required include directories - @b Xxx_RELEASSE_LIBRARY_DIRS - A list of paths to all required release library directories - @b Xxx_DEBUG_LIBRARY_DIRS - A list of paths to all required debug library directories - @b Xxx_RELEASE_LIBRARIES - A list of libraries needed to use the release version of Xxx - @b Xxx_DEBUG_LIBRARIES - A list of libraries needed to use the debug version of Xxx - Each module produces an [imported target](https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries) in the form @b Xxx::xxx, and may generate multiple imported targets if multiple components are found. @subsection buildMixingDepInstalls Mixing Dependency Installations There may be a situation where you use a package manager to install some dependencies, use a DCC such as Maya to provide others and manually build and install others from source. Care must be taken when providing CMake with these locations to ensure that the correct files are used. Incorrect use of the above variables can lead to difficult to diagnose build and runtime errors. As an example, let's assume we have a manual installation of TBB (either through a Maya installation or a manual installation from source) and we want to use this with other dependencies installed through a package manager such as homebrew. As homebrew copies all headers and libraries it installs to a `/include` `/lib` directory structure, it can be tempting to set @b Xxx_ROOT variables to points to the `` folder. However you may already have an existing installation of TBB through your package manager, potentially installed by as a dependency of a completely unrelated piece of software. Whilst CMake may report to you the correct include/lib path, this can end up being hidden at compile time through these types of shared installations. You should not rely on the dependency order of the CMake build system - instead, it's important that you try to use the explicit directory paths where possible. For example homebrew will install each piece of software to `/Cellar//`, where the subsequent include and library directories can be passed to @b XXX_INCLUDEDIR and @b XXX_LIBRARYDIR respectively. In summary try to stick to a single installation workflow and, if in doubt, provide direct include/lib paths to isolated software locations. @subsection buildBloscSupport Blosc Support Blosc is an optional dependency of all OpenVDB components. The documented build steps below treat blosc as a required dependency. There are two reasons for this: - Blosc produces significantly smaller `.vdb` files - If Blosc is disabled, you will not be able to read or use any `.vdb` files that were created using blosc compression. This includes OpenVDB files from Houdini. See the note in the [known issues list](@ref depKnownIssues) regarding supported versions of blosc. @subsection buildZLibSupport ZLIB Support ZLIB is an optional dependency of all OpenVDB components. The documented build steps below treat ZLib as a required dependency. You can disable ZLib using `-D USE_ZLIB=OFF` if Blosc is also disabled using `-D USE_BLOSC=OFF`. @subsection buildVCPKG Building Dependencies using VCPKG It is recommended to set the VCPKG_DEFAULT_TRIPLET=x64-windows environment variable to use 64-bit libraries by default as even on a 64-bit Windows OS, VCPKG builds and installs 32-bit libraries by default. @section buildComponents OpenVDB Components The following table lists all targets (mainly library and binary components) which can be built through the CMake build system. They can be set when using CMake from the command line with `-D VAR=ON/OFF` or with a CMake gui: Component | Description | CMake Variable | Default | ------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------- | ---------- | OpenVDB Core Library | The Core OpenVDB shared/static library | OPENVDB_BUILD_CORE | ON | OpenVDB Print | Command line binary for displaying information about OpenVDB files | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_PRINT | ON / ON | OpenVDB LOD | Command line binary for generating volume mipmaps from an OpenVDB grid | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_LOD | ON / OFF | OpenVDB Render | Command line binary for ray-tracing OpenVDB grids | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_RENDER | ON / OFF | OpenVDB View | Command line binary for displaying OpenVDB grids in a GL viewport | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_VIEW | ON / OFF | OpenVDB Python | Python module for OpenVDB C++ Python bindings | OPENVDB_BUILD_PYTHON_MODULE | OFF | OpenVDB UnitTests | OpenVDB's Unit Test suite | OPENVDB_BUILD_UNITTESTS | OFF | OpenVDB Houdini Plugin | The OpenVDB Houdini shared library and OpenVDB Nodes | OPENVDB_BUILD_HOUDINI_PLUGIN | OFF | OpenVDB Maya Plugin | The Maya OpenVDB Nodes | OPENVDB_BUILD_MAYA_PLUGIN | OFF | OpenVDB AX Library | The OpenVDB AX library | OPENVDB_BUILD_AX | OFF | OpenVDB AX Binary | Command line binary for running OpenVDB AX code | OPENVDB_BUILD_AX_BINARIES | OFF | OpenVDB AX Grammar | Allows for re-generation of AX grammar, typically not required | OPENVDB_BUILD_AX_GRAMMAR | OFF | OpenVDB AX Unit Tests | OpenVDB AX's Unit Test suite | OPENVDB_BUILD_AX_UNITTESTS | OFF | NanoVDB | NanoVDB headers | OPENVDB_BUILD_NANOVDB | OFF | NanoVDB Tools | NanoVDB command line tools | NANOVDB_BUILD_TOOLS | OFF | NanoVDB Examples | NanoVDB example binaries and benchmarks | NANOVDB_BUILD_EXAMPLES / NANOVDB_BUILD_BENCHMARK | OFF / OFF | NanoVDB Unit Tests | NanoVDB Unit Test suite | NANOVDB_BUILD_UNITTESTS | OFF | Documentation | The OpenVDB doxygen documentation | OPENVDB_BUILD_DOCS | OFF | @section buildGuide Building With CMake @subsection buildBuildTypes Build Types The first step is to decide what type of OpenVDB build you're after. This primarily boils down to three main options: - A standalone OpenVDB build (no Houdini/Maya plugins) - OpenVDB for [Houdini](https://www.sidefx.com/) - OpenVDB for [Maya](https://www.autodesk.co.uk/products/maya/overview) Each option provides various benefits. Apart from the support for either the Houdini or Maya OpenVDB plugins, the latter two options can make it easier for new users to install the range of OpenVDB dependencies without having to worry about using a package manager or manually installing for source. You'll still be able to build and use all components of OpenVDB with these methods. However depending on the DCC (Digital Content Creation) software's version, you may find that some features of the Core library are restricted to ensure compatibility. For more information of building OpenVDB against a Houdini or Maya installation, see [here](@ref buildBuildHouMaya). Developers may wish to build a standalone version of OpenVDB to take advantage of newer dependencies and newer library features. See [here](@ref buildBuildStandalone) for more information. @b Note: Blosc and ZLib are treated as required dependencies in these install instructions. See the [blosc support](@ref buildBloscSupport) and [zlib support](@ref buildZLibSupport) sections for more information. @subsection buildBuildHouMaya Building Against Houdini/Maya Building against a DCC reduces the list of dependencies you need to provide. You should not mix between Houdini and Maya libraries and should not attempt to build the Maya plugin using Houdini libraries and vice-versa. Additionally, it's a good idea to read the above section on [mixing dependency installations](@ref buildMixingDepInstalls). DCC | Supported Version | OpenVDB ABI | -------- | ----------------- | ----------- | Houdini | 20.5 | 11 | Houdini | 21.0 | 12 | @subsection buildBuildHou Building Against Houdini Houdini ships with a number of libraries that OpenVDB requires. When downloading Houdini, take note of the file version information. The version you install will determine the compiler version you should try and use to build OpenVDB. For example, for @b Linux Houdini 17.5, with a file name of `houdini-17.5.219-linux_x86_64_gcc6.3.tar.gz`, GCC 6.3 should be used. You will need to install some of the following dependencies depending on which OpenVDB components you wish to build. Package | Description | OpenVDB Components | -------------- | --------------------------------------------------------------- | ------------------ | CMake | Cross-platform family of tools designed to help build software | All | C++17 Compiler | Matching Houdini compiler and version | All | Boost | Components: iostreams | All | GoogleTest | A unit testing framework module for C++ | Unit Tests | GLFW | Simple API for OpenGL development | OpenVDB View | Doxygen | Documentation generation from C++ | Documentation | Log4cplus | An optional dependency for improved OpenVDB Logging | Optional (All) | nanobind | C++/python bindings | Optional (Python) | LLVM | Target-independent code generation | OpenVDB AX | At a minimum a matching C++17 compiler and CMake will be required. See the full [dependency list](@ref dependencies) for help with downloading and installing the above software. Note that as Blosc and ZLib are provided as part of the Houdini installation `USE_BLOSC` and `USE_ZLIB` should be left `ON`. With the necessary dependencies installed, create and enter a directory for cmake to write to. It's generally useful to create this in the location you've extracted the OpenVDB repository. It will house CMake's generated build files. @code{.sh} mkdir build cd build @endcode Now you can call CMake by providing the absolute or relative path to the root of the OpenVDB source tree along with the following options: Required: - @b Houdini_ROOT =`/path/to/houdini/install` # Path to Houdini Install - @b USE_HOUDINI =`ON` # Force all components to build against Houdini - @b OPENVDB_BUILD_HOUDINI_PLUGIN =`ON` # Required for building the Houdini Plugin. Optional: - @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html) =`/path/to/install/dir` # The location you wish to install OpenVDB to. See the link for default values. - @b OPENVDB_HOUDINI_INSTALL_PREFIX =`/path/to/install/dir` # The location to install the Houdini plugin to. Defaults to directories defined by Houdini: - Linux: `$ENV{HOME}/houdiniX.X` - Mac: `$ENV{HOME}/Library/Preferences/houdini/X.X` - Windows: `$ENV{HOMEDRIVE}$ENV{HOMEPATH}\Documents\houdiniX.X` - @b USE_DEFAULT_HOUDINI_INSTALL =`ON` # Use the above default locations if @b OPENVDB_HOUDINI_INSTALL_PREFIX is not specified. If `OFF`, uses the value of @b CMAKE_INSTALL_PREFIX. - @b BOOST_ROOT =`/path/to/boost/install` # Path to boost. May not be required, CMake may find it automatically For example on MacOS and where the build folder has been created inside the OpenVDB source root: @code cmake -D BOOST_ROOT=/path/to/boost/install \ -D Houdini_ROOT=/Applications/Houdini/Houdini17.0.506/ \ -D USE_HOUDINI=ON \ ../ @endcode After the CMake build files have been successfully generated, run the build tool within the build directory to compile the project. On UNIX, you can typically incoke `make` directly: @code make -j4 @endcode Where the value of the `j` argument is the number of CPU threads to use for a multi-threaded build. On Windows, you can leverage CMake's build tool to invoke the selected builder (usually msbuild): @code cmake --build . @endcode Finally, once a successful build has completed, you can install all files. @code cmake --build . --target install # or simply `make install` @endcode See the [troubleshooting](@ref buildTroubleshooting) section for help with CMake and Make errors. @subsection buildBuildMaya Building Against Maya Supported versions of maya only ship with TBB. Package | Description | OpenVDB Components | -------------- | --------------------------------------------------------------- | -------------------------------- | CMake | Cross-platform family of tools designed to help build software | All | C++17 Compiler | Matching Houdini compiler and version | All | Boost | Components: iostreams | All | ZLIB | Compression library for disk serialization compression | All | Blosc | Recommended dependency for improved disk compression | All* | GoogleTest | A unit testing framework module for C++ | Unit Tests | GLFW | Simple API for OpenGL development | OpenVDB View | Doxygen | Documentation generation from C++ | Documentation | OpenEXR | EXR serialization support | OpenVDB Render | Imath | Used half precision floating points and EXR serialization support | Optional (All) | Log4cplus | An optional dependency for improved OpenVDB Logging | Optional (All) | nanobind | C++/python bindings | Optional (Python) | LLVM | Target-independent code generation | OpenVDB AX | * See [blosc support](@ref buildBloscSupport) At a minimum, boost, a matching C++17 compiler, ZLIB, blosc and CMake will be required. See the full [dependency list](@ref dependencies) for help with downloading and installing the above software. With the necessary dependencies installed, create and enter a directory for cmake to write to. It's generally useful to create this in the location you've extracted the OpenVDB repository. It will house CMake's generated build files. @code{.sh} mkdir build cd build @endcode Now you can call CMake by providing the absolute or relative path to the root of the OpenVDB source tree along with the following options: Required: - @b Maya_ROOT =`/path/to/maya/install` # Path to Maya Install - @b USE_MAYA =`ON` # Force all components to build against Maya Optional: - @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html) =`/path/to/install/dir` # The location you wish to install OpenVDB to. See the link for default values. - @b OPENVDB_MAYA_INSTALL_PREFIX =`/path/to/install/dir` # The location to install the Maya plugin to. Defaults to the value of `${CMAKE_INSTALL_PREFIX}/maya${Maya_VERSION}` - @b BOOST_ROOT =`/path/to/boost/install` # Path to boost. May not be required, CMake may find it automatically For example on MacOS and where the build folder has been created inside the OpenVDB source root: @code cmake -D BOOST_ROOT=/path/to/boost/install \ -D Maya_ROOT=/Applications/Autodesk/maya2019/ \ -D USE_MAYA=ON \ ../ @endcode As the Maya plugin is disabled by default, you may also want to add `-D OPENVDB_BUILD_MAYA_PLUGIN=ON` to the command. The [components](@ref buildComponents) section shows which targets are enabled by default. After the CMake build files have been successfully generated, run the build tool within the build directory to compile the project. On UNIX, you can typically incoke `make` directly: @code make -j4 @endcode Where the value of the `j` argument is the number of CPU threads to use for a multi-threaded build. On Windows, you can leverage CMake's build tool to invoke the selected builder (usually msbuild): @code cmake --build . @endcode Finally, once a successful build has completed, you can install all files. @code cmake --build . --target install # or simply `make install` @endcode @b Note: The Maya OpenVDB Visualize Node is @b only compatible with Legacy OpenGL support. You can enable this in Maya by navigating to `Windows->Settings/Preferences->Preferences->Display` and changing `Rendering Engine` to OpenGL - Legacy. See the [troubleshooting](@ref buildTroubleshooting) section for help with CMake and Make errors. @subsection buildBuildStandalone Building Standalone It's recommended you first visit the [dependency list page](@ref dependencies) before attempting to run CMake on a standalone build. With the necessary dependencies installed, create and enter a directory for cmake to write to. It's generally useful to create this in the location you've extracted the OpenVDB repository. It will house CMake's generated build files. @code{.sh} mkdir build cd build @endcode Now you can call CMake by providing the absolute or relative path to the root of the OpenVDB source tree. Below are some common options you may want to provide: - @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html) =`/path/to/install/dir` # The location you wish to install OpenVDB to. See the link for default values. - @b Xxx_ROOT =`/path/to/Xxx/` # Give CMake a path to where a package has been installed or simply to where your prefered package is installed if it cannot locate it. For example, a typical first attempt at generating the build files may look as follows: @code{.sh} cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb ../ @endcode See the [components](@ref buildComponents) section to find which targets are available, their corresponding CMake flags and their default values. After the CMake build files have been successfully generated, run the build tool within the build directory to compile the project. On UNIX, you can typically incoke `make` directly: @code make -j4 @endcode Where the value of the `j` argument is the number of CPU threads to use for a multi-threaded build. On Windows, you can leverage CMake's build tool to invoke the selected builder (usually msbuild): @code cmake --build . @endcode Finally, once a successful build has completed, you can install all files. @code cmake --build . --target install # or simply `make install` @endcode See the [troubleshooting](@ref buildTroubleshooting) section for help with CMake and Make errors. @section buildUsingOpenVDB Building With OpenVDB This section is for users wishing to use a build of OpenVDB in their own applications with CMake. The following assumes that OpenVDB was installed with `OPENVDB_BUILD_CORE=ON` and `OPENVDB_INSTALL_CMAKE_MODULES=ON`. Don't worry if you didn't specify these options directly, they both default to `ON`. This ensures that OpenVDB has installed the required CMake modules that your application will need to use. @b Note: Typically, projects provide a @b Config-file rather than a @b Find-module for downstream use. OpenVDB currently provides a @b Find-module. This may change in the future. Further information [here](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#using-packages). You can add the below CMake snippet to your main `CMakeLists.txt` to bring in OpenVDB as a dependency: @code{.cmake} cmake_minimum_required(VERSION 3.24) list(APPEND CMAKE_MODULE_PATH "/location/of/openvdb/install/lib/cmake/OpenVDB") find_package(OpenVDB REQUIRED) target_link_libraries(myapp OpenVDB::openvdb) @endcode `myapp` in the above is a CMake target, usually created with `add_library()` or `add_executable()`. You can optionally provide `CMAKE_MODULE_PATH` as a `-D` argument to the cmake command line instead of specifying it in your `CMakeLists.txt`. Note that the `FindOpenVDB.cmake` module relies on the other `FindModules` provided in the OpenVDB installation to find it's own dependencies. This may require you to provide additional dependency locations for OpenVDB's dependencies. See [Locating Dependencies](@ref buildDependencies) or the below troubleshooting for more information. ------------------------------------------------------------------------------ @section buildTroubleshooting Troubleshooting If after reading this guide you're unable to find your specific issue below, please get in touch or [file an issue](https://github.com/AcademySoftwareFoundation/openvdb/issues) with the OpenVDB TSC. @b Note: If running into issues when changing CMake settings/dependency paths, try clearing the designated CMake build directory and running your `cmake` command again. @subsection troubleshoot1 CMake Error ... Could NOT find XXX (missing: ... ) It's fairly typical that CMake may fail to find some dependencies on first runs, especially if you've manually compiled from source your own dependencies. Analyzing any dependency errors will help with running further invocations of cmake. The [Locating Dependencies](@ref buildDependencies) section details the variable format required to point CMake to the correct locations. Alternatively, with interactive cmake systems such as `ccmake` or CMake GUI, variables which are not found will be shown, allowing you to provide them directly. As an example, earlier versions of [Threading Building Blocks (TBB)](https://www.threadingbuildingblocks.org/) do not come with CMake modules or [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) modules. For OpenVDB to locate TBB, you typically need to provide this location manually: @code{.sh} cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb -D TBB_ROOT=/path/to/tbb/install ../ @endcode Note that this is also equivalent to: @code{.sh} cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb \ -D TBB_INCLUDEDIR=/path/to/tbb/install/include \ -D TBB_LIBRARYDIR=/path/to/tbb/install/lib \ ../ @endcode @subsection troubleshoot2 CMake Error ... Could NOT find XXX (Found unsuitable version: ... ) By default, OpenVDB sets a number of minimum version requires for its dependencies. These can be found in the root CMakeList.txt or in the [dependency table](@ref dependencies). These minimum versions either track the oldest supported [VFX Reference Platform](https://www.vfxplatform.com/) or are otherwise required for compatibility. Although not recommended, you can bypass these checks with `-D DISABLE_DEPENDENCY_VERSION_CHECKS=ON` if necessary. Note that using older or untested dependencies may produce undesired behavior. Older versions in particular are not supported by OpenVDB. @b Note: Boost will produce a version error in the format `Detected version of Boost is too old.` @subsection troubleshoot3 CMake warnings/errors in FindBoost.cmake There are a variety of potential warnings and errors that may arise from the version compatibility of Boost and CMake. These are related to how both Boost and CMake have historically been kept in sync. A common warning and error combination is: @code{.sh} CMake Warning at ... Imported targets not available for Boost version XXXXXX ... Target "..." links to target "Boost::XXX" but the target was not found. Perhaps a find_package() call is missing for an IMPORTED target, or an ALIAS target is missing? @endcode OpenVDB uses [imported targets](https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries) for all its dependencies. For imported Boost compatibility, the following versions of CMake are required: - Boost 1.82 requires CMake 3.27.0 or newer. - Boost 1.83 requires CMake 3.27.4 or newer. - Boost 1.84 requires CMake 3.28.2 or newer. - Boost 1.85 requires CMake 3.29.3 or newer. - Boost 1.86 requires CMake 3.30.6, 3.31.1, or newer. - Boost 1.87 requires CMake 3.31.4 or newer. Use the above list to identify the version of CMake you require for your version of Boost. Note that this may be implemented into the OpenVDB CMake in the future. @subsection troubleshoot4 Detected VCPKG toolchain is using a mismatching triplet for OpenVDB build artifacts If you are on Windows and using vcpkg, builds of OpenVDB should usually only build the static OR shared library depending on your vcpkg triplet. This is related to how libraries link against the Windows CRT. In vcpkg, static triplets, such as @b x64-windows-static, will use the @b MultiThreaded (/MT) flag and dynamic triplets, such as @b x64-windows, will use the @b MultiThreadedDLL (/MD) flag. These flags @b must match throughout all software artifacts in your toolchain (regardless if you are using vcpkg or not). This warning is shown when OpenVDB detects you using either a dynamic or static VCPKG toolchain on Windows, but have the opposite core library variant enabled. By default, the static build of OpenVDB links against the @b MultiThreaded (/MT) CRT and the dynamic library links against the @b MultiThreadedDLL (/MD) CRT. As OpenVDB configures both by default, it is typical that you may want to disable one or the other depending on your needs. Note that you can provide a value for `CMAKE_MSVC_RUNTIME_LIBRARY` which is a native CMake variable to override any CRT selection done by OpenVDB. For more information, see the following articles: Description of CRT selection: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library In depth descriptopn of the CRT on Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features Related errors: https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2038 `CMAKE_MSVC_RUNTIME_LIBRARY` docs: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html @subsection troubleshoot5 Unexpected value for the Windows CRT with target build artifacts. On Windows, it is typical for static builds to link to static libraries and dynamic builds to link to dynamic library variants. This is not related to the libraries themselves, rather it is due to the way that all libraries used within a specific toolchain must use the same version of the CRT. The rule of thumb is to configure static builds against the static CRT and dynamic builds against the dynamic CRT. This warning is shown if you have provided a value for the CMake variable `CMAKE_MSVC_RUNTIME_LIBRARY`, but this value is the opposite of what's expected for a target library. Note that there are some cases where it makes sense to link static builds of OpenVDB against the dynamic (/MD) CRT. However, unless you are confident in your usage, it is strongly encouraged to match the selection against your desired build type. For more information, see the following articles: Description of CRT selection: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library In depth descriptopn of the CRT on Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features Related errors: https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2038 `CMAKE_MSVC_RUNTIME_LIBRARY` docs: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html @subsection troubleshoot6 error LNK2038: mismatch detected for 'RuntimeLibrary' A build artifact of OpenVDB has been linked against a dependency which uses a different version of the Window CRT. See the [above section](@ref troubleshoot5) on dealing with CRT selection for static and dynamic library builds on Windows. */ openvdb-13.0.0/doc/changes.txt000066400000000000000000007255271510223237100161640ustar00rootroot00000000000000/** @page changes Release Notes @htmlonly @endhtmlonly @par Version 13.0.0 - November 3, 2025 @par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 11 for Houdini 20.5 and 12 for Houdini 21.0.
@par
Support for reading .vdb files written prior to VDB 1.0 has been removed. To read older .vdb files, please use VDB 12.x or older and re-write them, so that they use the newer file format and can be read in VDB 13+.
@par Highlights: - OpenVDB now includes in-memory support for Half Grids and the file format has been extended to add I/O serialization for half grids. More work is planned on adapting algorithms when using Half Grids for better performance and improved precision. - NanoVDB is no longer limited to static applications, such as rendering, but can increasingly be applied to problems that involve dynamic topology, such as level set tracking, grid building, morphology operations and merging of grids. This is due to the fact that we keep adding more and more tools to NanoVDB that facilitates tree modification. However, unlike OpenVDB, these operations generate new NanoVDB grids (as oppose to in-palace modifications in OpenVDB), yet are typically much faster since they are performed on the GPU. Many of these exciting new features are the foundation of fVDB. @par OpenVDB: - New features: - Added native registration of HalfGrid type. - Added customization of the output transformation attribute for @vdblink::points::pca points::pca@endlink. Can be output as a quaternion or as a combined affine transform with the scale/stretch ommitted. - Added support for input quaternions attributes and affine transformations (that include scale) in @vdblink::points::rasterizeSdf points::rasterizeSdf@endlink for ellipsoidal rasterizations. - API Changes: - Added @vdblink::tree::LeafBuffer::storage() LeafBuffer::storage()@endlink for direct const access to the raw data buffer when using the bool LeafNode. - Removed Grid::evalMinMax(), use @vdblink::tools::minMax tools::minMax@endlink for superior threaded performance. - Removed points::rasterize() that took a custom filter and interrupter. - Removed LeafNodeBool TopologyCopy constructor in favor of using explicit mask/buffer constructors. - Removed @vdblink::tree::ValueAccessor ValueAccessor@endlink NodeT0, NodeT1, NodeT2 aliases, use NodeTypeAtLevel instead. - Add @vdblink::tree::InternalNode::setValueMaskUnsafe() InternalNode::setValueMaskUnsafe()@endlink to write a value mask directly. - LegacyFrustum and RootNodeMask have been removed. These classes were only used for reading old .vdb files, which is no longer supported. - @vdblink::io::writeCompressedValues() io::writeCompressedValues()@endlink now takes a const ValueT* source buffer for improved const-correctness. - Bug Fixes: - Fix a bug in the @vdblink::tools::LevelSetRayIntersector LevelSetRayIntersector@endlink class where two of the methods were incorrectly adjusting the time even when an intersection was not found. - Fixed an assertion in @vdblink::math::Quat math::Quat@endlink where a vector length check was using too small a tolerance. - Fixed a bug in the unit tests where detecting if assertions were enabled was using @c NDEBUG rather than OpenVDB assertions. - Build: - Removed the unnecessary @c USE_NUMPY build option for the OpenVDB Python module. All functions which take numpy arrays are now always generated (numpy is not required at compile time for this support). - Bumped minimum supported CMake version to 3.24, and new future minimum to 4.0.0. - Bumped minimum supported OpenEXR and Imath versions to 3.2, and new future minimum to 3.3. - Bumped minimum supported Boost version to 1.82, and new future minimum to 1.85. - Bumped minimum supported Python version to 3.11 - Bumped minimum supported Log4cplus version to 2.0 - Bumped minimum supported Houdini version to 20.5 - Bumped minimum supported GLFW version to 3.3 - Bumped future minimum for TBB to 2021 (oneapi). - Bumped future minimum for nanobind to 2.5.0. @par OpenVDB AX: - New: - Added support for LLVM 21. @par NanoVDB: - Highlights: - NanoVDB is no longer limited to static applications, such as rendering, but can increasingly be applied to problems that involve dynamic topology, such as level set tracking, grid building, morphology operations and merging of grids. This is due to the fact that we keep adding more and more tools to NanoVDB that facilitates tree modification. However, unlike OpenVDB, these operations generate new NanoVDB grids (as oppose to in-palace modifications in OpenVDB), yet are typically much faster since they are performed on the GPU. Many of these exciting new features are the foundation of fVDB. - New features: - Added nanovdb/tools/cuda/DilateGrid.cuh, which performs topology dilation on the GPU. - Added nanovdb/tools/cuda/MergeGrids.cuh, which merges the topology of two grids on the GPU. - Added nanovdb/tools/cuda/CoarsenGrid.cuh, which performs topological coarsening of grids on the GPU. - Added nanovdb/tools/cuda/RefineGrid.cuh, which performs topological refinement of grids on the GPU. - Added nanovdb/tools/cuda/PruneGrid.cuh, which prunes the topology of a grid using a sidecar mask on the GPU. - Added nanovdb/util/cuda/Injection.cuh, which facilitates sidecar data copying - on the GPU - in the overlap of two grids with different topology. - Added Mat classes and other math types to NanoVDB. - Major rewrite of nanovdb::NanoToOpenVDB, which now allows nanovdb::IndexGrids and blind (or sidecar) data to be converted into an openvdb grid. - Added support for LevelSet, FogVolume, and Staggered grid semantics. Added toGridClass and toSemantic to map Grid Blind data semantic to Grid class and vice versa. - Improvements: - Improvements to mGPU grid building and introduction of a separate test executable for mGPU tests - Added stand-alone function nanovdb::writeUncompressedGrid that allows nanovdb::IndexGrids and blind (or sidecar) data to be written directly to a stream. - @c nanovdb_print now (optionally) prints the blind data count per grid. - Extended nanovdb::GridBlindDataSemantic with nanovdb::GridClass types to support conversion between IndexGrid and regular grids. - Improvements and bugfixes to PNanoVDB. - API Changes: - Removed nanovdb::ValueIndexMask and nanovdb::ValueOnIndexMask since they are no longer used by fVDB (or elsewhere). - NanoVDB version is now 32.9.0, so the ABI of the grid is preserved but not the API. However, the API changes are very minor! - Bug Fixes: - Several fixes for compiler warnings. - Fixed error in nanovdb/io/IO.h related to missing throws. @par Houdini: - Remove support for openvdb_houdini::Interrupter, use openvdb_houdini::HoudiniInterrupter instead. - Remove input-stealing via duplicateSourceStealable(), SideFX have since introduced verbification and compiled SOPs to provide zero-copy node evaluation. @htmlonly @endhtmlonly @par Version 12.1.1 - September 30, 2025 @par OpenVDB AX: - Fixes: - Fixed an issue which was causing host specific optimization passes to be omitted when using LLVM 16 and higher. @par Houdini: - Fixed a compilation issue with the OpenVDB Activate SOP with Houdini 21 [Reported by @callen128] @htmlonly @endhtmlonly @par Version 12.1.0 - August 8, 2025 @par OpenVDB: - New features: - New level set constructor tools::createLevelSetCapsule creates a grid containing a narrow-band level set representation of a capsule (tube with constant radius and sphere caps). - New level set constructor tools::createLevelSetTaperedCapsule creates a grid containing a narrow-band level set representation of a tapered capsule (tube with sphere caps and different radii at both ends, or equivalently the convex hull of two spheres with possibly different centers and radii). - New level set constructor tools::createLevelSetTubeComplex creates a grid containing a narrow-band level set representation of a tube complex (a collection of capsules or tapered capsules defined by endpoint coordinates and segment indices). - New level set constructor tools::createLevelSetDilatedMesh creates a grid containing a narrow-band level set representation of a dilated surface mesh (dilated by a radius in all directions). - New class tools::ConvexVoxelizer, used by the above methods, which can be inherited to implement a convex level set constructor. - Introduced anisotropic surfacing tools in points/PointRasterizeSDF.h and principal component analysis (PCA) methods in points/PrincipalComponentAnalysis.h. The latter tool analyses point neighborhoods and computes affine transformations representing elliptical distributions. The prior tool takes rotational and stretch point attributes (optionally computed from the prior PCA methods) and generates anisotropic surfaces. - Improvements: - Significantly improved the performance of all LeafNode ValueIterators, up to 5x on some platforms and up to 10x when delay loading is enabled. Construction of a ValueIterator from a leaf node now requests the leaf buffers ahead of iteration to avoid potentially expensive API calls. - Improved the performance of PointRasterizeSDF.h tools with larger radii with better bound computation approximations. - Significant performance improvement to delay loaded files - the warning logic which checks the underlying mapped file for the last modified time has been removed, resulting in performance gains upwards of 10x when loading in node data buffers. Note that the check that was removed is entirely redundant on Windows and would only print a warning on other system. [Contributed by jjtParadox] - Added OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION and OPENVDB_HAS_MEMBER_FUNCTION macros to help determine the presence and compatibility of interface member functions at compile time. - Added OPENVDB_ASSUME macros to mimic builtin assume and C++23 assume attributes. - Improved read and write of PLY files with vdb_tool so they support Vec3d and 64 bit attributes. Changed vdb_tool version number from 10.6.1 to 10.7.0. - API Changes: - Mat3 and Mat4 functions have been marked [[nodiscard]] where it may be confusing if they are operating in place or returning a result, in particular tranpose, invert, adjoint, and timesDiagonal. - Re-worked the API in PointRasterizeSDF.h with the addition of anisotropic surfacing kernels. The new API exposes more concise free functions which take structs of parameters. The old API remains supported but is deprecated. - Deprecated providing a filter or interrupter as arguments to points::rasterize. These can instead be implemented on user transfer schemes. - Transfer schemes provided to points::rasterize can now optionally implement a rasterizePoints callback that takes a range of points per voxel. - Fixes: - Fixed a bug in points::rasterizeSpheres and points::rasterizeSmoothSpheres which could cause sections of the generated surface to incorrectly be marked as negative interior values. - Fixed a bug in points::rasterizeSmoothSpheres which could result in incomplete surface reconstruction with significantly larger search distances. - Fixed some precision issues in various Matrix methods. - Fixed bugs in vdb_tool that prevented build with newer namespaces in nanovdb. @par OpenVDB AX: - Improvements: - Added support for LLVM versions greater than 15. Upgraded CI to test with LLVM versions 16, 17, 18, 19 and 20. - As of this release, LLVM 15 is the minimum required version for OpenVDB AX. Note that there is an issue with LLVM 17 symbols which makes it incompatible with the OpenVDB Python plugin. AS such, LLVM version 18 and greater are the recommended LLVM versions to use, with LLVM 18 being the new future minimum version. - Significant performance improvement to the compilation of AX kernels when using LLVM 18 and greater. - Significant backend refactoring to AX IR generation to support newer versions of LLVM. In particular, parts of the codegen::Function and codegen::FunctionBuilder API require new usage from LLVM 16 due to the LLVM opaque pointer changes. If you're not using the OpenVDB AX Function codegen API then no client changes should be necessary. - Migrated OpenVDB AX unit tests from cppunit to gtest [Contributed by Tim Straubinger] - Fixes: - Fixed a case of undefined behaviour when explicitly casting variables to the same type as their storage type e.g: double a; double b = double(a); - Fixed an AX compiler error which would produce invalid IR when using 64bit integer variables for matrix array offsetting e.g: int64 a = 0; mat4f b = 1; float c = b[a,a]; @par NanoVDB: - Added nanovdb::openToIndexVDB, which can convert an OpenVDB grid into a NanoVDB IndexGrid. - Added new options "--index" and "--onIndex" to the command-line tool nanovdb_convert so it can produce IndexGrids. - Fixed memory leak in DeviceBuffer. - Added constructor for DeviceBuffer from an existing HostBuffer. - Added VoxelBlockManager, an acceleration structure for sequential access and stencil ops over active voxels. - Added helper functions for kernel launches with shared memory. - Added support for CUDA 13.0. - Fix warnings and compilation errors for GCC and Clang. - Fixed inconsistent usage of util::cuda::mallocAsync/freeAsync that affected vGPUs. - Added support for custom memory resources in PointsToGrid. - Fixed race condition in split/mergeGridHandles. - Fixed offset bug in nanovdb::tools::cuda::IndexToGrid related to non-POD build types. [Contributed by Andreas Henne] @par Houdini: - Define OP_InputIdx and OP_OutputIdx for Houdini 21.0 compatibility - Add Houdini 21 style camera interface to support LOP cameras - Include env flag for avoiding stream writing (was backported to 19.5) @htmlonly @endhtmlonly @par Version 12.0.1 - April 3, 2025 @par OpenVDB: - New features: - Added read and write support for OFF (Object File Format) files to vdb_tool - Build: - Fixed a build issue with vdb_render on Windows with newer versions of glew not including glu.h by default - Fixed issues with newer versions of clang refusing to accept older ::template syntax @par NanoVDB: - New features: - Added support for multiple GPUs to DeviceBuffer - Added a UnifiedBuffer class that wraps CUDA unified memory - Added example for multiGPU sparse convolution - Added CUDA utility functions for device queries - Added functions to independently stop and compute the elapsed time for timer classes - Improvements: - Replaced CUB's CachingDeviceAllocator with the default asynchronous stream ordered allocator in PointsToGrid for improved performance - Bug fix: - Map is now properly transposed when converting NanoVDB to OpenVDB. - Fixed ostream specializations being hidden within the nanovdb namespace - Fixed a call to a non-existent method in GridBuild.h @htmlonly @endhtmlonly @par Version 12.0.0 - October 31, 2024 @par
OpenVDB is now licensed under the Apache 2.0 license, instead of the MPL 2.0 license.
@par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 10 for Houdini 20.0 and 11 for Houdini 20.5.
@par
GCC 9 is no longer supported.
@par OpenVDB: - New features: - Added tools::LevelSetFilter::fillet() method to round off concave edges to create smoother transition between surfaces. - Improvements: - Added openvdb::assertAbort to replace cassert and a @c OPENVDB_ENABLE_ASSERTS cmake argument/compile define to toggle assertions in OpenVDB code, independantly of NDEBUG. Asserts are no longer enabled by default in when NDEBUG is absent (e.g. Debug builds). - Removed last traces of Boost when @c OPENVDB_USE_DELAYED_LOADING is OFF [Reported by Brian McKinnon] - RootNode code cleanup to eliminate redundant key conversion and to create map values in-place. - Add RootNode::deleteChildOrTile() to delete a child or tile of the root node. - ValueAccessors are now defined and created in the Tree class instead of in the Grid class so that custom Tree implementations may define and create their own ValueAccessors if desired. - Added support for PDAL to vdb_tool [Contributed by Tom Matterson] - LeafManager and NodeManager now use Index64 for leaf counts internally. - Added RootNode::probeChild() const. - Added RootNode::probeChild() and RootNode::probeConstChild(). - Added RootNode::probe() and RootNode::probeConst() to query key presence, child node, value and active state. - Added InternalNode::probeChild() const. - Added InternalNode::probeChild() and probeChildConst() with coord access and optionally value and active state. - Added InternalNode::probeChild() and probeChildConst() with index access and optionally value and active state. - Added InternalNode::isValueOff(), LeafNode::isValueOff(), LeafNodeBool::isValueOff(), LeafNodeMask::isValueOff(). - Added LeafNodeMask::probeValue(Index,val), LeafNodeBool::probeValue(Index,val). - Added RootNode::getValueUnsafe(), RootNode::getChildUnsafe(), RootNode::getConstChildUnsafe(). - Added InternalNode::getValueUnsafe(), InternalNode::getChildUnsafe(), InternalNode::getConstChildUnsafe(). - Added InternalNode::setActiveStateUnsafe(), InternalNode::setValueOnlyUnsafe(), InternalNode::setValueOnUnsafe(), InternalNode::setValueOffUnsafe(). - Added InternalNode::setChildUnsafe(), InternalNode::resetChildUnsafe(), InternalNode::stealChildUnsafe(), InternalNode::deleteChildUnsafe(). - For LeafNode, LeafNodeBool and LeafNodeMask - added LeafNode::getValueUnsafe(), LeafNode::setActiveStateunsafe(), LeafNode::setValueOnlyUnsafe(), LeafNode::setValueOnUnsafe(), LeafNode::setValueOffUnsafe(). - ABI changes: - Tree::leafCount(), Tree::unallocatedLeafCount(), Tree::nonLeafCount() and Tree::nodeCount() now use Index64 in their return types instead of Index32. - API Changes: - RootNode::tileCount(), RootNode::activeTileCount() and RootNode::inactiveTileCount() are now public. - RootNode::hasKey() and RootNode::coordToKey() are now public. - RootNode::leafCount(), RootNode::nonLeafCount() and RootNode::nodeCount() now use Index64 instead of Index32. The Index32 variant is deprecated. - InternalNode::leafCount(), InternalNode::nonLeafCount() and InternalNode::nodeCount() now use Index64 instead of Index32. The Index32 variant is deprecated. - LeafNode::leafCount() and LeafNode::nonLeafCount() now use Index64 instead of Index32. The Index32 variant is deprecated. - Bug Fixes: - Fix potential crash reading corrupt .vdb files with invalid blosc or zip chunks. [Reported by Matthias Ueberheide] - Fix a bug in RootNode::setOrigin() where the origin was updated before the error was thrown potentially leaving the root in an invalid state. - Fixed a thread sanitizer issue which could cause undefined behaviour in VolumeToSpheres::fillWithSpheres [Reported by Jérémie Dumas] - Fixed an occurance of undefined behaviour in tools::activate (though this would typically not have manifested with any unintended behaviour) @par NanoVDB: - Bug fix: - nanovdb::readGrids works with raw grid buffer. - Improvements: - Restructure files location and namespace to be more align with OpenVDB. The namespaces touched by the restructuring are: io, cuda, util, tools, and math. - Add two scripts updateFiles.sh and updateFiles.py to update the files using NanoVDB. The script updateFiles.py works on both Windows and Linux. For a more complete list of changes, see API Changes (details). - cuda::PointsToGrid supports target density. - Add support for NanoVDB Grid of type UInt8. - Add ability to use externally managed CUDA buffer. - Add create methods for CudaDeviceBuffer and exceptions. - Improve GridValidator logic, e.g. include check for grid count. - Add operator > and >= for class Coord according to lexicographical order. - Add toCodec to convert string to Codec enumeration type. - Add nanovdb::strlen(). - Add strncpy util. - Add @c NANOVDB_DISABLE_SYNC_CUDA_MALLOC that maps cudaMallocAsync and cudaFreeAsync to cudaMalloc and cudaFree respectively. - Add guard to @c UINT64_C. - Remove use of cudaMallocAsync in PointsToGrid.cuh. - Align PNanoVDB blind metadata to NanoVDB. - API Changes: - Change mapToGridType to toGridType. - Change mapToMagic to toMagic. - Change CpuTimer.h to Timer.h. - API Changes (details): - These APIs are now under the math namespace: Ray, DDA, HDDA, Vec3, Vec4, BBox, ZeroCrossing, TreeMarcher, PointTreeMarcher, BoxStencil, CurvatureStencil, GradStencil, WenoStencil, AlignUp, Min, Max, Abs, Clamp, Sqrt, Sign, Maximum, Delta, RoundDown, pi, isApproxZero, Round, createSampler, SampleFromVoxels. - These APIs are now under the tools namespace: createNanoGrid, StatsMode, createLevelSetSphere, createFogVolumeSphere, createFogVolumeSphere, createFogVolumeSphere, createFogVolumeTorus, createLevelSetBox, CreateNanoGrid, updateGridStats, evalChecksum, validateChecksum, checkGrid, Extrema. - These APIs are now under the util namespace: is_floating_point, findLowestOn, findHighestOn, Range, streq, strcpy, strcat, empty, Split, invoke, forEach, reduce, prefixSum, is_same, is_specialization, PtrAdd, PtrDiff. - Move nanovdb::build to nanovdb::tools::build. - Rename nanovdb::BBoxR to nanovdb::Vec3dBBox. - Rename nanovdb::BBox to nanovdb::Vec3dBbox. - Move nanovdb::cudaCreateNodeManager to nanovdb::cuda::createNodeManager. - Move and rename nanovdb::cudaVoxelsToGrid to nanovdb::cuda::voxelsToGrid. - Move and rename nanovdb::cudaPointsToGrid to nanovdb::cuda::pointsToGrid. - Move nanovdb::DitherLUT to nanovdb::math::DitherLUT. - Move and rename nanovdb::PackedRGBA8 to nanovdb::math::Rgba8. - Move nanovdb::Rgba8 to nanovdb::math::Rgba8. - Move and rename nanovdb::CpuTimer to nanovdb::util::Timer. - Move nanovdb::GpuTimer to nanovdb::util::cuda::Timer. - Move and rename nanovdb::CountOn to nanovdb::util::countOn. - Move util/GridHandle.h to GridHandle.h. - Move util/BuildGrid.h to tools/GridBuilder.h. - Move util/GridBuilder.h to tools/GridBuilder.h. - Move util/IO.h to io/IO.h. - Move util/CSampleFromVoxels.h to math/CSampleFromVoxels.h. - Move util/DitherLUT.h to math/DitherLUT.h. - Move util/HDDA.h to math/HDDA.h. - Move util/Ray.h to math/Ray.h. - Move util/SampleFromVoxels.h to math/SampleFromVoxels.h. - Move util/Stencils.h to nanovdb/math/Stencils.h. - Move util/CreateNanoGrid.h to tools/CreateNanoGrid.h. - Move and rename util/Primitives.h to tools/CreatePrimitives.h. - Move util/GridChecksum.h to tools/GridChecksum.h. - Move util/GridStats.h to tools/GridStats.h. - Move util/GridChecksum.h to tools/GridChecksum.h. - Move util/GridValidator.h to tools/GridValidator.h. - Move util/NanoToOpenVDB.h to tools/NanoToOpenVDB.h. - Move util/cuda/CudaGridChecksum.cuh to tools/cuda/CudaGridChecksum.cuh. - Move util/cuda/CudaGridStats.cuh to tools/cuda/CudaGridStats.cuh. - Move util/cuda/CudaGridValidator.cuh to tools/cuda/CudaGridValidator.cuh. - Move util/cuda/CudaIndexToGrid.cuh to tools/cuda/CudaIndexToGrid.cuh. - Move and rename util/cuda/CudaPointsToGrid.cuh to tools/cuda/PointsToGrid.cuh. - Move util/cuda/CudaSignedFloodFill.cuh to tools/cuda/CudaSignedFloodFill.cuh. - Move and rename util/cuda/CudaDeviceBuffer.h to cuda/DeviceBuffer.h. - Move and rename util/cuda/CudaGridHandle.cuh to cuda/GridHandle.cuh. - Move and rename util/cuda/CudaUtils.h to util/cuda/Util.h. - Move and consolidate util/cuda/GpuTimer.h to util/cuda/Timer.h. @par Python: - OpenVDB Python bindings are now implemented using nanobind instead of pybind11 - The OpenVDB Python module has been changed from pyopenvdb to openvdb - Added Python bindings for NanoVDB @par Houdini: - When @c OPENVDB_ENABLE_RPATH is @c ON, the location of libopenvdb_houdini is now added to the rpath of all Houdini dsos. @par Build: - Fixed an issue with OpenVDB AX's CMake on Windows where the static and shared library targets would have the same name [Reported by Nicholas Yue] - @c USE_EXPLICIT_INSTANTIATION is now disabled on Windows by default due to OOM linker issues. - Jemalloc is now the preferred allocator of choice on all platforms when @c CONCURRENT_MALLOC is set to Auto. - Fixed an issue with the Blosc CMake FindPackage for the OpenVDB Windows static library. @htmlonly @endhtmlonly @par Version 11.0.0 - November 1, 2023 @par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N.
@par
OpenEXR 2 and Python 2 are no longer supported.
@par OpenVDB: - Improvements: - Removed use of @c boost::any in favor of @c std::any. [Contributed by Brian McKinnon] - Bug Fixes: - Fix potential crash reading corrupt .vdb files with invalid blosc or zip chunks. [Contributed by Matthias Ueberheide] @par NanoVDB: - Highlights: - Several new tools to generate and modify NanoVDB grids on the GPU. - New file format that supports streaming of raw grid buffers. - New Features: - New memory efficient @c GridClass::IndexGrid that separates values from tree - 4 new GridTypes (@c Index, @c OnIndex, @c IndexMask, @c OnIndexMask) used by IndexGrid - Added @c createNanoGrid that replaces older conversion methods in GridBuilder.h, IndexGridBuilder.h and OpenToNanoVDB.h - Added @c cudaPointsToGrid that constructs a point device grid from a list of points. - Added @c cudaVoxelsToGrid that constructs a voxel device grid from a list of voxels. - Added cuda/CudaUtils.h with several cuda utility functions. - Added @c GpuTimer for timing of kernels in a specific cuda stream. - Added @c cudaIndexToGrid that converts IndexGrids into regular Grids. - Added @c cudaSignedFloodFill that performs signed-flood filling on the GPU. - Added @c cudaAddBlindData that adds blind data to an existing grid on the GPU. - Added @c cudaGridChecksum that computes checksums of device grids. - Added @c cudaGridHandle that handles grids on the GPU. - Added @c cudaNodeManager that constructs a NodeManager on the GPU. - Added build type @c Points and @c GridType::PointIndex for point grids. - Added @c GridType::Vec3u16 and @c GridType::Vec3u8 for compressed coordinates. - Added PrefixSum.h for concurrent computation of prefix sum on the CPU. - API Changes: - Version 32.6.0 (ABI is unchanged). - Transition from C++11 to C++17 - Vec3R is deprecated, please use Vec3d instead. - nanoToOpenVDB now takes the index of a NanoVDB in a GridHandle. - GridData, InternalData and LeafData are now public. - GridMetaData can be copied. - Improvements to GridBuilder.h that allows construction of grids on CPU. - GridHandle's move c-tor now requires the GridBuffer to contain a valid grid. - Moved CudaDeviceBuffer.h to cuda/CudaDeviceBuffer.h. - New API for acceleration of custom random-access with ValueAccessors. - Added BitFlags class for convenient bit-mask operations. - Added Vec2/3 min/maxComponentAtomic GPU methods. - Added @c BBox::expandAtomic and @c BBox::intersectAtomic. - Added @c Coord::expandAtomic. - Added Map constructors. - Added @c Mask::DenseIterator, @c Mask::setOnAtomic, and @c Mask::setOffAtomic. - @c InternalNode::ChildIterator is now const-correct. - Added several new NanoVDB Build Traits. - Syncing PNanoVDB.h with NanoVDB.h. @par Build: - Support for OpenEXR 2.X has been removed. - Better support for building with external package configurations with CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON. @par Python: - Removed Python 2 support. [Contributed by Matthew Cong] - Removed explicit bindings for Math types. [Contributed by Matthew Cong] - Improved type casting for TypedMetadata. [Contributed by Matthew Cong] @htmlonly @endhtmlonly @par Version 10.1.0 - October 11, 2023 @par Highlights: - OpenVDB Python bindings are now implemented using pybind11 instead of Boost.Python. [Contributed by Matthew Cong] @par OpenVDB: - New features: - Added points::replicate() for the replication of PointDataGrid points and attributes. - Improvements: - Upgraded OpenVDBs internal half representation to IMath 3.1.6. Brings conversion support using F16C instructions (if enabled using -mf16c) and the removal of the exponent lookup table in favor of bit shifting. - OpenVDBs copy of Half.h is no longer built with an internal lookup table, but explicitly selects the non-LUT version and disables the creation of the LUT. This is required to avoid symbol conflicts with different namespaced OpenVDB builds. - Removed boost::uuid from Archive, instead std::random_device is used directly to generate UUID-like objects. - Moved all cases of file static/global variables which relied on non-trivial construction into function scopes as static locals. These would previously initialize themselves on start-up in a non-deterministic, compiler-dictated order(static-initialization-order-fiasco). This order is now defined by the program's execution. - Fixed the constants used in openvdb::math::Coord::hash() and nanovdb::Coord::hash() to correctly be prime numbers (note that this changes the result of these methods). [Contributed by Benedikt Mersch] - Updated tools::meshToVolume to take two new optional arguments to provide an interior test oracle and an interior testing method. These allow the default outside-flood-fill to be replaced if the actual sidedness can be known. [Contributed by Tomas Skrivan] - LevelSetRebuild now includes example code that demonstrates the intended use of the new meshToVolume interior testing parameters for the resampling of level sets, where the original grid is used as the true sign value. However, due to differences between polygonalization and trilinear interpolation, this behaviour is disabled and exists as a reference. - Introduced openvdb::TupleList to wrap std::tuple and provide interface interop methods with openvdb::TypeList. - Added OPENVDB_FORCE_INLINE, OPENVDB_LIKELY and OPENVDB_UNLIKELY macros. - Introduced openvdb::make_index_sequence to solve clang compilations issues with compiler built-in index_sequence implementations. - API changes: - Significant infrastructural change to the ValueAccessor header and implementation. All ValueAccessor specializations have been consolidated into a single class which supports all possible ValueAccessor configurations using index_sequences. Backward compatible declarations have been provided. The new ValueAccessor implementation is marked as final. - PagedArray iterators no longer derive from std::iterator (but remains standard compliant). - Bug Fixes: - Internal counters in tree::RangeIterator were limited to 32bit precision. They are now extended to size_t. [Reported by SpaceX] - Fixed a bug when compiling with -fvisibility=hidden and GCC 11 which would cause a crash in openvdb::initialize(). - Fixed a bug with LeafManager which wouldn't correctly initialize its LeafNode array for single level Tree configurations i.e. RootNode (bug introduced in 7.2.0). [Reported by @lanwatch] - Fixed a bug with LeafNodeBool Topology constructor with designated on/off values which wouldn't apply them correctly. [Reported by @hozhaoea] @par OpenVDB AX: - Improvements: - Added support for LLVM 15. - Bug Fixes: - Fixed a bug in AX on older X86 hardware which could cause a crash when accessing point attributes with half compression (bug introduced in 9.1.0). - Fixed an incorrect option in the `vdb_ax` command line tool where the default optimization level was set to NONE instead of O3 (issue introduced in 10.0.0). @par OpenVDB Houdini: - Improvements: - Added Preserve Holes option to VDB From Polygons that uses the fast winding oracle to not collapse holes in polygonal geometry. - Bug Fixes: - Fix a bug in the projection mode of the Advect Points SOP that was causing a segfault. @par Build: - Fixed a build issue where Boost was not being pulled in when OPENVDB_USE_DELAYED_LOADING was set to OFF. - Fixed a build issue with AX on 32-bit platforms. [Reported by Mathieu Malaterre] - Fixed a compilation issue with the min() and max() methods on Stencils in openvdb/math/Stencils.h. [Reported by Samuel Mauch] - Fixed a compilation error that would be encountered when attempting to enable the SSE4.2 or AVX SIMD options on non-x86 based platforms. - Improved support for compiling with C++20. [Contributed by Denys Maletskyy and Jérémie Dumas] - OpenVDB's CMake no longer modifies the BUILD_SHARED_LIBS variable. [Reported by Maksim Shabunin] - Fix int-in-bool-context GCC9+ warnings by switching to use constexpr if. @par @htmlonly @endhtmlonly @par Version 10.0.1 - November 30, 2022 @par Bug Fixes: - Fixed uninitialized point flags in tools::VolumeToMesh which could result in non-deterministic results (bug introduced in 10.0.0). @par Build: - Fixed CXX standard requirement for VDB components in FindOpenVDB.cmake @htmlonly @endhtmlonly @par Version 10.0.0 - October 27, 2022 @par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N.
@par Highlights: - Introducing OpenVDBLink, which provides a Mathematica interface to OpenVDB. This link ports over access to various grid containers including level sets, fog volumes, vector grids, integer grids, Boolean grids, and mask grids. Construction, modification, combinations, visualisations, queries, import, export, etc. can be achieved over grids too. Any Mathematica 3D region that's ConstantRegionQ and BoundedRegionQ can be represented as a level set grid, providing a more seamless integration with OpenVDB. - Introducing a new command-line tool, dubbed vdb_tool, that can combine any number of the high-level tools available in openvdb/tools. For instance, it can convert a sequence of polygon meshes and particles to level sets, perform a large number of operations on these level set surfaces and export them as adaptive polygon meshes. @par OpenVDB: - Improvements: - Significantly improved the performance of all ValueAccessor methods which access LeafNode value buffer data. This improvement applies to any type which is delay load compatible (all default types except for bool and mask grids) and improves the performance of many OpenVDB tools. - Improved the performance of volumeToMesh by 10-15%. - ABI changes: - ABI change to openvdb::RootNode, which now has a new member that defines the origin of the node. For now this origin is set to a default value of (0,0,0), but in the near future we will allow for offsets to improve access performance and reduce the memory footprints. - Removed deprecated virtual methods from AttributeArray. - API changes: - Removed PagedArray::push_back(). - Removed Tree visitor methods from Tree, RootNode, InternalNode and LeafNode classes - visit(), visit2(), visitActiveBBox(). - Removed LeafManager::getNodes(). - Removed tools::dilateVoxels() and tools::erodeVoxels() in favor of tools::dilateActiveValues() and tools::erodeActiveValues(). - Removed tools::FindActiveValues::any() and tools::FindActiveValues::none(). - StringGrid and StringTrees have been removed. - Bug Fixes: - Fixed an issue with tools::topologyToLevelSet which would previously ignore active tiles in the input topology. [Reported by Tobias Rittig] - Fixed a bug with ValueAccessor::addLeaf and ValueAccessor::addTile which wouldn't add the provided leaf nodes to the underlying tree. This bug did NOT affect the specialized accessors which are used by the default tree configuration. [Contributed by Andrey Zakirov] - Fixed a bug where ValueAccessor::probeNode and ValueAccessor:probeConstNode would return a nullptr if the NodeT type was not explicitly being cached by the accessor but the node existed in the tree. - Fixed a bug on Windows where math::Abs could truncate 64bit integer values. [Contributed by Edward Lam] - Fixed an occurrence of undefined behaviour with math::floatToInt32 and math::doubleToInt64. [Reported by Vojtěch Bubník] - Fixed bugs in the sum merge that produced incorrect merged grids when deep-copying the input nodes or when non-zero background grids were being used. - Fixed a bug in FastSweeping where voxels/tiles are left with min/max float values. - Fixed a bug in math/Tuple.h that prevented compilation with VS2017. @par OpenVDB AX: - Improvements: - Major updates to the command line interface of the vdb_ax binary, exposing more controls such as tile streaming, value iterator types and attribute bindings. @par OpenVDB Houdini: - New Features: - Add convex hull activation for VDB Activate SOP (requires 19.5). - Improvements: - Improved SDF activation to use dynamic node manager. - Bug Fixes: - Fixed a bug in VDB Visualize SOP where color values that exceed the range wrap around instead of being clamped. @par NanoVDB: - New Features: - Added nanovdb::IndexGrid that allows for arbitrary voxel values and even multiple channels to be associated with NanoVDB grids. They are more flexible and memory efficient than regular grids at a small cost of random-access performance. IndexGrids are constructed with the new nanovdb::IndexGridBuilder and accessed with the new nanovdb::ChannelAccessor. - Added iterators to all tree node classes for visiting inactive, active, or all values and child nodes. - NanoVDB.h now includes standalone implementations of reading and writing uncompressed nanovdb grids buffers. - Added Stats::getExtrema, which computes the min/max values of all voxels in a NanoVDB grid that intersects with a user-defined bounding-box. - Added nanovdb::Mask::countOn(int) which is essential to the new nanovdb::IndexGrid. - Added RootNode::probeChild and InternalNode::probeChild. - Improvements: - Added a new much improved nanovdb::NodeManager, that is both faster and more memory efficient, and that works on both the CPU and GPU. Note, it uses a handle for allocation (just like nanovdb::Grid) and replaces the old nanovdb::LeafManager which is now deprecated. - NanoToOpenVDB is extended to work with grids templated on Fp4, Fp8, Fp16, FpN, bool and ValueMask. - Renamed RootNode::findTile to RootNode::probeTile and made it public. - Made Mask::getWord return both a const and non-const reference. - Improved unit-tests to use explicit 32B alignment (see alignment bug-fix below). - PNanoVDB.h (a C99 port of NanoVDB.h) has been updated. - Bug Fixes: - Fixed a bug in nanovdb::HostBuffer that could produce crashes due to misaligned CPU memory allocations. - Fixed bug related to uninitialized memory in nanovdb::Grid which could confuse CRC32 checksum validation. - Fixed bugs related to the use of intrinsic functions for fast bit-counting in nanovdb. - Fixed a potential security vulnerability in NanoVDB.h related to buffer overflow exploits. @par Build: - Added OPENVDB_USE_DELAYED_LOAD flag that enables delayed loading and defaults to on. - Add a placeholder to inject the specific revision and URL used to build OpenVDB, useful for 3rd party build scripts to publish their exact versions. - Fixed an issue where OPENVDB_AX_DLL was not being defined on shared library builds of AX, resulting in symbols not being exported. [Reported by Ray Molenkamp] - Fixed an issue where setting Tbb_INCLUDE_DIR could cause CMake failures. - Updated FindTBB.cmake to support newer library ABI suffixing in TBB 2021.5. - Updated FindBlosc.cmake to better handle cases where blosc is built with external sources. - Resolved LLVM deprecation warnings in AX and added support for LLVM 14. - On Windows (MSVC), OpenVDB is now built with extra compiler options to ensure stricter C++ conformance: /permissive- /Zc:throwingNew /Zc:inline. - On Windows (MSVC), the _USE_MATH_DEFINES macro is no longer defined when including (or any dependent headers). If you were relying on this in your own project for M_PI, M_PI_2, etc. you can add -D_USE_MATH_DEFINES to your own project compiler options. See this page for more info. @htmlonly @endhtmlonly @par Version 9.1.0 - June 9, 2022 @par Bug Fixes: - Minor fix to move assignment operator in nanovdb/util/HostBuffer.h. This could potentially be a problem on Windows debug builds (unconfirmed). - Minor fix to range in openvdb/tools/LevelSetSphere.h. This could result in data races for multi-threaded execution (unconfirmed) [Reported by Tommy Hinks] - Fixed a bug with Tree::combineExtended which wouldn't propagate the resulting active state when a destination tile overlapped a source child node. [Reported by \@frapit] - Fix unit tests failures with Blosc versions >= 1.19.0. - Fixed a regression in ax::run which wouldn't propagate exceptions - Fixed a bug where ax::ast::parse could return a partially constructed but invalid AST on failure - Fixed AX logger exit handling in ax::Compiler::compile and ax::ast::parse - Fixed an issue which could result in significant compilation times when instantiating TypeList<>::Unique<> @par New features: - Added support for AMD's HIP API in NanoVDB [Contributed by Blender Foundation] - Added bindings mechanism to AX to allow differing data and AX attribute names (@) in Point and Volume executables. - Added support for OpenVDB AX on Windows. - Added tools::memUsageIfLoaded() which returns the memory consumption of a deserialized VDB tree, useful if delay-loading is enabled. - Added points::rasterizeSpheres() and points::rasterizeSmoothSpheres() variants, new kernels and improved performance for OpenVDB points to surface rasterization. - Added points::rasterizeTrilinear() for OpenVDB points, fast staggered or colocated trilinear rasterization for scalar and vector attributes. - Exposed TypeList declarations in openvdb.h which denote the default set of types supported by OpenVDB. - Added points::FrustumRasterizer for efficient rasterization of OpenVDB points to frustum volumes with optional motion blur. @par Improvements: - Added a --thread [n] argument to the vdb_ax binary. - Added a --copy-file-metadata option to vdb_ax. This behaviour is now off by default. - Added support for multiple input files with the vdb_ax binary using -i. Positional arguments as input files are deprecated. - Added tools::minMax() which supports multithreaded evaluation of active minimum and maximum values. Grid::evalMinMax() has been deprecated. [Contributed by Greg Hurst] - Significant performance improvements to AX point kernels, primarily due to providing AX access to attribute buffers for superior code generation. - vdb_print now prints both the in-core memory and total memory usage for VDB grids. - Improved build support for MinGW [Contributed by Mehdi Chinoune] - Added a new foreach method to TypeList for iterating over types without constructing them. - Added TypeList::Transform declaration for transforming TypeLists into new types. - Moved Grid::apply implementation to TypeList::apply to allow for other polymorphic types to invoke it. - Minor updates to NanoVDB to remove compiler warnings. @par Build: - Regenerated AX grammar with Flex 2.6.4 and Bison 3.8.2. - Improved locating NumPy in CMake when multiple python versions are installed. - Fixed an issue which could report Python as missing when using CMake 3.18 and later on some systems. [Reported by Sam James] - Changed the way boost_python and boost_numpy are located. Both components must match the major/minor version of python in use. This can be circumvented by providing Boost_PYTHON_VERSION or Boost_PYTHON_VERSION_MAJOR. - Relocated OpenVDB binaries to a new openvdb_cmd root directory. - FindTBB.cmake now prioritises newer TBB installations. - Added option to compress PDB data in MSVC debug builds. @par Houdini: - Added Attribute Bindings to AX SOP to allow differently named AX attributes (@) and target point attributes/volumes. - Fix race condition in OpenVDB Merge SOP that could cause crashes or merged VDBs to not be deleted. - VDB Activate SOP no longer stops at the first non-VDB primitive, but instead just skips such primitives. - Added VDB Rasterize Frustum SOP for efficient rasterization of OpenVDB points into frustum volumes with optional motion blur. @htmlonly @endhtmlonly @par Version 9.0.0 - October 29, 2021 @par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 7 for Houdini 18.5 and 8 for Houdini 19.0.
@par
Official release of NanoVDB, which for the first time offers GPU support for static sparse volumes in OpenVDB. See the documentation for details.
@par New features: - Faster build times from support for explicit template instantiation, which is enabled by default for most of the tools. - Added support for OpenEXR 3 and TBB 2021. - Added transient data to the RootNode, InternalNode, and LeafNode. @par Improvements: - Added tools::countActiveLeafVoxels(), tools::countInactiveVoxels(), tools::countInactiveLeafVoxels() and tools::activeTiles() to perform multi-threaded counting. The Tree methods now use these implementations. - Moved from the deprecated TBB task scheduler to TBB arenas. Various methods now respect the TBB arena state they were invoked from. - Introduced a new thread/Threading.h header to consolidate calls to third-party threading methods. - Minor performance improvements to dilation calls in fast sweeping algorithms. - Added hsvtogrb() and rgbtohsv() AX helper functions for converting hue, saturation and value inputs to RGB values and vice-versa. - PointDataGrid conversion can now be performed using 32-bit float arrays. - Improved support for size_t grid types on systems where size_t is a unique type. [Contributed by Brecht Van Lommel] - Add support for dilation in one direction and extending a field in one direction in fast sweeping algorithms. - Added PNG support to vdb_render which can be enabled with during CMake with -DUSE_PNG=ON. - Explicit template instantiation has been enabled by default for most of the tools. This pre-compiles template instantiations into the core library to reduce the time spent compiling code in downstream libraries or applications. - Added a python binding for OpenVDB AX which allows you to invoke accelerated AX code from the python module. @par Bug Fixes: - Fixed a bug where ax::run() would crash if it could not parse a single statement. @par ABI changes: - Added transient data to the RootNode, InternalNode, and LeafNode. @par API changes: - DynamicNodeManager can now set one grain size for threading across leaf nodes and another for threading across non-leaf nodes. - StringGrid and StringTrees are deprecated. - The NullInterrupter is now a virtual base class to help reduce compile-time instantiation cost. @par Houdini: - Fix crash in VDB Combine in Copy B mode if the second input has more VDBs than the first. - VDB Vector Merge SOP is now VDB Vector From Scalar SOP to distinguish it from the VDB Merge SOP. It keeps the same internal name so this is merely a label change. - Add option to pass in OPENVDB_DSO_NAMES to CMake to configure which Houdini DSOs are compiled. - VDB Activate SOP now has an option for the expansion pattern to use for dilation. - The label for Voxels to Expand is now Expand Voxels to match Houdini. - Fix bug to allow VDB LOD SOPs to be chained together. - SOP Extrapolate supports dilation in one direction and extending a field in one (domain) direction. - The default OpenVDB ABI is now 8 for Houdini versions > 18.5. - VDB Visualize Tree SOP is now multi-threaded and provides slicing and color remapping. - A new HoudiniInterrupter has been added that derives from the NullInterrupter and the Interrupter is now deprecated. All the SOPs have been updated to use the new HoudiniInterrupter. - Add a sanitizer in SOP OpenVDB Extrapolate when expanding a narrow-band level-set with a dilation value of 0, which will result in no operation. @par Build: - Added support for TBB 2021. - Enabled the OPENVDB_FUTURE_DEPRECATION variable by default to warn on upcoming deprecations. - Introduced a OPENVDB_DOXYGEN_INTERNAL CMake variable which is ON by default and removes the majority of internal namespaces from the generated doxygen. - Improved the doxygen deprecation listings, folder layouts and fixes issues when using later versions of doxygen. - Build fixes for MinGW on Windows. [Contributed by Brecht Sanders] - Added support for OpenEXR 3. [Contributed by Cary Phillips] - Added an OPENVDB_NAMESPACE_SUFFIX CMake string option which provides the ability to customise the VDB namespace. - The Python Module now appends the base directory defined by Python_SITELIB to the default install path (typically dist-packages or site-packages). [Contributed by Ignacio Vizzo] - As of this release, VFX Reference Platform 2019 is no longer supported. CMake now issues deprecation warnings for 2020 VFX Reference Platform version dependencies. - Build fixes for OpenVDB AX with C++17 and greater. - Bumped the new blosc version future minimum to 1.17.0. - OpenEXR is now optional for vdb_render. It can be enabled with -DUSE_EXR=ON. @htmlonly @endhtmlonly @par Version 8.2.0 - November 24, 2021 @par
Added support for TBB 2021.
@par
Added support for OpenEXR 3. This is contributed by Cary Phillips.
@par Improvements: - Added tools::countActiveLeafVoxels(), tools::countInactiveVoxels(), tools::countInactiveLeafVoxels() and tools::activeTiles() to perform multi-threaded counting. The Tree methods now use these implementations. - Moved from the deprecated TBB task scheduler to TBB arenas. Various methods now respect the TBB arena state they were invoked from. - Introduced a new thread/Threading.h header to consolidate calls to third-party threading methods. - Minor performance improvements to dilation calls in fast sweeping algorithms. - Added hsvtogrb() and rgbtohsv() AX helper functions for converting hue, saturation and value inputs to RGB values and vice-versa. - PointDataGrid conversion can now be performed using 32-bit float arrays. - Improved support for size_t grid types on systems where size_t is a unique type. [Contributed by Brecht Van Lommel] - Minor performance improvements to dilation calls in fast sweeping algorithms. - Add support for dilation in one direction and extending a field in one direction in fast sweeping algorithms. @par API changes: - DynamicNodeManager can now set one grain size for threading across leaf nodes and another for threading across non-leaf nodes. @par Houdini: - Fix crash in VDB Combine in Copy B mode if the second input has more VDBs than the first. - VDB Vector Merge SOP is now VDB Vector From Scalar SOP to distinguish it from the VDB Merge SOP. It keeps the same internal name so this is merely a label change. - Add option to pass in OPENVDB_DSO_NAMES to CMake to configure which Houdini DSOs are compiled. - VDB Activate SOP now has an option for the expansion pattern to use for dilation. - The label for Voxels to Expand is now Expand Voxels to match Houdini. - Fix bug to allow VDB LOD SOPs to be chained together. - SOP Extrapolate supports dilation in one direction and extending a field in one (domain) direction. - The default OpenVDB ABI is now 8 for Houdini versions > 18.5. - VDB Visualize Tree SOP is now multi-threaded and provides slicing and color remapping. - Add a sanitizer in SOP OpenVDB Extrapolate when expanding a narrow-band level-set with a dilation value of 0, which will result in no operation. @par Build: - Added support for TBB 2021. - Enabled the OPENVDB_FUTURE_DEPRECATION variable by default to warn on upcoming deprecations. - Introduced a OPENVDB_DOXYGEN_INTERNAL CMake variable which is ON by default and removes the majority of internal namespaces from the generated doxygen. - Improved the doxygen deprecation listings, folder layouts and fixes issues when using later versions of doxygen. - Build fixes for MinGW on Windows. [Contributed by Brecht Sanders] - Added support for OpenEXR 3. [Contributed by Cary Phillips] - Added an OPENVDB_NAMESPACE_SUFFIX CMake string option which provides the ability to customise the VDB namespace. - The Python Module now appends the base directory defined by Python_SITELIB to the default install path (typically dist-packages or site-packages). [Contributed by Ignacio Vizzo] @htmlonly @endhtmlonly @par Version 8.1.0 - June 11, 2021 @par
As of this release, support for grid ABI=5 has been removed.
@par New features: - Added @vdblink::tools::erodeActiveValues() tools::erodeActiveValues@endlink, to match the existing @vdblink::tools::dilateActiveValues() tools::dilateActiveValues@endlink. New erosion tools support all tile policies and edge/vertex neighbor patterns. - Added support for automatic filtering of active tiles in @vdblink::tools::Filter Filter@endlink by setting @vdblink::tools::Filter::setProcessTiles Filter::setProcessTiles@endlink. Active tiles are densified on demand, only when necessary. - Added tools::visitNodesDepthFirst and tools::DepthFirstNodeVisitor which visit nodes in a tree or sub-tree in single-threaded depth-first order. - Significant performance improvements to AX volume kernels, primarily due to improved vectorization. Performance scales depending on the available host CPU instruction set and scalability of the AX kernel. Trivial assignments profile upwards of 3x faster on AVX. - Introduced Active Tile Streaming for volumes kernels. AX can now dynamically expand and collapse active nodes at all levels of a VDB tree on demand, switching on or off by checking the spatial access pattern of AX programs. - Added tools::countActiveVoxels() for multi-threaded counting of active voxels, optionally by bounding box. The Tree::activeVoxelCount() method now uses this implementation. - Added tools::memUsage() for multi-threaded counting of bytes of memory used. The Tree::memUsage() method now uses this implementation. - Added tools::SumMergeOp that uses a parallel breadth-first algorithm to accelerate summing grids. @par Improvements: - Significant performance improvements to large dilations with @vdblink::tools::dilateActiveValues() tools::dilateActiveValues@endlink. Performance gains will improve relative to increases in the inputs size and dilation scheme. - Added an optional argument to @vdblink::tree::Tree::topologyUnion() Tree::topologyUnion@endlink which preserves active tiles on the destination tree should they overlap leaf nodes from the source tree. - Reduced the time spent in the hot path of @vdblink::initialize() initialize@endlink and @vdblink::uninitialize() uninitialize@endlink by leveraging atomics with double-checked locks. [Contributed by Ben FrantzDale] - Extended @vdblink::tree::DynamicNodeManager DynamicNodeManager@endlink to allow for use with a const tree. - Replace tbb::mutex with std::mutex and tbb::atomic with std::atomic as these have now been removed in TBB 2021. [Contributed by Ben FrantzDale]. - Significant performance improvements to @vdblink::tools::activate() tools::activate@endlink and @vdblink::tools::deactivate() tools::deactivate@endlink through use of the DynamicNodeManager to parallelize tile processing. - Added degree() and radians() AX helper functions for converting radians to degrees and vice versa, respectively. - Added adjoint(), cofactor() and inverse() AX matrix functions. - Added sort(), argsort(), isfinite(), isinf() and isnan() AX utility and math functions. - Added Vec4 argument support to normalize() AX function. - Removed unused int16 AX modulo function signatures. - Refactored the backend AX representation of strings with SSO support and heap allocation. - Added new methods on the VolumeExecutable to control active tile streaming and node execution levels - The deletepoint() AX function is now natively supported by the PointExecutable - vdb_view: Fixed a bug which wouldn't reset the camera speed on focus - vdb_view: Improved the drawing of PointDataGrids - vdb_view: Improved the exception handling of BufferObjects and added support for drawing an array without index values @par Bug Fixes: - Fix a memory leak in AttributeArray when delayed-loading is disabled. - Fixed a crash in OpenVDB AX when declaring arrays with non-scalar elements (unsupported) i.e. {"foo", 1, 2}, {1, {1,2}, 3} etc. - Fixed a bug in OpenVDB AX which would cause an error when multiplying a vec3 by a mat4. - In OpenVDB AX, improved the error message produced when attempting to use a matrix literal (i.e. {1,2,3...}) in a binary expression (this is invalid but would previously print out bad IR). - Fixed a non-deterministic failure in the TestStreamCompression unit test. - Use copy-by-reference for the operator in a @vdblink::tree::DynamicNodeManager DynamicNodeManager@endlink to fix a performance regression. - @vdblink::tools::deactivate() tools::deactivate@endlink now also works with a MaskTree. - Fixed a memory leak in the OpenVDB AX parser - Fixed an occurrence of undefined behavior in the OpenVDB AX visitor - Fixed some memory leaks in the OpenVDB and OpenVDB AX unit tests - Fixed a bug in AX which could cause string allocations in loops to overflow the stack - Fixed a bug where the ValueOff iterator for the AX VolumeExecutable could remove child branches of a VDB tree. - Fixed a crash in the AX Houdini SOP with an empty PointDataGrid input. - Fixed all cases where PointIndex and PointData aliases were used instead of a templated type. [Reported by Karl Marrett] - Fixed a crash when calling openvdb::points::pointOffsets with an empty PointDataGrid input. - Add missing 8-bit and 16-bit attribute type registration. @par API changes: - Restructured the internals of Morphology.h and moved @vdblink::tools::activate() tools::activate@endlink and @vdblink::tools::deactivate() tools::deactivate@endlink to a new header, Activate.h. - Deprecated tools::dilateVoxels() and tools::erodeVoxels() in favour of new morphology methods. - The @vdblink::tools::Film tools::Film@endlink class no longer has a saveExr method in any build configuration. Sample code for saving exrs from this object can be found in the command line render tool. - Added ability to run @vdblink::tools::activate() tools::activate@endlink and @vdblink::tools::deactivate() tools::deactivate@endlink single-threaded. @par Houdini: - Updated the VDB Activate SOP and others to use the multi-threaded implementation for voxel dilation, providing a significant performance increase. - Introduced the VDB AX SOP which provides an interface for running OpenVDB AX code in Houdini on VDB grids. - Updated the VDB Smooth SOP to support the filtering of active tiles. - Fixed a parameter warning in VDB AX SOP. - Transfer Surface Attributes in Convert VDB SOP could use uninitialized memory. - VDB Activate SOP now uses the multi-threaded @vdblink::tools::deactivate() tools::deactivate@endlink for much faster performance. - Improved the formatting and updated the OpenVDB AX SOPs help card. - The AX SOP utilizes the new Active Tile Streaming feature for Volumes. Grids will only be densified in areas where unique values are created. - VDB Activate SOP dilation will affect tiles, changing its behavior from previous versions, but producing a more expected result. - VDB Activate SOP has a world space dilation option. - Introduced the VDB Merge SOP that merges multiple grids in parallel and is faster and more convenient to use than the VDB Combine SOP. - Fix a bug where the VDB Rebuild SDF was not preserving metadata from the input grid. - Fix a bug in VDB Resample SOP where input transform was not being used for voxel size and voxel scale transform modes. @par Build: - Dependency on OpenEXR's Half implementation has been removed from the core library by naturalizing the implementation into openvdb::math. This is fully bitwise compatible, but may require switching Half references to math::Half. The USE_IMATH_HALF build configuration can be used to switch back to OpenEXR based half. - Blosc, Log4cplus, IlmBase, OpenEXR and TBB find modules now configure release and debug library variants. [Reported by Matthew Cong] - Fixed an issue where FindBlosc wouldn't add zstd as a dep in non static builds BLOSC_USE_EXTERNAL_SOURCES. - Fixed Log4cplus interface language and missing interface libraries on Win32. - Removed Jemalloc and Tbbmalloc logic from the core library builds. - The variable CMAKE_MSVC_RUNTIME_LIBRARY is no longer set by the OpenVDB CMake. If CMAKE_MSVC_RUNTIME_LIBRARY is not explicitly provided, OpenVDB configures the static library with /MT(d) and the dynamic library with /MD(d). [Reported by Jérémie Dumas] - Added support for ABI=9 and a CMake option OPENVDB_USE_FUTURE_ABI_9 to use it without errors. - The value of CONCURRENT_MALLOC is now respected when building the vdb_ax command line binary. - Added an option OPENVDB_ENABLE_UNINSTALL to allow the toggling of the uninstall build target. [Contributed by Jérémie Dumas] - Improved the behavior of locating static zlib libraries when USE_STATIC_DEPENDENCIES is enabled. - Fixed an issue where extra hboost libraries could not be found when building against Houdini 18.5 on Windows. - Build fixes to OpenVDB AX for LLVM 12. - Re-introduced the OPENVDB_DEPRECATED macro with an additional option that takes a message. Added support to disable deprecations throughout OpenVDB by defining OPENVDB_NO_DEPRECATION_WARNINGS - Added an optional OPENVDB_TESTS variable to easily build a subset of the unit tests. - Fixed various incorrect RPATH directory paths in CMake (introduced in 8.0.1) [Contributed by Ignacio Vizzo]. - Removed some unnecessary CMake for vdb_view - The Windows defines NOMINMAX and _USE_MATH_DEFINES are now provided in Platform.h. - Moved the logic from PlatformConfig.h into Platform.h. - The version.h header is now an auto generated header (version.h.in) populated by CMake. The OpenVDB Version and ABI defines are computed from the installation settings. Importantly, the value of OPENVDB_ABI_VERSION_NUMBER now always matches the version used at build time. - Added OPENVDB_USE_HALF, OPENVDB_USE_BLOSC and OPENVDB_USE_ZLIB as publicly available defines in version.h. These will be defined depending on the settings used to build OpenVDB. @htmlonly @endhtmlonly @par Version 8.0.1 - February 5, 2021 @par Bug fixes: - Fixed a bug in the new CSG intersection merge algorithm where data outside of the intersection region was not being removed. @par Build: - Fixed various incorrect RPATH directory paths in CMake - Dropped the minimum boost requirement back to 1.61. - Documentation installed by the doc target is now installed to the share/doc/OpenVDB prefix @par Houdini: - VDB Combine SOP no longer attempts to invoke SDF CSG operations on bool grids because unary negation is undefined on bools in the template expansion. @htmlonly @endhtmlonly @par Version 8.0.0 - December 23, 2020 @par
This version introduces ABI changes relative to older major releases, so to preserve ABI compatibility it might be necessary to define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 6 for Houdini 18.0 and 7 for Houdini 18.5.
@par
Official release of OpenVDB AX, a new C++ library that implements a domain specific JIT (just-in-time) compiled expression language, providing users with a new way of interacting with OpenVDB data. AX is tailored towards writing highly parallelizable and customizable OpenVDB volume and point kernel operations. See the documentation for more.
@par New features: - Added @vdblink::tools::anyActiveVoxels tools::anyActiveVoxels@endlink and @vdblink::tools::anyActiveTiles tools::anyActiveTiles@endlink that check if respectively active voxels or tiles in a tree intersect a given CoordBBox. - Added @vdblink::tools::activeTiles tools::activeTiles@endlink that returns a vector containing all the active tiles in a tree that intersects a given CoordBBox. @par Improvements: - Made LeafManager class non-virtual. @par Bug fixes: - Fixed a determinism bug in @vdblink::tree::NodeManager NodeManager@endlink when using non-thread-safe functor members. - Fix @vdblink::tools::GridTransformer grid transformer tool@endlink construction to use correct rotate-scale-translate order when recomposing matrix components. [Contributed by Tom Cnops] - OpenVDB AX: Fixed a potential code generation crash in binary, ternary or comma operators when errors occurred in first operand. @anchor v8_0_0_ABI_changes @par ABI changes: - @vdblink::Grid::isTreeUnique() Grid::isTreeUnique@endlink is now virtual as of ABI=8 so that it can be accessed from the GridBase. - Private method RootNode::getChildCount() has been removed as of ABI=8. - Mark map classes and functions as final for ABI=8 where beneficial to allow devirtualization optimization. - As of ABI 8, Vector, Matrix and Quaternion types now satisfy the Trivial Type requirement. Their empty constructors and copy constructors have been removed (and are left to the compiler to define). - As of ABI 8, removed an unnecessary specialization of NodeUnion and CopyTraits from NodeUnion.h. Replaced std::is_pod usage with std::is_trivially_copyable which allows more types to benefit from the union storage. - As of ABI 8, PointDataGrids use the union NodeUnion specialization, reducing the memory footprint of their topology by 50%. @par API changes: - Removed a number of deprecated point, volume and AX methods. @par Houdini: - VDB to Spheres SOP doesn't reset the radius when in worldspace mode. VDB Write SOP should likewise not reset the compression values. @par Build: - As of this release, VFX Reference Platform 2018 is no longer supported. CMake now issues deprecation warnings for 2019 VFX Reference Platform version dependencies, with the exception that OpenEXR/IlmBase 2.2 is still supported. - Added a missing header include to resolve an undefined size_t build error on GCC10. - Improved the python module's linkage with the CMake 3.15 Python::Module target. Explicitly linking with the Development target could result in crashes, particularly on macOS. [Reported by Alexander Hagen] - Removed OPENVDB_DEPRECATED macro in favor of C++14 [[deprecated]] attribute. @htmlonly @endhtmlonly @par Version 7.2.3 - @par Bug fixes: - Use copy-by-reference for the operator in a DynamicNodeManager to fix a performance regression. @htmlonly @endhtmlonly @par Version 7.2.2 - February 4, 2021 @par Bug fixes: - Fixed a bug in the new CSG intersection merge algorithm where data outside of the intersection region was not being removed. - Fix @vdblink::tools::GridTransformer grid transformer tool@endlink construction to use correct rotate-scale-translate order when recomposing matrix components. [Contributed by Tom Cnops] @par Houdini: - VDB Combine SOP no longer attempts to invoke SDF CSG operations on bool grids because unary negation is undefined on bools in the template expansion. - VDB to Spheres SOP doesn't reset the radius when in worldspace mode. VDB Write SOP should likewise not reset the compression values. @htmlonly @endhtmlonly @par Version 7.2.1 - December 23, 2020 @par Bug fixes: - Fixed a determinism bug in @vdblink::tree::NodeManager NodeManager@endlink when using non-thread-safe functor members. @par Build: - Added a missing header include to resolve an undefined size_t build error on GCC10. @htmlonly @endhtmlonly @par Version 7.2.0 - December 9, 2020 @par New features: - Added @vdblink::tree::DynamicNodeManager DynamicNodeManager@endlink that lazily caches the nodes at each level of the tree to allow for efficient threading of topology-changing top-down workflows. - Added @vdblink::tools::CsgUnionOp CsgUnionOp@endlink, @vdblink::tools::CsgIntersectionOp CsgIntersectionOp@endlink and @vdblink::tools::CsgDifferenceOp CsgDifferenceOp@endlink that use a parallel breadth-first algorithm to accelerate CSG union, intersection and difference operations. - Added @vdblink::tools::TreeToMerge TreeToMerge@endlink which provides methods to steal or deep-copy from a tree based on the tag dispatch class used in its construction. - Pre-release of OpenVDB AX, an open source C++ library that provides a powerful and easy way of interacting with OpenVDB volume and point data. @par Improvements: - util::CpuTimer now uses C++11 chrono instead of TBB. - Threaded the construction of LeafManager and NodeManager linear arrays. - @vdblink::tools::csgUnion() csgUnion@endlink, @vdblink::tools::csgIntersection() csgIntersection@endlink and @vdblink::tools::csgDifference() csgDifference@endlink now use the new parallel breadth-first algorithms for much faster performance. - Extended @vdblink::tree::NodeManager NodeManager@endlink to allow for use with a const tree. - Added @vdblink::math::Abs Abs@endlink, @vdblink::math::cwiseAdd cwiseAdd@endlink, @vdblink::math::cwiseLessThan cwiseLessThan@endlink and @vdblink::math::cwiseGreaterThan cwiseGreaterThan@endlink methods for Matrix types. Matrix grids can now be instantiated. @par Houdini: - Fixed a bug in the OpenVDB Points Convert SOP where the auto voxel transform was ignoring the contents of packed geometry. - Fixed a bug in the OpenVDB Points Convert SOP where points representing packed geometry were also being converted. - Fixed a bug where a Houdini SOP's verb would not be correctly associated with the corresponding node if the node's internal name was changed. - Fixed bug where OpenVDB Convert SOP could revert the name attribute. @par Bug Fixes: - Fixed a bug which could cause recursive compile time instantiations of TypeList objects, manifesting in longer compile times. - Deprecated util::PagedArray::push_back due to a race condition. Instead use util::PagedArray::ValueBuffer::push_back which is faster and thread-safe. - Fixed various cases of undefined behavior in some LevelSetUtil methods [Reported by fkemmler] @par API changes: - Deprecated tree::LeafManager::getNodes. This method is no longer used when constructing a NodeManager from a LeafManager. - Deprecated Tree::visitActiveBBox, Tree::visit and Tree::visit2 methods in favor of using a tree::DynamicNodeManager. - Removed tools::CsgVisitorBase, tools::CsgVisitorUnion, tools::CsgVisitorIntersection and tools::CsgVisitorDifference. The CSG tools now use the parallel breath-first algorithms. - Moved openvdb::TypeList from Types.h into its own header TypeList.h @par Build: - Removed the Makefiles. - Re-organised the repository layout such that each independent library is able to be configured against an existing installation of OpenVDB without ambiguous include paths. - Upgraded CMake minimum version support to 3.12. - Removed OPENVDB_STATIC_SPECIALIZATION macro which is no longer required. - Fixed various compiler warnings for GCC 9.1. - Moved to CMake doxygen commands and removed the doxygen-config files for doxygen documentation. - Added USE_ZLIB compiler flag that enables zlib compression and defaults to on. - Added the OPENVDB_STATICLIB define to all static builds to fix builds on Windows which use the multithread/DLL-specific version of the CRT. [Reported by Tobias Rittig] - Core library unit tests use GoogleTest instead of CppUnit. @htmlonly @endhtmlonly @par Version 7.1.0 - August 13, 2020 @par
As of this release, support for grid ABI=4 has been removed.
@par New features: - Added a novel parallel sparse @vdblink::tools::FastSweeping tools::FastSweeping@endlink class that outperforms our existing techniques for computing signed distance fields in addition to supporting velocity extension. - Added @vdblink::tools::fogToSdf tools::fogToSdf@endlink which converts a scalar (fog) volume into a signed distance. - Added @vdblink::tools::sdfToSdf tools::sdfToSdf@endlink which re-normalizes a signed distance field; - Added @vdblink::tools::fogToExt tools::fogToExt@endlink which extends an arbitrary field (e.g. velocity) off the iso-surface of a scalar (fog) volume. - Added @vdblink::tools::sdfToExt tools::sdfToExt@endlink which extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added @vdblink::tools::fogToSdfAndExt tools::fogToSdfAndExt@endlink which computes a signed distance and extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added @vdblink::tools::fogToSdfAndExt tools::fogToSdfAndExt@endlink which re-normalizes a signed distance and extends an arbitrary field (e.g. velocity) off the iso-surface of a signed distance field. - Added @vdblink::tools::dilateSdf tools::dilateSdf@endlink which dilates a signed distance field. - Added @vdblink::tools::maskSdf tools::maskSdf@endlink which extends an existing signed distance into a user-defined mask. - Added @vdblink::Grid::isTreeUnique() Grid::isTreeUnique@endlink to tell if the tree is shared with another grid. - Added @vdblink::points::PointDataLeafNode::stealAttributeSet() PointDataLeafNode::stealAttributeSet@endlink and @vdblink::points::AttributeSet::removeAttribute() AttributeSet::removeAttribute@endlink for releasing ownership of attribute data. - Added AttributeSet::Descriptor::groupIndexCollision for detecting group index collisions when attempting to merge two Descriptors. - Added @vdblink{tree::RootNode::childCount,RootNode::childCount}, @vdblink{tree::InternalNode::childCount,InternalNode::childCount} and @vdblink{tree::LeafNode::childCount,LeafNode::childCount} to count the number of immediate child nodes that exist below the current node. @par Improvements: - Added GroupWriteHandle::setUnsafe() for faster performance when the group array is known to be in-core and non-uniform. - Add support for default value metadata when creating AttributeArrays or appending to an AttributeSet. - Added new group inspection methods to the @vdblink::points::AttributeSet::Descriptor AttributeSet::Descriptor@endlink. - Introduced a @vdblink::points::StringMetaCache StringMetaCache@endlink class for convenient string attribute metadata lookup and performed some minor optimizations. - Removed redundant floor in @vdblink::points::floatingPointToFixedPoint floatingPointToFixedPoint@endlink. - Add gitignore to repository root. - Removed some logic for compilers older than Visual Studio 2019. - Add a new Houdini ABI test binary. - Fixed an indexing typo in tools::Filter. [Contributed by Yuanming Hu] - Removed redundant null pointer checks. [Contributed by Kuba Roth] - Added support for vdb_view on Windows. Requires GLEW. - Removed support for GLFW 2. - vdb_view now uses OPENVDB_LOG_FATAL when catching exceptions. - vdb_view, vdb_print and vdb_render now use std::terminate() when catching an unknown exception. - Removed Boost::thread as a dependency of vdb_view in favour of std::thread. - Removed usage of boost/integer.hpp and boost/math/constants/constants.hpp, the latter in favour of new openvdb math constants for pi - Removed usage of boost/mpl/\*.hpp methods in favour of new template meta-programming methods on the @vdblink::TypeList TypeList@endlink struct. This now supports get, front, back, contains, index, unique, popback, popfront and range removal of types. - Changed the @vdblink::tree::NodeChain tree::NodeChain@endlink implementation to use an @vdblink::TypeList TypeList@endlink rather than a boost::mpl::vector and updated all usage of @vdblink::tree::NodeChain tree::NodeChain@endlink accordingly. @par Bug fixes: - Fixed a bug where grids with no active values might return true when the method evalActiveVoxelBoundingBox is called. The correct behavior is to only return true if the grid contains any active values. - Fixed a sign propagation bug in @vdblink::tools::traceExteriorBoundaries() tools::traceExteriorBoundaries@endlink used by @vdblink::tools::meshToVolume() tools::meshToVolume@endlink. This could cause values to not be propagated across node boundaries, leading to voxels incorrectly being marked as inside the isosurface. [Contributed by Tristan Barback] - Fixed a rotation order bug in the @vdblink::tools::local_util::decompose() decompose@endlink utility that caused it to fail to decompose some matrices. - Fixed a bug where @vdblink::math::Quat::inverse() Quat::inverse@endlink was not marked as const. [Contributed by Michael Tao] - Fixed a bug in the unit test for util::CpuTimer on Windows by using a more accurate sleep implementation. - Fixed a bug where the requested uniform value of an @vdblink::points::AttributeArray AttributeArray@endlink was not being applied on attribute creation if the default attribute value was not the default value for that value type. - Fixed a compiler error when using C++17 by changing std::unexpected() to std::terminate(). [Contributed by Mark Sisson] @par API changes: - Removed a number of deprecated point methods. - points::StringIndexType is now deprecated, use @vdblink::Index Index@endlink instead. - @vdblink{tools::PointPartitioner::voxelOffsets(),PointPartitioner::voxelOffsets} now returns a std::unique_ptr instead of a boost::scoped_array. - Renamed AttributeSet::Descriptor::nextUnusedGroupOffset() to AttributeSet::Descriptor::unusedGroupOffset() to allow for providing an optional group offset hint. @par Houdini: - Platonic SOP is now verbified. - Extend all SOP references to support VDB Points. - Combine SOP will not error in flatten-all mode if second has no grids. - Changed the label (but not the opname) of Resize Narrow Band SOP to match the corresponding native Houdini SOP. The new label is Activate SDF. - Fixed a bug by using @c GEO_Detail::getBBox() instead of @c GEO_Detail::computeQuickBounds() as the latter was incorrectly using the point of the VDB when computing bounding box. SOPs affected include Clip, Fill, Points Group, Rasterize Points, Read, Remove Divergence. [Contributed by Kuba Roth] - OpenVDB from Polygons SOP now always displays the vector UI, as otherwise it might be stuck hidden if the input hasn't cooked. - OpenVDB from Polygons and OpenVDB from Particles SOPs no longer require input geometry to have been cooked to offer a choice of attributes, the user may now also type in a value. @par Build: - Improved the CMake build for the OpenVDB Houdini library on Windows. [Reported by Ian Woodward] - Remove some logic for compilers older than Visual Studio 2019. - Fixed a bug in the CMake FindIlmBase/OpenEXR modules which could cause compilers on UNIX systems to fail to find stdlib.h if IlmBase/OpenEXR headers were installed to /usr/include. - CMake now checks the minimum supported MSVC compiler for Windows. - CMake now only requires a CXX compiler. - Improved the Windows README instructions and various MSVC warnings. - Remove CMake warning when using GLFW 3.2+ on Debian. - Various fixes to unary minus on unsigned compiler warnings. - The defines _CRT_NONSTDC_NO_WARNINGS and _CRT_SECURE_NO_WARNINGS are now enabled by default with MSVC. - New CMake option OPENVDB_BUILD_PYTHON_UNITTESTS to disable or enable the python module tests and fixed the required environment for them on Windows. The python interpreter is no longer required by default if the tests are disabled. - Improved the CMake user messages when locating python and numpy. - The python module extension is now .pyd on Windows. - Fixed some build issues with the Houdini plugin on Windows. - Standardized the library components install paths for the OpenVDB Houdini shared library. - Added a USE_PKGCONFIG option to CMake to optionally disable use of pkg-config. [Contributed by Kartik Shrivastava] - Standardized the dependency search paths in FindPackage modules using GNU install paths. - Added better library type detection of dependencies through FindPackage modules on UNIX. - Added missing TBB, OpenEXR and IlmBase defines for static builds on Windows through the relevant FindPackage modules. - Improved the logic in FindOpenVDB for static builds. - Fixed a compiler warning on Apple Clang 11.0 where the @vdblink::points::AttributeArray AttributeArray@endlink move constructor was being implicitly deleted despite being marked default. - Added an option BLOSC_USE_EXTERNAL_SOURCES to FindBlosc to include blosc dependencies as interface libraries. - Added a root CMake option USE_STATIC_DEPENDENCIES to force CMake to only locate static libraries on UNIX. On Windows, if enabled, located libraries are assumed to be static. - Added support for CMAKE_MSVC_RUNTIME_LIBRARY for compilers that target the MSVC ABI. Requires CMake 3.15 or greater. - Fixed an issue where OPENVDB_OPENEXR_STATICLIB was not being defined and OPENEXR_DLL was being defined when linking against static builds of OpenEXR/IlmBase on Windows. - Improved the behaviour of boost implicit linking with the Boost::disable_autolinking target. - Added support for importing pyopenvdb and openvdb_houdini through the FindOpenVDB CMake module - Removed the @c OPENVDB_2_ABI_COMPATIBLE and @c OPENVDB_3_ABI_COMPATIBLE macros. - Fixed a few GCC compiler warnings by adding override keywords. [Contributed by Edward Lam] - jemalloc/tbbmalloc are no longer linked into library artifacts of the OpenVDB CMake build. The @c CONCURRENT_MALLOC CMake option now only applies to the executables. - Introduced a new @c OpenVDB::openvdb_je interface target through the FindOpenVDB CMake module which adds Jemalloc as a link time dependency. - CMake build fix for the vdb_render binary on Windows when building statically and using OpenEXR 2.5 @htmlonly @endhtmlonly @par Version 7.0.0 - December 6, 2019 @par
Some changes in this release (see @ref v7_0_0_ABI_changes "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 18. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 5 for Houdini 17.0 and 17.5 and 6 for Houdini 18.0. As of this release, a C++14 compiler is required and the oldest supported Houdini version is 17.0.
@par New features: - @vdblink{tools::LevelSetMeasure, tools::LevelSetMeasure} can now compute multiple types of curvatures (averge and total Gaussian and mean curvature) as well as Euler characteristic and genus of level set surfaces. - Most stencil classes now have an intersection method that detcts the axial directions of zero-crossings (as oppose to the existing boolean intersection test). - The @vdblink{math::CurvatureStencil, math::CurvatureStencil} can now compute Gaussian and principal curvatures (in addition to mean curvature). - Added @vdblink{tree::Tree::nodeCount,Tree::nodeCount}, which counts the number and type of nodes in a tree very efficiently. - Added new @vdblink::tree::RootNode::addChild() RootNode::addChild@endlink and @vdblink::tree::InternalNode::addChild() InternalNode::addChild@endlink methods to allow the insertion of child nodes directly. @par Improvements: - The minimum ABI for OpenVDB is now always enforced through CMake separately from other minimum dependency version variables. - Added support for CMake 3.12 compatible @c Xxx_ROOT variables. - Replaced the CMake @c USE_SYSTEM_LIBRARY_PATHS option with @c DISABLE_CMAKE_SEARCH_PATHS and removed the hard coded list of @c SYSTEM_LIBRARY_PATHS in favor of using CMake's default search procedure. @c SYSTEM_LIBRARY_PATHS can still be used as a global list of paths for all dependency searches. - Improvements to OpenVDB's CMake module setup order in regards to CMake policy, minimum version and project calls. - Replaced occurrences of boost::scoped_array with std::unique_ptr. - Added an OPENVDB_SIMD option to CMake to optionally define SSE4.2 and AVX compiler flags, this is switched off by default. - Made various small changes to improve Visual Studio compatiblity and deprecate some logic for compilers older than Visual Studio 2017. - Standardized CMake install locations using GNUInstallDirs. Importantly, this changes the default library installation folder from lib to lib64 on some 64-bit systems, or to lib/multiarch-tuple on Debian [Contributed by David Aguilar] - Added SIMD intrinsics to a few common NodeMask methods. [Contributed by Konstantin] @par Bug fixes: - Fixed a bug in FindJemalloc.cmake where paths were not being handled correctly. - Fixed a Windows build issue in openvdb_render. - Fixed a non deterministic threading bug in @vdblink::tools::meshToVolume() mesh to volume@endlink during polygon voxelization which could result in different distance values. @anchor v7_0_0_ABI_changes @par ABI changes: - OpFactory destructor is now virtual as of ABI=7 - Added new virtual methods for copying const grids and replacing the metadata and/or the transform - @vdblink::GridBase::copyGridReplacingMetadata() GridBase::copyGridReplacingMetadata@endlink, @vdblink::GridBase::copyGridReplacingTransform() GridBase::copyGridReplacingTransform@endlink and @vdblink::GridBase::copyGridReplacingMetadataAndTransform() GridBase::copyGridReplacingMetadataAndTransform@endlink. - AttributeArray copy constructor is now thread-safe. @par API changes: - @vdblink{tools::VolumeToMesh::pointList(),VolumeToMesh::pointList} and @vdblink{tools::VolumeToMesh::polygonPoolList(),VolumeToMesh::polygonPoolList} now return a std::unique_ptr instead of a boost::scoped_array. - AttributeArray::copyUncompressed is now deprecated. @par Python: - Removed the requirement of CMake 3.14 for NumPy usage. - Added support for Boost versions 1.65 and later when building the Python module with NumPy support through CMake. - Improved CMake Python3 support. - The Python Module is now disabled by default in CMake. @par Houdini: - Fixed a bug in the Points Convert SOP during conversion from Houdini geometry to OpenVDB Points, where point group information could end up corrupted or cause a crash with non-contiguous point offsets (mesh inputs). - Threaded the population of point group memberships during conversion from Houdini geometry to OpenVDB Points - Added logic to the Rasterize Points SOP to suppress the output of non-finite attribute values due to subnormal input densities. - Introduced a position compression option to the Scatter SOP for VDB Points and default to 16-bit fixed point. @htmlonly @endhtmlonly @par Version 6.2.1 - September 30, 2019 @par Bug fixes: - Fixed a crash that arose from an inadvertent ABI change of an I/O class with the 6.2.0 release. The crash occured when attempting to write out a point data grid using an I/O routine from a different version of OpenVDB than the one with which the grid was authored and when one of those OpenVDB versions was 6.2.0. @htmlonly @endhtmlonly @par Version 6.2.0 - September 18, 2019 @par New features: - Added @vdblink{tools::FindActiveValues,FindActiveValues}, which counts the active values in a tree that intersect a given bounding box. - Added @vdblink{io::DelayedLoadMetadata,DelayedLoadMetadata}, which stores mask offsets and compression sizes on write to accelerate delayed load reading. @par Improvements: - @vdblink{tree::LeafNode::modifyValue(),LeafNode::modifyValue} and @vdblink{tree::LeafNode::modifyValueAndActiveState(), LeafNode::modifyValueAndActiveState} now modify voxel values in place for improved performance. - Added @vdblink{math::isInfinite(),math::isInfinite} and @vdblink{math::isNan(),math::isNan} to resolve Visual Studio compatibility issues with integer types. - Made minor performance improvements to moving and filtering VDB points. - Improved performance related to a mutex contention when appending multiple @vdblink{points::AttributeArray,AttributeArray}s in parallel through various point operations. - Significantly improved the performance of @vdblink::tools::createLevelSetSphere() createLevelSetSphere@endlink using threading. - Improved directory and file path lookups of some CMake commands in the root CMakeLists.txt. [Reported by Daniel Elliott] - Improved CMake support for GLFW versions 3.1 and later. - FindOpenVDB.cmake now correctly propagates @c CXX version requirements. - Added CMake support for linking against Jemalloc and TBB malloc and enabled Jemalloc by default for Linux and non-Maya builds and TBB malloc for all other builds. - Added a @c USE_COLORED_OUTPUT option to CMake to display compiler output in color. - Added an @c OPENVDB_CODE_COVERAGE option to CMake. - CMake now automatically detects and configures the CXX11 ABI requirement for Houdini builds. - CMake now issues deprecation warnings for 2017 VFX Reference Platform version dependencies. In particular, C++11-only compilers are now deprecated; OpenVDB 7.0 will require a C++14-compatible compiler. @par Bug fixes: - Replaced @b std::vector with @b std::deque as the underlying container for @vdblink{util::PagedArray,PagedArray}, to address a rare crash when reading from multiple threads while writing from another thread. - Fixed a bug that could cause an empty @vdblink{math::CoordBBox::volume(),CoordBBox} to report nonzero volume. - Fixed a bug in @vdblink{tools::computeScalarPotential(),computeScalarPotential} that could produce a corrupt result due to invalid memory access. [Reported by Edwin Braun] - Partially reverted the @vdblink{tools::ClosestSurfacePoint,ClosestSurfacePoint} tool’s distance calculations to their pre-OpenVDB 5.0 behavior to address a bug in the @vdblink{tools::fillWithSpheres(),fillWithSpheres} tool that caused generated spheres to sometimes extend outside the target volume. - CMake now correctly sets rpaths for the unit test binary. - Addressed a Valgrind warning by allocating the point attribute array @vdblink{points::AttributeArray::registerType,registry} using a Meyers singleton. [Contributed by Autodesk] @par ABI changes: - ABI versions 3 and older are now deprecated, and support for them will be removed in a future release. Until then, define the macro @c OPENVDB_USE_DEPRECATED_ABI (or set the CMake @c OPENVDB_USE_DEPRECATED_ABI option to @c ON) to suppress deprecation messages when compiling OpenVDB or dependent code. @par API changes: - Changed @vdblink{points::RandomLeafFilter::LeafMap,RandomLeafFilter::LeafMap} from a @b std::map to a @b std::unordered_map. - Removed the @b TableT template argument from @vdblink{util::PagedArray,PagedArray}. The table type is now hardcoded to @b std::deque. - The minimum supported version of GLFW is now 3.1. @par Python: - CMake now always produces a .so for the Python module on Linux and Unix platforms. - Fixed a compile-time error when building the Python module for Python 3. [Reported by yurivict] @par Houdini: - OpenVDB SOPs are now displayed in an ASWF sub-menu of the VDB tab menu. - Added API documentation and examples. - Added @hvdblink{GEOvdbApply,GEOvdbApply}, which invokes a functor on a VDB primitive if the resolved grid type is a member of a given type list. - Fixed a regression in the Fill SOP that caused it to modify VDBs in the input detail. - The Combine SOP no longer crashes in Copy B mode when the destination is not a VDB. - Added an @hulink{OpFactory::addSpareData(),OpFactory::addSpareData} method and @hulink{addOperatorSpareData(),addOperatorSpareData} and @hulink{getOperatorSpareData(),getOperatorSpareData} functions to manage spare data associated with operator types. - Added an @c opsparedata HScript command and @c hou.NodeType.spareData and @c hou.NodeType.spareDataDict methods to retrieve spare data associated with operator types. - Added a pythonrc.py startup script to set the tab menu visibility of nodes and their native Houdini equivalents, based on an OPENVDB_OPHIDE_POLICY environment variable. - Added an @hulink{OpFactory::setInvisible(),OpFactory::setInvisible} method to hide nodes from tab menus. - Added an @hvdblink{OpenVDBOpFactory::setNativeName(),OpenVDBOpFactory::setNativeName} method to pair OpenVDB nodes with their native Houdini equivalents. - Added an @hulink{OpPolicy::getTabSubMenuPath(),OpPolicy::getTabSubMenuPath} method to allow @b OpPolicy subclasses to provide their own tab sub-menu path. - OpenVDB nodes now override @b OP_Operator::getVersion to return a version string of the form @c "vdb6.2.0 houdini18.0.222". @htmlonly @endhtmlonly @par Version 6.1.0 - May 8, 2019 @par
As of this release, the oldest supported Houdini version is 16.5.
@par New features: - Added new @vdblink::QuatTraits QuatTraits@endlink, @vdblink::MatTraits MatTraits@endlink and @vdblink::ValueTraits ValueTraits@endlink type traits to complement @vdblink::VecTraits VecTraits@endlink and added an @vdblink::IsSpecializationOf IsSpecializationOf@endlink helper metafunction. - Added support for @vdblink::Vec4SMetadata Vec4s@endlink, @vdblink::Vec4DMetadata Vec4d@endlink and @vdblink::Vec4IMetadata Vec4i@endlink metadata. - Added a generic @vdblink::TypeList TypeList@endlink class. - Added @vdblink::GridBase::apply() GridBase::apply@endlink, which invokes a functor on a grid if the resolved grid type is a member of a given type list. - Added @vdblink::util::printTime() printTime@endlink, which outputs nicely formatted time information. - Added a @link std::hash std::hash@endlink template specialization. - Added @vdblink::math::CoordBBox::moveMin moveMin@endlink and @vdblink::math::CoordBBox::moveMax moveMax@endlink methods to @vdblink::math::CoordBBox CoordBBox@endlink. @par Improvements: - @vdblink::util::CpuTimer CpuTimer@endlink now makes use of @vdblink::util::printTime() printTime@endlink for nicer output, and its API has been improved. - Significantly improved the performance of point data grid string attribute generation. - @vdblink::points::AttributeArray::copy() AttributeArray::copy@endlink and the @vdblink::points::AttributeArray::operator=() AttributeArray@endlink copy assignment operator are now thread-safe. - The command-line tools (vdb_print, etc.) now include the library ABI version in their -version output. - Further improved the responsiveness of the @link MeshToVolume.h mesh to volume@endlink converter to interrupt requests. - The CMake build system has been significantly improved to support a wider range of build options and use cases. This includes better dependency handling and status reporting, find module installation for external use, more robust handling of different platform configurations and the introduction of dependency and build documentation. @par Bug fixes: - Fixed a bug in the @link tools/Clip.h clip@endlink tool that caused some grid metadata to be discarded. - Added a check to @vdblink::points::setGroup() points::setGroup@endlink to compare the maximum index of the provided @vdblink::tools::PointIndexTree PointIndexTree@endlink to the size of the membership vector. - Fixed a race condition introduced in ABI 6 when moving points in point data grids, due to non-const access to an @vdblink::points::AttributeArray AttributeArray@endlink triggering a copy-on-write. - Fixed a bug that caused the @link MeshToVolume.h mesh to volume@endlink converter to consume unlimited memory when it encountered NaNs in vertex positions. - Fixed a rounding error bug in @link PointConversion.h point conversion@endlink when using single-precision floating-point. - Addressed some type conversion issues and other issues reported by GCC 6. - Fixed a crash in @vdblink::tools::extractActiveVoxelSegmentMasks() extractActiveVoxelSegmentMasks@endlink when the first leaf node had no active voxels. [Reported by Rick Hankins] - Fixed a bug in @vdblink::tools::segmentActiveVoxels() segmentActiveVoxels@endlink and @vdblink::tools::segmentSDF() segmentSDF@endlink where inactive leaf nodes were only pruned when there was more than one segment. - Fixed a crash in point moving when using group filters. - Fixed a bug where the stride of existing attributes was being ignored during copy-construction of an @vdblink::points::AttributeSet AttributeSet@endlink. - Fixed a bug that caused @vdblink::points::AttributeArray::operator==() AttributeArray@endlink equality operators to fail for attributes with non-constant strides. @par API changes: - Moved the @vdblink::CopyConstness CopyConstness@endlink metafunction from @link tree/TreeIterator.h TreeIterator.h@endlink to @link Types.h Types.h@endlink. @par Houdini: - The Points Convert SOP now reports NaN Positions as warnings when converting from Houdini Points to VDB Points. - Fixed a bug where the Points Convert SOP was incorrectly ignoring point attributes with the same name as an existing point group. - The Transform SOP now supports frustum transforms by applying the transformation to the internal affine map. - Changed the labels (but not the opnames) of several SOPs to match the corresponding native Houdini SOPs. The new labels are Morph SDF, Project Non-Divergent, Rebuild SDF, Renormalize SDF, Reshape SDF, Segment by Connectivity, Smooth SDF, Topology to SDF, and Visualize Tree. - Added an @b OpPolicy::getFirstName method to allow @b OpPolicy subclasses to provide their own first name scheme. - Added an @b OpPolicy::getLabelName method to allow @b OpPolicy subclasses to provide their own label naming scheme for tab menus. - Added type lists for sets of commonly used grid types, including @b ScalarGridTypes, @b Vec3GridTypes, @b AllGridTypes, etc. - The Vector Merge SOP now copies metadata from the representative scalar grid. - Deprecated @b SOP_NodeVDB::duplicateSourceStealable, @b houdini_utils::getNodeChain and @b houdini_utils::OP_EvalScope. @par Python: - Added limited support for @ref secPtContents "point data grids", comprising I/O and metadata functionality for now. - Added support for @vdblink::Mat4SMetadata Mat4s@endlink and @vdblink::Mat4DMetadata Mat4d@endlink metadata, in the form of nested Python lists (e.g., [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]]). @htmlonly @endhtmlonly @par Version 6.0.0 - December 18, 2018 @par
Some changes in this release (see @ref v6_0_0_ABI_changes "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 17. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 3 for Houdini 15, 15.5 and 16, 4 for Houdini 16.5 and 5 for Houdini 17.0.
@par New features: - Added support to the @link ParticlesToLevelSet.h ParticlesToLevelSet@endlink tool for fast rasterization of particles into boolean mask grids. - Added convenience functions @vdblink::tools::particlesToSdf() particlesToSdf@endlink, @vdblink::tools::particleTrailsToSdf() particleTrailsToSdf@endlink, @vdblink::tools::particlesToMask() particlesToMask@endlink and @vdblink::tools::particleTrailsToMask() particleTrailsToMask@endlink for common particle rasterization use cases. - Added batch copying functions @vdblink::points::AttributeArray::copyValues() AttributeArray::copyValues@endlink and @vdblink::points::AttributeArray::copyValuesUnsafe() AttributeArray::copyValuesUnsafe@endlink that significantly outperform the older AttributeArray::set() method. @par Improvements: - Improved the responsiveness of the @link MeshToVolume.h mesh to volume@endlink converter to interrupt requests. - Attempts to use a partially deserialized @vdblink::points::AttributeArray AttributeArray@endlink now errors. - Updated point deletion to use faster batch copying for ABI=6+. - Methods relating to in-memory Blosc compression for AttributeArray::compress() now do nothing and have been marked deprecated resulting in memory savings for ABI=6+. @par Bug fixes: - Fixed various signed/unsigned casting issues to resolve compiler warnings when moving points in point data grids. @anchor v6_0_0_ABI_changes @par ABI changes: - Added multiple new virtual functions to @vdblink::points::AttributeArray AttributeArray@endlink. - Changed the order and size of member variables in @vdblink::points::AttributeArray AttributeArray@endlink and @vdblink::points::TypedAttributeArray TypedAttributeArray@endlink. @par API changes: - Removed a number of methods that were deprecated in version 5.0.0 or earlier. - Removed the experimental @b ValueAccessor::newSetValue method. - Deprecated AttributeArray::compress() methods relating to in-memory Blosc compression. @par Houdini: - The Convert and To Polygons SOPs now correctly transfer vertex attributes when the output is a polygon soup. - Added an option to the Visualize SOP to display leaf nodes as points. - Renamed the Visualize SOP’s leafmode, internalmode, tilemode and voxelmode parameters to leafstyle, internalstyle, etc. and converted them from ordinals to strings. - Made various improvements to viewport rendering of point data grids. - Added a ParmFactory::setInvisible method to allow parameters to be marked as hidden. This is useful for multi-parms, whose child parameters cannot be made obsolete. - Removed the option to use in-memory Blosc compression from the Points Convert SOP as this feature has now been deprecated. - Made various small changes for Houdini 17 compatibility. @htmlonly @endhtmlonly @par Version 5.2.0 - August 13, 2018 @par New features: - Added @link points/PointAdvect.h tools@endlink to advect points stored in point data grids through velocity fields. [Contributed by Dan Bailey] - For point data grids, voxel data can now be @vdblink::points::prefetch() prefetched@endlink independently of position or other attributes. [Contributed by Dan Bailey] - Added @link points/PointSample.h tools@endlink to sample voxel values onto points stored in point data grids. [Contributed by Double Negative] @par Improvements: - The @vdblink::tools::UniformPointScatter UniformPointScatter@endlink tool now generates points in “points per volume” mode even when the product of the density and the voxel volume is less than one, and the point count now varies continuously with the density. - Added a minimum/maximum sphere count argument to the @vdblink::tools::fillWithSpheres() fillWithSpheres@endlink tool. (The previous version, now deprecated, supported only a maximum sphere count.) - Added a method to the level set tracking tool to enable and disable @vdblink::tools::LevelSetTracker::setTrimming() trimming@endlink of voxels outside the narrow band. Previously, trimming was always enabled, which caused dense SDFs to be converted to narrow-band level sets. - Added @b state methods to point data @link points/IndexFilter.h index filters@endlink to improve optimization opportunities. [Contributed by Dan Bailey] - Added @vdblink::points::ActiveFilter active@endlink and @vdblink::points::InactiveFilter inactive@endlink value mask point data index filters. [Contributed by Dan Bailey] - Replaced include/exclude group list parameters with filter functors in various point data functions. [Contributed by Dan Bailey] - Refactored and simplified the @link points/PointCount.h point count@endlink API. [Contributed by Dan Bailey] - Computing cumulative per-leaf point offsets is now parallelized. [Contributed by Dan Bailey] - Made various small changes for Visual Studio 2017 compatibility. [Contributed by Edward Lam] @par Bug fixes: - Fixed a bug that could cause an infinite loop when iterating over an empty root node. - Fixed namespace-related bugs in @vdblink::math::Tuple::isZero() Tuple::isZero@endlink and @vdblink::math::Mat::isZero() Mat::isZero@endlink that led to compile-time errors. - Fixed type conversion bugs in the vector-to-vector rotation function that made it impossible for it to return a single-precision rotation matrix, and modified the function to accept @b Vec3 arguments of any value type. - Fixed a bug in the @link MeshToVolume.h mesh to volume@endlink converter that made it uninterruptible in certain cases even though an interrupter was provided. [Reported by Doug Epps] @par Houdini: - Added an option to the From Particles SOP to output an interior mask grid. - Added options to the Metadata SOP to set the grid name and to propagate metadata to primitive attributes and vice-versa. - Modified convertVolumesToVDBs to set the output VDBs’ grid names to the names of the volume primitives. - Added an option to the Offset Level Set, Renormalize Level Set, Smooth Level Set and Resize Narrow Band SOPs to enable and disable trimming of voxels outside the narrow band. Previously, trimming was always enabled, which caused dense SDFs to be converted to narrow-band level sets. - Fixed a bug in the Resample SOP that prevented it from reading a reference VDB from the second input. - Added an option to the Scatter SOP to scatter points only on an isosurface of a signed distance field. - The Scatter SOP now generates points in Point Density mode even when the product of the density and the voxel volume is less than one, and the point count now varies continuously with the density. - Added a minimum sphere count option to the To Spheres SOP. - Added enable/disable toggles to the To Spheres SOP’s minimum and maximum radius parameters and eliminated the world space radius parameters. The remaining minimum and maximum parameters, formerly the voxel space radii, are now used in both world unit and voxel unit modes. - Added transform and rotation order options to the Transform SOP. - Added support to the Advect Points SOP for advecting points stored in point data grids. [Contributed by Dan Bailey] - Added support to the Sample Points SOP for sampling onto points stored in point data grids. [Contributed by Double Negative] @htmlonly @endhtmlonly @par Version 5.1.0 - April 10, 2018 @par New features: - Added an option to @vdblink::points::deleteFromGroups() points::deleteFromGroups@endlink to delete the groups as well as the points. [Contributed by Nick Avramoussis] - Added a @c header_test Makefile target that checks library header files for dependencies on missing or indirectly included headers. [Contributed by Dan Bailey] - Added support for @vdblink::math::Mat3s Mat3s@endlink and @vdblink::math::Mat3d Mat3d@endlink point data @vdblink::points::TypedAttributeArray typed attributes@endlink. [Contributed by Dan Bailey] @par Improvements: - Added per-test timings to vdb_test to help in identifying performance regressions. - @vdblink::zeroVal zeroVal@endlink now returns a zero matrix instead of an identity matrix for @vdblink::math::Mat4s Mat4s@endlink and @vdblink::math::Mat4d Mat4d@endlink, and it is now also defined (and returns a zero matrix) for @vdblink::math::Mat3s Mat3s@endlink and @vdblink::math::Mat3d Mat3d@endlink. @par Python: - Fixed a bug introduced in version 3.2.0 that caused boolean and integer values added to a grid’s metadata to be stored as floating-point values. @par Houdini: - Added options to the Clip SOP to expand or shrink the clipping region and, when clipping to a camera frustum, to set the near and far clipping planes. - Added output grid naming options to the Points Convert SOP. - Added a Keep Original Geometry toggle to the Points Convert SOP and improved the efficiency of point unpacking. [Contributed by Dan Bailey] - Added an option to the Points Delete SOP to delete point groups. [Contributed by Nick Avramoussis] - Fixed a rare crash when extracting points from a point data primitive. [Contributed by Jeff Lait] - Added a @b SOP_NodeVDB::evalStdString method that facilitates string parameter evaluation in expressions, e.g., matchGroup(*gdp, evalStdString("group", time)). - Removed the deprecated @b openvdb_houdini::validateGeometry function. Use @b convertGeometry instead. - Added a @b SOP_NodeVDB::matchGroup overload that eliminates the need to @c const_cast the @b GU_Detail. [Contributed by Jeff Lait] - Grid transforms are now more aggressively simplified, making it less likely to produce nonuniform voxels erroneously. [Contributed by Jeff Lait] - Fixed a bug when copying and pasting a Create SOP that could cause the Voxel Size toggle to change state. - Added a @b houdini_utils::OpFactory::setVerb method to register compilable SOPs. - Made @b SOP_NodeVDB::cookMySop @c final (that is, non-overridable) to facilitate the implementation of compilable SOPs. Override @b SOP_NodeVDB::cookVDBSop instead. (In most cases, it suffices to rename @b cookMySop to @b cookVDBSop.) - Renamed some parameters on the following SOPs to match the equivalent native Houdini nodes: Advect, Advect Points, Analysis, Combine, Filter, Fracture, From Particles, From Polygons, Morph Level Set, Occlusion Mask, Offset Level Set, Points Group, Resample, Resize Narrow Band, Smooth Level Set, Topology To Level Set, Vector Merge, and Visualize. - Added @b SOP_VDBCacheOptions, a convenience base class for compilable SOPs. [Contributed by Jeff Lait] - Converted most SOPs into compilable SOPs. @htmlonly @endhtmlonly @par Version 5.0.0 - November 6, 2017 @par
Some changes in this release (see @ref v5_0_0_ABI_changes "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini up to and including Houdini 16. To preserve ABI compatibility, when compiling OpenVDB or any dependent code define the macro OPENVDB_ABI_VERSION_NUMBER=N, where, for example, N is 3 for Houdini 15, 15.5 and 16 and 4 for Houdini 16.5.
@par New features: - Added a @vdblink::getLibraryAbiVersionString() getLibraryAbiVersionString@endlink function, which returns a string such as "5.0.0abi3". - Added a @vdblink::WeakPtr weak pointer@endlink type alias for ABI compatibility. - Metadata fields of unregistered types are no longer discarded after being read from a .vdb file, and although their values are not printable, they can be written back to disk. - Added a @c DESTDIR_LIB_DIR Makefile variable for Linux multiarch support. [Contributed by Mathieu Malaterre] - Added tools to create @link tools/PotentialFlow.h potential flow@endlink fields, as described in the 2017 SIGGRAPH OpenVDB course. [Contributed by Double Negative] - Added @link points/PointMask.h tools@endlink to create mask grids from point data grids and to compute @vdblink::points::pointCountGrid() point counts@endlink. [Contributed by Dan Bailey] - Added @link points/PointScatter.h tools@endlink to scatter @ref secPtOverview "OpenVDB points" randomly throughout a volume. [Contributed by Nick Avramoussis] @par Improvements: - Significantly improved the performance of point data grid @vdblink::points::MultiGroupFilter group filters@endlink. [Contributed by Double Negative] @par Bug fixes: - Fixed bugs in the @vdblink::tools::ClosestSurfacePoint ClosestSurfacePoint@endlink tool’s distance calculations that caused searches to produce incorrect results. - Fixed a locking issue that affected multithreaded access to @vdblink::points::PointDataLeafNode PointDataLeafNode@endlink‍s when delayed loading was in effect. [Contributed by Dan Bailey] @anchor v5_0_0_ABI_changes @par ABI changes: - Made @vdblink::tree::InternalNode InternalNode@endlink’s destructor non-virtual. - The @ref v4_0_2_delayed_load_fix "fix" for a delayed-loading race condition in the @vdblink::tree::LeafBuffer LeafBuffer@endlink class that was only partially rolled out in the previous release is now enabled on all platforms. - Replaced a bit flag with an atomic integer in @vdblink::points::AttributeArray points::AttributeArray@endlink to address a threading issue during delayed loading. [Contributed by Dan Bailey] - Deprecated the @c OPENVDB_2_ABI_COMPATIBLE and @c OPENVDB_3_ABI_COMPATIBLE macros in favor of a new @c OPENVDB_ABI_VERSION_NUMBER macro. The new macro defaults to the library major version number but can be set at compile time to an earlier version number to disable ABI changes since that version. (Older ABIs will not be supported indefinitely, however.) For example, compile OpenVDB and any dependent code with -DOPENVDB_ABI_VERSION_NUMBER=4 to use the 4.x ABI. @par API changes: - Replaced @b tools::ClosestSurfacePoint::initialize with @vdblink::tools::ClosestSurfacePoint::create() tools::ClosestSurfacePoint::create@endlink, which returns a newly-allocated and properly initialized object. - Removed methods that were deprecated in version 4.0.0 or earlier, including @b io::File::readGridPartial, @b points::initialize, @b points::uninitialize and @b util::PagedArray::pop_back. - Deprecated IllegalValueException in favor of @vdblink::ValueError ValueError@endlink. - Changed the naming scheme for the @link OPENVDB_VERSION_NAME library namespace@endlink from openvdb::vX_Y_Z to openvdb::vX_YabiN, where @e X, @e Y, @e Z and @e N are the major, minor, patch and ABI version numbers, respectively. The abiN suffix is added only when the library is built using an older ABI version. @par Python: - Reimplemented NumPy support for Boost 1.65 compatibility. @par Houdini: - Fixed bugs that caused the Ray SOP’s closest surface point searches to produce incorrect results. - Changed the @b VdbPrimCIterator::FilterFunc type from @b boost::function to @b std::function. - Changed the @b houdini_utils::OpPolicyPtr type from @b boost:shared_ptr to @b std::shared_ptr. - Debug-level log messages generated by OpenVDB are no longer forwarded to Houdini’s error manager. - Fixed a bug in the Read SOP that made it impossible to select among grids of the same name in a file. - Added @b houdini_utils::ParmFactory::setAttrChoiceList, a convenience method for the creation of menus of attributes. - Added a Potential Flow SOP. [Contributed by Double Negative] - Added point data grid support to the Scatter SOP. [Contributed by Nick Avramoussis] - Added mask and point count output options to the Points Convert SOP. [Contributed by Dan Bailey] @htmlonly @endhtmlonly @par Version 4.0.2 - July 28, 2017 @par New features: - Added @vdblink::tools::compActiveLeafVoxels compActiveLeafVoxels@endlink, which composites active voxel values from a source tree into a destination tree. It is threaded and faster than existing tools that merge trees, however it operates only on leaf nodes. - Added a vdb_test -f option that reads a list of tests to be run from a text file. - Added functions for @link points/PointDelete.h deleting points@endlink from point data grids based on group membership. [Contributed by Double Negative] - Enabled display of point data grids in vdb_view. [Contributed by Nick Avramoussis] - Added a view mode indicator to vdb_view. - Added @vdblink::math::Mat::isFinite() isFinite@endlink, @vdblink::math::Mat::isNan() isNan@endlink, and @vdblink::math::Mat::isZero() isZero@endlink methods to @vdblink::math::Mat math::Mat@endlink and added @vdblink::math::Tuple::isZero() isZero@endlink to @vdblink::math::Tuple math::Tuple@endlink. - Added @vdblink::tools::interiorMask() tools::interiorMask@endlink, which constructs a boolean mask grid from the active voxels of an input grid or, if the input grid is a level set, from the interior voxels of the level set. - Added @vdblink::math::CoordBBox::begin() begin@endlink and @vdblink::math::CoordBBox::end() end@endlink iterator methods (and related methods) to @vdblink::math::CoordBBox CoordBBox@endlink, so that it can be used in range-based for loops. - The @link tools/Clip.h clip@endlink tool now accepts either a box, a mask grid or a camera frustum as the clipping region. The latter is new in this version. @par Improvements: - Moved the @vdblink::math::Tuple::isFinite() isFinite@endlink, @vdblink::math::Tuple::isInfinite() isInfinite@endlink, and @vdblink::math::Tuple::isNan() isNan@endlink methods from @vdblink::math::Vec3 math::Vec3@endlink et al. to @vdblink::math::Tuple math::Tuple@endlink. @par Bug fixes: - @anchor v4_0_2_delayed_load_fix Fixed a delayed-loading race condition that could result in crashes. [Reported by Dan Bailey]
@b Note: To preserve ABI compatibility, this fix is currently enabled only on platforms for which the alignment of a tbb::atomic<uint32_t> is the same as for a @c uint32_t. On other platforms, warnings will be logged during OpenVDB initialization, and it is recommended to disable delayed loading in that case (for example, by defining the environment variable @c OPENVDB_DISABLE_DELAYED_LOAD).
- Fixed a delayed-loading memory leak in the @vdblink::points::PointDataLeafNode PointDataLeafNode@endlink. [Contributed by Double Negative] - Changed the random number seeding mechanism for .vdb file UUIDs to avoid duplicate IDs. [Reported by Jason Lefley] - Fixed an off-by-one bug in the @vdblink::tools::GridResampler resampler@endlink that produced grid patterns of missing interior voxels for scale factors greater than one. @par Houdini: - As of Houdini 16.0.549, @c houdini_utils::OpFactory can generate help cards for operators automatically. New @c OpFactory::setDocumentation and @c ParmFactory::setDocumentation methods allow one to add custom help text in wiki markup format. - Added help cards for all SOPs. Houdini 16.0.578 or later is required. [Contributed by Dan Bailey and SideFX] - The Extended Operator Info window in Houdini 16 now renders correctly for OpenVDB SOPs, instead of displaying a Python stack trace. [Contributed by Dan Bailey] - Added a Points Delete SOP for deleting points from point data grids based on group membership. [Contributed by Double Negative] - Added a Mantra VRAY procedural and a delayed load SHOP for rendering point data grids. Houdini 16 is required. [Contributed by Double Negative] - Replaced the Combine SOP’s “A/B Pairs” and “Flatten” toggles with a menu of collation options that include flattening only A grids and flattening groups of A grids independently. - Added a slider to the Remove Divergence SOP to set the error tolerance for the pressure solver. - Added value type conversion options (for VDB output) to the Convert SOP. - Added a Densify SOP that replaces active tiles with leaf voxels. - Fixed a bug in the Rasterize Points SOP that capped density values to one instead of to the particles’ densities. - The Convert and To Polygons SOPs now accept grids of any type as surface masks, not just level set or SDF grids. - Added an option to the Clip SOP to clip to a camera frustum. @htmlonly @endhtmlonly @par Version 4.0.1 - March 8, 2017 @par New features: - Added functions to util/logging.h to simplify configuration of the logging system (via command-line arguments, in particular). - Added @vdblink::tree::LeafManager::activeLeafVoxelCount() LeafManager::activeLeafVoxelCount@endlink, a faster, threaded alternative to @vdblink::tree::Tree::activeLeafVoxelCount() Tree::activeLeafVoxelCount@endlink. - Added a -shuffle option that causes vdb_test to run unit tests in random order, which can help to identify unintended dependencies between tests. - Added @c vdb_lod, a command-line tool to generate volume mipmaps for level-of-detail effects. - Added methods to compute the median value of @vdblink::tree::LeafNode::medianOn() active@endlink, @vdblink::tree::LeafNode::medianOff() inactive@endlink or @vdblink::tree::LeafNode::medianAll() all@endlink voxels in leaf nodes. @par Improvements: - Added a @vdblink::Metadata::str() Metadata::str@endlink specialization for @vdblink::StringMetadata StringMetadata@endlink that eliminates the overhead of writing to a string stream. - Made various minor improvements to @vdblink::util::PagedArray util::PagedArray@endlink. - Added an @c install_lib build target to the Makefile. [Contributed by Double Negative] - Added @subpage points "documentation" and Cookbook @ref openvdbPointsHelloWorld "examples" for OpenVDB Points. [Contributed by Double Negative] - Registration of OpenVDB Points grid and attribute types is now handled in @vdblink::initialize() openvdb::initialize@endlink, and @vdblink::points::initialize() points::initialize@endlink and @vdblink::points::uninitialize() points::uninitialize@endlink are therefore deprecated. - Extended multi-pass I/O to handle a variable number of passes per leaf node. [Contributed by Double Negative] - Addressed a name conflict between macros in util/NodeMasks.h and symbols in the Eigen library. [Reported by Trevor Thomson] @par Bug fixes: - The @vdblink::tools::fillWithSpheres() fillWithSpheres@endlink and @vdblink::tools::ClosestSurfacePoint ClosestSurfacePoint@endlink tools now correctly handle isosurfaces outside the input volume’s narrow band. - The @vdblink::tools::MultiResGrid MultiResGrid@endlink tool now supports all standard grid types, including @vdblink::BoolGrid BoolGrid@endlink and @vdblink::MaskGrid MaskGrid@endlink. - @vdblink::tree::LeafNode::fill() LeafNode::fill@endlink now correctly clips the fill region to the node’s bounding box. - @vdblink::Grid::denseFill() Grid::denseFill@endlink no longer densifies all existing active tiles, and it now correctly handles both active and inactive fill values. - Fixed a bug that caused @vdblink::tools::copyToDense() tools::copyToDense@endlink to only partially populate the output array when delayed loading was in effect. [Reported by Stuart Levy] - Fixed an issue with duplicate registration of @link points/PointDataGrid.h PointDataGrid@endlink attribute types. [Reported by SideFX] - Fixed an uninitialized memory bug in the @vdblink::tools::meshToVolume() mesh to volume@endlink converter. [Reported by SideFX] - Fixed a thread race condition in @vdblink::math::QuantizedUnitVec QuantizedUnitVec@endlink that could cause it to produce incorrect results. [Contributed by Jeff Lait] - Fixed a dangling pointer bug in the @vdblink::tools::ParticleAtlas particle atlas@endlink tool. [Contributed by SideFX] - Grid operators (@vdblink::tools::divergence() divergence@endlink, @vdblink::tools::gradient() gradient@endlink, etc.) now produce correct results even for grids with active tile values. - Fixed a bug when writing an out-of-core @vdblink::points::AttributeArray points::AttributeArray@endlink that could cause corruption of the metadata associated with the array. [Contributed by Double Negative] @par Python: - Added functions @c getLoggingLevel, @c setLoggingLevel, and @c setProgramName, to allow configuration of the logging system. @par Houdini: - Fixed a crash in the Ray SOP when the user selected an isosurface outside the target volume’s narrow band. - The LOD SOP now supports all standard grid types, including boolean grids. - Added @c houdini_utils::ParmFactory::setGroupChoiceList, a convenience method for the creation of menus of primitive groups. - Made various small changes for Houdini 16 compatibility. [Contributed by SideFX] - The Create SOP now supports matching the new grids’ transform, voxel size, and topology to a reference grid. If the topology is being matched, it can optionally be resampled to a different voxel size. - Added some support for point data grids to the Clip, Topology To Level Set and Visualize SOPs. [Contributed by Double Negative] - Compression is no longer enabled by default in the Points Convert SOP for normals and colors, because they are not guaranteed to have a [0, 1] range. [Contributed by Double Negative] - Added a 16-bit truncation compression option to the Points Convert SOP. [Contributed by Double Negative] - Fixed a build issue with the GR_PrimVDBPoints render hook plugin that could cause @c hython to report a DSO error. [Reported by Double Negative] - Added an @c install_lib build target to the Makefile. - Rewrote the Remove Divergence SOP to actually remove divergence from vector fields on collocated grids, and added support for stationary and moving obstacles and an option to output a pressure field. - The Analysis SOP now produces correct results for grids with active tile values. - Added a sparse/dense toggle to the Fill SOP. - Added @c openvdb_houdini::startLogForwarding, @c openvdb_houdini::stopLogForwarding and @c openvdb_houdini::isLogForwarding, which control the forwarding of log messages to Houdini’s error manager. Forwarding of library warnings and error messages is now enabled by default for SOPs when OpenVDB is built with log4cplus. @htmlonly @endhtmlonly @par Version 4.0.0 - November 15, 2016 @par Highlights: - Incorporated Double Negative’s OpenVDB Points library. - Introduced some C++11 constructs. A C++11-compatible compiler is now required. - Blosc-compressed .vdb files are now as much as 20% smaller. - Vector-valued grids are now constructed and destroyed much faster.
@b Note: This change and other changes in this release (see @ref v4_0_0_ABI_changes "ABI changes" below) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini 15, 15.5 and 16. To disable these changes and preserve ABI compatibility, define the macro @c OPENVDB_3_ABI_COMPATIBLE when compiling OpenVDB or any code that depends on OpenVDB.
@par New features: - Added an option to the @link PointScatter.h point scattering@endlink tools to specify how far each point may be displaced from the center of its host voxel or tile. - Added a toggle to the @vdblink::tools::clip() clip@endlink tool to invert the clipping mask. - Custom leaf node implementations may now optimize their file layout by inheriting from @vdblink::io::MultiPass io::MultiPass@endlink. Voxel data for grids with such leaf nodes will be written and read in multiple passes, allowing blocks of related data to be stored contiguously. [Contributed by Double Negative] - Added @vdblink::tree::Tree::unallocatedLeafCount() Tree::unallocatedLeafCount@endlink, which returns the number of leaf nodes with unallocated data buffers (typically due to delayed loading). @par Improvements: - Vector-valued grids are now constructed and destroyed much faster. - Changed @vdblink::math::Coord Coord@endlink’s data representation to facilitate C++11 uniform initialization. - Delayed loading from @vdblink::io::File io::Files@endlink is now faster due to the use of seeks instead of reads. [Contributed by Double Negative] - Made many small changes to address type conversion and other warnings reported by newer compilers, including Clang 3.8. - Improved Blosc compression ratios and write times by increasing the block size. [Contributed by Dan Bailey] @par Bug fixes: - Fixed a bug that caused topology operations (@vdblink::Grid::topologyUnion() union@endlink, @vdblink::Grid::topologyIntersection() intersection@endlink and @vdblink::Grid::topologyDifference() difference@endlink) on @vdblink::MaskGrid MaskGrids@endlink to sometimes produce incorrect results. (MaskGrids are used internally in a number of tools.) - Changed @vdblink::GridBase::copyGrid() GridBase::copyGrid@endlink and @vdblink::Grid::copy() Grid::copy@endlink to close const-correctness holes. - @vdblink::tools::fillWithSpheres() tools::fillWithSpheres@endlink now returns an empty list of spheres instead of crashing when the user selects an isosurface that lies outside the bounding volume’s narrow band. - Fixed a null pointer dereference when copying grids that were loaded with @c io::File::readGridPartial. [Reported by Nick Avramoussis] @anchor v4_0_0_ABI_changes @par ABI changes: - Added a @vdblink::tree::NodeUnion NodeUnion@endlink template specialization for non-POD value types that significantly expedites construction and destruction of vector-valued grids. - Changed @vdblink::math::Coord Coord@endlink’s data representation to facilitate C++11 uniform initialization. - Replaced occurrences of boost::shared_ptr with std::shared_ptr. - Changed @vdblink::GridBase::copyGrid() GridBase::copyGrid@endlink and @vdblink::Grid::copy() Grid::copy@endlink to close const-correctness holes. - Added virtual function @vdblink::tree::Tree::unallocatedLeafCount() Tree::unallocatedLeafCount@endlink. @par API changes: - Introduced some C++11 constructs. A C++11-compatible compiler is now required. - Added a parameter to the @link PointScatter.h point scattering@endlink tools to control the displacement of each point from the center of its host voxel or tile. The default behavior, as before, is to allow each point to be placed (randomly) anywhere within its voxel or tile. - Renamed @c LeafManager::getPreFixSum to @vdblink::tree::LeafManager::getPrefixSum() LeafManager::getPrefixSum@endlink. - Made @c LeafNode::Buffer a top-level class and renamed it to @vdblink::tree::LeafBuffer LeafBuffer@endlink. [Contributed by Double Negative] - Deprecated @c io::File::readGridPartial in favor of delayed loading. - @c tools::ClosestSurfacePoint::initialize now returns a boolean indicating whether initialization was successful. - Dropped the @c CopyPolicy enum and added @vdblink::GridBase::copyGridWithNewTree() GridBase::copyGridWithNewTree@endlink and @vdblink::Grid::copyWithNewTree() Grid::copyWithNewTree@endlink in order to close const-correctness holes that allowed newly-constructed, non-const grids to share their trees with existing const grids. (Where that behavior is still required, use a @vdblink::ConstPtrCast ConstPtrCast@endlink.) @par Python: - Fixed a build issue with Python 3 and NumPy. [Contributed by Jonathan Scruggs] @par Houdini: - Certain changes in this release (see @ref v4_0_0_ABI_changes "ABI changes" above) alter the grid ABI so that it is incompatible with earlier versions of the OpenVDB library, such as the ones built into Houdini 15, 15.5 and 16. To disable these changes and preserve ABI compatibility, define the macro @c OPENVDB_3_ABI_COMPATIBLE when compiling OpenVDB or any code that depends on OpenVDB. - Introduced some C++11 constructs that are incompatible with versions of Houdini older than 15.0. - Fixed a bug in the Rasterize Points SOP that caused vector-valued attributes to be transferred as scalars. [Contributed by Double Negative] - Added a toggle to the Clip SOP to invert the clipping mask. - Added a slider to the Scatter SOP to specify how far each point may be displaced from the center of its host voxel or tile. @htmlonly @endhtmlonly @par Version 3.2.0 - August 10, 2016 @par Highlights: - New features: tool to produce and store a sequences of progressively lower resolution grids (mipmaps), an acceleration structure for fast range and nearest-neighbor searches on particles, arbitrary volume and level set specific segmentation tools, a new binary mask grid type and an efficient point to level set conversion scheme. - Optimizations: Faster volume to mesh conversion and threaded grid destruction, morphological dilation, csg operations and fracture tool. - New Houdini nodes: Segment, LOD and Topology To Level Set. @par New features: - Added @link MultiResGrid.h tools::MultiResGrid@endlink a tool to produce and store a sequences of progressively lower resolution grids (mipmaps). - Added @link ParticleAtlas.h tools::ParticleAtlas@endlink an acceleration structure for fast range and nearest-neighbor searches on particles, points with radius. - Added @vdblink::tools::segmentActiveVoxels() segmentActiveVoxels@endlink, which operates on grids of arbitrary type and separates connected components of a grid’s active voxels into distinct grids or trees. - Added @vdblink::tools::segmentSDF() segmentSDF@endlink, which separates disjoint signed-distance-field surfaces into distinct grids or trees. - Added @vdblink::tools::extractActiveVoxelSegmentMasks() extractActiveVoxelSegmentMasks@endlink, which constructs a mask for each connected component of a grid’s active voxels. - Added threaded level-set CSG tools @vdblink::tools::csgUnionCopy() csgUnionCopy@endlink, @vdblink::tools::csgIntersectionCopy() csgIntersectionCopy@endlink and @vdblink::tools::csgDifferenceCopy() csgDifferenceCopy@endlink, which, unlike the existing CSG tools, produce new grids rather than modifying their input grids. These new tools are faster and use less memory than the existing tools (if only because the input grids never need to be deep-copied). - Added a threaded @vdblink::tools::dilateActiveValues dilateActiveValues()@endlink tool with tile value support. - Added a @vdblink::tools::PointsToMask PointsToMask@endlink tool, which activates voxels that intersect points from a given list. - Added a new @link openvdb.h MaskGrid@endlink type that uses a single bit-field to represent both voxel values and states for the @link tree/LeafNodeMask.h leafnode@endlink to reduce memory usage. - Added a @vdblink::tools::topologyToLevelSet() topologyToLevelSet@endlink tool that generates a level set from the implicit boundary between active and inactive voxels in an input grid of arbitrary type. - Added @link LevelSetPlatonic.h tools::LevelSetPlatonic@endlink a new tool that produces narrow-band level sets of the five Platonic solids. - Added @vdblink::tools::extractIsosurfaceMask() extractIsosurfaceMask@endlink which masks voxels that intersect the implicit surface defined by the given isovalue. - Added a @vdblink::tree::LeafManager::getPrefixSum() getPrefixSum@endlink method to the @vdblink::tree::LeafManager LeafManager@endlink, for user-managed external buffers. - Added a @vdblink::tools::Dense::print() print@endlink method to the @vdblink::tools::Dense Dense@endlink grid class. - Added the @vdblink::math::CoordBBox::Iterator CoordBBox::Iterator@endlink class to conveniently iterate over coordinates covered a CoordBBox. - Added bit-wise operations to the @vdblink::math::CoordBBox CoordBBox@endlink class. - New component wise constructor for the @vdblink::math::CoordBBox CoordBBox@endlink class as well as the method @vdblink::math::CoordBBox::getCornerPoints CoordBBox::getCornerPoints@endlink. - Added a new @vdblink::tree::LeafManager LeafManager@endlink constructor to create the structure from an existing array of leafnodes. - Added active tile count to @vdblink::tree::Tree::print Tree::print@endlink. - Added the templated @vdblink::math::MinMax MinMax@endlink class to compute the extrema of arbitrary value types. - Added @vdblink::Grid::sparseFill() sparseFill@endlink and @vdblink::Grid::denseFill() denseFill@endlink methods to the Grid, Tree and RootNode classes. @par Improvements: - Complete overhaul of the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink tool brings significant performance improvements and enhanced region masking, tile support and bool volume surfacing. - Improved the performance, parallel scaling and memory usage, of @vdblink::tools::LevelSetFracture tools::LevelSetFracture@endlink and updated to use the new @vdblink::tools::segmentSDF() segmentSDF@endlink scheme. - Improved the performance of @vdblink::tools::LevelSetAdvection tools::LevelSetAdvection@endlink by up to five times. - Improved the performance of @vdblink::tree::Tree::voxelizeActiveTiles() Tree::voxelizeActiveTiles@endlink by means of multi-threading. - Improved the performance of the @vdblink::tools::meshToVolume() mesh-to-volume converter@endlink, particularly for large narrow-band widths and for signed distance fields with dense interior regions. - Threaded the Tree destructor and the @vdblink::tree::Tree::clear() Tree::clear@endlink method. - Added a parameter to the @vdblink::tools::signedFloodFill() signedFloodFill@endlink and @vdblink::tools::signedFloodFillWithValues() signedFloodFillWithValues@endlink tools to constrain the flood fill to specific levels of the tree. - Added @vdblink::tree::LeafManager::reduce LeafManager::reduce@endlink and similar methods to @vdblink::tree::NodeManager NodeManager@endlink [Contributed by Brett Tully] - Improved constructors of @vdblink::math::Mat3 math::Mat3@endlink and @vdblink::math::Mat4 Mat4@endlink. - Added @vdblink::math::Mat3::cofactor Mat3::cofactor@endlink. - Added @vdblink::math::Mat3::setRows Mat3::setRows@endlink, @vdblink::math::Mat4::setRows Mat4::setRows@endlink, @vdblink::math::Mat3::setColumns Mat3::setColumns@endlink and @vdblink::math::Mat4::setColumns Mat4::setColumns@endlink. - Added @vdblink::util::NodeMask::isConstant NodeMask::isConstant@endlink method for faster bit processing. - @vdblink::tools::prune tools::prune@endlink performs an improved estimate of tile values by means of medians. - Added toggle to switch between cell centered and node centered transforms to @vdblink::tools::PointPartitioner tools::PointPartitioner@endlink @par Bug fixes: - Fixed a bug in @vdblink::tools::LevelSetAdvection tools::LevelSetAdvection@endlink that could cause non-deterministic behavior. [Reported by Jeff Lait] - Fixed a bug that allowed for unexpected implicit conversion between grids of different value types. - Fixed a bug whereby the origins of leaf nodes with value type @c bool were ignored during equality comparisons. - The @vdblink::tools::GridTransformer grid transformer tool@endlink now correctly handles affine transforms with shear and/or reflection. - Fixed a bug in the @vdblink::tools::meshToVolume() mesh-to-volume converter@endlink that could produce incorrect distances for large bandwidths. - Fixed a bug in @vdblink::tools::meshToVolume() mesh-to-volume converter@endlink that produced different results on machines with different core counts. - Fixed a threading bug in the @vdblink::tools::compReplace() compReplace@endlink tool that could cause crashes. - Resolved a floating-point exception in @vdblink::math::QuantizedUnitVec::pack() math::QuantizedUnitVec::pack@endlink caused by calling the method with a zero-length vector. [Contributed by Rick Hankins] - Improved the API of @vdblink::tools::Dense Dense@endlink with non-const access methods. - Fixed a potential threading bug in @vdblink::io::Queue io::Queue@endlink. [Contributed by Josip Å umeÄ�ki] - Fixed a possible division-by-zero bug in openvdb/tools/LevelSetAdvect.h. [Contributed by Rick Hankins] - Corrected the @vdblink::math::outerProduct outer product@endlink method to not return the transpose result. [Contributed by Gergely Klar] - Fixed a memory overallocation issue in @vdblink::tools::VolumeAdvection VolumeAdvection@endlink. - Fix bug in @vdblink::tools::VolumeToMesh tools::VolumeToMesh@endlink failing to clear its state when exiting early. [Contributed by Edward Lam] - Fixed bug in @vdblink::tools::PointIndexIterator::worldSpaceSearchAndUpdate tools::PointIndexIterator::worldSpaceSearchAndUpdate@endlink that resulted in missing point indices. [Reported by Rick Hankins] - Fixed Windows build issues in unit tests. [Contributed by Edward Lam and Steven Caron] - Fixed @vdblink::math::isApproxZero() isApproxZero@endlink so that it works correctly when tolerance is zero. [Reported by Joshua Olson] - Fixed bugs in @vdblink::tree::NodeUnion NodeUnion@endlink that could cause crashes. - Fixed memory leak in a @vdblink::tools::meshToVolume tools::meshToVolume@endlink sub-tool (expandNarrowband). [Reported by Kévin Dietrich] - Fixed parameter type inconsistencies in @link math/Stencils.h math/Stencils.h@endlink and @link tools/RayIntersector.h tools/RayIntersector.h@endlink. [Contributed by Kévin Dietrich and Nick Avramoussis] - Fixed a bug in the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink tool that produced artifacts for adaptive surface extraction on clipped level sets. [Reported by Jeff Lait] - Corrected empty grid background value in @vdblink::tools::meshToVolume() mesh-to-volume converter@endlink [Contributed by Jeff Lait] - Fixed a bug in @vdblink::tools::volumeToMesh volume-to-mesh converter@endlink that could produce NaNs.[Reported by Rick Hankins] - Fixed a bug in the "Advect Points SOP" that could cause a crash when the input grids were of incorrect type.[Reported by SideFX] @par API changes: - Deprecated @c math::Mat3::setBasis and @c math::Mat4::setBasis. - Renamed @c GudonovsNormSqrd to @vdblink::math::GodunovsNormSqrd GodunovsNormSqrd@endlink [Contributed by Branislav Radjenovic] - Renamed @c ValueType to @c PosType in the PointArray interface. - Deprecated tree::Tree::addLeaf(LeafNode&) and added tree::Tree::addLeaf(LeafNode*). @par Python: - Updated the Python module for Python 3 compatibility. - Updated the Python module for Boost 1.60 compatibility, to address “no to_python (by-value) converter found” exceptions. @par Maya: - Fixed bugs related to data ownership, and improved error checking. [Contributed by Crawford Doran] - Updated the Read and Write DAG nodes to support file sequences and subframe evaluation. @par Houdini: - Added a Segment SOP that separates a grid’s connected components into distinct grids. - Added a LOD SOP that produces a sequences of progressively lower resolution grids. - Added a Topology To Level Set SOP that generates a narrow-band signed distance field / level set from the interface between active and inactive voxels in an arbitrary grid. - Revamped the From Particles SOP UI and added a more efficient level set conversion method that supports Houdini 15 packed points. - Updated the Rasterize Points SOP with support for frustum transforms, sub region masking and orientation logic that matches the native Copy SOP’s orientation. - Updated the Platonic SOP with support for all five Platonic solids. - Added hooks for registering SOP_NodeVDB text callbacks for different grid types. [Contributed by Nick Avramoussis] - The Resample and Combine SOPs now correctly handle affine transforms with shear and/or reflection. - Removed the StaggeredBoxSampler code path in SOP_OpenVDB_Advect because it introduces bias. [Contributed by Fredrik Salomonsson] - Fixed a bug in the Ray SOP whereby the distance attribute was created with the wrong data type. [Contributed by Nick Avramoussis] - The From Polygon SOP now allows the user to either specify the voxel count along an axis or the voxel size in world units (the only option in the past). @htmlonly @endhtmlonly @par Version 3.1.0 - October 1, 2015 @par Highlights: - New features: advection of arbitrary volumes, general-purpose preconditioned linear solver and Poisson solver, segmentation of topologically-enclosed regions of a volume, new and faster bitmask operators, concurrent paged array, volume diagnostics - Optimizations: threaded grid constructors and topology operations; faster mesh to volume conversion, SDF to fog volume conversion and grid pruning; faster, unbounded particle partitioning - New Houdini nodes: Advect, Diagnostics, Rasterize Points, Remap, Remove Divergence, Sort Points @par New features: - Added a @vdblink::tools::VolumeAdvection volume advection@endlink tool for sparse advection of non-level-set volumes. - Added a preconditioned @vdblink::math::pcg::solve() conjugate gradient solver@endlink. - Added a @vdblink::tools::poisson::solve() Poisson solver@endlink for functions sampled on grids. - Added @vdblink::tools::extractEnclosedRegion extractEnclosedRegion@endlink, which detects topologically-enclosed (watertight) exterior regions (cavities) that can result from CSG union operations between level sets with concavities that are capped. (See the unit test @c TestPoissonSolver::testSolveWithSegmentDomain for an example in which this tool is used to identify regions of trapped fluid when solving for pressure in a volume of incompressible fluid.) - Added @vdblink::util::PagedArray PagedArray@endlink, a concurrent, dynamic linear array data structure with fast O(1) value access (both random and sequential). - Added @vdblink::tools::Sampler Sampler@endlink, which provides a unified API for both staggered and non-staggered interpolation of various orders. - Added equality and inequality operators to @vdblink::Metadata Metadata@endlink and @vdblink::MetaMap MetaMap@endlink. - Added @vdblink::tools::CheckLevelSet CheckLevelSet@endlink and @vdblink::tools::CheckFogVolume CheckFogVolume@endlink tools that perform various tests on symmetric, narrow-band level sets and fog volumes, respectively, to diagnose potential issues. - Added support for value accessors that are not registered with their trees. (Bypassing accessor registration can improve performance in rare cases but should be used with caution, since the accessor will be left in an invalid state if the tree topology is modified.) - Added a @vdblink::tree::Tree::stealNodes() stealNodes@endlink method that transfers ownership of all nodes in a tree of a certain type and inserts them into a linear array. - Added a @vdblink::tools::createLevelSetBox() tools::createLevelSetBox@endlink factory function for level-set grids. - Added @vdblink::tools::Dense::offsetToCoord() Dense::offsetToCoord@endlink. - Added @vdblink::tree::LeafBuffer::data() LeafNode::Buffer::data@endlink, which provides direct access to a leaf node’s voxel value array, avoiding out-of-core overhead. Use with caution. - Added a @vdblink::util::NodeMask::foreach() NodeMask::foreach@endlink method for efficient evaluation of complex bitwise operations. - Added a bitwise difference method to @vdblink::util::NodeMask::operator-=() NodeMask@endlink. - Added a @c -version option to @c vdb_print, @c vdb_render and @c vdb_view. @par Improvements: - Deep, conversion and topology copy @vdblink::Grid Grid@endlink constructors are now threaded and up to five times faster. - @vdblink::Grid::topologyUnion() Grid::topologyUnion@endlink, @vdblink::Grid::topologyIntersection() Grid::topologyIntersection@endlink, and @vdblink::Grid::topologyDifference() Grid::topologyDifference@endlink are now much faster due to threading. - Significantly improved the performance, parallel scaling and memory usage of the @vdblink::tools::meshToVolume() mesh to volume@endlink converter, and implemented a more robust inside/outside sign classification scheme. - Reimplemented the @vdblink::tools::PointPartitioner point partitioning@endlink tool for improved performance, concurrency and memory usage. The tool is now unbounded in the sense that points may be distributed anywhere in index space. - Significantly improved the performance of the @vdblink::tools::sdfToFogVolume() SDF to fog volume@endlink converter. - Significantly improved the performance of the @vdblink::tools::sdfInteriorMask() sdfInteriorMask@endlink tool and added support for both grid and tree inputs. - Made various optimizations and improvements to the @vdblink::tools::LevelSetMorphing level set morphing@endlink tool. - Aggregated @vdblink::tools::DiscreteField DiscreteField@endlink and @vdblink::tools::EnrightField EnrightField@endlink (formerly in tools/LevelSetAdvect.h) and @vdblink::tools::VelocitySampler VelocitySampler@endlink and @vdblink::tools::VelocityIntegrator VelocityIntegrator@endlink (formerly in tools/PointAdvect.h) into a single header, tools/VelocityFields.h. - Modified the @vdblink::tools::signedFloodFill() signed flood fill@endlink tool to accept grids of any signed scalar value type, not just floating-point grids. - The @vdblink::tools::prune() prune@endlink tool is now faster, and it employs an improved compression technique on trees with floating-point values. @par Bug fixes: - Fixed a build issue that could result in spurious “Blosc encoding is not supported” errors unless @c OPENVDB_USE_BLOSC was @#defined when compiling client code. - Added NaN and inf checks to the @vdblink::tools::PointPartitioner point partitioning@endlink tool. - Fixed a vdb_view issue whereby the frame buffer size did not necessarily match the window size. [Contributed by Rafael Campos] - Fixed a roundoff issue in @vdblink::tools::LevelSetTracker LevelSetTracker@endlink that could result in NaNs. - Changed @vdblink::tools::CheckNormGrad CheckNormGrad@endlink to check the magnitude of the gradient rather than the square of the magnitude. - Fixed parameter type inconsistencies in math/Ray.h and tools/RayIntersector.h. [Contributed by Kévin Dietrich] - Fixed incorrect handling of signed values in the @vdblink::tools::clip() clip@endlink tool (and the Clip SOP). @par API changes: - Removed the math::Hermite class since it was no longer used and caused build issues for some. - Refactored the @vdblink::tools::LevelSetAdvection level set advection@endlink, @vdblink::tools::LevelSetFilter level set filtering@endlink, @vdblink::tools::LevelSetMeasure level set measuring@endlink and @vdblink::tools::LevelSetTracker level set tracking@endlink tools. - Extended the API of the @vdblink::tools::Diagnose Diagnose@endlink tool and disabled copy construction. - Extended and unified the API of various Samplers. - Added an optional template argument to the @vdblink::tree::ValueAccessor ValueAccessor@endlink class to allow for unregistered accessors. @par Houdini: - Added a Rasterize Points SOP that produces density volumes and transfers arbitrary point attributes using a weighted-average scheme. The node incorporates a VOP subnetwork for procedural modeling, and its accompanying creation script defines a default network with VEX procedures for cloud and velocity field modeling. (See the creation script file header for installation details.) - Merged the Advect Level Set SOP into a new Advect SOP that supports advection of arbitrary volumes, not just level sets. - Added a Remove Divergence SOP that eliminates divergence from a velocity field. - Added a Diagnostics SOP that can identify various problems with level sets, fog volumes and other grids. - Added a Sort Points SOP that spatially reorders a list of points so that points that are close together in space are also close together in the list. This can improve CPU cache coherency and performance for random-access operations. - Added a Remap SOP that maps voxel values in an input range to values in an output range through a user-defined transfer function. - Added an option to the Convert SOP to activate interior voxels. [Contributed by SESI] - The To Spheres SOP can now optionally output a pscale attribute. - Added openvdb_houdini::SOP_NodeVDB::duplicateSourceStealable(), which in conjunction with the Unload flag can help to minimize deep copying of grids between nodes. The Advect, Convert, Fill, Filter, Fracture, Noise, Offset Level Set, Prune, Remap, Remove Divergence, Renormalize Level Set, Resize Narrow Band, Smooth Level Set and Transform SOPs all have this optimization enabled, meaning that they can potentially steal, rather than copy, data from upstream nodes that have the Unload flag enabled. [Contributed by Double Negative] - Redesigned the UI of the Visualize SOP and added toggles to draw with or without color, to use the grid name as the attribute name for points with values, and to attach grid index coordinates to points. - Added toggles to the Filter, Rebuild Level Set, Resize Narrow Band, Smooth Level Set and To Spheres SOPs to specify units in either world space or index space. - Fixed an issue whereby grids generated by the Rebuild Level Set SOP did not always display as surfaces in the viewport. - The Metadata SOP now sets appropriate viewport visualization options when the grid class is changed. @htmlonly @endhtmlonly @par Version 3.0.0 - January 14, 2015 - The @vdblink::io::File File@endlink class now supports delayed loading of .vdb files, meaning that memory is not allocated for voxel values until the values are actually accessed. (This feature is enabled by default.) Until a grid has been fully loaded, its source .vdb file must not be modified or deleted, so for safety, @vdblink::io::File::open() File::open@endlink automatically makes private copies of source files that are smaller than a user-specified limit (see io::File::setCopyMaxBytes()). The limit can be set to zero to disable copying, but if it cannot be guaranteed that a file will not be modified, then it is best not to enable delayed loading for that file. - .vdb files can now optionally be compressed with the Blosc LZ4 codec. Blosc compresses almost as well as ZLIB, but it is much faster. - Added @vdblink::tools::PointPartitioner PointPartitioner@endlink, a tool for fast spatial sorting of points stored in an external array, and @link PointIndexGrid.h PointIndexGrid@endlink, an acceleration structure for fast range and nearest-neighbor searches. - Added @link NodeManager.h tree::NodeManager@endlink, which linearizes a tree to facilitate efficient multithreading across all tree levels. - Added @vdblink::tools::prune() tools::prune@endlink (and other variants), which replaces and outperforms @c Tree::prune. - Added @vdblink::tools::signedFloodFill() tools::signedFloodFill@endlink, which replaces and outperforms @c Tree::signedFloodFill. - Added @vdblink::tools::changeBackground() tools::changeBackground@endlink (and other variants), which replaces and outperforms @c Tree::setBackground(). - Added a fast but approximate narrow-band level set @vdblink::tools::LevelSetTracker::dilate() dilation@endlink method, a fast narrow-band level set @vdblink::tools::LevelSetTracker::erode() erosion@endlink method, and a @vdblink::tools::LevelSetTracker::normalize(const MaskType*) masked normalization@endlink method to @vdblink::tools::LevelSetTracker LevelSetTracker@endlink. - Added @vdblink::tools::Diagnose Diagnose@endlink, which performs multithreaded diagnostics on grids to identify issues like values that are NaNs or out-of-range. It optionally generates a boolean grid of all values that fail user-defined tests. - Added optional alpha masks to @vdblink::tools::LevelSetMorphing LevelSetMorphing@endlink. - Fixed an intermittent crash in @vdblink::tools::LevelSetMorphing LevelSetMorphing@endlink. - Added @c tools::topologyToLevelSet(), which generates a level set from the implicit boundary between active and inactive voxels in an arbitrary input grid. [DWA internal] - Improved the performance of point scattering (by orders of magnitude) and added a @vdblink::tools::DenseUniformPointScatter DenseUniformPointScatter@endlink class as well as support for fractional numbers of particles per voxel. - Improved the performance and memory footprint of the @vdblink::tools::ParticlesToLevelSet ParticlesToLevelSet@endlink tool for large numbers (tens to hundreds of millions) of particles. - Added edge-adjacent (6+12=18 neighbors) and vertex-adjacent (6+12+8=26 neighbors) dilation algorithms to @vdblink::tools::morphology::Morphology::dilateVoxels Morphology::dilateVoxels@endlink. The default dilation pattern is still face-adjacent (6 neighbors). - Added @vdblink::tree::Tree::getNodes() Tree::getNodes@endlink, which allows for fast construction of linear arrays of tree nodes for use in multithreaded code such as the @vdblink::tree::LeafManager LeafManager@endlink or @link NodeManager.h tree::NodeManager@endlink. - Added @vdblink::math::Extrema math::Extrema@endlink and @vdblink::tools::extrema() tools::extrema@endlink to efficiently compute minimum and maximum values in a grid. - Added support for material color grids to all level set @vdblink::tools::BaseShader shaders@endlink, and added an option to @c vdb_render that allows one to specify a reference grid to be used for material color lookups. - Added @vdblink::getLibraryVersionString() getLibraryVersionString@endlink and @link OPENVDB_LIBRARY_VERSION_STRING OPENVDB_LIBRARY_VERSION_STRING@endlink. - Modified the mesh to volume converter to always set the grid background value to the exterior narrow-band width, and added finite value checks to narrow band parameters. - @vdblink::tools::volumeToMesh() tools::volumeToMesh@endlink now compiles for all grid types but throws an exception if the input grid does not have a scalar value type. - Added a @vdblink::io::File::readGrid(const Name&, const BBoxd&) File::readGrid@endlink overload and @vdblink::GridBase::readBuffers(std::istream&, const CoordBBox&) readBuffers@endlink overloads to the grid, tree and node classes that allow one to specify a bounding box against which to clip a grid while reading it. For large grids, clipping while reading can result in significantly lower memory usage than clipping after reading. - Added @vdblink::GridBase::clipGrid() GridBase::clipGrid@endlink, which clips a grid against a world-space bounding box, and @vdblink::GridBase::clip() GridBase::clip@endlink and @vdblink::tree::Tree::clip() Tree::clip@endlink, which clip against an index-space bounding box. - Added @vdblink::tools::clip() tools::clip@endlink, which clips a grid either against a bounding box or against the active voxels of a mask grid. - @c io::File::readGridPartial allocates the nodes of a grid’s tree as before, but it now allocates leaf nodes without data buffers. (This feature is mainly for internal use. Partially-read grids should be used with care if at all, and they should be treated as read-only.) - Grid names retrieved using a @vdblink::io::File::NameIterator File::NameIterator@endlink now always uniquely identify grids; they no longer generate ‘more than one grid named “x”’ warnings when there are multiple grids of the same name in a file (for files written starting with this version of the OpenVDB library). - Fixed a bug in @vdblink::tree::Tree::ValueOffIter Tree::ValueOffIter@endlink that could cause @vdblink::tree::TreeValueIteratorBase::setMaxDepth() depth-bounded@endlink iterators to return incorrect values. - Eliminated a recursive call in @vdblink::tree::TreeValueIteratorBase::next() TreeValueIteratorBase::next@endlink that could cause crashes on systems with a limited stack size. - Fixed memory leaks in @vdblink::tree::RootNode::topologyDifference() RootNode::topologyDifference@endlink and @vdblink::tree::RootNode::topologyIntersection() RootNode::topologyIntersection@endlink. - Fixed a memory leak in @vdblink::io::Queue io::Queue@endlink when the queue was full and a write task could not be added within the timeout interval. - Fixed a potential division by zero crash in @vdblink::tools::compDiv() tools::compDiv@endlink with integer-valued grids. - Fixed kernel normalization in the @vdblink::tools::Filter filter tool@endlink so that it is correct for integer-valued grids. - Fixed a bug in @vdblink::tree::LeafBuffer::getValue() LeafNode::Buffer::getValue@endlink whereby Visual C++ would return a reference to a temporary. [Contributed by SESI] - Fixed a bug in @vdblink::tools::ParticlesToLevelSet tools::ParticlesToLevelSet@endlink related to attribute transfer when leaf nodes are produced without active values. - Added @vdblink::util::CpuTimer util::CpuTimer@endlink and removed the more simplistic @c unittest_util::CpuTimer from @c unittest/util.h. - Eliminated the use of @c getopt for command-line argument parsing in @c vdb_test. - @vdblink::initialize() openvdb::initialize@endlink now properly initializes log4cplus if it is enabled, eliminating “No appenders could be found” errors. - Fixed a bug in the @vdblink::math::QuantizedUnitVec::pack() QuantizedUnitVec::pack@endlink method that caused quantization artifacts. - Added convenience class @vdblink::tools::AlphaMask AlphaMask@endlink - Added constructors and methods to both @vdblink::math::RandInt RandInt@endlink and @vdblink::math::Rand01 Rand01@endlink to set and reset the random seed value. - Added convenience methods for @vdblink::math::Transform::indexToWorld(const BBoxd&) const transforming@endlink @vdblink::math::Transform::worldToIndex(const BBoxd&) const bounding@endlink @vdblink::math::Transform::worldToIndexCellCentered(const BBoxd&) const boxes@endlink to @vdblink::math::Transform math::Transform@endlink. - @c vdb_view is now compatible with both GLFW 2 and GLFW 3. - Made many small changes to address type conversion and other warnings reported by newer compilers like GCC 4.8 and ICC 14. - Replaced the @c HALF_INCL_DIR and @c HALF_LIB_DIR Makefile variables with @c ILMBASE_INCL_DIR and @c ILMBASE_LIB_DIR and added @c ILMBASE_LIB, to match OpenEXR’s library organization. [Contributed by Double Negative] - Eliminated most local (function-scope) static variables, because Visual C++ doesn’t guarantee thread-safe initialization of local statics. [Contributed by SESI] - Fixed a bug in @vdblink::readString() readString@endlink related to empty strings. [Contributed by Fabio Piparo] - Fixed a bug in the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink simplification scheme that was creating visual artifacts. @par API changes: - The addition of a @vdblink::GridBase::readBuffers(std::istream&, const CoordBBox&) GridBase::readBuffers@endlink virtual function overload and the @vdblink::GridBase::clip() GridBase::clip@endlink @vdblink::GridBase::readNonresidentBuffers() GridBase::readNonresidentBuffers@endlink and @vdblink::tree::Tree::clipUnallocatedNodes() Tree::clipUnallocatedNodes@endlink virtual functions changes the grid ABI so that it is incompatible with earlier versions of the OpenVDB library (such as the ones in Houdini 12.5 and 13). Define the macro @c OPENVDB_2_ABI_COMPATIBLE when compiling OpenVDB to disable these changes and preserve ABI compatibility. - All @vdblink::tools::BaseShader shaders@endlink now have a template argument to specify the type of an optional material color grid, but the default type mimics the old, uniform color behavior. - Removed a deprecated @vdblink::io::Stream::write() io::Stream::write@endlink overload. - The point counts in @vdblink::tools::UniformPointScatter UniformPointScatter@endlink and @vdblink::tools::NonUniformPointScatter NonUniformPointScatter@endlink are now specified and returned as @vdblink::Index64 Index64@endlink. - @vdblink::math::RandInt RandInt@endlink has an extra template argument to specify the integer type. The @vdblink::math::RandomInt RandomInt@endlink typedef is unchanged. - @vdblink::io::readData() io::readData@endlink, @vdblink::io::HalfReader::read() io::HalfReader::read@endlink and @vdblink::io::HalfWriter::write() io::HalfWriter::write@endlink now take a @c uint32_t argument indicating the type of compression instead of a @c bool indicating whether compression is enabled. - Removed @c io::Archive::isCompressionEnabled() and @c io::Archive::setCompressionEnabled() and renamed @c io::Archive::compressionFlags() and @c io::Archive::setCompressionFlags() to @vdblink::io::Archive::compression() io::Archive::compression@endlink and @vdblink::io::Archive::setCompression() io::Archive::setCompression@endlink. - Internal and leaf node classes are now required to provide "PartialCreate" constructors that optionally bypass the allocation of voxel buffers. Leaf node classes must now also provide @vdblink::tree::LeafNode::allocate() allocate@endlink and @vdblink::tree::LeafNode::isAllocated() isAllocated@endlink methods to manage the allocation of their buffers. - Removed @c pruneInactive and @c pruneLevelSet methods from the @vdblink::tree::Tree Tree@endlink and various node classes. These methods have been replaced by the much faster pruning functions found in tools/Prune.h. - Removed @c signedFloodFill methods from the @vdblink::Grid Grid@endlink, @vdblink::tree::Tree Tree@endlink and various node classes. These methods have been replaced by the much faster functions found in tools/SignedFloodFill.h. - Removed @c Grid::setBackground() and @c Tree::setBackground() (use the faster @vdblink::tools::changeBackground() changeBackground@endlink tool instead), and removed the default argument from @vdblink::tree::RootNode::setBackground() RootNode::setBackground@endlink. @par Python: - Added grid methods @c convertToPolygons() and @c convertToQuads(), which convert volumes to meshes, and @c createLevelSetFromPolygons(), which converts meshes to volumes. NumPy is required. @par Maya: - Added an adaptive polygonal surface extraction node. @par Houdini: - Added a new Resize Narrow Band SOP that can efficiently adjust the width of a level set’s narrow band. This allows, for example, for a level set to be created quickly from points or polygons with a very narrow band that is then quickly resized to a desired width. - Fixed bugs in the Smooth Level Set and Reshape Level Set SOPs that caused them to ignore the selected discretization scheme. - Added a Morph Level Set SOP. - Added a From Points SOP to very quickly generate a level set from a point cloud, ignoring any radius attribute. [DWA internal] - Added a Voxel Scale mode to the Resample SOP. - Improved the performance and memory footprint of the From Particles SOP for large numbers (tens to hundreds of millions) of particles. - The Scatter SOP now accepts fractional numbers of particles per voxel. - Improved the performance of the Scatter SOP by more than an order of magnitude. - The Clip SOP now has a toggle to choose explicitly between a mask grid or a bounding box as the clipping region. As a consequence, the mask grid can now be unnamed. - Added the OpenVDB library version number to the Extended Operator Information for all SOPs. - SOPs are now linked with an rpath to the directory containing the OpenVDB library. - Like the native Houdini file SOP, the Read SOP now allows missing frames to be reported either as errors or as warnings. - The Read SOP now has an optional input for geometry, the bounding box of which can be used to clip grids as they are read. For large grids, clipping while reading can result in significantly lower memory usage than clipping after reading. - The From Polygons and Convert SOPs now default to using the polygon soup mesh representation, which uses less memory. @htmlonly @endhtmlonly @par Version 2.3.0 - April 23, 2014 - Added @vdblink::tools::extractSparseTree() extractSparseTree@endlink, which selectively extracts and transforms data from a dense grid to produce a sparse tree, and @vdblink::tools::extractSparseTreeWithMask() extractSparseTreeWithMask@endlink, which copies data from the index-space intersection of a sparse tree and a dense input grid. - Added copy constructors to the @vdblink::Grid::Grid(const Grid&) Grid@endlink, @vdblink::tree::Tree::Tree(const Tree&) Tree@endlink, @vdblink::tree::RootNode::RootNode(const RootNode&) RootNode@endlink, @vdblink::tree::InternalNode::InternalNode(const InternalNode&) InternalNode@endlink and @vdblink::tree::LeafNode::LeafNode(const LeafNode&) LeafNode@endlink classes, and an assignment operator overload to @vdblink::tree::RootNode::operator=(const RootNode&) RootNode@endlink, that allow the source and destination to have different value types. - Modified @vdblink::tree::Tree::combine2() Tree::combine2@endlink to permit combination of trees with different value types. - Added @vdblink::CanConvertType CanConvertType@endlink and @vdblink::tree::RootNode::SameConfiguration RootNode::SameConfiguration@endlink metafunctions, which perform compile-time tests for value type and tree type compatibility, and a @vdblink::tree::RootNode::hasCompatibleValueType() RootNode::hasCompatibleValueType@endlink method, which does runtime checking. - Added optional support for logging using log4cplus. See logging.h and the @c INSTALL file for details. - Added @vdblink::tools::VolumeRayIntersector::hits() VolumeRayIntersector::hits@endlink, which returns all the hit segments along a ray. This is generally more efficient than repeated calls to @vdblink::tools::VolumeRayIntersector::march() VolumeRayIntersector::march@endlink. - Added member class @vdblink::math::Ray::TimeSpan Ray::TimeSpan@endlink and method @vdblink::math::Ray::valid() Ray::valid@endlink, and deprecated method @vdblink::math::Ray::test() Ray::test@endlink. - Fixed a bug in @vdblink::math::VolumeHDDA VolumeHDDA@endlink that could cause rendering artifacts when a ray’s start time was zero. [Contributed by Mike Farnsworth] - Added a @vdblink::tools::compositeToDense() compositeToDense@endlink tool, which composites data from a sparse tree into a dense array, using a sparse alpha mask. Over, Add, Sub, Min, Max, Mult, and Set are supported operations. - Added a @vdblink::tools::transformDense() transformDense@endlink tool, which applies a functor to the value of each voxel of a dense grid within a given bounding box. - Improved the performance of node iterators. @par API changes: - Collected the digital differential analyzer code from math/Ray.h and tools/RayIntersector.h into a new header file, math/DDA.h. - Rewrote @vdblink::math::VolumeHDDA VolumeHDDA@endlink and made several changes to its API. (@vdblink::math::VolumeHDDA VolumeHDDA@endlink is used internally by @vdblink::tools::VolumeRayIntersector VolumeRayIntersector@endlink, whose API is unchanged.) - @vdblink::tree::Tree::combine2() Tree::combine2@endlink, @vdblink::tree::RootNode::combine2() RootNode::combine2@endlink, @vdblink::tree::InternalNode::combine2() InternalNode::combine2@endlink, @vdblink::tree::LeafNode::combine2() LeafNode::combine2@endlink and @vdblink::CombineArgs CombineArgs@endlink all now require an additional template argument, which determines the type of the other tree. - Assignment operators for @vdblink::tree::LeafManager::LeafRange::Iterator::operator=() LeafManager::LeafRange::Iterator@endlink, @vdblink::util::BaseMaskIterator::operator=() BaseMaskIterator@endlink, @vdblink::util::NodeMask::operator=() NodeMask@endlink and @vdblink::util::RootNodeMask::operator=() RootNodeMask@endlink now return references to the respective objects. - Removed a number of methods that were deprecated in version 2.0.0 or earlier. @par Houdini: - Added a Clip SOP, which does volumetric clipping. - Added an Occlusion Mask SOP, which generates a mask of the voxels inside a camera frustum that are occluded by objects in an input grid. - The Combine SOP now applies the optional signed flood fill only to level set grids, since that operation isn’t meaningful for other grids. - The Filter SOP now processes all grid types, not just scalar grids. @htmlonly @endhtmlonly @par Version 2.2.0 - February 20, 2014 - Added a simple, multithreaded @vdblink::tools::VolumeRender volume renderer@endlink, and added volume rendering support to the @c vdb_render command-line renderer. - Added an option to the @vdblink::tools::LevelSetRayIntersector LevelSetRayIntersector@endlink and to @c vdb_render to specify the isovalue of the level set. - Added methods to the @vdblink::tools::LevelSetRayIntersector LevelSetRayIntersector@endlink to return the time of intersection along a world or index ray and to return the level set isovalue. - Improved the performance of the @vdblink::tools::VolumeRayIntersector VolumeRayIntersector@endlink and added support for voxel dilation to account for interpolation kernels. - Added a @ref sInterpolation "section" to the Cookbook on interpolation using @vdblink::tools::BoxSampler BoxSampler@endlink, @vdblink::tools::GridSampler GridSampler@endlink, @vdblink::tools::DualGridSampler DualGridSampler@endlink, et al. - Added a @ref secGrid "section" to the Overview on grids and grid metadata. - Modified @vdblink::tools::DualGridSampler DualGridSampler@endlink so it is more consistent with @vdblink::tools::GridSampler GridSampler@endlink. - The @vdblink::tools::cpt() cpt@endlink, @vdblink::tools::curl() curl@endlink, @vdblink::tools::laplacian() laplacian@endlink, @vdblink::tools::meanCurvature() meanCurvature@endlink and @vdblink::tools::normalize() normalize@endlink tools now output grids with appropriate @vdblink::VecType vector types@endlink (covariant, contravariant, etc.). - Added a @vdblink::tools::transformVectors() transformVectors@endlink tool, which applies an affine transformation to the voxel values of a vector-valued grid in accordance with the grid’s @vdblink::VecType vector type@endlink and @vdblink::Grid::isInWorldSpace() world space/local space@endlink setting. - Added a @vdblink::tools::compDiv() compDiv@endlink tool, which combines grids by dividing the values of corresponding voxels. - Fixed a bug in the mean curvature computation that could produce NaNs in regions with constant values. - Added a @vdblink::Grid::topologyDifference() Grid::topologyDifference@endlink method. - Added @vdblink::math::Vec3::exp() exp@endlink and @vdblink::math::Vec3::sum() sum@endlink methods to @vdblink::math::Vec2 Vec2@endlink, @vdblink::math::Vec3 Vec3@endlink and @vdblink::math::Vec4 Vec4@endlink. - Improved the @vdblink::tools::fillWithSpheres() fillWithSpheres@endlink tool for small volumes that are just a few voxels across. - Improved the accuracy of the mesh to volume converter. - Fixed a bug in the mesh to volume converter that caused incorrect sign classifications for narrow-band level sets. - Fixed a bug in @vdblink::math::NonlinearFrustumMap::applyIJT() NonlinearFrustumMap::applyIJT@endlink that resulted in incorrect values when computing the gradient of a grid with a frustum transform. - Fixed a file I/O bug whereby some .vdb files could not be read correctly if they contained grids with more than two distinct inactive values. - Fixed an off-by-one bug in the numbering of unnamed grids in .vdb files. The first unnamed grid in a file is now retrieved using the name “[0]”, instead of “[1]”. - Fixed a build issue reported by Clang 3.2 in tools/GridOperators.h. - Fixed a memory leak in @vdblink::tools::Film Film@endlink. - Added library and file format version number constants to the Python module. - Improved convergence in the @vdblink::tools::VolumeRender volume renderer@endlink. [Contributed by Jerry Tessendorf and Mark Matthews] - Made various changes for compatibility with Houdini 13 and with C++11 compilers. [Contributed by SESI] @par API changes: - @vdblink::tools::VolumeRayIntersector::march() VolumeRayIntersector::march@endlink no longer returns an @c int to distinguish tile vs. voxel hits. Instead, it now returns @c false if no intersection is detected and @c true otherwise. Also, @e t0 and @e t1 might now correspond to the first and last hits of multiple adjacent leaf nodes and/or active tiles. - @vdblink::tools::DualGridSampler DualGridSampler@endlink is no longer templated on the target grid type, and the value accessor is now passed as an argument. - The .vdb file format has changed slightly. Tools built with older versions of OpenVDB should be recompiled to ensure that they can read files in the new format. @par Houdini: - Added topology union, intersection and difference operations to the Combine SOP. These operations combine the active voxel topologies of grids that may have different value types. - Added a Divide operation to the Combine SOP. - Added support for boolean grids to the Combine, Resample, Scatter, Prune and Visualize SOPs. - The Fill SOP now accepts a vector as the fill value, and it allows the fill region bounds to be specified either in index space (as before), in world space, or using the bounds of geometry connected to an optional new reference input. - Added a toggle to the Offset Level Set SOP to specify the offset in either world or voxel units. - Added a toggle to the Transform and Resample SOPs to apply the transform to the voxel values of vector-valued grids, in accordance with those grids’ @vdblink::VecType vector types@endlink and @vdblink::Grid::isInWorldSpace() world space/local space@endlink settings. - Added a Vector Type menu to the Vector Merge SOP. - Removed masking options from the Renormalize SOP (since masking is not supported yet). - Reimplemented the Vector Merge SOP for better performance and interruptibility and to fix a bug in the handling of tile values. @htmlonly @endhtmlonly @par Version 2.1.0 - December 12, 2013 - Added a small number of Maya nodes, primarily for conversion of geometry to and from OpenVDB volumes and for visualization of volumes. - Added an initial implementation of @vdblink::tools::LevelSetMorphing level set morphing@endlink (with improvements to follow soon). - Added @vdblink::tools::LevelSetMeasure tools::LevelSetMeasure@endlink, which efficiently computes the surface area, volume and average mean-curvature of narrow-band level sets, in both world and voxel units. Those quantities are now exposed as intrinsic attributes on the Houdini VDB primitive and can be queried using the native Measure SOP. - @vdblink::tools::Dense tools::Dense@endlink now supports the XYZ memory layout used by Houdini and Maya in addition to the ZYX layout used in OpenVDB trees. - Improved the performance of masking in the @vdblink::tools::LevelSetFilter level set filter@endlink tool and added inversion and scaling of the mask input, so that any scalar-valued volume can be used as a mask, not just volumes with a [0, 1] range. - Added optional masking to the non-level-set filters, to the grid operators (CPT, curl, divergence, gradient, Laplacian, mean curvature, magnitude, and normalize) and to the Analysis and Filter SOPs. - Added more narrow band controls to the Rebuild Level Set SOP. - Improved the accuracy of the @vdblink::tools::levelSetRebuild() level set rebuild@endlink tool. - Added @vdblink::tools::activate() tools::activate@endlink and @vdblink::tools::deactivate() tools::deactivate@endlink, which set the active states of tiles and voxels whose values are equal to or approximately equal to a given value, and added a Deactivate Background Voxels toggle to the Combine SOP. - Added @vdblink::math::BBox::applyMap() BBox::applyMap@endlink and @vdblink::math::BBox::applyInverseMap() BBox::applyInverseMap@endlink, which allow for transformation of axis-aligned bounding boxes. - Added a @vdblink::tools::PositionShader position shader@endlink to the level set ray-tracer (primarily for debugging purposes). - Added an @vdblink::io::Queue io::Queue@endlink class that manages a concurrent queue for asynchronous serialization of grids to files or streams. - Fixed a bug in @vdblink::io::Archive io::Archive@endlink whereby writing unnamed, instanced grids (i.e., grids sharing a tree) to a file rendered the file unreadable. - Fixed a bug in the @vdblink::tools::VolumeToMesh volume to mesh@endlink converter that caused it to generate invalid polygons when the zero crossing lay between active and inactive regions. - Fixed a bug in the @vdblink::tools::UniformPointScatter point scatter@endlink tool (and the Scatter SOP) whereby the last voxel always remained empty. - Fixed a bug in the Read SOP that caused grids with the same name to be renamed with a numeric suffix (e.g., “grid[1]” “grid[2]”, etc.). - Fixed some unit test failures on 64-bit Itanium machines. @par API changes: - The @vdblink::tools::Filter Filter@endlink tool is now templated on a mask grid, and threading is controlled using a grain size, for consistency with most of the other level set tools. - The @vdblink::tools::LevelSetFilter LevelSetFilter@endlink tool is now templated on a mask grid. - All shaders now take a ray direction instead of a ray. @htmlonly @endhtmlonly @par Version 2.0.0 - October 31, 2013 - Added a @ref python "Python module" with functions for basic manipulation of grids (but no tools, yet). - Added ray intersector tools for efficient, hierarchical intersection of rays with @vdblink::tools::LevelSetRayIntersector level-set@endlink and @vdblink::tools::VolumeRayIntersector generic@endlink volumes. - Added a @vdblink::math::Ray Ray@endlink class and a hierarchical @vdblink::math::DDA Digital Differential Analyzer@endlink for fast ray traversal. - Added a fully multi-threaded @vdblink::tools::LevelSetRayTracer level set ray tracer@endlink and @vdblink::tools::PerspectiveCamera camera@endlink @vdblink::tools::OrthographicCamera classes@endlink that mimic Houdini’s cameras. - Added a simple, command-line renderer (currently for level sets only). - Implemented a new meshing scheme that produces topologically robust two-manifold meshes and is twice as fast as the previous scheme. - Implemented a new, topologically robust (producing two-manifold meshes) level-set-based seamless fracture scheme. The new scheme eliminates visible scarring seen in the previous implementation by subdividing internal, nonplanar quads near fracture seams. In addition, fracture seam points are now tagged, allowing them to be used to drive pre-fracture dynamics such as local surface buckling. - Improved the performance of @vdblink::tree::Tree::evalActiveVoxelBoundingBox() Tree::evalActiveVoxelBoundingBox@endlink and @vdblink::tree::Tree::activeVoxelCount() Tree::activeVoxelCount@endlink, and significantly improved the performance of @vdblink::tree::Tree::evalLeafBoundingBox() Tree::evalLeafBoundingBox@endlink (by about 30x). - Added a tool (and a Houdini SOP) that fills a volume with adaptively-sized overlapping or non-overlapping spheres. - Added a Ray SOP that can be used to perform geometry projections using level-set ray intersections or closest-point queries. - Added a @vdblink::tools::ClosestSurfacePoint tool@endlink that performs accelerated closest surface point queries from arbitrary points in world space to narrow-band level sets. - Increased the speed of masked level set filtering by 20% for the most common cases. - Added @vdblink::math::BoxStencil math::BoxStencil@endlink, with support for trilinear interpolation and gradient computation. - Added @vdblink::tree::Tree::topologyIntersection() Tree::topologyIntersection@endlink, which intersects a tree’s active values with those of another tree, and @vdblink::tree::Tree::topologyDifference() Tree::topologyDifference@endlink, which performs topological subtraction of one tree’s active values from another’s. In both cases, the ValueTypes of the two trees need not be the same. - Added @vdblink::tree::Tree::activeTileCount() Tree::activeTileCount@endlink, which returns the number of active tiles in a tree. - Added @vdblink::math::MinIndex() math::MinIndex@endlink and @vdblink::math::MaxIndex() math::MaxIndex@endlink, which find the minimum and maximum components of a vector without any branching. - Added @vdblink::math::BBox::minExtent() BBox::minExtent@endlink, which returns a bounding box’s shortest axis. - The default @vdblink::math::BBox BBox@endlink constructor now generates an invalid bounding box rather than an empty bounding box positioned at the origin. The new behavior is consistent with @vdblink::math::CoordBBox CoordBBox@endlink. [Thanks to Rick Hankins for suggesting this fix.] - Added @vdblink::math::CoordBBox::reset() CoordBBox::reset@endlink, which resets a bounding box to its initial, invalid state. - Fixed a bug in the default @vdblink::math::ScaleMap ScaleMap@endlink constructor that left some data used in the inverse uninitialized. - Added @vdblink::math::MapBase::applyJT MapBase::applyJT@endlink, which applies the Jacobian transpose to a vector (the Jacobian transpose takes a range-space vector to a domain-space vector, e.g., world to index), and added @vdblink::math::MapBase::inverseMap() MapBase::inverseMap@endlink, which returns a new map representing the inverse of the original map (except for @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink, which does not currently have a defined inverse map).
@b Note: Houdini 12.5 uses an earlier version of OpenVDB, and maps created with that version lack virtual table entries for these new methods, so do not call these methods from Houdini 12.5. - Reimplemented @vdblink::math::RandomInt math::RandomInt@endlink using Boost.Random instead of @c rand() (which is not thread-safe), and deprecated @c math::randUniform() and added @vdblink::math::Random01 math::Random01@endlink to replace it. - Modified @vdblink::tools::copyFromDense() tools::copyFromDense@endlink and @vdblink::tools::copyToDense() tools::copyToDense@endlink to allow for implicit type conversion (e.g., between a @vdblink::tools::Dense Dense<Int32>@endlink and a @vdblink::FloatTree FloatTree@endlink) and fixed several bugs in @vdblink::tools::CopyFromDense tools::CopyFromDense@endlink. - Fixed bugs in @vdblink::math::Stats math::Stats@endlink and @vdblink::math::Histogram math::Histogram@endlink that could produce NaNs or other incorrect behavior if certain methods were called on populations of size zero. - Renamed struct tolerance to @vdblink::math::Tolerance math::Tolerance@endlink and @c negative to @vdblink::math::negative() math::negative@endlink and removed @c math::toleranceValue(). - Implemented a closest point on line segment algorithm, @vdblink::math::closestPointOnSegmentToPoint() math::closestPointOnSegmentToPoint@endlink. - Fixed meshing issues relating to masking and automatic partitioning. - @vdblink::Grid::merge() Grid::merge@endlink and @vdblink::tree::Tree::merge() Tree::merge@endlink now accept an optional @vdblink::MergePolicy MergePolicy@endlink argument that specifies one of three new merging schemes. (The old merging scheme, which is no longer available, used logic for each tree level that was inconsistent with the other levels and that could result in active tiles being replaced with nodes having only inactive values.) - Renamed @c LeafNode::coord2offset(), @c LeafNode::offset2coord() and @c LeafNode::offset2globalCoord() to @vdblink::tree::LeafNode::coordToOffset() coordToOffset@endlink, @vdblink::tree::LeafNode::offsetToLocalCoord() offsetToLocalCoord@endlink, and @vdblink::tree::LeafNode::offsetToGlobalCoord() offsetToGlobalCoord@endlink, respectively, and likewise for @vdblink::tree::InternalNode::offsetToGlobalCoord() InternalNode@endlink. [Thanks to Rick Hankins for suggesting this change.] - Replaced @vdblink::tree::Tree Tree@endlink methods @c setValueOnMin, @c setValueOnMax and @c setValueOnSum with @vdblink::tools::setValueOnMin() tools::setValueOnMin@endlink, @vdblink::tools::setValueOnMax() tools::setValueOnMax@endlink and @vdblink::tools::setValueOnSum() tools::setValueOnSum@endlink (and a new @vdblink::tools::setValueOnMult() tools::setValueOnMult@endlink) and added @vdblink::tree::Tree::modifyValue() Tree::modifyValue@endlink and @vdblink::tree::Tree::modifyValueAndActiveState() Tree::modifyValueAndActiveState@endlink, which modify voxel values in-place via user-supplied functors. Similarly, replaced @c ValueAccessor::setValueOnSum() with @vdblink::tree::ValueAccessor::modifyValue() ValueAccessor::modifyValue@endlink and @vdblink::tree::ValueAccessor::modifyValueAndActiveState() ValueAccessor::modifyValueAndActiveState@endlink, and added a @vdblink::tree::TreeValueIteratorBase::modifyValue() modifyValue@endlink method to all value iterators. - Removed @c LeafNode::addValue and @c LeafNode::scaleValue. - Added convenience classes @vdblink::tree::Tree3 tree::Tree3@endlink and @vdblink::tree::Tree5 tree::Tree5@endlink for custom tree configurations. - Added an option to the From Particles SOP to generate an alpha mask, which can be used to constrain level set filtering so as to preserve surface details. - The mesh to volume converter now handles point-degenerate polygons. - Fixed a bug in the Level Set Smooth, Level Set Renormalize and Level Set Offset SOPs that caused the group name to be ignored. - Fixed various OS X and Windows build issues. [Contributions from SESI and DD] @htmlonly @endhtmlonly @par Version 1.2.0 - June 28 2013 - @vdblink::tools::LevelSetFilter Level set filters@endlink now accept an optional alpha mask grid. - Implemented sharp feature extraction for level set surfacing. This enhances the quality of the output mesh and reduces aliasing artifacts. - Added masking options to the meshing tools, as well as a spatial multiplier for the adaptivity threshold, automatic partitioning, and the ability to preserve edges and corners when mesh adaptivity is applied. - The mesh to volume attribute transfer scheme now takes surface orientation into account, which improves accuracy in proximity to edges and corners. - Added a @vdblink::tree::LeafManager::foreach() foreach@endlink method to @vdblink::tree::LeafManager tree::LeafManager@endlink that, like @vdblink::tools::foreach() tools::foreach@endlink, applies a user-supplied functor to each leaf node in parallel. - Rewrote the particle to level set converter, simplifying the API, improving performance (especially when particles have a fixed radius), adding the capability to transfer arbitrary point attributes, and fixing a velocity trail bug. - Added utility methods @vdblink::math::Sign() Sign@endlink, @vdblink::math::SignChange() SignChange@endlink, @vdblink::math::isApproxZero() isApproxZero@endlink, @vdblink::math::Cbrt() Cbrt@endlink and @vdblink::math::ZeroCrossing() ZeroCrossing@endlink to math/Math.h. - Added a @vdblink::tree::ValueAccessor3::probeNode() probeNode@endlink method to the value accessor and to tree nodes that returns a pointer to the node that contains a given voxel. - Deprecated @c LeafNode::addValue and @c LeafNode::scaleValue. - Doubled the speed of the mesh to volume converter (which also improves the performance of the fracture and level set rebuild tools) and improved its inside/outside voxel classification near edges and corners. - @vdblink::tools::GridSampler GridSampler@endlink now accepts either a grid, a tree or a value accessor, and it offers faster index-based access methods and much better performance in cases where many instances are allocated. - Extended @vdblink::tools::Dense tools::Dense@endlink to make it more compatible with existing tools. - Fixed a crash in @vdblink::io::Archive io::Archive@endlink whenever the library was unloaded from memory and then reloaded. [Contributed by Ollie Harding] - Fixed a bug in @c GU_PrimVDB::buildFromPrimVolume(), seen during the conversion from Houdini volumes to OpenVDB grids, that could cause signed flood fill to be applied to non-level set grids, resulting in active tiles with incorrect values. - Added a Prune SOP with several pruning schemes. @htmlonly @endhtmlonly @par Version 1.1.1 - May 10 2013 - Added a simple @vdblink::tools::Dense dense grid class@endlink and tools to copy data from dense voxel arrays into OpenVDB grids and vice-versa. - Starting with Houdini 12.5.396, plugins built with this version of OpenVDB can coexist with native Houdini OpenVDB nodes. - The level set fracture tool now smooths seam line edges during mesh extraction, eliminating staircase artifacts. - Significantly improved the performance of the @vdblink::util::leafTopologyIntersection() leafTopologyIntersection@endlink and @vdblink::util::leafTopologyDifference() leafTopologyDifference@endlink utilities and added a @vdblink::tree::LeafNode::topologyDifference() LeafNode::topologyDifference@endlink method. - Added convenience functions that provide simplified interfaces to the @vdblink::tools::meshToLevelSet() mesh to volume@endlink and @vdblink::tools::volumeToMesh() volume to mesh@endlink converters. - Added a @vdblink::tools::accumulate() tools::accumulate@endlink function that is similar to @vdblink::tools::foreach() tools::foreach@endlink but can be used to accumulate the results of computations over the values of a grid. - Added @vdblink::tools::statistics() tools::statistics@endlink, @vdblink::tools::opStatistics() tools::opStatistics@endlink and @vdblink::tools::histogram() tools::histogram@endlink, which efficiently compute statistics (mean, variance, etc.) and histograms of grid values (using @vdblink::math::Stats math::Stats@endlink and @vdblink::math::Histogram math::Histogram@endlink). - Modified @vdblink::math::CoordBBox CoordBBox@endlink to adhere to TBB’s splittable type requirements, so that, for example, a @c CoordBBox can be used as a blocked iteration range. - Added @vdblink::tree::Tree::addTile() Tree::addTile@endlink, @vdblink::tree::Tree::addLeaf() Tree::addLeaf@endlink and @vdblink::tree::Tree::stealNode() Tree::stealNode@endlink, for fine control over tree construction. - Addressed a numerical stability issue when performing Gaussian filtering of level set grids. - Changed the return type of @vdblink::math::CoordBBox::volume() CoordBBox::volume@endlink to reduce the risk of overflow. - When the input mesh is self-intersecting, the mesh to volume converter now produces a level set with a monotonic gradient field. - Fixed a threading bug in the mesh to volume converter that caused it to produce different results for the same input. - Fixed a bug in the particle to level set converter that prevented particles with zero velocity from being rasterized in Trail mode. - Added an optional input to the Create SOP into which to merge newly-created grids. - Fixed a bug in the Resample SOP that caused it to produce incorrect narrow-band widths when resampling level set grids. - Fixed a bug in the To Polygons SOP that caused intermittent crashes when the optional reference input was connected. - Fixed a bug in the Advect Level Set SOP that caused a crash when the velocity input was connected but empty. - The Scatter and Sample Point SOPs now warn instead of erroring when given empty grids. - Fixed a crash in @c vdb_view when stepping through multiple grids after changing render modes. - @c vdb_view can now render fog volumes and vector fields, and it now features interactively adjustable clipping planes that enable one to view the interior of a volume. @htmlonly @endhtmlonly @par Version 1.1.0 - April 4 2013 - The @vdblink::tools::resampleToMatch() resampleToMatch@endlink tool, the Resample SOP and the Combine SOP now use level set rebuild to correctly and safely resample level sets. Previously, scaling a level set would invalidate the signed distance field, leading to holes and other artifacts. - Added a mask-based topological tools::erodeVoxels() erosion tool and rewrote and simplified the tools::dilateVoxels() dilation tool. - The @vdblink::tools::LevelSetAdvection LevelSetAdvection@endlink tool can now advect forward or backward in time. - Tree::pruneLevelSet() now replaces each pruned node with a tile having the inside or outside background value, instead of arbitrarily selecting one of the node’s tile or voxel values. - When a grid is saved to a file with @vdblink::Grid::saveFloatAsHalf() saveFloatAsHalf@endlink set to @c true, the grid’s background value is now also quantized to 16 bits. (Not quantizing the background value caused a mismatch with the values of background tiles.) - As with @vdblink::tools::foreach() tools::foreach@endlink, it is now possible to specify whether functors passed to @vdblink::tools::transformValues() tools::transformValues@endlink should be shared across threads. - @vdblink::tree::LeafManager tree::LeafManager@endlink can now be instantiated with a @const tree, although buffer swapping with @const trees is disabled. - Added a @vdblink::Grid::signedFloodFill() Grid::signedFloodFill@endlink overload that allows one to specify inside and outside values. - Fixed a bug in Grid::setBackground() so that now only the values of inactive voxels change. - Fixed @vdblink::Grid::topologyUnion() Grid::topologyUnion@endlink so that it actually unions tree topology, instead of just the active states of tiles and voxels. The previous behavior broke multithreaded code that relied on input and output grids having compatible tree topology. - @vdblink::math::Transform math::Transform@endlink now includes an @vdblink::math::Transform::isIdentity() isIdentity@endlink predicate and methods to @vdblink::math::Transform::preMult(const Mat4d&) pre-@endlink and @vdblink::math::Transform::postMult(const Mat4d&) postmultiply@endlink by a matrix. - Modified the @link NodeMasks.h node mask@endlink classes to permit octree-like tree configurations (i.e., with a branching factor of two) and to use 64-bit operations instead of 32-bit operations. - Implemented a new, more efficient @vdblink::math::closestPointOnTriangleToPoint() closest point on triangle@endlink algorithm. - Implemented a new vertex normal scheme in the volume to mesh converter, and resolved some overlapping polygon issues. - The volume to mesh converter now meshes not just active voxels but also active tiles. - Fixed a bug in the mesh to volume converter that caused unsigned distance field conversion to produce empty grids. - Fixed a bug in the level set fracture tool whereby the cutter overlap toggle was ignored. - Fixed an infinite loop bug in @c vdb_view. - Updated @c vdb_view to use the faster and less memory-intensive OpenVDB volume to mesh converter instead of marching cubes, and rewrote the shader to be OpenGL 3.2 and GLSL 1.2 compatible. - Given multiple input files or a file containing multiple grids, @c vdb_view now displays one grid at a time. The left and right arrow keys cycle between grids. - The To Polygons SOP now has an option to associate the input grid’s name with each output polygon. @htmlonly @endhtmlonly @par Version 1.0.0 - March 14 2013 - @vdblink::tools::levelSetRebuild() tools::levelSetRebuild@endlink now throws an exception when given a non-scalar or non-floating-point grid. - The tools in tools/GridOperators.h are now interruptible, as is the Analysis SOP. - Added a @vdblink::tree::LeafManager::LeafRange::Iterator leaf node iterator@endlink and a TBB-compatible @vdblink::tree::LeafManager::LeafRange range class@endlink to the LeafManager. - Modified the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink tool to handle surface topology issues around fracture seam lines. - Modified the Makefile to allow @c vdb_view to compile on OS X systems (provided that GLFW is available). - Fixed a bug in the Create SOP that resulted in "invalid parameter name" warnings. - The Combine SOP now optionally resamples the A grid into the B grid’s index space (or vice-versa) if the A and B transforms differ. - The Vector Split and Vector Merge SOPs now skip inactive voxels by default, but they can optionally be made to include inactive voxels, as they did before. - The @vdblink::tools::LevelSetFracture LevelSetFracture@endlink tool now supports custom rotations for each cutter instance, and the Fracture SOP now uses quaternions to generate uniformly-distributed random rotations. @htmlonly @endhtmlonly @par Version 0.104.0 - February 15 2013 - Added a @vdblink::tools::levelSetRebuild() tool@endlink and a SOP to rebuild a level set from any scalar volume. - @c .vdb files are now saved using a mask-based compression scheme that is an order of magnitude faster than ZLIB and produces comparable file sizes for level set and fog volume grids. (ZLIB compression is still enabled by default for other classes of grids). - The @vdblink::tools::Filter Filter@endlink and @vdblink::tools::LevelSetFilter LevelSetFilter@endlink tools now include a Gaussian filter, and mean (box) filtering is now 10-50x faster. - The isosurface @vdblink::tools::VolumeToMesh meshing tool@endlink is now more robust (to level sets with one voxel wide narrow bands, for example). - Mesh to volume conversion is on average 1.5x faster and up to 5.5x faster for high-resolution meshes where the polygon/voxel size ratio is small. - Added @vdblink::createLevelSet() createLevelSet@endlink and @vdblink::createLevelSetSphere() createLevelSetSphere@endlink factory functions for level set grids. - @vdblink::tree::ValueAccessor tree::ValueAccessor@endlink is now faster for trees of height 2, 3 and 4 (the latter is the default), and it now allows one to specify, via a template argument, the number of node levels to be cached, which can also improve performance in special cases. - Added a toggle to @vdblink::tools::foreach() tools::foreach@endlink to specify whether or not the functor should be shared across threads. - Added @vdblink::Mat4SMetadata Mat4s@endlink and @vdblink::Mat4DMetadata Mat4d@endlink metadata types. - Added explicit pre- and postmultiplication methods to the @c Transform, @c Map and @c Mat4 classes and deprecated the old accumulation methods. - Modified @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink to be more compatible with Houdini’s frustum transform. - Fixed a @vdblink::tools::GridTransformer GridTransformer@endlink bug that caused it to translate the output grid incorrectly in some cases. - Fixed a bug in the tree-level @vdblink::tree::LeafIteratorBase LeafIterator@endlink that resulted in intermittent crashes in @c tools::dilateVoxels(). - The @c Hermite data type and Hermite grids are no longer supported. - Added tools/GridOperators.h, which includes new, cleaner implementations of the @vdblink::tools::cpt() closest point transform@endlink, @vdblink::tools::curl() curl@endlink, @vdblink::tools::divergence() divergence@endlink, @vdblink::tools::gradient() gradient@endlink, @vdblink::tools::laplacian() Laplacian@endlink, @vdblink::tools::magnitude() magnitude@endlink, @vdblink::tools::meanCurvature() mean curvature@endlink and @vdblink::tools::normalize() normalize@endlink tools. - Interrupt support has been improved in several tools, including @vdblink::tools::ParticlesToLevelSet tools::ParticlesToLevelSet@endlink. - Simplified the API of the @vdblink::math::BaseStencil Stencil@endlink class and added an @vdblink::math::BaseStencil::intersects() intersects@endlink method to test for intersection with a specified isovalue. - Renamed @c voxelDimensions to @c voxelSize in transform classes and elsewhere. - Deprecated @c houdini_utils::ParmFactory::setChoiceList in favor of @c houdini_utils::ParmFactory::setChoiceListItems, which requires a list of token, label string pairs. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Fixed a bug in @c houdini_utils::getNodeChain() that caused the Offset Level Set, Smooth Level Set and Renormalize Level Set SOPs to ignore frame changes. [Contributed by SESI] - The From Particles SOP now provides the option to write into an existing grid. - Added a SOP to edit grid metadata. - The Fracture SOP now supports multiple cutter objects. - Added a To Polygons SOP that complements the Fracture SOP and allows for elimination of seam lines, generation of correct vertex normals and grouping of polygons when surfacing fracture fragments, using the original level set or mesh as a reference. @htmlonly @endhtmlonly @par Version 0.103.1 - January 15 2013 - @vdblink::tree::ValueAccessor tree::ValueAccessor@endlink read operations are now faster for four-level trees. (Preliminary benchmark tests suggest a 30-40% improvement.) - For vector-valued grids, @vdblink::tools::compMin() tools::compMin@endlink and @vdblink::tools::compMax() tools::compMax@endlink now compare vector magnitudes instead of individual components. - Migrated grid sampling code to a new file, Interpolation.h, and deprecated old files and classes. - Added a level-set @vdblink::tools::LevelSetFracture fracture tool@endlink and a Fracture SOP. - Added @vdblink::tools::sdfInteriorMask() tools::sdfInteriorMask@endlink, which creates a mask of the interior region of a level set grid. - Fixed a bug in the mesh to volume converter that produced unexpected nonzero values for voxels at the intersection of two polygons, and another bug that produced narrow-band widths that didn’t respect the background value when the half-band width was less than three voxels. - @c houdini_utils::ParmFactory can now correctly generate ramp multi-parms. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - The Convert SOP can now convert between signed distance fields and fog volumes and from volumes to meshes. [Contributed by SESI] - For level sets, the From Mesh and From Particles SOPs now match the reference grid’s narrow-band width. - The Scatter SOP can now optionally scatter points in the interior of a level set. @htmlonly @endhtmlonly @par Version 0.103.0 - December 21 2012 - The mesh to volume converter is now 60% faster at generating level sets with wide bands, and the From Mesh SOP is now interruptible. - Fixed a threading bug in the recently-added @vdblink::tools::compReplace() compReplace@endlink tool that caused it to produce incorrect output. - Added a @vdblink::tree::Tree::probeConstLeaf() probeConstLeaf@endlink method to the @vdblink::tree::Tree::probeConstLeaf() Tree@endlink, @vdblink::tree::ValueAccessor::probeConstLeaf() ValueAccessor@endlink and @vdblink::tree::RootNode::probeConstLeaf() node@endlink classes. - The Houdini VDB primitive doesn’t create a @c name attribute unnecessarily (i.e., if its grid’s name is empty), but it now correctly allows the name to be changed to the empty string. - Fixed a crash in the Vector Merge SOP when fewer than three grids were merged. - The From Particles SOP now features a "maximum half-width" parameter to help avoid runaway computations. @htmlonly @endhtmlonly @par Version 0.102.0 - December 13 2012 - Added @vdblink::tools::compReplace() tools::compReplace@endlink, which copies the active values of one grid into another, and added a "Replace A With Active B" mode to the Combine SOP. - @vdblink::Grid::signedFloodFill() Grid::signedFloodFill@endlink no longer enters an infinite loop when filling an empty grid. - Fixed a bug in the particle to level set converter that sometimes produced level sets with holes, and fixed a bug in the SOP that could result in random output. - Fixed an issue in the frustum preview feature of the Create SOP whereby rendering very large frustums could cause high CPU usage. - Added streamline support to the constrained advection scheme in the Advect Points SOP. - Added an Advect Level Set SOP. @htmlonly @endhtmlonly @par Version 0.101.1 - December 11 2012 (DWA internal release) - Partially reverted the Houdini VDB primitive’s grid accessor methods to their pre-0.98.0 behavior. A primitive’s grid can once again be accessed by shared pointer, but now also by reference. Accessor methods for grid metadata have also been added, and the primitive now ensures that metadata and transforms are never shared. - Fixed an intermittent crash in the From Particles SOP. @htmlonly @endhtmlonly @par Version 0.101.0 - December 6 2012 (DWA internal release) - Partially reverted the @vdblink::Grid Grid@endlink’s @vdblink::Grid::tree() tree@endlink and @vdblink::Grid::transform() transform@endlink accessor methods to their pre-0.98.0 behavior, eliminating copy-on-write but preserving their return-by-reference semantics. These methods are now supplemented with a suite of @vdblink::Grid::treePtr() shared@endlink @vdblink::Grid::baseTreePtr() pointer@endlink @vdblink::Grid::transformPtr() accessors@endlink. - Restructured the @vdblink::tools::meshToVolume mesh to volume converter@endlink for a 40% speedup and to be more robust to non-manifold geometry, to better preserve sharp features, to support arbitrary tree configurations and to respect narrow-band limits. - Added a @c getNodeBoundingBox method to @vdblink::tree::RootNode::getNodeBoundingBox() RootNode@endlink, @vdblink::tree::InternalNode::getNodeBoundingBox() InternalNode@endlink and @vdblink::tree::LeafNode::getNodeBoundingBox() LeafNode@endlink that returns the index space spanned by a node. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Renamed the Reshape Level Set SOP to Offset Level Set. - Fixed a crash in the Convert SOP and added support for conversion of empty grids. @htmlonly @endhtmlonly @par Version 0.100.0 - November 30 2012 (DWA internal release) - Greatly improved the performance of the level set to fog volume @vdblink::tools::sdfToFogVolume() converter@endlink. - Improved the performance of the @vdblink::tools::Filter::median() median filter@endlink and of level set @vdblink::tools::csgUnion() CSG@endlink operations. - Reintroduced Tree::pruneLevelSet(), a specialized Tree::pruneInactive() for level-set grids. - Added utilities to the @c houdini_utils library to facilitate the collection of a chain of adjacent nodes of a particular type so that they can be cooked in a single step. (For example, adjacent @c xform SOPs could be collapsed by composing their transformation matrices into a single matrix.) - Added pruning and flood-filling options to the Convert SOP. - Reimplemented the Filter SOP, omitting level-set-specific filters and adding node chaining (to reduce memory usage when applying several filters in sequence). - Added a toggle to the Read SOP to read grid metadata and transforms only. - Changed the attribute transfer scheme on the From Mesh and From Particles SOPs to allow for custom grid names and vector type metadata. @htmlonly @endhtmlonly @par Version 0.99.0 - November 21 2012 - Added @vdblink::Grid Grid@endlink methods that return non-const tree and transform references without triggering deep copies, as well as @c const methods that return @c const shared pointers. - Added @c Grid methods to @vdblink::Grid::addStatsMetadata populate@endlink a grid’s metadata with statistics like the active voxel count, and to @vdblink::Grid::getStatsMetadata retrieve@endlink that metadata. By default, statistics are now computed and added to grids whenever they are written to .vdb files. - Added @vdblink::io::File::readGridMetadata io::File::readGridMetadata@endlink and @vdblink::io::File::readAllGridMetadata io::File::readAllGridMetadata@endlink methods to read just the grid metadata and transforms from a .vdb file. - Fixed numerical precision issues in the @vdblink::tools::csgUnion csgUnion@endlink, @vdblink::tools::csgIntersection csgIntersection@endlink and @vdblink::tools::csgDifference csgDifference@endlink tools, and added toggles to optionally disable postprocess pruning. - Fixed an issue in @c vdb_view with the ordering of GL vertex buffer calls. [Contributed by Bill Katz] - Fixed an intermittent crash in the @vdblink::tools::ParticlesToLevelSet ParticlesToLevelSet@endlink tool, as well as a race condition that could cause data corruption. - The @c ParticlesToLevelSet tool and From Particles SOP can now transfer arbitrary point attribute values from the input particles to output voxels. - Fixed a bug in the Convert SOP whereby the names of primitives were lost during conversion, and another bug that resulted in arithmetic errors when converting empty grids. - Fixed a bug in the Combine SOP that caused the Operation selection to be lost. @htmlonly @endhtmlonly @par Version 0.98.0 - November 16 2012 - @vdblink::tree::Tree Tree@endlink and @vdblink::math::Transform Transform@endlink objects (and @vdblink::Grid Grid@endlink objects in the context of Houdini SOPs) are now passed and accessed primarily by reference rather than by shared pointer. [Contributed by SESI] - Reimplemented @vdblink::math::CoordBBox CoordBBox@endlink to address several off-by-one bugs related to bounding box dimensions. - Fixed an off-by-one bug in @vdblink::Grid::evalActiveVoxelBoundingBox() evalActiveVoxelBoundingBox@endlink. - Introduced the @vdblink::tree::LeafManager LeafManager@endlink class, which will eventually replace the @c LeafArray class. @c LeafManager supports dynamic buffers stored as a structure of arrays (SOA), unlike @c LeafArray, which supports only static buffers stored as an array of structures (AOS). - Improved the performance of the @vdblink::tools::LevelSetFilter LevelSetFilter@endlink and @vdblink::tools::LevelSetTracker LevelSetTracker@endlink tools by rewriting them to use the new @vdblink::tree::LeafManager LeafManager@endlink class. - Added @vdblink::tree::Tree::setValueOnly() Tree::setValueOnly@endlink and @vdblink::tree::ValueAccessor::setValueOnly() ValueAccessor::setValueOnly@endlink methods, which change the value of a voxel without changing its active state, and @vdblink::tree::Tree::probeLeaf() Tree::probeLeaf@endlink and @vdblink::tree::ValueAccessor::probeLeaf() ValueAccessor::probeLeaf@endlink methods that return the leaf node that contains a given voxel (unless the voxel is represented by a tile). - Added a @vdblink::tools::LevelSetAdvection LevelSetAdvection@endlink tool that propagates and tracks narrow-band level sets. - Introduced a new @vdblink::tools::GridSampler GridSampler@endlink class that supports world-space (or index-space) sampling of grid values. - Changed the interpretation of the @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink’s @em taper parameter to be the ratio of the near and far plane depths. - Added a @c ParmFactory::setChoiceList() overload that accepts (@em token, @em label) string pairs, and a @c setDefault() overload that accepts an STL string. - Fixed a crash in the Combine SOP in Copy B mode. - Split the Level Set Filter SOP into three separate SOPs, Level Set Smooth, Level Set Reshape and Level Set Renormalize. When two or more of these nodes are connected in sequence, they interact to reduce memory usage: the last node in the sequence performs all of the operations in one step. - The Advect Points SOP can now output polyline streamlines that trace the paths of the points. - Added an option to the Analysis SOP to specify names for output grids. - Added camera-derived frustum transform support to the Create SOP. @htmlonly @endhtmlonly @par Version 0.97.0 - October 18 2012 - Added a narrow-band @vdblink::tools::LevelSetTracker level set interface tracking tool@endlink (up to fifth-order in space but currently only first-order in time, with higher temporal orders to be added soon). - Added a @vdblink::tools::LevelSetFilter level set filter tool@endlink to perform unrestricted surface smoothing (e.g., Laplacian flow), filtering (e.g., mean value) and morphological operations (e.g., morphological opening). - Added adaptivity to the @vdblink::tools::VolumeToMesh level set meshing tool@endlink for faster mesh extraction with fewer polygons, without postprocessing. - Added a @vdblink::tree::ValueAccessor::touchLeaf() ValueAccessor::touchLeaf@endlink method that creates (if necessary) and returns the leaf node containing a given voxel. It can be used to preallocate leaf nodes over which to run parallel algorithms. - Fixed a bug in @vdblink::Grid::merge() Grid::merge@endlink whereby active tiles were sometimes lost. - Added @vdblink::tree::LeafManager LeafManager@endlink, which is similar to @c LeafArray but supports a dynamic buffer count and allocates buffers more efficiently. Useful for temporal integration (e.g., for level set propagation and interface tracking), @c LeafManager is meant to replace @c LeafArray, which will be deprecated in the next release. - Added a @vdblink::tree::LeafNode::fill() LeafNode::fill@endlink method to efficiently populate leaf nodes with constant values. - Added a tree::Tree::visitActiveBBox() method that applies a functor to the bounding boxes of all active tiles and leaf nodes and that can be used to improve the performance of ray intersection tests, rendering of bounding boxes, etc. - Added a @vdblink::tree::Tree::voxelizeActiveTiles() Tree::voxelizeActiveTiles@endlink method to densify active tiles. While convenient and fast, this can produce large dense grids, so use it with caution. - Repackaged @c Tree::pruneLevelSet() as a Tree::pruneOp()-compatible functor. Tree::LevelSetPrune is a specialized Tree::pruneInactive for level-set grids and is used in interface tracking. - Added a GridBase::pruneGrid() method. - Added a @vdblink::Grid::hasUniformVoxels() Grid:hasUniformVoxels@endlink method. - Renamed @c tools::dilate to @c tools::dilateVoxels() and improved its performance. The new name reflects the fact that the current implementation ignores active tiles. - Added a @vdblink::tools::resampleToMatch() tools::resampleToMatch@endlink function that resamples an input grid into an output grid with a different transform such that, after resampling, the input and output grids coincide, but the output grid’s transform is preserved. - Significantly improved the performance of depth-bounded value iterators (@vdblink::tree::Tree::ValueOnIter ValueOnIter@endlink, @vdblink::tree::Tree::ValueAllIter ValueAllIter@endlink, etc.) when the depth bound excludes leaf nodes. - Exposed the value buffers inside leaf nodes with @vdblink::tree::LeafNode::buffer() LeafNode::buffer@endlink. This allows for very fast access (const and non-const) to voxel values using linear array offsets instead of @ijk coordinates. - In openvdb_houdini/UT_VDBTools.h, added operators for use with @c processTypedGrid that resample grids in several different ways. - Added a policy mechanism to @c houdini_utils::OpFactory that allows for customization of operator names, icons, and Help URLs. - Renamed many of the Houdini SOPs to make the names more consistent. - Added an Advect Points SOP. - Added a Level Set Filter SOP that allows for unrestricted surface deformations, unlike the older Filter SOP, which restricts surface motion to the initial narrow band. - Added staggered vector sampling to the Sample Points SOP. - Added a minimum radius threshold to the particle voxelization tool and SOP. - Merged the Composite and CSG SOPs into a single Combine SOP. - Added a tool and a SOP to efficiently generate narrow-band level set representations of spheres. - In the Visualize SOP, improved the performance of tree topology generation, which is now enabled by default. @htmlonly @endhtmlonly @par Version 0.96.0 - September 24 2012 - Fixed a memory corruption bug in the mesh voxelizer tool. - Temporarily removed the optional clipping feature from the level set mesher. - Added "Staggered Vector Field" to the list of grid classes in the Create SOP. @htmlonly @endhtmlonly @par Version 0.95.0 - September 20 2012 - Added a quad @vdblink::tools::VolumeToMesh meshing@endlink tool for higher-quality level set meshing and updated the Visualizer SOP to use it. - Fixed a precision error in the @vdblink::tools::meshToVolume mesh voxelizer@endlink and improved the quality of inside/outside voxel classification. Output grids are now also @vdblink::Grid::setGridClass() classified@endlink as either level sets or fog volumes. - Modified the @vdblink::tools::GridResampler GridResampler@endlink to use the signed flood fill optimization only on grids that are tagged as level sets. - Added a @vdblink::math::Quat quaternion@endlink class to the math library and a method to return the @vdblink::math::Mat3::trace trace@endlink of a @c Mat3. - Fixed a bug in the @vdblink::tree::ValueAccessor::ValueAccessor(const ValueAccessor&) ValueAccessor@endlink copy constructor that caused the copy to reference the original. - Fixed a bug in @vdblink::tree::RootNode::setActiveState() RootNode::setActiveState@endlink that caused a crash when marking a (virtual) background voxel as inactive. - Added a @c Tree::pruneLevelSet method that is similar to but faster than Tree::pruneInactive() for level set grids. - Added fast leaf node voxel access @vdblink::tree::LeafNode::getValue(Index) const methods@endlink that index by linear offset (as returned by @vdblink::tree::LeafNode::ValueOnIter::pos() ValueIter::pos@endlink) instead of by @ijk coordinates. - Added a @vdblink::tree::Tree::touchLeaf() Tree::touchLeaf@endlink method that can be used to preallocate a static tree topology over which to safely perform multithreaded processing. - Added a grain size argument to @c LeafArray for finer control of parallelism. - Modified the Makefile to make it easier to omit the doc, @c vdb_test and @c vdb_view targets. - Added utility functions (in houdini/UT_VDBUtils.h) to convert between Houdini and OpenVDB matrix and vector types. [Contributed by SESI] - Added accessors to @c GEO_PrimVDB that make it easier to directly access voxel data and that are used by the HScript volume expression functions in Houdini 12.5. [Contributed by SESI] - As of Houdini 12.1.77, the native transform SOP operates on OpenVDB primitives. [Contributed by SESI] - Added a Convert SOP that converts OpenVDB grids to Houdini volumes and vice-versa. @htmlonly @endhtmlonly @par Version 0.94.1 - September 7 2012 - Fixed bugs in @vdblink::tree::RootNode RootNode@endlink and @vdblink::tree::InternalNode InternalNode@endlink @c setValue*() and @c fill() methods that could cause neighboring voxels to become inactive. - Fixed a bug in @vdblink::tree::Tree::hasSameTopology() Tree::hasSameTopology@endlink that caused false positives when only active states and not values differed. - Added a @vdblink::tree::Tree::hasActiveTiles() Tree::hasActiveTiles@endlink method. - For better cross-platform consistency, substituted bitwise AND operations for right shifts in the @vdblink::tree::ValueAccessor ValueAccessor@endlink hash key computation. - @c vdb_view no longer aborts when asked to surface a vector-valued grid—but it still doesn’t render the surface. - Made various changes for Visual C++ compatibility. [Contributed by SESI] - Added an option to the MeshVoxelizer SOP to convert both open and closed surfaces to unsigned distance fields. - The Filter SOP now allows multiple filters to be applied in user-specified order. @htmlonly @endhtmlonly @par Version 0.94.0 - August 30 2012 - Added a @vdblink::Grid::topologyUnion() method@endlink to union just the active states of voxels from one grid with those of another grid of a possibly different type. - Fixed an incorrect scale factor in the Laplacian diffusion @vdblink::tools::Filter::laplacian() filter@endlink. - Fixed a bug in @vdblink::tree::Tree::merge() Tree::merge@endlink that could leave a tree with invalid value accessors. - Added @vdblink::tree::TreeValueIteratorBase::setActiveState() TreeValueIteratorBase::setActiveState@endlink and deprecated @c setValueOn. - Removed @c tools/FastSweeping.h. It will be replaced with a much more efficient implementation in the near future. - ZLIB compression of .vdb files is now optional, but enabled by default. [Contributed by SESI] - Made various changes for Clang and Visual C++ compatibility. [Contributed by SESI] - The MeshVoxelizer SOP can now transfer arbitrary point and primitive attribute values from the input mesh to output voxels. @htmlonly @endhtmlonly @par Version 0.93.0 - August 24 2012 - Renamed symbols in math/Operators.h to avoid ambiguities that GCC 4.4 reports as errors. - Simplified the API for the stencil version of the closest-point transform @vdblink::math::CPT operator@endlink. - Added logic to @vdblink::io::Archive::readGrid() io::Archive::readGrid@endlink to set the grid name metadata from the descriptor if the metadata doesn’t already exist. - Added guards to prevent nesting of @c openvdb_houdini::Interrupter::start() and @c end() calls. @htmlonly @endhtmlonly @par Version 0.92.0 - August 23 2012 - Added a Laplacian diffusion @vdblink::tools::Filter::laplacian() filter@endlink. - Fixed a bug in the initialization of the sparse contour tracer that caused mesh-to-volume conversion to fail in certain cases. - Fixed a bug in the curvature stencil that caused mean curvature filtering to produce wrong results. - Increased the speed of the @vdblink::tools::GridTransformer GridTransformer@endlink by as much as 20% for fog volumes. - Added optional pruning to the Resample SOP. - Modified the PointSample SOP to allow it to work with ungrouped, anonymous grids. - Fixed a crash in the LevelSetNoise SOP. @htmlonly @endhtmlonly @par Version 0.91.0 - August 16 2012 - @vdblink::tools::GridTransformer tools::GridTransformer@endlink and @vdblink::tools::GridResampler tools::GridResampler@endlink now correctly (but not yet efficiently) process tiles in sparse grids. - Added an optional @c CopyPolicy argument to @vdblink::GridBase::copyGrid() GridBase::copyGrid@endlink and to @vdblink::Grid::copy() Grid::copy@endlink that specifies whether and how the grid’s tree should be copied. - Added a @vdblink::GridBase::newTree() GridBase::newTree@endlink method that replaces a grid’s tree with a new, empty tree of the correct type. - Fixed a crash in @vdblink::tree::Tree::setValueOff(const Coord& xyz, const ValueType& value) Tree::setValueOff@endlink when the new value was equal to the background value. - Fixed bugs in Tree::prune() that could result in output tiles with incorrect active states. - Added @c librt to the link dependencies to address build failures on Ubuntu systems. - Made various small changes to the Makefile and the source code that should help with Mac OS X compatibility. - The Composite and Resample SOPs now correctly copy the input grid’s metadata to the output grid. @htmlonly @endhtmlonly @par Version 0.90.1 - August 7 2012 - Fixed a bug in the @vdblink::math::BBox::getCenter() BBox::getCenter()@endlink method. - Added missing header files to various files. - @vdblink::io::File::NameIterator::gridName() io::File::NameIterator::gridName()@endlink now returns a unique name of the form "name[1]", "name[2]", etc. if a file contains multiple grids with the same name. - Fixed a bug in the Writer SOP that caused grid names to be discarded. - The Resample SOP now correctly sets the background value of the output grid. @htmlonly @endhtmlonly @par Version 0.90.0 - August 3 2012 (initial public release) - Added a basic GL viewer for OpenVDB files. - Greatly improved the performance of two commonly-used @c Tree methods, @vdblink::tree::Tree::evalActiveVoxelBoundingBox() evalActiveVoxelBoundingBox()@endlink and @vdblink::tree::Tree::memUsage() memUsage()@endlink. - Eliminated the @c GridMap class. File I/O now uses STL containers of grid pointers instead. - Refactored stencil-based tools (Gradient, Laplacian, etc.) and rewrote some of them for generality and better performance. Most now behave correctly for grids with nonlinear index-to-world transforms. - Added a @link FiniteDifference.h library@endlink of index-space finite difference operators. - Added a Hermite grid type that compactly stores each voxel’s upwind normals and can be used to convert volumes to and from polygonal meshes. - Added a @link PointScatter.h tool@endlink (and a Houdini SOP) to scatter points randomly throughout a volume. */ openvdb-13.0.0/doc/codingstyle.txt000066400000000000000000000315251510223237100170640ustar00rootroot00000000000000/** @page codingStyle Coding Style @section Introduction This document details the coding practices that are used in the OpenVDB codebase. Contributed code should conform to these guidelines to maintain consistency and maintainability. If there is a rule that you would like clarified, changed, or added, please send a note to openvdb-dev@lists.aswf.io. @section sStyleContents Contents - @ref sNamingConventions - @ref sNamespaceConventions - @ref sClassConventions - @ref sClassMethods - @ref sClassInstanceVariables - @ref sClassStaticVariables - @ref sLocalVariablesAndArguments - @ref sConstants - @ref sEnumerationNames - @ref sEnumerationValues - @ref sTypedefs - @ref sGlobalVariables - @ref sGlobalFunctions - @ref sBooleans - @ref sPractices - @ref sGeneral - @ref sFormatting - @ref sIncludeStatements - @ref sComments - @ref sPrimitiveTypes - @ref sMacros - @ref sClasses - @ref sConditionalStatements - @ref sNamespaces - @ref sExceptions - @ref sTemplates - @ref sMiscellaneous @section sNamingConventions Naming Conventions @subsection sNamespaceConventions Namespaces -# Lowercase words, keep simple and short (e.g., @c tools, @c tree). -# Use @c internal (or @c detail) or module_internal for symbols such as templates that must be defined in header files but that are implementation details not intended for public use. @subsection sClassConventions Classes and Structs -# Mixed case; first letter uppercase (e.g., @c AffineMap, @c TreeIterator) -# Do not use a prefix. @subsection sClassMethods Class Methods -# Mixed case; first letter lowercase (e.g., getAccessor(), gridType()) -# Accessor methods that return a member variable by reference or a primitive type by value are just the variable name (e.g., Grid::tree()). -# Accessor methods that involve construction of objects or other computations are @c get + the variable name (e.g., Grid::getAccessor()). -# Simple mutators are @c set + the variable name (e.g., Grid::setTree(tree);). @subsection sClassInstanceVariables Class Instance Variables -# Mixed case; always prefixed by @c m (e.g., @c mTree, @c mTransform) -# The @c m prefix may be omitted for members of structs used in the public API (e.g., struct Color { float r, g, b; }). @subsection sClassStaticVariables Class Static Variables -# Mixed case; always prefixed by @c s (e.g., @c sInitialized) @subsection sLocalVariablesAndArguments Local Variables and Arguments -# Use mixed case with an initial lower case letter (e.g., @c ijk, @c offset, @c range, @c rhsValue). @subsection sConstants Constants -# All uppercase; words separated by underscores. If not in a namespace or local to a source file, then prefixed with the library name in all caps (e.g., @c HALF_FLOAT_TYPENAME_SUFFIX, @c ZIP_COMPRESSION_LEVEL) @subsection sEnumerationNames Enumeration Names -# Mixed case; first letter uppercase (e.g., @c GridClass, @c VecType) @subsection sEnumerationValues Enumeration Values -# With @c enum, all uppercase with words separated by underscores (e.g., @c GRID_LEVEL_SET, @c VEC_INVARIANT) and with a common prefix -# With enum class, mixed case with the first letter uppercase (e.g., @c GridClass::Unknown, @c GridClass::LevelSet) @subsection sTypedefs Typedefs -# Mixed case; first letter uppercase (e.g., @c ConstPtr, @c ValueType) -# Do not use a prefix. @subsection sGlobalVariables Global Variables -# Mixed case; always prefixed by @c g (e.g., @c gRegistry) -# In general, try to use class static data instead of globals. @subsection sGlobalFunctions Global Functions -# Mixed case; always prefixed by @c g (e.g., gFunc()). -# In general, try to use class static members instead of global functions. @subsection sBooleans Booleans -# When naming boolean functions and variables, use names that read as a condition (e.g., if (grid.empty()), if (matrix.isInvertible())). @section sPractices Practices @subsection sGeneral General -# Code must compile without any warning messages at the default warning level. -# Prefer the C++ Standard Library to the C Standard Library. -# Restrict variables to the smallest scopes possible, and avoid defining local variables before giving them values. Prefer declarations inside conditionals: if (Grid::Ptr grid = createGrid()) { ... } instead of Grid::Ptr grid = createGrid(); if (grid) { ... } -# For new files, be sure to use the right license boilerplate per our license policy. @subsection sFormatting Formatting -# Indentation is 4 spaces. Do not use tabs. -# Lines are no more than 100 characters long. -# Use Unix-style carriage returns ("\n") rather than Windows/DOS ones ("\r\n"). -# Do not leave debug printfs or other debugging code lying around. -# Leave a blank line between a group of variable declarations and other code. -# Leave a space after the keywords @c if, @c switch, @c while, @c do, @c for, and @c return. -# Leave a space on each side of binary operators such as @c +, @c -, @c *, @c /, @c &&, and @c ||. For clarity in mathematical situations, you may omit the spaces on either side of @c * and @c / operators to emphasize their precedence over @c + and @c -. -# Do not leave a space between any dereferencing operator (such as @c *, @c &, @c [], @c ->, or @c .) and its operands. -# In parameter lists, leave a space after each comma. -# Do not leave a space after an opening parenthesis or before a closing parenthesis. -# Parentheses should be used to clarify operator precedence in expressions. -# Do not leave a space before an end-of-statement semicolon. -# Do not use literal tabs in strings or character constants. Rather, use spaces or "\t". -# If a parameter list is too long, break it between parameters. Group related parameters on lines if appropriate. -# Modified spacing is allowed to vertically align repetitive expressions. -# Always begin numeric constants with a digit (e.g., 0.001 not .001). -# Use K&R-style brace placement in public code. -# You may leave off braces for simple, single line flow control statements. -# The return type in a function definition should go on a line by itself. @subsection sIncludeStatements Include Statements -# Always use double quotes ("") to include header files that live in the same directory as your source code. -# Use angle brackets (<>) to include header files from outside a file’s directory. -# Do not use absolute paths in include directives. -# If there is a header corresponding to a given source file, list it first, followed by other local headers, library headers and then system headers. @subsection sHeaderFiles Header Files -# Header files have a .h extension. -# All header files should be bracketed by @c \#ifdef "guard" statements. -# In class definitions, list public, then protected, then private members. -# List methods before variables. -# Fully prototype all public functions and use descriptive naming for each argument. -# Declare every function defined in a header but outside a class definition explicitly as @c inline. -# Prefer forward declarations to @c \#include directives in headers. -# Do not take advantage of indirect inclusion of header files. -# Do not use anonymous namespaces in header files. @subsection sSourceFiles Source Files -# Source files have a .cc extension. -# Properly prototype all file static functions with usefully named arguments. -# Whenever possible, put variables and functions in an anonymous namespace. -# Avoid global variables. @subsection sComments Comments -# Use @c // style comments instead of / * * / style, even for multi-line comments. -# Use multi-line comments to describe following paragraphs of code. -# Use end-of-line comments to describe variable declarations or to clarify a single statement. -# Large blocks of code should be commented out with \#if 0 and @c \#endif. -# Do not leave obsolete code fragments within comments as an historical trail. -# Document public code with Doxygen comments, formatted as follows: @verbatim /// @brief Create a new grid of type @c GridType classified as a "Level Set", /// i.e., a narrow-band level set. /// /// @param voxelSize the size of a voxel in world units /// @param halfWidth the half width of the narrow band in voxel units /// /// @details The voxel size and the narrow band half width define the grid's /// background value as halfWidth*voxelWidth. The transform is linear /// with a uniform scaling only corresponding to the specified voxel size. /// /// @note It is generally advisable to specify a half-width of the narrow band /// that is larger than one voxel unit, otherwise zero crossings are not guaranteed. template typename GridType::Ptr createLevelSet( Real voxelSize = 1.0, Real halfWidth = LEVEL_SET_HALF_WIDTH); @endverbatim @subsection sPrimitiveTypes Primitive Types -# Avoid writing code that is dependent on the bit size of primitive values, but when specific bit sizes are required, use explicitly-sized types such as @c int32_t or @c uint64_t. @subsection sMacros Macros -# Avoid macros for constants. Use global static constants instead. (Local static constants are not guaranteed to be initialized in a thread-safe manner.) -# Avoid macro functions. Use @c inline and templates instead. @subsection sClasses Classes -# Constructors that can be called with only one argument should be prefixed with the @c explicit keyword to avoid unintended type conversions. -# Never call virtual methods from destructors. -# If you have a copy constructor, make sure you have an assignment operator. -# If you have an assignment operator, you probably need a copy constructor. -# If you have data members that are pointers to dynamically allocated memory, make sure you have a copy constructor and an assignment operator, both of which do the right thing with that memory. -# Classes which are to be subclassed always have a virtual destructor, even if it is empty. -# Check against self assignment and return *this in assignment operators. -# Declare methods as @c const wherever possible. -# Declare object-valued input arguments as const references wherever possible. Primitives may be passed by value, however. -# Arithmetic, logical, bitwise, dereference, and address of operators should only be used when their semantics are clear, obvious, and unambiguous. -# The application operator [ () ] is allowed for functors. -# Conversion operators should be avoided. -# Never return const references to stack allocated or implicitly computed objects. -# If a class does not have a copy constructor and/or assignment operator, consider creating a private unimplemented copy constructor and/or assignment operator to prevent automatically generated versions from being used. @subsection sConditionalStatements Conditional Statements -# For test expressions, use a form that indicates as clearly as possible the types of operands by avoiding implicit casts. -# Assignments that occur within conditional statements must have no effect in the enclosing scope. -# Allow for arithmetic imprecision when comparing floating point values. -# In switch statements, always comment fallthroughs and empty cases. @section sNamespaces Namespaces -# Namespaces should be used whenever possible. -# Avoid pulling in entire namespaces with @c using directives (e.g., using namespace std;). -# @c using declarations are allowed for individual symbols (e.g., using std::vector;), but they should never appear in a header file. -# Define global operators in the namespace of their arguments. -# Namespaces are not indented. @subsection sExceptions Exceptions -# Appropriate use of exceptions is encouraged. -# Methods should declare all exceptions they might throw using comments, but not exception specifications. -# Throw scope local exception instances, not pointers or references or globals. -# Catch exceptions by reference. -# Never allow an exception to escape from a destructor. @subsection sTemplates Templates -# Use @c typename rather than @c class when declaring template type parameters. @subsection sMiscellaneous Miscellaneous -# Don’t use pointers to run through arrays of non-primitive types. Use explicit array indexing, iterators or generic algorithms instead. -# Use C++ casts (static_cast<int>(x) or int(x)), not C casts ((int)x). -# Multiple variables of the same data type may be declared on the same line if closely related. -# Library code must never deliberately terminate the application in response to an error condition. -# Avoid using malloc/free when new/delete can be used instead. -# Avoid @c goto. -# Avoid \"magic numbers\". Use named constants when necessary. -# If you use typeid/typeinfo, be aware that although all runtimes support typeinfo::name(), the format of the string it returns varies between compilers and even for a given compiler the value is not guaranteed to be unique. */ openvdb-13.0.0/doc/dependencies.txt000066400000000000000000000255541510223237100171730ustar00rootroot00000000000000/** @page dependencies Dependencies @section depContents Contents - @ref depComponents - @ref depDependencyTable - @ref depKnownIssues - @ref depInstallingDependencies - @ref depUsingAptGet - @ref depUsingHomebrew ------------------------------------------------------------------------------ @b Note: The dependency information on this page details a complete requirements list for building OpenVDB as a @b standalone package. If you wish to use OpenVDB with a supported 3rd party DCC (Houdini/Maya), make sure you've first read the [Building OpenVDB](@ref build) information. ------------------------------------------------------------------------------ There are a number of optional and required dependencies necessary when building different components of OpenVDB. Below you'll find a full list of all dependencies, any minimum/recommended version requirements and some guides for getting these dependencies installed. You'll also find information on any known issues with particular software. Please report any issues not listed here to the OpenVDB TSC. Note that OpenVDB is production tested against the [VFX Reference Platform] (https://www.vfxplatform.com/). Not all dependencies exist in the VFX Reference Platform, but for those that do, their specified versions are @b always recommended. @section depComponents OpenVDB Components Component | Requirements | Optional ----------------------- | ----------------------------------------------- | -------- OpenVDB Core Library | CMake, C++17 compiler, TBB::tbb | Blosc, ZLib, Log4cplus, Imath::Imath, Boost::iostream OpenVDB Print | Core Library dependencies | - OpenVDB LOD | Core Library dependencies | - OpenVDB Render | Core Library dependencies | OpenEXR, Imath::Imath, libpng OpenVDB View | Core Library dependencies, OpenGL, GLFW3, GLEW* | - OpenVDB Python | Core Library dependencies, Python, nanobind | - OpenVDB AX | Core Library dependencies, LLVM | Bison, Flex NanoVDB | - | Core Library, CUDA, TBB, Blosc, ZLib OpenVDB UnitTests | Core Library dependencies, GoogleTest, numpy* | - OpenVDB Documentation | Doxygen | - - @b * GLEW is only required for building the vdb_view binary on Windows. - @b * numpy only required for python binding unit tests - @b Note - Bison and Flex are only required for re-generation of the AX grammar which is not typically necessary for the majority of users. @subsection depDependencyTable Dependency Table Package | Minimum | Recommended | Description | apt-get | Homebrew | Source -------------- | ------- | ----------- | ----------------------------------------------------------------- | ------- | -------- | ------ CMake | 3.24 | Latest | Cross-platform family of tools designed to help build software | Y | Y | https://cmake.org GCC | 11.2.1 | 11.2.1 | C++ 17 Compiler: The GNU Compiler Collection | Y | Y | https://www.gnu.org/software/gcc Clang | 5.0 | Latest | C++ 17 Compiler: A C language family frontend for LLVM | Y | Y | https://clang.llvm.org Intel ICC | 19 | Latest | C++ 17 Compiler: Intels C++ Compiler | Y | Y | https://software.intel.com/en-us/c-compilers MSVC | 19.30 | 19.30 | C++ 17 Compiler: Microsoft Visual C++ Compiler | Y | Y | https://visualstudio.microsoft.com/vs Imath | 3.2 | >= 3.3 | Half precision floating points | Y | Y | http://www.openexr.com OpenEXR | 3.2 | >= 3.3 | EXR serialization support | Y | Y | http://www.openexr.com TBB | 2020.3 | >= 2021 | Threading Building Blocks - template library for task parallelism | Y | Y | https://www.threadingbuildingblocks.org ZLIB | 1.2.7 | Latest | Compression library for disk serialization compression | Y | Y | https://www.zlib.net Boost | 1.82 | >= 1.85 | Components: iostreams | Y | Y | https://www.boost.org LLVM | 15.0.0* | 18.0.0 | Target-independent code generation | Y | Y | https://llvm.org/ Bison | 3.7.0 | 3.7.0 | General-purpose parser generator | Y | Y | https://www.gnu.org/software/gcc Flex | 2.6.4 | 2.6.4 | Fast lexical analyzer generator | Y | Y | https://github.com/westes/flex Python | 3.10 | 3.11 | The python interpreter and libraries | Y | Y | https://www.python.org nanobind** | 2.0.0 | >= 2.5.0 | C++/python bindings | Y | Y | https://nanobind.readthedocs.io GoogleTest | 1.10 | Latest | A unit testing framework module for C++ | Y | Y | https://github.com/google/googletest Blosc | 1.17.0* | Latest | Recommended dependency for improved disk compression | Y | Y | https://github.com/Blosc/c-blosc/releases Log4cplus | 1.1.2 | Latest | An optional dependency for improved OpenVDB Logging | Y | Y | https://github.com/log4cplus/log4cplus libpng | - | Latest | Library for manipulating PNG images | Y | Y | http://www.libpng.org/pub/png/libpng.html GLFW | 3.3 | Latest | Simple API for OpenGL development | Y | Y | https://www.glfw.org OpenGL | 3.2 | Latest | Environment for developing portable graphics applications | Y | Y | https://www.opengl.org GLEW | 1.0.0 | Latest | A cross-platform OpenGL extension loading library. | Y | Y | http://glew.sourceforge.net CUDA | - | Latest | Parallel computing platform for graphical processing units. | Y | N | https://developer.nvidia.com/cuda-downloads Doxygen | 1.8.8 | 1.8.11 | Documentation generation from C++ | Y | Y | http://www.doxygen.nl - @b * See the note in [known issues](@ref depKnownIssues) regarding supported blosc/llvm versions. - @b ** See the note in [known issues](@ref depKnownIssues) regarding supported nanobind build issues. @subsection depKnownIssues Known Issues - @b On Linux, LLVM == 17 has symbol issues which makes it incompatible when used with the OpenVDB Python plugin. LLVM versions greater than 18 should be preferred. - @b GLFW: Crash with GLFW 3.2.1 when used with EGL on Linux. OpenVDB View may segfault on closure. Fixed in GLFW 3.3 - @b Blosc: OpenVDB has historically used an old version of blosc (1.5.0) to serialize .vdb files. OpenVDB has moved to a new blosc version minimum of 1.17.0. We have tested a range of blosc versions and found that the following versions are NOT compatible with OpenVDB caches written using blosc 1.5.0. Additionally these versions of blosc may generally not be compatible with OpenVDB itself. Avoid using these versions and upgrade to the new minimum of 1.17.0 where possible. - All versions from 1.11.0 through to, but excluding, 1.14.0. - Versions 1.16.0 and 1.16.1. For more information see: - https://www.blosc.org/posts/new-forward-compat-policy/ - https://github.com/Blosc/c-blosc/issues/260 - https://github.com/Blosc/c-blosc/issues/261 - @b nanobind: Nanobind requires a fast-hash-map implementation library called tsl-robin-map. If you're installing nanobind through homebrew, this library may not be installed correctly and OpenVDB's CMake will only produce a warning. Make sure to also: `brew install robin-map`. @section depInstallingDependencies Installing Dependencies This section details a number of ways to get you up and running with the required OpenVDB dependencies. @subsection depUsingAptGet Using UNIX apt-get You can use apt to automatically install required packages. Note that different Ubuntu distributions will have different versions available. You can use apt pinning to request newer versions of specific package from later distributions if the required version isn't available by default (see [man apt_preferences](https://linux.die.net/man/5/apt_preferences)). For example, the below settings will request TBB specifically from Ubuntu 22.04 (Jammy). @code{.sh} Package: libtbb-dev Pin: release n=jammy Pin-Priority: 990 @endcode Alternatively you can install any missing dependencies manually or through other package managers. @code{.sh} #!/bin/bash # Core library apt-get install cmake # CMake apt-get install libtbb-dev # TBB apt-get install zlibc # zlib apt-get install libboost-iostreams-dev # Boost::iostream apt-get install libblosc-dev # Blosc # AX apt-get install llvm-15-dev # LLVM # Python apt-get install python-dev # Python pip install nanobind # nanobind # Optional apt-get install libpng-dev # libpng apt-get install libopenexr-dev # OpenEXR apt-get install liblog4cplus-dev # Log4cplus apt-get install googletest # GoogleTest # vdb_view apt-get install libglfw3-dev # GLFW # Documentation apt-get install doxygen # doxygen # CUDA for NanoVDB apt-get install nvidia-cuda-toolkit # CUDA @endcode @subsection depUsingHomebrew Using Homebrew [Homebrew](https://brew.sh/) is a package manager for UNIX systems and is an alternative to apt-get or manual installation from source. @code{.sh} #!/bin/bash # Core library brew install cmake # CMake brew install tbb # TBB brew install zlib # zlib brew install boost # Boost brew install c-blosc # blosc # AX brew install llvm # LLVM # Python brew install python # Python brew install nanobind robin-map # nanobind # Unit Tests brew install gtest # GoogleTest # vdb_view brew install glfw # GLFW # vdb_render brew install openexr # OpenEXR brew install libpng # libpng # Documentation brew install doxygen # Doxygen @endcode */ openvdb-13.0.0/doc/doc.txt000066400000000000000000000660421510223237100153070ustar00rootroot00000000000000/** @mainpage OpenVDB The @b OpenVDB library comprises a hierarchical data structure and a suite of tools for the efficient manipulation of sparse, possibly time-varying, volumetric data discretized on a three-dimensional grid. It is based on VDB, which was developed by Ken Museth at DreamWorks Animation, and it offers an effectively infinite 3D index space, compact storage (both in memory and on disk), fast data access (both random and sequential), and a collection of algorithms specifically optimized for the data structure for common tasks such as filtering, CSG, compositing, sampling and voxelization from other geometric representations. The technical details of VDB are described in the paper “VDB: High-Resolution Sparse Volumes with Dynamic Topology”. @b OpenVDB is maintained by the Academy Software Foundation (ASWF). It was originally developed at DreamWorks Animation, primarily by - Ken Museth - Peter Cucka - Mihai Aldén - David Hill See the @subpage changes "Release Notes" for what’s new in this version of @b OpenVDB. See the @subpage dependencies "Dependencies" page for @b OpenVDB requirements. See @subpage build "Building OpenVDB" for information on building @b OpenVDB. See the @subpage overview "Overview" for an introduction to the library. See @subpage transformsAndMaps "Transforms and Maps" for more discussion of the transforms used in @b OpenVDB. See the @subpage faq "FAQ" for frequently asked questions about @b OpenVDB. See the @subpage codeExamples "Cookbook" to get started using @b OpenVDB. See @subpage points "OpenVDB Points" to store point data using @b OpenVDB. See @subpage python "Using OpenVDB in Python" to get started with the @b OpenVDB Python module. @if OPENVDB_AX See @subpage openvdbax "OpenVDB AX" for the AX documentation. @endif @if OPENVDB_HOUDINI See the @subpage houdini "Houdini Cookbook" for help on implementing Houdini nodes. @endif @if NANOVDB See @subpage NanoVDB_MainPage "NanoVDB" for the NanoVDB documentation. @endif Contributors, please familiarize yourselves with our @subpage codingStyle "coding standards". Code Coverage @page overview OpenVDB Overview @section Contents - @ref secOverview - @ref secTree - @ref subsecTreeConfig - @ref secSparsity - @ref subsecValues - @ref subsecInactive - @ref secSpaceAndTrans - @ref subsecVoxSpace - @ref subsecWorSpace - @ref subsecTrans - @ref secGrid - @ref secToolUtils - @ref secIterator - @ref subsecTreeIter - @ref subsecNodeIter - @ref subsecValueAccessor - @ref subsecTraversal @section secOverview Introduction This document is a high-level summary of the terminology and basic components of the OpenVDB library and is organized around two key motivating concepts. First, OpenVDB is designed specifically to work efficiently with sparse volumetric data locally sampled at a high spatial frequency, although it will function well for dense volumetric data. From this follows the need for a memory efficient representation of this sparsity and the need for fast iterators (and other tools) that respect sparsity. Second, data storage is separated from data interpretation. OpenVDB uses unit-less three-dimensional integer coordinates to address the sparse data, but introduces a unit-less continuous index space for interpolation, along with a transform to place the data in physical space. When manipulating data in OpenVDB, the three essential objects are (1) the @vdblink::tree::Tree Tree@endlink, a B-tree-like three-dimensional data structure; (2) the @vdblink::math::Transform Transform@endlink, which relates voxel indices @ijk to physical locations @xyz in @ref subsecWorSpace “world” space; and (3) the @vdblink::Grid Grid@endlink, a container that associates a @b Tree with a @b Transform and additional metadata. For instancing purposes (i.e., placing copies of the same volume in multiple locations), the same tree may be referenced (via smart pointers) by several different Grids, each having a unique transform. We now proceed to discuss the @b Tree and ideas of sparsity in some detail, followed by a briefer description of the different spaces and transforms as well as some of the tools that act on the sparse data. @section secTree The Tree In OpenVDB the @b Tree data structure exists to answer the question What value is stored at location @ijk in three-dimensional index space? Here i, j and k are arbitrary signed 32-bit integers, and the data type of the associated value (float, bool, vector, etc.) is the same for all @ijk. While the @b Tree serves the same purpose as a large three-dimensional array, it is a specially designed data structure that, given sparse unique values, minimizes the overall memory footprint while retaining fast access times. This is accomplished, as the name suggests, via a tree-based acceleration structure comprising a @vdblink::tree::RootNode RootNode@endlink, @vdblink::tree::LeafNode LeafNode@endlinks and usually one or more levels of @vdblink::tree::InternalNode InternalNode@endlinks with prescribed branching factors. @subsection subsecTreeConfig Tree Configuration The tree-based acceleration structure can be configured in various ways, but with the restriction that for a given tree all the LeafNodes are at the same depth. Conceptually, the @b RootNode and InternalNodes increasingly subdivide the three-dimensional index space, and the LeafNodes hold the actual unique voxels. The type of a @b Tree encodes both the type of the data to be stored in the tree (float, bool, etc.) and the tree’s node configuration. In practice a four-level (root, internal, internal, leaf) configuration is standard, and several common tree types are defined in openvdb.h. For example, @code using FloatTree = tree::Tree4::Type; using BoolTree = tree::Tree4::Type; @endcode These predefined tree types share the same branching factors, which dictate the number of children of a given node. The branching factors (5, 4, 3) are specified as base two logarithms and should be read backwards from the leaf nodes up the tree. In the default tree configuration, each @b LeafNode holds a three-dimensional grid of 23 voxels on a side (i.e., an 8×8×8 voxel grid). Internally, the @b LeafNode is said to be at “level 0” of the tree. At “level 1” of this tree is the first @b InternalNode, and it indexes a 24×24×24 = 16×16×16 grid, each entry of which is either a @b LeafNode or a constant value that represents an 8×8×8 block of voxels. At “level 2” is the second @b InternalNode in this configuration; it in turn indexes a 25×25×25 = 32×32×32 grid of level-1 InternalNodes and/or values, and so the @b InternalNode at level 2 subsumes a three-dimensional block of voxels of size 32×16×8 = 4096 on a side. Unlike the InternalNodes and LeafNodes, the @b RootNode (“level 3” for the default configuration) is not explicitly restricted in the number of children it may have, so the overall index space is limited only by the range of the integer indices, which are 32-bit by default. @section secSparsity Sparse Values and Voxels Like a tree’s node configuration, the type of data held by a tree is determined at compile time. Conceptually the tree itself employs two different notions of data sparsity to reduce the memory footprint and at the same time accelerate access to its contents. The first is largely hidden from the user and concerns ways in which large regions of uniform values are compactly represented, and the second allows for fast sequential iteration, skipping user-specified “uninteresting” regions (that may or may not have uniform values). @subsection subsecValues Tile, Voxel, and Background Values Although the data in a tree is accessed and set on a per-voxel level (i.e., the value at @ijk) it need not be internally stored in that way. To reduce the memory footprint and accelerate data access, data values are stored in three distinct forms internal to the tree: voxel values, tile values, and a background value. A voxel value is a unique value indexed by the location of a voxel and is stored in the @b LeafNode responsible for that voxel. A tile value is a uniform value assigned to all voxels subsumed by a given node. (For example, a tile Value belonging to an @b InternalNode at level 1 is equivalent to a constant-value cube of voxels of the same size, 8×8×8, as a @b LeafNode.) The tile value is returned when a request is made for the data associated with any @ijk location within the uniform tile. The background value is a unique value (stored at the root level) that is returned when accessing any @ijk location that does not resolve to either a tile or a @b LeafNode. @subsection subsecInactive Active and Inactive Voxels Any voxel or tile can be classified as either @b active or @b inactive. The interpretation of this state is application-specific, but generally active voxels are “interesting” and inactive somehow less so. The locations of active values may be sparse in the overall voxel topology, and OpenVDB provides @ref secIterator "iterators" that access active values only (as well as iterators over inactive values, all values, and general topology). An example of active vs. inactive: the voxels used to store the distance values of a narrow-band level set (i.e., close to a given surface) will be marked as active while the other (“far”) voxel locations will be marked as inactive and will generally represent regions of space with constant distance values (e.g., two constant distance values of opposite sign to distinguish the enclosed inside region from the infinite outside or background embedding). The @vdblink::tree::Tree::prune() prune@endlink method replaces with tile values any nodes that subsume voxels with the same values and active states. The resulting tree represents the same volume, but more sparsely. @section secSpaceAndTrans Coordinate Systems and Transforms The sampled data in the tree is accessed using signed index coordinates @ijk, but associating each indicial coordinate with a specific physical location is the job of a @b Transform. A simple linear transform assumes a lattice-like structure with a fixed physical distance Δ between indices, so that @xyz = (Δi, Δj, Δk). @subsection subsecVoxSpace Index Space To simplify transformations between physical space and lattice index coordinates, a continuous generalization of the index lattice points called index space is used. For example, index space coordinate (1.0, 1.0, 1.0) corresponds to the same point as (1,1,1) in the index lattice, but (1.5,1.0,1.0) also has meaning as halfway between the index coordinates (1,1,1) and (2,1,1). Index space can be used in constructing interpolated data values: given an arbitrary location in physical space, one can use a transform to compute the point in index space (which need not fall on an exact integer index) that maps to that location and locally interpolate from values with neighboring index coordinates. @subsection subsecWorSpace World Space The interpretation of the data in a tree takes place in world space. For example, the tree might hold data sampled at discrete physical locations in world space. @b Transform methods such as @vdblink::math::Transform::indexToWorld() indexToWorld@endlink and its inverse @vdblink::math::Transform::worldToIndex() worldToIndex@endlink may be used to relate coordinates in the two continuous spaces. In addition, methods such as @vdblink::math::Transform::worldToIndexCellCentered() worldToIndexCellCentered@endlink actually return lattice points. @subsection subsecTrans Transforms and Maps A @vdblink::math::Transform Transform @endlink provides a context for interpreting the information held in a tree by associating a location in world space with each entry in the tree. The actual implementation of the @b Transform is managed by a @vdblink::math::MapBase Map@endlink object, which is an encapsulation of a continuous, mostly invertible function of three variables. A @b Map is required to provide @vdblink::math::MapBase::applyMap() applyMap@endlink and @vdblink::math::MapBase::applyInverseMap() applyInverseMap@endlink methods to relate locations in its domain to its range and vice versa. A @b Map is also required to provide information about its local derivatives. For more on these classes, see the @subpage transformsAndMaps "Transforms and Maps" page. @section secGrid The Grid For many applications, it might not be necessary ever to operate directly on trees, though there are often significant performance improvements to be gained by exploiting the tree structure. The @vdblink::Grid Grid@endlink, however, is the preferred interface through which to manage voxel data, in part because a grid associates with a tree additional and often necessary information that is not accessible through the tree itself. A @vdblink::Grid Grid@endlink contains smart pointers to a @vdblink::tree::Tree Tree@endlink object and a @vdblink::math::Transform Transform@endlink object, either or both of which might be shared with other grids. As mentioned above, the transform provides for the interpretation of voxel locations. Other grid metadata, notably the grid class, the vector type and the world space/local space toggle, affect the interpretation of voxel values. OpenVDB is particularly well-suited (though by no means exclusively so) to the representation of narrow-band level sets and fog volumes. A narrow-band level set is represented by three distinct regions of voxels: an @b outside (or background) region of inactive voxels having a constant, positive distance from the level set surface; an @b inside region of inactive voxels having a constant, negative distance; and a thin band of active voxels (normally three voxels wide on either side of the surface) whose values are signed distances. Similarly, a fog volume is represented by an outside region of inactive voxels with value zero, an inside region of active voxels with value one, and a thin band of active voxels, with values typically varying linearly between zero and one, that separates the inside from the outside. Identifying a grid as a level set or a fog volume, by setting its @vdblink::GridClass grid class@endlink with @vdblink::Grid::setGridClass() setGridClass@endlink, allows tools to invoke alternative implementations that are better-suited or better-optimized for those classes. For example, resampling (in particular, scaling) a level set should normally not be done without updating its signed distance values. The @vdblink::tools::resampleToMatch() resampleToMatch@endlink tool automatically recomputes signed distances for grids that are identified as level sets. (The lower-level @vdblink::tools::GridResampler GridResampler@endlink does not, but it is optimized for level set grids in that it transforms only voxels in the narrow band and relies on @vdblink::Grid::signedFloodFill() signed flood fill@endlink to reconstruct the inside and outside regions.) Other tools whose behavior is affected by the grid class include the @vdblink::tools::divergence() divergence@endlink operator (which has an alternative implementation for @ref sStaggered "staggered velocity" grids), the @vdblink::tools::volumeToMesh() volume to mesh@endlink converter, and the @vdblink::tools::fillWithSpheres() sphere packing@endlink tool. In addition, a number of level-set-specific tools, such as the @vdblink::tools::LevelSetTracker level set tracker@endlink, throw exceptions when invoked on grids that are not identified as level sets. It is important, therefore, to set a grid’s class appropriately. When a vector-valued grid is transformed or resampled, it is often necessary for the transform to be applied not just to voxel locations but also to voxel values. By default, grids are identified as “world-space”, meaning that if the grid is vector-valued, its voxel values should be transformed. Alternatively, voxel values of grids identified as “local-space”, via @vdblink::Grid::setIsInWorldSpace() setIsInWorldSpace@endlink, do not undergo transformation. A world-space grid’s @vdblink::VecType vector type@endlink, specified with @vdblink::Grid::setVectorType() setVectorType@endlink, may be invariant, covariant or contravariant, which determines how transforms are applied to the grid’s voxel values (for details see, for example, Covariance and contravariance of vectors [Wikipedia]). The @vdblink::tools::transformVectors() transformVectors@endlink tool can be used to apply a transform to a grid’s voxel values, and it handles all of the supported vector types. A grid can optionally be assigned @vdblink::Grid::setName() name@endlink and @vdblink::Grid::setCreator() creator@endlink strings. These are purely informational, though it might be desirable to name grids so as to easily select which ones to read from files that contain multiple grids. In the absence of grid names, or at least of unique names, OpenVDB’s file I/O routines recognize an ordinal suffix: “[0]” refers to the first unnamed grid, “[1]” refers to the second, and so on, and “density[0]” and “density[1]” refer to the first and second grids named “density”. Also of interest for file I/O is a grid’s “@vdblink::Grid::setSaveFloatAsHalf() save float as half@endlink” setting, which allows it to be written more compactly using 16-bit floating point values rather than full-precision values. Finally, during file output certain statistics are computed and stored as per-grid metadata. These include the grid’s index-space active voxel bounding box, its active voxel count and its memory usage in bytes. This information can also be @vdblink::io::File::readAllGridMetadata() retrieved@endlink efficiently from a file. @section secToolUtils Utilities and Tools OpenVDB provides utility functions and classes for the manipulation of grids and the data they hold. Tools such as those found in GridOperators.h compute vector quantities from scalar data or vice-versa. Other tools perform filtering (Filter.h and LevelSetFilter.h) and interpolation (Interpolation.h) as well as sampling (GridTransformer.h), compositing and constructive solid geometry (Composite.h), and other transformations (ValueTransformer.h). OpenVDB also supports advanced finite difference computations through a variety of local support stencils (Stencils.h). @section secIterator Iterators OpenVDB provides efficient, often multithreaded, implementations of a large variety of morphological, filtering and other algorithms that address common data manipulation tasks on three-dimensional grids. For more specialized tasks, OpenVDB provides lower-level data accessors that enable fast iteration over all or selected voxels and over the elements of a @b Tree. These take several forms: iterator classes of various types, functor-based @b visitor methods, and the @vdblink::tree::ValueAccessor ValueAccessor@endlink, an accelerator for indexed @ijk voxel lookups. Iterator classes follow a fairly consistent naming scheme. First, the @b CIter and @b Iter suffixes denote @const and non-@const iterators, i.e., iterators that offer, respectively, read-only and read/write access to the underlying tree or node. Second, iterators over tile and voxel values are denoted either @b On, @b Off or @b All, indicating that they visit only active values, only inactive values, or both active and inactive values. So, for example, @b Tree::ValueOnCIter is a read-only iterator over all active values (both tile and voxel) of a tree, whereas @b LeafNode::ValueAllIter is a read/write iterator over all values, both active and inactive, of a single leaf node. OpenVDB iterators are not STL-compatible in that one can always request an iterator that points to the beginning of a collection of elements (nodes, voxels, etc.), but one usually cannot request an iterator that points to the end of the collection. (This is because finding the end might require a full tree traversal.) Instead, all OpenVDB iterators implement a @b test method that returns @c true as long as the iterator is not exhausted and @c false as soon as it is. Typical usage is as follows: @code using GridType = openvdb::FloatGrid; GridType grid = ...; for (GridType::ValueOnCIter iter = grid.cbeginValueOn(); iter.test(); ++iter) ... @endcode or more compactly @code for (auto iter = grid.cbeginValueOn(); iter; ++iter) ... @endcode Note that the naming scheme for methods that return “begin” iterators closely mirrors that of the iterators themselves. That is, @b Grid::cbeginValueOn returns a @c const iterator to the first of a grid’s active values, whereas @b LeafNode::beginValueAll returns a non-const iterator to the first of a leaf node’s values, both active and inactive. (@c const overloads of begin* methods are usually provided, so that if the @b Grid is itself @c const, Grid::begin* will actually return a @c const iterator. This makes it more convenient to use these methods in templated code.) Finally, note that modifying the tree or node over which one is iterating typically does not invalidate the iterator, though it might first need to be incremented to point to the next existing element (for example, if one deletes a child node to which the iterator is currently pointing). @subsection subsecTreeIter Tree Iterators @anchor treeValueIterRef @par Tree::ValueIter Tree-level value iterators traverse an entire tree, visiting each value (tile or voxel) exactly once. (It is also possible to restrict the traversal to minimum and maximum levels of the tree.) In addition to the methods common to all OpenVDB iterators, such as @b test and @b next, a @b Tree::ValueIter provides methods that return the depth in the tree of the node within which the iterator is pointing (the root node has depth 0) and the @ijk axis-aligned bounding box of the tile or voxel to which it is pointing, and methods to get and set both the value and the active state of the tile or voxel. See the @vdblink::tree::TreeValueIteratorBase TreeValueIteratorBase @endlink class for the complete list. @anchor treeLeafIterRef @par Tree::LeafIter By convention in OpenVDB, voxels in the narrow band of a narrow-band level set are stored only at the leaf level of a tree, so to facilitate the implementation of level set algorithms that operate on narrow-band voxels, OpenVDB provides an iterator that visits each @b LeafNode in a tree exactly once. See the @vdblink::tree::LeafIteratorBase LeafIteratorBase@endlink class for details, and also the related @vdblink::tree::LeafManager LeafManager@endlink acceleration structure. @anchor treeNodeIterRef @par Tree::NodeIter A node iterator traverses a tree in depth-first order, starting from its root, and visits each node exactly once. (It is also possible to restrict the traversal to minimum and maximum node depths—see the @vdblink::tree::NodeIteratorBase NodeIteratorBase @endlink class for details.) Like the tree-level value iterator, the node iterator provides methods that return the depth in the tree of the node to which the iterator is pointing (the root node has depth 0) and the @ijk axis-aligned bounding box of the voxels subsumed by the node and all of its children. @par Naturally, a node iterator also provides access to the node to which it is pointing, but this is complicated somewhat by the fact that nodes of the various types (@b RootNode, @b InternalNode and @b LeafNode) do not inherit from a common base class. For efficiency, OpenVDB generally avoids class inheritance and virtual functions in favor of templates, allowing the compiler to optimize away function calls. In particular, each node type is templated on the type of its children, so even two InternalNodes at different levels of a tree have distinct types. As a result, it is necessary to know the type of the node to which a node iterator is pointing in order to request access to that node. See the @ref sNodeIterator "Cookbook" for an example of how to do this. @subsection subsecNodeIter Node Iterators Less commonly used than tree-level iterators (but found in the implementations of some of the narrow-band level set algorithms referred to @ref treeLeafIterRef "above") are node-level iterators. A node value iterator visits the values (active, inactive or both) stored in a single @b RootNode, @b InternalNode or @b LeafNode, whereas a node child iterator visits the children of a single root or internal node. (Recall that non-leaf nodes store either a tile value or a child node at each grid position.) @subsection subsecValueAccessor Value Accessor When traversing a grid by @ijk index in a spatially coherent pattern, such as when iterating over neighboring voxels, request a @vdblink::tree::ValueAccessor ValueAccessor@endlink from the grid (with @vdblink::Grid::getAccessor() Grid::getAccessor@endlink) and use the accessor’s @vdblink::tree::ValueAccessor::getValue() getValue@endlink and @vdblink::tree::ValueAccessor::setValue() setValue@endlink methods, since these will usually be significantly faster (a factor of three is typical) than accessing voxels directly in the grid’s tree. The accessor records the sequence of nodes visited during the most recent access; on the next access, rather than traversing the tree from the root node down, it performs an inverted traversal from the deepest recorded node up. For neighboring voxels, the traversal need only proceed as far as the voxels’ common ancestor node, which more often than not is the first node in the sequence. Multiple accessors may be associated with a single grid. In fact, for multithreaded, read-only access to a grid, it is recommended that each thread be assigned its own accessor. A thread-safe, mutex-locked accessor is provided (see @vdblink::tree::ValueAccessorRW ValueAccessorRW@endlink), but the locking negates much of the performance benefit of inverted traversal; and because it is the accessor object that is thread-safe, not the grid, concurrent reads and writes are not safe unless all threads share a single accessor. All accessors associated with a grid must be cleared after any operation that removes nodes from the grid’s tree, such as pruning, CSG or compositing. For those and other built-in operations, this is done automatically via a callback mechanism, but developers must be careful to call @vdblink::tree::Tree::clearAllAccessors() Tree::clearAllAccessors@endlink whenever deleting nodes directly. @subsection subsecTraversal Tree Traversal To be written */ openvdb-13.0.0/doc/examplecode.txt000066400000000000000000002240601510223237100170240ustar00rootroot00000000000000/** @page codeExamples OpenVDB Cookbook This section provides code snippets and some complete programs that illustrate how to use OpenVDB and how to perform common tasks. @section sCookbookContents Contents - @ref sHelloWorld - @ref sAllocatingGrids - @ref sPopulatingGrids - @ref sModifyingGrids - @ref sStreamIO - @ref sHandlingMetadata - @ref sAddingMetadata - @ref sGettingMetadata - @ref sRemovingMetadata - @ref sIteration - @ref sNodeIterator - @ref sLeafIterator - @ref sValueIterator - @ref sIteratorRange - @ref sInterpolation - @ref sSamplers - @ref sGridSampler - @ref sDualGridSampler - @ref sXformTools - @ref sResamplingTools - @ref sValueXformTools - @ref sCombiningGrids - @ref sCsgTools - @ref sCompTools - @ref sCombineTools - @ref sGenericProg - @ref sTypedGridMethods - @ref sPointsHelloWorld - @ref sPointsConversion - @ref sPointsGeneration - @ref sPointIterationFiltering - @ref sPointIteration - @ref sPointGroups - @ref sPointFiltering - @ref sPointCustomFiltering - @ref sPointStride - @ref sConstantStride - @ref sPointMove - @ref sPointAdvect - @ref sPointCustomDeformer @section sHelloWorld “Hello, World” for OpenVDB This is a very simple example showing how to create a grid and access its voxels. OpenVDB supports both random access to voxels by coordinates and sequential access by means of iterators. This example illustrates both types of access: @code #include #include int main() { // Initialize the OpenVDB library. This must be called at least // once per program and may safely be called multiple times. openvdb::initialize(); // Create an empty floating-point grid with background value 0. openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(); std::cout << "Testing random access:" << std::endl; // Get an accessor for coordinate-based access to voxels. openvdb::FloatGrid::Accessor accessor = grid->getAccessor(); // Define a coordinate with large signed indices. openvdb::Coord xyz(1000, -200000000, 30000000); // Set the voxel value at (1000, -200000000, 30000000) to 1. accessor.setValue(xyz, 1.0); // Verify that the voxel value at (1000, -200000000, 30000000) is 1. std::cout << "Grid" << xyz << " = " << accessor.getValue(xyz) << std::endl; // Reset the coordinates to those of a different voxel. xyz.reset(1000, 200000000, -30000000); // Verify that the voxel value at (1000, 200000000, -30000000) is // the background value, 0. std::cout << "Grid" << xyz << " = " << accessor.getValue(xyz) << std::endl; // Set the voxel value at (1000, 200000000, -30000000) to 2. accessor.setValue(xyz, 2.0); // Set the voxels at the two extremes of the available coordinate space. // For 32-bit signed coordinates these are (-2147483648, -2147483648, -2147483648) // and (2147483647, 2147483647, 2147483647). accessor.setValue(openvdb::Coord::min(), 3.0f); accessor.setValue(openvdb::Coord::max(), 4.0f); std::cout << "Testing sequential access:" << std::endl; // Print all active ("on") voxels by means of an iterator. for (openvdb::FloatGrid::ValueOnCIter iter = grid->cbeginValueOn(); iter; ++iter) { std::cout << "Grid" << iter.getCoord() << " = " << *iter << std::endl; } } @endcode Output: @code Testing random access: Grid[1000, -200000000, 30000000] = 1 Grid[1000, 200000000, -30000000] = 0 Testing sequential access: Grid[-2147483648, -2147483648, -2147483648] = 3 Grid[1000, -200000000, 30000000] = 1 Grid[1000, 200000000, -30000000] = 2 Grid[2147483647, 2147483647, 2147483647] = 4 @endcode @section sAllocatingGrids Creating and writing a grid This example is a complete program that illustrates some of the basic steps to create grids and write them to disk. (See @ref sPopulatingGrids, below, for the implementation of the @b makeSphere function.) @code #include int main() { openvdb::initialize(); // Create a shared pointer to a newly-allocated grid of a built-in type: // in this case, a FloatGrid, which stores one single-precision floating point // value per voxel. Other built-in grid types include BoolGrid, DoubleGrid, // Int32Grid and Vec3SGrid (see openvdb.h for the complete list). // The grid comprises a sparse tree representation of voxel data, // user-supplied metadata and a voxel space to world space transform, // which defaults to the identity transform. openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(/*background value=*/2.0); // Populate the grid with a sparse, narrow-band level set representation // of a sphere with radius 50 voxels, located at (1.5, 2, 3) in index space. makeSphere(*grid, /*radius=*/50.0, /*center=*/openvdb::Vec3f(1.5, 2, 3)); // Associate some metadata with the grid. grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); // Associate a scaling transform with the grid that sets the voxel size // to 0.5 units in world space. grid->setTransform( openvdb::math::Transform::createLinearTransform(/*voxel size=*/0.5)); // Identify the grid as a level set. grid->setGridClass(openvdb::GRID_LEVEL_SET); // Name the grid "LevelSetSphere". grid->setName("LevelSetSphere"); // Create a VDB file object. openvdb::io::File file("mygrids.vdb"); // Add the grid pointer to a container. openvdb::GridPtrVec grids; grids.push_back(grid); // Write out the contents of the container. file.write(grids); file.close(); } @endcode The OpenVDB library includes optimized routines for many common tasks. For example, most of the steps given above are encapsulated in the function @vdblink::tools::createLevelSetSphere() tools::createLevelSetSphere@endlink, so that the above can be written simply as follows: @code #include #include int main() { openvdb::initialize(); // Create a FloatGrid and populate it with a narrow-band // signed distance field of a sphere. openvdb::FloatGrid::Ptr grid = openvdb::tools::createLevelSetSphere( /*radius=*/50.0, /*center=*/openvdb::Vec3f(1.5, 2, 3), /*voxel size=*/0.5, /*width=*/4.0); // Associate some metadata with the grid. grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); // Name the grid "LevelSetSphere". grid->setName("LevelSetSphere"); // Create a VDB file object and write out the grid. openvdb::io::File("mygrids.vdb").write({grid}); } @endcode @section sPopulatingGrids Populating a grid with values The following code is templated so as to operate on grids containing values of any scalar type, provided that the value type supports negation and comparison. Note that this algorithm is only meant as an example and should never be used in production; use the much more efficient routines in tools/LevelSetSphere.h instead. See @ref sGenericProg for more on processing grids of arbitrary type. @anchor makeSphereCode @code // Populate the given grid with a narrow-band level set representation of a sphere. // The width of the narrow band is determined by the grid's background value. // (Example code only; use tools::createSphereSDF() in production.) template void makeSphere(GridType& grid, float radius, const openvdb::Vec3f& c) { using ValueT = typename GridType::ValueType; // Distance value for the constant region exterior to the narrow band const ValueT outside = grid.background(); // Distance value for the constant region interior to the narrow band // (by convention, the signed distance is negative in the interior of // a level set) const ValueT inside = -outside; // Use the background value as the width in voxels of the narrow band. // (The narrow band is centered on the surface of the sphere, which // has distance 0.) int padding = int(openvdb::math::RoundUp(openvdb::math::Abs(outside))); // The bounding box of the narrow band is 2*dim voxels on a side. int dim = int(radius + padding); // Get a voxel accessor. typename GridType::Accessor accessor = grid.getAccessor(); // Compute the signed distance from the surface of the sphere of each // voxel within the bounding box and insert the value into the grid // if it is smaller in magnitude than the background value. openvdb::Coord ijk; int &i = ijk[0], &j = ijk[1], &k = ijk[2]; for (i = c[0] - dim; i < c[0] + dim; ++i) { const float x2 = openvdb::math::Pow2(i - c[0]); for (j = c[1] - dim; j < c[1] + dim; ++j) { const float x2y2 = openvdb::math::Pow2(j - c[1]) + x2; for (k = c[2] - dim; k < c[2] + dim; ++k) { // The distance from the sphere surface in voxels const float dist = openvdb::math::Sqrt(x2y2 + openvdb::math::Pow2(k - c[2])) - radius; // Convert the floating-point distance to the grid's value type. ValueT val = ValueT(dist); // Only insert distances that are smaller in magnitude than // the background value. if (val < inside || outside < val) continue; // Set the distance for voxel (i,j,k). accessor.setValue(ijk, val); } } } // Propagate the outside/inside sign information from the narrow band // throughout the grid. openvdb::tools::signedFloodFill(grid.tree()); } @endcode @section sModifyingGrids Reading and modifying a grid @code #include #include openvdb::initialize(); // Create a VDB file object. openvdb::io::File file("mygrids.vdb"); // Open the file. This reads the file header, but not any grids. file.open(); // Loop over all grids in the file and retrieve a shared pointer // to the one named "LevelSetSphere". (This can also be done // more simply by calling file.readGrid("LevelSetSphere").) openvdb::GridBase::Ptr baseGrid; for (openvdb::io::File::NameIterator nameIter = file.beginName(); nameIter != file.endName(); ++nameIter) { // Read in only the grid we are interested in. if (nameIter.gridName() == "LevelSetSphere") { baseGrid = file.readGrid(nameIter.gridName()); } else { std::cout << "skipping grid " << nameIter.gridName() << std::endl; } } file.close(); // From the example above, "LevelSetSphere" is known to be a FloatGrid, // so cast the generic grid pointer to a FloatGrid pointer. openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast(baseGrid); // Convert the level set sphere to a narrow-band fog volume, in which // interior voxels have value 1, exterior voxels have value 0, and // narrow-band voxels have values varying linearly from 0 to 1. const float outside = grid->background(); const float width = 2.0 * outside; // Visit and update all of the grid's active values, which correspond to // voxels on the narrow band. for (openvdb::FloatGrid::ValueOnIter iter = grid->beginValueOn(); iter; ++iter) { float dist = iter.getValue(); iter.setValue((outside - dist) / width); } // Visit all of the grid's inactive tile and voxel values and update the values // that correspond to the interior region. for (openvdb::FloatGrid::ValueOffIter iter = grid->beginValueOff(); iter; ++iter) { if (iter.getValue() < 0.0) { iter.setValue(1.0); iter.setValueOff(); } } // Set exterior voxels to 0. openvdb::tools::changeBackground(grid->tree(), 0.0); @endcode @section sStreamIO Stream I/O The @vdblink::io::Stream io::Stream@endlink class allows grids to be written to and read from streams that do not support random access, with the restriction that all grids must be written or read at once. (With @vdblink::io::File io::File@endlink, grids can be read individually by name, provided that they were originally written with @b io::File, rather than streamed to a file.) @code #include #include openvdb::initialize(); openvdb::GridPtrVecPtr grids(new GridPtrVec); grids->push_back(...); // Stream the grids to a string. std::ostringstream ostr(std::ios_base::binary); openvdb::io::Stream(ostr).write(*grids); // Stream the grids to a file. std::ofstream ofile("mygrids.vdb", std::ios_base::binary); openvdb::io::Stream(ofile).write(*grids); // Stream in grids from a string. // Note that io::Stream::getGrids() returns a shared pointer // to an openvdb::GridPtrVec. std::istringstream istr(ostr.str(), std::ios_base::binary); openvdb::io::Stream strm(istr); grids = strm.getGrids(); // Stream in grids from a file. std::ifstream ifile("mygrids.vdb", std::ios_base::binary); grids = openvdb::io::Stream(ifile).getGrids(); @endcode @section sHandlingMetadata Handling metadata Metadata of various types (string, floating point, integer, etc.—see Metadata.h for more) can be attached both to individual Grids and to files on disk. The examples that follow refer to Grids, but the usage is the same for the @vdblink::MetaMap MetaMap@endlink that can optionally be supplied to a @vdblink::io::File::write() file@endlink or @vdblink::io::Stream::write() stream@endlink for writing. @subsection sAddingMetadata Adding metadata The @vdblink::Grid::insertMeta() Grid::insertMeta@endlink method either adds a new (@em name, @em value) pair if the name is unique, or overwrites the existing value if the name matches an existing one. An existing value cannot be overwritten with a new value of a different type; the old metadata must be removed first. @code #include openvdb::Vec3SGrid::Ptr grid = openvdb::Vec3SGrid::create(); grid->insertMeta("vector type", openvdb::StringMetadata("covariant (gradient)")); grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); grid->insertMeta("center", openvdb::Vec3SMetadata(openvdb::Vec3S(10, 15, 10))); // OK, overwrites existing value: grid->insertMeta("center", openvdb::Vec3SMetadata(openvdb::Vec3S(10.5, 15, 30))); // Error (throws openvdb::TypeError), can't overwrite a value of type Vec3S // with a value of type float: grid->insertMeta("center", openvdb::FloatMetadata(0.0)); @endcode @subsection sGettingMetadata Retrieving metadata Call @vdblink::Grid::metaValue() Grid::metaValue@endlink to retrieve the value of metadata of a known type. For example, @code std::string s = grid->metaValue("vector type"); float r = grid->metaValue("radius"); // Error (throws openvdb::TypeError), can't read a value of type Vec3S as a float: float center = grid->metaValue("center"); @endcode @vdblink::Grid::beginMeta() Grid::beginMeta@endlink and @vdblink::Grid::endMeta() Grid::endMeta@endlink return @b std::map iterators over all of the metadata associated with a grid: @code for (openvdb::MetaMap::MetaIterator iter = grid->beginMeta(); iter != grid->endMeta(); ++iter) { const std::string& name = iter->first; openvdb::Metadata::Ptr value = iter->second; std::string valueAsString = value->str(); std::cout << name << " = " << valueAsString << std::endl; } @endcode If the type of the metadata is not known, use the @vdblink::Grid::operator[]() index operator@endlink to retrieve a shared pointer to a generic @vdblink::Metadata Metadata@endlink object, then query its type: @code openvdb::Metadata::Ptr metadata = grid["center"]; // See typenameAsString() in Types.h for a list of strings that can be // returned by the typeName() method. std::cout << metadata->typeName() << std::endl; // prints "vec3s" // One way to process metadata of arbitrary types: if (metadata->typeName() == openvdb::StringMetadata::staticTypeName()) { std::string s = static_cast(*metadata).value(); } else if (metadata->typeName() == openvdb::FloatMetadata::staticTypeName()) { float f = static_cast(*metadata).value(); } else if (metadata->typeName() == openvdb::Vec3SMetadata::staticTypeName()) { openvdb::Vec3S v = static_cast(*metadata).value(); } @endcode @subsection sRemovingMetadata Removing metadata @vdblink::Grid::removeMeta() Grid::removeMeta@endlink removes metadata by name. If the given name is not found, the call has no effect. @code grid->removeMeta("vector type"); grid->removeMeta("center"); grid->removeMeta("vector type"); // OK (no effect) @endcode @section sIteration Iteration @subsection sNodeIterator Node Iterator A @vdblink::tree::Tree::NodeIter Tree::NodeIter@endlink visits each node in a tree exactly once. In the following example, the tree is known to have a depth of 4; see the @ref treeNodeIterRef "Overview" for a discussion of why node iteration can be complicated when the tree depth is not known. There are techniques (beyond the scope of this Cookbook) for operating on trees of arbitrary depth. @code #include using GridType = openvdb::FloatGrid; using TreeType = GridType::TreeType; using RootType = TreeType::RootNodeType; // level 3 RootNode assert(RootType::LEVEL == 3); using Int1Type = RootType::ChildNodeType; // level 2 InternalNode using Int2Type = Int1Type::ChildNodeType; // level 1 InternalNode using LeafType = TreeType::LeafNodeType; // level 0 LeafNode GridType::Ptr grid = ...; for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) { switch (iter.getDepth()) { case 0: { RootType* node = nullptr; iter.getNode(node); if (node) ...; break; } case 1: { Int1Type* node = nullptr; iter.getNode(node); if (node) ...; break; } case 2: { Int2Type* node = nullptr; iter.getNode(node); if (node) ...; break; } case 3: { LeafType* node = nullptr; iter.getNode(node); if (node) ...; break; } } } @endcode @subsection sLeafIterator Leaf Node Iterator A @vdblink::tree::Tree::LeafIter Tree::LeafIter@endlink visits each leaf node in a tree exactly once. @code #include using GridType = openvdb::FloatGrid; using TreeType = GridType::TreeType; GridType::Ptr grid = ...; // Iterate over references to const LeafNodes. for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) { const TreeType::LeafNodeType& leaf = *iter; ... } // Iterate over references to non-const LeafNodes. for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) { TreeType::LeafNodeType& leaf = *iter; ... } // Iterate over pointers to const LeafNodes. for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) { const TreeType::LeafNodeType* leaf = iter.getLeaf(); ... } // Iterate over pointers to non-const LeafNodes. for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) { TreeType::LeafNodeType* leaf = iter.getLeaf(); ... } @endcode See the @ref treeLeafIterRef "Overview" for more on leaf node iterators. @subsection sValueIterator Value Iterator A @vdblink::tree::Tree::ValueAllIter Tree::ValueIter@endlink visits each @ref subsecValues "value" (both tile and voxel) in a tree exactly once. Iteration can be unrestricted or can be restricted to only active values or only inactive values. Note that tree-level value iterators (unlike the node iterators described above) can be accessed either through a grid's tree or directly through the grid itself, as in the following example: @code #include #include using GridType = openvdb::Vec3SGrid; using TreeType = GridType::TreeType; GridType::Ptr grid = ...; // Iterate over all active values but don't allow them to be changed. for (GridType::ValueOnCIter iter = grid->cbeginValueOn(); iter.test(); ++iter) { const openvdb::Vec3f& value = *iter; // Print the coordinates of all voxels whose vector value has // a length greater than 10, and print the bounding box coordinates // of all tiles whose vector value length is greater than 10. if (value.length() > 10.0) { if (iter.isVoxelValue()) { std::cout << iter.getCoord() << std::endl; } else { openvdb::CoordBBox bbox; iter.getBoundingBox(bbox); std::cout << bbox << std::endl; } } } // Iterate over and normalize all inactive values. for (GridType::ValueOffIter iter = grid->beginValueOff(); iter.test(); ++iter) { openvdb::Vec3f value = *iter; value.normalize(); iter.setValue(value); } // Normalize the (inactive) background value as well. openvdb::tools::changeBackground(grid->tree(), grid->background().unit()); @endcode See the @ref treeValueIterRef "Overview" for more on value iterators. @subsection sIteratorRange Iterator Range A @vdblink::tree::IteratorRange tree::IteratorRange@endlink wraps any grid or tree iterator and gives the iterator TBB splittable range semantics, so that it can be used as the Range argument to functions like @b tbb::parallel_for and @b tbb::parallel_reduce. (This is in fact how @vdblink::tools::foreach() tools::foreach@endlink and @vdblink::tools::transformValues() tools::transformValues@endlink are implemented; see @ref sValueXformTools, below, for more on those functions.) There is some overhead to splitting, since grid and tree iterators are not random-access, but the overhead should typically be negligible compared with the amount of work done per subrange. The following is a complete program that uses @vdblink::tree::IteratorRange tree::IteratorRange@endlink. The program iterates in parallel over the leaf nodes of a tree (by splitting the iteration range of a @vdblink::tree::Tree::LeafCIter Tree::LeafCIter@endlink) and computes the total number of active leaf-level voxels by incrementing a global, thread-safe counter. @code #include #include #include #include #include #include // Global active voxel counter, atomically updated from multiple threads std::atomic activeLeafVoxelCount; // Functor for use with tbb::parallel_for() that operates on a grid's leaf nodes template struct LeafProcessor { using TreeType = typename GridType::TreeType; using LeafNode = typename TreeType::LeafNodeType; // Define an IteratorRange that splits the iteration space of a leaf iterator. using IterRange = openvdb::tree::IteratorRange; void operator()(IterRange& range) const { // Note: this code must be thread-safe. // Iterate over a subrange of the leaf iterator's iteration space. for ( ; range; ++range) { // Retrieve the leaf node to which the iterator is pointing. const LeafNode& leaf = *range.iterator(); // Update the global counter. activeLeafVoxelCount.fetch_add(leaf.onVoxelCount()); } } }; int main() { openvdb::initialize(); // Generate a level set grid. openvdb::FloatGrid::Ptr grid = openvdb::tools::createLevelSetSphere(/*radius=*/20.0, /*center=*/openvdb::Vec3f(1.5, 2, 3), /*voxel size=*/0.5); // Construct a functor for use with tbb::parallel_for() // that processes the leaf nodes of a FloatGrid. using FloatLeafProc = LeafProcessor; FloatLeafProc proc; // Wrap a leaf iterator in an IteratorRange. FloatLeafProc::IterRange range(grid->tree().cbeginLeaf()); // Iterate over leaf nodes in parallel. tbb::parallel_for(range, proc); std::cout << activeLeafVoxelCount << " active leaf voxels" << std::endl; // The computed voxel count should equal the grid's active voxel count, // since all of the active voxels in a level set grid are stored at the // leaf level (that is, there are no active tiles in a level set grid). assert(activeLeafVoxelCount == grid->activeVoxelCount()); } @endcode @section sInterpolation Interpolation of grid values Applications such as rendering require evaluation of grids at arbitrary, fractional coordinates in either index or world space. This is achieved, of course, by interpolating between known grid values at neighboring whole-voxel locations, that is, at integer coordinates in index space. The following sections introduce OpenVDB’s various interpolation schemes as well as the @ref sGridSampler and @ref sDualGridSampler classes for efficient, continuous sampling of grids. In most cases, @b GridSampler is the preferred interface for interpolation, but note that when a fixed transform is to be applied to all values in a grid (that is, the grid is to be resampled), it is both easier and more efficient to use the multithreaded @vdblink::tools::GridTransformer GridTransformer@endlink class, introduced in @ref sXformTools. @subsection sSamplers Index-space samplers OpenVDB offers low-level zero-, first- and second-order interpolators @vdblink::tools::PointSampler PointSampler@endlink, @vdblink::tools::BoxSampler BoxSampler@endlink and @vdblink::tools::QuadraticSampler QuadraticSampler@endlink, in addition to the variants @vdblink::tools::StaggeredPointSampler StaggeredPointSampler@endlink, @vdblink::tools::StaggeredBoxSampler StaggeredBoxSampler@endlink and @vdblink::tools::StaggeredQuadraticSampler StaggeredQuadraticSampler@endlink for @ref sStaggered "staggered" velocity grids. @code #include #include const GridType grid = ...; // Choose fractional coordinates in index space. const openvdb::Vec3R ijk(10.5, -100.2, 50.3); // Compute the value of the grid at ijk via nearest-neighbor (zero-order) // interpolation. GridType::ValueType v0 = openvdb::tools::PointSampler::sample(grid.tree(), ijk); // Compute the value via trilinear (first-order) interpolation. GridType::ValueType v1 = openvdb::tools::BoxSampler::sample(grid.tree(), ijk); // Compute the value via triquadratic (second-order) interpolation. GridType::ValueType v2 = openvdb::tools::QuadraticSampler::sample(grid.tree(), ijk); @endcode These examples invoke the @vdblink::tree::Tree::getValue() getValue@endlink method on the grid’s tree to fetch sample values in the neighborhood of @ijk. Accessing values via the tree is thread-safe due to the lack of caching, but for that reason it is also suboptimal. For better performance, use @ref subsecValueAccessor "value accessors" (but be careful to use one accessor per computational thread): @code GridType::ConstAccessor accessor = grid.getConstAccessor(); GridType::ValueType v0 = openvdb::tools::PointSampler::sample(accessor, ijk); GridType::ValueType v1 = openvdb::tools::BoxSampler::sample(accessor, ijk); GridType::ValueType v2 = openvdb::tools::QuadraticSampler::sample(accessor, ijk); @endcode Another issue with these low-level interpolators is that they operate only in index space. To interpolate in world space, use the higher-level classes discussed below. @subsection sGridSampler Grid Sampler The @vdblink::tools::GridSampler GridSampler@endlink class allows for continuous sampling in both world space and index space and can be used with grids, trees or value accessors. @code #include #include const GridType grid = ...; // Instantiate the GridSampler template on the grid type and on a box sampler // for thread-safe but uncached trilinear interpolation. openvdb::tools::GridSampler sampler(grid); // Compute the value of the grid at fractional coordinates in index space. GridType::ValueType indexValue = sampler.isSample(openvdb::Vec3R(10.5, -100.2, 50.3)); // Compute the value of the grid at a location in world space. GridType::ValueType worldValue = sampler.wsSample(openvdb::Vec3R(0.25, 1.4, -1.1)); // Request a value accessor for accelerated access. // (Because value accessors employ a cache, it is important to declare // one accessor per thread.) GridType::ConstAccessor accessor = grid.getConstAccessor(); // Instantiate the GridSampler template on the accessor type and on // a box sampler for accelerated trilinear interpolation. openvdb::tools::GridSampler fastSampler(accessor, grid.transform()); // Compute the value of the grid at fractional coordinates in index space. indexValue = fastSampler.isSample(openvdb::Vec3R(10.5, -100.2, 50.3)); // Compute the value of the grid at a location in world space. worldValue = fastSampler.wsSample(openvdb::Vec3R(0.25, 1.4, -1.1)); @endcode Note that when constructing a @b GridSampler with either a tree or a value accessor, you must also supply an index-to-world transform. When constructing a @b GridSampler with a grid, the grid's transform is used automatically. @subsection sDualGridSampler Dual Grid Sampler It might sometimes be necessary to interpolate values from a source grid into the index space of a target grid. If this transformation is to be applied to all of the values in the source grid, then it is best to use the tools in GridTransformer.h. For other cases, consider using the @vdblink::tools::DualGridSampler DualGridSampler@endlink class. Like the @b GridSampler class, this class can be used with grids, trees or value accessors. In addition, @b DualGridSampler checks if the source and target grids are aligned (that is, they have the same transform), in which case it avoids unnecessary interpolation. @code #include #include const GridType sourceGrid = ...; // Instantiate the DualGridSampler template on the grid type and on // a box sampler for thread-safe but uncached trilinear interpolation. openvdb::tools::DualGridSampler sampler(sourceGrid, targetGrid.constTransform()); // Compute the value of the source grid at a location in the // target grid's index space. GridType::ValueType value = sampler(openvdb::Coord(-23, -50, 202)); // Request a value accessor for accelerated access to the source grid. // (Because value accessors employ a cache, it is important to declare // one accessor per thread.) GridType::ConstAccessor accessor = sourceGrid.getConstAccessor(); // Instantiate the DualGridSampler template on the accessor type and on // a box sampler for accelerated trilinear interpolation. openvdb::tools::DualGridSampler fastSampler(accessor, sourceGrid.constTransform(), targetGrid.constTransform()); // Compute the value of the source grid at a location in the // target grid's index space. value = fastSampler(openvdb::Coord(-23, -50, 202)); @endcode Note that interpolation is done by invoking a @b DualGridSampler as a functor, in contrast to the more general-purpose @b GridSampler. @section sXformTools Transforming grids @subsection sResamplingTools Geometric transformation A @vdblink::tools::GridTransformer GridTransformer@endlink applies a geometric transformation to an input grid using one of several sampling schemes, and stores the result in an output grid. The operation is multithreaded by default, though threading can be disabled by calling @vdblink::tools::GridTransformer::setThreaded() setThreaded(false)@endlink. A @b GridTransformer object can be reused to apply the same transformation to multiple input grids, optionally using different sampling schemes. @code #include #include openvdb::FloatGrid::Ptr sourceGrid = ... targetGrid = ...; // Get the source and target grids' index space to world space transforms. const openvdb::math::Transform &sourceXform = sourceGrid->transform(), &targetXform = targetGrid->transform(); // Compute a source grid to target grid transform. // (For this example, we assume that both grids' transforms are linear, // so that they can be represented as 4 x 4 matrices.) openvdb::Mat4R xform = sourceXform.baseMap()->getAffineMap()->getMat4() * targetXform.baseMap()->getAffineMap()->getMat4().inverse(); // Create the transformer. openvdb::tools::GridTransformer transformer(xform); // Resample using nearest-neighbor interpolation. transformer.transformGrid( *sourceGrid, *targetGrid); // Resample using trilinear interpolation. transformer.transformGrid( *sourceGrid, *targetGrid); // Resample using triquadratic interpolation. transformer.transformGrid( *sourceGrid, *targetGrid); // Prune the target tree for optimal sparsity. targetGrid->tree().prune(); @endcode @subsection sValueXformTools Value transformation This example uses @vdblink::tools::foreach() tools::foreach@endlink to multiply all values (both tile and voxel and both active and inactive) of a scalar, floating-point grid by two: @code #include #include // Define a local function that doubles the value to which the given // value iterator points. struct Local { static inline void op(const openvdb::FloatGrid::ValueAllIter& iter) { iter.setValue(*iter * 2); } }; openvdb::FloatGrid::Ptr grid = ...; // Apply the function to all values. openvdb::tools::foreach(grid->beginValueAll(), Local::op); @endcode This example uses @vdblink::tools::foreach() tools::foreach@endlink to rotate all active vectors of a vector-valued grid by 45° about the @em y axis: @code #include #include // Define a functor that multiplies the vector to which the given // value iterator points by a fixed matrix. struct MatMul { openvdb::math::Mat3s M; MatMul(const openvdb::math::Mat3s& mat): M(mat) {} inline void operator()(const openvdb::Vec3SGrid::ValueOnIter& iter) const { iter.setValue(M.transform(*iter)); } }; openvdb::Vec3SGrid::Ptr grid = ...; // Construct the rotation matrix. openvdb::math::Mat3s rot45 = openvdb::math::rotation(openvdb::math::Y_AXIS, openvdb::math::pi()/4.0); // Apply the functor to all active values. openvdb::tools::foreach(grid->beginValueOn(), MatMul(rot45)); @endcode @vdblink::tools::transformValues() tools::transformValues@endlink is similar to @vdblink::tools::foreach() tools::foreach@endlink, but it populates an output grid with transformed values from an input grid that may have a different value type. The following example populates a scalar, floating-point grid with the lengths of all active vectors from a vector-valued grid (like @vdblink::tools::magnitude() tools::magnitude@endlink): @code #include #include // Define a local function that, given an iterator pointing to a vector value // in an input grid, sets the corresponding tile or voxel in a scalar, // floating-point output grid to the length of the vector. struct Local { static inline void op( const openvdb::Vec3SGrid::ValueOnCIter& iter, openvdb::FloatGrid::ValueAccessor& accessor) { if (iter.isVoxelValue()) { // set a single voxel accessor.setValue(iter.getCoord(), iter->length()); } else { // fill an entire tile openvdb::CoordBBox bbox; iter.getBoundingBox(bbox); accessor.getTree().fill(bbox, iter->length()); } } }; openvdb::Vec3SGrid::ConstPtr inGrid = ...; // Create a scalar grid to hold the transformed values. openvdb::FloatGrid::Ptr outGrid = openvdb::FloatGrid::create(); // Populate the output grid with transformed values. openvdb::tools::transformValues(inGrid->cbeginValueOn(), *outGrid, Local::op); @endcode @section sCombiningGrids Combining grids The following examples show various ways in which a pair of grids can be combined in @ref subsecVoxSpace "index space". The assumption is that index coordinates @ijk in both grids correspond to the same physical, @ref subsecWorSpace "world space" location. When the grids have different transforms, it is usually necessary to first @ref sResamplingTools "resample" one grid into the other grid's @ref subsecVoxSpace "index space". @subsection sCsgTools Level set CSG operations The level set CSG functions in tools/Composite.h operate on pairs of grids of the same type, using sparse traversal for efficiency. These operations always leave the second grid empty. @code #include #include // Two grids of the same type containing level set volumes openvdb::FloatGrid::Ptr gridA(...), gridB(...); // Save copies of the two grids; CSG operations always modify // the A grid and leave the B grid empty. openvdb::FloatGrid::ConstPtr copyOfGridA = gridA->deepCopy(), copyOfGridB = gridB->deepCopy(); // Compute the union (A u B) of the two level sets. openvdb::tools::csgUnion(*gridA, *gridB); // Restore the original level sets. gridA = copyOfGridA->deepCopy(); gridB = copyOfGridB->deepCopy(); // Compute the intersection (A n B) of the two level sets. openvdb::tools::csgIntersection(*gridA, *gridB); // Restore the original level sets. gridA = copyOfGridA->deepCopy(); gridB = copyOfGridB->deepCopy(); // Compute the difference (A / B) of the two level sets. openvdb::tools::csgDifference(*gridA, *gridB); @endcode @subsection sCompTools Compositing operations Like the @ref sCsgTools "CSG operations", the compositing functions in tools/Composite.h operate on pairs of grids of the same type, and they always leave the second grid empty. @code #include #include // Two grids of the same type openvdb::FloatGrid::Ptr gridA = ..., gridB = ...; // Save copies of the two grids; compositing operations always // modify the A grid and leave the B grid empty. openvdb::FloatGrid::ConstPtr copyOfGridA = gridA->deepCopy(), copyOfGridB = gridB->deepCopy(); // At each voxel, compute a = max(a, b). openvdb::tools::compMax(*gridA, *gridB); // Restore the original grids. gridA = copyOfGridA->deepCopy(); gridB = copyOfGridB->deepCopy(); // At each voxel, compute a = min(a, b). openvdb::tools::compMin(*gridA, *gridB); // Restore the original grids. gridA = copyOfGridA->deepCopy(); gridB = copyOfGridB->deepCopy(); // At each voxel, compute a = a + b. openvdb::tools::compSum(*gridA, *gridB); // Restore the original grids. gridA = copyOfGridA->deepCopy(); gridB = copyOfGridB->deepCopy(); // At each voxel, compute a = a * b. openvdb::tools::compMul(*gridA, *gridB); @endcode @subsection sCombineTools Generic combination The @vdblink::tree::Tree::combine() Tree::combine@endlink family of methods apply a user-supplied operator to pairs of corresponding values of two trees. These methods are efficient because they take into account the sparsity of the trees; they are not multithreaded, however. This example uses the @vdblink::tree::Tree::combine() Tree::combine@endlink method to compute the difference between corresponding voxels of two floating-point grids: @code #include // Define a local function that subtracts two floating-point values. struct Local { static inline void diff(const float& a, const float& b, float& result) { result = a - b; } }; openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; // Compute the difference between corresponding voxels of aGrid and bGrid // and store the result in aGrid, leaving bGrid empty. aGrid->tree().combine(bGrid->tree(), Local::diff); @endcode Another @vdblink::tree::Tree::combine() Tree::combine@endlink example, this time using a functor to preserve state: @code #include // Define a functor that computes f * a + (1 - f) * b for pairs of // floating-point values a and b. struct Blend { Blend(float f): frac(f) {} inline void operator()(const float& a, const float& b, float& result) const { result = frac * a + (1.0 - frac) * b; } float frac; }; openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; // Compute a = 0.25 * a + 0.75 * b for all corresponding voxels of // aGrid and bGrid. Store the result in aGrid and empty bGrid. aGrid->tree().combine(bGrid->tree(), Blend(0.25)); @endcode The @vdblink::tree::Tree::combineExtended() Tree::combineExtended@endlink method invokes a function of the form void f(CombineArgs\& args), where the @vdblink::CombineArgs CombineArgs@endlink object encapsulates an @em a and a @em b value and their active states as well as a result value and its active state. In the following example, voxel values in floating-point @a aGrid are replaced with corresponding values from floating-point @a bGrid (leaving @a bGrid empty) wherever the @em b values are larger. The active states of any transferred values are preserved. @code #include // Define a local function that retrieves a and b values from a CombineArgs // struct and then sets the result member to the maximum of a and b. struct Local { static inline void max(CombineArgs& args) { if (args.b() > args.a()) { // Transfer the B value and its active state. args.setResult(args.b()); args.setResultIsActive(args.bIsActive()); } else { // Preserve the A value and its active state. args.setResult(args.a()); args.setResultIsActive(args.aIsActive()); } } }; openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; aGrid->tree().combineExtended(bGrid->tree(), Local::max); @endcode Like @b combine, @vdblink::tree::Tree::combine2() Tree::combine2@endlink applies an operation to pairs of corresponding values of two trees. However, @b combine2 writes the result to a third, output tree and does not modify either of the two input trees. (As a result, it is less space-efficient than the @b combine method.) Here, the voxel differencing example above is repeated using @b combine2: @code #include struct Local { static inline void diff(const float& a, const float& b, float& result) { result = a - b; } }; openvdb::FloatGrid::ConstPtr aGrid = ..., bGrid = ...; openvdb::FloatGrid::Ptr resultGrid = openvdb::FloatGrid::create(); // Combine aGrid and bGrid and write the result into resultGrid. // The input grids are not modified. resultGrid->tree().combine2(aGrid->tree(), bGrid->tree(), Local::diff); @endcode An @vdblink::tree::Tree::combine2Extended() extended combine2@endlink is also available. @section sGenericProg Generic programming @subsection sTypedGridMethods Calling Grid methods A common task is to perform some operation on all of the grids in a file, where the operation involves @vdblink::Grid Grid@endlink method calls and the grids are of different types. Only a handful of @b Grid methods, such as @vdblink::Grid::activeVoxelCount() activeVoxelCount@endlink, are virtual and can be called through a @vdblink::GridBase GridBase@endlink pointer; most are not, because they require knowledge of the Grid's value type. For example, one might want to @vdblink::tree::Tree::prune() prune@endlink the trees of all of the grids in a file regardless of their type, but @b Tree::prune is non-virtual because it accepts an optional pruning tolerance argument whose type is the grid's value type. The @b processTypedGrid function below makes this kind of task easier. It is called with a @b GridBase pointer and a functor whose call operator accepts a pointer to a @b Grid of arbitrary type. The call operator should be templated on the grid type and, if necessary, overloaded for specific grid types. @code template void processTypedGrid(openvdb::GridBase::Ptr grid, OpType& op) { #define CALL_OP(GridType) \ op.template operator()(openvdb::gridPtrCast(grid)) if (grid->isType()) CALL_OP(openvdb::BoolGrid); else if (grid->isType()) CALL_OP(openvdb::FloatGrid); else if (grid->isType()) CALL_OP(openvdb::DoubleGrid); else if (grid->isType()) CALL_OP(openvdb::Int32Grid); else if (grid->isType()) CALL_OP(openvdb::Int64Grid); else if (grid->isType()) CALL_OP(openvdb::Vec3IGrid); else if (grid->isType()) CALL_OP(openvdb::Vec3SGrid); else if (grid->isType()) CALL_OP(openvdb::Vec3DGrid); #undef CALL_OP } @endcode The following example shows how to use @b processTypedGrid to implement a generic pruning operation for grids of all built-in types: @code #include // Define a functor that prunes the trees of grids of arbitrary type // with a fixed pruning tolerance. struct PruneOp { double tolerance; PruneOp(double t): tolerance(t) {} template void operator()(typename GridType::Ptr grid) const { grid->tree().prune(typename GridType::ValueType(tolerance)); } }; // Read all grids from a file. openvdb::io::File file("mygrids.vdb"); file.open(); openvdb::GridPtrVecPtr myGrids = file.getGrids(); file.close(); // Prune each grid with a tolerance of 1%. const PruneOp pruner(/*tolerance=*/0.01); for (openvdb::GridPtrVecIter iter = myGrids->begin(); iter != myGrids->end(); ++iter) { openvdb::GridBase::Ptr grid = *iter; processTypedGrid(grid, pruner); } @endcode @anchor openvdbPointsHelloWorld @section sPointsHelloWorld “Hello, World” for OpenVDB Points This is a simple example showing how to convert a few points, perform I/O and iterate over them to extract their world-space positions. For more information about using OpenVDB to store point data, see the @ref openvdbPointsOverview "OpenVDB Points Documentation". @code #include #include #include #include #include int main() { // Initialize grid types and point attributes types. openvdb::initialize(); // Create a vector with four point positions. std::vector positions; positions.push_back(openvdb::Vec3R(0, 1, 0)); positions.push_back(openvdb::Vec3R(1.5, 3.5, 1)); positions.push_back(openvdb::Vec3R(-1, 6, -2)); positions.push_back(openvdb::Vec3R(1.1, 1.25, 0.06)); // The VDB Point-Partioner is used when bucketing points and requires a // specific interface. For convenience, we use the PointAttributeVector // wrapper around an stl vector wrapper here, however it is also possible to // write one for a custom data structure in order to match the interface // required. openvdb::points::PointAttributeVector positionsWrapper(positions); // This method computes a voxel-size to match the number of // points / voxel requested. Although it won't be exact, it typically offers // a good balance of memory against performance. int pointsPerVoxel = 8; float voxelSize = openvdb::points::computeVoxelSize(positionsWrapper, pointsPerVoxel); // Print the voxel-size to cout std::cout << "VoxelSize=" << voxelSize << std::endl; // Create a transform using this voxel-size. openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(voxelSize); // Create a PointDataGrid containing these four points and using the // transform given. This function has two template parameters, (1) the codec // to use for storing the position, (2) the grid we want to create // (ie a PointDataGrid). // We use no compression here for the positions. openvdb::points::PointDataGrid::Ptr grid = openvdb::points::createPointDataGrid(positions, *transform); // Set the name of the grid grid->setName("Points"); // Create a VDB file object and write out the grid. openvdb::io::File("mypoints.vdb").write({grid}); // Create a new VDB file object for reading. openvdb::io::File newFile("mypoints.vdb"); // Open the file. This reads the file header, but not any grids. newFile.open(); // Read the grid by name. openvdb::GridBase::Ptr baseGrid = newFile.readGrid("Points"); newFile.close(); // From the example above, "Points" is known to be a PointDataGrid, // so cast the generic grid pointer to a PointDataGrid pointer. grid = openvdb::gridPtrCast(baseGrid); openvdb::Index64 count = openvdb::points::pointCount(grid->tree()); std::cout << "PointCount=" << count << std::endl; // Iterate over all the leaf nodes in the grid. for (auto leafIter = grid->tree().cbeginLeaf(); leafIter; ++leafIter) { // Verify the leaf origin. std::cout << "Leaf" << leafIter->origin() << std::endl; // Extract the position attribute from the leaf by name (P is position). const openvdb::points::AttributeArray& array = leafIter->constAttributeArray("P"); // Create a read-only AttributeHandle. Position always uses Vec3f. openvdb::points::AttributeHandle positionHandle(array); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Extract the voxel-space position of the point. openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter); // Extract the index-space position of the voxel. const openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); // Compute the world-space position of the point. openvdb::Vec3f worldPosition = grid->transform().indexToWorld(voxelPosition + xyz); // Verify the index and world-space position of the point std::cout << "* PointIndex=[" << *indexIter << "] "; std::cout << "WorldPosition=" << worldPosition << std::endl; } } } @endcode Output: @code VoxelSize=3.34716 PointCount=4 Leaf[0, 0, -8] * PointIndex=[0] WorldPosition=[-1, 6, -2] Leaf[0, 0, 0] * PointIndex=[0] WorldPosition=[0, 1, 0] * PointIndex=[1] WorldPosition=[1.1, 1.25, 0.06] * PointIndex=[2] WorldPosition=[1.5, 3.5, 1] @endcode @section sPointsConversion Converting Point Attributes This example is the same as the @ref sPointsHelloWorld example, however it demonstrates converting radius in addition to position. It uses a tailored attribute compression for the radius to demonstrate how to reduce memory. These methods heavily rely on the point conversion methods contained in points/PointConversion.h. @code #include #include #include #include #include int main() { // Initialize grid types and point attributes types. openvdb::initialize(); // Create a vector with four point positions. std::vector positions; positions.push_back(openvdb::Vec3R(0, 1, 0)); positions.push_back(openvdb::Vec3R(1.5, 3.5, 1)); positions.push_back(openvdb::Vec3R(-1, 6, -2)); positions.push_back(openvdb::Vec3R(1.1, 1.25, 0.06)); // Create a vector with four radii. std::vector radius; radius.push_back(0.1); radius.push_back(0.15); radius.push_back(0.2); radius.push_back(0.5); // The VDB Point-Partioner is used when bucketing points and requires a // specific interface. For convenience, we use the PointAttributeVector // wrapper around an stl vector wrapper here, however it is also possible to // write one for a custom data structure in order to match the interface // required. openvdb::points::PointAttributeVector positionsWrapper(positions); // This method computes a voxel-size to match the number of // points / voxel requested. Although it won't be exact, it typically offers // a good balance of memory against performance. int pointsPerVoxel = 8; float voxelSize = openvdb::points::computeVoxelSize(positionsWrapper, pointsPerVoxel); // Create a transform using this voxel-size. openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(voxelSize); // Create a PointIndexGrid. This can be done automatically on creation of // the grid, however as this index grid is required for the position and // radius attributes, we create one we can use for both attribute creation. openvdb::tools::PointIndexGrid::Ptr pointIndexGrid = openvdb::tools::createPointIndexGrid( positionsWrapper, *transform); // Create a PointDataGrid containing these four points and using the point // index grid. This requires the positions wrapper. openvdb::points::PointDataGrid::Ptr grid = openvdb::points::createPointDataGrid(*pointIndexGrid, positionsWrapper, *transform); // Append a "pscale" attribute to the grid to hold the radius. // This attribute storage uses a unit range codec to reduce the memory // storage requirements down from 4-bytes to just 1-byte per value. This is // only possible because accuracy of the radius is not that important to us // and the values are always within unit range (0.0 => 1.0). // Note that this attribute type is not registered by default so needs to be // explicitly registered. using Codec = openvdb::points::FixedPointCodec; openvdb::points::TypedAttributeArray::registerType(); openvdb::NamePair radiusAttribute = openvdb::points::TypedAttributeArray::attributeType(); openvdb::points::appendAttribute(grid->tree(), "pscale", radiusAttribute); // Create a wrapper around the radius vector. openvdb::points::PointAttributeVector radiusWrapper(radius); // Populate the "pscale" attribute on the points openvdb::points::populateAttribute>( grid->tree(), pointIndexGrid->tree(), "pscale", radiusWrapper); // Set the name of the grid grid->setName("Points"); // Iterate over all the leaf nodes in the grid. for (auto leafIter = grid->tree().cbeginLeaf(); leafIter; ++leafIter) { // Verify the leaf origin. std::cout << "Leaf" << leafIter->origin() << std::endl; // Extract the position attribute from the leaf by name (P is position). const openvdb::points::AttributeArray& positionArray = leafIter->constAttributeArray("P"); // Extract the radius attribute from the leaf by name (pscale is radius). const openvdb::points::AttributeArray& radiusArray = leafIter->constAttributeArray("pscale"); // Create read-only handles for position and radius. openvdb::points::AttributeHandle positionHandle(positionArray); openvdb::points::AttributeHandle radiusHandle(radiusArray); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Extract the voxel-space position of the point. openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter); // Extract the world-space position of the voxel. openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); // Compute the world-space position of the point. openvdb::Vec3f worldPosition = grid->transform().indexToWorld(voxelPosition + xyz); // Extract the radius of the point. float radius = radiusHandle.get(*indexIter); // Verify the index, world-space position and radius of the point. std::cout << "* PointIndex=[" << *indexIter << "] "; std::cout << "WorldPosition=" << worldPosition << " "; std::cout << "Radius=" << radius << std::endl; } } } @endcode Output: @code Leaf[0, 0, -8] * PointIndex=[0] WorldPosition=[-1, 6, -2] Radius=0.2 Leaf[0, 0, 0] * PointIndex=[0] WorldPosition=[0, 1, 0] Radius=0.0999924 * PointIndex=[1] WorldPosition=[1.1, 1.25, 0.06] Radius=0.499992 * PointIndex=[2] WorldPosition=[1.5, 3.5, 1] Radius=0.149996 @endcode @section sPointsGeneration Random Point Generation This example demonstrates how to create a new point grid and to populate it with random point positions initialized inside a level set sphere. @code #include #include #include #include int main() { // Initialize grid types and point attributes types. openvdb::initialize(); // Generate a level set grid. openvdb::FloatGrid::Ptr sphereGrid = openvdb::tools::createLevelSetSphere(/*radius=*/20.0, /*center=*/openvdb::Vec3f(1.5, 2, 3), /*voxel size=*/0.5); // Retrieve the number of leaf nodes in the grid. openvdb::Index leafCount = sphereGrid->tree().leafCount(); // Use the topology to create a PointDataTree openvdb::points::PointDataTree::Ptr pointTree( new openvdb::points::PointDataTree(sphereGrid->tree(), 0, openvdb::TopologyCopy())); // Ensure all tiles have been voxelized pointTree->voxelizeActiveTiles(); // Define the position type and codec using fixed-point 16-bit compression. using PositionAttribute = openvdb::points::TypedAttributeArray>; openvdb::NamePair positionType = PositionAttribute::attributeType(); // Create a new Attribute Descriptor with position only openvdb::points::AttributeSet::Descriptor::Ptr descriptor( openvdb::points::AttributeSet::Descriptor::create(positionType)); // Determine the number of points / voxel and points / leaf. openvdb::Index pointsPerVoxel = 8; openvdb::Index voxelsPerLeaf = openvdb::points::PointDataGrid::TreeType::LeafNodeType::SIZE; openvdb::Index pointsPerLeaf = pointsPerVoxel * voxelsPerLeaf; // Iterate over the leaf nodes in the point tree. for (auto leafIter = pointTree->beginLeaf(); leafIter; ++leafIter) { // Initialize the attributes using the descriptor and point count. leafIter->initializeAttributes(descriptor, pointsPerLeaf); // Initialize the voxel offsets openvdb::Index offset(0); for (openvdb::Index index = 0; index < voxelsPerLeaf; ++index) { offset += pointsPerVoxel; leafIter->setOffsetOn(index, offset); } } // Create the points grid. openvdb::points::PointDataGrid::Ptr points = openvdb::points::PointDataGrid::create(pointTree); // Set the name of the grid. points->setName("Points"); // Copy the transform from the sphere grid. points->setTransform(sphereGrid->transform().copy()); // Randomize the point positions. std::mt19937 generator(/*seed=*/0); std::uniform_real_distribution<> distribution(-0.5, 0.5); // Iterate over the leaf nodes in the point tree. for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { // Create an AttributeWriteHandle for position. // Note that the handle only requires the value type, not the codec. openvdb::points::AttributeArray& array = leafIter->attributeArray("P"); openvdb::points::AttributeWriteHandle handle(array); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Compute a new random position (in the range -0.5 => 0.5). openvdb::Vec3f positionVoxelSpace(distribution(generator)); // Set the position of this point. // As point positions are stored relative to the voxel center, it is // not necessary to convert these voxel space values into // world-space during this process. handle.set(*indexIter, positionVoxelSpace); } } // Verify the point count. openvdb::Index count = openvdb::points::pointCount(points->tree()); std::cout << "LeafCount=" << leafCount << std::endl; std::cout << "PointCount=" << count << std::endl; } @endcode Output: @code LeafCount=660 PointCount=2703360 @endcode @section sPointIterationFiltering Point Iteration, Groups and Filtering This section demonstrates how to iterate over points and to use point groups and custom filters during iteration. See the documentation describing iteration and filtering under @ref openvdbPointsIterators "OpenVDB Points Iteration" for more information. @subsection sPointIteration Point Iteration Iterating over point attribute data is most easily done by iterating over the leaf nodes of a PointDataGrid and then the index indices of the attribute within the leaf and extracting the values from a handle bound to the attribute stored within the leaf. This example demonstrates single-threaded, read-only iteration over all float values of an attribute called "name". @code for (auto leafIter = pointTree.beginLeaf(); leafIter; ++leafIter) { openvdb::points::AttributeArray& array = leafIter->constAttributeArray("name"); openvdb::points::AttributeHandle handle(array); // Iterate over active indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Retrieve value float value = handle.get(*indexIter); } } @endcode This example demonstrates single-threaded, read-write iteration for a similar float attribute by setting all values to be 5.0f. @code for (auto leafIter = pointTree.beginLeaf(); leafIter; ++leafIter) { openvdb::points::AttributeArray& array = leafIter->attributeArray("name"); openvdb::points::AttributeWriteHandle handle(array); // Iterate over active indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Set value handle.set(*indexIter, 5.0f); } } @endcode Here is the same read-only example using TBB and a custom operator for reading values using multi-threaded access. In this example, we also find the index of the attribute in the descriptor to avoid having to look this up each time (assuming that all leaf nodes share the same descriptor). A similar approach can be used for multi-threaded writing. @code struct ReadValueOp { explicit ReadValueOp(openvdb::Index64 index) : mIndex(index) { } void operator()(const openvdb::tree::LeafManager< openvdb::points::PointDataTree>::LeafRange& range) const { for (auto leafIter = range.begin(); leafIter; ++leafIter) { for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { const openvdb::points::AttributeArray& array = leafIter->constAttributeArray(mIndex); openvdb::points::AttributeHandle handle(array); float value = handle.get(*indexIter); } } } openvdb::Index64 mIndex; }; // Create a leaf iterator for the PointDataTree. auto leafIter = pointTree.cbeginLeaf(); // Check that the tree has leaf nodes. if (!leafIter) { std::cerr << "No Leaf Nodes" << std::endl; } // Retrieve the index from the descriptor. auto descriptor = leafIter->attributeSet().descriptor(); openvdb::Index64 index = descriptor.find("name"); // Check that the attribute has been found. if (index == openvdb::points::AttributeSet::INVALID_POS) { std::cerr << "Invalid Attribute" << std::endl; } // Create a leaf manager for the points tree. openvdb::tree::LeafManager leafManager( pointsTree); // Create a new operator ReadValueOp op(index); // Evaluate in parallel tbb::parallel_for(leafManager.leafRange(), op); @endcode Tip: To run a multi-threaded operator as single-threaded for debugging, set the grainsize argument to a number larger than the number of leaf nodes (it defaults to 1). @code // Evaluate parallel operator in serial tbb::parallel_for(leafManager.leafRange(/*grainsize=*/1000000), op); @endcode @subsection sPointGroups Creating and Assigning Point Groups Point groups in OpenVDB are analagous to Houdini point groups as an efficient way of tagging specific points to belong to a named group. This example uses the data set generated in the @ref sPointsGeneration example. @code // Append a new (empty) group to the point tree. openvdb::points::appendGroup(points->tree(), "positiveY"); // Count all points that belong to this group. openvdb::Index groupCount = openvdb::points::groupPointCount(points->tree(), "positiveY"); // Verify group is empty. std::cout << "PointCount=" << count << std::endl; std::cout << "EmptyGroupPointCount=" << groupCount << std::endl; // Create leaf node iterator for points tree. auto leafIter = points->tree().beginLeaf(); if (!leafIter) { std::cerr << "No Leaf Nodes" << std::endl; } // Extract the group index. openvdb::points::AttributeSet::Descriptor::GroupIndex groupIndex = leafIter->attributeSet().groupIndex("positiveY"); // Iterate over leaf nodes. for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { // Create a read-only position handle. const openvdb::points::AttributeArray& positionArray = leafIter->constAttributeArray("P"); openvdb::points::AttributeHandle positionHandle( positionArray); // Create a read-write group handle. openvdb::points::GroupWriteHandle groupHandle = leafIter->groupWriteHandle("positiveY"); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Extract the voxel-space position of the point. openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter); // Extract the world-space position of the voxel. openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); // Compute the world-space position of the point. openvdb::Vec3f worldPosition = points->transform().indexToWorld(voxelPosition + xyz); // If the world-space position is greater than zero in Y, add this // point to the group. if (worldPosition.y() > 0.0f) { groupHandle.set(*indexIter, /*on=*/true); } } // Attempt to compact the array for efficiency if all points in a leaf // have the same membership for example. groupHandle.compact(); } // Count all points in this group once again. groupCount = openvdb::points::groupPointCount(points->tree(), "positiveY"); // Verify group membership. std::cout << "GroupPointCount=" << groupCount << std::endl; @endcode Output: @code PointCount=2703360 EmptyGroupPointCount=0 GroupPointCount=1463740 @endcode @subsection sPointFiltering Point Filtering using Groups One highly useful feature of groups is to be able to use them for performing filtered iteration. Here is an example iterating over all the points in the same data set to compute the average position in Y. @code openvdb::Index64 iterationCount(0); double averageY(0.0); // Iterate over leaf nodes. for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { // Create a read-only position handle. const openvdb::points::AttributeArray& positionArray = leafIter->constAttributeArray("P"); openvdb::points::AttributeHandle positionHandle( positionArray); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Extract the world-space position of the point. openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter); openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); openvdb::Vec3f worldPosition = points->transform().indexToWorld(voxelPosition + xyz); // Increment the sum. averageY += worldPosition.y(); // Track iteration iterationCount++; } } averageY /= double(count); std::cout << "IterationCount=" << iterationCount << std::endl; std::cout << "AveragePositionInY=" << averageY << std::endl; @endcode Output: @code IterationCount=2703360 AveragePositionInY=1.89564 @endcode And the same example filtering using the "positiveY" group during iteration. @code iterationCount = 0; double averageYPositive(0.0); // Create a "positiveY" group filter. openvdb::points::GroupFilter filter("positiveY"); // Iterate over leaf nodes. for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { // Create a read-only position handle. const openvdb::points::AttributeArray& positionArray = leafIter->constAttributeArray("P"); openvdb::points::AttributeHandle positionHandle( positionArray); // Iterate over the point indices in the leaf that match the filter. for (auto indexIter = leafIter->beginIndexOn(filter); indexIter; ++indexIter) { // Extract the world-space position of the point. openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter); openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); openvdb::Vec3f worldPosition = points->transform().indexToWorld(voxelPosition + xyz); // Increment the sum. averageYPositive += worldPosition.y(); // Track iteration iterationCount++; } } averageYPositive /= double(groupCount); std::cout << "IterationCount=" << iterationCount << std::endl; std::cout << "AveragePositivePositionInY=" << averageYPositive << std::endl; @endcode Output: @code IterationCount=1463740 AveragePositivePositionInY=11.373 @endcode This approach still performs this operation in two passes, (1) creating and assigning the groups and (2) iterating using the group. @subsection sPointCustomFiltering Point Filtering using Custom Filters For common operations, it is typically faster to sacrifice the flexibility of point groups for a custom filter. This is using the same data set from the previous example. @code // Evalutate true for points that are positive in Y only struct PositiveYFilter { using Handle = openvdb::points::AttributeHandle; explicit PositiveYFilter(const openvdb::math::Transform& transform) : mTransform(transform) { } PositiveYFilter(const PositiveYFilter& filter) : mTransform(filter.mTransform) { if (filter.mPositionHandle) { mPositionHandle.reset(new Handle(*filter.mPositionHandle)); } } inline bool initialized() const { return bool(mPositionHandle); } template void reset(const LeafT& leaf) { mPositionHandle.reset(new Handle(leaf.constAttributeArray("P"))); } template bool valid(const IterT& indexIter) const { openvdb::Vec3f voxelPosition = mPositionHandle->get(*indexIter); openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); openvdb::Vec3f worldPosition = mTransform.indexToWorld(voxelPosition + xyz); return worldPosition.y() > 0.0f; } const openvdb::math::Transform& mTransform; Handle::UniquePtr mPositionHandle; }; // Drop the "positiveY" group. openvdb::points::dropGroup(points->tree(), "positiveY"); // Create a new positive-Y filter. PositiveYFilter positiveYFilter(points->transform()); iterationCount = 0.0; // Iterate over the points using the custom filter for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { for (auto indexIter = leafIter->beginIndexOn(positiveYFilter); indexIter; ++indexIter) { // Track iteration iterationCount++; } } std::cout << "IterationCount=" << iterationCount << std::endl; @endcode Output: @code IterationCount=1463740 @endcode @section sPointStride Strided Point Attributes Point attributes can have a stride greater than one in order to store multiple values with each attribute with each point. @subsection sConstantStride Constant Stride Attributes A stride can be constant so that each attribute has the same number of values. This example demonstrates using a hard-coded 10 samples per point in an attribute called "samples". @code // Store 10 values per point in an attribute called samples. openvdb::Index stride(10); openvdb::points::appendAttribute(points->tree(), "samples", openvdb::points::TypedAttributeArray::attributeType(), stride); // Iterate over leaf nodes. for (auto leafIter = points->tree().beginLeaf(); leafIter; ++leafIter) { // Create a read-write samples handle. openvdb::points::AttributeArray& array( leafIter->attributeArray("samples")); openvdb::points::AttributeWriteHandle handle(array); // Iterate over the point indices in the leaf. for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Use ascending sample values for each element in the strided array for (int i = 0; i < 10; i++) { handle.set(*indexIter, /*strideIndex=*/i, float(i)); } } } @endcode @section sPointMove Moving Points in Space As points are stored within voxels in an implicit spatially organised data structure, moving points in space requires re-bucketing the data. @subsection sPointAdvect Advecting Points Advection uses a specified integration order (4 = runge-kutta 4th) as well as delta time and time-step parameters to advect the points in-place using the supplied velocity grid. @code // Create an empty velocity grid with gravity as background value auto gravity = openvdb::Vec3SGrid::create(openvdb::Vec3s(0, -9.81, 0)); // Advect points in-place using gravity velocity grid openvdb::points::advectPoints(*points, *gravity, /*integrationOrder=*/4, /*dt=*/1.0/24.0, /*timeSteps=*/1); @endcode @subsection sPointCustomDeformer Moving Points with a Custom Deformer A custom deformer generates the new position of each existing point in a point set. This can use any number of mechanisms to achieve this such as a static value, a hard-coded list of positions, a function that uses the existing position to compute the new one or a function that uses the index of the point within the leaf array in some other way. This example simply takes the input position and adds a Y offset. Note that it is also possible to configure a custom deformer to operate in index-space. @code // This custom deformer is also used in the TestPointMove unit tests. struct OffsetDeformer { OffsetDeformer(const openvdb::Vec3d& _offset) : offset(_offset){ } template void reset(const LeafIterT&) { } template void apply(openvdb::Vec3d& position, const IndexIterT&) const { position += offset; } openvdb::Vec3d offset; }; // Create an OffsetDeformer that moves the points downwards in Y by 10 world-space units. openvdb::Vec3d offset(0, -10, 0); OffsetDeformer deformer(offset); // Move the points using this deformer openvdb::points::movePoints(*points, deformer); @endcode */ openvdb-13.0.0/doc/faq.txt000066400000000000000000000305501510223237100153040ustar00rootroot00000000000000/** @page faq Frequently Asked Questions @section sFAQContents Contents - @ref sWhatIsVDB - @ref sWhatLicense - @ref sWhatCLA - @ref sWhyUseVDB - @ref sVersionNumbering - @ref sGeneralizedOctree - @ref sLevelSet - @ref sCustomizeVDB - @ref sAdaptiveGrid - @ref sMeaningOfVDB - @ref sAccessor - @ref sValue - @ref sState - @ref sVoxel - @ref sTile - @ref sBackground - @ref sThreadSafe - @ref sMaxRes - @ref sCompareVDB - @ref sReplaceDense - @ref sContribute @section sWhatIsVDB What is OpenVDB? OpenVDB is a library comprising a compact hierarchical data structure and a suite of tools for the efficient manipulation of sparse, possibly time-varying, volumetric data discretized on a three-dimensional grid. It is based on VDB, which was developed by Ken Museth at DreamWorks Animation, and it offers an effectively infinite 3D index space, compact storage (both in memory and on disk), fast data access (both random and sequential), and a collection of algorithms specifically optimized for the data structure for common tasks such as filtering, constructive solid geometry (CSG), discretization of partial differential equations, voxelization of polygons, skinning of particles, volumetric compositing and sampling. The technical details of VDB are described in the paper "VDB: High-Resolution Sparse Volumes with Dynamic Topology". @section sWhatLicense What license is OpenVDB distributed under? OpenVDB is released under the Apache License Version 2.0, which is a free, open source software license developed and maintained by the Apache Software Foundation. For more information about this license, see Apache License, Version 2. @section sWhatCLA Is there a Contributor License Agreement for OpenVDB? Yes, developers who wish to contribute code to be considered for inclusion in the OpenVDB distribution must first be authorized under a signed Contributor License Agreement. The signature and authorization process is managed via the Linux Foundation's EasyCLA system, to handle the different CLAs depending on whether you are contributing on your own behalf or on behalf of your employer. The EasyCLA process will begin the first time you submit a PR to the project. @section sWhyUseVDB Why should I use OpenVDB? The typical reasons to adopt OpenVDB are if you are storing sparse data and/or if you are performing sparse computations. OpenVDB is also effectively unbounded, which makes it very convenient for applications where the topology of the data is dynamic or unknown. Unlike many existing sparse data structures, OpenVDB is also optimized for numerical simulations, multithreaded volume compositing, near real-time boolean CSG operations, fast random and sequential data access and voxelization of points and polygons. @section sVersionNumbering What is the version numbering system for OpenVDB? We currently use a major.minor.patch version numbering system, and with every release of OpenVDB we change one or more of the three numbers. The patch number is incremented for new features and bug fixes that change neither the API nor the file format of the library nor the ABIs of the @b Grid class or its constituent classes (@b Tree, @b Transform, @b Metadata, @b io::StreamMetadata, etc.). The minor version is incremented for releases that change the API without changing the @b Grid ABI, and for releases that change the file format in such a way that older files can still be read. The major version is incremented when the @b Grid ABI changes, or when the file format changes in a non-backward-compatible way (which should be rare). No release of OpenVDB guarantees ABI compatibility across the entire library, but rather only for the @b Grid and its constituent classes, and primarily to allow third-party app plugins compiled against different versions of the library to coexist and exchange data. @section sCustomizeVDB Can I customize the configuration of OpenVDB? Yes! OpenVDB is specifically developed to be highly customizable. That is, the user can define the sizes of all the nodes at each level of a tree as well as the number of tree levels and the data type of values stored in the tree. However, note that since OpenVDB makes extensive use of C++ templating, configurations are fixed at compile time rather than at run time. This is a fundamental design characteristic of OpenVDB, and it leads to very high performance, thanks to techniques like inlining and template metaprogramming. @section sGeneralizedOctree Is OpenVDB merely a generalized octree or N-tree? No! While OpenVDB can conceptually be configured as a (height-balanced) octree, it is much more than an octree or N-tree. Whereas octrees and N-trees have fixed branching factors of respectively two and N in each coordinate direction, OpenVDB’s branching factors typically vary between tree levels and are only limited to be powers of two. To understand why and also learn about other unique features of OpenVDB, refer to the paper in ACM Transactions on Graphics. @section sLevelSet Is OpenVDB primarily for level set applications? No! Don’t let the fact that OpenVDB can represent and operate so well on level sets mislead you into thinking that it is limited to or even focusing on this special type of sparse volumetric application. OpenVDB was developed for general-purpose volumetric processing and numerical simulation, and we have even had success using it for volumetric applications that traditionally call for blocked or dense grids. However, the fact remains that narrow-band level sets play an essential role in many volumetric applications, and this explains why OpenVDB includes so many tools and algorithms specifically for level sets. @section sAdaptiveGrid Is OpenVDB an adaptive grid? Let’s first stress that the term "adaptive grid" is somewhat ambiguous. Some use it to mean a grid that can store data sampled at adaptive voxel sizes typically derived from a so-called "refinement oracle", whereas others mean multiple grids with different fixed voxel sizes all sampling the same data. An example of the former is an octree and of the latter is a mipmap. Since OpenVDB stores both data values and child nodes at each level of the tree, it is adaptive only in the first sense, not the second. The level of adaptivity or refinement between the tree levels is defined by the branching factors of the nodes, which are fixed at compile time. @section sMeaningOfVDB What does "VDB" stand for? Over the years VDB has been interpreted to mean different things, none of which are very descriptive: "Voxel Data Base", "Volumetric Data Blocks", "Volumetric Dynamic B+tree", etc. In early presentations of VDB we even used a different name, "DB+Grid", which was abandoned to emphasize its distinction from similarly named, but different, existing sparse data structures like DT-Grid or DB-Grid. The simple truth is that "VDB" is just a name. :-) @section sAccessor Why are there no coordinate-based access methods on the grid? It might surprise you that the @b Grid class doesn’t directly provide access to voxels via their @ijk coordinates. Instead, the recommended procedure is to ask the grid for a "value accessor", which is an accelerator object that performs bottom-up tree traversal using cached information from previous traversals. Caching greatly improves performance, but it is inherently not thread-safe. However, a single grid may have multiple value accessors, so each thread can safely be assigned its own value accessor. Uncached—and therefore slower, but thread-safe—random access is possible through a grid’s tree, for example with a call like grid.tree().getValue(ijk). @section sValue How and where does OpenVDB store values? OpenVDB stores voxel data in a tree with a fixed maximum height (chosen at compile time), with a root node that has a dynamic branching factor, with internal nodes that have fixed branching factors, and with leaf nodes of fixed dimensions. Values can be stored in nodes at all levels of the tree. Values stored in leaf nodes correspond to individual voxels; all other values correspond to "tiles" (see below). @section sState What are active and inactive values? Every value in a grid has a binary state that we refer to as its "active state". The interpretation of this binary state is application-specific, but typically an active (on) value is "interesting" in some sense, and an inactive (off) value is less interesting or uninteresting. For example, the values in a narrow-band level set are all active, and values outside the narrow band are all inactive. Active states of values are stored in very compact bit masks that support sparse iteration, so visiting all active (or inactive) values in a grid can be done very efficiently. @section sVoxel How are voxels represented in OpenVDB? Values stored in nodes of type @b LeafNode (which, when they exist, have a fixed depth), correspond to individual voxels. These are the smallest addressable units of index space. @section sTile What are tiles? Values stored in nodes of type @b RootNode or @b InternalNode correspond to regions of index space with a constant value and active state and with power of two dimensions. We refer to such regions as "tiles". By construction, tiles have no child nodes. @section sBackground What is the background value? A tree’s background value is the value that is returned whenever one accesses a region of index space that is not explicitly represented by voxels or tiles in the tree. Thus, you can think of the background value as the default value associated with an empty tree. Note that the background value is always inactive! @section sThreadSafe Is OpenVDB thread-safe? Yes and no. If you’re asking if OpenVDB can safely be used in a multithreaded application then the answer is a resounding yes. In fact, many of the tools included in OpenVDB are multithreaded (using Intel’s Threading Building Blocks library). However, like virtually all data structures that employ caching and allocate-on-insert, certain operations in OpenVDB are not thread-safe in the general sense. In particular, it is not safe to retrieve voxels from a grid while another thread is inserting voxels. For multithreaded insertion operations we typically assign a separate grid to each thread and then merge the grids as threads terminate. This technique works remarkably well: because OpenVDB is sparse and hierarchical, merging is very efficient. For more details, please consult the @subpage codeExamples and Appendix B in the Transactions on Graphics paper. @section sMaxRes Is OpenVDB unbounded? Yes, to within available memory and the 32-bit precision of the coordinates used to index voxels. And OpenVDB supports signed coordinates, unlike most existing sparse data structures, so there are almost no restrictions on the available grid resolution or the index range of OpenVDB grids. @section sCompareVDB How does OpenVDB compare to existing sparse data structures? OpenVDB is very different from existing sparse data structures that you are likely to have heard of. Foremost it is hierarchical (unlike DT-Grid and Field3D), supports simulations and dynamic topology (unlike GigaVoxels), is effectively unbounded (unlike Field3D), and offers fast random and sequential voxel access. @section sReplaceDense Does OpenVDB replace dense grids? This depends a lot on your application of dense grids and your configuration of OpenVDB. Clearly, if you are storing or processing sparse data, OpenVDB will offer a smaller memory footprint and faster (sparse) data processing. However, even in some cases where both data and computation are dense, OpenVDB can offer benefits like improved CPU cache performance due to its underlying blocking and hierarchical tree structure. Exceptions are of course algorithms that expect dense data to be laid out linearly in memory, or applications that use very small grids. The simple truth is only a benchmark comparison can tell you the preferred data structure, but for what it’s worth it is our experience that for the volumetric applications we encounter in production, OpenVDB is almost always superior. @section sContribute How can I contribute to OpenVDB? If you have bug reports or ideas for improvements or new features, please contact us! If you want to contribute code, please see our License page. */ openvdb-13.0.0/doc/houdini.txt000066400000000000000000000466441510223237100162070ustar00rootroot00000000000000/** @page houdini Houdini Cookbook This cookbook provides code snippets that illustrate the use of some new tools that simplify the construction of operators in Houdini. It also shows how to write operators that use OpenVDB. @section sHoudiniContents Contents - @ref sUIConstruction - @ref sParmFactory - @ref sOpFactory - @ref sScopedInputLock - @ref sOpenVDBOperators - @ref sListOfIncomingGrids - @ref sIteratingOverGrids - @ref sProcessingTypedGrids @section sUIConstruction General operator construction This section gives usage examples for some general helper classes that aid in the construction of Houdini operators. These helper classes are independent of OpenVDB and can be used in the implementation of any type of operator. @subsection sParmFactory ParmFactory and ParmList The @hulink::ParmFactory ParmFactory@endlink provides a simplified interface to define the parameters of an operator. Invoking the @hulink::ParmFactory::get() get@endlink method on a @b ParmFactory produces a new @b PRM_Template describing a single parameter. For example, @code #include ... PRM_Template groupParm = houdini_utils::ParmFactory(PRM_STRING, "group", "Group") .setTooltip("Specify a subset of the input VDB grids to be processed.") .setDocumentation( "The subset of VDB grids to be processed" " (see [specifying volumes|/model/volumes#group] for details" " on selecting grids)") .setChoiceList(&houdini_utils::PrimGroupMenu) .get(); PRM_Template toleranceParm = houdini_utils::ParmFactory(PRM_FLT_J, "tolerance", "Pruning Tolerance") .setDefault(0.01) .setRange(PRM_RANGE_RESTRICTED, 0, PRM_RANGE_UI, 1) .get(); @endcode Note that, using a @b ParmFactory, one need only specify those attributes of a parameter (@b setDefaults, @b setTooltip, etc.) that have non-default values. By default, a parameter’s tooltip is used to describe the parameter on the Help page for its operator. More detailed documentation in Houdini’s wiki markup format can be added with @hulink::ParmFactory::setDocumentation() setDocumentation@endlink, as in the example above. Call @b setDocumentation with a null pointer or with an empty string to exclude a parameter from the Help page. @b ParmFactory objects may be added directly to a @hulink::ParmList ParmList@endlink, which among other things ensures that the list of templates is properly null-terminated. Typically, the @b ParmList is populated at the time the operator is registered, as in the following example: @code #include void newSopOperator(OP_OperatorTable* table) { houdini_utils::ParmList parms; // Define a string-valued group name pattern parameter and add it to the list. parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group") .setTooltip("Specify a subset of the input VDB grids to be processed.") .setChoiceList(&houdini_utils::PrimGroupMenu)); // Define a menu of verbosity levels. parms.add(houdini_utils::ParmFactory(PRM_ORD, "verbose", "Verbosity") .setDefault(PRMoneDefaults) .setChoiceListItems(PRM_CHOICELIST_SINGLE, { "quiet", "Quiet", // token, label "verbose", "Verbose", "verbose2", "More Verbose", })); // Define a menu from a dynamically-constructed list of items. { std::vector items; for (int i = 0; i < openvdb::NUM_GRID_CLASSES; ++i) { openvdb::GridClass cls = openvdb::GridClass(i); items.push_back(openvdb::GridBase::gridClassToString(cls)); // token items.push_back(openvdb::GridBase::gridClassToMenuName(cls)); // label } parms.add(houdini_utils::ParmFactory(PRM_ORD, "gridclass", "Grid Class") .setDefault(PRMzeroDefaults) .setChoiceListItems(PRM_CHOICELIST_SINGLE, items)); } ... } @endcode @subsection Switchers The @b ParmList provides a convenient way of defining switchers (tab menus): @code parms.beginSwitcher("switcher"); parms.addFolder("Tree Topology"); parms.add(houdini_utils::ParmFactory(PRM_HEADING, "nodes", "Nodes")); parms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "viewnodes", "View")); ... parms.addFolder("Isosurface"); parms.add(houdini_utils::ParmFactory(PRM_HEADING, "surfacing", "Surfacing")); parms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "extractmesh", "Extract Mesh")); ... parms.endSwitcher(); @endcode The above generates the following UI: @image html tabmenu.png Switchers can also be nested: @code parms.beginSwitcher("switcher"); parms.addFolder("A"); parms.beginSwitcher("nested_switcher"); parms.addFolder("1"); parms.addFolder("2"); parms.addFolder("3"); parms.endSwitcher(); parms.addFolder("B"); ... parms.endSwitcher(); @endcode @subsection Multi-Parms Multi-parms are dynamically-sized parameters that consist of a variable number of child instances. Each child instance is defined by a second @b ParmList that itself consists of multiple parameters. These parameters’ tokens must include a @c # character, which is typically placed at the end of the token. @code houdini_utils::ParmList parms; ... // Build the multi-parm's parameter list. houdini_utils::ParmList multiParms; multiParms.add(houdini_utils::ParmFactory(PRM_STRING, "gridname#", "Grid name") .setTooltip("Specify a name for this grid.")); ... // Create the multi-parm itself. parms.add(houdini_utils::ParmFactory(PRM_MULTITYPE_LIST, "gridlist", "Grids") .setMultiparms(multiParms) .setDefault(PRMoneDefaults)); ... @endcode The above generates the following UI: @image html multiparm.png A multi-parm’s parameters are accessed by iterating through each child instance: @code UT_String gridNameStr; for (int i = 1, N = evalInt("gridlist", 0, 0); i <= N; ++i) { evalStringInst("gridname#", &i, gridNameStr, 0, time); ... } @endcode Note that evaluating the multi-parm gives the number of child instances, and that the instances are numbered starting from one. @subsection sOpFactory OpFactory The @hulink::OpFactory OpFactory@endlink is used in conjunction with a @hulink::ParmList ParmList@endlink to register a new operator by adding it to the @b OP_OperatorTable. Among other things, the @b OpFactory ensures that the operator’s type name follows a consistent naming scheme, that its Help URL is set correctly and that its inputs are labeled. Continuing with the earlier @b newSopOperator example, @code #include void newSopOperator(OP_OperatorTable* table) { ... // Register this operator. houdini_utils::OpFactory(houdini_utils::OpPolicy(), "My SOP", MySOP::factory, parms, *table) .addInput("VDB grids to process") // input 0 .addOptionalInput("Reference geometry"); // input 1 } @endcode The first argument to the @b OpFactory constructor is an instance of the @hulink::OpPolicy OpPolicy@endlink class (or a subclass thereof). @b OpPolicy objects allow for customization of certain behaviors of the @b OpFactory. The base class specifies a policy for converting an English operator name like "My SOP", which appears in menus and other UI elements, into an operator type name. The default policy is simply to call @b UT_String::forceValidVariableName on the English name. If the policy does not specify the URL of a Help page, or if the @b OpFactory is constructed without an @b OpPolicy, then documentation for the operator in Houdini’s wiki markup format can be provided with @hulink::OpFactory::setDocumentation() setDocumentation@endlink. By default, documentation for the operator’s parameters is generated automatically and appended to the text provided with @b setDocumentation. When a particular @b OpPolicy is to be used to register multiple operators, it might be convenient to subclass @b OpFactory itself and provide a constructor that automatically initializes the base class with the desired policy. If an operator ever needs to be renamed, call @hulink::OpFactory::addAlias() OpFactory::addAlias@endlink with the old name. This will help to ensure that scene files in which the operator was saved with the old name can still be read: @code houdini_utils::OpFactory("My Renamed SOP", MySOP::factory, parms, *table) .addInput("VDB grids to process") .addAlias("My SOP"); // old name @endcode If the operator name changed as a result of an @b OpPolicy change, supply the old operator type name directly, with @hulink::OpFactory::addAliasVerbatim() addAliasVerbatim@endlink: @code houdini_utils::OpFactory(houdini_utils::MyNewOpPolicy(), "My SOP", MySOP::factory, parms, *table) .addAliasVerbatim("My_Old_SOP_Type"); // old operator type name @endcode Among other @b OpFactory features, @hulink::OpFactory::setObsoleteParms() OpFactory::setObsoleteParms@endlink accepts an additional @b ParmList of parameters that are no longer in use but that might still exist in older scene files: @code #include void newSopOperator(OP_OperatorTable* table) { // This boolean "draw" parameter has been replaced with a multi-state // "drawmode" parameter. houdini_utils::ParmList obsoleteParms; obsoleteParms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "draw", "Draw")); houdini_utils::ParmList parms; parms.add(houdini_utils::ParmFactory(PRM_ORD, "drawmode", "Draw") .setChoiceListItems(PRM_CHOICELIST_SINGLE, { "none", "Don't Draw", "wireframe", "Draw Wireframe", "shaded", "Draw Shaded", })); // Register this operator. houdini_utils::OpFactory("My SOP", MySOP::factory, parms, *table) .addInput("Input geometry") .setObsoleteParms(obsoleteParms); } @endcode Override @b OP_Node::resolveObsoleteParms to convert the values of obsolete parameters into values of current parameters where appropriate. @subsection sScopedInputLock ScopedInputLock A @hulink::ScopedInputLock ScopedInputLock@endlink locks the inputs to an operator and then automatically unlocks them when it (the lock object) goes out of scope, even if an exception is thrown. @code #include OP_ERROR MySOP::cookMySop(OP_Context& context) { try { houdini_utils::ScopedInputLock lock(*this, context); // // do cook work // } catch (std::exception& e) { addError(SOP_MESSAGE, e.what()); } return error(); } @endcode @section sOpenVDBOperators OpenVDB SOP construction OpenVDB SOPs are derived from the @hvdblink::SOP_NodeVDB SOP_NodeVDB@endlink base class which, among other things, adds guide geometry and node-specific info text. @code #include #include #include #include class SOP_DW_OpenVDBTemplate: public openvdb_houdini::SOP_NodeVDB { public: SOP_DW_OpenVDBTemplate(OP_Network*, const char* name, OP_Operator*); ~SOP_DW_OpenVDBTemplate() override {}; static OP_Node* factory(OP_Network*, const char* name, OP_Operator*); // Return true for a given input if the connector to the input // should be drawn dashed rather than solid. int isRefInput(unsigned idx) const override { return (idx == 1); } protected: OP_ERROR cookVDBSop(OP_Context&) override; bool updateParmsFlags() override; }; @endcode @subsection sListOfIncomingGrids Selecting grids A typical SOP will have at least one group name parameter for each of its inputs. These parameters should be defined as follows (note the use of spare data to specify the input): @code houdini_utils::ParmList parms; // Define a string-valued group name pattern parameter. parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group") .setTooltip("Specify a subset of the input VDB grids to be processed.") .setChoiceList(&houdini_utils::PrimGroupMenu)); // Define a group name parameter associated with this operator's second input. parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group") .setTooltip("Specify a subset of the input VDB grids to be processed.") .setChoiceList(&houdini_utils::PrimGroupMenu) .setSpareData(&SOP_Node::theSecondInput)); @endcode Associated with each parameter is a menu of primitive group names. Users can select one or more groups from the menu, or create new groups on the fly using Houdini’s \@attr=value syntax. For example, entering \@name="density*" as the group name creates a new group comprising all input primitives whose name begins with density. Entering \@vdb_value_type=float creates a new group of input grid primitives whose data type is @c float. Users may enter multiple space-separated group names or grouping expressions. @subsection sIteratingOverGrids Iterating over grids In @b cookMySOP, the string value of a group parameter is used to construct a @b GA_PrimitiveGroup. (SOP_NodeVDB provides a convenience method, @hvdblink::SOP_NodeVDB::matchGroup() SOP_NodeVDB::matchGroup@endlink, to simplify this step and to handle errors in a standard way.) The @b GA_PrimitiveGroup so constructed may be iterated over using either a @hvdblink::VdbPrimCIterator VdbPrimCIterator@endlink, for read-only access, or a @hvdblink::VdbPrimIterator VdbPrimIterator@endlink, for read/write access: @code OP_ERROR MySOP::cookVDBSOP(OP_Context& context) { try { houdini_utils::ScopedInputLock lock(*this, context); const fpreal time = context.getTime(); // This does a deep copy of native Houdini primitives // but only a shallow copy of VDB grids. duplicateSource(0, context); // Get the group of grids to process. UT_String groupStr; evalString(groupStr, "group", 0, time); const GA_PrimitiveGroup* group = matchGroup(*gdp, groupStr.toStdString()); // Get other UI parameters. int verbose = evalInt("verbose", 0, time); UT_AutoInterrupt progress("Processing VDB grids"); // For each VDB primitive in the selected group... for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) { if (progress.wasInterrupted()) { throw std::runtime_error("processing was interrupted"); } GU_PrimVDB* vdbPrim = *it; // Optionally get the primitive's name (or, if the name is empty, // the primitive's index). const UT_String gridName = it.getPrimitiveNameOrIndex(); // If this primitive's grid is shared with other primitives, make // a deep copy of it. If the grid is not going to be modified // in place (or when using GEOvdbProcessTypedGrid()--see below), // skip this step. vdbPrim->makeGridUnique(); openvdb_houdini::Grid& grid = vdbPrim->getGrid(); // Process the grid. // (Your code goes here.) // In cases where it is not possible to process the primitive's // grid in place, replace the grid with a new grid: // openvdb_houdini::GridPtr outputGrid = ...; // vdbPrim->setGrid(*outputGrid); } } catch (std::exception& e) { addError(SOP_MESSAGE, e.what()); } return error(); } @endcode @subsection sProcessingTypedGrids Processing grids of different types Recall that a @b Grid is a container for a transform, metadata and a @b Tree, and that the @b Tree holds voxel data of a specific type (@c bool, @c float, @c vec3s, etc.). Whenever possible, try to write generic grid processing code. That is, write code that can handle grids of more than one type (@c int, @c float and @c double, say, instead of just @c float) or, ideally, grids of arbitrary type. Writing generic code can be tricky, but convenience functions exist to make the job easier. Use @b GEOvdbProcessTypedGrid to call a method or methods on a primitive’s grid, regardless of its type: @code MyGridProcessor proc; // functor (see explanation below) // Call a method on the primitive's grid, regardless of the grid's type. // Note that by default, GEOvdbProcessTypedGrid() calls makeGridUnique() // on the primitive if it is non-const. GEOvdbProcessTypedGrid(*vdbPrim, proc); @endcode @b GEOvdbProcessTypedGrid accepts a primitive and a functor (an object for which the call operator, operator()(), is defined). The functor’s call operator must be templated on a single type (the grid type) and must accept a single argument (a reference to a grid of the template type). The operator’s return value is ignored, so it’s best to declare it @c void. The following is a simple example of a functor that satisfies these conditions: @code struct PruneOp { template void operator()(GridT& grid) const { grid.prune(); } }; @endcode @b PruneOp can call the @b prune method on a grid of any type, but it’s necessary to know the specific type, because @b prune takes an optional tolerance argument whose type is the type of the grid’s voxel values. (Note that grids also have a @b pruneGrid method that doesn’t require knowledge of the voxel value type.) Because a functor is an object, it can have member variables. This makes it possible for the functor to process more than one grid at a time, even though it gets called with only one grid. This example shows how one might compute the CSG union of two level set grids, A and B, of the same type: @code #include // for csgUnion() struct CSGUnionOp { // Pointer to the B grid // (non-const, because CSG operations modify both the A and B grids) openvdb_houdini::Grid* bGridBase; template void operator()(GridT& aGrid) const { // Cast the generic B grid pointer to point to a grid of // the same type as the A grid. if (GridT* bGrid = UTvdbGridCast(bGridBase)) { // Compute the union, storing the result in the A grid // and emptying the B grid. openvdb::tools::csgUnion(aGrid, *bGrid); } } }; OP_ERROR MySOP::cookVDBSop(OP_Context& context) { ... // Retrieve the A and B grids from primitives on the input detail(s) // (non-const, because CSG operations modify both the A and B grids). openvdb_houdini::Grid &aGrid = aPrim->getGrid(), &bGrid = bPrim->getGrid(); // CSG operations require the A and B grids to have the same type. if (aGrid.type() != bGrid.type()) { addError(SOP_MESSAGE, "grids have different types"); } else { CSGUnionOp proc; // Hand the functor a generic pointer to the B grid // (whose concrete type we don't know yet). proc.bGridBase = &bGrid; // Apply the CSG operation, overwriting grid A (and emptying grid B). if (!GEOvdbProcessTypedGrid(*aPrim, proc)) { addError(SOP_MESSAGE, "failed to compute CSG union"); } ... } } @endcode Certain operations might make sense only for grids with scalar or with vector voxel values. Variants of @b GEOvdbProcessTypedGrid exist to handle those cases. For example, @b GEOvdbProcessTypedGridScalar and @b GEOvdbProcessTypedGridVec3 invoke a functor only on grids of scalar or 3-vector types, respectively, and they return @c false for and ignore grids of all other types. */ openvdb-13.0.0/doc/img/000077500000000000000000000000001510223237100145455ustar00rootroot00000000000000openvdb-13.0.0/doc/img/banner.png000066400000000000000000040644461510223237100165420ustar00rootroot00000000000000‰PNG  IHDR#ȇ § pHYsÊ&ó?tEXtSoftwarewww.inkscape.org›î< IDATxœ´½Û–$9®%¶AšGd]º{ÎŒô“Ò?éû¤¥™9çTUF¸Ð°ÐÜ=2»µÆª<=ÜŒF‚ ˆ;Iù?ÿ�ÿË`€Á`ÿÖå¿E$¾@ÿ �°”µwYÞê>ß�GqÛ0 ‡À‰ÁT½�©ÿŽoÑÚ߬Û`Æ�Âlï‹\`Û»©ÑÎã%l+êÈ�ħÿ;¡ÁÈ&ž.þ¦†ކ"õq8†ãL1ÂÉ 7›lðš— |ʆx�C‡(é0Úöĸ4ù‘$ o#ñ“�öëéñ-0ˆiÞ„?q"ÃÛ«ö%ñ5¤õõ{ôñ‚Å󺇆§!ÀÅ_Ž ñåÇá |m®4ºXý@dÄÜjc™£&#a°þ7g¯8%|b$ŒÉösË€5@­€ÊoÀd�ð·$xC2„­îDd†Á$ ÞhLZ?ùñ6E�Î�õØ€ &ÆxÃ7@¦—Óà ä¤`0›Ž°5LˆM˜ l° ¶lL X,�¨:!6à K> àìÓºš98L/ƒaÀ0ë݇ùÕY‡ `â]Q+Ö·rîï.øä7ùáR˜ªÿ­šü—È2 Áô–c舄©AuÁÖ€�ï°uóñQ`�Šû©ø¼/|Þ÷e¸ŸŠïŸ'>>îøó¯üù×>?ïøü¼c©BM1æÄívÃ<Ìã­†¥Šs­(˜–Ôâ£À¹ü^õ;¨Ô_r�òA�²BóžùX‘Q»gæí,UÇ�ià=8o ˜hË©õöUMØT-àã<’žKHÅ ŒA&ˆ|ÖË”li�´¯&=²Ýk?ž�aé¤�5X›‹…Sƒ`A ùlÿæ‹�ØÂ‹»5\‡Oæf§í|…|@ƒ—”ܲÐG ¡Ÿ¸Èú¤õŸ€”\OÉÜ”�>®£D å�â“b}§¯gó¿s`\áÛZë¸ ek»ê¼^WÖ–úJ’„¹1>4U*u8I�òÊßJÇÃNÚùÕí¥Î�É/Û»Rø¦þH]{ˆ¸¼Q¯Ú>ïe©’qž›:kèóù÷æsø÷˜ÑçY˜¢˜Ãç5Õ”1¼ŽcG”åû#í¢Ôõáé ©™6!x‡à-ô°�«AoßÞ¿2NŒqâ]?ñÍ>]‘Yúc`ÝÄç…bAmAMq.ÿ¬XK`K K :`:RÏXëÄÒ…e'–žX!—!3tȉ1&Æ8„}#>_�ç1,¾ÃnÍ.´w=€:‡YÉ@ÎeÚaNsnãŽÛPŒù ÆüÅ;7üÏÿøŽÿùïaó6ñûoïøÛßÞq›Š! °OØú„ˆa¦,»>78¸ñ¡�Öô? � `C\¯ ƒ Í:dL`�9�9!c¸Ž+NÁ Ð5\oÔ¬¼ a£Ÿ3¸iª’ŸnžÚ9Ý Ý5 20Úd-÷æ€ÌápŽQs8}(žÔì p£ ºBŒ¿®· ÜV±%°Ó ' ÷ø^p;ñáe1€°w0ÊÞ3‰¶ÔBF�bVœÈ6½È\O]Ê÷ã9dÿt}7ô른èÊ�A†2¹©¼�ç5&œ¯�þ—–VÌÙÒµ5ño½þ]¦�©¹$´~¿ìêï�e€fí‡ÝÛ9é®w¸¢Ëq«nµ7I ׫ëF¥ËÂùáÖfµˆ´Y¢åªÍÙÅW!�˜Î]æÉ&FåCH?J§¥ŸÈ¤tVúfè—¢Ü LŸÈ�í&…ˆº¬˜|>°Nú/Œyà¸P[8׆ "ê~¦ Ì1!˜.À¼ŒˆbLç“°ð[Äü™¢˜s=èkég �N©zÕ¹½Øˆ~Òw†Ý÷Ão⣫Y�ð7…ß)xÈ®oÈE—â@YÁŠ®«”î²õçÒ?¶_ÓoׯJ,¸L×ôK"oKž}J=[~þ]1ú<.sgã·¨zJo­{ÕΖëßìȨ±Žq½ìÙýfãl€Å·mÏ“ŠšíÐç/ÂUÖqÓä[ýÓæ¡ üÄ÷WWó1>¹*/HP‘ø JwN‚j«ší0jyÆ.ÿÖ§ŒtÅÐëë_\mB<‚øŠ'ÌýIy§?»<|U²ZèÂaƒ/{±+8å0J(Íq¨ê:�ÿ”¨GU`1¶fé0w!²ƒ+¡óXèÝy$"�öY*I*N÷t(\9¯1\ç)B„Jå´)"%³•hG ÜYÛL&î\~Y·Âaà¼r>B5¡à’„¡Tk2÷þI¡ï¤q—m6áAFÌú£ü&ÜÃ0,H£ a¸J×5"31þ`?4cKaRn<¯[QA D¹�¬Ý.Ûó ¶MA#ÔW,ðтنÕ'ë2@†N*ÐYB4bîp‡–™<Ã6e q†ÆèLÖT Ë�æºV8ÏC«Ô ؀؄@!²rL�Æ|ô1L@ 6"àvŠÃxœÓÜ>Ââ$ŽÒz ¼¦fËÉe´ˆ®Ë�s  #Iuça/çòÂZá`¶â-ÊÒ˜£Øû†SP„E!kA—âÔ‰¥ "–k§Ë �Š@¦à¸ ÜTðf6¦›îwèyÂL°Ô|¢P,]iT¸cÜ•ÿeÀZ†ó¬9—´ÜŒp…m¿Ëh²ÍÚ�ª>åÈ×f0‘W:¿,‡c*}ˆç­Î«áF�(Ã[?ø½9.F‹ÏË�«.ë¾Ôõ¬�‡ßæóé™áPNpž)_JW›-(ðÌyú£ëI±n<ÈðËe˜å7ÐèäY¿»|~¦¯<ˆÖd讈>êO†ø'®Ç¾uX*Èò/Uþ¼Eëß?£lökW’‹&ÿyŸ%zýÿJ?ZMRw^Ãöâ>Éè'ßø×®Æ£S§&íP» í5 iD΋ìãðÇõþ:ûAç¯ôüð õ„÷_Çf:9BïÙÛ®$%Gã“�´½íN+õ¤tÞtJÎÊðÈ튮; _P²”†ñø²ë�)�t«±ø\ �€_J¯ y…éI•JÍU%Â!VNAÊ;ª€bBs5‘á…5°ÃÀÄ„áðd Q¸RRýWEèjç: v`ÈÄ1'¾Ü?pÇw SÜô£^¬tDPFŠËóHTQõ¤]® ¬“{^—z`@W$08 é,”ÐwÆœn.;D‹ƒ \�A¥‰™Ñ¹FƒBB/—‹’ýÔ5°á»x–øXŒ6&N�!˜1§©ó||*þúTLn7ÅûÝéâ‚ÐåЦ=@‚T« ‘¥QK›VL*âÆñÏòþ‘x ×o»(çït0)My`)L=8›Þð «x™¸£©ý Ô Ä"ÞΈ‰?ÄõÅHdÁV¿�€ßÛ&“K>–üâI`€Cð(Wt“ü‡u dXd !—t� Þöà@®J@‘ù"WŸÌ²iù\1@¼y�1èRªŽ$°.²³å8Ü™·ÕË|7©ÙߊÙÞiecÔ�ŸŒEd€­”4®äÈç„nd ŒÉ ‹Dá KY\þ.YÇhP ÃF\Y_Šu.X8»Mµ2”L‹² ˜‘ @c@Ç&`®p ÷³»‚ä i©0É1¶ñ'J©%›^¾W9ÃÍ rNŒs¦Æ› -ø“`™Ìò ÀZË•4õ@†Dfž„Bf�È“ìˆ7¡ka­÷Sð¡‚ÏÕ�öž±wªá\À¹€»ÎÓ3„>ï ç–Fî®§Â@'¿Bh,D`eÆS×ËÒpYæ†=;b àêô·4Ö3Ãh{Fù�4Z æ�¤–Í”>š&?6Ĭò|iæŠCƒí‰’tyæ}ÑR–ºì¶”,[û@9)ú½­•˽çÙ,ÏÔ‰æð%.ôˆÀKâ§Æ£×�mP!|iùv8kÌJ~å€ìrêz»é+‚ Ã/`ЧÁ«ˆ÷W¾|/¡ýâIsª^ŸI£/ô·þ¤´�çø}TÔ/„ƒ¬Vu\…LÇYèö*´Dgd§¯çtúCR&òç®PáúïÄ‹ÔóàŽD£Óô-lL¼p[¤°Ã.½�Öõ¦f=t7dM¶qéFÞê2ûZGµþcºì}zöû«ë™‰Ë«ÁÁguü ø Zm÷·7ŸTñ8ú唺¢;�:xþü±K­?�ïø{� ª Ü(…H]È„ŒyÔù-øK'élñÂw�÷ÄèîãéÁŽh7Û†˜ƒÖT4‹C[!—KÜ>3Ls¹™±ÂSÌAήj§áó®øþá+ ooÞÞÞñy¿†C&nv`báÝ>a"æ–ì·£©ºÝ©©Ë Ë¿8—FPÂu ¥ZÒ�½®Y &Ü$ž®Ã…~àÎÙÊ®ÖNLº¤Æ³ Ý)%²î€mòï2_-¢"®«Žá2]-;êã´ øÔ�eÓõ‘SðyŸw¯{ uç[8x"¡™¤R‰‹ÌòŒïI-6�A™LdOâr¾‘Ï À <Ì ¨A‚ŠB�ÅõŽØz2�ú™ò�–¤#,`YCÍ:þ€m2‹œ— @–¹sQ4;–ú ‚mb­q€pšŠ9žý#i÷ D3õH Ú<�.×IZtIskhÎO:7‹Ã©Y$71ðÐt§'ý¦¾¢á„§CÞW©Oh<ÔšN»gñóo«Šã;¹¼\²sS[~3èàóÏaÉÀ@!ÙŽªlzy®ÚeÞöU=áçA—�r±À·0–Ì]³?)ßcP¸¢(›TÀù·ùb>7êkz`áçQŽf®hmü­•Ú~QIßêØ’[‚‘‹f=9NUpŒà_ìOø,L(Ÿ$Ý p~×&!Xæ•3Iò® ŸŸgÆ|…ó섬B¼¯Ë‹|"V,±’É™ƒ=,–xØÃ]j±ñ˜»©LÄ�8¯dµˆäS€$*SÜÇÕ‚6û {Mˆe�¢¹m6íèQ'ý¡pmŽa¡sJ£Í¨±ùÏønw/§Ø�2ÆU­ß>HPq½„þšˆh¬ +ÿE »ÓWð~aaºLq~JÜ5ª�¾%è²Ûo©œø˜Ëð¤ÎtöI)ª–³2P01;M\mó>îWclììö¹ÞcåI¶Ýk\%?=ø`/ÛÚ†Ò$ú³g—ü°Ì%0𢎟º®õHn<²{'æ�—bÈÉÅ(x2q.mÒ¨ “ËCw»×Õˆas‚^ûùä}iUå›7iÔà[’‰nÇÛîßxb4Xœàå±Êwè0ºè†E°jŒ’×(duK6XÒÀ¢ÀŒ1£B*ˆD&áT°¬ªY}w�'ba¨Dà‘¼@\‘��{ÿ-™RÑý&ÜÁráIÁU£$bX—À@WŒÄVB½Lofáô G2úÀï¨ Á†‹ø;Ì•lŒ}Ø–qI½#‚X¹�äc’Ì—iðÂï`ÕPƒg <ñïQϤa1…L‡±E’³¿B#©Íƒ>Çi\ ƒœF +[ÕÑl‡Ú�‰ ²3G=ã ‘A³Îå‡[µ˜F–û3 r@dbÚ‰�3³ƒ2XêªqEÄÆ”HЈaLÁœÃ3ô…¼«ãÖ"€Áìx¤“œÁ�qØ9ƒ5–Â9\{�qª Xka�g8õ=80æô ¹XòjÓ`Ó c23(àÁŒ “PèÎsás.àûŠL¼4ÄÃñ¯XÌþ�,¡Ó—)/ ÃW[„à�ÉÌÿ_Ö²úûǼÞû ÜO):á•Æ•÷.bÊ9}Ý.ˆ¼,QÛ~»Á¨ ¬ÜJ¨ÖÆËÔô2!诰޶=PÉ­ºW+=¸*/ ØDÁÃ+Yø:0€”ÁÒ0oئ\e/pu#±A®f³ûŸ:öm—Ë–Lë lRªÒC5 O¯ƒ2ÿÜ•cúD?ÙK½º^è$í—ïã�|˜N>‚UzmS,QÎn:+@àŽ^ã¶ŽFLS¹,ð þ!žÝìtª€,”“`@!ø¸ÿù—â?ÿT|Ü ï¿ø†wÜoÀyÞæ�·Ûoö�_ùÊ-‡8¾.;�}t8F$xH$?(îK7g(KµÉí™0fn„¶mPh¸õ}„rÍs:ÿ-Vœî€Ðk¦%v*/à5 Z…­9T:†™ÍäøûX˜Þ¦Ÿ'ðq�mcD1öA' PüCÊ©/tàǶH*žê¶óyŽ}ˆ|5Jz�øA£×  °¾w@Â{[êz¹‹@Z§@UFfÜ:¤Éí ¤…QÄé8ÍÄa'¸Ø2ÏPNG£e³" 7œ@´1Â)Iå̓H§¥Ï€é´ƒ¥Ë·:O…ž±’e!¶êa?œÖÝú&«¹jœwÁE÷w8é˜$/òùa¹‚ÆéŸt–‰ùóJûï¶¢¨/`†¡Ù× =º¦ú»a»Dæ¿4ôx©¡Ê`»íC}´¯èߊŠ'•~�Jª‚~+2GH[ea‡<ñ­ÜÇ`tœ[ImîòPI•] <ÊÎnkÀJkºí3�šs'q�iop|ÊqßUvö·j¬ DÎ@Àõ ôàÛ�E,eŒó÷ ûçºã\Ÿ±p›7¼Í = ºb´„ã«to#·ï™ÙÊ2Íõ)'äö À ZÚü)Öh”„Á}ó±lµzà•øUû+øüÁ“g°È l³Y0žÙPrwƒ'¿·]*†Œå‘Œb…Gë+ß%_|è8eÕ>ùNcAm¨�»7¤3ŒWúiâ��[¦îWH¶Ö¤9aÞVùiØà¶H5§bÂ̾šgƒ ���ÍY˜pcŸlMU�gÏúß;UÕ«�Ïä;ûL¾tºw¶é ýs…éúÞµþëu�ñÉu€„lƳ˛½Ú>Ù�ø¼YyjÙ^ƒ Ùúv)óSQjþÔùŠù{ ¸ÒYªa'eÁª¡gæ·¹¸µÅÌåŒÆõ º•CòßE·.`ö Joq'·æü7¢–0–ÐxsôZûŠA9¬rß6WÎûËo Ïä9mEÎeÎSk÷Z_i眚åj.•¥C>ÏTHgCdx@dù·mKËÉŸ¼³¦ã”¾ 2¨Àçù‰Lý LÌìçÊæ¼çýÑ["…+A¨Oçyñ± ,_çT›{ýWà/®¹¼/õ>é!™¨µþj?·˜º‘xåg p¯R±0"áÙ; ÁðùC®Ku‘Td¶Ýo8¸À—NcM5ñ–°ŒÁøoUÒZMƒbS¤�uçÞv»Mr4õ&ù êÇõw¬4*&H$4Ü·óLÀ@·ê|R¤ÏCû$úC^2²^Ùø_G®IÐÎpºïesZ B�ô¥o„¡*íA�À Éz%˜sá] ™-±íKI¼„¡´‚“L2!É¿ˆ[‡5GV®u²ˆ æ}Fˆ(%¿G at=ňCÌ|É™¡–ôFÝÖÒ‘˜…À ©Dã0«{¤¶Èâ'¤‹Ëxy€Yd–¹Â.‘Áîð̤×X¦èg |�øNv±6¸3‹[, Ô–Cü¾b`ø�vtêo{çGPr²Àu-ø¡Ém�"j—�a8qåƒ5£Íç˜ÃŒ¾3QAmµ== \ìös-œç‰ï'ð§Þð} >ï§ãÐP[í¨à\†{ËÜcPB#‹ÏyRä€ÄJ µÆ¡,8‰U`À·(çþRÁ2&‘oì+Š_;‹â  ƒ¥¹YKùýP*ÊPÑ ô¬z�¯,‚Y3Z¢]«údÿú÷Ç•AOðî�‚~=Ðú�äõF¹�e¿¾®A‰‡ë‰pÝW¹÷ƒÖkr^žtºîŽ6¹|ÿ“í=ÅYã�ãòÏÔßÞÊàÀë!ø:(ðõ“gµõ7š*êýk6ÕÊ IDAT–ñW0}}ý€æþÅ«½¯¯kÂÎ>Vr%xCÒ£D >(¬ËöîÖ3Ããзªw…‰õf;[ °:þz\ôèìI ÕÓ+ÇÏvýZ«iÃ1•º()|?ïLØr)¶ŠvU&Gd’ Ü2ˆd ÓØBˆ°Ê–”‘×ô- §M|¬‰?î#övÀÎÃWšâ»þ'>m@Í0�ªm؄ړÆ0Ïš?Oœkø6†ç©á4Ų8S x³¤SÊWGò°ªkötßÕTZ2Wíg�KlÃXßakPgìÎêvÝ™I]L˜  0)÷\‚Ó[ø8�ãÓ°¦ú¡Åb8Äý2 t€Iíw*5“—$꾕�*,âÓ| ýÌŠ°Yl<ÿhõ‘úÀÀ³‰+0°_MØõÕ!«S¹r”4®Iïþ©U3ž01âàb¢Þ8˜�„ÝRIÏ9ýí €˜÷3÷áb66+`6—�XwźkèÂÌÞ÷ä?{ƒtÇyHdŒ‘C¥®Þïô¡D{P€²Ú@ ’j4uÙ¾…&3ê3‡º†ÀêSg\qo<Ø/”ýÖWüjéÐh´®-Ã?ørwƒŠU=ËX½°÷$ž^¯ó(Cm‹\ºqíÓèBÚø¾`¦SŸZ ’´$£JÛ>i¤˜ƒ]'À¦Ë[k½ïÅ .<óÐà6…ÎÃL¬¹ Ê7‘S5æ@X/Ñþ¨$Ãf[Á ‹s˜�\›¾Ý™DÕ·Òǘ8,[¸/`bbÊŒ6ì¥ÓU¬Î÷}á�e@`ÈDÓ~â‡Á·§]æö=å(ç5ýú©qœblc悘HÑ”%5Ö+ÉÓGlµ«Æt_¤°Ø¯:غ y£á1nŠ_ÙäLƒÛe¥Ô½Þ¨H9ý›íšõ ²_õÞcõ›8Ñf;SO§œ˜S¾{ípNHò߬í£H)¢î«øa©@ `Úþû•^ÿpÛ.¯ï¾úÝg«ëUYiÏôé >öcø^_G»Rhp¢%^¯Mì�ìZÖ‹ŒF &a+ïEw�2=0@îOFµeprÓë–x1µëXn?­úص�àlXöwúÞ�à²âBÁXwx‚Z‡·÷Oêž»=G:„¤îe·…‹ö>Æ×Òd¾‚Å2K™“1’£ÐºdòQÑáÕÑhµŠ€LªÞG®Ä辑HjjŽojK!tfÁ´Ù—†ÇÀÀ.ú5Ä�Q›í9W ÇÙë \C€EFÖûœs‰ü•�ÂÊɳ|ß…&�Ôn|Äzå¾T:ðÀèÙK<û@òüئöî&´.ÌØ• M©/öÀ€´þ°~Þãr]É=øÇ0èPŒÜÃÞƒ9¾ Ü“5Wà�X­èÊKäxø'¬n?s†a6=j ¬ èùœ[átãq™`Á|ïBXœ#f¸µý@ \:"o’ŠU.Ùœ�¡˜a|¤!"±tu¸uÒP× ™Ý“Æ�“Ãi†¡ŠAt­Ê®ƒ „ég×r³�€UÛˆef‘Æö6÷…ŒÀÀý<ñy©ác î÷÷Ž{ÃÀ±�ûRÇql#T�×MÈ" �+Úr¯µüxÑ8 æãO¶«Y Yh­»bí»ÁP¼9�Šn„@ris tCB°`âKc+ËÊ6݇<rÜÛotÔ¾ Adf `é�[p¤ã�¸M9³3»Í?µÉ¢ý²­ìc™ì‹°·Tü W›qvé_ñ «òÓ›³ë“ìSw¨}¸¼�N\Î9)š‘ë{"ŽºxqÖ4€�³>�»æùÖ•'p{;×~¼pÔ^�ö´ˆÈVfÙZMéf¿QÀ$Ã%.ß²‡1{u‘n/wÉO­‚óU_S~¢…­€]ÊGã×­'ŸngõäÙÃn$Ú`Í¢—6~™óÃN<@±½cA#WízbÒvk®Ï›�`§Ögtôêz@�>^œ7Rmwcµ½õ`Úä¿„¤ˆ={êÉHgêÝ$åÞ ¶ü§nìAÐxÖ²RKC|Ò!”åŒë÷ Ôb˜û{‡��™ìä>µRÀeðFkáÀê[<�æ„`Xò‹�Õbð â¹\7ÖX}œ²&œ§f™óv`~Hë] ëã„|; ÷ ½O¬;ð›Ýðij C+yŸEB@x1ãWŒ ×ÛİD=Á‚%‡Ë°HdÁ€o%Ôqåø6u=Õ¡›9e‘ëñ<3ªã�&¥‘�`ÃoW on+£MÔšq#�OÁ=VFǸ߼¼Ž,†%‘CCy¾€Áƒ¶œø"¥�ß6¾Ûeãù£Í˜ˆMÀ&Lç…Ó–,RKeû¯ ’LåiÛÛ8ñ‡.©ãÌóª,·®4Ò4É9“Zàñg=xÓW€Jm6AŽGoÍáß‘¹\ zqä‰dUv¼åY X~Ðö¹|¥+“¾Ò~±Qv½háJ�É0äׄ×8V‘yŠÀOêó}¥@eãkÏÞO¢+U$§\Ôå:t¬½Ú—#mN€‹-¼ºN,\‘º˜ãÔÛ"Œ©‹[Àhœ;’sv[õ[,"û íY’0aMaxýFâÑ­Rzw ΰ "–Á¦=Å{E«�úø®·�JÍ þì,ßê_H§ó>¥‚Òª ¾ô¤‚1¦û Ì`ª|‰~YI6¯7‚Êa1(Ž÷7¼G�s§qÆÜVä§ æü$o�ð]1ܦà6˜ (8ÍWƒù¡ÈLF”Ìñåª-ãj®d7mî_¦�n,ÎÒ/šcHÁ <Ç+�³øPå‹¢ýf×`¸Ò¦Æ(/4×çŒTá¦+ù ô—g�B¾GŸõ dp€2†Ô'`š¥d€7[²ã^A­T©9FªIdÁ§x}[ÒqÒQCr’|ÞoÏDR) ™˜�~Àű�œ‘I‘6¸O/bɪom4w‰÷.õYþ;ör›VðüS+®m=+wï¾gðîב„„î•Z{ùò~9ç5"­q#�À…Hg¼Ðb’<ù“=Y%P[Õ¹r È&ÜŸ_�¸írKúDnQ«­ð“>¿ºoRB2qÌÁúûV-^ÏÕ �IaÃ-ê÷Sm»W¯–ÀáäÙ‚#ÁHºSåzUFû…Ne¬ÉÖ¾x%Öþ¯¸)æç˜ŒªQ¦sK¤ÛÈ?ùÿàoi×6_xIÓ͵Þ#ø½N fUÕìAÉv[6}ñ©æ°¯w]�†o·Ø©ª«oyDœÇY²ÍéUm�!oÔm¤ò#dKÚæX|¢ã¹�QwŠoðÆÌ®0Œ¡SÃáN'±øv6àAmn|šÅž©t©\ßVኵŠB1pÆòsy–ì`Ð5¡KcÕ€ Îåå³ÕZ`@2‡‚;Ýœ—9lÆ¥¬]Y¾FÁCýË`@<1)”l¹’æœùkà’†‚HqRŽXf¹‘ãK9§ ðÀ´u.ÜõLeÚ³ïQøX®ÔÜt-ÅýäáÃÀç8ÏÓ3ùá+ H8#Ã�þ�YQÆ€ù®Ô¼j¼×àÁˆe-K,Œv°.ΣgŒ�wÈ‹$úŠø¤�Ec©ünFþ½X·@a²�Šо%ûY†Í+¹åН;äýMÙ ,(þÍ>T@`‡e¿®ÊA<5<`5ëÞÖÛûÞÉ®Äv9“]l5öv¾V_®×c»ÏEÙÖE‘ÛÅo× ªÄ,¸ÈÛlȶwþµë¹<Þï=—×_iDu]uyòWüÚU—pû}€xù14×±§ÜÛn¾¸~®­*ò‚'/öàÐW-ì²ôŠ·AÔÝ�|?¤ =6/_µ'¸h7W½O黸ÏÞÊ~e…¶�Ç“·þ™kÌpA½¹·½J³“KÛž|5×$_¸:D®ä¶›ôö2Ù êÏ÷™¿DÓ&-÷²éJ@ñÖ+L^¾ì•�?U;¤2E h×Àý»á³Æ{Iµy`@1À w€x–8·ðL™š¶™7®â��ÛÛ ·÷�Û}âc)î÷;ÆçäC s`á†9pÊÂÐЗ@sTJ¯_dŒkJg–– ¬á�‚ÿftôû6IÚ-c[¡Ë©E¶-áèú~èj�ÒÏú¤êúošmÜZ†»bÛ[ÝE¿D¶º”ÑÂÀ€†ÓY�ûÜWhéAÓ?M~Xhê×^‡*»Ð‘…)\ý1�Ör¥r£z¬xPÜb*’h\÷P˜�Mˆ#Dq±Öö¹„™ç äøú™UçYÁ�U¨Æw`±EMÛbHBkøy ´O¼mŽÅ D×Ç8&pþ™k`ˆogBZÉí}¦ÀæòóÃFÀláp_’[™ú6œŠûB¬¢õõ…Èí„HO[¡ÑE\†~•ÿNSgS Î( ˜8’jqàkêµ¥?vJõ€‚F–O¨iÉhÃi"ùcÀê牕ÎÛy¾f[-HkmÁSÉŽL¾�ËŒ*¿¸Ú@É=í]×ɹíUÓ7®’C€ÜÍ$ç:eVƒëñ-Ëïé%ú[]9ž2ãZÖ/§JKg'�÷}¾–Î2˜˜õ·Ã�3ÆÄœ3bL±[ÐÀ[!“M1†?œØûúí×oøý÷oøó¯?ñçŸæ9/|b YP¬_†)‚ `ˆâà6€·)x{¸ÍR«Aï+¶0QHð9Ñ6Æ1ïmCXé—[�ËÒ3‰˜Ÿà­@Ôýz&~èñ€±…²Ä†û jUYIï�Ûb  Øœu—߸ܿ^Ïî=–ñ/ŠÃö—ß×6®Ÿë³+¼I}/¯£–ÍÇ�ÍðàºTÌIÃ�ÀNhÕx<Óšˆ› îmê�€rµm„R�ø§;±sMÞ‹ò�çCìýrÅzgÂZ¯*-Ëv|Hƾ÷®"ò˜è°~àH;®/Ó¸ú× J¹É¾o½¾à!d›—­+…_wœ}qŽÓ|´RŒ7Qën PmìXa–W}æÜµ`Ö‘=:]¯ÓÂ6æ[Ùý—2�ø½æÈmøi´`l‰žÈYïÎà�î‚¡ñ£k�¥õ‹ï.3VïôçÖ~׊�rD \ c<]1@x8úÕ@p]È­�ÈÈa�_k<†XH¦›4Â/3éc+¡1Æd� V6€™D¡Hr»•àÓrLÏЖ c° Ãe¾„ÕÓÕÓ÷úÔ…µ&T%«Cd´G`@{²¾áÆ®ÄÊ1œf8*FŸ‚ͳډà¶¢Ë]ŽÁ±‘ XBYð ¥P6„"d@Å|É7ç�ˆ¯ÀˆÀ€ÄAeß¶h‚ÀŒâÌ€O5|®rt¯€¿‚‘eɽ\Ý83Üï¾EЧ*îqÏWTÆ>`yŸYRe|ìJIÑIô3ðÕ*Û�� P†Òæ¸ïíÄ·ÆŠ4�Oª~Ö2�´ÎèËû·À@Sj<‹,hs“q%ÆRZÙ^††e¨^ꆕœrÞÕÜvñŽeCíõï 8”’ ¼*×ß(YÞûñ:{½ø�Aõ•óú‹&ÚFAð¨ó°ìŽŸ|�N‰�4è,äžÅ|»:_û½Ì´yª˜eÍ%C{Ÿ.ÿîx}…¨'z T†Ë³zÒ³Â]ÀKJÌF ךv�誠>o»éwWýÈz»;¼Uj÷aly�Fàa\·º¤ è+*_W¶�YºP›·)ß,]j`o¿6½´)Ößû‘o¥bÖiÓêaö{€_Å‹vÈ~bâþô%Û·q¬²‡)D/H‘G \ ýD»õ;É �M¾ ”6ˆËø�žHCõw¯÷J¯eíxÎí: ¨³ÕzûÜ+'™Ëóu†ÍHlÙ~.ã\/:e`bàÀûÏ.ˆ­�§£}ùJNõügz3l¹þdp]ïvÞ߀û÷…�óŸŸo�ï't¼a͉¿æ�¿æ¦œîˆ`p_êˆdH4j6`:`ÜRÈÐv¡ömtü7bÅû7ãÓÕáXvg¥gÇ"2ÄË4oº ¬î�ÉÔ»!‹NŠÖ~Ò¬�³Rß½L³V%á?y®BîËïåxÇø›˜gÔJ2†ï†ŸÃn€{tâz¥f‚9ý[,‚¹¥ŽgbŽf‡H&–¤jžê (<½œ�‚vž–À±ì‰>¥S®ÅUH>j�m»�1K›¤'X�öL{_c̘Ãp†cææP 9áG�F#‹N_‘=‡¿ÇUÌî¯ÕõáÙX]gVïonHW’‹Ž>è‡OQØ=%±‚"WRà*k»¬ˆßÔÊ1_«v“—�ʨ¨ÏÊHŽ WùÚEÏË X³�H¿µj—:|Ñ4¶rãv qÒCÿûd)h{½åNrLµ!‰§Ü²hÓ?Ú[ÔË~‹§R}JVïâµëQç‹!gJirwae1Nfé'�ÉÉŠBŒàÓ~D$«ÍéÛO«vb­Ö/«ñÔ¬gb8Ž¿ürà¿üý7ü×ÿöwü?ÿ÷ÂÇÿ ® âhÂ@‚¦˜Ž�÷ÛÀ·÷‰oïïïÇ Xëçù�?þì/ʉmuE¢1ûªS¥ÿ´áñ±ñ»ýÓÆ¾ýMôû¶ÊÁ»Åý‰p6Ôƒ¨p™G†Ýyù�'º�äÅ16é!3ÖªÀ5|ˆœ3Moó7ÕW…‘w˜¥¾ÉäÊ¢ãòŸÖ¶n-‘•¤ND |[d hg[eäÿC5ã»LW ŒâÅ�õÀuÓ{ÙxÊÍ€°ùÕR¶r’ò›÷ú'ÊÚBøKX‡\>:‰¾æ–"O±å_IÏ.Iìö‚WÏ*qÑm©ëÇÚ¨Èöž¿y-�ìÏóëë ûOjñ÷k¹ã¥;—…^{˜J@9OJ9ØßW˜®$Â$²„ãI†•ꀧ†ú«V•Î4y,íURÉrx†ÞÂÖD+×ál%/©j�æLs˜÷þðL‘˜*Ó¾ÄÙni}ÝÈ•´o–³ÊÀ¨áîŠÙêº�#»G'zÏИSÇM¾/ÜYrä�A7YÍåË´ð÷ý¹×1J\^¦VµQŽt»šA ÷ëxï>“ËôÞ‚‚=0.ß�û}ð¦î†í¬ÂqÃÓ¨ @õ�ÙéV‡&w&˜Ê‘¡²úÆ3.루¥¸sÎ3ËÈ.ûäWV™o¤˜SqD`@¦eVŠ ³f øœp‡îL:Yœ‘ý²a �Üïþ~7Ü?ïP��tÔ>Ÿ+œâ° Hd`H)í"ÀðmŒNSðP)@rž˜¶À@â™ãÍñ—¢Ï «!†!šcëhÌ!ð̶ܣ2ðl±餶#*:6U =p3rÌʶ*>OÅý¾Ê8 <{&bÛŸœ'pkÀ©žñt_aˆs)¿I-UŽÿÖ² &,MíNufQ¡!cLòl�2LJ‘+:´à·eϱàq̬³Âãâ�–kFXMÝÈ)gw¹µÉ®Žë†‡ƒ¿H7)ñôé6Eì§ÇÖJq—ö<�'£éï×w]Ňùèšõ¾•¶†ëvïÖ ˜mòªáª+’Ïø}µ}Ë#üyÅlO¥×O\M·r�˜€Í=@˜Ÿš‚¶ÃÈ1¼ê‘ ,lûŸ ü¯º’•ZÒÿ:×y=ÒÏõúº›‚}oËV·áÚð‹«aYžÍ‰Ÿ¿6cýªíPmë:æÖžÏ“�‡u=ú£W84»¬õg/šœØi¹—æd ª«Õ]·ù_s}5¸ÒÆŸY`Ñ�Æ×~¾¾ëó _)í¤•¥ˆÅNz@àE»�|ètÄù&b?€\¶¯‡¥› Ãç!‡‡:ÉsØ_ðU—‚å.txÄÊ��…a'ŠaêȱÍâL/p…à‚É‚�ÈÂÛmâýøó¾ ŸŠÏϬqøgNüy»áÏÛ;c…;ÓÉ‘ÛZšÀtƒf P3œ&8 8a8aXXµwuhV ˆkùi :¡ bbÅ*<†6Eêð�ØþB`<;KŽ”…¤Í¦7|›œ�³Ö‹5›ƒ+ò …å:×Ùôøc‹–Ûà›ð<.‘ ÂÃÝ µUR­bØÈ ü(î5’ÄÚÖ�M§ÚEî­é¦Fâ­;Iší¨)Ý_§wó~ªjêîªå€ÎCuµ¶ÈIM)wÇh®BÕèQ$ìË0§ažîüŸ81d%-Pï‚Hnòàót-(ç¤�‘Û QwæJãž%ïÔŠ”‘Î]P/�ß/´µú—<€:­û!µHÝ¿ÒÞAèÂȕԭ´·$€Ï>&�•î[ÁÊé`�6˜º¿éË”‚ÍÚ{Uõƾ­ÌÚß�Ø{%Ý/(Ní­AÿX(Ë<¶Ð�ß?rú'2$�ºQ­ç*kÆ'’SµE,�zTøSl×è21ÇQçRjŒqìæÁ¦;Ôž¢'x»áo¿¿ã¿þÛïøßÿ·ÃçÿŽÿ¡w˜Z¹XþÎ1g¬ð À´…oCðÛû~ûí ¿ÿþŽ_ÃÛ/Žðùù>¾‡÷ñóCpçäÉeBå¤é-Wv½€ôÓ ’Òt#kë+rõÀ58 #ð#ºÕG¹Î�æÌaÁK#\#…RÒƒrœ”GFdÏï”e9ö©©Ø^/çì!÷’�–=Û-Y…øÎÆV!W!@Hÿá§0ÒŽa‚ôv9))‡ŒßVÏ"�Ûq<Ìjå?qNA&$f‚k§üàzÆ%®/‘ãè¥Lç2׎âòýÕçÚæ+ ŸK�~©‰´AÚf½}] �Ê–‚*f �ŠæÎöû|¤ƒ…‡¶ö=U±pa‘ÎýÍ»p˜e8ãJk2Äx%¾ÏÆ@áªÊ< G“2Él»b$ R ù">è‚&WQqñH’�`õÕŽÏ£ø¦€MÅ“RÎÛU‰œíWN¢x•Ç›—U2)Jr]œ#r�_YëK0…仸Ìàÿ6¶]u ÜÙ[ÛËU𥂬cÿ;™8á²·ùG |¾;:Ýt58§Dg;?‚!a*û^üMˆ¤ oÛót>?k߉¾(»1fP¹�0£X6Ã郰sÁš�+ 2@¡ç Œa˜K±¦zæüÜá‹¡j‚ß±�»g²{Ð2°,êç1Ìã†y¸¢$"P=ñy_±ü8Œ‹XžÜ&n ©Ä!F‰†rBl¹1ܘzÁÚ úèØxJwàꔚ–’ãW˜õy`ÀŽ9®4ð2L£Z"¸†·ðf‡�ÈL3ÜOÃ}!VT?ÍÄ$¨PœÂËUà o5œ†:PM‘˸]GÓ\e°´ ¶4R‚�ùj àéaA–ñŒ¦ZÁPJ4)– ùÅW1°”6ÍᯠƒŸŽº2�ŠÆÒj÷YÛÆùOùPÎ5#-7þ× ž4¬mÿìò�¤c­›%§³|ËÎKüØþýìÚà}UŽmeš½LUUä`5|„|¿ví"x¿R<�«ß·í+ùÊ×Þ|LQÙî>sô;‰öû^Ó³à@I†.³ã.i� í¥í'�|ý[¾~v!‰§×«€L6ç M¦×:Pt_Òô£§ãèežÕêr¶ãP굇�|T�ëý/`¸Ü\9Àú\ êºl•ëó1žY«·Ro6êÂU_× ²Ó“]»üêÚ¦ˆmD¶á©«éw½ ê7<ŠÏ/¸{^ïOÀ…-ÿ}UÙåï§²w‡�×#àß�/?ÂP:À–mzU¶Zí×öò첡’Ô®0]ïït‘gè¨gÐ×klµÑvlÝã’o¥Óz`ŒÅ“‰é) vBìî™æXð úH%0¤3ÃDaãIJ;† ÜxRˆk}àþ1�ãÆmâ»Ýð‡½á‚!'¸•Pž&e’�è„o5é�o�Žón˜ú–)ý*œhŠ�ižþãT“¤vÐì…p;¥¦«‘&\s"VoŽf_»®£·Òñ¢·tÓ7l�Qå€pv‰á\ž�Ñõ«Óà™³Ý6 Ü‹¤/HK¹'˜P£Unƒc¾-$³öeI¬ð6R7 ü¦í/’çqå�½´ßÓŽ¯ÝÚ�øcòÌjË$_1p‡zZ«WcÛ¤–éžÙïºkìû‘| ñëœÇÝ¡ dø*…©Àðäf²0°0Cßf\=2Há3 ˜ø�ØwåÊYŽ™ëÏjžpãü¿‚2µ¥èà45Ú*ú”W—NXrÑ_kÎùÆm(ŠˆÇ ¨]Ö¡½V�ÐVj"»ï ÎId_“�`ÅwjÅ@ÉŠÒ‡›L X;Kæ™)iQªåïzCMÑ[úûS<¶5(šÈþ¢BÄ»<¸þí}ÝØk ™µ’ƒºV8øŸèdY.¾½¦˜9+è5‚‡>-:D~;Íh´‡˜¿Þ³[®i¬(JoGr¼è>¥; ßÞÅ?þö†¿ÿzÃß~™x—¹ÿ…q‚Ä�‰ÞFlÙ5€c· üòmàï»á÷¿¿ã׿Ã/{ÇñËÀ¸·ÃíÀÃ0àóÃdžóc`}jž/cE �¸Â€d¤ ë›]—ÙlqÙÈ”oAæ Ðán<èžóÚruQ s àGÀ>šò!ØÖŽË ¹æIQõ€:W’Ä.F϶³ ©¾’fË *]�»c‚ÚŽ×åÓPﻨKÄڎ켞7y(„H$„ý IDAT'Ê kAißVziŸ¨"!ÁIžåÈÀ¥P7AÏü VÀ—‰j�)<\ÏØS}´�ˆ—ʵΡý½v=õ x²Ì±E/vI’Lëeµ â �FØ‚y$w•½ND-u$z«º®úHÇÛÆ XC›‚½¯|Fœ?ÏÞJšõ†Ì°4.H*Q\ÃBK¹á=óaè{Ï>Âз•Øá¢´­w|Ž„²ÛèŠøvEéºàåÕõÌèsù�ÜyØs%ð+i§2ׯ§ðW÷Ø{œ|#xWe=+_: 4Ç<Û§<÷ýN÷¬ÖÇò’õUžÉ�¿÷XW �¹_P‘ï\—Âr¿»„Wáf?)(*#ïÐ9y™›?„’Ú„•q‚Џ'òÄ >€1]Ñž+¶Ô™tlWç]a¥aR›˜ï­ WÆ!šîÌvÿ6Þ0Ç&ÜýøŽsÝq?ýÝ¥¾oé :�Mò=h]ºáQܱ‡¦é 踪¤ršvG‡1µ.›jïZG{ÑKp'‘}"yJ*uN¯±ú*N>¼¿½áýÍ—.¿ÝœhM-ú.ax‘ „MÇ&ÕK˜ú¶�Äð 5�­~,øžÉUÆe,SNiMDSÊòÀº TÆ*\ñÊÐ]á‰É[ζ¦ì¤ÉŸ\6vËÕú,0`¹Ò@/K§ï %~‡÷òiØxµR`›�¼Û m€ïqþ&^ê,p~U²ä$|¾B°+±U÷˜îúÄÖ¯TlKµy ÷M}¦ÊôÀ³Û6Uo‰è'²·Ç»ìJíɺ\…¹ Û�Û q¤·°Á_ïTù§_­æx­ãÙ� üôåÊt[¹ôªEö'!°¢ÕK¹ëßÏV�ü4|ÙÞõn�aÊиü©ö ;�û^ŒÓ¸—s¢é¿Ý|èEÀŸ¸º.þ—†Ø¶ïgÝ/Ç?ײ•éð<öáZçuåÏCüœöz ŽøªÚ‰³j¿û³'pØ®[¶—QÝ ²™$‘æÉ€<5ƒæ{ëyI¬#êþÄÀ¯ï†ûý ¿¿Þð‰yþ|ÿ �8æ7L¹ùy}Sê lïï¿þvÃ?þí¿ý㎿¿áøý€¼rŽsB>ß1ß~ýå ßÿ}áûÛÂ_ÿã~ÜqÅ]¸œôF~Gü;?î÷FÚn6Xê @úNJtÓWçI„<Ç‘Nq„ì5A¬’Wÿ¬ô´`ÎGПn%qK¿Ò O"p�6Ï�S.iMDBü_4OÞ›úp§ )6Øl`âbêH:,𾱍`W§­×C\åìºÔSb YLØ~|[þ“ïõídÆC¿-]Úãn’· ~�5=`“Fú¦ÑÈüÙ³þפd _@S)á�|α©�T…µÚðÉöé¼o´+‚íoÀçùû>F›1hõ^1KËwÓ©-Öž¶ý½2Ä ‘-Àº®pOà7®­íTÌŠ¯mL^Ú·xP£;™)Dªû-û“-k· 0•Ö…§N!OÚNa…0œ|¡± súž÷2 rú6=ƒû;©ì¯ÄF,ʨ„5ëʧø~–fxûeàööƒ¤ñôy_8Of ϲRÄùV‘õÀ@eL¹QFeMõÓ3�v‹9ØY yÍØçxÒ…éFÿ•Ùá¦Aw[ …°hÆ@f#¨ÂTý<ux�1<»(„tn¡cš‚ß,–Ó±’ƒ7’㪵%Ð+ÿ\ˆ}S•û¾2»ß{Ãeú}É/ ! /M[õçj¼º^­øò�F—�B_ÊÑK®?´ÙuÕK¥Õ¯èû �ÀâŠírH’/üHáÜ ¸üŠ€uêaØhkã‹ù¼Áµ½ÓßèúOïGŒÉeÌ_�cñáVëÖv›�ºj<ß•Q<£‡ªäq¾¥3°Oõ4á“WXëÍÚX_Û$8ö7 ˆe9y„kï’}Ir¶ííg¥ë6Oéc/Ì9ZUîãÀàU£’'ub× ¯uýð"ªyõ »ç™Rr(KIƒ2�Ø‘”:WǃííQŽ39;㨠�ÜjÀ³ë—q¯~žM`ÙôMl L(†-˜ž¾…�©Ô¤}ƘÔ€;xØ•ïá.�ÏzÞqÞOÜ?¾ëÄŸ·o‘­:c³?XrJlücшն@&…bé øéL¶8ß­9ÏP§ øöDR«-0tÐì†\1 Ha“znàwpOeÐù]ºwÚÂ%£‰ßn¤er»êg¹e&·w\±B"í<ê²áÍR ¿Ç_�-`ÑEË¢ÀT×чÀwÕ¤i¬^_ H,`­8â2u}uýþ攢ÍXuYJ2w0f#ôt*­X™�£xcâɲG'p�ZN• áñR ôY•‰X¾«a ǵ¯À®í£Ø ÛW9©BMw;â4xPþ›‰IZ°“œ´€S€|Bq>ð ìpꂉëø¨N²çø �µ�%ÀàõU¾Ó;ÒYme1VKÖ¶ƒ ¾Ð@ßʲΔÕF:yYkü©Æ ©lăõ~µ{èA‡×jñXzâ+½$h÷ÂoIW~7ÇКljcźR7b¦·&êtÑ"]†º½‰ÆéLP q̃žwd“ω)  \u>,ö©×QÅœ·ã†7ÜøüüÀçç'Ö¹Ò_KûÞäÄ1OüúMð�¿Ýð~Sàüþã�OŒyÃÛ\8މcnp»o7ÁûÛÀÛûÀû7Á¯¿ßðû¹áýïãoùÕ€›Ó Ë ïó¸áímâ�7;!'ÖËñ=,‚’oó Ä>ýɨÃþT ²õ¥|1Ĥv‡'yFÈÒ¸«¤¿ Hli úLÃWÕë�8k�¼„|¹Û#KgT¤ŽqÀM>ì2Øh{RkÓhé)Ö$ÛPÌWƒµü眙ÛñÞ ›ÐëóƒíãeÁƤÒÇkH§<éSy¹Û …W0r!ô8Æ„c Çcr.L¸LkX"i˹~¢›^ÿ6ʶí´sÉ«~¸¿ÓuÏþ&×ø•§’ÔÊDµý’‡÷ž^�Ð�†™ûÖDÒ`cð©Õ´æÍÒ_}ˆeeű™KJ'¶mÃÅò{_I‘èh\»ª~kHÛ­h¾{½ß›‹¶„i#u…'&aK±ª×вe•­º¨Îpi� ¹îÀ ¦&¡ì&üö¨ ïn“/æMîíÞà¡¢"ø|ôÜ,KÜÓ�’÷dïwG-ÿ æšç}P;¤2”íËVO§-š:ó0P¡¨çÉгÜÞ“Æ[¶ºÒÉ  ·æ³ý�A?]ìàQ{1ù óí…j»gÁtÿM ½ÕKÁå±_½ÿý°hR YW�!q ÑãÚ ‹{þ£‚Ì3'h,Hd 1p?v¹ò= OµõLPÑXC°âì3Ò–u0ùTÿ¿üú>?O||Þqž Ÿw?þ#º^”NÉ­Ý‹Ãw“Er½ÕŠqÿÛÐ ¤¤MêGQݯ‡ÆЗë½âº×ÞPðXeããÛ߯`Š:šqµéF]— ý)WÍp8D°,®LËy™ÿöYËœ±â!;\Ïqù O?Ž•þ¸÷{Çýx¥O~QïþíwxÈ‹–(~ÞkÙÇõGüòÕ<8¢È†ËϬùÁ¡-¤¢¨mU¯:@ÓŸÂоÆù¯5�“ó£ Á8R·90ÆÓ‰¥Àç©8ï'¾ÝÈmúêQ,;¡÷Hú8¼ÕÁ„1™õ@¦÷pÒøá–2Àºßñù×w|¼ >Ưrƒo;áÛã"8ÆÀÄÂ0ËÃz}/cwñ{æ8 ˜®oˆÄ&D†J@’\M¼à:j%z&)D3 Ð—O‹·­9IƒüMã@Z0)"ôচ¶(_w[‚ξc9îV³Ã,p{®Øª1¶u¼ßÕÏž§%…áÈm„D"Ah¸Î¼ÌÃ&ó80çH !=Î)8´ì«VL*¸J×Bæ< 0¬çI¼ ÜŽ�9|›Q[Ìš rãö¬±`¢‡ϧðÏi‚µÜ ”$LàÑ|·Ò�ÝVÊ×�Ùy@é'å`ól}‰½ÖÕƒ-ê­ÏpæÙrGÚ��Élù¨Ldø*xPàAœ»Në[dÊ´ïHÅ€º&œ+>;EPXö7UAú¹‰ÄaÇ�tˆöÔ³ÕZ=p9b( ­ÿ;­îÔ5ºÞl¼)”n@†W–ÕnüÜyÛÙý`’ïUà¢orékaF=ñ1I#°Cû¡'žH#,õ½}ÉoÂiƃÍ}œÔ"3*un¥ª8ÏÓaŠ9ÇÀœX¡¤®«È­øŸPÏ×…1Ž1¸kÀôŽÛ¸á×_¾a�ê¯øë¯?ñßÿßÿŽïç'Ž11çˆmb¿ÞÞc%Md¥�1°–âó´ÀÔa8§`ã7.¹¦¸Ab ß¾}Ãçý?ñý㟟¸ßïX:!cÅùÃ3àµ�/Qq*ÊÌ8Š2�F ÃûCJ¬= •9¾”Bm_îóO#¬ËÈú5D14–xÍl-ƒyF™Öé|[‘u‚‚¹rúʈ!–�³5Å“I| „ÐãŠ�ü»p?>ï'ÎcZ[7­íœ�ØRˆJ'—x™1Q|%VU˜ó¾ÊT`™Ô“âÒXIñ3,÷8ÝêN9÷á›õg�Â!–°ý‘×\¡Ìl¢Æ£z¶ÓöÒåƒÏ †' ãZ— VìØ®”mÙ½[Ë{]OšÞðÈàðèP§œÜqR&ñ“þØ^X¥ý}íí³Å—Õv‡ÁöŸ›0zRG)Asa‰x…¹Wðüø6É \ ÒÇ÷ñø;ùÄU©ÛGx¾ÿM}âË+d¡×u­ãÇW¶)©¤}·ºÌÂðÍ‘xÒV�^û3WVýl6<ÎÏ. Wøöù°Ýïôy},ÉižÀa—ß¡—^º¹e½ËþÆÖƒn#Hé¦[¹{úY[é¶[·¬ÕQãXºc½¿]†œs5û³§  (jס.…žÞkª ó–ÀÉëc}¯ù�µR��®¨eࢡEC¯xMéõ¤œ]¿ò’}Ø]§/êÒ`ŽÜN§ürž�ïNuKç‹û4\6c-¦°Ø3ÆÌ“`š¼ZÕu¡¡ú…ÁÎØÌï3²¯ ºî¸ÿŽÏqÃ÷Û7 9Üá¯Ó…CÜqå�?IÕm†AGYè^ÿ¥~&5F®+Ó<âC7œ"Œµ_¦c­6èÛ“»]á'TR„;æ‘Á3@}sùÔ×wœ[j+’*`¹½Á¹4Þßsî+ô-¡¦ô›‘öuCÃÒÀ³�&÷4VŸÎ%8¦—É$ ãöŠÎÍ– NuøÐ3Ãç§ë—ï§áíf~^Äl5}…8LŒ¶mo˜*è8_îÆd˜´ê�.ÛíÔ68@M/£¡s­íïæäLñm7C¿<†o)d§�åÀŒñwÖfnΈ©r ¡¦+W�%}ÁÑ+|–¯d ™¼ÄWplNùN¤Òȶ‹ (ç·4æK9CMCG�ß}õQ—ÙíR×Ü`›]ï¾ ³Y/÷ëyÈTwÕª¶r¨•1LjkQ»|Øæ+ûì"µ]õ˜ >wyü‘ÀI§®Þ·ºrµtÔ†HJ‹ùý"]—S7c‘l5`ü å .øÉ+ÙìS ³¯R"»MÜn·À£âvøy*‡ïÇÄûû cÜÁ_üÖ]ÒÁÌ�1ÿ?ÚÞ´ËqG~@J¶#îRU½ÌrÎûÿÚœž™šêº7ofØ ¼°”äȬî剴-Q\@±± ×Ë›àýç Þ~¾`ûxbû¶áí}Á?ýóOXÊŠëò†¥¬¨eÁº.¸¬ .׊Û[Åz«Xß Ê{~&Л†¬vx}Ñ®QUñO¥ ¾èQpý¹bûP~³¡Ôµ.h­£>�;ãћѷÁ@n (†+Ê/ÜPÀ¾71Ù/t|)jÌiE–/�ç ã‚ ô`†�ÝùCig{× =n(U$œ2§ý¡±¸Á�†ã cèG©ã�âàYVÂuDž2Ëö”dxæ„BŠõ+d/_™ê¦ß&O@Ⱦ/ˆtcFÊtûíp$[./e¯Är÷‹½¼ R†Çùá´ïZ¨ŸŽ2.À9­‰9ËÐXC;‚p�tH2—‰/ŽS©Ï{ÃO¼B>AC]ÉÂóQϬÿ3Žš[X€¿C.›ðñIØwÞ‰èTAê‡s¾Äq�Ö‘‰R¦w³2xÔãï{�0¶Ÿï{ °ƒBÏýõúmñyHêhýÃuþ=t’‰" ¡œÁsĂșº,Äû©½|c±Ñ‡x7ò癪 šÕü뮤SÌ›sgJÑßì`7ïAR_½I0s¢Ÿ5’àº÷-ÛãÙ®GIÐ;Â4ÚÍèb‹- „ûKqp<†�¬Ìâ@!h^>"º BLÖþâ>AÊÀØ¥¹?N‡@ª8®V¯‡‹93ØUgDvÝ1'¢ãP%TZPÖ „mÐ{Wa|kæiUmS£B;UÝ–1·0V°…*ˆÊX¶}¥3×u“[jx+À Nxlx1 öXÃ^ÍóïëMóN"¸´jù5»åÃï*ðªñ¸¢”M�7~�ÙPŠ«7�žAáta ’�ƒY� [Sã@gOÝ$ØlSÈvÆ€>Ü%åíŸ6Yn©‚b�éF�qø0F]鹋!nÈ�Ó–ñÝ¡œŸ‹¬äÃÜdl¢"pÍxPfI¹n‡iŽî9?�96Wz˜¯ý}¥{sjÓÌcölü ¤>©}î =ËêÌswug¾î›¾í ¥›ÏÁIO8:%ÈYÉ]çeÀ?Õ„#uÛ½:•>Þ§é¾àU/Nä·]m/ŽR±&>-•[=ëÉ Ÿû‘ÖS ŽbAw(ýšD„˜æW"æ¾—{‡ŒhOF…§,rHòßï¿wÒŠ†CkÕ ‹ 1»ÚtC®ók µCˆîq] yT?çu“SºÍôð’»50¡!ºæ5 ߛĄ*_Ÿ–ìg3—ZØegú´Žƒ—Zší‡@X¦ú§ëÊ“÷äåÃOû55as;¯üÓ‚Á¦µzÒLƻӪ¬ßtKÐ]7¦Øº›p×hÍTS¢ÎôqáTo² ’2ƒÀRn:‰Ê]9¢¥Ÿèš:°“FvFÙT¡Þ /¢(WˆžÏ§ÒZPhIõ?ÛE E•£Å õFmèü�çVqßVÔZPÍI"èòÀÆOi(¨–Ãø2̹@4¥�Àv„�c�‡Ô æÄ"j$ôƒLN\D†'&¬H ò?i @a…£Î�ÉT øy2ck9;–ù*k¬q ,IÑdž—…ªÉ±0Y(‡•Çjýdéƒ,•áé¾0¡çw1 i, çïHÔ�¡HE—‚ÖÕH@�Ð;ã~ï`n¸nו°,d‡I«'hŠèé^îù©²Ø¼¨lTvè.h~f̵Œ% õ–µuä®u»ª‡r/JŽ)ô9%Ò9'zшgØZéfPglÅ£Z|ߢc$Û_0é|5éŸÄR•jv%2¦1ˆ¡ûA#B+ãük\±_ï‹Ñ€4~±ûlmΩ>�æh_†Á&Áx§¤“ôß �”xàTrê×ü4+ sÙèuLK9MA8°cËÊ÷÷½9—>LulûßO GÈãh1Éy¡Ex¸³Y¤Ír9ŒL!NJ¹ iš+–n8Üiªøæ榩�`@µÆoOQSkÅR+.—×ëµh@(´I Ò@´àzY¹âívA7½,×ËŠõBÀ*Xß;Þ~yGýé Z–KÇ?Ó_p{W“ÅB È¢Í éz© °\:ÊM@o ðV€7nÔ©]O×ÐqÃRÔ]*è(½âÚVÞpÝ€Ö ©†Ö žÏ†ËáôþDï[¤)*ˆ*PìÓ Œœ�ŸFÒ‰à9(bï dÎ�ÅS©é0�=…ŽÎ¤á®+ÁˆÎwƒšzH¹@)B€¥ [„hˆA“q£0Cïv"† cíŒIïÂ�5³À-åúwNu‡l‡,SÌD�D¥RŒoïe_7PŠ#�e 0U�¶ å(²*L²ÒŒQ‘ª¬— òDPã­+í `|&Ú¦˜ÈÄ 0Œ>).zMB‚(³(e‹¦Â‰�q U]@ðºI?*Å'UžRŽìÞGÛˆd[×<ÎpíO#Is9ú<å©vãG*Ç;¡)z�ÜîS‘{,ŠÌ s7‡}†WFŠØh¸DFdç¤�«=w¼·Hi¹ÉƒËÖ‘ì`"†Ì˜WD’çÞoŸ©2)óêý]'žÇÅâ þ�Ÿ¢#êÙú7 量„>úä›ÚÁ˜ûJéƒ�è2 IDAT GÁ�Â¥$ò{©’ Uñ`"†áYÀ&ÚÚÁ4[G£Oöž¤‰ZíAa² KEGEc¶T6¦l&µrûf­£0+cæ •ÕÛhÆ'W´3Œý˜’^Cõ˜² :,–džDÆ/KÁ²®Xª†8¶í‰¯|ÁýÞ5uP³ •‰a]ŠnPiœЙЇgü²P„$r7Ã!zǰ"Æ!h Bfë K¬g �ቘç2�à‚al0ØR91«‚ÐpfãdÂÞ[o©6§ƒ �®囓7ÛQQ/ î‚Æ­µHïÓÙB¼Uç ˆE�xš!AÀ |ºip:bã²Ïyª´Éé›Ì›ƒȼ>ŒgQ·Ód¯Ë¤¼Od<Ëõúß´ªÅ„† Þ³Òo.6ª8cÎ*Pù³3jw¼d7Þ=;ßG �ž»‘xV|Y¿tt<›Ø&íé=ÖþßY]Oyqÿì üÉ&Œ¤Ð±û×ÓgÍ�T$;úxîñuÞÆQÙë<�uí çSå‡ö&2Ú˜ß>3íß>ö¥2ÍÎRÉyg^µ»òz9yìÊÒ܇1†‰A§�É®¥ ÿápà¸ãsþË|c¨ÅøX€R‹Žäñ™iÞ¨0ôöžâ>扸Ížqc†‹‘í€× Ä)ÑÕWerñØ4pƒ�ŒñFï’!à\R›ú�éêôÎñÝL ãû'ý?li(‘á­›÷¼.ó˜£ì P£#Ÿ^ç²²_i”ã—7�Ö”ŒyÝ�˱v&P£ 9„†GpqÜs;A!¨c!Òè¨rÃÏ#b0wp'lP÷ï.‚ ÖŠZ¯`¶¦{žRÔ0 !ž€*ºRUùâip@êMέ¡÷;¶ö†{+X„°,E#B…µÃ!PÑí¾*NÇ'y’ûYiIñ1,ß6[Ú–4äO­7¡Wè42ÄܺBÄûDN“ÈeÄ�¢†±Á–Ì+Xb'C ˆ±uÁÖ «1U@Ce¢—ýÙÖ.ŸÁ¼‹éŽÚÇÎ n@œ@1ù3ò>ó¸•b‘·Eç’[ëøö­¡÷'®3 T`©ë²`­K¤ÍÈ‡Òæ�àwà½GpÌÏ�| N+€”ñ›ü�ħ †L™%œ_åçŽÅ˜D§°õ¾6QUôOû,ц@é­;ÈøŸ:Ðèød70îW�h+*w�ñŽÏ�¬™1dþ?³—Ë=UMÀS’ük°›¢t Ã@Ì™ìîŽ:&x'÷­þ€áñiŒ…-ÍN®sŒ3ECx[‰Õ�g—ËùŽAu�ÜŒÉm»wx¢Å�zó>ÀùµÏ¥k%$Ç>aë-Ò׺·;©6´ X6ôÎh€hÊ[X™R ×ËŠëZ!Üéª�/„˺êßuÅõrA)…Û¶áñxÐóÕÑôZÔÓÿ²bY+ÖE� —KA½×_×÷7”·+JmÀÚPÖ_ñöóEu£(à­¡?šZ!ESÐQeÐ¥·º1p!ÈJ1¤tè¿{[2D\+ˆ Ö¾*M¾ úXêŠu½`yD6lOÂGe%ÂiJkØÒ׋í]m."MjÌ¡òB'&š×�gmZŒ¢±§rnâú¢�}”ú�}¡Þ)PËò6ÚBì©áœ—Ø÷"(¤äB%ÒæÌRòŒó¡×™Óp-Ö QÇ©¨¥ÊXþCv­9½ÊuLã—d�ð9 ·XË~ài›=÷1ؾݜà¥xTžd´9'kÿkÔŠ–ù™@âœ!ŠÓ&ñIžù"²èC!–¢‰ÁP4Æ„ÜO¤ßÖn‰áhñ®ÐDS�©„2ËXöi+2á÷Æ�­&æ“>½ÛUX5A+u•ÿû:󳿣=‚ €q� �×’T0”d.šìÀµ&v}ï%�%ƒy½{™¬( !Dvè0ÂH1 ³.´}ïJ¡`‚ÞÝxæ ÄÇF£H\l¹GwŒÛ•;‰éå+瘞»5`¿“0�ët’@��¯}Ò(OÂn>¦¹D2Ÿ�÷Ýð…8óî;Ú"LFÌQ�â¨6!ížG�Æ)†Á=�mÆl'"âp™“š'öCÁ蛾Ù+fߦ¿lmNiœÞeã5Ü[Ã}ë¨ËPŲ^�¡>±m Џ`­ê}éhݨ`âÛ³Z*J­–«´ÇØz�n÷ƒÈÜ@Ò}SrÄ•?Ý~¯?ÿ„ËZ!¼Ù_Co m<[ÁÖ}»,è(Ðhn²C‡Í0à©zÐîmëhMÓ itC• òá½/ÒÍ‚mžU2 lY¸ÅH&á>gÓêÈž"ºÉk 4²ƒ“{W‰Hx`H±Íw×ÃÊbÝ;4g ¨pxåÚ´C‘&BÞY´-îjÐ×Ñ VbžüÃ0€øé2=ý‰Œ¤‡%g›N)„"b�Í¡d³j]QîuxkA¿vl, @>•à4^ëšéãâÛZóãÆÀƒÄWçËy LQ4÷ÆÕÜ©1ÊáàÃx|LiG°›ù.&üÕN(½ð q.wìžGº7\æ¾_J§yÐ�}3”jHUÍPÝ �§w“<ñI¿·&aÿØÊkpdü=ÃÉOÚžï×!¦s°ÆÚUûp(ùÑDP.+ÞÞßp½\”~QDz^q»V,ë°\y¨(Ë ËûÑ/¸?�; [·¡) Z«2¼ P9r÷+�’ Ãñ³¨{ó•PÞ+Ô Ažª†/D(]PJ•†B ¥(-"§âgMeÀÙ£i‚™¿8�a[LªIŽÃ¶·`¸ã©â…;D‹R8<ßuÚM¹l¥µãÐól„r!@–¶ÍSøUÓ�ËíÚ`ÏÍÔÀ4Úk�}ØwbsG�šð:‹/ˆ,bhß�òØ+ÿÕÈ*×ÃU+Q¾Žl…É�tì½”ÐiŒ}‡ÄŸóã¡K‘òÇa•¤‰+Ÿ„/ïcw¾1–ëô'Ì`?'B…èùŽ‚|Ðñ��~#Æy.zÊî�ìîïŸ�ùß_K>½Ü'+àN>¯y³kpP¯t”qY¥û�3ÅwÎÝKEâ]¯û¼ó Û Š¥uÅéZ÷H ²±ùïÈͬ=ÉíÁ[mA¢0â…üa:Š"IYms™ÓÀl]±ugKM¿­rR¥q¨²;X*«²*Rd°DÜI Ee]P—ýÉxö§ö‰É‡¥2E¡ÆsÒZWyyk*¿ßï_¿5´­áÚ Ö§€ûŒçÏ@犗�¯ s#-…î ³!ÌðÑœC$M‰’½dHKk¬^«ë ¬ípfOµ™U“r›tÃÄæÍ«Æ,?œP§�ÒËX‹äŠŸàÈXêc¬Gé­€GˆEæv²Ã‡eàÍ4®is;袷1Œ12Õág „¡B4ªÚËÄR°.JfÃ'WjþpíåõÏ_œ¥îüŠjW²a qyß#dùÛdzëGîW’,5ÞõIÒJ3: ‚΃Ì~d.Ó(¯u…¿EiÃx¶saJÏ¡åÝÀÙAqƈªÑ ׺‚êŠårÅåí†ÛûÞÞ®àÞÀÜõ|€ª†ƒËºÆ\rmÃ}cÜŸzHyÝŒ†û³¡mO<6˰^Q/<ïw´.¸aÅZo(Ë ¨W¨a`E© ÊrElà€jC¿ðì4Õ7,Y²p(]]ƒ6dÏ�#h°t+¨X€…€µ€Ü¡ÿÉ@i j ê¨Ô�ªÜ8tH§àž­ãkTÌ <áˆWtŸ¬ ‡ÑÚŽìwèÇñÆzΧPªÓüÑiðwƒö ¾íiê C#>Šžq°ˆ¥×q½ƒÑ¡¡Cr O:Sî̇8”<„À5|­¶Û…iÈ%.ãÙê 1é±ô¬FçaÖ ¬;H{´E)J§cÖ}ß´Áöa@ŒQá\Ávèqî¸�M|*Õ©Òy^¢ÕTT�—»qÇp”ìr`àÆåQ¿:Ÿr¥iÎÆÒVù|(hÈÇôéðñ2nÄdž�ø6>Ï.š-5Y}•Ð`ùA*åŠó¹\cz&aÛ³ìiq�Œ¿|Pîî�¼•àvÎ2Ù˜8ÀÌQà6Ç„È{˜%8Fÿ%·í t÷¼uA"õ?�a,,‹,ñA½lLÙã¹ÅáÒÂÿEA˜“ 0ƒ™fü ”Q¼:cr3lö³9 )GføÇ�a¬ðþ`W,l²ƒNŽþOõÍ—ôjÈŒ˜³‰“ÏJ—%b@Ã#2åµhÎ 2>?»&œ‡;Í¿s9k$<)Ák‡g·3#aŒwϼCý‡Œr%d†�Ë;ÿØôð`T¬Ë€P×+‘†e)(‹å$·ÊoXxœy,4?ªo0Üó¾‹Þc1ÊI* ‘q°B2é*ðv½áÏú3X¾üþ;ÖuÁûoÿ·ß?ð÷ß> ¿?ðñx¢³yWؘ,‚ ê†Çóž€zWêB�RÃ]CÚmc 2Ì8 <(�¦D½ä¸<^’mc4. t±C“…ƒy(ÐÀºñŽP?¥Ea¤=,2x�h ™²À¢,¥€¿ÇfÌé&ÐxÊ?4Úßë.4(h$bl7ER„@2 œÂ. åòêóhpÈ‹ÌÏ�¾Ïæ€ADóU�Ðé:íÚ;hzîãTå i?D¤ïÄýXß�¡©ì¡ölÆÁõÖö(8q‚‰_¼¼^ôLæÑÖ�çÉô™=´¦ñØûì ,ùúœŸÎFƒù ¾sòòùíï¶úÿê:Ç•¡`ô¨¶3¦âôÊ�ˆ¹VÙÿìéë¾É^Ö“ÝœÁ�|+Ù3ßs(Kȉgë꬧YèÑ:]†Ûn\þË£ž À,ƒÄ§à¼íT6op’QÀCþ7 ˆFé­ë\C÷u`ã�¡0ÌrUtÉ÷{’Ï®¬˜ ¥÷w‘œ¬üWþüÞõ©‘sjctæ¬fç#.ëѾÜÏ‘¢DfœŸKù×Ýø€7Çqßù Ë2Óõ¹Œê2è£oÓü&¹Õ»e|×Cø‹Ô¨Wd8è„"�Ȳú(ŸoÍaFX늵\TeU”·3«€JØÔÕÅ FX!¡¡É�öªÔå‚b£¬`ZÍñ¤›Ä¥r œÞ‡|a¼Xà;݇ú‘q›â,Š€!¨ì0P'ŒuLé퀸y÷JÌ@É$mšŸØÍîô�d!VgœJ@…)ã�> ¶®û¡»dQ\4b£ Ø¹[Š¥ÂlçFUì],H!\邺¾«pƒ)lDÓç˜ÅAÝaòŸ°TV•�‰ÁÔÑiE§¦ŠNŒ�¤w¬péP¥]pñqù¤è!Ç u¡5¸³Óº±nC ‚Ž%f*öT®¶uƒîX ŽÿÌn˜â ¬ÝÁ7õaõn.¤.&—çú zÈ|î½kKoÈ€)š1ºäð†±4[»nüKÍÙMþïø¬Ä&Þ=Úž"¬³'="­ò{ÖÙ6�"Á×é©ì�1žò>yýs¯·pc†x;ÈFyì~;}ØÁãy< ÌÎ…çÜ#æ2öS§ý¦ÀÏ7—]NÇm 2T Böéô\´VÝŒ ÔÀLB \€z…”+žR�'Ð;À]P£ >µtˆí%Ÿ�÷;�;�–Zñõ¬‹:"ô¶á~¿›‘ñŽëµãããÀ eý ?ýº@ú�+P6`µp¦Ò0PèhÒ‹�g©ë‹*G”›.=¥WÅNÎówPq´: ÊÀé‹04Ïí -PªÉº¥ Ô ¢@…¤Þ�¶¶¦çêQKä&€xêª=žÓ´í£FÆzƒÑf±ï­¹.@kôô2’̤¤Ù\·ãÊô")`䥸õŽyÐJ«¤”¢´‰`g6úÚ¡´æ¡ø**‹p!¥Q.3X œ¯5´Ë ºF®{d‚í, Jº iÕhè#9@˜¾¸®W&4оey("(â\@Y€Ç2Ôòe÷Ûø õ ¦Ÿ ë}ä¢Cª[cK"ã Yï‹E,�çûNφQóýœ÷.ô@¦†Ô¡#'DØÇK¹XJ`®[R“�!~Òk«UËC’ TGÏÂùÞÌN(ºìõz®¶xgR¬§²Vw6:äE§�G[Î@Èètï2ÿ"`lš³RÄÛQE(�$Ä6¸¡ ´YÙã0�Çq—Y¼^„EOCZµæ¬4;My ƒùù¢NNãŸy®™mlùÝ=CγΓ‹Ò˜à›gr� “mŒc(æ§¾ÃךÌ7sc2Œ¡`Êq˜„¹©Ÿ»çÃ6�€çýÊŸ&佊–øü:¾—hRjÈ¿Ž>ˆ¯G=-w"òàÔošªuåò±"Š~KêmÔzÇÆ.ÂZ5-Ðz-(tA)ŒZë,¥‚ù‰ÖHéì_*fdèŒÖ)RÓtKIÓ<´¯ ¼½jwÑÌʽ½á×_Åo¿ý;~ÿò×·wüË¿ü ¨|Á³¾~tßѹ¡`C‡ 5Aƒ)ýÉ `DWÑ—5§ž(\8«¢‰njܳ]±“×°°°±Î ¼N¶f ïŒ#Ù ¤){�h«^Lº!ÑMÚÀ-¥ÍsJ¡,˜;¾+ßñü„V§˜Q@FĈ�¥]’ÍÖ¾G ÈØÀ¸âHJµ �rJßœ¦…¡ÁÈRÞè8ïBü×Y$ÁÞ{oP˜”ùNç}úƒ[(~X/ƒè÷H°«'_:Çatˆå6]p×à…c¾æëxo�Ag0Ƀ¦ôl6–HúD¢åÞÃÁ'·|Ñî� Ëü1õë87ãþùï‹9-;¯ƒâyfŠç„ü?!óîµxâK? pRÿùõ L7wå"‘ï‹b0V€ò Ó±ØÔ‰WN!*£p–õ†·¼ø‚Kå}îCbƒ¦œ@ÈÈtm¬˜¿=ž�ÀÎéµäñùZ˜£)…F™´vrkÏOû�Ú�z6œP”Œ¿Rм„­ÛZ+–eu0ƒKŸÚèF�S‘E0ä¯ ýúŒ²{ƒÉùµ£töå{ï¦ó…Ì™J˜ —¥¸rc);G¤@¹½L:x‡×ÁÃó¿§ß6( ÏÓñü8Ô´¦2` 8/½“yrÂPÍM$Ì�ÕDœø³#)QPŒ' >YÜ}]�þboÈô–VÑ¥b)Ûä2„;M£>Ù•¿E=çÄ6Ê 3 ”B`Þð””E°tBå VZ e…” �7T‰TÝ«2h‰g†v_ÛA³‹­S¦dðpšǨʘ‘Ýž6Ëç³qÀçË÷ ³2/ðLA )¾F÷0ec!`59NÏò2•Ï®Æ�*sˆê„ERJ¤Ú$¡Xë€8ºè$n½ƒ¡mÐB@¹šaàž›*¹„TǼ   R ¤t1˜.èÄèTb<ù î ÏNxvBiU³L@ÕtO^•© \ÑåÊ¢±Yžî‹éì‚ÌËlÎÈp‚ͯÝ<ÉW @  ® 8ߣ'ÙÜ ®ŠÛz~WM'Tk¿G¶€|¹!&èŒ ÆÓtŠy/w¨q`r�çóg¤†ƒdÒdÃÀÀÕ8Ó!ÑI3mÜÁ47VÁàñÇëû4ü¤ÍôÛi�qæTçùžàØ\ôp*0mÛ¬D®3Z?“«¦€¤ZTõv Y ¹ �ˆ�^ÈBz`ŠYñ/šBˆE ¥¤{¿Ž¦+¸\Ð邆áÑÜÒE�v�6A÷gÜÏçÏÇ�ÇÏ熥6|}@Ï{�€{Ãö| ÐäŽËÚpÿøIÇûû ú&¸wh:¶²ŽTƮܬ²ÈB�®žÔ¨°ÃY 4Ðq×!+/i™ŠD ëXÓé0„:Â(€"F©ŒZýüC²V,ËD UuMðx6<‹5Àè"¦ �DT•:Ñ1:sðÖÀ!x˜÷WÕƒÕmìöýNå({ü�ï,ª';ÏÑx0�ýù�õOŠ˜ÁÕVP„\Nº¬àº£cY*ñ ;Åé´+ÌÊkŠB*''g£7l‘/‚WòeiÑ{= ·L ºm8Òþîuosäg¥Ä¬Lžþñ0Œ¼b4 \,RÁ*Ìïg#Á•Fé™{ÿ—Ù(0FY0�ª3/“-„‡}Òч,\Ž�+ÿZŠ+`0êÝ¿’p�:†À=þayšjbLÕ™•-ví Æ”烕ÔFôÛ­\ á(炜-¼4ò±!4, ¯ƒQó´¸M©5)…€ø>Žõ–Iùëó&âDžÂˆÃb^ÅCM,(Þqâ0$©Ì°õP±÷w2ˆv�\˜¶">ô!Ä Æ{x}´ÿswØÙ↛‡´‘œ¸ûlWÌiQ»xgx’�'Ù0@¡p˜ËêCJ¡[^†Æ÷ak1Õå¿£ôè竱X“ùW¨rcŽö@rÿ]™šÁb}!š}A‡²z¬„¼ǃ1V!šà¡ùP-·a'ô�†ûS7h×Ë‚_~~Çíý‚Z:ÖEðþ¶àv)xþòŽÇýgüñå ¾üþ@ª<ÞZÇãÉèæyÔE´íB`Ò-[ˆõê8êšë¢}«KÅz­¨×Ÿ�ëÏxÊoøúñDYn¸½4f<Ÿ<žwlíŽÎ M*Z˜ ¨¬ Ro95ì&/x` Œ ¥ê9­{dAw‰ÀÚ}@ƒ©grôÖ—ÉD§òü�¹“¬%Oå]ÕLÆ ±&¬v§I�]Ú¢YJ=#ѼH!¹pF]ÆaMºyÉyJ)¥ÑÁhMüm£•ÜMhñ ÏeVâ^ciÜ{ú´Âö†€YŽÃý£�{@wøAÅY‘ IDAT ibð€16@ý:\2ønæíù ÁòìåÃÝ}Áù÷žÆN%w0šøkFЩý“. ʧýŸÊ»¯ ~s¿æºÏ áóÜì{”ØöÉû£|ö¥˜)µÉ1yLâʦTæÚÜþXÙ|Íýúüý3ÅìÑ9�Ñ[Q9 σ³–}ùñ;­„Ô3š‹#Ñ Ý4¸"o’õŒok K­y(ýsûö ä~jãŒã Üø°‡Ðø–q<ÌvkÙú˜›Ê»Š—kFÒòžÁß�Ï„™~ùFÐS3EØ<` d©YÜë­�ðìÏð6Ë™£í>ç5r©52¬N¯�Ìô²˜ï}þAƒš÷k�õB£½Ô'{+8/uæ=M©?§B^–æY¦“o¹éÆô•ì?yõÖЖÅÖE?3µÊ­ïÿSF•Hj‘O4ºÙ4/¶Ûe6ÏsSL—¦o/µjžüEPÐйccý$¯Ü–$�Q¤šŸ{Ë­Ï&X ‹î¼k½€kG§ ÌŒÖ;˜õ@Iõ©÷ÏdH¤/óðÔ¯’äx7³‘yê^#ø‘{”»G¶ � (€¸– ‚¤† WXŸ4o~ŸøBlÚE•vF%޳T‘â©„\U&æ0k}‘”…\Øœ³Ì[“Ty$”`* „VH¹€êB+šTõäe“÷Š)«»¾yCÑ4!õŠRª&5Y(W� £.W5d®^5“9ÌIÈÏbÓú‹yšbèJLÃ<] Ø­7ç'{ aÈÖ‡BGDÜ$ÿø{<ÜqE&€D½5øl{yF;ÆöZbë˜ ï\®`‹F ‚B|",¦ô-§ŠF'C” € ¥Å4˜Cy«Ã%<…V£Ž™;ƒâÔ ' â¶¥œ¨™¤ùÉóõйWvèÁ[üKô}ªÏdz‡MêœÝ:7Îîzè —�|¿±ã¡iï2xÊžÂ[Š)¸¬âLmhÿÄ4�ì4Ãöy구t€­®biYtÌQåÒl'³/À³ ‰àþ4o}±ƒÜ'Þ­^Wš‚¦ ·­�.xnj‚gÔª{|a mšŠ­SÃe0«ìÿüíÒ:>:ðåë®ï‚Ë»àí§‚÷Ÿ –XWo‚mÓÔ¾ReYP/Ôë‚r]€ey”„Ç>Öôjl{Ç�ÁOFÛ[¬�pÙÔ:¤7@6ÔEp¹Ün j-€TÔºâz}ò\©è¸ß7ô¶²Adƒ:­õ˜bñ9”á Ï>ÑäkÕVL:•>D n2(A�#u™jJ!ÇC!MoThÈÀî°a\$$`×­±°ÌØÐ%<Þ�M¥äô½¶VBnN;§C4ŒN·|M»nšÌQ‘n 0úJš¨—q02‚/9ý±õdÄ]‚þJD8ä6�¬—òu™� £bì;MF'NeÄi¤Gx¹H7d‘ÅVqg:Ä_ÀÔhp ”�Tí!à‰Â�¨±¦`ÐX†!¬#ÞÁbtåSãÀ‘÷�Q§|-ë ž‰²ÁY˜$ÀÉ›pR4yÙ°Ó#,|þ„LF�Apy×fRú“áéùL‘ÍÚÿž!˜žòdébpÃY¹ÄAT…=åDê¿(\¥ÝdÍB¾m>üਗN�†‡ïè^ž1}ßè¥1ù±°�£ö›NhòÞOh´åB«‡O�¶�×k&o 3�ax6 ”öÓø|t¯ê”vÜÇ»]Ÿ(á§�yÂ4ÿ2„ýx~l<<±w°È¿³'ÌfŽgáàÄØgÓ_H*+¯JšÑ³ªg´0ðfÇ0çMœÌˆ™@T2Ó²Ö0éÀè ¼¿ ~úuÁz{ÇR®à—_nøåý‚Þ~FßîøŸÿVðíÛÝîU#ÀcÓ£Ò¨4)j°ÐÁ ‹€8Yו»)t*a)„º^@ë;x}Ó ¾~l¸Ü:ÞEø�ç[{¢³n* WˆTUü—ŠÅæÃ/f=P­³†|+C*XˆPJÕ�Qï!l“å°Ö|ûÖzªtO ”0Ðûúu¼‰9w/¶Á¼¢9vÃ3aæ„bÞýÎäË•c;\-& k?ƒAïèsÐBlÃÃp`:/�{vå ‰÷/m¶¥G¼ÿõS=�G]ø¢DÚ�LnRè 0ó–ü{†ÁüÇS�™÷Á„±Ábäd ¯É×þËR‚õWö±²™fÊùCqn=Æ™?�uÎ|×ñàUÆm‰9‘ ´»1Ò˜©Ñ½]ömMÊÉ4§|}ÆŸ—ðjJCbC¼‹=ÌmMòÎi^ÂqÕ×$Mߣ|Xç½gдƒÙ+<0ÜÙZv}£벂*�¨mCgÁ³ws|ò*MyÑ‹ËvhèYEÛÆhkAç•J¶ò÷“@ˆQ¨kŽwKyY/�)ù<\>ö~¸ÂÞ5êHTºXDºy3ºE†< £“M:B**ú§)wÌôbZsCki‰µhj$±Ü ¢‰i?C•òšJˆL‰! !õ%XP¡Ž-EŠé±%¢^]ÑÁ õh—Š7¬èX,EÌèC@g�K�ŽT)IEÛ«�T¨ ”B š@Sn.W,傲¬�²   ‘žR 4./ºÈ¡ž Å}€Ä×Þà4Aª“¸!ãéX)¶ËK)Ö�O Ëm �ô\¶ß±Ÿµ©W]¥§xaÑù«b 18={±�G=âX�ä]AŽ`�Þ­fß¼ÏËp:‘ßm|îpÇxn½ š1 æ î± F“ÉQ4à죙çä\¥þ™¸³gK£¿¦m’ñûÕŠMšû™¹½ã”¤ÏIF8´±£³Îã™þµw$ÛçeÀfÁ ßéü¶Î PQC\© ZAT�r…¦Å0 žLèOà± ˆ¸o`n¨¥¨·¸áœ°ì¾®¬— Èæ‚g]Ÿ• ¨U°Tíwo6öì —U°¬ .•ðï¿Ýññûøzâ·ß~ÇO^ñó_VüéŸnè¹áí­@®ýÙð|h¾²R ÊeÁú¾¢^ªE Ø‚’b©e’¬!pwÏ4𣃠[c<£Ø¡)Ò;˜5…ÐR—kËŠu€*ÖåŠ·Û Ër3a{2zZ¤€`¼eD]ÕèƒÓG?³ÅQJŒ÷vÈΩÒé°Â”`΢9ñÙw ža„O[SèkÝ¥¸ÙɬfètIsÇ`ãhº=ãÁÁÐ’ñz$B(ŒPdÑ`8ûWŒ7fØ«…õð`Ó+3¤Åòs±Ü>g'qÕ…jú£A³iK"îƒn™Øg7q†‚f…##TŸë‘U!£¸QÂ3�˜X¥ó`ãµ?rC%¹ÂáUŒOû|ù}’¡ô�ÈLÄÙ£dÈs.ž­4 D¤ü³I¶�AO�þœI…~-�>,6‘A=”n&²3¡Ü~I�iSzü 0Ï÷|šC´\@Ëïr ΪõaPãD˜½ßÆÜöJ¡©î�ùX£IÇä”NÈ JêÛÄÙΕo¾É¹3$ˆaÎù•/ï¡3}x—¬[£Ëtú^xæH¼äË1ÿÆx@}Pd…NÐîtè2õO¦'~g¯aJr,œûîkpàÄ,¨D=V"z&ÓGTâ 4¿œEŸøxµ¹ÍÊþ O}J ,‡²Ap\Еèö��ÂM%jJ“K£Sš÷Ÿ ŠïDªT‡�d¨D¿õwFýrpÇZ„F¡ŸðÓÏ7üòç_ññèøúí¢US]Ë•ñqg|<Ï&x6 ýêši]ÌV_‹†J“n`© J'tT”¶à·?6üõ¯à÷?6Üá·¯:}Áï_?ðìËeÁŸÿü @+êrÅcc|ù¸ãÙ6tnº)Uç¶‹ê­¥BØ7*`2/¹äiÈ~p:Ä2°Ì‚±^�†FÜ•¯=ñõI¦Hò bIfHWO†£ŠIýs&)é™?ˆ¬}bñ0@§=@8Ed%Òá§1D !§AI™’ Cáž�ƒî�^:5ù+©Ü2 u6<Ïô6øl�óï[tÙïĸ€ãŠÌ×gÏÜè@ hWæ|Èù˳}†diõïÐñ_?Ü™Ûs9&ï ç‘<|~3u†0äÌ,ôÑ ä<‹D<Ò„AŸüùø>lÇ!å~ZßáÓ=÷öF¡“:²´eww(ø–×R JY°,W5 °…”³{‰ Z/øø`0ßÑÚTz¢Vàz]ðë?ýþ×Å·oOüñåÀ`ÅÚ×Fèô�?î_ñÜ6<°± ‰,õtÐÝê`^lª¨­â÷/ný‚ß¿løØ Ú·'>¶†oß>ðlëeÅÛÛËrA]V|Ü<ðÇdžûó‰.@©UÝ@u‚žh´(ô¤šPtœÐa�‘!(äu[C¡3ÿÖïC“7@1õ�Q:ƒO¶A0¹£�ŒDo�þˆ†2)`B¼çü©~C……)óðjÉ7'•Àh'"…ˆÓýDc$:Z‚æ„'•d꿣ݒf'èÒyìÙ  þ)å–W7ú9)ÒRTœ§œÚ_™6ùx²‚8úfåNÈBVè–óø¦ò4'¼éË“–cÛòêÜíy¯á�d¼Ož€s#ñF~x„Eþ6 ÈçI�¤NÈl®S¢{S¾o(~ú {~¨U¼ÂŸWÆo1Ãàìýãg–­ý^ŽÈm%Ö‘ä‘eBø„31ß æ`E-—Ë뺌kµxkhž¾Bü ˜ã;åf0CrÐ*ÊýJ**Nd9餚O.ÚµÿŸ5Œ>ÚÈIqMÓO¿5hG*6~xꓸ·_˜2÷�îë‰úï•l£ÄKå0§ ;§ØÞ¶z¨…¥¦€»ïœË%JÎ{Óšƒž7Ô;ccÆÂŒE*.—T+*uTêhÏZ{¢– ”‚ŠD«ž;À€”ŽR:„;šlØž[½¢^WP½¢VB­½6H»Cý#4RÀ,ˆƒÅ ýA[ì]6Âȯã)â†?ŸÃׯ{Yêû#Ú×)ªÿÁ)z¨e¢IKœ9ÔšàÙ4}S)ªÄ!TSB0HšFÊ Ì(PÑ¥¢Ë‚&–àÂx~AU8iÿa† ÷´JD±Šˆl ð&jøúñÕ>žÓ�b„!ÒU¡e2"CÓ*ˆ}–®@é\Ì0 i Jï€ïo .×›©#ÄÒ¤´�wæ/+Hêž—€è_;#±ÎbyŸð¾ýæKüþþù|ÕB¸PÁ’hÝõ‚‘áæN)iL=«!Ä8CLÃMß»3†÷qz¬ ²ð´~ðð~üó~{'„Œ›`•XÒ�~ãuÌhR¬+¤6)óEý Hß{ös£€Žºç¶Ò˜ÏÆy*íŒö^Ø~OÞ:¯åLNñýNìÔWIrÇ�—F䀈)�Ù¬{¥¦N*oÒ37�ÏM ¥êQ¼kQcXk*„[]PPÀÜÌa‹�÷ÔZPH£v˜:ºòìBj ]::ohÝë¶´k>{ªeÓÃešTP}S'„Fè�ðõþ _¾}CýûK}¢÷¯àþ —Up½þõ¿üŠÿúßÿ‚ºü þôÏÂzY�¢ú±'̲ äÙѿݱ}|`ûø€»˜¯ë ërÃr» ^ßAüúSŸ÷†R u!ÕÎ+(Xê‚e½`¹]PÊ yv®à±Ë&Xj�™òýMd0ú$Rl­ÛY2>çH‡*Âí W Π÷ÑÄ ¡T–5 "”Zô ú¢FÊ!ÂŒT¿{ü_AèD(Uì eÃö�½¼JSI�á='RcD%�|S¥9…®I×b’‘mI›‡GܹaÀSW©;Ñ£uÞn†Û0&PôÀåhÌi&Ž{}‚µbeÒ€»ÓÓ8#2Ú²w �#%|Œ¥ÀδÐTqR4‚2"ÜSŠáA–“€ºçr}½˜\áÆ�4 a0aL)ÇŸçžwY4K£™nqæ×Ò{Ã>qz;+?Ž^O6ñÜòíû†Ç� `hb­cÉ£^œÓ¥Íá0é„oÚG³a 3Ü ðdm´/†x�È>„¾`i1!ÇOñ4!9†Hj'#˜Ä»@–‘ÄúOi±Š—Mé öýŽÅ�<¿|»—[ú|áÓ\cjG¢| M·¨£ÌŽ–�i;ñÎŒñÌ—2Í#SþœÅçÆ÷ã³{q{,†Á®çž¼‡·Í®{úñJȘÀ䓞WYì(ÆÂ%™îïz35!»ïdL"�äMÚÛ`ôáàÞ89�lЗ¯ÖÍRÐPA¼€›nvX³À¨×‘(Sxl ��ëU@²¡Ö†ÿûWëõŠu¹àþè¨ëJ¹¢–+.¸@ä‚Gûÿ0îØ¸áÙ[gtT*˜ î² sEX‘›�ö­5üñîò~ûhàþ ½ïT@ëŠëûϸÜn¸^VÜ®W,K…‡ïýøï¸?žøöõ+¾~ûÀ_ïøãë_¾>,ÿ)APÑØóÙÖØL‡^Á±X”R1;^8ãÔÐKöEBFéÝŒJ„qšNÂu_×ÂèžSzB•¡ªõÿEä`> ¸—Ê á²h¾%4ðì¤s·æH ÛgÐ.[iâŒZ[eÎôr“=ZÊ7/±ìP÷ªͳñÐAÇÝãØ»7àiÐ ¾°Û¥ïÅ`<Åçrÿ{ŒDæ‹Á§Æ|ÅÙ1�ô¹¤yÍýè%£7§|Y†!~oô}Ø�<ê€g»æcœˆþHçɰBñž>Ï®Ï!qNïÇFíÇj›Ú&'otèã�te´^Œ)šJ›×Ó*™§ßÿ7Ò§D]˜±ØÄ‘Ôæ”dæ(âé\ޤã{rÊÙí9}#ÉxCa!άFó—“k¸‹ät‡.�'YÐk�pßû=ßõÝû;F|Ú/¯Þǔ˧ºƒfPîO^S‰—Ù&ªŽÍ})“r»õ¼®¥hÊ*(vñe]£þP]. è¹é¤]ÓpgtËÙ>Ó—Ïq‘,a,–6óžyÿqæåöyåQzãÿúuJÊä¤Í]Ÿ$um@kð÷:ÅyÎoÌ·îVíIySm†‚EEXúEÝÕ+Í %ƒ „ º)ÊÕP‚‡š¯`ðX O2ÙHå¢ÆÆ ‹¨"c] ¨V¬¤i*ÄrމWåëzh$ à½mx<î(¸ ÒM½=—«¥ây@xóSåA§ä¼Ü#á íà ¡ùÏS‘+è¨õ¸ÁÜbÎDÿ â0%�(LYFÚÌ8·ª½«J¤h¤†:“[šHtUÈIÓbÆ�鉜ž� ‹zb²)L˜tïÈ¢J~ó(ùËV­ëY÷ ¥>ðññÄÇÇÓ8¦Äñ´¢Da*ê¹ZadzŠj‡ŽVB@©+êrQO^nJ[ÌÐ ž®ƒ†×¼Ê•]ñ—šÁWçà ãýÎa… r4èЫý^ìŸ�•ƒpY.x¿•àüºßiÚ7ÒT/lž§ªÔSظÙ1 õ#ôPy>‘í‹+â-zJaÞõŒ˜Ü@Ðg$æ°'àª)ã¨$Z2tÒšNB)“¦¯!¼ÐØCè²ó^T'Q†î"­e=tÝÏ pùÔ0=Rcc(ÓÙ| =RУjQ™¶RÑ =ç±¾ÿƒ wP^7Ư=]O¬6D¶•X³n¬÷nž…‡#ɽ‘ÿ¿'Q¡PÐ:�Ðóóˆª(l‰7ÎZPc¨=ÑJ¨¢…¤^Ã9ƒ”ŠˆoâLç0bîxè!l~F=Ù¹þóké½ínYƬdB:›¨©¼yï³yˆ {û«@ ³²87I9¤\@`À½.C1Ÿêˆžè;;"6Oó&r”%"Í“.ÀÑLR~˜>'K]Vš8L…%˜¦õ\¢êÙ0àu(˜t—;©ÏÉÖaÞåT~‡Ù:§±-‡¯æ}‡{Ä™è5mhe¢4S©Ó¯Ç²:Ç9/ûù5ŒùnFƵ&ÝÛßû}¬^bSwæýë•ÉÙ#¯šö7Æïá%˜;öJ)%§{Bå‹6‹¶´õß’ Ë„o‡îMM‹Ùó £ c¤¢³:Ü6h¡X–ŒZ4¼ûò`¬uú4@¾¢mO\¯7Ü.W<ïuyú¾aYÞQëO(õ|,(õL‚&„gkxt%uuÑ0jHÅ&Ò¡ùÿ7 oº7ÔÒñû½ã¯¿}ÃÛ�p»´\°à§·7üô¶à矮øå§7¨ãdÇr»âúë/è½ãëßÿŽ¿ýï¿áüÛÿÆ¿ý¯¿a{2¶ÇTRX£"ôܵà±!Rí™nú,¤®ªg‘Ó§PŠ;C‹ƒêò$ä‰0�œã¡Óc¶(¥Ctݼ…y@`9j%ªw §òU5…¸ F΋$Ñß �¼7 8ÊÍ´!ÖîQDÎ'lí�& .’Œ±Qòõ»7 ¤öGgù 2‡O6ì?ƒ2¥1HŒÅ‚<£¾½Õpl‚|®_ДäbSü IDATO¯#ïòß“’Mdº:nG†xvN7Ï_”ýt–NêùQÅ»QÅ´ÿGú—˾nÇÉ¡Ë?b¸Ø÷bÐÏóy9»rýg^Bû²/jÁ9,ö\οùäüüÕ»@D.�l¸�ÝK›á,ûdÜŒµôjMîx�¼ÆË¨)èæ,cì#&ûÐ~MæñÎ2¨Â.›ø}¬gwO0Þ“½'宦4fC±ÍÓRªFÎ%^‡[ÖB–CX�K­¸\.±É,æáDµuAm ½w´¦D„ÖZȵŸ­¡hÞÿ+Ëtß×a„—Ç@v~…Š÷xç»òH_÷,·/Ó}‘Å0÷[_^7j¢…~·ç‡È‡ÓWÆÏ5|]y”'Ú¢zÚ¨×*ÓH#ÄRôÚà“ÐØ=6íðI‹<ª¶B•<ê™>d� uàÛå PÅ·�'î÷Í@„ËBX²´A–FŠTÒh±t:6îRAeQ¹™5â¢T=‡@ð„p7å¶ÁQL5Øö´º'Oé•ç}}þŽÏ[H7öüÝëòýÒ¨+­&“¿k-X×ï·�Õ ÒZÇSz@¬|:.Á†2 Û“‰+-Ÿ5ÇJë˜Õ8õØx…¨sî¢LûkæX”Šgƒ€Ý•×Î]�n{"ÑCÞSjdŠÕ8dnÍ—Qȳs÷ÅnÊ©ŒœiÏqt§!ÕµçÓû¹FôQé¦÷ýøî膘½QË�ΰýÓÞ“0Œ³šrŒPÀM MÏ­ã±5D^RÏc�Þ/¥¢.+ÖË ··w0+N «C@©ž fŒëv@ª†;[dW×T<¥Àp1íÖÃ�—JX+h M ÒÑÚÜÏÖÑx»Ýpýi¾„*V&ˆ:ü=€ŸQ’�C[ªP…¼ËR"ƒ'Ú…ÒYÂ.ÌaŠø!ñÖ¢ô¤À&—Lõ�öƒ<×RŽ„=òÈW×Ò[6 ˜²Ù¤´�¥’rá`°ƒ4\YÂ’Óü’‘+Â�Èz³”IÒôdŽ+ÅÅ6¦yƒ–IQ0?Æ“/Wdí“2~3 8R:éb6droÙ)w×áàÊ]ß\àt�€(Ä<®nÒÌ}$ Ɉ6¹Ç˜þ�˜Á:Ïö^A�icŸ§Õæ++š~ nù¥ÉÈ“ïy›(Ò|Éq–¢ÄA±#~/¶¾gAdR˜N + ÇN7ï^©{-Ù€Î<þXû”^¡4~§­'£ K`Ì„U™†�f?³A‰Ñ$Š#õPÁÀ…‰ô"; IÌdk– \¡‡¬)îUu´Þ ÏŽ …îh hí@ðÇ—/v4¡–J}3ÃÀOøÛß¿áËÜïŒm#t©P¯¡Ô=ߢ‡ ÷&è­èÁÀšb­¨¤Îa¸5ÂÆ÷­A°�,íRà oõ'¼Ñ– �Þпü‚åç+~ùׯ_þç¿ãoý‚/4|ýƸ¬+Dôà´.„íÙ°m[œ#@v 2­s†kžý~H9ÅÉ6ƒ#èºkzÌ7#ïÆ˜ŒíL7Gâ4�*o”†± Ðî˜î­`\ðmnµÆ†xÇ3mž±7æqpv`„sà|wŸC<âžG†¢{úºSø7ã}3þ‰Né´Vß4výÙ;Îcÿõçö{öçÏØôö¼÷øÂ_~È)®Á@&oáùWÞó¯=îáý\þ×¼ÿÜoÍõ?\Rh<äWÎ:gKœ .±/¼ÜHÌõÝç ¼~×10áÏ[2ǯÌâümË_"ì !Ï�£|OÔêü·fç€]sv*žþk™~û5§@À+”£“2Y %糌ܕÂ49¿9Žc-JJè"höÚïy4Ò4m”Æl£&Þ{í2â0ŠŒù çÀÐIÏ8×\|{ó hïí­ÿèÞxçaïúÍSNRýiÿÌ:ÃÙeö­'¼¥åòþu2°WNÂÝ|¦pn´k²„JÈÞ`°;|.aÐJStòiBž¼þ¡nÑÂ8`çV;†”�Äv˜!)g%KµÈÓTàØi»9®ŽºYtf[Üp¹ÍÚ”£Uöt°o%7Öe%§…’Wj^©â%v<W¢#ݦÝÀr–J8D /³D�ÜP¨CŸÁ> ì‘¢ˆÌôÍMÐf -÷ÃdÅÖ¹kΫ\|ª×:¦¯AvÃK §€Fãg[K¤õï"â>Ö¿VåØ*PiY(Kb‘Å �RA�¶”ee½lîpš8eB¾õçh”“šh~8]"ë¥â†G‡­‚5Å|gš3Ox 6ž §t=`ü=°¹õ¡~ƒß»<��çM«º1ÚÁOß¶L º{ žVh<=WT¸Ÿï|ÿûÏó�B´s­ uo¯ Ú¯�Çuá,„­£õ‰��¶"Ùû­dÓ Emoâ%KAr!å‚xt9ÀQ+²ï B)b½Z’éÁ­†~ÙÔᇕ%Ì}Î��­™Î nÐ ÇJ­ÚvT+VÌèí~lpmKåšvi|, ß}zâ?ÿð‘ß<~|(¼>ÿ;Ï_~¢æ+ºî¬RH ã!ZÝæøTLç—Ô¹×DÓ•vìÔë+·ç�íùFΕ²ä’¬d°ºc 5ÚQ͆¶xÿ˜TL=n´Ãµ ë²PÖÖ°<°¬|¸ì4ö½!rCõÆmW8€Éé2°Ô�þŽ;a¯KÉzX¹'!yVUÐ;)pç9¬ü_†�A/årXöÈû”F5‡æåq“•ô+ëÊe]�æû~ ÛÕìM"Ùl4î`9¸É°5j2>®ð°ý†ýÓØ„Ñ´œ¼Ü\×FpÁ‘Íøßt18Zzh£‡e»Ø” >½\åpö �’CÑWC}¯š±þÞ10dËà0q‹N�,0‡m\Œ/4 Å™#22’“°b1“Õ9ìÉA0ÃÓ Óƒcþ“|9øÒt ¥ ’�o ~s®‰þ>½œ�rLŽ�Y í÷ì÷8+ŠLˆ Z«Í$‡G1�Æ §MÝ?«‹ÙñŽzôk�ßãq®ôk»ë§FˆÙ¨/“#±±ð‘¢=ÕµëÃå4\ç våIa~Gᙃ'hžÅ~ï' ã�"Å9nâkó|GšO0&ûn\ŠFgJê°Q™ñÏXO¤5!'uÜðëú¹So‰t"k¤÷s<#ðüýŽè×él.òA‡3! ¼î½Ê›âµ+q¾+}¡Ó¨˜gÃDZä)P~êzÔv\Kì»Åœ„1›ÆXáÉ'6.‘ÉÕ+cL!­8fƒÆ„iœ¥».þ·g�ˆ' ¢-ÖH+åD^ŒAm·ƒm?€Œª§ØY?{ÐDÓ…æFyR�80ÁX©Ú8ZCõ*4¡µUåaKKJ»™ð‘"�27RÚ9Z⨖<ؤX¤„/JòÌ�Ö¨íàØ•ýØN–†,À^áå¥qì™íš�¦´M)ÒHª¼>n\¿|÷1ñÝÇL–†/í™ë—/µ‘?¡ù‘�ø/¿eßnÝyx|âòð}x@ו?üÓ¿òÏÿô¯<¿¼¼ª×‡]\¸AÌ"årgôf#1zL–70Òiÿ*¨VRJJ4c|Bl`\%AÄ QkN„×·ÕÀ% Õ™¿&g^™$ Z¶º±–MD®Ñ©3Ñ3<²9†#9” Ž3Ëh¯‘Eš&ºÐ/ô=ª“(|Çûs}Ó÷ÆÆNe]Üc�y�GHŸ³á­ÁŸÓžœ(Áy|Ïgô¹ù×ï:²ýúî\žxæyŒô½?OVyNûú2ÎÃÏ 8�ûN�“1†wyÛéO}ç·Á7ô�sØÞÿþ½c˜´?íìðC•iúº�§Áù+ocÁ¦1^;dîä‚.G°ïØŠÆIżߦÌ=IãÉ:Ÿïg9®ÑÉR»»M›d… 3úxg@ �¯�º,7Íé~�ß�õÀÝ5~ú6hK¬ì Éå4<é8öö‘q—®ï3Mú^¸~¿ñ7�SNЄ.w>Ýé®Í×"ZJ7Öµv{°G‰åµ¯b‘ÓGmÀNkÍÒ×=’¬äLX“üv1jR“¸JËú‹ZÙmzÝ7'�9tzʈ@dTµyí#-×£à:é yjrö:$îè’t$´è8Ï]$m‚ÿP¨�ŽËóžŸ ‹6¯ppLÓ×LòL)Çž‹qjß÷%6´äõÇ;œíx,Ðíú3Út<¿'rÆÑÀº0êNu‘‡´À j!ŒIÃ($Ji®Ìô¬=²ó²4UfmYwû RStJº�Ja¹TØÝøÙà¨7’TŠ�¸|\ká8 Ç!Gò&Ä,å;öܬwÍ´öê²Po|Øj¥Õp6D¤}™ˆpàk”ÿ©r�ˆhö€‡ÁÉúj¹ƒå®Æ´Å¼Zvcã0¹Y³Åª4ƒ]*™²dÊ%“¡‰g’º\U›;(î°(4-42�LUs4DyÓØ¼÷W³~íêa2±G"_¢êMM³d„BM+š/´t¡ÉêQðÖPzwdjU&Ø:G'ÏNiÝ�-“wzž2xû< ¡”A�‡`3qü˜‹Ë:.÷Ï“‘5hð,Ï¥Gô@µŽ{á2Pç'g¹dÈþûÄ7Ä�Öõr�º· ëÄzYX–Âv»±ÝnDÖ°õðùµ 9“¼"¶O¡m�*7ª([Rž—ÌÏžÖï(ž–ïXŸàëëO|yùÊöò…úåB[WäÉÁˆÛ~ Ù+ìuÁW-Cc¾²¾òü¯?óüÇŸYÓÊEVòE)ˆe¶)ÿ±I´ì{#µÉVñ ÉA+Í+û ò!!�Jƒ¼“ä©ññ’Ñ�>|��_-àñØ¡6ÏæjP�Æ^•í€}Wöýp,ysÊ‹ƒ­8Îɼÿ¥o�¡[ÜÄå“”ü<3ë°dË>ÉËBΙÒÄÊù9.K¢,™ËcááañmÒØvá¶^6ç�)Ei;¡Öƶ+zXY�ÚwZUk²0²ô©žYæŽ%q™,ù|U1>”¶UtI˜�Ü(”õ¼ªæÄ*Þ±5’ZψôÕ³ ̦�Ã&áBn{@{§-.ãEÆÁɆc¯±^B)‘IÉÞÇAûz ‚äLtš¸PÐbòj?²SÏ”¼†ñ+MC´ì’jl’69$]6¡Ýg…NÄú¤�ëé Þ8Ò ˜¾à³XmH9¥&y²¢Ö´":¼”ÓHúlf&&ÅèK`ˆ: Îâ†d6ÊNfÛ±q‚)úÉßÔ£¼6·8hj†Æ$&œï÷¢3ÊÁÀ„(w ±œ3r33›§ôoù&gHŒXË`&ªíÍïã´±ŒF�B®‚’3|iâÃf¯„Q2yzªâTÊÎ8‡ãÂxŽ!Iò61"Ûtgü›äBà¸DªéÒdÞÅša$kˆ MÅ›¦ÆÆÔZÍþíkŒ{-kì5ÌÕpa‚š¨z�Dº¢Ùd¬“™ÖÃë>èäÄûÔdF\Ìs“ŒŽ©ÁØ«6ãKŽ29xÄÁPRGÐVc â¼'Ì«>s¡cç0Ö“2e-\yY8ôàØ6Ð *s ¬àõQ#E·E§,¤Uº·î•íØ­>±7 C/ÀÊ^3%Éɼn¯\¯WR.®¯qhè•r¦, %­,y%•…RT•ÛvåØ^Ø·Æq줬^;Ϙä¾Wn,rá5]8^•×Ï�%)øú¸óõÃŽþ§~øî#KÒþ¾¿ðËOäz½±,¸<ýÈÓïÿ+ÿùŽ×Ï<è+O?ðôé�÷;ÖßýÀÿõ6¶ëϨÀë¦(…&/Á£(;J#¥FrfG·ÓDo‚ä‹l¸\-ú!YÝ^ÚF“„Ê ©!²#²;€+"ÅáŸ:Í’lÆ–C�ñ¥¶ º ,Àbôq±°¹“Ò„€�m�‘Zú·‰¡^;7hµNØÄN|çLUG$Í`�“RÐi®e„óy­5ã�³Gb0™±Ÿ'¾6Œ‹_òvRý{�ÿ˜O›Ç¦~ã)'7Ù›IN˜ >}‡/tÁ>(šB=,ø¦µ�û,ˆ%GÄжàö­Áî ›Ts¤Â²¬Þ¼X¬à‰Ë½Æ}”,P³P«5Am^K»ÕjjG„+C†/3Ðá¢Í�ú>šIÎéW/¥f%œ‡ t"CàsZ�‹Që©7Åv—¥$u™nø�Áˆläæsò(¼I™‹:´ƒYHŠH"‹;×1gûÀË™g)Ö‡(2ÜÚ˜·šqöMMØ‹Ã:Ä…(ßÛŸ'Mçi7ÇŽḠ¸n'Rm »`l°:ºþR®]oðZEug8º¬%5A[Ðe%çÂ¥dT6ŽºÓŽ�£ÞX¥±$3Fh»a‘ä Z¢‰}Ê’AÉù] y3£›j¦¶ yƒt�–¥™1ºÝ H‹ï™l²?&ÝG°ŠJ¥ª[¤~ˆð3ŠCAš•»40W”Jã@9zi¢F¡êbY· r^)k¡\ÖÇ‚¤Jm[7pj³úÖZ“œ) …(÷T�ÊVÙ -yˆ—qjµRa·Þ î8´ò¡™Wǃ¤´ËB §Àä8:Ov{…$+¢ ÂâÎ+ e½%6޶±×ÝyÏ×�ªJÛwê±³]olÛ+ë’X–L”˜,KbŠÙ›^¶p¦¸Q5"ðCÖŒ�´3ép Èä¼ñšØ*!x�mÅzt�GÍ…T€U�%ó°B¹Tê×+¯ÛW®ÇÆ­î¤bå^zÝv1:IoÂÜ*^ŽÓC†ÔÔ,Š^¢©ïÕf½#h•Ô"€±QÝ 5Ö»!±ó¢06 Z×¥§à1>ï^N´Ë\]c iоSËdpâ3à=Ñkß«?wpÈ‘±Ð%ƒ¨¹Œp/ÂkÈU}*3Sn$=ö.¹ÍœùX8�ª‹8jô;‚AÃ~ì�F¼÷e#çÄšß=<òñéŸù™_^^Ü–d�_’=cJ°X�ÿä%Ùo<ÿáþø�ÿÂOÿø/ü§χÏBb�2r 3´�X÷5ªÇÕz¦”�¬˜yÉð)«=*; IDATÃÇNËi iÊÓwðp[¹}QnŸǵqÜÔhu+l[åzÝy½)/Wá媼¾îì›5’N©¹\htI¼‡Ã(¹à{MÜ ìBgd v®^zÎp¼aó%eR)°®¤eårÀ¥Ú"JY„e?4l·®›÷ š%É�¾Â~(zU;ÿðŒßßÚZ= Xñ/zǶ¤)64dJ²¾Qâ©¡ÔÔhKµRƒŠèV–Kr¹9šSS’7ÃÎÙ*+¨Û EÕš^§lÐSs¸§1-“¥1ÛJÈ�¡K×vPuŸè™÷cPË�ý4QÄúR$„³W½D_ÐÁãg.{EPcмà" MÉÅÏã]‘MÖ)aó²Oš½ÍeØ–üéáˆ#~êÇ öñ^ª3±QO>”Jú9¸¸Ðܸd�Ã�±öúѧúc“R8x8Q“͆bÛ¢áƒLÛ™W§Ÿ»bäGSg6v[¬‰:cšE]h È€UsäÕ0Øéüsv~q~Ÿù`V¦CqR7„˜€3žrâ‹ÀÂØ5”y{žLÏî7›TíþœÔײ©Å¿Ø¤Û4.‡£4Os—Î`Ç:ßá“�Xœxö@u›Clža$Ò Ö:ÁÙª0v÷†Gaµ®õTg.+%&�œcs†CIñúë.ÔD ¶(¹#Ièþ s­‘i̦Íöœéœˆ†Ñ!PõHºå‚SÀcÞ$á-œ`¯]Lô&Ÿc6ãûåòÀwßÏã‡'šþ;¯¯Êâ/�NÒì Õ˜— þjé]õ@Äj­úË ß*ÆÅ”¤ É_Ùœ™* •lB®”½ )£óÈ%#R0ǛТñp5™Ü%¬ÍX½)UÌ‹+-¡‡�¹"í…Ûõƾm|ÿ Zûdr3§É²dö¼<æzÛÑåÂÃÓ||Ì”ß~âz½òùç~»ðiýÈßýö·¿ÿ;²üÌËóÏì5ð\&L¥g±í1!¾5¯iÛ…q\ŽôìÀ's¼6 ñÈi®@WÞ'Œži¡ˆEvc}m¨˜”Äk¶:¾Œ;2=§‚;àlQ=òÄCÕ —Õ…“Ù€ýmÇ€ß|œÎ»fNËç ºy:"¹r:�Žr"G}ޱ·çý77hŒôëÏ1P`ÄF�•±ØƒÚ¯š&4}|K9þÒcâ9ïðÉ·ð:ÓúÓïÁv܉çõµžxÙôÿyçã䈾;ûÞ!ð­aÝßñ��ÿ¹‹Ææœî1ôO§ï¿¶22æñÇߌo`Ì {fžÜ麯¥¼…SÏ€Ó7užÚÝ’†q.ÆsJßG>÷‰µ}ÿiãþÃs¼ß¯÷ø2Æ¥®ÔÏp9ãWÈ6÷¸ýÍLŠÎ`ÏóŠ�ØÇÑ,§åéÛCbOÏcœ¯ ¼9GþÜ×�¥u,’©¸Ñk® 1øÃݾÄdWš+ö­qÿ$⑊ž¦.r 1…Æ"°öÝ2 Â(.%gX@R¢æbõf½ü‡Á›ß½GC‘s9G5œ0zLçjƒÁð¡ ƒôÿΰß %*^! %ÔwNkÑ�~ãpÜZ©Æà¡6¸p DDžjÏ<+Fm_�1G}�ÁôÆKæ÷æcL„¡ª£U|¥�u‚ýþçÌÖ‰^�¶s$ŒúxsŸ[_[5'OÈêÎ8‹h�0¶¾ó]¹îï4TÌjªad˜fš‹ RÈJmÔ¥¡lÜŽjú˜RÝÑz…cE6 `¹¬ ’W–åƒ7ƒ½!í†ç�²–̺*©íPµ—Àå0Áöcð}e8ÀEŠéÕP±Ò�Zq·�¯Or#k5K,8FÅêΛÞa¥•¢.³E�F çÚ�ƾa„íò 4F_µ¿‰ *[;Û­–}±Íj’‹x&¨; I�”ê2VRmܶƒëõf¥Ÿ<¢½úö'¥±xÐQ6ƒ X›\?hÕ›Rql‡rÕ" 5eʲö†“T—rAò‚b¥ŒúÎWPÏvFé¦Â3=÷ucèðvß‰ŽˆÝÇ_̰¦nÏ5ǨéyÍ{0ÍX²°‹ðmš¹í�—×�m¯#5Ç…¢ÞÿÚöx+ƒe¥L†þÙÔËß…QÖu9ú{²ŠºÍôێ؉�Oy£p/?÷¹ý0�B;í2È(9ã,p‰Ì2w2(ȺP3ù’Yê†5P®ZáØ*ÛëÆõåàõµòò¼ñüœy½ÞØ÷F­Š¶�º›�4×Åú à zó¨íüZÁœK^&/ö‰4÷'H"‹U€(©�S!I6Cµš°ŒÑ¤¤Ò‚gK½³2DÖ\Ú„"ëwN�£*›$Rkdà�FK]8¦U� mоA0Ú¦0,–y’tÐ9Ô‚r+•Ò”¨’®!ÇÎ9µ¬:µ¦Ôê™Xξˆ9röÈT2Ë#äÕ²õDpYÀ«Ý`N+ }Pk!(jì/k¯Ñ: íÔ/cq˜Q™&ÊŠ@Q¤¨ï)7ðì<ÓV“݃$P²$dͰ¤$ÛÙÎO.ÿEoXuÚeû2{vOFR á‘Sª)³ˆ8Sð!«”æÄÅÒ[¡�)c@gEÇR“”aêæ¬fF§èˆ0”Ñ`Š:õ‰1Æ÷T�•ƒ3«é¿£›žÖ¨¿‘TßCˆŽ�ARÅ!„]$¤¡à2ÎT”.ŸÇ¡w¯{Àß?�q²¶Ä³fæ7�7Ÿ›ÄÓ¬lÑC� a5eØerW(´K 3²Øh#:¾R› ¹á‰ŽW(DJq%JéÎOô®Ôö5h!Ô1ò¿M네V»±×óÑIçØÑøÅJô4È­¯g#bd`cÙÔ±�éžÆ:ÞD5"<¬LD&Ü­Ûyß�çM543šñ»¹¼£ÚÃY!� ƒPrƒ©kk_´GgÄí‰RVžøÍ�¿çû~äzU~þ劲Òt¡¶-£ µÒ�VÒÀ¼ç–æms¯Õ¼ÈÑ VqGQ²Œ€œJ.”’Y–•Z�pŠ9RZÈNÔÌp>µ¾{|JM#’QÉbŒ¦9.í{eß-%šGEJkp<Óö/ìÛ�V7^^S<üY9>~úUáó—?òòù™Ú„Oß½òñé#~û‰ø‡ÿ‡?üá\>e~û»üî» OÿÇÿÎ~~ú×ϼ^•ý¨¦pL ‘&]!mûÕ½¸i2hˆ•dª!ì#a€ÕW=—"ÖŶ‹EôˆBS«q›RÉhµ=Üð&€ÙÒC#*Þ‡1‘O7‚´õÌã™nï•hvwG§Þ}¿ûýîÕ±†seÚS÷äÕÓ™þß3‚éˆghàÑP¬ÆXP5GxܧX­�>’’ÝК3˺¸èMI=í»¡5ÒÚ¥¿ÅË,‹ŽÜHÕzpÔê ûRî�F1—[n“„ô0 :­F˜½ü:7LIÀé½½?¯À9€)Fñ´wsИp%nìŽ�žU}6æ‹¶Þ“Gœ—vØô¡šÜ/.EY;AIžÑ Sü‚Ïô¹¸ãAæ÷6þöH{¼eŽz4aøêã ó.Ï fçD¬Á�'zЉë|ÊìÀrcÏÌç#Z>œÝ é 7czî ²¨ºQ¸?¿5/Gò¾ë(ŽK˲t9à¶ïÜö½ã%ÉdzQëE û M7ÈòÒ(ia¹\hz°m ÇaÄá¡/B®7dÏT—_U+Ú\>ÍbÚ6²î,¢öBS‹¼W*Ùá~^Þ@¼o‚µ´º#¹¹Xt«º“—#øCP-˜õ•kß÷£ÌŸõhh¸!D¬Qq.Ù Õk8Óu³ê}¯šªÃQ: 7ð†î¡j{ýv½òœ3Ûv3y±™�Óš|I—½Í°oÆ”3Rš­kKî (HZÝðX Y§­d±ìÞe½�e%%+kê$ÄÊmäìYî4 Ã…CwרÏLÛ!µˆŒO'è¼/ª`V›‹�ÁÛ~¶JmͲ²�¡¬dᨅëMy~9Ø*´f‘£¶F†nkQ >J›ÜßœÞt}TݹãÎÞØêÖK@™· 93 vc©=ОÄÊV:àRÕ«4L<Ètˆ;ÛG<ŸÓSÎŽiÃ$¿§†Çß¡¯G™äÙ9ÐÇl¸÷õf87¾%1›sÒCŒ�æ…N܃[eÜ»‹Ð�|½Jn|48\‚Åæe><]øá‡'öý™Ûõìì{µà¹)¬H5±–…u½˜Qô¶s´Ù�Ú”}ß­W@RK,Á‚àj5½{WË\וu])9!ëzP¡—)rhY¹ �Z�^~enDk4 :O÷u~JY\•1>”³Õç_JvÃ||Eϰ²+•ãØÑv˜³0%¢?†´JÛú|å_þí3ðÄR©mAÒM•mÖ›²ÜНt6\K2ì á7O«°~X)iayE_®<=~ _”F/ç[›—sIHrVÙh’VÛ"ÖÇá²�><"dI£¤Ë´GÄmËz¡|Pô0ºG+h[`k´×ÇËÎöuçõë�/_/|ýú—¯¯¼¼Ü¸Þ6öCi¹RójælpOÙ�V2©KV–Í�>óψÛV KZX¤�ÕÊÝ5Ž$f$Ï Yi ªÀÞ*‹…ÄZ2‹¸Á2ÓjƒãPvilzP¬šÙå æÑ¯"l?µ6ÚárQk^mWQ«!M£zù4=•(±O´r4%c½Œr²L{ƒ‰÷èÕ•{ƒa·{Ä^u¹-g±’DnøÌ«°~L,�…¼.–UÑ �˵ÒÚAmf/ét$l7µu¾ÔêhŠ\ âšæòaAW…BÏ@­x@f—ñü•r6§À’‘µ k�’aÉ=«Dò,xÎÄÑ�ØÃ0hëÐm:�ä$$ž>û6TÁ(¡ ¡gÆ¢Ó‡`ÎwŠ‹ˆ"å-ˆó¬øœ @'¾rwôóDûæxc�~Dþþ7õçâ® cµß¤?'ΑiÌ÷ÏcлŸæ¼3‡1¥w矇wGüG½»ØHf4²¦:1ÓÙ¬3jܱY�E¿ƒk Cç·pþèˆÈ.¸—E¸\¬�Žº@”Ì¡àõqm3·Ž;­;ƒÒ¨'×a æèxÕ†Ð0ë”}lį6GW¶†G؀檧H©þ`�–ª�GtþDD`àb?·s+áNN"Œ�‘91:-�;uœ€õ(¸pøˆµg{D¡_k''àÌRóh4ÕFmÂQ¡VAÄ¢­ry$å Ç‘©Õ¼ÄûqXD�&RvÊ�,Ñã‘VΪ >ÃëmŠ­â�’rBšÍų�<™§3åBÉ&µVOÛ’TÈyeY.žÂy éè‘'y1 )K!K¶u÷Nõ­VöÃz)lûÁm;xy½QëA’�VwöÖxøþ;ʬe!q�³¥“>< �¾}æçŸþ‰uý‘ï¿û‘§GaÉ7gXIÌkoÆŠ…ª•ã°¦ÌÒ•é{ݬ<@ÛÉÐîP¦jƒ#bÎÔÛÝ1Ù›@ڒצ5Á@ún ¼Q÷+ še uÐh‹¦²:¹xŠuìZËZ@§¥ANߘÞ'û`7¦™ž b±Ñgâ;aôÌ�:š¿zǽªã7½‡Ž ô1Çøm›ÉiŒwÖ®»ãÌ´à~ìãüY zKKÆZ¼Ý˜4}îó¸NcÕîðÞ<îÓ½æsuçî²)¦úW˜û}Dôûã› Ñou·hÿmÀø?vĽÿ¼!ÿׯŸá3;Þ=÷ÏǽSiÆÉîßÝë½èów“ûïþò#véY´|ï9o³iÖÈÎ*½DÖŸ»Ç›�ë:í�þÛ›;�{L÷T=ãb(÷ë:;¤ |.7Šâ³Gc2AO‡dß´Õ&ÍìB®¤—Hxs‹¬ÞqD€Ž ¨$²ß¯�ÍrM–SÈÙ¢³R§~®�³Ï/è�Œ[sÞÆTêlʪ´¦pêe‡B&»£ £0øw˜Æ~¯½,Þl/”iÕ.¿ƶî˜^I‘fN”€wbD Ÿ1ÏÂHîˆZαւ%[Œ~…#`ú;Ê-‰G€õe�7¯€Mw4(DÀR7%jëfy>æ }Ò!cŽ,¹aX�ñ¯¯› #¢ö1øóï¢wjòVè`QŸ!G´væmªJJ ’r.¬+ìz£VSr[ÇŸi›—(¸A½’Ž åx€bQ÷)[Jކ’µqÉ…ï?\øáqEøÄŸþô™Ÿÿô™Ã|Ô&âFÜfô*Ð ¨x‰ÓÈípg“ŸkÍsåÄ—uœÖy¥½MЊ¦“=§_Å�â¯ã¤¯…Îb�0£õqTöÃ�ÍÊ$”Œ¯UõÇNÄdÍÁF‚E *ô¾MUùúüLÝw®Ï/ìûn�ëAÂâï¦Õ 4£Ìh›°×TBéѧQRB'£vЩ\ ©¶CøúÜxy…×+4Iž RÈR0ƒr¡ÛCb 2•£P˺¶Lëáy¿±O< T?¬ž4¥Šõäè†y× g9`–‡Î¢‘kß^ аK�ïBù=|ˆ>ºæÔ·¨ï�в[§!ÖØst¢!ýÚÉ:Ñåÿ·]Ðóø±©ë”³Jï -,�+ùÃ…äŽdm^G-ñäü7qÇ{N¤Ë‚\VÒº Kñ„6 ¶ÚwN7D)beœš‡Œ·ŒÞÍ…"�¥5-”taÍÊ"öÊ¢ÈëNÃúðXvÝ^ºÚç!N‹ÍŽùI̘_r¡¤…,…¤ÙMh)q$A³ÓQ«·MV%ÕɘNd¸¯ ‡¶‘éÔ`uæ‘R¢: V´h§×–á¦>¿vvÄ�0x)ïæö‰tÚéI•ÜÄœ%{0Æ´‹#(Ù2³÷̤ËW9[Cî”Í1–˧Dù�IËJ*^~K ;š—mvÚt&œ!zÕjM‘-3Èdë,$¡Ý{žJYÈÅ›8§dýtL`4\ŠÀlI%!%#K6¹&'È>Ö2dŒß¿îrø™7ÄwCQ“‰2Nòx¿¯%:Œ‹üçÇr1 ¸b*Œ,z¾Â�3:ã³bJ•ô¿çgv>a£Œï¾ÚÏé˜~÷˜ÇÈÄâùa Lé-[rÈÊýOçózÄÇhB�z§ÜLü®SÔ·¯Ù[9�!ÌÆ£a‘æ+ã™�+âéÚw¦±‰?¯›££LNŒ·¦Œñ÷´k±Ô§uM<Á.6´2Åsá)”-�à-§k¹[Û€YˆaÓØNXãXFôF½A�EfYê› …·�aRôºTËø:„Ÿ¦‰v(×[cyݹm�Z¥ r¡¶Æmky¿ƒ¤Å ýÁ29Û³Z³ÈˆZw‹Âj-�ËJYJÞ÷cc?¶®à4 O‚àõæR&å…h£#—Þæ–„œK /ÐtAeÙ‰RfKÚ"$]H­X³»æëÝë> {m¼\7~ùRIòж+u¿²~xä‡ÿü¿òáéõùn"ª?üøH^~OMWþùŸÿ¿û]ãññ#9m$®W¹<²”ÜÂ~èt2›i_]dVñ:sÍÒƒ{¶`lßÕc§Ö�’K±ÈžZû½jWŒ{™"Â(åx“,*ÁI+âY@fLòæÈŠ;º!'š�ˆ½ïFeRh':¨oßM¸Q?õ޹é|æL+µŸx> ®m�ôLÁg Ù÷¹ó¤!pœÿ?1@“‚'þ@ßßcl†>÷ }ïÓþsùÞþ~�ÏF©¾S¹†˜OÀmŒó[†Þn`²¾�ô~9f9èåðI~øóÇYNßýí‡ÈÙ8þ—ŒâÖñĪdý½;¾%[Ä¥o¿Ÿ{ñÜ?7´éìwÖþÛ81wüÚ¾õ[¸¥U¢„̆ò¿ÄÑ`r¢ó@™ÇÄ� ¾õün z‹‚ï:˜Ä·i ¿¡6qÛYN˜~œ�ï;ÂÐ5íeÏÔ´¬H'¸xäž*©ëwO—yœ®ˆ$r2Cøhhi2ƒñç‚Lc;�¯…Ñ'ï|]»´`¼$‰EL&HYÉM‡²ðHCz¢‡��r0ê4ݦêJ%xzpvÐ÷P8=â‘[Ÿ¯9ŠÃ#wx«NM䯒éÛQº�¶S@N/Ý3±U]i^ fÎÜ;g–‘”Þo­÷ZÝÂ×~¬q—0ON�Ô÷Xs ŸúÉè{—ÿg9Ô�Œñ ÆÉ¨8 KÇþz]8œBpºìf# éøñxÅJk¨§ƒ¿´ëš(Ëbéþ"¤¶"mõ€ 3€5=�™„ê†ÔrÜÈû %³xƒÌ\ )êf2ÓZ2?~úÈ÷Ÿ>ðô¸òÿÃãåçÏ –uZõp;S¢&«c JV «Í ÔÃP’׊6zåQìÍ䥄ËÙuÚc¾–V6ÇË<¸3K´LkB¸)&YÉ“£ZÍþë~XV…ï�”¬¦zPGó m<Â<ÐÏQÞ0Ði«9êqð"BÛwÚ~�S"'/ã2¥!h4¯Ndò(ª…ÖšRº°.™œ¡Õ·ë ·í@ ‰%‡qßë6»Nö­yë¤ä(õ䎂œ­DisøFüZòÞ)­Ô‘µÖO0Ô %2(¼_Ak=xMëU…õ70[Œé%†W ·›r»Už_”ë–­yi)DùUÉ�‹îµqØz%¼ÜQn)œ–÷[O⤾|¿â™ÀVçIßÓ;yì´�'YÄödì;òK¦[†šÜ�‘Ng,�ÉhŸEÄÚsÕׄÐ]»Ì;t„�Oß8fy£—<º“aÞ“ŒC ¾.V_»%§iãÚð¥Æ“ûêG¦×ýSÃPŽÒRcIF“օLJ•”•Zo,—Äw?<òõEÐvCÓ…œ—NŸ«šýCUX¼?À5í´¶±Ý6®ÛÁQ•¦™²JYØ+ɯ»•*ó¾~9‰Ñ‰)(‹v í@ëî½²—;Ê�³E='!/VZÇt£j=3Äá5A;,ÛèØ7nÉzõLò‡–œ­Ä‘1S/óèwZ-B;EÖ�Ù­,‹®Aj|¹î\oŸy½ÝøúòBÝ¿p{9h²òñVØë*i­r\_øò§_øÇÿñÿr´ÿ÷ÿ•Ëßô"VZ%šÚ[P=²€¬�Ÿ åûG¯ÿ®è튾¾ØÉ^ËÎÊØ¨½2¤’`]H䲚wUNË÷Œ÷Ýslî2BØkªõ!ÐZѲAÙÉeçamÉ\ò…55ÖÅaxÛ”mÛPYœO—¹ŒÆ�þ¾kTFö‡Ó‡$BöòA9«vÑ|_$á#‹ûœƒŸ[ÂWjf„7‡ñä˜5ë=ì {ƒ£"G%ÕFñífˆO^ñÀ6[u:jå¯è´âu¯´½rT·©9m‰`ØY¼m$Åœk2‰oqgfôÍ,£�+�«•$ÌJmG;HYÈ%±¬…².ä ùò˜ß'νxÙdÛ}Acêa¼Ñ‚W³õêØj=Œ'ép Hx½r±>šfßJ¤’-ƒ"dÝ¡ =s;[wÌÑ,§CO2Ýù�óy§ŸBf{OCç–S_(}÷¢··ÊU-Ư' Œ±d,Ç¡¤†²Ô¯Ô‰9…A†i©Î“ï¸%c<=-”•>^÷ëÞ�ßÓèïàù. Þ3šÄt0Ã87T¯oÞZ‡±ßäÉx�;OݼgÎN¼ÜçóNiÿ.üÃY�˜çÒ¥Ê^7P;á/E(Kâ²Z*“*´Ú82¤v1EÒ¢Ó�3ñ„Px⻿+à 4½Ç:G}Zì“[å‚ \ î K¸Xzªvó�­ x¨p‡ê6p«óZþO±üÝÅñnà¶ßSH4¢õϪãœhÔpó›ê¬ Þí€îtRè¶My}­|ùrãòðÊõÚP-ÇÆ¶UŽ*nËPh IDATÔé\Vâgé“7™M�ðåLöfÁ€(�Sì{u/©+ŠEÌÖšP=[!%ȹyÞæûÁ¥\VRˆ áÍi‚äl‘jÕ=ù‡•8ôÖáñiåòøDYÉK" l·ƒç×�­ÁÓv …õñ‚,™Vw´í<}ÿÀåû…çí…ëq%=(ä�å¡ñô©pÝ®¼\77|–RXW+ËTRæz;ÜÓl=Ä(“•Mjžm‘yAŒº0Xw–²òtYYÖ̲ ·mãëË+ûn™kLöú°£YM¸�® Í•ÒFòò�¨ êÑBS=äa´?ãÖ ½wô¯3ˆi¿:˜© tøŸ7 þã^wû @Út}<_li26M4ú섘Æ=í§ñLŠØ4{l'hÀˆíT@ƒVÝñ×~ÿ€§ãÇôÌ0 Ç€Ž÷>—˜ÛÌþÅoμ«Ïvâ AaÎæ÷øKwCMÎÛ¿€�¾;xÓãgR†¾ùí�|ôö´óï^÷{áÿí›ë»ßþ­Ç}4½­¯tºÐq;Ä–Ó~ |¸¿—žþîï}Mïáù+³¸?ºQëoδ˜÷n„¾ï|ôLŒ>y÷Üþ·Ä8gYóÍ]'²ãÂú ¤ÿ&á弯ý92]Æûa?½3X¿‚ô9Îz�é ‰e±¦€ftÕn,벞DDWòRѾ—#=“8UºÁ?Àrwër‰iPÑÄ3æ„ Ò†É„�©Ô F yE»’ "*#Î{:GDðþ<.YiïQ} \tnð‡xõÁ ¤ìujçõœ€ôÜi†=¿M÷l�Ww'€4�ê´}Έ?sÑ@¥™†Ž‡Ë´Ÿ¡Ë{P@ÃéBæx%�gT ã{Ü<äß¡ÓMNâ�Æ@ˆ<ë$­ß#†â&5W¸-Hã€Ãy¹ H�d5ûI‰\}ä¨Ö¨¶©zGÌ�£­äãÊm¿ -«­O.äu¥ÕÅ é·mç8*4e- Ÿx‰úê±­É2ªËA4íÛVâ#¥tG¿%Ô²,�ÇÑ@œ~kî2}¹ 0c¾•Œˆ¬—Œjº„¬5škk}|Çá£]S²õ¬•v˜\)%úoøþmmÈT½Ü ÂqXŸ0iC�JÙkM·ÔñÇ2…ÇuŠÓµZ`ŠÈBÊ™R %HÉ…¢fûèUá²èIæšd3µÌsT-ðHÒ”�¡ÝéˆD/íý¼ÂÎÄè™—/³¦}[¦ÖíÛÇæUq‡‹fZ˼Þà8Û^P,j¢íê:]dTÇžhžàsjF1z¿ÿÖ‚`%‚á£Õ7wÝO[·‹ždÒÓ®¼4DÕû³‡Ý#R!KL2…Ó�î¤8Hý-äÄ áÎPí3ëÔlÛ<òI¿?4pfú]£ÄUî5·ß~_³,íÉA;ÑbÅô°ÔF�QÊf\\/ M¯·WÖ%óáÃüûŸ~2}I„”J¶ ºÛ¾ñúzeß+//Wx~~áåõÊÍ3"ˆB›é¶4¼š•R©–E%s6Zf“6ïùæµÆsÙÂ~ÜØŸJÏj·Ùˆe„Ýq¸”Ñ2Ú¤n+h‹õ8HÙëÐ'RµÌ‚êkœ¤XÆBÊdÉl比”íVyÝ,z¿VËH¤.|8.lû…íºp{N´­R¯Âþn¿ìucÿñ }ªÓîpžW•È®Jk!=®¤§ó׊´†ìâ™�?š—Î˳X™rŒ0ƒ™N¨2xa7ÎwüwÙ+WÈ”ƒ´P[7ö«�DÉ%ñòz˜Ý…BÓBÕD%»\fŽáAã\ÿs×)xãb±ˆø$Ùì42QAÈ“ÓÑ;\J3L¯.“UsÄF¹TOÎÍÀAsºZ¦jô—©Íz@ÆØ÷Š—D«Þ³µ3ʱMDU_*¥¨7nPD)%³a]„‡KárÉVÂ*ìË RÊE(—L¹òc†'E/x#ßÚ3$2†Ô>‡h­Ø«Z¤ÖhG"ÕÒƒ r\¥0z2bU2"³7 ’‹áÙtÿñ9^â«�ÝND½ãž©û‰ŽÎ"ìÀÞwŒ³Jò¦B}p2}ŽËeº°G‡† l!ˆÔ`D!h§ð–D=ÐØDq‚j2a¬@Ó^ï®.�@ÿJñ¥#VüB`€F�TéÎ }X:nüàú7]9`òRGÄsÌoœûmcCÀÒ6¦ˆL‹:)§)…v#(í«q7ô W l>æ@`ñïBq£—¡ºŽ�=–œX–D)&lUoÆeœ9úp'8Ÿ£†¾nKó†Én´wÄï^Ö4'oÕÖ‰xs�æXYgþ+A£ÑÐê5;¾#}’±º„�?'¾eZ?ÜÑ1Í&ˆŸ ʈÀ5/¯àŠ‚Ø¾0e+uØ™¤&3z�>LäÎŽ‚jcßáåõàßÿô•½¾~½r‰ý€mk� ©Ùeµ”¦ þ­™±ï=eYÄ¢µJ)±˜rÇÙ®0E_±2?>•z4jÝ€‘[OE+E‘´ RÍñ ÉQÖi�XztÔéTuÏ­DŸ‚±«JN,yåéã#¿ùÍÊo~ó=ß}ÿ[~ø~ááRùòù'~ùå+Ÿ~¡”?Ðn?üþ·|øþ‰ýë/[eýøÈã‡>äï©©’ëíØxø˜øÍïŸxÝ~þòbcj™œWž>,H*<>4¾|½²ï_¨Ça…+½´Sܪ!5cDÖæÞkÛ‹Oká7ŸžøÍï>ñãï?òó/ŸùÿþñüüË•msæïJh…® ©4$©Ñ �íüÐOÔ…©ÖNFñ°´HÅ6\v”ŒMÜ÷«:MŸöÈL£t|Ð7çÍŸåtîü霩æê|ÚþÕ)ÌÎ~IÕ�­˜Ž]*,3dH2‡Ìª‚¦B.‰‡‡ ¯¯•××Jk™ÚÛ¡l;ìµ±Õ­×´Wï·ù&w[¢nô´(19ˆT šVŽ£ÑÄû5dírrˆJöR LžaQ[84&ž]9|p– •E¬â€oµs®U7ÎH­Èav…¤Ã ¬:(^Ö)u^2zvÔf=pQ–5sY kâ²&+ï•-+¥I…ÔH ä‹P2ù!#<4ë±à=r]uñ’שӪq ™Ï2ü\^ïM•… ñ!¿uÚzyØq�PZцs/ß!ùÝéÇç7:]v>ëÚ)wßêݼòlƒ?�iG¡{ƒ'ËÁ¢û9m”q¥ƒ¡ g€û»â:ÂHqN)÷‰F_WPº§3„ÖÖï2.†ò7 S7¨ôW@f‚ôuSf¸œõâY1x À9_NÌGïÎtüÐûùÄ/2È„Pq—P"£)ÙäÅ?¡³3NðÄ€íÀÏ.c”öHÛün?<±Ëˆä bŸS¨jaX4æ,®(y« KŠ“0ÚÚ@’HdtO“0Œé‡$1¼²ÓXö‘±¨ïâB®¸ƒ isÍŽZk÷·BÌ5™Ð/É0N¬œ‰šW:[DƒÅ==•ß7tÀÛ<Êœª§‰ç7žE·)Ú&"Š\é�¦*ÚÜÁ¢g§ØÉÁ2Áe¬–;ñ:éc6¢P�Ä×ç�£=s»l›r&Ø—R(Ë9/HQNµšâaKQÃÓRmϰª©ÒŒ)tG=hÇA˜½Cñ4DŒ¸‘ÄhE.u$î�ˆ²5æðw¿ûŽÿô¿ýÈzQþøÇåËçf•Ú,É$ajJ¨Š)¢!ÖÏB´Õ<:=¦D °L™ýM!Œ*&ÅwgüîÙ�ñF‡îq5n0=dºË8«#þ:{zºŽóǽý~}óóîî&Ó=ÂH×þÚ¡:Ííí|Æåa`’a?šçê—ˆ¾Ÿ�a@JÍ<„o;Þ81#òzâ Ó‡Áýf¾4ŽQ ûÝŸßŒÓÆêÏŸ–ø×\ã¼_wTL#íÍQãÓï�ö/¹÷ùDý¦1ýôì¿æ˜ÇøðWŒí[QóßÎrü•1À¤ �½üèÞ)ð7Í7†‚Êø¢?ÿÝû†qÂ6Ì_öìíɉ0ɺ2‚1–@lÿm–AãüéÜ™jÅåFlV�22Ùjc_ã2Xò&€¦¸OëÏÅ 9åQÿÔÇaÑÃ1™î¨a1ƒ9 #�óß06jŒDM汌@—Wĵ›î¸Œ`…˜„ýmö¤Áš‚x©“¾F�Ô³!~Z�Ån�ŠøÆÈ\˜{õø+°¡Ã²i¬G” tÇN”r¡-ÁÈL;ãÈp ø}´‚4´ �—O8ÔË&i¿Å†Ä{ô8˜ùXcΔ°QKÿα„Þl.ôµ`b1†�^Ó[�í=±Ãáp5ÂGÑ#ë|Öd•¡îv ꆠìÂÈðT¬œ ²¡j88µ¤‚¦¹"í@Ún³o;7T3�Â!¶)bå.( ,š®“Î9%t¨ MÃ+!úôw }xÌþß Ò+â€Ý&Ø™;£‹?‚­Šñß]G¿ý}¿–ËÆéƒ¸Õ'/=ë-'ÕÃûpwS—~u§óG™"ñ�=±/GPý‹>Âñ Ü@®ø¡ù€j¥VÙ™œÒ´™Ój $A£éʈ«¹ÓuF¸?ê5á4™sMy DÔþ`½Mâ×)ôÔÿ?2†ýxyõËí+l‚7–ñõ¯ ƒÝØIƒ£á*±ÞHi~<Ê?ˆL/S&dÞ“™r:3÷§"ägËoðÜ#W#bgÏÅ3À{µæäÔ¶Ò×=O¼ÆèPN·,ä" Ùº¤§`ÜêLú $sÙ+˜Nú]·T̽&‡6Ê™”“+ê:¶�5=3Óá-’Ñ>hª ±€‚bÍ[útcá¬=h°Ó•$WðŒMçõû›Æâát3¥Æ˜�§ŽQ:ÄöÔ ƒp‡c(q‡Ç¿SÞŽÌ×PŸ^.Qìù›R雹ný9ÌåvØŸóz+Kûmù2oáµ"ö·ªÞ_ÿÆß/Ïû›ã[ÿÌ ·ë�.îŠý ^/õ‘É©·‚æ_5¿é�‹º«ð7G½ük_sï¼'õ28pwvÚO\û…È>Î=øK8t�}¯n/vp ŽÛ¯ùrp}õ— rký¹�c' ,µ²,Õ‚õ9SkaYï鸮ÞÌÐï#š�YÛ1³ÿ­ôÜ–¸O~Î L§�ë‘êÇLX!Ϭµßw×Ïî²5Q y ½�U€nÎçOŠ‚Ãÿ¼&Í�†Ó~/‚­o·9†;4¢šÐ$“WYî |°cœV’§ÂHd~¥]_S<˜Ásšlñ¼$3öüºó†)ÛŽYa7ïh^¹SËĆ�ùËñÞ�¹½hÐÛ¼´ìòèˆ7<¥ÎÁ�=¶îØóÈôõ˜žkà‡ Ìû§‡£¢!v}_y;Þ+ti�¡W×e…”*)%ªTr=SeÐDim³ ¹L8–”²5Xl‚ÊÉn9Ós¡¥Êº]ù´5>2XdðpRÎBk ©B2;ãè$N¾¶Ç†ƒŠõJ(i°ÔÄi9ñøPXjâùé‰çç mm¬ ·w«ë’åP©¡n×9ôáy8I)5óð¸p>Ÿé#s]+ýë…§ë•Í{¶™mmv`ÉÅèÓÍ·ÞÐÖ¬ï—÷Ö’[×›˜QW£§äv�x2—L–…š…šÅôÀ1l=4’ ºá’�fþ´‘éøÛ{ÈðàÒ¶ D¹dÎ÷grndÙhk£� Ñ4×û`™›îÛ7$«%£ŒÍ’ÎÄù›õ:³D¥¡Ãú¤ ðœ:ƒQùbAÒ:«ÃÕÃZA£©çBÎw('Ú¨\[çÚ†%så…HÞjcemÝmff…WxPO:ën�NÉ,Q)�æÞ˜N|áÆ¯4USçÕ7ÁúÏh6ó“CEªý뼓œàŽ_ÓïÃFŽ`kðÏ�×[òß|â3Øq(†n4uÜ9Ì+MT_ýǾ¬'Л߅Á„9õwÏÝÿ±ÿ©»CPd⹫&†Û¸¶=„ml«ÒGBµÒú…¶Z룑ï8�¾à¹-\×N*�\;[Ǫ¶%Y2¢ËÏ1”¶5ú0'¦x‚¥AÁ`vpìoÔ�ñ…@mˆ šºc팱±mW6Ýl¿“ض�îŽÏ1\ÞÈíŠÏÀf.,u¡ÖBkV-eAƒlú@7(¸m½Úó攵$ØBOG§mÝVšÈô«äÓÂðdÖRO¨v®­Ï=üñÒ»ÆÓ§NæJÍKÞ¨¥QË=÷w‰¤�èvb{í²qúb!Ÿ…?\øñ/?rY¯\®WêÝW|ùÕ@:HÃöq*ô¶±­ ¤SŠ�‹û?ª7ƒÍNjŽ o{å ÷ŽÉ«˜é¥á‹rÚN®)ˆXÖ~ÍpR¸l�·é;Ê9[ÿ‡*œN¶*Ûj~5aP²R t¯úoª´¡lc° emƒu3ÿ€¦‚Š\›]L.ö®Ð½¾A° 2âý …6ºKש½ËÀ‚Âhô? z³}{ƒðEf!ÕD­Åýs�7GA‘Ñ( ª?ï®Ö'(£lªl:h®©áㆧŠàDSk†Ü—ìzIšÀšÕ<Ù%RÓ"¤»‚ÜW䔡ŠÆ’�M·æÉ„?1x›Ëì{õéÑÓ¬ó³]:Ú »MÿÊ@¹ñ“¼Öÿ^�óÙ¿z(Ç× wŸ4¼sÆ�¡3¾õ²ãÊÄ9w|<îM�†O(ËâÑËo&ÌÉ~‘�hp(…œªÁ’d+oîbå€Ñ f:9Cá ×’3ñ¤Ùì°<ê‹àe�àe­ž‚?îÙ‰0ÈÁ~wÖ O÷eŸZÿd´/²ø‘q-=œÿÖQ¾É\H¢ÆÏ4$0"鍸ë|fAŒ¢2…_8ÆB7�˜T aíXaÓÙŸ¼©€'«›òsÀ¾·ó ›œ!hÐl׉ò¡¡@uºO$c\bÕ-éTˆÆŒ„†Îæ¥_.|rjΔdQî,vœ’LØ•dýcr¶ëŒá%¸½“è4íä”)9ML¼Àfë]Ød°Û M™6Lði·ÊÐ×DæfR”½b[ÆF“œ†ð…g~MÈ5×�"r(C× Ý©×ú˜zC+sênàÏ*ŒY…¥Ðº•à^·ÁuëNãÙ£²…Ñ-³gëƒÖ a{Ë:¿—ÈÅ©õÑçµ�{w6qV¯ÀP+ɱ¢¨p:Ÿ¹»»'§‚PCæÜ±Œ³mÛ¸^WÚXéºM¸‰ýîA¿ä‘ôÑk.ëàãÓÊïŸQ<-‚Ž•Ö$=€^Ù¶ —>ññ}§ýâò¥ÎÙ"Þ’VÊK…‡Ryx|ä×þšßþî+þ’ßñî‡Oät¥F¢¬l§Á©tJÚ\à™j•1,Ó¼SÅ£&»"h K#a Œ– ç¥SózEÇŠŽŠ«LPé^�Õ-øJ'E¶”�ˆÁoi�foFã¿@Ò©tßòéÉQ&ÅOlâ_�ÙBâKU?Gþå´Ìc"¶‰Ó‹óÚøü¥é&–°vÀ>æq€xÇ,‰?J¸êÝX<ˆ„ÀÇÞws 4~ê>¦ÝkfYaöÚy1çÈÂ=:éÂèÚ±[÷ì€Ý!„øñ# >¾¯ûñû›ÓofzÈæóµù²‚ïøÚ¹ºSÌËùÝ÷ö·—Ý�˜45ƒ®/ ÉÛù}fgÎfê:ûGo9Ô�೯ÿW:ÞÿrÇþNCǹ¾ 4¼øó-�æ–pŽßîûà§æùóƒz3¿—ÏíZàõ³>¤_Íá¥û€¦«…NÿÉ{nçqðQg SlT� IDATáö>Ž+©�Q}î8‹75ÚïyB:ŒP¶æÙššþS(¹x†5.O;©u¯vÄaLRl8“7ÞÌ/­G0`w»Ò:�3ƒš ]6Í�1¬ÿ�“fòNП)€"‰!; JT�Fceeçý ˜:~tÏ®’ȸÝÁ%ñÜt×çCÏ­LìÑ;TFÞy±ìÁ3¤wZ8êÀ~EöÊ £Ÿ‰¾°/¥ŸtgûõzàÁë~³cw§>¡Äœ[ç}É�Ù»®¥;/7ñw�w‡Ïæ_¡+Ž=(°×žË�ÄEc 罕²{PáØúb7þe_•n.¼’´æŒ¸ãªf¥º³ªri}l~� Í•‘2š„‘A8‘SBꡳus@_ÛJj�­5¶¶N]3•B̓ћ9Öqxk¨®D\š+‘8-™o¿ýš¯¾<óþÝ�¼ûñï~¼r¹\ÉåL–ÄÐÌÐìY�™Níä¶,óy¤$œïÎ<>-<]„ß5¶öĺm¬­y¿/ëåeA7[Ó>Ò”Ñ Ú†‘p¤bó›T'}˜‘AÅ¥Z5’dKÔi›ZE®Ãt™îh°Q3´çÏuV –ô¢8lN#‰õøªe!»ó«5wa7ÊA‡°†¿ÊÃÙ/¿z !¬O—ç+—˅޷鈢tSU³DÑðæ—QU¤8~»í�ÄA�f[–äUÔÝ}ž¤%y!å3ÊB…µ+Ï[Ÿ�7»´‰v³KZ·gRTÌðM�ªôÉ#ÇÜ—î“ðõœ°BºóÒÉæÞÝ™Ân÷Çfäö¬yxð‚=È9¥äLîôŒôàmtt¾ oG¾áJû¾§yão ž§ž s;Ç›J®¹.Ç[ºýìöƒÿöõŽúÍ-?EƒM»SKZ5G£9K-[Yè#±5akÂÚ„m³÷ÓSçÝû+ë–Èõz¥5,8ð¼²nÝàÉ4ÍŸ�5Ë>È�AÈ÷ÖÝšž›9hAðmÛØÚʺ­¬ëJ$ŠCû�B‡CôÎä5±6â¾”#Ìò�$KhŽY dõ:Pu>¤œÈ#OŸ`ï›�ÍŒÝ؇šãÙ‘Ö.HÒEAYô+YVN¹s¾úâÌy91Ú=íZéýjP1táÓ»�þúDójœO®¼ÿþe@nV•$ÚØ®ÖçgJ�»ûJƱ̒õ×CÕ¼Ï�;ì1 ηӱ³‡'9äzÏÀ/®X$ë2ì<QïÝ"¤‘IÃz2Œ,¤Ô€a"'XN^½‘­Q­<(Еçµñô¼²uÁ{_Eñ$ {]œÜö9Ž!ŒäòÙ{Z˜p3È£¡Öõ„÷ xÔiª9"®E¯†ì( bËhzfgÐH$ªCE¢¦½•4,ñ±9lÑ´ÓÕü¹–í±ë23©O\ —DZToB- ¤S!- © ªÏuê±y÷‡!óm<ä¥õó¹×®÷φì€é¹oÙqVØðGþtL> Žu{Öë÷[î©+:çàt s å­qŽƒ)”¡¡°Å~ðT”JghÓXÙ‰yÞÔ)‹Dè,µ—5l¨¤l��”³e.¹’»«ª ° Còï‚ÃXšA�WÏO˜Ùöˆ—YÚ]F¶åÑñL8¿˜1ú©Ñ‡¨ÒÐð_½^~qTÌ÷¿#zsœè.&ÃXq­Y’óg"~¯ÓPrÉa®=à±ß�“ÍÃKäTax·m¼2@pç>~ŽñBs¨ïÇ_ÃR2%Wð(µE޾e�䑨…Ù€øª†£‹3�žLYë!,É 5EÌJö mf±±¡l6¯$œråþ\¹;-Ü- 5'/ß5E¿w+5FºW2„P´  Tt’6–t⼈—å—©õkÎÖL\@Kak ½!Ž'Ù‡Uôˆ.« Þ`L5œõfĆŠ4ÎÜl¾öìuÏdp<¶”™W¨a‚¦Ù�ƒÇ Ñ-ý°v�ûÉ®e tNÖ¨¦k§ ã–’} ®ÛÆÖ6®Û•Þ°Òdx°æ°ÈÙŒ›{?܇_Ó«šg=ͽàÇHI”bã¥Ã�áY ›W)ˆ½›R´mM-Þ\²eTæ´�s1E½é¬&Y2œ*H†µ)?¼{FPþZ•L£¤A-ÊR…»ó=)ž/WÖöL�ko”_ü‚/¤ú"6`µÕÖèø›¯Ïüû÷wÔ$\Ÿ>°Ô�‡;åá´”¯EH–ƒ?鵸’ÎÝÞÙÍ!ÇoŒ«‹úÒ¹û“úÓÏQ®þ¿yý\Õïí×Ï;ó§Ôÿª«¾ ‹Á™?ñùþÝkšø×\ãówû?[Iðkø-Ýêoâÿƒ?®%¢Si™Y¶vZúLP`üâ}þ^­œÚ n��Éj"80ñOÍ8Cé}ÐÚ@¤;–¶Ï-%’Ë\Ã@Í„Ch¨çâüL‡*ô Ò’JHjeÙ�#äö\O+ è³ù_˜ )‘Ò`ŒlÎŽ€Ô`˜Ã1êÉt¯$�Ïüw»º{éïÙ¤“ ‹8Ê&"/à-"%#¨yÕ˜¸øxžY{SB4 †ùPÙí¥#�?J±ãN‰¬-<æµÛDûØsyÛi½´Ž’A÷#ˆ*�ù·úªäžê �p*töÌߘơ"è; Ù#Åx¦Īf7®›/Ãjº¤7›û(èè,R©ä¢Ô¤ÈèômµLÈÑ R(?3¼R7%¬ò´œ¨çGêù‘ ,ôË'Zæ¹ }tNKæ|J”ºpZ*³¬Z<¶ºH"‰%hÔºðÛßüŠ¿ÿû_òãå¯ý ÿùÿþ#ï?|$¥n ´)#™‰t)+¹àNrËz¶5Ïäd�J)«%Øð΂ÛÆ¶5rQ2Åæ8«éaŒÎÖ•Þ ÖÆð¾­Ú¨Ö…ÙY'sP·­Ó›5;>-•ó©Ò{¦×Ìõze½^L½MK˜:Ó!ŸK%Õj|¹¡[ k¤*�%'ƒ%¥ƒ¦éM Ž"à!%å|wæá~áïþþ·üûÿõßRsæýïøîà?ÿóæ‡þŠ2�ç³éü[l­»M ’Ä�¾C÷¼Æ­.NKåáápy¾°mjðK¹�r…\ÑTh$Ö>¸´ºÙŒ¹.”z¢¨04Ó›=«@��Uƚܭèø7™¼9‚ãÀv5ó¸u¡÷øÛÊŸã¼PB"4“Ћ•´#„ßÁ厊Uù‡µNGt8dðžþ{"¸r3�9=q¢•àÑwò" ðR}uÁŸ¶ikîJ¶Ü?eVCš’UPÏŠƒ¡× T3}.W(O�í*´–øË÷O¬ýOüðîÊÐ;T ¤…­CºÐÚÆu³Êk.ž)eÌ‘.ÉxÏþxáùãÿ *Å,jôv¡¯O<<œ8�¾2y«@ë  óA¸wÛœ“„'¨ªtšÊìÞÑ+&×;ØHPÏ N!‘5#©#-Á–ÌFn¶fôPêËéÄr:‘N iY¼º†òtÙxÿéÂõ:è#¿î™Þ,Ésô£ì7c•J¦î¦� KGh€4Eè4dâvrÀã¡áKPï™`÷Ý:žä"°õ�µ¯\· —õ 9�Ìw£¸ßÁƒc�‡°¶NëÍ*vÔ;=jÍo'ͽ ˜£cgL7åÑÑØb†‰”Èf ›*¹P³¥vñ!c^"G'ç I�Xš»¨ž«'–‘Ny=*Öˆ[wÅ:öuŽà‚ ©a™0‘QeÎéèt~)!Xü~• ññâÙì¿Öäf}5~ö}ñãþ�xì‰23厧H¸9]Pøæµ)ˆ­u2¼|«Þ}Ç«‹ Á�”öŸ–™&D=¤ËR9-…1£{c›6èÍð‹(U§”8/�­$¶lš‘ªÍ{«9>‘Dk¦Ì­Û`K–ÅÖ›—IéFNÂ’ ÷KâË»Âãý™/îïXJ†1èmåzÖMé£1t ÉÂã#y‰½Xó•.ƒ‘”»“pg%ù¹TÔ‰Ö×Í2h¬L>1´pÝ26&ì·6³´§`�L ó¥úÃi&̇©Y­±½4”´g�’ïq…@;÷'~û›oyzÿ�¿~W¹?¾ú²òxWAëU9/�¥¬t÷½Ûþ-4"ŽªDôï�Ô]ˆ4º¬4®4® *Ö°Ù²²¦¬Ýl¬¢+àrœ&f)»e i¨ÑttB�P‡ç9âÓ�ýyt):ÄgqÄñ÷ã{:âþ÷÷ž½×9:„â¼�²‡á_1è…áp¸V8ãÔŸá H”Ûù5f[å˜ßYV¬ï÷Ø�ëx;}ÝoÃe ­uÚO;@mľе¹Ö._޲Èß70tÓ¯ô2ÿŠWÇÌ5:Î;Ž™Îü€W…ܼÑoÞ¾æë9ü´Úòs2æo3ÌßÔžüÇ[ךœwÉB=ž~óÙíï?ã^ºà$ÝÃiÇe½½åÏ_ão­Íëy¿¸èñú“~zÌ›Ê�›uûYþ‹‚1ô+ܳ½õùJ yõËaÐPÒ_¼÷½ëàŽrÙ3�d*¡GÎô¹j‰àdß-Ld߯î}np[»ÑÇtЫ–³A’ g;  :¾¢+G9¸ Ä� DÖS<£ ù4짃!&š\ç�Ì4RîÀÜõ�>ãU “]Å�n LqÝéÄ×ËL�=Ïéæò¢{ª7г¯¸D=³}öˆÌxxÈÀÎK^ ßí{RôÉ>{¹8Î×_ÐÁœcèòv ñÌ×ãMè�fYû‘OOAb�™=$°+�·UþY@o8ÝírÅž‹DrG”?øþ”!ºóÉÐ_cÂSŸ�×µYE/©¸QÓ£ƧMXÙ‚ª%‘¼âbv˜ÁH6’D^˳u{ß÷qoÂÖ[³9wOŒ±žœF7¸MƒùQ‡ZÈõäpœÉ’ƒÄ˜T Ödu[ŽpEq]×u#-wž¨•5“SÜqë ³ÂHÍ ‰A_y…&”â pÚß^U¥ J=q÷pÏ/õkþñßþ÷'ƒõ|\¸nPžY×'R¾ùökîøøñ™�/¼{ÿÌe] ¥ %ƒØÄ2£Í&6‡ ˆeÇ><œùå·ß0ÆàÝ»ÄÓÓÊÚ|¿e«–蘻«Lî@8çjM©‹�µÐ:l­Í}7²í¯,ê�ÛÄ�„Șö�õ³°^uêûŪbªvÄöM:¨Ü7²ü%N¤jÏàà@ß�ñçà“žI=qËíÈÈ<»%�D=Dæ¾÷ä•£í{þÀEäÀ§,0ä'ïë¥8Õ£ni>r#”—㿦C‡öÿ™SÞò �KqÙå‰n’h£ð|Q 1ºÙÀß¿»ðþSãò|eë•¡¥°µá¶i³ŠM Å‚yß«{?ñ¾ ¸¬Ã«-€Ô]ÎöÖç³°êžf[£÷�Œw[%_ÊÙx@T&y%Íôácòœà-á[1ÿA…â™X5þ «¸þávÑèh _À˜÷@kfßç´WŒxÐ4P²*ŒD&Ñè™=è£q¹trRtl,Oƒ�?n\>¾¸ã|Ϻ^yþøDQ¨*ˆ „NoÚöѨ˜Ìï&ïtX� 4ŒewÊdKh ø4æCÂ! D=†°¯Šñ.UÂæG¢ZòeRÛ÷¬~|†yOsÔƒD)‰ûÇ…ûÇÊÝ™t>¡8Œ³BðtÝ8<ó|i¬+¬W¸^”ëUÑ«AÞÍ>•îEè(ÚÇtÊ3@RbˆÑLëæÃH2­H>Ʀ¿v%Ñ{¿¤aüF"ªàMe¸ñwOÞÚÓνpž ’ø˜¶q¼Ê ñ9ÓÖ˜YØá »Ñ"ƒý½´Ö”ã§3zcμÐwõvŒÝ�ðzê[¯rÌ:ÿEðÌãéÄ?쀈˜‰»4FésMQµFáüÃ5+1d8ƒò””ý!î„7² –&ê\=ÌÍ~o<›K`8óéá‰S/—E ;qLÁ¸íÃbL?�‚KD]ÔíÆä«E?xøwgWàªïY_1æN|/ÌÇ?4=>šëZÃÖ’ §¥r:-”d @´£½¡}C‡A‘”%y€ Þ9‰ì ÓR+K-œN•Ó²°­Öë3—‹5JÙV¡mJÎ�snÜ/•‡{+uïwÙ`™³Û,ë{ëVUŠáÛm­Ó¬›²mJBïÖ·7¨Y8Uáñ>ñåcáˇÊw6/F£wåzm\·Në^Bj–$�Û?zbŒlÑÙ>¸;Ÿ¹¿3 û’ ’3’2­ÖÖÌ™�]ëÏ×NÉ §EY=ˆñ¼n<¯�kseÉ #+å¬ÓK4Ù=X±“K9?QEÔ “ìyÚsN)Q«Rаu5œPw¨Ž)ÜCxÚø“N’a\Z@ÎÛÖiMÑamxV˜t†D2¥.Fç¢õ«e-Œ ´¸°Ù “>'ÌÌþ�ú>j‚Àp ÷Jƒì•C½ïY�}tzk¬ëÆSzvÁÄ[0L;a�³P«•MJ*œNgÎç;NË™e9Ó¶Aßl¼±m(ƒ6† Åd¸¯Í«ÕF«S1ª%ñðx¢ÖÂéÔ�TQžÌp¿ôÃ@îî*p¶·ÜA:ÛÞÕ+÷ç3¿þö¾xø‚ßýö<Ü=‚&�?—øôÑ0Z·!†…èM=ãdS#è, @JGËF¹Ëœ¿yäþý#÷÷gÎK£­bÎ#m„{CÅ"úÑÄ]ÈäZ©åDIecf%V¶NQk*è˜ÃDlŸ‡3á¶b ¸£x×|ˆ ‡ÏMƒœJdÐ÷¤¡ÉGwÁðg}ó³øœ¾.�ŽN�[N¿;õíj=ÿ09|¦‡ÏðóǼÇÈ”œïHýÜq»äºU>þÿðúÛ÷óµüÔK?{Ôß¼ëxˆrTø^YǯOyq }ñÛ[óû¹¯=³ÛÏ}E3ÿ²ñ�üýó×ùŸ£�ƒ†õêóãÈŸÝó?5òÜÆ¾ogP`OÎ0#}Ï̾ ÜìùãL}ƒö¹÷¢Ž�SBƒô�/Ž>è˜Ë^ äl½Qe·ßŸ;õÇ u¥õæð)Ví(IÐn‚e×ÓÝìI0a&C¿ØéÙæ$€ö¾ËÔû^é\;qç’e,:—S+y̾êA~s�Ep *Š<üƒÂ·‚*_=ˆ~£=K,RŽ�tÐŒ…˜ÕÁ§ç$ÃVò¬S_¯ÛKêáZ¾Ú3˽ 7�L6ˆÏóÕXÇõ(^Qáѱ³Ÿòû68°;9b­ýÌ  äµÜ^'‚@õs}'EE0‹°Ó”!�.Ú¤AMJ©”åMé�¦Xµ#+J†TecÔ�ŒD*'jꌣ zWè+­ÃuÝ85 ‚œÎ'¾NßðñÓï?}4G< dŠD ™>è­óáãßýñ;¾ü~ûÛ_ðÿø{þðÇ?ó_þˉmS¶õ™¡gÄ+búhŒ±1d£ Ã_jGŠ"Zcp½*>|¤·‚Ž O—�|úðLÛL‹ R �BÕ‰67M‘¼�g|W�ÂÐâÐa¦§§œ0’XG±Ìÿ!‰mX¥nׄõaX�t²`ÊÌš5¸�” h6hÐ1ž †\)RÜ)iöGïbÖž­X‚ Þ‡PÌ–j XÏ—Îû�þúÃ{rþŠÇ/ùûü=©v¾ýõ—üé»?@Rþýÿþ¿ñË_ÿ–¿þé{þôÇ?óÿ¯ÿÊû§ïH’Pɤ¼�¥RK¥ÖÂØ.´í™’3ç¾ùÅ7üþï~‡êàtþ ßÿð�w®¬›õ›kvBÑ”�Ric£m�Ô Â „T*¤•�X…óè(jÕÈÙ5¡ÍÛvSìL Ü’£‚×+²fKP q”ïÁ#ür;ªMÃ/¢¾™¶i UºÆusëwÖC 8„ð™;\g×í§8|ÝÒ²%% �èÃà�•Nø�ËÏ€�$j©,ˉœ ¥]©3Ouµ«²æÂc®Ÿ�gï’ ”’½?à‰,Ø{÷ý&¾���OûÃESv9®ÙF#Ã+Ëö¾½‘d`•°[v¿Ó÷jÕj–¯ª#¡š q‡Ö1è—ÆÓóG¾ÿA¹?g{ßUÎçÌ�ïžHiðñ㞟_>žùêîôÅ|y(y¬QoWžºò¼~dÛÃýgl{ V½�°=ÿ\‹4º64yPÂ4~õšê\Àïú.ŽuLKõÓ, ÑV 6 ïsPªõ{XÊ}EN »fvÿG&#UHE8_ë.σ§ÜH¸ŸÏ!¡‡Úz60= {æ=ySdv“r¨U¨ ¬¡ùm ¦5KLÉú½ÄiÂô¿¨FˆÝÕ†AÿY±ŒÐÛ  O.–€û,ª6�–¨Á,-Å�ϵR ,E8-™Ó)SªA(É]-p£›Zµ@V¤€t� * kD-ösç´ÆSÅi ƒ„CT†�ôzLØý=ˆ?˜e¼�ÆŒWÛ7FÞÉÞ6uÛ`]žy ãN¿ñ<Î÷«„Æû†õóRß…ƒlø¼}Y‚�Î ÞÞ¸X0i,³H"�ıdt²¼0ÝA:† ½°Ÿ[\Ç@SXûu��î†è.4ŽÊg\sì÷�Ò,§ ¥z‹ Ñ�Ì-óEtr.–ì÷q¼æ­›žù¸¢ŠdïO8L®),‰ì"¼¨�ÈÖš"W9˜¨søp0Ù§ÉJPKå|:qÇR,â†v´¯h/h_I ÃíÌBÉæxÏÙšöÖR¨%±$wÈ/‹——.œN•Ëó'ž> Ÿ>u>••ë%±]-±,ðx—øê¡r:�[ëlkçr]¹^á²mlmPOV²ÖºÒšÒZfëvNW¥oJ_5'NËÂãýÂW� �÷(©ëCY·…­Á¦ÙÊo]ê‡sUtrx`༜8ŸÎƒ“ŠES¦eëÍàæRb¦œž7_[Ë®¹®�ú¬¤Ôáj µƒgÇÇžÉnô˜ãäû>rEÅ –›)�%–*,Kb\•µw§Â£ò{&hË÷ˆR±RâZ+ªBºl ¦È µ5½Cò9lÏ m^ÚÖi}³ßÕ”]‰õ·x”ü˜yû5JÕƒu)EÀ£RkeóJ€©° ¥wË‚0w@)˜Ò”½Fèˆ r²{ÍY8�ì™.ÈÒiÒiÀf©VµØ‘Ý-:ŒMØ’eQÖ"<>'j]@ÉUh[¢·+Ïï;þü .èýФŠ$˰<}j<}Za�÷|óõ|ûí—<><€ [{âëo OOÂÖ…kƒ|Èje };ð9�:H¶ôz‚zVê]b9Ÿ¨§…¥jN”M¬4Ñø†g9}á°EY2KY,pètdJ4V2§…â�(uwGÆÞ¬LåÄÜ>ÿùwðû0~‚wýê«ÿ˜†Ž†L¾‚ý \óö+Qû¹;îqé²ó×)æ´�0 ‘ÙÙ¡ª»sìep!è>dņˆJ4úŒµ±f°gÀ¾sQØ N ‡�3=àÅY?õ:f~!#Äÿ•ù×çVüöÉÏš¦[Lìå„vÔ›s}ëþ+j›ž^ޝW´ú™û½­Vx{ŒÏÍ0ŽyÙ7@&œ�¯2Ï_QÃ<áðsÿúí qý÷0Ö \YÈÔáYÂÁÃÁ:Ÿ¯ÁôdwÄïNñ‡­[‰vëOx™/QåµR:½¾ IDATºgs¢;Ϻ½¯ÐsÈÁ™D4«t·!"³9e¢çÀ¬"<à�†—¡Ç½ï;A^ñ<K°'bYx6Ù¨xf#ê– Òt\ß~΄’:Råì¶ñ&ï™ú¾�9ßrÆ®-s‘“kÈx1—ÙËá†�îðÁÏŽNµ[Vsà§r¸—…7iDs½÷Á!0BìÁ¸ÝÇg¯=`{\ß¡ŒdÕ¼wö¾¡’¡gØ #ƒf!¥B®w�*Ò6Ô\£m(ÒÆØš9Fš ¥PÒ”D/�^;c†ï Fcu(Ž\ ÷´>øøé™16šZ†~r8>¢¡¯žžß}÷'îï¿ùí×üòW¿àW¿ú†_þêk~ø~ðôôl% r2Ýi º6š®–üä:ZI…ìÙã[릮Bßžyº|âò¼2ºï;§“Âé0Lìž�$t<9¨ÛŽ©¹ ©�˜ã¾¢ÚIÉÃrà ?E2RΤr&å;�cY„J' ·útµD£Þ-1J�öEª9Õ½gF/æH¡`îvï U«¨X7xzn|ÿãGþûÿø3)Áïû5_}óeùî�F×Á?þÓ?ñûøþüÍŸ¸;?ð§ï?‘ÿð’ðæÁ%ŸY6j½f†–îï _ó ~ý›ßø}Ö¦|ºtÖ>ÌQT2#Y1¥ µ2¶Æ:© ¤uj®”\‘\@’Ù°^ål~ƒíL äjë¯ðÄßÏâº%˜@v(PD2dî¯Ø‚:uu±¿ó’Ð-ÖãÜüó€Ç™3»ÏÀ€ñ‡à¸¹À±Âá §XÄΘ‚VC÷‘ +´ó ÝõÆÐE >µ¤09Ò¿„<=*À^�=«©œo÷ÒÔ`w¯ÝÐ <Éj(}…´uGPÈæ¯ØÆt„wºˆ*‡eý—lÀVQoÏVF÷jnw< â²Ûúì•R ²wXoÄÖú¤‘” ß? cmÌw”'�Ž*úR ¡”<åï–2Ò‘œðEêÞ)³Sb’#ÖÂ0ÈY”È®þª$4•Ýmà0‡:}ràIH*�¬ZŒW\7Ø®W´]Y²r>e¾þêž/N +èJo“![¦r¦[ç dúXi}µ¦íúžÞ“õTÜÔ ¥i@wQíÙýy@ßí½1:›6sc @x«×íz‹ÿ-·Kj±dƒnzÏH&c†—”¥pww¢Ü-¤sñ¦¹žd¦ê0á�k¦,‰Óª¬8UƒŽËª°m°6ƒŽŒ{P�£¡ÉýRâs”¨ÓÜŸxßÇœ“{›%o¤lý5­ÇM@èȢʞmÝ}®’ ¶±½;KZÈb°y° Ÿ¹0zvºÊ,µpv´’’ ê¼ÖD­Éûd&k²¼ºÌç~�TÅ‚í7Q¤/óDµ€Š#%H'•dë]Å*¢ Îõ:‰Æ¯ºgÔº>[eé0ÝF»2šñ+˜K°ˆ«ƒaƒzàÓ}•–k£“Ç_µGš§Ï˜I/“v—2ùê�÷ùÊ4Ù©¸È¬�7ßS�œ¯dŠãdÂÕ“©î¶ˆý>TŒÁz¶Q0ø]éµÏö¬ù4¯-ÎDb, Á׈FÕ‚g)9£5Ev0RÔRf¦!@k¸zcø£U%§2›Ô-¥ØÊn EkoUŠ –*œj²òœx—À¤Ìœ3,YX–ÊRmcž–ʧOʧ¥qW7îêÆz�m˨|ñøÈ×_}ÉÝÝ�gªÃu]¹<¯|ú$|zRÊ¥q]ËIYNÞ E}7³—1j[Ñö@IÂR wËÂÝyá\+§ Ù›èYs­;Èg"‹EüîE0åk(íºÒ®E2ELˆšlYw]•­™`I¬MYlMN•ë&lÝš ½û¥ R2¦Ø†ÒTÉC¬<ÑéªÇs5`�:ŠÍŠs° JN•Z3wçÄù\Ù†ò¼U÷¢½¬Ly"@YÉžXú|wÆÊŸ±^ „be°BÖ3a#W+ÝÖ±—ÿJoªÕa$dXó³Þ­3|8&ÄKÌŽ/Õ›•¨é°r¹”¬¬2—L)ÅË ƒXÅJΙîMâÔ³Üm ›°1€¡NÛ®´Þ,"2–¯Ãh#y¹³€C u®Íœ$I;itã ½Ss¢Ÿ„”;¹\x¾vD®ˆlO5hÿü=ßýåG®ù=[úHÉ÷”rOÍ_°”G.Ÿžyzÿ‘íòL»>qÿðˆæŒÜ-�…»ë¿ùÝWäܹ®‰ç«ðñ“òñ ><+ŸžÕKÇ7‡9D7D6NUY–Â×_Ÿøå/¹_Û‡�\Þ½çùÓÛõ ãD"‘ÅËkU­Á�F8ÒÖ·&k^ ‘ÁbÁ Ë‹êD¿Ëâ4£dD@¼ôÙé$1&ÏÜŸýî|gÃ4{n‚>·ç/h\öˆúkI6yðm òœ‰³ÇÝí½#ºîŸß»iòr,cÿ).|s� S�)Ð9‹—Mº<ØÐÛfŽæÀ­OÉšiõÁ1æ•Ì%WJ½£.‹?s³AÆè¬ë…u»LˆØÓéÄù¼Pê#¹>‚êLÒaz±¥+uD6Ó½_ÀžÁìMLJi�Iî(uñÊ$Ù(36L·ì£s]7ÚýŽßäÏþ%ïþé·üêÛ/9�*’ΨœØÖ+ïxâþî×gÈå‘»»_ðÅ—PÎ(g–zÏRï­a{6[{tå|WøòË;îï¿¡”{úhÔåž\Ÿ�ôD®p÷ø%çû¯P©tr=‘{'£¡­ÆåŠÜeê’©Kå|f½vÚºÒFC7ƒ–éÝlÉ¥X2S4D–ðC¸oõ„€:Òbó!#;”�LãV«¹Õxcß5Ü=&½óÌ®LüY[` {` l1pÒ½¦w—-»|>^;ØÂQO WJ€?§Ng7Áÿ޼ÇlçþÎÀët–ËôãÙõ…�59~,HÕÕ‚:ƾv?”¡]X6¼ä…%Ÿ ½5ÓÜ$é„¢‰ÏT=û: Wš�AÄ{¤½ÏxÔ\fÁkq»V½/BÞÍÏ©�s,ði•ô�Z`Io`ˆZ%×)ÇÓ�/+–É]òH0œy»Éàe¬²èŽóµë‘»ïãP‚!è”^4C<£ö¯oŒØ‘53�Øß3;eÜŠ�9ugnC#0Á�ˆ»’ 0t8VÌQ_ÖÀ^åXð&/ªVtS2|0lL+3f&QölNÛ™]3ß¶ »¢ë÷+.Šoœø~ÿ±Œ7ÆN”›`2üÄPü sݘj.ê7<{ÖXI‰’-gX†õy”š•ó’8Ÿ2çsá¼ÎKæäA�¥fî œ ÔZ½yU¢Ö̹n,iå”7N¥±�…Þ 9Y‚ÇÇG¾ùê‘»ûÏ>W®ÏWž>=Ss'ˆ dQN0ébÚ¥Tr-æÌ é9aÙÐ9yV´gðÆY)äS¦œ2å®RN©¶™q�ƒ÷XŸ¯¬ÏWÃ�émö±À€eµÆ^bݬÌiQÖuak™m×M©JVD ºem‰µ[?›mΦaRNô0ŽR<[7àÂéª&lsJ.œO‰»»Â§µ#ÏÉ¡†tî×¹£"o_pÓœ¥X‡û”Ón¨ÁÜ#Ã÷”s¤cì­™ ;‚= ʘcoìŽÃm´¦Ï¦ "g™¸‡¹$k<4mâxˆÅJÝÄ0SMÎXÖDWùC;£oÖŒ¸8t˜Cr¡ì•ɱAº5z·žk¿¢ÖMÙ¢ã K)6÷4P®<=o休҆$˦ÿþÇèã™§þ�çþ‘šî¨ùŽóé îÎ_°]¯\/Ï”ÔYÊàëo7.½qŸ•r_8}âÛߟ›ñ`™bÇœFÝ{ìò"äçmÏ®¸ÏÃtã~æwG;E” û¾zqNìËùß‘ÏuØç¿Ó_‘#c× W%ªª�R-†ð‡0dÙ;á‹;ä6`1gu€5=îƒ 9:ý=˜2Ã̱—7è÷uËÍÏÑ!l’;�‚î<[:ƒ7h º\écên ª :”$'–º­h" !ð„­0CÑÞ[£¯¨õÄ’Ò©S´ËGž\GTí<_ži}åÜ:gµ^h9ŠV¶aMduDаO SÿÝ»�ôþžï¾û ¿û_~Íù|Ï¿ù7ÿÈûïŸhí¿!i�𤴃]Ù×m¬ô±šãÌmìm³Îw£wz7»®æÂ¦í»¼½ÓÚ†´CãñdÁ«€.–É�ÒÝ�$#©Zÿ…ådIXb~Ñ1šéº±6aÛ”z*äzO©”ò`6øXѾÁFßè½�ªE‡ÚÜ«žÝvIe¡ñ$ d�ucŒ•­­Þ‡Ã+×�w?ñßÿð?þø­]xþûßòë_~ËÖ„­.וïÿü‰¤?0Èl[¥”/yxø%mTÚ¨,ËËòà>¡´N)�eY8�ìÞú(‡$'‡MZ�,œî8?<²vË—²�ë •ŽdïÑÍ‘ŸK¦êbüJWÆHŒ°­cnÿ¥.s/$ïG±óýá|Y˜=¾Äs|G¥¹Ÿw,mÊ­ù�:Ë:Ô%Šïá¹eÁÛ�´ ÀØm„pí‰óÝõ§öA·Ú’ÏsçkÇàÀ-W 9k#Ìä¡(Î5|PþÓú—ìN³HÆÛºî4w¸)õ>%¸ÜE-QmO.Ušš#z©•\+cÛx@Ì¢<¤ľ޿ÄÏ#5ìùZk¦Ö…œëä©©ëO3‚ÉhQ™«ä°AVP©õ„ l›exƒÉ–áQ «~²®»?Œ å»W˜MÝ»G‡†MíÕB£;°PŠÿPÇì�â Ý"§’)%�v‡³Sg±9i°Fˆ j¼²T„lò09úÏføóY ½YÀôýû XjaY úX¨)±”Î_}ͽ*wÞ£ú‰µ \¢W–¢È}5§l§•3”èÅc*ÕHb]wÝòæ‡=»ääh�÷õ\%ÐG§m͜Ȫ@òFîÆÿ¤+¤d…þ3Ëã±9O'ò)'îJæÄ€kFVx ZC5[@ËÀ›HjEêÞ©#$GXAö�ºCwxG<×"ÞG¼ò}Øó%‚tæ7M¬ÒÒ 2ICªHÞ÷1!ÉhRߤy@›{ò)bI¶­wh&orJa>û;AƒÜMðv8¨,Ö^œ ÷±æY�mXf$— ¥˜/½[2«nÐÖn¾«°@Œ¥oÃû°Z` äÁ(Ù‚ÖÛh¤$RMHÍPfÈÚ1Ä",Z[ƒ£§dç•Gÿv¼f ‚¿vžÊì¯ûB•óW9fùÄ˲…—ßíö¾'^àaSVÅÙA™ŸbËÕW.Vò”ÈâÑ©ÈÒPƒTÉ^M7ç¢ùúƒ‰âå5ÑØÔâ_Q‚ýò–Mq2.T¼Ìy̽½GCqÇðÔu5J9ÕÓ1Ôp¸ŽAà½ßi…½¹�W ˆ—NF‰&†„Øìc„e0®b›¶÷Áºmä+$Œšé5Q’’hdÔ¼i%gN¥r·TΧÊiÉ3Ù~)ÊyJ…RÔ2�{'icIʨ 9WFTOVö³TÎwwœN•RR¬ëz-‰SMœk¢� ‰Ób�hRùT2÷'îf`€±¡mõÞÈN S6d�š�s!�3iÉÈ’aÉPó,Ïñ´}òEY.‚uî–Y´Ffz³f:˜¦,)³t¥œàî×Õª ”B‰ÇûÊW_Üñõüøá™OO��O�˦\ÖA‰®BІ3\wBJr8ŸnðVnuM»ÇX­�Þ|L-œÎ‰u]éëæû?¸Z”Z-Êz:W–¥’s¡µÎ»÷ïiÍú0¬Û 1œùLñʇ}’:Sª•¸É(0j^¨ÞÇbY¢‡Á¡™ 3+ës`8w3ƒAÔ¢ócз�¾mlëjWL‰”¹nêù¼EëºÒÚ :¨¥�“ Z¬ò/GiÛÆåù™œ«5EóæºC;½o¶?ƒnTHX�‹$&”j²FÔƒÂus˜:èÆÖžéý‰”:)ƒæ/ÉùKžŸ:ï.�’¥|rå§Skç¼tþÇ¿GÊä÷Ï¿áwÿô{$‹Á8¸1pw®|óÍ/ض…ÿôŸþÈúü#§;$�mþ’¹®Êõzáñ.ñxU©ºQ8±Ô3§Ó÷wwœO�§>�quøšD®V�Ó†ÑmÎ'j¹ãt>S—…ëµsíaÂ[“¥®›)*‘N–cŒ²Çfªóá,8ˆ™éÃâÖˆyË©òcr<~ó†ÿíRÇ ¼=â xúðÜ(0¤`®–qQr8Ø,#/Êþ£Q¢eY6ŒŠ;FG¤ÌR^ûïX}`¬'çD-…¥Ö¹OÚt ©+ß�=êY#‡§q\Ïøuw¦ë”33 û÷pß/°+kÛ¥Ôî3=ò„9ã9ò"8p;ö[êÆñ:”ÿÌGEû�c^Ñ {h fÂÏOÏbþ]ÝÐÝg&wóQ8ä˜?÷c#±bšíkµï¯Ý)y˜‰ßèM@ø¸odwüÆ=í§ŸÃ¼ßŸX©ÏäðÛç¨êåsúys9Îg¿ö« Àgçsxœ˜r<ð� À|æ7D}¼žõ!{çìtÊâ—ù©`Ê0ï¿�2 ä]ï´bÏÝð‹Ãq“’„Š:ùž&×û Ó]ΤY„\^X€ÓÔ]78£¯X8ñ]™?�ÔÍ.›vÁqù8dž"“çîÁT»žaÚÝš¼R±Ìñ 5ØÚÎ+£_ËÎ!Íi!Ù˜DѤ7}Œ/ìòAçÞwtîû/Èbÿ9rðpLÚƒ+ÓÉ}�•„°½êN¾€•œ6QòëXâ‚9Ê>¯ãPtF¢Ÿa¤}8Ö<a€ùÏ• FÐ7O4<ÿ{P`¿# 9ËêõæYÏKÇýøÞ»äô>̈žÕ�¸…#{?²; ¤'ÐÌè�–6 e—»’!WrUFS£õÑ C{»^)òLA–DÉÀRXNÖ3­�Í›`'Ú\¶•íéªiö)“ØpçÁ±òQZ¸^¯üó?‡�yxü†óéK.ÏJ)÷ gðgjl øÛawZçº^ B‘.× Q,!kYXF§éð^_cfc2†éÕü’e$ŠcŠ/^5`IfÉ+J^¨uAR¥�=xh=®:ÍíÉ'{åÌH ¤…”Ðî|Â*~ÿÖÞlË‘$IÓûD3î™Õ]]Ý37|ÿÇ!`HÎvwU.±¸0]„"ªfððÌ*ö!òxz8ƒš.²þòËVîÔv¥ÔâtN… †&]–Õ*Æ) Ù*á�Ö…œm,µ¼RZãõÖ¸^oh÷ëDk lHnåëKáü_ãËç;>üŒ_¾¾Pkãvû+ÿ÷ÿ|EI”¿üvc+'Z�4µFË¥ÕYÜ[EkäË·JÙ¾ðòºñ·_¾"÷íη—ÊV#�Ƚ‚z»­YO¿Ϭk@Ä|ߘœòb]�ÐéÎñÂéÍ�í›{%Û« äe%„N�ŠH3jÕÖL¶„Ý_tãΕârÞeÿè0“ŒaîPF/:“±£ZÅE€Ø'§?’`ÕÖÖ°Ñ hŠ6?£}·;§ê;Ê‚7¾ÀMª8W÷,0ªŠÆ5‡íîÏw¦,²b?OÊ@ÚÏ„„?­]'—?ÃÖÄû]ÚSŽÏ‰ÏSŒ°:XlÝ]éÝhÌÆs#ð?TÂÀçemìW¬J ø™Œ“¶gÈÒ˜²õßs.ÁãìCŸ I«¾#¹¡æKŒ˜ÚHh Ô­ÃÎ�ù½Á“‰C]Ï>Kn–Xèn÷!æ²:A÷_Š¡Ïµ{•‚Ð�ª-º¿��wtТº¥#Z¼²:z"£[œ, †OÑšÏ �¯ õ>&MJ_é%P»Å•:w¶ðÂ&V}tùð‰”ž¹<z{áÛç+×û�Ú —¾rþpf‘Œ;ƒÞ�¹A²¸JL�”ÄyêÇ&{Ôù�àzt¤¾5ï0=¹Ò-N Þgé~»³½´)u«œÎ+§Ëʨà DdYv$ùÔᦜÿ‡”*O %‹§j‡ÛfúÑ}ÛÙûkº¼ësÛpºoÛK~�QHI,˜ Р žR³[t]D  ¦Æm±ä‹ ÎN"ŒXx‹Ò±}äúÍzN ÷!lÄì�Ñ‹ ºïÆOŒä@A#U-V„ŸñÄÀ°€îHjÙóJÌÍZëD�-A+Æ”7«èn—�‚uÊŽÞL†6ï *@‹BLŠÄ†¤fIÂd”p{ŠnJ,9 ¶Þ#´¸Ø°ÓöÇ®$ŒžºÃî•îÄù;›��Ž�¾wdÞ $¨îåSŒ`Ê„2“7/øaÚ�÷±X.Ä¢5%­ÕË]˜EWºxVæ?©öù`�úÉÏ©6‘­aáPý0&Vt/KiÎio4.m"DƵC?: ¶vˆÎ¯Ö{µr™(ì�«ãüùnœÙÚ‘"@†¯Á!ª…çmN³k Åï£C9 ªk¢×HŽJ �%Y2J$Cð²ÊÌ’çñЍ6ëA�à´x6/bÙðV‰TrTÈ‘¤ ²fB€”¬iJZbN†€Iº’’Ñ­9PW3ZOÍzô®ä%°,‘�Oüðéy&´mô–,ùãkÜ{¬ Šq¶‰%N =%ã[–„æ03~4Oll a‹ÈÝyØnÐn�^½šR�!yYOD;¬«RnÊýÖ©U qE%óñYy½v~x¾óéë�_»òÛçW^®•o¡xB@ŒÓ^…¦PQ–ùܨ¶nÓI�#߇TBPò’XÏV¬[sŸ{8åÖ&:1ZÞ¼˜“PJåõzeÛ*Mžd~Ÿq%Æ•òD†ŒÒCñ½s$'A4#}±R䔬A2£¦‰ Çဇˆ1Ùþ.Ú Ý�'òÔùµlÔ²Mã#jBD‰Ëº.€¸¢ʵ‘r6ÚŸúä[­e£w%¦FÊ 9e$ÛÙ¬uCµNC[±¤c ‘³ñƒz´Žx#lënßZáz½Q¶WÖ5°¬‰åü�Ÿ¹¿~á·_¿š’åjU$ÉöÌvê´¿þÆËõWZ¬|ú·âiµ2BBƒPY—Ì¿þåGb|âäm,p IDATó¯¿òëß*§Sd=]H!BäåÛ�oß¾ñtž/�KRR»“äÂ’N§ OOOœÎw¶­ÐzŸÍ××óBL‘Ú�LJ+)�Éy%ÆL¯w¶éœ[Ÿ�æòwJ-ç7"G—Y30òäòJ§¸zÔ*16dœçÀ6ì¢ÎåîüÔ[™ ÐÝ€Ù•â0�ge‘ËLsPÌó�Ql«ß½ç¸&óº ý¿—ÎÎ8ëLø¿ù¼ìÓöûßx^¾·9¦­ß¯ôï]WyD¦wÞ¿ÅÇ€ý{µÝú°gÿÞgÆ^÷=¼—½ßaOƒÛ;ðà½ëŸ;€Þ&ÞùÔû›ÄÛûkþè¼?¼ò�-øø‘Ç=òû�a>Ø0oßó»c“ï÷Ç;ïy÷ªc³î­›ªcÜìAþÃ>œhJ_{oôß�m\cÜ?¾G­Zošz£ŸÎx—Ó9t“Yf·G ‚î˶ŸÐ�ZgÆ”F ÅGnŒ%8šÀ&8Šxp¾¿Mpí�ÇõÚ¢6�DâÁžïÅ�Ù£Êq m¹Ìû2êûà>´YßÏ´•Àú)(0Àxλn5šfÛO�v˜�‘zDwÆÂþ£s¬`Aÿ#™ð�Ãs~¼ôïÕ3οOê¨hˆÁ“2!2hq¦ƒ¸À\ûODÏy‚cRàØïfÞö�«c”33+‡ëŒ$÷£ØëêïgäÙ?u“ý“Î^YÊðQÔlw£Y°ï ìM¤Q%H1ZÃ.ôÐf½¨ªJ^ˆi¬¹nL�N£z!^¼ÜåÎ&‰SJÆíŒŸxYËšÑ-P*L•¶YÓF Ù¼AÝv:ÝQ‘Þa4QJáý¯Ÿyy¹ñç?ÿw~ú)p½)1]躠ä}‰ˆ$PCÓöÞ(ÛÝhVëßußnÐaY–uõHg»Ÿ6jö˜¶nI@uJÂlÁIˆÓ¦ïÆÜL”DŒ yYIÑi†4u�î�ÀKƒŽñ0IOhX!dëI0)"‹É6ZÛ([q@a1tŠD,ÀiI=«†·¤ @8ÓŠJ¥´·­ñíå†Ò�ÐXaqŠ©.Ê××ÂýþÂüû–”gŸ²ÿùŸ?Óõ›[ÉWTÖ Î’ ”F+­’t’¶Û�/ŸoüòËWÖup±'ª*[‰hLÜ«Rï…ûV�ºb%†•eMä|fY­o��ÕÔ‚¤=×39�lÏ´B¯m»¡­¢­A,)›;6`£U§6V¤À î1 E°ê°Ä@=ÀÜæ<ÐOp‹šeô6ž9’ !YuúèVµÆ b(»"œã9JŒýa2å±bÀùƒÎnäöúL¨]{„O´ëÜ÷V�2®–œÛí]¿¶‹lõ¹›g8t›XEÍø÷7í•7iV߀ëKOà7ŸÛö àƒ%ÅözK>ÙšØ5­¥„hþ™#σSŒ Ÿ>¥DÊ‹÷Ù¼òFEBðžÕÖ™ëÒh£rЮ7ª¢Z³Äâx„ЉQIÉ’–†°ëgè²}H Ì}Àì�лɢ:Ç‘`ªXe0„´š>€)Üö±þ-•àl"‚´€›ËƒUöäLN–(ÐViÕzùu�T2÷–MÕôNiwîÀ­5ÎO�ÓåÎáü¸½¶_ÿÆýõn A”x^LR›ú¤ÑhT$Z4Fññ �ºëñ± æZ€¿VßèH×ÝâQt“áÛmãåë+ukl¯?üô9­ h'ä){†¨í6ÄNˆÅ.cl\ž„( mB-�VĪÍÜþ°ð“|Úq&- e ¼FîÉ×Mœ†Ê4Áuwã9Áï;Šõ1ìÑ(±¶yÕÈ ÌÊÑbJ)z/ÞhàLÔšx×Ò¬š¢Yu@íÍ>fqŠ3Ù)‡ÖœYkd�F¤'¤G·A¤C€ŠÝ®¦Ï�OC—Æ$Ö0:šíÝ»Ù�#W‹�«:)�ýóÍ«¬Z·å½´H B¬„TI9R²s!CâÆÁ˜¶Þ(:Ô!ëÜÎòv?¡.QýÃ²Ûø:=û7 «w$x:ü{oÔ‘ñÚ?öö¿ÇËÀ�—f@—�tÂÕ~T?Ú(‡• ÃÙêÚg9ÓDò³ §¡eõÜÏ‘×Ô¾gd†]I9*ÉçŒêOAls|^ö@—>†²‹M�©—}l�³=! G‡…ƒ07â ñ’½a\�@Ð~ñÃDû•Ç~j­S7¸÷N«ƒƒL!‚r€Vµ%)ÛÍøÖµÙÁ_brtƒ /°òÜÖœÃҦجñp™g´´™ÄT…ºU+mkæØæh q}²Í[§óB\¢%ÂpÝIŽ>gÝOGT’I,å¸ dÐÁß•F¹N÷Ê%s´L%X0úœ¤H HuÇ[¬–�nÐ!ôRÁùð„D` ‘ œBdá„—SáÛi£i ØjãV*¬L¬ve«•R;[Ž´¾£ú ]‘³�Ó ÈùÄENÜï�Ú^|¿ˆ'΢•öõFÉ÷–U„ånÏ©º&”^:ÙÝÑñÂ>ŽáYe8[£PÉΡ†2B˜çs»‚WyŒ2,ðÔÐ:C¦hŸgerc_ª­º‘KœOÙ’}­PZ§ÕÍ+¬±ZˆBp¡]¶ÊÕ¯Ù{E»%Xb€Rîl÷«q�®'Bô&m˜<w/ô@IùLZëY—HÎR:³¦Ê’Ç8ir†em¬k%¦Biw¶[ ¿ µ ·Wáv�ôÐ�¹] A®àrZ­ÌZ*Oç3O—'~x‚òÓB¯„ðBÐÆë×Ϭç3—ÏŸ>ò¯ÿý_P")ýÆëõN8�O|úéGÖÓ™×kcÛ"€3¥À½Üém£7Oš`¥ŠCn >Û=æ!Žˆ±ÀE7-}�=ú ’Ü•~#§Ø Ç`郡µU�±§…}fL‡Èx,­ìµÏKI4DPJ�”“_·Óz¥Õb&œZ®œ„E¨U™”­²U§P¥»ĪTl£v†®ÿÒ 6´S3¤ß£^­YtŠÔÚ¨1r»ß�6˪c*Æ|3½{N~ß»:=ðŽöý¿ÿè1LØ Ý‡u�Ý1Jgî‘ÝÏû;ÁÜ7ßyÐùû÷þ{¼½Æ ª}Ÿ¥ðÀÎx7íÑ®Øçíû;ygOƒÊïÿí½è»O¿W-ð{ßþÞëòýSsþc³ù¸Îï q·ûäßSoÈß?÷Gïÿþ1#�´úý, cT�cuyÓ�—^ƒ'j½ Tdî�ƒ�=Ç>ƒ!¿»·ÿh­þÞ: I?íVÿVÛ³2�˜Qi C ^ Aåð¼F›ñù±ew+úšê¨ÎñÜœy8vô»ƒ€úwUÆöF«²’nà…ñÒà;6Më\®3hdò0^ŽÔÖñ¹�ÂrûžCâ¸Ò:ì ™'dßÓãQ³˜ÜMX-¥–€ÙoØ{�ù Ö”TÃÔ�Vµ<* ú øD,Ðeó!Žž Áû;Ù¾sn7#LÐÃæß§üû3üݶÇf|øá0ï{dªz0ǰ?^CÞ\\ÊñÊHbh7Ð�¥iÔ‚£î;¤hHÌ%Öeá´®ˆÞ ܹo•û½±•B©ŠR^;=ŸiA‚5×$D¨êհеRÚ†ÔÀ­Fb §n ¦ó‰*‘¶ZÇ}9²U°~ h H �ÄîÅ8i ,ù>œyz:s»Eþýß?óÛç+ÛÖ- ’ö•ŒÑš(Ön½¤¥ãô�º[ž1&.Oøøá#­n÷+´ZŒVaîvGtzÀgð#(ˆÏiAÄú1ˆ5`sªEµÎÄÀ°ÁššMj¬Ïd¡; _(ˆÛ@iT&4 ÎײQôViµQë�Ö6–ue]V–e%¥‰‰^­wî[£S¸•Fé�e0‰U»Q¾ŠÙE¡K ÕH[µ'J5ÿ¹V ‚Ì�CxÖnÔ®£ JÝ×�tG*7c¢"Z4ðÔf¨ý{kh„oÄE©ŠÙØ*hô&±Ùöýí^@+J…^�‰IÈ‹Ág ¡µÐÒ2çuáÓǾ|þ�ÏŸ¿€VzßhXàYUœ"\É3r *”^í,‰Á÷Mu龑ý�îôÈ.›üÇh °¬'Äx­·n 3Ǿraq£L›sÈí)»²@÷10e5~ÍCRq&¦Ðð ÛáÚz¬zz´!¦ç §Ç Õªbv……3ºŒx”Óo9z?£\6˜�Bë´¶÷RSLg 7î-xÕÞ �Ã^92p„iŸú]y¿�”²ì ß´{¿f%x΋±bèn÷ë°m†¶ó$X`{4ˆ=VVÃήa¾r§RLÔdzkí~ü®)ÍЈ})h3D¹D–Hx ŽDëG¨MèÞóP§_i3&�-$ƈ†@Q ‡©½MVzîM¨7ï笥ð½^Zå·ë+Oω�?,ü˜Ÿ8­OœO‘¦ðòyáúí¾]¯¬÷•´Ekî hc¶êLA�jÈ5Å190fj®#^ýæÉyCsøæë¶®ñn×h­²m›¡ÍKc]ÎëÊÂBÙ(…¶bq/­f§à‡ÄýS É£8]‰O�k ÕNªêôÍ‘”#qq&uÿ´¶É ¼ËŒ}�ZßB«È)p^3kŽÔW¢³îFÕ{„™Ôë5ÓJœÁò ‘$J � F·Ü™kµYü·vïã⳦Îb ê„hD4A‹–i� À¼D�vW�>iÛPu™º'•ˆv;óeÛ:!8Èý`sµÚ)¥Sk£Ôþp¶öX˜ Kô B´ª½ÐÉÚ‰={°dVsÊ=c7Ùºn¢NvºŽò¡)0ÅÒnœ=x›ÓÝ&2ùyÜËã“é˜8"©öý~àL‡èÑÍr§¥:®æ’z Œ£sá‹2{Y“ݘz…Ù�hÜ”²s:‹Ok©ÊyOß³'&k-ކÁ$^¦ýàä¸  qÆX¼¦…”Vr^QO °|àó—jóऊõ€XzoH-¾‡"H$„l‰�X‰jÏw"´ˆU$shÕ‘:„Ÿ9¼E1òc“d;��â=†\bŠ vŽS hp*¡n ¶õ:¥Ç±d~$†ñØ{õÎõ²5a®¥ÓëÍÐ7Õ’Môè” ²#ƺ}Ϩ4Q–%²,‘ûvãõõë’gÀØsÁN-0ªx›%³€åtb]/¬kb]"IV" k*¬©R$æD^yòÒXÖújÍ„o�~ ´&Ü®ÂíI! Ý†¤.§ÅΗ4žO‰?}z"È‚ð�ûö3÷[Gú•ë—W.Ÿ>!9ñüãGþí¿ýJ½“¿6b>|<óoÿö—§�|þ|ç奣úD-+¿}¹q»ÞÐv§·Âl*vD�@ÙÃÚxF-Å9�Ye—SØžØqO{5À8×û¿†µ®ÓàÜÔ÷2¯9€ƒ ÁzL@3Þ?×Y¨![rެëâ�Z„;ÍÂÆO�c"¥Ñ�"qEd Æþ°äR�²;E‡={tÈìœ4z…â¥0úks>j­”¨nγø0QÂà èÅc`ò;T7GZ†ß{ü†ÿðŽÃÚÛ:þ=XjñÔï>­#âï?QðÿµÇÛkLYòvtCþ‚¿[öÝñµ·ÿÞƒÓúð÷CÐzòºüèEüñ]}÷Ì®õñõ±õÞ˜h<¯oöŽï³9þyhõ½·ÿÝ=ôöa[çѱÿî=ï<ÿ6é3×ú÷ôǨ)oWÏ#]öÉr'—ûà8xÞ[’ÇÞ½­ãZ}�ãmtŒCÁPé"‡½¼¯Mkƒsv  �#ß�¯Ä}Ï«>89ãÊŠ ÆLãz}°YÙmPƪ‹î=1G¹!X_!—H“Öa܃Ûù÷ W2X Ùlúlšñ&×Iax³GŽÕ9ŸÊý¾SÛ¸L�zM½ø¶Óµ"j‰�…%Då(œí^ m ž qŽ«Ã¬>ÍøDØÈZì=úvæ‚D†ÇõÞ' £*úõñì?&äáù}íÏs\•Ç—ÇŸÞËA¯=\cÎñ^q’ÙU ceÊCƒ;å0¸ …ÓøøáÄ?’ú+Y//7¾†Æ7-|+Í@F­Ò[!­OÄåìçhëì€ëÖ]6´A®‘Ø`‰‘‚Ñ �OD*¡7z/Ênz?¦HJ'>'¡{³Ïn‰žÓéÌåœøðñ‰ËùÄç//|ùò™ÏŸïÜ7ëO6ƒ€þ–ˆ4õÊ̆z•ª•ú›ícærùÀ§O"D¥”+÷ë•—¯_™€ßû�ªC«ŽSB"ç2ÝAA Á@ Îä�X¸“0|ZаÐ4;ë@™A<0ž=ˆ™R¤P­lÛÍè1¶+k9¡OÜ_4fs•[ilMÙJ§ªµ×àôbïiµ2ú‹5ZÒ­ukî3«PªÅSF…{—N§R†í6e¡íÞˆUƵš ÄŸÚŒ¶tkFßDTŠÞˆ«Z¯²è6êœîKä¾½ú=oôv·ª”½ª:[¯QÁ+Z ôÆÇç ÿú—?“¢�Rz/¶Î´z#f�G2Äl1•BÓ�akŽëØ+l¿¢b:5¿Mðê™lI Ôé/ÔQÌ»Î{k?ô&rÕãñ:)d‡è Òñ^£7ÁxÙe�âpWÙCÎ�›>Ø–�º\}«wu|ÊÖl´¶QðB€½é®„ˆ6¶‚¬Š@ý|tÔ©hw?HU #§Š ê´8~FìÒ‘ð›ïô�1Z5|ΤœýåN-ê�{©«rè½#­%ßC×ßÁ¶{oŸ]OïTÛûóCŒœ`ÕÜ �ê1CܽB}Ä'ñJ�äIÛ„,F½Ò1h"^íäÜô]ܨ¤l}Rb6Z%°djs”}Љ*B‘[5_.EC£o½jA¯eããm¥ðÄòÃ…×'žžž9Ÿ"Ë"¼¼~æöú�§Û�å”èb j×°’×Åc‹®0;»™ñ�O°ïk™›s$ðäzó32ÊZL?öÚ(Û†–F•Âåtb;ŸI)"KFZ‡R-Z®G°„­¡à :H0�’ª�«�ï�´u5ž2˺�×Lm…Ò6¶MÙîûù=Ú�à ‹!�ƒõù\râ¼fNK$ùZF�èº~?™cŸ ZZ[±$n°îªž8Ê2Þ5UO 4ª*Mað�[žߴ&Z ”î}<1ʶ%ˆï7£TOR 2Z ‹÷Àñx0î"oö"1ÀA×a·*¥tÊÖ)µQœÑb·O‡�Ú‰1°¬‘ÕåAêÑHÒNè�Ø‚%Ú¡*§w«¶‰–œ’ìqËä†HTN›…5öÖŽ�ѱ�sÆ^Õñ™ù³û$rŒ™#$knyÜßn(ÊxËxóîHïNÃxÍ>|D½�`õñüŒq�àª)j/#õß1ì%º2'jÜÐ8“ÃùËPá´>>RÝ›YpÞNô‘ûs4QµÎÒéé™<‡‡»œ›Þƒ¤G'HƼ=ZÑS™Øÿœ[Ó3rsæéjÆYeçDÝ×™Qš�²Ã×èX~SþU!xó” B¡VeÛš•ýø¡÷ä.µtJjVS# wV)Ó¸ü°¢;MŽÀ�ÁëiMTj-Ôb�ß”6±çªQÔ„˜¬1VŒ‡j‘Dô,ýn‘‡~º[#c¸_ ×ÄJ[;ÖDF96î8—yk&ÕRôù ì&ÓÒ›Ô2ˆ+Cè FÒN–Æ*55tiP+1 iÉ|¸d>èÁšé”žø¡dn¥qÝ:M#!�PY¬éWµäp­Ð5rß·^¹õ¶Ò q%yB&ÄŒeGì`õÛfM˶b{¡Th-׿:'`÷õKÎDç]ŒÑ3Ûb‰¸Y¦Ü;�JT�U ‚̾#À‚ ^8œˆQ.o×´ÒB�†Ÿ:¿®‚¦ ê�[œz¥uSœµnh-†LòJ"»u±òOÂ^ÑbÈ$q½‘\1j& †šo­q7Dƒ!Ô+§T1ŽDåIVR>±¬g>~|â)g.)ò|‚.�Š)­�Ä~b#¤F)…­Dþú×þ�ÿý�~ùù¯Ü¯¯äXóÂóS!ÅÄ×o7*xã2 *�Óeåù陪 U? rGÂÆåÇOÄEXè<Lüðcæ‡ÏfŒ-Kâ‡Ogþù_Ÿ¹<=“—HNw¾~¹óz¿²Ýîl÷;­nˆnX)g#¢Î0²Þ®ÜŃ;, ìrnRU @Äp®E,¸“.bœæi¾£ÿðú£±5Îâ _¼yF}\#c:bæ†�*h >Ðnh¨fˆ¶^î  I¨· �•%ñ ‚ÙJeÛµ;åOW*}Ú‰&ŸöS7…Üèo7~{�dMÉV¾�âwkÉÔ\½±Ò±|Üó^v=‚Mǹ6}ð‰õ_| wüýX9°ëÞ£ÚcBï!Ôõðÿw¾ÓÏÛ~¿ûóúÎß»ÎYî1msüô͵íóûžzû�s¬o‚Îï"úG°ß�²÷~?Œw¼®á{wõö÷{÷:’dG]¹¿úþGß>ùø·øøö—¾¿ßïª2þÎãhÁ› ð¼ÿ0¢9†· õ3ö0ž· Œ·ö¨ê<¡ƒ&5ð bT ûwëaÿ="pßï‰ïz˜Sÿ-û{ç¹õñš 9ìÿÄa³ŽF–v&XÁË­ƒQ�ØQ f³…èÔ„5Ú«»Ï™5‡ëžÄ\ΙŸöV„CuÃáôŒäC7OU�ÙhpØÉÌñë¨>[ûŽÃ::½Û\"8¥Ä¨´�Áª<‡]*Gº‰Öæy_3iGýy vbĩ߄œ­©]ЦWfSÐnsY›ÛÔ¥;bYeú2�œÝdï>· mì#·W$"®ë1X…=˜å6ªõ©¯¨èŒú´GŠƒÝ·xØ–êA²Ãüsø>ÓiJ—΃.9T,“g¶Ç|¯…qí]¶ÊÃÿwp•``�óš8Ÿ–d ˜§Sàù,üééÿôô×Û�—ë�_¾¼òËç¾¾V¾Ý¶QO ­¡ÒYI!YÀlÚT÷vCï�BfÑLU�´òÙš0–;Z6z/–¼¯ÄC¨‡˜DŠ¡gZ¥kc+6ß)™¾~½Ám3 QB ‹Ò´MÇ}=-\žO´~æ\ÎÔZÑÖÉiátzBz@Û*¼¼Vb|á| Ĩ<xæ_þå_(ec+/¯¯èëë\‰q[ëHi¤ !fR>¹Ÿ½:x_§î�ÅéÏ»O¥¾¬âØ(6ƒšÝÞZç®…Ö- p¿oGœ†YÖl< ÞgÌèHcŠÖ0S $VêDV;Õia9]�Ð�#¼ûQøˆFèÖ¬öÍüXq¯Áº-tm¾öJtJØìòóa¾o#I$iŠvÆ“7ÿt¹ÔJ5–�”ˆZ(ô\=!"Üo•××+ÛöÊ}{e]§5[Uh6P ‚¶BÝ6K°Ð¸»ý�£òåË/¼¼~F¹³,vµ7‚:ˆK#ôdÔH]è¡£ÆñËH@à19Ú›Ÿ]÷mcŠÄ0®¾Øƒ÷Ü™´µy®wz¢£ ÞeŠÊ®[a· ÷QàU-Óèn§êÔ çA„Ýï‘,þ^˜±¥¡ÓuÜ0Ç—v½‹ÑˆŒØ�tT¬1h§P%’R%Ö„D«0_Ùi•å_>Q`ׂ˜®biH¿Ý} „]2î,¦3½‰Q©4ãìoÍ‚îë’Y×ëº2@­[)Ô²³8Œ*Ët_VKöÍ …°Ûp‚'Ÿ<°ßZ˜+‚ú´�$ãnÿônÊAŒfIFO”CÔÌ€Z¥*�ÖGGbò©0ýÕ�9 8Ë€Q«6àXña‰c„›R¢©÷pÐ0«Æ,–f¶ÎíõÊo?oœOÂ�W–ŸÎ¤,,OøÓ?ý™Z.<ÿé#Ëó‚–+ÚîÖg‚nIÑ&sI÷Ãu8ûÌÍ;?ZÏâþóô�¢|ó)±ž3ë9³œ’%â Gujì`@�ºÑ´PûÝöMôÆÎ9bBB²½Ý:l•5 ='Â9pù)²žŒš.­‰´dZÙèåÎvߨîÅc¬a5ô¦ôÚ *ÞìY,\–”5)9©Ó+á1=§T £�6š>ž’õP)e6æÕ.H·µÞÚFïPª²•ƽTî¥²ÕÆÖ¼Éû4à,(Á›»ëNE8(4cèÜCsšF%I#K!R]N„ƒ} xŸŽ>¨¿=æáa{ÍA§µ*µB«ÐšÅ›§ ƒyAˆ*�Lô¤&ÆÒeRƒö¦DµøZÈN_>h·¦óÌZòã¤.ÇFÙ"–(Ic^ÆæU€¾/ÍPcôf°ôòq‡>úz $9PôŒMü •�gà謗¡y’ÁÙU jÙ²&�ÜiD©31ЛRD)1Ъ¢=qŠ…ðt‘” IDATs*(ƒ‚É¿D,�/ž$Ëê•Ú\ÀÜÙ¶�®F7$£¾Ý%iŒÙ¹òöÄ@tô‰Ä8‘E6§ìkþ° ÜÖ�Á´®Xb`LzÀùÿÜ <Ü‹µhOþwß¡AãËÖÎSîÄŽ ‰J¦rŠ MÉ Y*ë)±>™Ò"U„Õñ*×Mùz­tY9=ýˆÄ3¯7ååµñùë�oß6’�—­ðm«žXˆ)‘cšèÛÛλv÷òµ­1œKUãÚì j¨€æ�‚,H>è †d­ zuä}3÷¦�”Fyü^†8�ùƒwÐÖ48oîî„õ‘k×ö�xz£„Q¯<ÀV�P¬Ys+Æ1ØvT¸tËò‹ìFP«…�Ü3Z ¿oïÙл5~³éèÌÄÀ ‚hcI�˜áò´Zbà‡ùÓ9ði>žŸŸ·²q-ÅóJB÷sÜÊF­–øòëÿ ½±ÝnÐ9NKâr¹qZwZsN Q†tÎO+?þé’? ¹@¨H(°²˜&|þ!s½f>~²ê›óyáÇŸNüó_ž¹<} yŸ�×—o”û‹�Õms}kþdò×Ê›++;‘‰@U«ž™Îå<�‡hÁá¦lzTB#ˆLJË[Cþ; l ™7Ã(zËp°=†œµ†Oµn´âIé™””„u‰œÖŃC†üºÝ7¢jkcëãª'w©1ôTwÉN%5«¬Jq$¢Ó° eË”\¦³LÇu‘ÝÛ1ð#>ƒ»úÙ²ãÞý¯>Smõ^P÷á©¡3÷q¾}õw¶ S‘Öðøúæ­4úãæ_‡€öÀE|g§üÁ|O4_`8vï½oú…‰îý£3úîl½ÿx»Ïæ;÷õ;•ù¿ÇëïI”·_ûh(>\ë˜øƒa?&˜êø÷îìíþ’ïýÝ—�`ùCå†?u°å¦c¾ïT ¦Î1�÷¥úÎÞ3lßÛ÷ÿ²M^0¹z°éýKGÒu÷SnÂ^²ì¶ B³a¤+‡©âȯ�€½êvpE£±Íct¦{å˜�Enw_[ þÉ[ Pÿ{&îǵÆýú.Ö‡³FbNÙq}aú Ã^™4–N¯h¶©Ìq̆òèä0î¸� 4B¯¬1s:eN§Èé‰Áì¤á ¢Xð¹ [�ûÖ¡C“N¤ÊÃÞÔÑÃ5Ð ¼HßmiëìÉ3ïpØJP ¾SÃ$¸0`Õp ¥éÆŽŸ+xTÞóg¼Ó5aß›ý:5²×Ötîžpgg(‰ï©IÄóy>gR´êŒ§Ux> ÿퟟùßþò�­T®÷;ÿñógþŸ¿Fþóç¯üç/ßxÝ*Åý$q]Ÿ2�@£—lTîݨ%‹¬¼‰uZ‘EˆXsZ* ŠAÅkF•˜¬¢y±ÄC 7#ƒpÛ¼5%& ϾÞtO ˆU7ªùnQXN™çÏÙ Û½�Bæ|ú*ôš)[ååµÒú7TVžŸžŸ9- ¯×^^^ •¿»ïÙ�¾ðG¥±t�˜ÈˉœW$$§,õ&™z8¾�âûM Ôœ§>¨ÑSh³ JZcÛ”R,1P›[b²a¡ Ô ^Å ɨMÁ¨Œ,°Y‰I¬¸:g–xqú.¥¶�Rn}éÍhd1Z¤Úðs­ÉfÀJÀhö'a€˜’íBÙw¸¨BR´F˜1ØZYÀýÝ.ôÖ�·tBì¤(ôhãY%gá~¯|ûvãõú�ëëWN§…óÉlÈ#)rôÚÛ´�¤òš•×o¿C¡–Wz»‚²,j¥z½•üè™^„R@ÖÑb“½àQ­°‹o�¶A;#KÊN—3¾â”«ê‰�wpTð£­Á°àç¿�a£‰�ăßCîÍXÎpÞ}¤ãÃjn¸=»ë¦.±j#™÷÷�ürg$:ÌÞ2ÀHb‰0J•ÖQZ«R ÎgŸ?!ììù‚’×8�Æ‚xòÍdÔh⼃B=˜ :åvïÕ|\Õ)Kó²’—Ìù´r>]¬7a-ÔZhצ¾1 ”¯ŒŽ„ƒzŒÀ0*–°ÄÖ¼ÕÊðÂ&kÇ d£D,éÉD0_;¸ßƒÓI B«¾k­ùO¥– )¡=’¢5D7°`Ú—P¬J@�ÖªƒúÚ¾ž(­6ï禮/“�Jµ)]¬ û  êc[çöºQï—Üyù¸pI?~:³<}à§ú3ª‰?^§@ÿö+zëj×8‚¬wüÑQyxÁöÝnÝ^,¨Ÿ­¯Ìr^XΙõ”­·Gë–ˆj˜ÏQ©hÛ¨õεތ3Gr^IK$œVH«•KÕNØ*- œ2§O+èʺ.¬ëŠäHXºÝá~§Ü7Êm³Ê•&ôÒi[¥Þ+å^�ýC �JŠÊ’ì'$L¦/rÚÏcmFƒás´„…"­Tê¶q¿W¶{¥”îU˜Í{g([U¶¢{b 9XN¼_@—=F­Buûd€¥†`ŠÁz«8UITLöÎ&Û"µœ�Ù^£|®M&Ý�Wµ©WðØOïâ!BñŠ!ïˆ%èBhBlBö~7ã3]G<¬Ók%Õ„dOöFh¤+8Gf¨xæ&ô�J=D�Ún4{%Ρ*Ú¢aâEÆå÷^YJÃÁ:h”É[4dúØÖ¾ “·ÓuxFú ¤w'èðå‡Ì¥Ùî^æëÍVâ3§Ór§  3n2¶]1×iÒ-p5ç§¹î†O· Óp–l¹G?‚dôÀ }ÜØá&Ç,¸“¦�rÁÆò&9H«C¥ÀC(i8õ<þØb¸�îÙÞw0ñ}NQ7x`6c›%O2X%‚8‚5x¦+¢¸�6JÒy�zÜËÇ0¸dý{G6½©¹(M,3Œ*]<›| ~f€™;ÃààÔÊÔˆâ[­=³eŽüÞ´ã©<�©0¼¶É¾Ì §ÅÖÄw©•hUepµÉØÃ#êY;4±ÌÝØÝÇÚiÖ‘}IBX#9¬äÔYbólpDc ‹•¼õ˜è!£ñÄ·k…_¾q«&à5œˆÖ“áõµ ¥FJ³,fL'.ñ4ÇØz§Þ«ŸWë`†$fØy¿OJEpf~Òwí;YÏ^ Òƒñ¸1l75G3Ò`”7®q»])ån /[î„P =¨1Pü}r Çbô}åMpe¼×¸áÌ`ŒÄ8œU+ã�ÀGÖ"Å@O–®éFó“#a#�xZûì$ß«ñ�j7yBZ¯\o7¾|ýbhÂ-°\„í¶Ñë�r¿q»Þ‰9“Ö…€²)$.ë3Úš¹ý¢ÄõŒöŠ5:oÜn…ÚŠ£úÍ�”×ûWþökç^~ãë׿s'-�ËSæùy%}ˆÈ)V%GøÐVþµÿÀí5\žË“–‚¤È+­}a+_ÍøìÍ8 S´Lô@Eø™³¦˜¶®.%ÍàïÝWf^×l8çŸõïŒãïAq NˆæÅÒšÑXÖVPº5»K�”¼§™' …Eá|ÎçÀé9Ÿ“—�ëN;ª6žÖkrBï–Lï†2ë˜: £ãêB4T²Z�Iˆµ&­�ÒU“Çz×.3¡ÁÁF3û~® ª–Ä4JUlkívó1é0‚/Vy~Šï8bõ §½l}"R}ô”ê¾Ôü,g0 d†s†Ë‚•ý'å²t.Kçù9ðÃ� Wª^X?NÏÊåCàü,|}Un%sݯ·ÂÖo^í#„à42Ü£V•Ö‘¦ä”Éi!iFdE[ mŽ ÖF”f@Š�PVDWèÎQãö´ÍK¤–�­6¾~+¼Þù1X¿´-ˆÙö@VÕd%Juû:{%oöy ôæ�Η'žŸž9�NœNgN뉧§'^¯w®×;÷Ú¹W%å•åtát¾°®'£%Ô(ûÑ�¿gE 8ÑéAAz§i'ª’m•ÐÚ›‘uç'Cö÷˜­*³5çk·~fað·§dv²Ûñã<=B·þA½¡ñ�Ö �Ñ+èf`¿ÞÍåuºT ú~ë^Rî>ßN¿âÈï!;†¨¯}6‹µ½)[1yUš@Nˆ˜-µ.Ôj�ÉóåÉO©U©*a¢CÁ?K\ŒšD �;1UbVÎkbÍ+1Tj¹S¶;§ÓÂ}ë¼^áz¶"l¥ÉóéD�WŠt“íCÂ7—ç»ÞrÔ¨­j?…h•âA§=¤Ó£ÑÛ¤ˆ)X³ÑätÁtiüö ñ&¸êûg\æ³9-òX3šÙàƒ²y7)5ˆÌ „™ä&*þØ«nT¤ ™öh·>²9°»…Úp­�*O£öJûTÂ<ÍÝÇC°€¨ë¢Fcë÷Ã|› EÉ7Olt¿×à>Ô¯¶^é^õ3ìTÁPû½A-‘-xÌ¥UZ½ÓêÝõ)¢bôÀ¶R®åe׋³º¸ÕIù3(D†ÕðõëÍw]üíj€½‘dIùcÃcÕŠ5Ž7¹?(¬Jk4U¤T$XòæèìÚ° ó È5Í×›÷Ä|ÑnIÊfÂ@B&j&H#E“IƲ¡Ý+áµ�CcBÙ¸}þÌuU’\'�RQ‘fÁl�3î�L¦ ÜÔ·Íd€Ô£m:è®Âuþ:�`l,£ÐÄ*‰K-”Ö([aÛ6äh¹Ós‡Ü}ŸG⺰º·dTK²dSª#_²dy"¬gT­o^J‰0â Q�ý"'Ò r² ,í‚n�~-´\(9XRÔ8šA->+¡íögPHql£ª'je÷ ˆÑ ƒ‹øC ¤n!¿Ò)÷j�w ÐÙTÙÔÚ77‰¨5wˆ‰‰Lï^�98ý-î)´€ƒhdiH´¤Ëè9«^5ÐUF�ŽPš17m^íÒQTƒ%ºèÜüÚÅYTFo"«:L£Ðj�Ø;©7b DiÈLÅA¬BèøYÀuT%T!¶N¨J¬v6ÔûØ(ÍÀ?‹QÄO*Q•½�ŸõXþØ{»GÍÜ…±ýJñ¡6ô�að‡‡“çÅÄ™§ŒnG¦Ó0��ýƒ ‡k8JašÄJ‘ºáÁŽ€—‘¡öf’£rh¹ÃšÙƒùÝ… ]¬Û³–°ä€ -¸a? »=)dWbÌ ŠAg´OÚþ÷8Lã œºàÀé6³îaW|—t�A�Ì®=·q–H‰Í1œË|1gÉ�Ýé—ÖÊÃ*z¦Ü Á ¢ÖÌ XSxžqµE›%¥ª¶ÉÍèß•Sëán Pd"̦ï>›@íx{fµ�W«2çß*'Ô�û¥nè+õJ>?Í- Õ¾ÁsDC;HØ9÷ÚF0ز%Q|°ã·qZŸ˜&†"éÑ>[Õš27KFD±¢ƒ%&ô$,¹sÊͲÁkDr¶Žò)£)#ùŒ,ÏüúõÎë½Ó_;1fšdÕȽ¼òúª´¨=P¼ŒjÍ™%g¶m£”�RîÔRˆ1xCgÀ µ:~ Þ·@’[î¼Añ^j»Ÿ[±³¢®ìÔ2üÖäÃÓ´fHy&Š Ýo=GŽÂ‘\±2µ™è³rÄÊs½Ì1�Áíh<ßjF¿!`ö`‚ÆK2‡#èL ,9z‚ÀÞ×[§•f]æ‹5�­Û�VªŸi¨½r½½òÛghýF¾G–-²9ÇÜíõ•×o¯¬— yùˆèrÈij³µyeB8™Z¶Wj}å^^¹×�KÈ„Q áõþ…×ûg~ýÍûk/Âi�?ÿó�¤ù‰s>!²DÒ)ð!¯œNŸØ®™²Ý 9‘Ÿ:°A¸¡¼Pû¶úµ™ÌŽñ„ÄÕ¦ÖK�mûÛ¹6Ñ aP ù_*q9hÏF`稙ü=²@Ð]/ÿ¿†©Sö€‡ÿÿ`‹�’ÿ‘nºÊäÝ@ÈZÅÈž¨ž˜1ô ±‰9uP ¬KbÉÉ+�Z…Z+w»sKþꨈ8�cÌCŽÑûý¶&Ô¨%’‚!ìB´þ)¥�z£ˆ; }¿Ù ò’CÅØC0ñï>ôa™FøçÝ„Àœò££ùh˜3pHðúsoßý{#{ïu}ç_x?Çñ0€öšrL à6ÆÓw¯òæÚoƒýúöÝ:êM™ë®Ç»øýuI‹?|øëáaÆ}Œ±½¿>ûsoì³wßú�Ì÷í1ßÿ^oŒüΚüÎ禾“ßyÿ!A°'.Ç‘ǽú°7ö30%×Áž>¾÷û˜ø>}“Ò ŽyåØ "ܺAÕ¨#GU©!óÜvë#Poh¿™X9$3†-ê¹ÎÉ�®ÁÌ! :߾ˉÃ|¾½{óÝ1ä>dêÌ<îK•‘tžs UŸ•h�ä&ÈËl×hÁ«˜"9FrN ÊVn”ÛVi]Y,«qk§gµãŠrB9Ÿ—KätŽœÏŽ¨|ìÕüDè=P«'ÔšèÕ6€r4ë&¿Gr7Ì}g¶¼/ÅK,øDA}}³£ Åæ�½ŽL´°åòwº+X�_—©¦9ƒã bM`§M|ÐgãÛ(s_[X‚FuÐUvÊà÷Œ&6ÈÖ$œ2œ³Z£Àç¥s^:—'áùÇÄr^ ëÂåSàé£rù(\ž…Ï_*ß^¿}éüµúµk¼O¾˜/ÖEÜ7lóÄ”éâ~O§oPcA¥Òu3¤_$dšœ÷ !’Dš«èmÊë­ }c] ™)1C"f±„@¶kŒÁ€0!“ÒB �”Vq„z2†fz*ˆp¹\x:Ÿ¹^Ï\n><à~¿óÛç¯üöù+__oô—yY¹\ž¸\.¬'£j]ö #ß;3!zH*íá޴ܹI¬-›¦LÒæ‡2eZk°€†öf\áÕ‘™Á š�žˆ)“µ Oj³G�õû ³º»×B)›%!Ôª>¶XØî›DÕúHWÔi7ϳŠìZV,•½ÖÌcß6‡5§ù‘ äe1$nÊ*Ý@gbv¯ímó¿Zˤ”yzú0ý“)}ú8!,¨œíþ"Ý�þBŽ…åÔxúùÓ§§¬|ûú+¯¯/ôn”²¿þZ oÔ µXúéü�k‡MïH�½ÇŸà®ë¡_ÆÐƒH£ÁnˆÎ»¦­£¡�Õ+ŇŸ´.™¼,N¯ê@ÀZ(J·ÀîmêØÏh½:¸PŠB}TèM0¤ï·å…=Ùk1è!@)“BLÕèAvz(×Í¥*®»$¨W�éþ}} ø™²ZzËíþ$"&›»Ùùt±OÔf ´ñÁzPVu0{dʤ¼S‰®KFÒ`èqïe1D BJ§ˆÕ«‚m3:ÔÑ+@4Yü…ÀÞÕÆÓ'KC˜>¯vë#iÄk¶[×ûpÕ&k…Û6VqmÉòÑ8E¯ˆ âÕsí¡N`¢Í¤DpÖ Õ@Õ@é jU)Y%ÏH Ð økÁV«Œµ$Sˆ+)5³iÔR(½ÐØhµ�¤‘Bg Ê%Bl…ÛçϼÆ�Sx&?G«¾_±H°€–ŠÖºGŒF­QOªØóè;ì`7ÝmÝoÔ…ˆqÄK'�eáâ ÜëõŠ\¹DêÒ鹡¹!Éöeމ4²ë]=ð0ƒÅuòr"¹ýÚ}|ög”HÀˆ-[‚.hpk�-r´­ÐKA«ƒ1ÃÐÎb÷”º!+†… L*\›£NT[ú4b™1’"UiÁú’¶¢3)PT)`Õ!€DÓ%a!ÄìûË*XZ«Ny½Û£a$ðxF¬$é¤äÉ}CáZ…@—Ùà©‘mlM¹—νv}xÂn„‡µ{"¥ã � ô�žè¢ÄÞü§ºšë-·ƒ*¡AÕJô„eoZŒ[%m�¥uP÷¤[§# RKÖr`ô›vVA¸~ôÍyûãã+)zíÖîk˜¦ÎH;di-ÀËvÔˆnÅL»|ò†3*# 'ÎKeá�ŨMêŠy}[£%o´¶o=¿Ùf‚Åx`ƒ59‰fj0î4í† M)Ì�£] ‘@ƒì“’�ׯóÇÈ_þí#˲ðóÏ7~ûuC ‘•ëµr»:¯ß&D ›× {&|$@- )V„É÷!ó†ô?#ñ:TÏÐ Ýi#†ñ9Œ+õ7“Øó„þÍ@�ºí~Pƒ~-7ì ­TÉ‚@˜(ÆìÉ�(FÒEÑ`FjŠ–@¯< Ã(’ñý¨‚„L1ª0Z5žÅM„ dÙ{­äÉ1н1¨7|ßµc9 AŽ(€?C눨iÆŽÀç@[}ÿûq1M ®îø7ï}ûñß{}š(:ÿ7Õ¯|o¿>tø‚±ï|…ø+ooÉfAú�9_cß>þÖÇ7öü1ëpÉû }øÊ·¯�5–Ãàý<çêûÇpŠeóï¾W~¯.ã|çô˜p–ôš<ÆA÷{“ö{é‡Çq¼5’e_Ø·cñ °o/�÷²Ÿ{}ø·ß÷^Âb^öñ Brž…cÐÎÖ±a"fÀoÜùÔ¯9hCs¹=ÐŒÁŸ—·÷°`îÝ.hpª Ÿ§y†­÷pü<é6ꨖeŒÝƒ˜~Çd£ŽF†‚s4‚ÛÿÆqëõjâ2_˜tlšS’(KAèH‹‰’2ª�óeåtZXVÓåµXEÁJg¥q>gΗÄi�¬«Qƒöî8�:–À*m[ Ü3ä Üw”n ój«ÔÖ<¨dà§ÞÔ(,ºQ¿ÐÜk¤e€¨û2}¬A!ª3ibs,j�ûñße9Êa=í &§Ç90©":¿¡O¼–×7Ѓ*;ì {¯N´hJ�œªxª­ª�¶¬ªS-ñž eÍÊ;K¨\N‘çsäOŸVþé§3Èä'!^„xžB‚°"é™Ó)ðí®·Äß~.¤ø•¿ýRùvWîu£k™ �`÷GÀpG�ÍŽ�bcÖ¼Ñó) 7Œ922F4X0ßÀ0�Ð]ƒh@âJ\,xܪ"iAc¶ eº­©6ó55×öu£Qé¶»�xzUGF›Dتr½ÙyºßîF»™ÏÏ8�Nüíç_8ýõòo_@¾—³!Ø%ðòz¥ö«õŽóê�IK Œ>|`4ëIYOBH‹U�1T¹WvŽ%"Ù]Ö¼Ù‘ýŽÊW§£Z×K^�h>† @„QOˆ÷ I9YBÏýzIÈ0iÀQ )Þ)u¡õ •‚²Â„¼:ÅSWë}—²Ñ6jj~K˜ã5ßÃAh¥4ú£�Ìv,¤˜ß"•­Ü¹ßy‰,ËÿKÛ»¯I’ÜX~?ØÅÝ#2+«ºIÎhv5Ÿ¤÷éVÜɾVfF¸]°fî‘]½­¾ 2»òás3ppp°€šVJe/Ö'í42µ9…†U?¤¹<]ùãŸù×ÿüŸ?-ÜÞ~æíõW^_ï¼¾ÞyùÔùõûÎß~¸ñÃ�wó׃Ð5Óô‰à1¡ª5 nÒhR-~ëG�Q Ö”5'o›"‹Wg‹ûøÍƒkX@r ’ż#µu`•ìJéɪ¤f¼8À¶FZ7Юì�Ý+÷eJ ³äýåBôçÇL\Øgày b2ø¾> q"âÙ¿š{© ÐÌ~ßU'‹]§qó$+Ýõʇ<XV|&qY¢÷`$¥º'ƒ"´Ýü›9õ=xTe‰á<æË;h¯NnRcFW­ôhõNÙÓtj­ÐwO°£{¢s IDAT}¥)jÝ��/°¾~=Xµ‚0+õG5×ô+ÆXzLÆðe<†²*zWrhâ} MŽM½1{§G4§L­a:‚Òh­ x…U«tol^MÒa{ ÚŠU!83^{CiÔ{äÞ‚C>Ö¬¼Öêòh�&Vž³õ‹é·DI7^Ã+½þÈõ9±=eÖçL”az½aê#8žo«2§îVÍúK³¤þV5p*訲�ÇAD¼_¥%‰–/WÈ�|¿°íOäÕª‹òeE.Ñ�øn˜YŒÓ÷›ÎÀ‡ ÃÏrIÁÑg‘6ItGO"wͺø5a1y K&Ü ý~§ï&áŒv»ö(ô h´¤�±zÝ7‘ærÊÃîîÛ=‹ 2³­e­J Á¿”>xѾ1‚‹õQHi!¥eÚ�*Ki½.E! Ò¸E Hâ’ˆiAñj+Ô4"l÷êk½7³�Õ{] e3¶ç¡^}£¦¡b„˜¦�Ú#¥WR „ªh»S¤Ì¤Zð¸;j'Ôƒ¼ˆã.9G–’II&K0ÿ@›¢µÑwãìU¨Öí{â}¶ñÌáüöø3K‘6ñ„!}cØ©Mªê¬|läažepf :-=®@D&hŸ£9ó=X`ÓÕÁH/í°#xé³7u~;¶�éCÊBœjÇ×h¬ÝÌ)Ï9zbÀºØ÷èѳ>ÁÊ8&fNh=VÃÑ÷8N{l@G9­;y¾f§vÛ¼�Á3ËFÐÕAIN{³œ0´Ü¦á6£íQ™†¡ëU§`,¦Å´ØË� �œ„ë–yyZ¹®™5‡ùuÙÏO+×ËjŽ@–ÔXs÷ò£Ht7Ùø¼\R;Xhêä͉° ·‡!s,,Ùi‰§Ö;œ¶8ÊßœíL«±‰š³^Çá<œ÷÷ïòá¢ÿïùp¼±¯ÎçÁ‡�þÇÇüÇI¦óÿç¿äßþé¿gèÇóë7Žò�¼ÒßþÍÖÊÇÙÏœ×gûs¾Ž‡¿+>ÑÇqŽVæ÷ÓçN“è·Þ÷o¯oø‘þç㘧Îï!ÄèM5ãL¨ë¹ïËØ_ýàÌ^mÙ}â`Øç<žy-õ%LOõìÙG?&Žë6Ýö'aøçF ç‡ÓÖûŒ‰Œã¨Ð 0}Þ€š¯�S\{5¡,ÁÚšó¬vx~¾p½n31°ïwÊýÎBc¥²]2ÛÅÈ1K¶ft–PZôÙˆôÙ«1ßïE Jïì­Qk TKÔV ¬,�VL¡Òz¨` (!4B´ÄÀ9¶êj»Ž1MÆàøã0çMöã<;ÇNø@ޤ€ ñùå…ï¿ÿÿé?ý'žžÿBÊ’VkÊ–Ë•÷{åç_áýV(õ þŒL|� C"åã D2‘%fK ŠU¸ÖÖ]jH¼b×È )/à•ÂÚ›ƒ3Ãÿv ‹=4p%ÄàŒè4c„31.>ï¼ tZæ±zl¤PYÓÚ.íFmïÔ~óùÜ;‘Ý$1ºRz%„IѪ*Tn­QJw©A4mˆt–%CrŸÊÁä>4š;{¹nJJOä¼Ùʉ ¹T‹%´¡(Õã¥Ð.”ÒY×Àõéú§âÿø¿þwþ·z¡í¯ÜÞ~å/ù+ÿûÏ”’¸ßþo?³®?ó~‡Û½£d„Og®w�µGb`<‹Á¼ŒQXr¶*€‘Xì_c½'cu۠¶,¬kfóĘœk­Â¾C®Pz¦6³Ýª:+‡F5¶zbà…Œpô,­#>nÎ:—`¶F‚Ë{ÚÂñŽ=/:«ÆGÜvì�2Íà$¹ÑRü9ŠÉ%u±ÄªLâRoDÄP5™™vôÆ ZA¨5&÷µ&™Ôœ4\¦¨öY-€Z¥µø>òp¿Ž‹´gi£k…]Ó¶�DìŒÓçfí�”%±Çð Ù�kõ³_ácÉØÅ"¶®sŸ‰�‘¤¯F°†°Ñ÷C8ÅÈiâ,ùÒ‹Ï ¥Óú>û¨«z¬Áø�§mDôB­ïÐwbzÄ10«Öoj¤á€KÆžp[ƒ…½V25$JL|­�_~¾³=%¾ÿÓg>é¹%Ò 4BTß›Ã1öÂQ¦(ÃÃtI{ÓQûdD}6ÁÈ�ûqH‘%?‘?m\[C[ER„¡jàë`o˜gyø:ù€á3™Õj–\ÁjIdzCÉa$ÏB€´ ›’è^èo�~�h5Þ‘hP#¦~œ¿k£‰á¹F¯Ø2 4ƒX€ªaµAhA<9àkÝ÷£‘•v9›Ê�*„PiRiT†¦¦ïÐs ,1—HZ29/¨“u{é–öfÛ1ô¡ÎdrãMMnzÙ}M`ø³jÿ:¡ U#U µ‹µü,&9ØYóʺ˜¼t1©CU´Æd ³j½(wó ò’H9²%ð&Ùd/žÐ0Ùï’‡2Î0âÓiO/>!$í;CžÃÛ_¹qíÆÄöàG�¼„£Ôú˜ Çê9.e,ð”Ô˜Ñ_í£Ë ét… n <Û8dˆ†žY5–Âh&$dwêU-˜ƒ�’•)�W¬:ÙŸæ˜�àr€ûâÚRÌŒïÁÎ:¯ïƒ…1Ê߬Éé(ñ0m?Ó¦äô¢ºg÷E°ŠÆØ‰ÊÌ,�ôe!E\;Îûßrd[¢‰^I:Kž. /Ïž¶Ä’„%Kv]#Ï×Ìõ’Üi€”216óp‘¹OC Bì ÍÑ t×îï*Kt‡ÔAãàr¨:ÄiÔƒ—µ ‰Œ,ý0¦cˆ[l<7 ‹É*8ME‹mø»¹Û{dªÆÔ²Ø¿ Z¡—€Ž2ru£Žy�̪l;]̈$—Zè’hy½W~úõÎO_w~~müòÞùú¯{à^2·=òvÞnp¯Ö;¼©ZuBèÐ<™<´ ¦A:®ë,«²øÜJœA¢³_|.©;ã¦ÅÇuȘ† %Z­ÕJi›�"}&N�¥ô`#Œçf3Ùÿ®§ä�= Þdžnç·j�Ãq™’0#ñ¬ È=€—§…¦ì• €£™,Žé‰º“¯�Z:ûÝ‚À²×Y¾5Ö³DèÅX69ó+ Ú®Þ£ã�^ßA:1v‹•E¶‘ÌT–h€J �À ­_AÖµ³nBÞV¶gáË÷ /ßEòS$®V9z¢Ü#·7!èB q½&t§·j`xp'8tÒ*<}ºÐ›WHeyZÙôr/{`¯–¨ku¡–…%&²D–÷È’‚õ ÍUëhh~0llŒÌ1¨A§?1æÜñŸá|e¶#Ù:LÉ�-z´©c­öZü—èËÃ߆TAŽiž goéXºþ¾<4T£q릫;ìx0#Jô¯L©›ÀGucmÙ>,¸<[;ÀÝ* I­Ì}$¼å¼wNè<ÖÃýëùwßñv¼ÿü;ÿÌéº�q=ÞcßWr€IÓÎyq¾‚ñó(}¸ �>Š>¾ï÷±êß&9ì£�AÍÃ��:N{>¿�çk8'Fd2uçy�¤Ø<ºŒ÷Ÿ@ßÓH|¼—ßþ¬þa,uùÍGÆß¾©É¯ß>ãÃëwÇø¿Îç´Àýqû=öÞoÏÌßë#0�÷�ÎÿðÝã3þÖ1�g{jÒ:Ë8†œ|aæ=�Œ=÷p�Ü/�'8?œÓgÝçÜnûìp <ø;Çaló·2lßãB8ª¤|WOŒù‚6*ý8ütc“©/wõ½Ò’¢CîaôÌ‘ �çú!10í�'‹{Öa\ï�gAè)10Øñ?O¾Ê´µV%`¶8Ç@Ž�Ë’¹l™ÄÀ¦^è­DYW!»Ïi=µ Ê5+—ÔYbõ8¤QR'¯—- —X3¬‹ÝºiÉ&£°I$ÆŒ’é-°Wá}oìU!d�HÑvT t'Ç´ÊýV¸ß ÷÷Æý½Òv¥•î¶J,f^Ûw[ëþ¯éÏŠ'c…p¿Õš~Ä sŠ=óóòš+Pä·Iä™´ s~Ÿc8y˜�'_Àýã• š£Õªô)·—Ø’I#štPài |y^øÓwþðeãûÏ —K@’‚륇Ð�DM½m ­]©%ñ÷Ï7~þ©ñÓϯmÞTs� 1dBÈFÕ ÷b¢!búÀGbN]Šn @“£ªÞ�&‘Ój€vö96æ¼Xìuº˜ÞÁ&Vëêe±ƒl=£=3 î@ àZæ¦ÎÜ0LÏHæìZ\1¦ë¸Xg™ª•. –ÓÀ¤mÌÍ 5UgÎ{R Ï„›AmÁ@甂•Ú_¦dDpY‰8²œ"ˆDÏ|¹ƒ$v6=Ø›‡stT* ÃÚ‚mÌѸÑXõ`.{à¦S›#3-ïˆÎIç÷dDÄô)½iæ9ƒêzÉ<]z$Gزð|Yøüráº%²ë Æ`�s¯—Äe� é-‰ ù8鈣™µÜb–|6¨�Ç<“hí5D}céÑ$�Ósézôî�Z,ÙÄʸWÕ ži=Æ<™êÑoaFìâá:KÙ¯fY؃­gYë!Ú„'­z‹èÐÚÅ2˜GBI�Æ)C²¦i�¸Òz`ï�_Þßø÷ ÿþ÷7þúÓ;¿¼V^ï�[ ”–)-Ñt¡öDi 1Øš«e ›G¶f¬š"z0cå»Í�ìsé¢%ß•ÐÕ>ãcaÁͰ :“âéÁ’ó¦MHéT¬Â§VcÈv¬µ±~{¿I�Ȳd/ÔéÎòÉÁ8rt£¶J­Á™(ƒ©aÁƒ%C¢7mÂ~N‘èý R²­¡5J 1"8=Úó-»ò¦÷´˜Œ�'ÌЮ݃s’BŠ$¢éòo ùWZüÊ`×¥Å6¯Ö•Ñ€fٲٰ^Iz£Þ*uÉ\¯ ק̧/‰ç—Äö)°^²íHÒÖ¸\•Ë.O�-/\–ĶfbjÀ�^Aªm¶(Ëùò‡/Ђ7ƒåy#Ëšhwø®<‘D)·Ì~Ëd"I­ñî–#kR–ØØk¥Ô¡Ÿ<üÃ!? –‚ùÂê®ãižœù±ÿôóÜ¥†î4 ã_N ºýç -Nm{±y7æÚφ½íÎ\2[k�O –@^r°fƒ›_Tûæ r¯œtàc$pݶqì¯cÿ›×®s€íL.Kç=´ÞÉÉÀ�ÖŽ²d81–�Ûfí)Æx�¾ñ~üÿÆñˆqHËðøç^|\ßcP§ÇcõmœWæÏ»ëïßÃéVÎÇ”ã\–>‚¹ó™ÆŒ”‡_>ÎÓP>ec?üÆM<Üãé°#|_wŽsœcm¡ú›«9ö[cóm€}^ÉïœóÍëðWléÙyû_t>ÀÎóáÏgUïg5,˜½AO¬i{s>�uý�Ö“]bbO>–É8¼‘<âü\p�åô˜Žsˆïーàd}«æèË1×»Wa†6|(cm^¤ƒHø8ȸn³w#6‡cÌE·aƒ0nß.ÝôÑ'ð ÌdJâ Æ8ì¸<Þðp×ÜÕc´L5»N ‘Câ²^ž3_^žY<©ÛêÎ~ƒnÒÞ* ÔÓY¥�UÉ-’D�^‰R‰ZìdQÖ \’²æäÒ½Þ§«xiµö¢Üö@éB\$eï`>aëjãõõÆÛë�×_o|ýµRÞ去©ÎdÛ2�Àû­pß+²7—œD¥É¯'‚XºŠU´c"Ïþø³Ò‘ P± U?®Ša=) ÇT<£<˜wñJ•QFKwâ�®ôFÄ’[ÖØÉÒYSçi ¼\ß¿¬üé»+ø¼ñåS&¬®£Ýûް³Ë¥úÆóSàåÓ•çë�%ÝÒ¼êZ}½DbÈÆ¦7Ò/´FÛwª¸¼„'ãÁã<ÔýÅŠ´Ý÷|°¤\ô$W"Ä…”7b\HΚ=¶“j1t­7Ú^M(R4dpÛÖ’�µu¨‚h§*Ð3e�6¾ªüüó¯ôZù·¿ü;OOOông±Þ™ˆt´6$D®OWò¦”bZï½9“¼wgÏ7P«ÊÍ9‘b$ºÏÒûG‘h qft72ÛHÚ1ªZg‹¤ŒØÕº%4Þn¯Æ¢¥oº(eoì{Ǫ}½‚w6vœ:g'$«R13f²¹T+µÞ­ª¹YãæǵªT:y±æ½!Úýt,îðkåûŽ6kŠI«D±~%½VZ)´à�Ž{ ÷Âe[)e÷9‘Ȳ³%¡ššäK)…!æàÔ…Î�Ÿyçßþò#/×Ê�+uåïû‘Ÿ~ú‘u{bÙ®|ú´òéóIwÞË�ú¸¿›|ËÐ2 #qDÃö‰”"Ûºðt¹rÙV“ÆLƒPgXµVú0öbA�¸—եР䵄å�¦²çc �ñ˜ß° “8N¬)ЖÄ}Iìkž~ù�;M‘�„ÔgeùìC7ü¸øzy !xüŠ�ÁàfåÓp¹aÇzs¦y±‚͹±£«2U2ÆððíX®�+Õj½/Ô÷Áñ\B´ñH– {ñá·úXkpZ °Qû�â`ôÙnh³¤¸ªIð¸ýµª [‚›lûÝ ¾)óèÍ‘S‚ä„*m"§0ØâkJ‘>ârk²=¤çšÛÞ�UÔR¨e÷ušPº+„Xÿ€˜‚íµt´èÖä²<ñ§?½p½d^-¼~}çím§×;/_>ó‡?\ùÃ÷_øþû—Ið}{{åíõ•RÚØoï¼½þÊe‰|þtáéÓ•ë§ i�hh•D±$ B76¶‘Å’ó{›dç”À¡ob‰€s‚à¡Jà�éïŸÑ!]î8Æ?°1RLêÖûNøŒ5«Ü°¶Ìˆæ8¦5ü×ài­q½îåMʈúñ& ;æNˆ IY#”@/B/ƒÞtĬòfús{[Ÿ“;T‹Â ¾†$“ù¶V}S 6ëwb ¡Õ�.Oª“R‡Ïœ/�N“o””†™�  b̤”¢E#™w$@º7¯²àÄJuc\IÎêÒÉLˆq4sRÓeìÕµO»lÌDiïh«>’?ÜæI8™29({ám$R\H!“¯Ÿ–H-;­îs ¦ÐI¢3q—<¶d¸^O—ÀÓ&\W¸n°mJJÅ1{7àSær_ùT6.ÛÂõ²s�FÈ ‹»í9ö+’× Ñd+o·&f#¯O�ðyá¥ÝwR¬äй,B’L 9VöØK¥Tå^¡µ³4SóD©¯�~¬•¹Q�ÍÿŒ•ÕÑûsÈd`øoçž}N Ûó Y>–¹?Î!-f*â=] 4îÎ¥G ØE Áª9–­¡“vë+á{Qˆ£Œ¾MmÅCÕñ`·Ž d®¿Éa&'Zàÿ¨ÝcPÔ÷„]d2ôwŽ=À¸UÇçwáóëp"�Ï�Oááïã\�{Áù’äáX�?ý�^ãZþÑ»ÿïvýÍÏf³ý!èoÿÎi„Žøì¸–‡�}L×Ó(Ÿyüf8ïð[Ð^�ÿêãØ}ë{{ÛéÚÆ?¬‰ß\¥ÂÇ„ÚÇãW¤¿;Ôçóü�’ àúùsߘÇÿ‘×9�öðl>^›žž­ÈÃX}ã §?èüùèàN¨ŽïÇgtîÉß8(Ç®{üNüž�!�éÿ�f½L0b8ð¶àtø‹œ¯oØJgÈvÃEÅ$ă49}Æ}çq¾Yñ5®]œ¡6Ì×POËçl—GBAõ¸O‰£éáG)Í!1†v<¯~H=ci$éDélKäéøòiá�ß]¸®™ ìï¼~m”ûÍ£»n31Íç½;{¿$mÔX©Z 4"Ê;[쬱sÉVel¬g™Õ“"É“ÿ�Ú„Ò]i] 9Ä(Í™ÑÍ¥2oo‰÷÷Ìë/ _¹qëÜß;½ZEBÈ‘¸&J«¼¾ oï¦-ß-0,U©½1ZÎŒê•h˜±ÏËÉÚ¬òmÌK±q môÇÓ8ÿ ˜ý!0 IDAT$zpB…ž¾ðÚ¨Q1.grΈ¿túÇF°ˆVÕa jÕˆØräÓuá»—�ï^.|÷²ò´ K(XÝ#T5–-é6‡Õ×wTñùó'÷:·÷Ìûm%J&†…}¿p¿mäxÚ¶ËÊr]ˆÉ欶Š¢µYÿCI‘�ƒõO•UøXºo¤ö½!Z“1ë¿yL“s|ƒØ¬:$mÇÜu¿l>%q?,LÿjØ–Ã<ê ÌuU{æÔNl$—Žø´Ÿ|i§ðøuxØ`�µŒŠ1“ÁO„KpL)FWX0²*î'1Ʀ6kîìU\t™ýq#‘hÉH}¬Éè¤`ÔàCÎì é¥h}ùLÉÛ*¤dŒ�˜Ù»:ÑD�n u$ [§#%7Ç|[iÞ ´ÑkE›Íís’åã�ÏqjÅút±Š‡&Pq¿Ié=Ðz¤(ôV=�ÙfE¬,‰Ž´ªôÖèM˜ý?Õ+ôÚák©Û*i ÅX°û¶+Ù×xÀ³Zc[ƒ=��²÷|12ñ·$@1YV°õÀ. ÑmG î¤=XNŸ\a,(ë'2(8»3Ù옆¸ŽrÄuJœtF‰ëÙÀÏ©­ƒul›Á\hjßzg(Ý[ƒ,/ÓÀ4£cb2 Å ÆŒé´v\;#ù³„¿?k�:Xëæ]å”ÉK6PÚÌH·`èÄP  X6Þvx½)?ýZøá—�¿üí�ÿö×;?í¼íÙû ÓŒ«•‹Ìà=‰¸#i�Óz3¶3ߘM‡¿–â '—ùb,öc‘›Ö¡ëË%ë?ÇûÃêßíÛÞ82Þ‚ÑRpÝP»çZ‹«­; ¦c2šm�Q½©'·¢ƒùG3n°²V»$E5’4:£¡úóÐ6$¤Yf9“@Ø&[›ÉõnÍrÄ如à«Ím�tºkonÛBhuGiž|S_Ç�ý~çý­x©”²]6¶ëÆe»ðüù…ÛÛ+··æ%òBÈð¼ÅÀšK^¬ÉÞsâòX®�m…%YIª6ë5"!¶€¤�K¿ ì¬×•ËuEêÊ . I¨ºSîwBVV+ᕈI, Ù—kq'¡³,�pÞ~½Sö­4´5r,k$Ç̺¬–¨�ÛÞXve¯�Ö„êÀ³©k¸ãeº›.O‡-³‡¬î„„)?ðI}üfº-s{±O¸k4`9ìqœUM¸ã–ûß(=Mb¶0xâ¸5�P:´µ™n븨ÃÑr`6Øú™°âÜ{†íðû·é,(ŠÍÕÚÚìË1€½‘ÑÇFÂÃÞ|¼ôt΀ü}üu^ƒíûðW9c:?©§ïÏÛÁ¸µÇÇöx Pv<+‚±óÛ¾u܃¡zü®ãÇíc2ááo¾§Ì€ô[×ü­¿0Œ+,¯1–çë1°c\öæÂ~ó¼Çß~÷ñž/æüßzÈÍ}õòu–“z<ÌÇŸNë¾~¯²ä˜çVû�0摃Hß8ÈožõÙØÈQQ4ÆXÇz°Q¿µg�Ö‡·ývl>|üwÆd–­Ÿ¯Çm‡ôî¥Ò#ˆ;Î2h5|=1«á ¤·«:ÿ«ªö†>nõ°öÓú™·êk8'låaȇDé™0~?ì�—Íbvup]­¹`ïÝô^Å$H—¨\Váù)òå%óÇï.¼\7¶5²¿'~L7^¿Þ¹ßvz+V±—"×ËÊe3Íì”"e¿±ßï쥳k±} [†5v¶¤l ë5°ïqd×ßÕúŠÍ•”�´�¶…°$k¼‡5îθU`¿¯ìû•÷×�·¯…Û×Êíµ²ß”²«ÉÚä̽T¶¯°¾Âò&¼ß*÷e¯Í]hq;EnÈÕ¾Äõ¾”­JÚüp³_'@‚îä¤Èš„%tr°—^>m|ÿå‰//ŸžÖÔ¡½¡÷H×hš“zN?˜œï½Òî;u/´Ö�4²Db߈º¢’é1“òJ^WÒáHWTï”û�ûýÕ¾Ê;U‹ÝW ´R¹½ß�IJläåB^kb\ÈëÆèÑÕ@…±_6*µJ-”²ƒ÷kó‘n­Ñª1‹S Ö#@„¦…ÒÞ(Þ¸º·Bi&¿¹ä…”LO¾«²ßnÔÒØ.�íOy#/+2­[ÕjÕj’^!àÕŒª^Î=$­ÚÝcWÄèÝ×®�Ûm²£�Æl!I'ÈRªéM�ê $øøJ½qßß(펆 R©E(E¸¬?çˆ]œÑÜ\ÃŒÅ.>/ÄÙ׈Uã—;ÜÞø§v}­�½ÜY·«ãNn ƒÙë$¡(¤l v¯Åä›\i€Å¢Æû^¨u¡ ­j-¤´ÄScŠE˜Ý�#GÁºøî¢Ögì¾+ûÛ+÷×wž¯¶. ðt}æ�üžú—?°>/¬O™þÏîå�ü?ÿ÷åë/æÇúN½¿éKÇÞg`\‘%›zÀõºMÛgøH?|S›ð6†!F£Jiâ¶ÃÿëU½{ïF”4jÜ~‡ .³c$½%EÖœSÀ–õ‚{L(Û˜ÕÚLVË“­÷©ÚxK³©Ê{O‹1°qW”^�ÈjÒA'c¯Ú žl³y†'>ªW¢ÀÞã Žµ�ÀhÚ=tòmcu|§ÙýYb@)µBb]/Ä”Ì^øïk³=.—•m]íÞzçýý�÷÷7Ê^)ûÛØq ¬ŽÙ{¸×BÙßgÓݱ·Ž=wÈ›�˜Ü)Fœ~âÀ£RdhÙ‹ZELˆC*Ýï?.&¥=ùöÛdäã #¡G¢ŠubÆ’·ùçë±vzè´Ð¨Þ¿£ÍD`ctwXS¢åIJ#¡DŒÄáû›võê1ü¤OȵÙ;¨Ön}xåœ€ÑøÚÕYò÷ù 4Mðbj~  ØYõì4ìáu=šG˜Î™N†Ø`âcÂK´1Mê™x³ç<ìp æ’×9iñ�Ò‚Šƒ­‹`YÔ0³c3ïŒ�l„ƒãØæ@æXrbÍqöL°  ï߀÷¶%rY-1°f!'E´Ò«Nƒ}½Z†~Œ§tKØÌFÁ?2ïVZrä ÎÿÐ�÷ÍÄðÓÃ=¡¤Î4ð@Ò3k½šýèUh-P¼\{/b‹È�ÕÈŒÇð˜«ÍÁØ #˜™Ž‡¿¡ûüïX¢1–p‡F,aÅÙJQ�ûÅW5�}î�{Ÿ¨˜M”Ÿ^+?þ\øë�ïüõÇ?ü´óÃ/ðvÏì-Sš°7+gŽÁôãG°¥b ‘>_$�œ©±+œË%í- wv˜|‚gÄc Ĉ Ì·° Ÿ•CkMà 5GÂä‡têk7—/êêr1’S"¦DtC¥ ç«[FÐSP:!=ßÇÆNÀŠßoŒ‰˜-Ð q±÷{‰V÷F¹ªípÎÔÎÅJ·ÛäÙXojC&ÅuÚ ë…äò^ÁVa-•ý~w§¶C(�nl›²¬v-�h‰€HÚ‰]¸äÄÓ²p]Û¹^×çÌrQÂRHk%FkXcþDpR�ú$Œ,Ÿ6�¼Dò­ V�hVHÔ¥s<©4œ|§;0*¦^èĸD$4Z}Å6çœY–�¦‰Ú2{+ÜëÎû½ñvkÜw¼ŠÀiKQ´YæzÝõýgé�æ|ð5,ê6p0GGps*ÏaÚü±Ë\+¨X€'âAåioÀ¡ïo#¹eÈS4À«J2QÁæQ3¥ì…}76ƒ)£ðÁ œr¸W¯aF ®Ûr\¿·k·ªUúÊUß°­àË7PÓ¹dޤø#àøø™sRà�åí6f~áØÜ$i"J߸ço¼Æ¹¾•ˆø½ëûø»á<ïùØÓ'þÖ!þ,€Ö8‡¿oÚZ?ÁY*íãëšüÒNçóðQŠæ|îCœ�÷ÿ¯ÉŒ÷�lí‡ëûÆçÎ÷9/à<Ïß|fÿ¸3ùðþ¹ãX¿sG“ØqNæLoè›×© •S²eL¶cÔõáñœ?t<×ã[Æœ;ªôŽpŠùþó×Q©pÚÃôü�ãá¾N“xú”2lÜrÝkÓnUËuKGRÀ¾Ô÷[ÕfRŽM|/ ³ß¬]ÍÉ>"(Ý’ç31êÁ•tßÇÑ÷ †­ç>ÿ�‡J»ã‘0"š�`Å`P/Ç–NN°f÷gsàó§•/ŸV>¿¬|þ´ðòdûë¾T¨+Y2ï1Òj#a[/ÏžŸ.,k&ÆÀí]¸½+¥ µ„I°Y/™õ²°®‘u�V‘iÊ#�n�JUÄÈqk$¬‰xÉÈjûíÐ< Ei-Ðjf¿-ì·Îýµ±­Þs Q5 aá}/,‹°­™Ëeçí½ò~_w^ß rk”jLTc#:Pð›õ4æþo £íÓßX‚3M“?ŒÒÑÐ�„u0‚ùÇ9G’75µ*P¯?ñéùÂvÉDÙA ”hM…�ñ6*i%£³í…ý­óúË¿üò•¯¯ïì 4:!‚ ’‘�Íɺÿ(£oÝ’ý­[#ÛÒvJ¯¦Ç/4YŽg›ÛWp™œî{xÀ’û,û~c¿ßÐVÐ^fŒi„ “¨Åˆn1f‹�<ñQ½bw¶±–Џ��šÉ˜¬�7œmV½?z@ÕR¹•NiJU�‰[º.´º;²;ù¥ŸâìÃÖˆ2%*‡ýS¯ÂQ´všW>qÐ@\Á€�ÅçYGµØX×7öòNZ„”ƒ­‹¬J›õâ•È­™äÈÐYþh[Õ• ,¾ˆvœÈqÄÇ&+Šî´²£½ÒZ!j¶¤ª# ªùÍ!zeMož¬@” )URW¢†ÖV¹ïwR^è(M­7гßk«ÔfǸß!J'i#yĽu~);õ])ïÂý"¬k#ÄÄzYùòÇ– ¤ <Ë‚JàǾã—:ÿå¿ÿõÏ_yk7Jq@:&“·Šû/‹‘åLúT¯ö¦»tŽ1ö%¸ª�3íkuûe £÷DxwÕ8T\NÙª,„ƒ=‡'Ž34¾NКz#èÆ#K·DÔ¨ºQ¯›•â@¾Kèö~¬Ù!í;á��&ÎïcsÇY¹5ze¼½F"Áw-¦ôéLX8U"êdÒYYO ÔνìˆXcöèUò­+1Vj ÓάKf]óÜa{»Sv#1Ñ«÷÷„ &�‚õq©µÑê}& Ð~$â͆�†Å‰¨‘îIƒî$:gÂQÇz6•†.ƒøæd8ÇîG¼áI/­„Pˆ1ñryâûÏO<_Ï×L ¡ðùË3ßÿá…—ÏO<~"D¥Ô•.",Ïžÿ˜Ù>E`¥·HÝ#­Ò–ˆk²}) [`1xz|Ï›RHFìlÚ�V© ÍCfAª7_NqíX�X·Ï½ó¦©ÃçU†Oƒ”�»Tò¸?Ï£ÌßÉ<¬%ÔBŠánþ–áß�ÿáVÙ¾™¬ŽÓ1üÒ>�ƒ×?+WG€Å—éÀŒ1òHÄYÕJ˜òæ;ZóäÌ”±c7_Oº˜Ž( 5@³¸˜&H· çóbôLœø=ü`—ÚÂ{ц„D«ÀÓ`ÒæÁŸ‰Än„€&PÄ+ùúL xA£Š²ãI¨ÇÉâþ$¨U3úø1['Æ0ˆF•�f û(€S÷χLü`÷kµ*‰)¥8¨Ì”SÀH4ø^+Á[ ò�Ë&3¾’Ïñ¤P=)-éT·’ì¾´û/ =?]æ†Ñš•1öê SDÈ1°-É3áÆ<ÞE(jV$ºñô!�ΦRO ÆÜæÆbZi2�÷Á¾Ÿ´JŠ�2ƒ;›XÝ7!õòÕQŠÅÊ!sN,)ÍÀ²ÕF›­yIŠO_ V&Ìñ%¶hƒÉ€³|Äù%þw8²HC&cNâù?±ñÉ âŒ+¼Ó�X)�¯ÔiB°{[rä².lK6û(�@÷æ˜Ýš‡æÀš­\wIÖˆ-h£îwc3Euí4ó‰*Áú0„è��„)M#ƒM2&˜O¨ÄJˆ\nÊ"Ÿ°<¨4çMÒ‚�•f qù›¶wê^Ùï�²wÇ0]#]3M­ì§v¼äSÝÖôÉpUKîFõ@¸yPâÏAðeÈ2꿘�E“tK8³#Ë^‡8ëÇó0']ìÙi0vN .~øùÆ_þöÆ¿ýí�¿üí�·{do+U3�Dõûê"ôfk( HPsx´X#T.VþeN:™*Áœè¹©xÒÄeeÄ‹Ÿ’—æÇ­2&AÞüYMoÔ4G-¸�ȉáïå…Ò¡Y™|m�½X#š„˜뺒—lzÂaA�És¨Ì…O{áÉ©ë^•áÆ_µÙœ �$BJ–Ü Û-`•û 0ÊóeÉ䜽d¬ÎûIÑdr^a±ù$‘J¥U+™#›e÷&bêŽA©op7‰�ÖL>h}Nl)qɉØR ŸÖ•/ÏO<_V.KfÝ"ùˆk‡¼C¼¡á�®�”â–­ Ñë ]ÂÌ‘ÁKJ±FV£¼:d3Z¦_™�j쟉أµzv>v´Ý‰’YrâéiãÓÓ'•Ê^ ÷zçõVøúVx½uÞïp»wÂÍtu·]ÕÛ[[Õ€ø3O8�ÄÒa7µwTŒù’’7¶{�ZkÞ¤ê¨ì™n” G�éü©KoMgé`:`°±æÅA(ÛÃ:¤‘ö½°[Ð}¿ïÜÞwŠk®»)É�Á"ýˆ¶ÈX¯r(›Zu…Ïù1ÿg@r‚¿‡Ü†'¾Ï!àà4wªŸ“‡O?ü~0¼†|ÁÏGâî,ëbcýûçù˜ø½÷ŽË=â¿GÖøÇŸÿ#¯G†þïø< É?'Î=’�c7UfN7£p±Â‡ùÿa0Ü…:Ÿû¾€9³çdÆG ýáÚ‡32þöÜùÖu�%ø�^#Áõ�ïH>Ì“?ÎÞ È|M‹?Ä]Ïo­ón÷œdÓ9ËO/=¾Ô Ç|¾Çú…ÓºøpjåqÍŒfbŒõäìÛqÄ#¡ŽøNê XX6*óÄÇÆƒ›Í¯�² ““$∃¡v~švLäH¾Œ÷ˆ¥„f¢â´~N¸ƒQc°Þ-ª¨Vóûšé¸ÌßÖÈÓ–xºfž/‰ÏÏ>Úøüiãù)q½¶lþJ{Î$Y¹dyR\ÖÌç—'>=]É9bà¶ ·Õˆ/];9Gûº¬¤ëê¤ %ôB¨w¤NºƒÖ7A�¬°€l W�-@Ô™¨7R„xAIù)q©�þ®´7e«ÜÞ { ”žØî�eI\®;O÷Æû{ãí½ñõµ~npk´îà,Ýö‰1Ãu$·ýY00’“÷øcȲü楾÷ “¼¤#€ XÕhJâ„…ÑÛ)Ñjã~/tÖäKÖØ"\7áÓó•ÏŸŸ¹XiήWÄ)†Öi):PkàŠvñU[s¥Tó_±Ô¤ˆ)ÏÞZ(Üï…ÛÞøz»³7õª– ™ ð¤NÔI1MÀeZ4=Xù¸ìDˆž°õØ\º4j/ô¦HŽJýó;«Ø*±J¥ëNí7ZÏtÍt1}öf~©šŒho–,„ ï\çd@N²–êjCFôY×…mIJ1E‰j@RÙo¤œ¹˜�ì·X‡h¢Wë�ÐõNmÕÁÎβD4EûL‡Ú ·û;yÙX{µ^­s/…{)^ýQiÕ$ar.9²Å`ñ¾'ÞH-�rk,[¥“èëóFÈ7ˆ7�aç_þå™?±-�·¯§–WîïoˆDBº°$k‚¼.�í…²‹ £Åf­YÃö-‰ž¼òŠ$ç.…j`ôá"»‘ë¤Í84zcøäàØØ%£@Žáx_ˆ„< (µRö:{‹%L€®y\pôw<âÊ!ƒ3È=ÍÁî^c$Ï-I4ì”xˆYÿ�€&«<1’›'bðmz�眵|rzš m&Æú$öÜîÅ×€UäXE} ªùÖ¹Gß#)'ïsicã¨tWBðdMïì÷B¹ß¦o~„£ìÿØþÓÄ«2è¨7ñ6I o¶í•¸Ë0ÕÔ+… p›1ÚÙž•ܾ·D©$idédQþøyãÿü×?ñÇïžøÃ÷Oîhg{^¹¼\Y®™´%ˆÐ%YŒšaI¤µ€¾Z~:;ëkR«±R¥Ñ8z|-„a#Õý=«~Tu\…F\”`úÓHMÄjEœœgU>2ýÃC� #½»½‹ƒgèsw°®-Õápö*O ¾ãN“V3*Å0Ô5¦–¹¿ÏsÍI¨'‡y@éã}b×Ùñëg^Çx~ã—:’y²ãô9ñÁ‚÷¸´ÏÊi_Ó!¹ë>ãPe™… ƒ0Ð@ Ô{§îB©‘R¥­z H·ú‰„:ö.÷SG2œVí>b?úÿ$ïq½£Â ºTAKw€fR}ªNN4û¤`„Ťs˜‚÷’î øÚmîøçÉ1YBÚ1I#׺L¿BhöùV;¥FÂ2K{š†3õbþ„j%†n¾¨FïOd Í€œ0¿P9$£iiŠÔnI‰¨P¬B_”¶ÑÆÂÄØ WÒwOæÐ·¦”ªD:; Ä2g9)9YáFórŠ¡5h}¸)êÓn8 £ƒ¸“8·¢u:°ƒ±0™AÈAè)2: �ò<[·xC &aI‰%D²o<£ƒƒ­íÝ@&q0ƒŽ%å®ðt¦œˆíz�Lgm, è�»™Ÿó…ïMV´yÓ�»øýÂÔ€ê#cäåácM�L|ÎÑú ,‘œƒKÞ×:Ê¡MçÜ&Pð~lkÅôÝj0RN.ví¨k‚fû¬xð9ôãC4]úÐ ·Ÿ�|œq¦3“£Í œ }Í0 …zLQ¥Uöb:�µŒNÄ®'Fw�ñXÜêSó@‡ ²Ú\讹(}8^`(:üWoVdê{Å9üù¸C<Ø'q6!Ë@/%&X#3ñ'Q¾¾U~ùzç—¯7~ùzãÞ2*ÙŠä=x›#2m³±‰ÛÉ bÁfÄ6êæìw”ŒMås=Xмٵk¢3’^ý“²•\!ÞÏ¡5z³¼:'K.XPèìgÃÔY H"¥L^Ò²�s¶s;€Ô»B©h­¦CÚÒ"Œ­$SÔt$Ï䨨ðàb$:K.:д¶¾Ä IDATÚ|¡øåŒî€­�‚—]àµù0ÔÀ�ZÀe¬Œ¡d•½@{!¦àë]y£µwÊ÷[cM‰œKÊlK&Ó‰=ñ´f®×ÌÓ5qÝ2Ë%¶HXº;B�Ò‡;gì4dÜ»o¨ Bv_·ÒD Û½7cƒÄ|r° Ô„í8&—E2Ôœ¡Eˆ,eIÝ2ÏO™ç§ÕÊÄ1¶ËûÝd‰¤ØÈ±“C³Ê·íwµ†Y£RMÅ’w=L6ëXŽÄMñ†Ñ UkjmNúч¥ûœ¥�×øaHŽóÙ5Œ�Ê:!ª'F"~$¤Ž¤€8B3›(*g¶HŒíy\ï˜ ‡'{°c”eúžã6FNNóÎíÞ8À¬~‘c/–iÏÎÀÁØw˜ó;ˆíÉkŠ¬Ù¤/SPT£ ´ªDŒèòò”yù”ùòéâ’3Ÿ®+/Ÿ2/We[ªéÖÓ�'aM™z½ }19‹%ñ|ݸ^–iÇ$Xõ¡` ͼ˜O/+áºúzhhî-NJ‘fw#Áª–@ØáÒakp –T�‡Í³@xÄ;Jt™Ù€‹rß:qQ–[£ïÂE”+�[μ—ÌëÖùe)HKÔ—BíÖo`J�©Ú|ð“öi;ô˜§Å¬¾'™Îñ‰Ñ(ñÇv,�þ¸xeB!JcYÄ$"ÖĺeÝb´¤@Ùé4¢4“hZàé¹f¸dåš/Wáå²p]2KŒVèß½R`ïènÛ­Vcâ*¤ËòßY{“&I’$KïcU3÷ˆÜ*«Ð4Qwá2ÿÿ�€pÃahBcPÝU•î¦* Ï�YDÍ£ªºëK²ô%ÜÌtáõ½Çìõ„·÷Á¯ï�/o'¿'�Qh]pVjÄù=fMÉh ‹=äôÁSZÅÌã ?W„{»}Ç}ÿDŽy–êX æµë1‹Rõ<8Žƒãí+�·¯È¶‘÷"—½ÃuЛ32TN/<´iÇý˜Äf~80qÆ4f�¤ô¸)iFËŽi¦gãqVÇér,+WŠâØ*Öú°ÉsèÐ�‚¹Â>šKµµºìOЏ8d;„A¯�zTløìF�Ÿ|«×q¼Æ ‹°¥Ä¦Ùóô¡4 €,NߎØwùª) ,ø¬+¯/yœh„Do}ÃÆ‰J¦l‰¬^L)e§l®õnQðð8ï¬Ôˆ;gÓuôƒVO¬žt;Q/¦>pZd¬½çòÀ§+)Ä–éÝ%^jkÞˆáÅCeC,¯‚Ôˆ�³Glg#=¼wøý¾ð»_¾ðúyðºY\�ƒï¾ß¹owÞÞ¿ãׯ¿!§“v¾qžhR�½dö²‘Õ‡”÷ó3T½y8f®ž+š#f:ر«‚™FîvßÑ÷^LM%yq»xaNB&ú¹`:›Þ `©DLu•DŒçÓvycp¬FÓ˜ù  šÍ–ä~'Ñ\:¦*Á”OsÐqŠæ…çóY…‘¼øN쓜•}ózËT èÝ›`³96g¶®Ô¦ôÑé½z­Å�<¸©Ñ†¡ÉemMf[ ²»�íÞ0T:*�$ •ŠN;5,¤p 5¥r}¢ÚX¹¤ß¯ðUq¿ÌÝb�ñйÆõ4‹õ;.¶6xœ:æ÷¶îÕj†¯�Œ²©ù¬Ë=óãw/ü§ß}Ço~|áçï¨8£+Ý”|ÏÈ®P,¤{‰¥£õ+C[äw`9j3ÇYÓbç#Îã)®µV6\K¥Gå—ˆ¹¼Q&IfG*%3i‰Ð2ò€!ê‰Y–ð"Z0Óæµ_1¯âsŽò4ƒ.‚¯ç\æYÎò9J½þÞ÷ã|È<¿§Üèz8€`!Bd^§¹ß¯(÷#ì#ò"`ÊåxLñfºÞß:Ân;Üÿú*;2ìÀð) 9»ì‹¦ìÆçƒªßO1Å’2Ä5Ðë¡ Ø×z3õaW“ú¬)£9c½:5Ð¥—\_0kfª† êÉ¢‘ö1ùq+ÔÚ8ŽsY­�ó<éÍ-ä¼q»ßÙö�”2¢‰û›¸þ¢èI=5£c ½{“"onWdDsÑV¡ª÷ õˆ†®W�ù Ai³A9Ÿ¡OœÅ÷tÆ8Ü^IÇH k´–aœXSFòfØ 8&ɶ!JÚv²d4äœz£�7ê±ñë—�¾ ¶)›$lKä-sÏPŠ1ôA“¥#{Aîv"HÈ®¹°s ÿ˜ŒÊ ¤ •Žp¢h÷åÇ ˆ!ÆTÐ)��B$¾ˆÓýö×Äw?odÛ(ì.S¶á µ–HïŠU¥«ÒSB²‘7Ø1n"ÜH˼œ'Ô@©X²`z3g˜£3TYƒ�·½°í»³KDh­sž'­FcÏp„êpMNÏ‹eŲ~ÉIȽ”©d†øþïé£#’jAéÃ0ÄJ!™�­ æ¨½f�Z;ïçàèPQG"jBFBÍYT3)LNŒÃчј| =² ¿1ƒ: É;YµÈ§^4"VAǃ€åg"é¾’ OzŒ«WëTÅY´7OjRøW]óC$ ƒ16KÕº˜kD—„&ñëA¨ÙD>ºm•Ð{ Úyüýdn1‡ühçxØ8Í¢·ÅñLôñM3Ѹ}t:ãé]ž‹³q&–1t53®çbï­×Á,AO0ÿ”Š›±�×Èbíȼ†~ùd\Eò™8yá6Å€¿é%ãXÌ” ‘�ø}ŒêÂЫȲ¾^q‡wŸþi-�«r¡uæúyþ{‰&Y¬�X+?š××ä:N{zí yÖG¬5,+ýX¿ž‹h:É“|ÖBÕÏFÞLXäJl E40�y5f³�Y˜+l‰8zÞBïy >'VÿAãù[›õéœçû…‰�ɲ•uÿÁÇÇGs[‰FþœQu¡ì-9çýÌ9Psm+™¤…”rìKqF¶o¿Îê�K�Ú±ß)cÄ|+�Gý_qûj*ÆB0Ô3—uÂpiézìáEÖé“ ¢È©Ì™..Y·§Âë&¼Þ„×MÙ³¬¸°�`It’v~ú~ü!óÛŸnüüÓg^_6î·B)BÎÇÈt©ˆ5n·„ê˺–S2B5æ˜!{'å+qÌ›�Š!û€}ÆUqCè&Tl¡ÌHB*ƒ¼ Û-£·7�mxò+OOÃ×üð¸Ýíp/’aöÎh¿’jçÞ”O]i Ž]øš¼È2Fç¨�mäJ‡:<1ó£ÌFàxì÷ÿb�ȺO޽vüµK¨º¶¤¡Ìy/XtYÅ�®…ÛÙ¼lÂËMy¹GN§‰7;©Ú0©ŒÜyÙŸ_•¿K|Ú…O;|ÚŸïÊç›P¬¡§:z¥gè7úñN=OÇÉñ8±˜™´kBoµgSV8%QE¨‚kÓÜ®šb៬{AÚÍáÌ?"™èQ„Jê§œ¹mßS¶Ÿ�|ÇjïÔöF'c5¿‚2"—…óñàx´Ç §7Gš˜ç¢¥0lÐÚá ¨æìÏ´šzÁô ù’„#ƒ¾˜÷ž²ûÜÓÄ9m  Z¦�Kª€ˆI$ì£*’wÒv#ïwÒ~ItsyœZOÎڼجï¨>.Û±r8_ÊI7J¾EÑo6 ½Òà–¾“lPPt»óRv^nŸ¸•WN3ÎfÉ"®—ÁH�”}œ~OÇõÍ¥�‹uÑ»û‚Þ;çñpô-d3Ø16RÚØ·ìhRÍ(¨'õýW×s<½… oŒ^�—>�EšLÊ7„˜G¨Éí|o´ó�¤LI™Óº7UªÏ:S [4 BÉU”³UÞ[#A«çwÛÛÁý¿þ lÆ?ýï¿áõÓ�Àáùdñ¡Øÿ�‰ÛË?r»ÃÛ×_ùÿ=œ½Ñ…¬[¾‘Ó†ˆ3³ÏÂpéQ^˜æì™Ù°6RH`xÎ� ›ì�vÒ&^ÛÙ)À‚’KÓÌ�D§h�¸–1‚"¹²a /j! D„ZÈÁ:“f*4³îÙ±zxƒsÅÖÅ�7ïŸX°¬ðÏu¿¤ž�˜ ]½V¢:È›q{¼¼^(ýŒ3˜ücP$“%Ñ[¦Õ`>´ÍN:�ãÖyÜgÎ6œ‘D¦[¢!´u>…wõœ–ŽØIÖ“$™÷å§/`\ n†� YTLTõ¤Ã\˜¥ =ç*3FÎP²w–�¶pÑ %‚•™ ê¼­Ñ¹íbôæ�œkÕeÀ¼žS¢dõ!¾ï¼!^dS §†�j§¥K’fÚ�ó� ý¨�B½†¼M„ε™ýÞ÷¦±P®ÝÆ“<™1%"æWÂ9¸á�îú6œ&}„ ƒÇ$ë¦é*ðÏär^ÛÞî�î9Èi"Ò.; Ѹ)])Y#œŠæZ‘š!5ÿíŒBbEÆ…Üe2À)9â(xOš S‹â�j47æÆÄ°Ùƒp-ÊÖćùÔ(j�~¹Š@<™f¦tPë-†ãBk£˜7Ҝ҆pi Š76Ml¦t²)£yt=©�s8o9So>´æëÍõºb¶5§ÌIq ›ifqdÒɺaÃ1£uOø—–S'soSKp ó Î?WUI¦ËW®‚’D±fh4þXÝkQÁeƒ*%<'£»|WfÛolû�R6w/‘—Rø²ÁÔŒï½;� ¸†i0K|9.�I<ý| —;ÏÊà$gÁ‹ù�ú ëuQÆ×0s›ìŠ)Q”¢™Ða$†ž8 JHrÜ´»Iä\HÉ •ìEÊ&§Ô¨ƒQ£$#‹²çİNÕõk{%�ÍõMQdréèÞÐÑX”ó+u_ƒø†­YÁÐ3:ÛiÛ Þuž…›éä'JY„ýž°v6ÙÙÄ;ª‚T…zSÎäÌ­M=`#y¿!›øðµžðÑ WÁ”ØiÝ8Ý<©K`õ þöqxóÑðbp OË>×Á¹“Ô‘iPøíë ÷U‘¬¬ØÊ.Ï¥/r>#w¿‰ëV|7ËuJ0è<àÕ§—Ú* úöbC0l²Ô‚ `2~—óÐlø›ú€zG-<}�—ºxy»Ïd"LŠ—ýú_:ó6% /ªyßcØ\ÊþþëØâšÅÏs� á*hø)9ðk®kŸ,dˆL?>}újãûë$šRhèëÞDd2¿ÆÓãí�EÕät3·:ßG¼I?|ï› <58„k«;ká©ÙaóŽÎ#�k"̜͜aîuYñKdUîõ|?¢à/ÓvØuýVŠ4ÿ÷„¸7y:›)Ûµ†×qÎÏù°ÄŸþ(ºÓWªòtNxùò�+½›�›ûËÙð{z�°{sï-[úá“ìú�ÍtÍ®µ~�T\‘yüöô^ßþÁð¦¼'�”@NyM‡¦¡e`exC ôëúò˜ ®¸wF«ó"'óâáv�sgW%Kb$¥¨·)ÏnlÚÉÚÉÉBÂG}¶_W†=œ·i¡g#/–\ŠÛN�õxÊEjȧ¬� ¡'ûæ5— Ùsâ^2/%Gc@±’xd…¢ 5î·Ä§—Ä÷Ÿ ß¿$¾»+Ÿwø|>Ý %‹KI�ÃV8Oã<{<# 7Ò¥ej/ÔÕ �L5¥ŽAµæ€$ñÙwfÐkõA¿"^w 6ݲyÃÂç%²dR*leg+¯¤ô‚è†Ñi£qœjýŠ�p‚tTF‡…ã89�“Ñ,úC“œV³ÏQî�Þ�7›s6Ì›ÉÙïÃ|O˜~$b}ó='ù†”�ÿ¯ÎôpV°¢i�¦&ó²õ,”R¢”Íc÷ý…¼ÝVØ9̇‘�wÞÞÞ~EøÕW–Hä@\¹Rn°%ÏkCnÇD™Wó€4!’½¨jckľ½VÈ!Ó@ñ§Y¥·¯´Ç/ôú 5¯ELäø”›éÝ›-­Z/±!œ9�Kèæâreõèr»>C¢‘ÛG @3Fõ8|¶EMFÌBÊJ.µž‹zÁÂ×f3bÙØé¹�ûfat¡5Á†®„Ôqæ Y¿qy^0bÕe] Có`Û�ûËàÓgã»ÏÊë=3ÎÂ8]êLû “(’­ÐëÆY;gš97½GB§òöPŽ*œ�õ¬#dˆL’ÄxaPhˆ´` ø :Ó@kDžvY¦GwÆòßwc2ëÅ}ÞòÍØLH"¾ò¦ù¬÷µ.ÁíΈ¸Ããb_Îþ˜s#¼V’ ò€,Æž3·Í}õV„œ"ݯs!òô®ÐK§yƪH4„ƒÅ-3«œõÁ©¹çÀXù€¿ü*d|ˆ|DV}ã9’\ì–È—}±^ú$ÿzÅuÁò_M�£ÁGhÌõ˜Gu=‰XRV¬½þFžâåõßüüáûù“0#½Õ¤�ùéO1ðó{­_?' ¬cúð7ëxÍ÷’}üçõ ůM.šèØ 5uN*‡GïœÕèõZÿ=ìFíθ©6ÙAþõ 턘3Z÷Y©­�Ðue 4íôT±`õƼ3 &Ã)‘ÔgÌä�sèq§$ØT¸á¶mˆ³j½!1ÙúmD><ƒF³À�.X—Er`{b*²K0% ©$ÊžÙn™ív£ì®Ê!)GÓÔ£©D3›?±Ûh�Ï'tÙô¸v�§æ�Åýñ;˜úá•>Œ³vµ³í·³ñ~Ž@LŽã�Ú¼³o­‘£ðŠš#v$´²‚áÉû¤Çûà\g øp†I5™tùÙȺ¤ôÃúqƒŸŸŽxHŽO^¸±y{ïp¶Ð|öå“Já&ʶ mjŸ¯i×n–§&Ö0®mt%‚3ØZ[¹à\3¢@«ËYÅ_°Z7« x%Æ^LCÆ×Qíž‚y0äèh³î³$Rr:KR—^êáüGo´æÃ3ûp¿†ê<%¶µ çYÉIèz2´1)D9 ©ã”–•5]}%{ú°«M¸ŒF,N‰Â÷dä¤ì¥�v(æ›Xq„rË™©ÓæÁWy�Šž¾R‹‰< þÀ›IµuZ=hÍ©œ#î/q�ûè¤~!Û=š×e]…Ó†PòDìÚÍQh#è—„<@ Û0R)N­L ÄQ-.Ç©Yæ°YØð´lŒîZ‰"0m¨Íà#Qäóu‚ÙU¨±áŒ,¤�bÀ‰áTýV9§H¼—aN�^¤Vpšm=±ÞÖqŠ™w6·ŒHBS!—â³)d¢÷Åï9SŸ<šƒÉu&‰„ÝiÍF[�4æ>Z’3Ñ…�@ÆFã|ÿ•vœl»R¼éÕhµÒ빘C¼Y£Éƒ{O fÉ-M÷K·�">¼7�>I)¥W,��6L2g{ðhm§­ÎÇ �p<„ã%S_‹#"o†�µeîmg;©Øjº.üD‡Ž§N‰L'ûNDR;)~Oì¥Yü¶¹'Õ ìW Ž$ƒRúz'Ù†²!âz¯3s‘,Ù>¨;ƒæ�ÎSÐôݬxåWC»tÛ ÛV¸Ý6nûÆëë+¯Ÿ>A4ŒÞÞ|Ý �ã¤ÕŽ;£šý¶wwþµvÎÖ8á?#ÑÌHfáèƒ=Æ8»É��ä@éoŠxѶ¯¢�+¦ ¢Ñ‰¢^ŸIâïåC5z‡÷ÏýB$9‘´L ¸Í -ݧ�vÝg–‰–ëöM°:ͳ`ã?åq± ¢¬ã�´È“½˜ÈÐù‘Ó‰EÞgªL­Ø@UÎ&ƒz!Peý[y2"¸H*0å�ðט'ó˜=Žmq‹µ O6Á®C"‰¿vòñz…)¼|±LšñJi¹ÐD0éÁ³);ƒýkËù}Y’gQt—  O¹%a6\XvÏ�Õ‘¸Cò*ÐÍ9*К7 ¢-ÌbòÍ8‡o\ÃÝUÙZ 0ÉH™‚;¿Îû|Å(Ë!³.vÈu-pÆÌ{fçy=>ç(Ñ›…f»®¸YÜ“ gäÿ­?¿âŸ ˜Z�ræ:‰êµ6ba¬]ú¬b�*s�Ë, º¶Ëc5Š®Œ’§Kÿôøëïé/FƒÇfr�s^ ÄÒzqì¼ç)¥u½}�„îél\£a.Š+VÖ+‰…k ñtûŸRI�ØHžšR«Ñhñ}4rFV2;¥F¢à+# 26ДطÌËÍQÿ·=qÛ·âq²e”›ëÑøîÓ�ï^ïÜJëXF¨Ã0jJ“1*W!Œé##¦‰õ—–OïðTÃFÝÆP%egtêH¤Ñœ^ž•œ"¶Ó'æÕZOþöãBˆg¬Õ$#n ¹§Ë7£�FmƒztÆ£ÂÑÐÖIc²¥’¢Ám1òˆÁuÆ’[Týp4�`_]n3öb Bt8kVf3„zÌžDÈ’¢ø™I²¡R¢I•(î·ŽH¢÷ÆíV¸ßo¼¾Þùá‡�?e>ßàu‡m ÉÓæ¨ßó89G l…!iß+tÉôQ¢¸&t+…a™Ñ…z4ΡPBGÓðÖ´5F?9Fç´±$§ôê’™ÙÜfå²±ß^HeX#�$î­rj}cô‡#íRì5$�4ml[!—�œýÚ`²bæ­»z 1gu ÌãðÃ@E1-lÛN);³ä$’è —(;)9sXñŸÅ÷s&‹èRM!µYØ·JÞ1L}nVS[9k­�ÑžGcÀm¡7ÆOŒ§Íw@H¶¦H4ñŒ`®‡/kµrV¨§y±CS€;}Ôõ£r_¿|á|¼ÓƒL;Û™a�p&·RkåñxP–4®K/¸&½Ñ�“£½1Žû^P}¡6—¯Ÿ>rë IDAT É à‰mñ÷n‡FµÍf£7ó–Iùζ%n·â ªc(Ùí”ç´ƒÚN/� Ãë'™´½ üÃÿàñþ¯|ÿCæ§Ÿ ?ý|ãçŸo §Û´¤ä-óÛßýÄù/ÿÿÌÛ—ÿ›¯¿þ¡ÑëƒOŸà~ûD.›ÛÅ䌓Þ4á:܉ÑÃ~D£WC’¹‡:Áè>kÍãþ­h4*Xu�©{¿f¬˜×*ZÈþhÈYÌlÙÿÀãÂ1ü8<ŸÍYùÏrm“õ/Ã�OYˌک½Ï•à…0.N›K‡Uòè¤a¤!dKdÒЄ™ 7e¿{ãòõîòªŸ>mˆmȸ¯†G™m˜íÔ¶qÖLÝ*c˜ƒ«rÊãTÞÆã0ÞOãl Ð-sV8«Q;Ô>|V[÷faÎyù¯Ñ64|µ»UoèôhŽ\qlȪŒÈç"6�Êb6qÞì2�SæõsÀZóØV³û€b�ÕE\Ú}¨ÑÕ¢~ Œ9—Èk.Qî€yUCe˜Ç�î>ûª°m%o¨Ï2\(Þ¸�È Üåµ>¯ù®\0$ö]Ö¾y=¤ûµˆ�}mç>ßhcpœ�íl”-³�|4T㽆näpm¤á”`—™J«00õÖæ^™›Dt¢«¹Pïñ…‹U ¸óììzRëkRkfG:%Ÿ€�’£.cJ7PK2Qs¢ŽT�t§Bk-°kÐÕ³ôÂÚà2Q�þ³Ð8 nGl5*mD`¥‘]Æn¨x¯™°=�þõòôõJ„±i¸ýõŽ|Ò�(©8¾ÖÚ¢®öî�)´°üF —.¬oÏ>\ê3rrr‡Ñ¯Ž«ÏgGÖ©J Þ¦q5¢!C1&Ã@-(¾9‘w1];ivjPJ«10 ‚iÎŽ#¦:áﲊ’F$]ŽÐlñô&�ÄF±¥Ûþœô÷«8¤J•AmÃU^r'É\S3H&fHr.µ�@»~§áV£ò"�ž�Í«qäCr:ó–×î%ÙI¯Lñž¯gOɯû³fjtÒ l4Zô®« ²öbk«YƒâHÖódô@xšÂ8­:g¸¼tï\ŠÓ|‡æØ;+u›¦mˆFæÐ¸Š]�3Oò„(�ŒN¯ ‘µ¶Œ˜Në•Úë¢NçîëF¨YèTzËÞ?Àœû!êCa¥y‡xŒ‚hÎl�†haôg?h½£6hÒ9¥{2ÿ´G¢?2õ53^ã.´ÓÝ‹22ì‚fO<\¼.½1ÿk(¥=óV°á{ó²)î�ÌpD êtY»0àËFb>l<Ý6?žñf |’}4[(]”³¤ÉÙ6i3Òp¶„$ó¸N ÑLQ<8/·/÷›7^_#Al|Ý3¿fåý‘9«ËÆyñË‹&J­ƒ³uŽÚ(§�³‘r4Tº¡�XJCH&Hó$¸¶ Ù…%U$¹äVšC0'Ãe²Ôíj–ˆaƒí�ŽD·]Î,��WÉxºzP^ì*ŒúsúŠeó£ø²M³Ø÷T¨~.:™ÆsÏO`!o¯‘Hªfs@ÂnÏϽâlj4Æ“\uöXÉâs:’KsMº1,´® KŽX­KgRœñÖ)ÀË^x˜TsCɱ¡¬bïÕ\·UxƼ8µÂn™¶ïé\×Õˆ}1<ñ�)éñk™M¢ûb62gs"RX DÐ3ÓÏÏN£r5 \ncú!A4;ó`!Á=Àe6�M™ ™°±—/÷`oÆ“‘¸&\kLC{~Æ>6Mî* ¯H’ÙAC^ñÉ�¬¸Lbç\¡ÌŒH0fré~f�õ©©3×Ü´0 Pa×eŸìº¿Ô[߸?³ä¿Þý¹‰ºÌýq�Ì|þúgùæ{yjÌ_Ïô§uÏ÷ÅíLF$G1ÍeXfc@ƒíiàÏ×\ÛÔDc†ÔE}NX#VÐÙŒñ_΀=í£ëgqêùì¯¸ÂæÏóš„þ™3±æ±E045F$Ø|SrE]·ùv+Üvo ì[c/-ŠÝBN…’ {Qö¢¼Ü /{¡$AFwæ2N!W†K$$/”¦(|­$•ˆkçÉÎe¢CÕY®¬;0`âx¯í~hÊ:ªùÐP)·ÊD:úûf>Xžìz<•¥Ï­»BÝ&4:µ6j´³Ñ�Š©�Ôj~­&‹Áå%Bþmà¶Š¹g5Î!ˆ¨c0ÇMÚŒ•ãZùkš'¨¢³³‘<<ߘR­99SEðB•��$"“óNnßKFwIÜî…×Ï;Ÿ^„×]�Œ;×·Æ8+­?xœGÐŽ„ù@3úPjOô*´÷Ácljëz÷`×Aí=Ž¿áÍ7�yG¯Œ^±Vé*ŽÒß¶È%bª9+0Rvöä¼_«¯yÂÃ¥IcgØèa“›zÀwŸŸo?#çm-Æ8=^MÁ¸˜>o ÌIYïìû'î·{0z]ÿ¿µŽJaÛîÁjÍÈŒdîy‹æƒ7WsRÔ÷ƒ*%ï$uƯ©‘ó ¥þã£Ý»†¨;XÄ÷cXÅ,{‘×£¹vÿè4Žó�Z´[k%i‰û'ÈÃýT®…R&�ŒZU5®ü~,¶‚ûÇËZù @¡õÎqžŒá礃œ.Téh1ø1iÌ[6Í ´ F)Ùc–�¤±ç5ÄÏ7XÈ=ê)9òÖïˆ RV¶­� [îïí ?×Ñ�Ù’¥DÜà5”,ë|ýúG¾üò'þÛ?ÿw~ü>cöw|ÿý‹#óS0@3üðÓ+ÿôŸÿWÞ¾¼óÿþ?ÿÂùøÊyü ¡yñ) ©Ä̸äc1ß³¤ 1]Yš–‰êÃb ¼çì))·œ£19Xltù‹×÷ÈEƒ+®¼&—Š�Õ÷U §="Ç��j·_ƒAgH÷¸Y]j÷~±âá,>¯F¬Á8É 2ƒM„ÍÙt¸Ë–(·D¹+û]¹*¼~Úx}-¼|ÚÐÀ.W}odÙhMÙŒQ¡²aCé-QÏÄñ€·¯�¯o�··Æq‚ÉÆ°�÷Þãq¼Ÿƒ¢É°)±•â –ôɈˆ6¡BvÎXrJg8ÐKaDq�X�£¨%$Š"¾–ubá"†ZìHePâélk_-jFn�̽í|P�Öo(Ùk!ÿŠLÆBcós0žðTç  Ì�9CÁ×—«u'ɅΜkæÅrݳøÆ¸âá§ùC8gß­:ZñéSŽö„~]ëYÄãë¿þ¸â)ùK¿—ù/"5x^ƒÏ?ÿ•wÿËÿ8ƒ•¿å¯åÃuùðº0l6�SìÏÿFð{­YÐ=QîÍw¸ÌÂøcÐlj™0º‚³t¤�ù¯øN†³s¢Q0›:¼êÁ’güìóF$lpŽ˜·Gü×{£�ÁÙNj?éÃÕYTC³8¨åÓËÎç— 8ÏÊq4ôlœÝ•Ü€uñy':ïô4èyø<×¢”MØ6Öι*"Þl-?L¨«ˆ<­ÛÑ]†Í!Ç›wYÖ tQ¯ÊSN9†®FàSªÄ§åû]é’xÑSæb6*Ô6�^I¡_¶íyi—Î$Ôµ›møxJ̽ùk¬¡¨^Håd�E‹6¾réW‡.ÏE»ŸxÀ7l^°Žä=èà ˆyÇ9‰KH8½ng1n†÷Ï¿…ž–­ó]Að‚lLw¶È¦³´ŠWÉßOmLç?{Á©*h\Üø æÃ£4˜ n§üšbà Öc"í½9`f«‘3ǵÅ�¼v¼ƒ›/wñQt¸| (Q̬'òHd3Ç&?&a�àÌL ›K§ŒqmTÉ^Œ”@ çÄÈA2ü‚‚Ö{ ÐqGfÁi%v^’Ê [gc./â ¿þ“ž»h¾±™–66^äWu¶LNÙå°æuY9ðÀ;›²4êPÎáòWM˜n#ж8ù\§Ñùò€ìršóÚù0 E˜�ècY@8r–CÊJ•\û¼7Y÷zZÄ�Mžho×+¡ÕÓ},:¢Ä>öÂÜDdsx¬'J'½…§ÀùŒÞ›Ó}Í·õÆÐÇwù‘îmÊ`Å0à0ˆ¤Ðy,LiŽAe<ÉbLQ”Ñ é�>µÞ$4Ý’1q= 1t§;2:J4%Äéf›fö’Ù’ñÞ+}¼;·7ºt>}Wºagçøµó~O<>M­ÅBÒ�R O Ò†–öÜg TœÒ•ܹ˜6%Ál,–ŽJ÷õ¢a«Å×Õ¤³­ôí‰Mðmc2ýhÞ‘Ø;¨'Z`Û­eZ/á4@ePePÌg uq‰JI®¿—³Ë lÙ¾Ý6îûÆmß¹ï;÷ûÎý¥`fô¦Ü7—”x‰óô¢H1NZ|ˆÞ¡�_�ªÎ8².XÐâÐA2#OXrOTªÕØ„”29æ[ähø”°ç=¨ö)-íø‰t*)†´«Ò’ÅÜ‹×Å_’Ô5÷“Óm"a4t(íBL›ÈªÁ =ó¤½tŽÏ>Θƒ•‰r¹³¤Ùzͳ-–ÅD�®r~ÊÚívÓ¸m°ïʾe¶âÅ�¤‘ðµÎ;ði§j6™¢îy3ðs Φ¹ÑÉ)戳lúÿÅïRbXô–Í“T·¥³çþЯO¸& a^/yZûOEò§â)L'.:ïôI2™¸¿qÂp„.ö%/³èí¬9'@#μ˜VGUë5(/e<ˆ› \9" ú–Ö<¥ä4P'S¯ÞžÖC`3‘š¨©±ŽaÆ!«H<×HÜË«Øv"½dã\zábTjåóOLï0M3™ú&n˜«_žÐ|�ÙȘûñuÑøúÎø÷3F›ïóŒûK¯½þ~î¸[h u¼øŸQÝâ™"•`ÈuzB ß8�E|ÎI0SJOkMÖMd Ó:ß‘¸ O×܈caàÂÆ=µ|VÜÏoN{1@FHD,)‚Ò ÑLÇ©%…mKÜoÙ›EØsã–+[Él%sÛ¦ŸUJ—2SŸÊ`Ý\«Z=>¶ó¯r"mÙiÖ™ØëO‹lx %káÍS²kO»º’Îu#Ʋ^P-^@Ì@JÁÀ‚Ã_ëë)A–hjÅÞ|Z”r+ЄQ3½ùü¬*ÐÆp&äyÒ�Έ8AF° ¦î¼Å÷p1Ž,fÅM9�6s›§5-CLŒ”:ƒúŒK¾Æã=aS¡ÄàNÌý@Fu™³5êÙéÕã½Z�ã�÷C8ÎÌèŽì% ¼Âˆ™d#7�‘i²û,±fŽÚ!7ôqrtãË_¾TÎãBÑ2”Q}¦”e�«{­Ø˜óÍ¢%‚ÜÞõ1¨}P›¦,#tÍ‹kÒ»vwaßoˆ î÷ ³/°=>tX¢A“ó�m}Ê/ü÷>{+“ËÆè;çùŽò ¶R‚±èM‡nÞÜØnŸÙïßóúú‰———@½wÇ��‡Ç0ÑHÉsr „ÔÊY7_£—? Ò¸âd�²yx~˜TÈ9±m…½¼FAÌ÷ÂÐ�îÇšRöâF2†�Ô£ñxÿJ­D�1TÛ;­>bt'§�”7|xæñ>8Ïcùà”½˜½í™Û½°m™mÛcÆkíšy³ öDöfU=;½ŸÔ:Ðt’Ò#Øö¬¯¥D1ÿ=øò¾’Þ×á—ÔÞ.ÁÓcpñyº|Ùí|Äüˆ9 ÚQðÓߊ@ÙbæK0„,Åe¬Ý{K˜%‡ròßÿå íü¿P~ûóO¼|êì¯x¼>n÷Ìoþî3ÿËÏüò‡ÿÄ-¿ÿýÿà<¿ðþîhøí¶¡éêµlÄ%Ä–”erÙN1¿½ú ì^]¶3rýV ·-GS@œMƒ1†Ð{p_ÃF»í�UŸÅf úèÊU…Á�æ1F›à;oØz ×>jK½ZïÔÄŽºŸô&î•ר5Ô*JeScϰga+PŠ#v·›rÿ¼s{ÝØ_ ÛK¦Ü Ü•í®¤-˜XŠ×ŸžYbQÐÓ®”^¢!€“åFÂ†Ë ÝÆþåàö«qÛ�‡×;†íœ5ñ8„_ß _Þ2Ø8Pj'½ùÀrŸ‹–ýES²WšF•Õ,M ÉX4¶dÊÞXäð„¼ˆtM¼——Ø&ûcú}�²Q%©Qd�¥S˜ÃWY ZO´dTêãdÔFeôDo ´y4¿Þ76eG@�¦þìâ2~iÆ4,þõúù“A,#Îÿ9oúøðØÛk2³x?A® ÄyÒ)ÈyÏWÒd×Ï+(b­çùã·�Å\—u4þrækßþþù_ÿÿy\ÙÓõ9ßþü—Žá¯=dåb-½# É›\^­p¿wŽ·Áû¯�¯_¾þZ‘÷„ t²ç'ÑÌZ¦ ÙömÖ�u”>`ø¾45Ÿc™qi5Döa´^y•ÇY9{åì§û.ílÉ%·$ìE|°ö¦FxÍ'j™¡%%«‘IHOœc²}ÁT»7Xs¾báY?�rÌÀÂŒÑ;­Vª*2pv,âl‰6¨g£·¶€Fއ؜àËì>ÇTs?潚R®OK+oyÐeÄ…Kâz˜O§?Oå‘„¢�ñà/I "ÊΜN>µí§3˜ˆü™˜›ô¸¹n D ubˉ-)-‚žÚí*žÌ$Å+^ø ý:K>rÈÕ]|.‚ŒUÔ$ YÿE¢“BÒ1¨�Hj¯æÀLÚfBµ6Ñd·’ ‚zºÒõaæ{¬„;lÛD] ³ci¡™çšZ«¸7¥d:×�tò+ÑžŸ´áîƒpkmKÆ`.Ä™�zëÔÕEs—OIBïBn¾`GF‹‚eè}o}&ëê#½ã~\If\œnH>s`xÁƒfÑ…&tJ `[õÄu ¡žÐŒ4W#Êõùüüs‚½$\K1ù=ŽÄmž[± Ò‡£A¦Ž?SÿÛ›Y�­dr~2£3÷ _�f ;ýÙlRe¼ Î̇:z*AMŬáÒ-±’ç ´X«2ˆ½÷ú©�m?,JÞ02Ú@üCcH/Ö‰¿Â †F©Ø,[ìóAÒtgæxª9ªµ»ô‘“" úƛ)ÆÐD—Ì,äÍóè�šuÄßLR½$Þi‰X /ŠÙ˜CfÃføpF�¦Š'©­U/´àÝk¸åz�cÂ’ñæ’J%Ó=yµ„2› }ôþ•Ñ…†O»×îMµNå°ƒq(ô�$wöòÂm‡óð“ ½9ª¦~.Ÿ$¯}F@~ü  mÝ»¾1£å¦ó‚¨‰³°®ÆÀe{>šßs¦`y†¶Š:¦æ ¨l>`±+}x5ăF/Ð1î dè0ol%³—_ýšíûÆm/ìecß6ö½°Ý¼H>š°oƒ}7ŽC9kã8Gu_`æÈtWcuDcJÆ–„–ëÉ©¡ÌõáöªŽDÞÔ®Uc²¢)SJ¡DR­Ç1:2üúzRœÉ]6é÷ʶùùµâð�£òˆ–»h&‘H6�ìE2Åœú�ºëïοß#¿…køºG~>²\Íúæ‚»³è:em¸>cŽ× ¡¼xï(Dàë¾ÄC’¢FQØ Ü Ü7áå–¸í>À/%—8φ´†Õ‰”päÑlk „ÝÎL³äõ�#¿² [ž¬�Ù1jÃY#kíÊdŽ9ݺ÷…Q )°«HjÓïÄ,¡«9pÙF—o»6Å%¹2ƒ§ÐuŸ’VQtq¦™D!T"ö ÊscÀ܇ÎdãCcà9¡ˆÃT�7ECwò¹1³b†„½Wl2‡$Ïë=‹C3ñö9aÝ¡¬øŠYµK¶æyí<ÇX6+N˜1ÔL_f3gØX�›ëÌð©�‰â^Ú×ò[…Óy»|};'Æð`ßâ¾Øüt›ëÙ® è)éZM ðXï)‘{þøçü.86Oïï4�ïÃüyÓ@¾Y[Ws ǰ±˜/ñóŸõ=æûjhD\^ zßWq—žOB#¶}B{m2=纱Õ+›÷úƒ·°‹“±váúûkM(¬+‚Š-1u‹Å­�*”64+[6¶<ØKå~Sî7åå¾ñ²ï^à 7l4_;3?Áç µÞœÕU¥m0””=<ðÛì…‚Åš\Å®ÞÌËf`×õŒXÍ“+]{L¢i¿¨‡Ï —Õ�Öé龬TÂ<ÌPЬä=3šbµx5ÈUa?¢SB¯“KqTìð‚ˆ»ˆÌíö‰—×y}ýÄý~»dQ‡ÐêˆFãå{œuäl·¡ÎìÅlwå <Ͷ‘µ·Ý-¹�Ê ¶¢ät£¤ì¬ ™6¾-6:šÀhŒa烯_áñøŠQ=Ÿ1ÿÚ‡Ï+Ë©’óî Ýh½a烳eKl{¹±í^[(e›®kí­aÕåHKÙÙ¶m û¨œ4TÏ`ì]¾e˜‘,1,/[:ýRÒYO˜VÑ,½�•×öîëgJíÔv’k¦Ö“zV—YÍþLšåvf²Š %ëFòñËÎöÞäÛò÷t¿üé÷üòÇ?ð¿üÝïø‡øÂOÝH¹£$è•·û�Ÿ~³ñ÷ÿÛ÷´Ç¯´ó�?þé ·_y<µ~¦÷˜I!„&¶ëÐ{m%P©##V¨fÔ³:è«©(·²¹n|öÂWR·.·ÈV*!/ãÍÛy­¦9TL*Ï~3êâ¬Óàº.]irØt�-ú™ßî¿KI()±åŒ —Êð㕜E{î›r+ÂV”­8SàöRxýaçå»;û§�rOHñÊ5·ÉY�© ›µƒ4’'Zà} FöF?ûÖÙK§äÎñBÛ8ÏÂcO^\ì�¾oô¶£ì$Ù}Ö^7’dŠ–È�vžÔ£óh`);$æŽ QŸõ5˜*ø=ž®Éçjg4Y§uhå9Ýž}†õ˜ë@Œàö$¼¾Ü¸•‚=”qxC{´#lñl dPŸË²p:#‚�‰njâŒë&Ð)E‘ì Éâ³yP÷Aó†�i™5ž›~ Ö"ØŠÙ!ÓåëŒ÷fSaVŸW�ä©tÇ×g<ÇŽÂeû?Ä·ÿä9‡»ò)n0ùð{ûöÍäã�üÅÏú³ û›“§ïù+?Û_}‡çcðOÒ?ûÇUŸŒßª Ï%·mãöbÔ÷Áí^]žX£è•·Ží¦3ªôµ>9üøXƒÏý‰±m�T)CVo®Ñ5DLg­¼¾¾?¨½ÑF## jÇY¡$aKÂ6Éj�õY9¹]íC¨I¼ ÚÙrœû4Ïúëý–¹Ý&“ÏA„.£³8�{[§ICMÐR@ ·A;;ÇᾸ䘘žš "¸ñÌk%L0ÀóÒ¸¶ˆ—Ï÷?¹£œ*D¡!:®Ê « kû’1™”Ër!åB>ÂBÚ£7¨u„A‹¤qD!$ùIO¤ƒë)©w‰•p¢}²‚®½¼‚Þ¹Iíë…KáyÓÎ�†â:wC½b‘ÈÎG7§¤LäÐDº]‰š]O®k:¸zmŽH«ž:ˆ3o½ô“ýuÃ, <^ÜÀ¤‚³³“„Þš#aW#3Þkôá '�D£êE†1²Ë©4¹tȇ#†/ä™;�Óðq°-9bÂiƒFÍp&8§Áì·Ä~dÚ™Ùo�¼5÷)È\2Ý“(ëƒÑÚ´ç1¸X¯l3пOvœ2üXrò"}SÃBç„î£ê|møàæÌ,-6½?­' ]_/üôÞ㵑HŒá�øø| 4¸®ýd¸¸L‘k�ÕîÓ†Zó?NÉCÉz4{Z :õθauÉ—tÛë¡®s>ì¸4hϧ•÷A#p5¾üÜżÁ0BBi¢ÏEÓ„Å^Ð�‚èË ù0±{j"/ô¬…Ž»™¡Ýþ,J¢'åMÊŒ$“$¯=² S ©Ë•ØÏ´¶7Æy2DÈe éE?òv]3¹ö¦ù®žCßB%ä–ÜXÌ„Á×Í*ì…¤S5ã°Î½$°Ä¨_é�?Ò[e¬�eƒV} $䖹홭¸�td|wÓáÃ{/4Â,HDÕk†úùKè)¯øD�tÉ\öHÂ>†EÒ@ˆLÛvQ‚rís9pjj�€¬›Ÿ·4§ç¦†c»+š Û–hgâ¬Í%çÎÁ­vúð”Ú‘].tÛ Û^Ø·âh®­¬!Ä) Rœ¢}°í‚Þ3¥B=å!è[G�Fï Í0mhêlæ’ða\twFÌÔÖ¨µS‡K€�mP›9q¢Å“Ò¼“²©ëÍ5A ûzßwî›:9MX(îœ]+ó¬>ïä뛑9½y+ëe­ IDAT Ù lmpœƒ³úg÷~�6¦™¨óx‚v"¸}Þ=öô–ý 6\|U{Ú“ñ:oˉ„�� yº¬$Þ_Ê"d�Á=ðÉÆž:÷¤¼nÆËûæ~¾u%™p&8ĨtèÍþ’¬ý˜Sq†Uök7p¡Ù ˆ°©±åÐ"á3ªi¶ ]N�T޳sÖæƒ)kÈõ¹ú-š´ástÄœ g´¼De`ÍÙ ´E ­&ÞLДÍTõû˜�©==ªSFh"¾�]'#!Ãã—…\´y�gc?$kä²ë^·Œ~9 _ç‘Ï2eˆ# ôg¸|Ël¨?ëÖ_’2Lñ/ùªµq2ìX Ƴ/°õþ„ݰLØâi ›í{Dl&f“�'Iú‡¼)ö‰­cýú›Çu^Þ¸¾^é’<=¯÷˜óÖoâþLÙ²QÿÊM×µg�ï[ÂsL½pÐ&¹þ,Žx"EÖ÷ßžé¼ ,³ðÍ5¹"Ýëˆõ¥¢ž¤ˆôWÁ°HþŸYµêgæ™Çd%û·]y¹'^ï…×ûæL-ôZH¡Œ>Aøœ™£º ˉRÍcÔâ>5äK§ œ>Ý/j‹ž �]>8ŽóØj"]½8öu9XbÂ}p±mV7"`T¾¹°×•�I‚’�/‚êéÞ øœ¬Ôá_»ž4©ôw—ÍiÖ¨M)¸5 «`�);c¶?XªO%Òú˜2¢E� çCH#fM™’ý¹ge/‰,>cG–Zäw}ÈbPyÊe`Ç;_ß:ooF7Ðû*¾HÌž²˜wå½&~ùzòË/ïüúVy{xL¢Ξy?áO_+�c0Ì?¯$g0ôV]z@d±Uç×6¦Â¹ûŽ1B›[”T6¶Û ·—O>PW‚‘$oÇðÁº½�<Þ;Çiô‘Q½q»½²ß^¸í¯Ün¯O ¾Èô¢°næÃ‡{ˆzñ¬D™39í¼¼|â~ÿLÉ. âÀÕDÙ ˆBÝ®uå.˜Þ]?ï–¹Y‰õÀcf\Y¥‡š¤Ñê­¾aVI©FAÖÙ‚)M)�ˆù¥yîÙÏ…zç<j{0¬âò“#ê2ZeÛ¹Ýïvo\´Jm•1º×*U™bî[OÐ` �×S÷7Ý=ù:2k±ÏO„„jG53:´:8ŽÆ¾olÛÎmåå¥rÖƒÞ+µ6Jk”2ý@!I!±ŠUA2HBҀ⌅a‰?üëÁÿùüWþá”<¡¤Œ’©§rœðåï¨}á§ éŸþŽûÃßÿþ�÷ÇÁ/ú7Gcy%í·`¹Ä†ËõºÜÕ`‚¼<Îsäë– /ûÆV¥B°´‘±rM¥ëÔËv¿LH¸ŽÐÞ€Lq Zäã3ý×ä>m Ôµ` L ”Z|¦ƒÂZ3¬Ã– û¶qf2ýÄúé��&ìyã¶ ¯{âå–Ù‹º¾wñÆòöRØ?ß)¯ùÒnÉ?×¥•‡³·Õ|`g¶uГÑ*¡_îõ qà_Ä:àÍ�Œp‹ù0·ÈÈXO<Þ]äç‹UìüJ±Êk�=¾{ýrÜÂ^nìÛ šÑÎÆ×/_øåO�/ï­™s®¡ÏBB›v993ˆåÇIl'·}߸¿ÜbO3;js -AèÉÁT{ÉÜö�Ÿó~øü™úåOœ_þÈ×·Îq@§ÖƒV½|Ža‹&¡âÞHTC*P@NuAÑ™˜@‰ç ~Á×㛆€ÎíüÓÌX*"%a­ÉåÐX'rŠ•£?ÇõÏïl«Š÷ña¬Àè/=þìéÇu\+Âú[^'ÿÁ¿Ûßøïó}ÆÓ÷òÍ_}ûó_zõxûu¤¸¥(² é&¤½�³øÀêMùu;}öéáÀPgª9·E K< öä0š‡¸úÁ0Ÿ{·wc³Î.‘,ޏ¯uð~TÞ•¯ï'_ßÎØ^ Léc.à,�†µï(!Ž`’è&§+NºSKÌmùŸÄ½I—ìÖ’¥÷Ùi¸GÄmxÉ—MUåZÒÒLƒh¢ÿÿ4–&R–2óñ‘¼M¸;pÓÀìˆK¾—¥AI¾Œîp8p3ÛÛö&æ@Ha¿@SŽL9îuÒá0F]}­Ö)e\)•­ÊV¨µÙ% ’ˆrØD£©�xN±çF§)´çžÿ¥²~†ŽÞ>Qcèjw&a`Éâ„ÄÉÙ�G’¼Õ§÷J«B1¸Ö†E7FQk¦y”=P ööù‘DƦTÅoßt‚Möv¨à~äÎTÙœßBËÿýƒv¥;ÎÔÅðÔaÐ0&þ Ãü †Þ®yì‹ÄXTÄÕ‘,î‰ã(Hœ¦Ý�¯Ø[Gçƒ'T]̼‚ÌhljzÂgI7ÖiÁ`vƒIÄ¥3’ëbvµ€ÐñÒ ƒ%!V@Ó6¢Z%G+ÈGQRè”ÐIA°B^�}KhéLS´Z�çP¶á»á±ªµÓjÛ;¾Ãho=­Ï;ªëyVŠìš×ô£R¼uPœñ£‚cê½™œ’¿Atí­”29O®œ�c÷ ©9Ž/ÀÒÎIð!›P›Ij¬¥²Õfó)4kƒ3ýH9P´šÐÖ9àãG„êÚú0`ã$Ɖ2ˆuCp×wVæù¡žÌtÛ!™ƒù0åE«ù<¸fîØ†°½`] C#z,ïM+Ú‹3Cèw;cãr@¦…8ØþHÍGö1k7ÚŒe]Udg�Š(}×3?ºhz+´zG�Z„;£Î§­¢Ø‘`s^Ɖz7I«Æ�Qo›ì¶˜Žu�}.Û½µà×ôæme›sÚö•¶þJ¯ ­nÞ"bê–ˆÓÄ2M\æÌ2Oäl÷@E‡4³3$ÄOW0†¸�áaå”e¿þ¼a {t ÊÐ v£A7~ ;‹ú»è\8Tq@@ *+†ô:Zûa¤¦€V¨5Q¶Ê¼ò½°–ÈYë÷4'.—Ìr™™–™i™ˆ9§!}$Ö‰| ®�Ô!idr³®pk¾[;s¤ÜTÛ ¸†x ig•”RíË�‹Ò”:Àº[…­áÀöDL™³5*V ±Í8å‰)K~™")šæ¾8»ì±®Ü+I6¤àÉÛ³Í× ¥Nܲ5Jµ¢tì*Uè0V02v�5©]ƒ½ß?5]B#®úº¯ÁXdj’#Ý�A:X®ì1ŠÝRä Læ(Ì)�£’cçš•çžfašlüm¤Ã#Â=ª±yµÚ:¡U’æ˜LK1'3�.�¢læsT–líõ1CG¿5gå‡àkyF$ql<ÂÙR»³Çq–¿îã=»†Väæ (`×À’º Ä0¤#l‚ª¿fx]ìŒ"µ¿zêpd´cÃÛ ±#†9 µ `¬4 ¡3ÂçÝÀçº�‡¼Òè,8´ž­˜t¼Ç ˆ{©Ú ÁxW� Ç2dqÊ©CRu_³9^Å gN…gßÔ‹®ûÕ?ÅNªJë‘Ú;Úí«xì¡Çó÷ôg³rü}hÍ ÐÀ&¿Uœ#Þö–QÈ×ù”¦ø¼9¿Ø=þ£ì�’ #qû>ç4®ù!ó¢³x÷§�ø’7÷ÕþvNÈtLöËrNÏä(¼Œ{sö8?‚î¤u¿Ÿß}9Î5»t(�ˆÉ-oûyªº|¦¶¹·{·¨)*S†y²„ð²X{5­£¶j¼±�¡@Z±®¥aüYȹ“ÅZ)Rb hôœÆ‚g÷{ð™’wîa¯gšwøúº¿fŒ![¨Ù;ü†Ýe:]òÓ¥ßWò1>˜ö{‚4f!.I£ûωB4‰Ù±9«M)j$•s^â2!.·fãÞïû~�Ç 2ð4I‚µËÇdan€7e¦Ù u—)²ähÒ¦j÷R«·´×FS!Vël $B0É•u«Üo�Û]¨íýq¹D™¶Îï <ªðm~{­üù·__7^oFT JO<Špß:�Í€�QÙ;Æ>ê §w>¾³i½kT##)ÎLó…yy"ÅL«¾‚uþ_­ßÙ6E5Sf¹¼ãåùyº0åeï¾·Ž-—B7¹Ž�L‚0ÜQï°P5iD3s�ä|åryb™¯ž;Ù~¤jç“rLy¬uc_ïÝöZ#ÂXÌ4üìn~Ü;BAÕºø¡³m¯”r³ˆ24Û%z® LÁ%i=w� ÖE°ÑÚ†jÝIƒÆÅ‘}­6ãÏ ÁîHÉä: Ó:ëÃŽ—SfβQ̈r3Ï8_ûRž˜æ«ºjCõf¿­PÊj&ÓDcèG—.nc�a�•Åå%¦,ät1ã^]fˆªÕC|�”„ƒ–ÛÉdÝ,Ge3Ú¾- ÞiÆ‘Á½Ýtß<ì5Á€ƒ8wÄp#v<öïH;ýä s_÷]}ÿqÄdoÿ§÷ÿÝCÿæ3Nt°ïþúý±Çsþè÷ß½ß8ÌïÎñü^ç3ï}ü]÷^{ÿæH¾ûz¾!V÷�°-âÉ50Í‘9 s>7áþÚ¸�."Å;Á 6¡¢;øeóPl\î¹N‚6‡H�Íë]–3×¢lkç¾V^Ü׺Ky§4rF�¥Kà]r+ŒÎ)!O£[3Qûá«›ÔœrUiIÄ)1¤0ÇóÆZwNmöúcLv¯[YZkµý¤6jmF� âž8¾Ñ-nè^có-‰K½Ë[I`/®­QšPZpS'CªK©l[¡Tc š¡™ÂZP-Ø÷ˆdhBïZg"nÌj�kS¬è,f$)[µu¦;Ã¥{=,¸ÁΞÐáÇÅ0üâ[;È`@öÜ8äHœOµõƒa,jÜè}@íÏ=˜Çö1ßañ‚Ĺ-yû¼ã¯?v¹!ÕýçîüS±œ£u5VïØ/nØhOÁžÝlµ–’]Æ&¡Twt{hé7/8X{Ww© cÒ7U²šÉl¥Š’èÔd?­ôC“°vÊI9Z !¦@ÎâÞöy‡Ѹ¸¦sÙ\ó.xat$´^”ˆÆ¦É)RS ·!bÄT}´{;Ôóc“Û½œ c46Tž¡ï�Q ÕÙÓ&?"ÑôÁmüyYH}�p�íÚœíª£Ý¶AΫ¼9Cc«�m�{à ,vi m¨{bŒk·©âhß”Ëôt/’{â¢f„˜ŽëØ‹i€x¢f‚+bA÷"‘öBÓͼ8º¿�ž$ t0V‹Y©½Ðk¡µBkÖ:=ô»0ÐvSOÝ8"´;ÞÔ4â(õA½UÄ×"m�ÐÛÞMÔ‹°­^Ä  u£—bÁlPk/È ™‘èû§¤ZÂÔ¬µP´Ñú�/_'n÷_Hå³;^®W^®ÏDŒù´$ž–‰ç§…wï®Á‚œAߎǸíè¸ï†pè^Òàc!œÂùÝ:´o÷çà&ªCÒöèÕ5‚C£E£¢  LzKÔ5qY"e3csE‰S$MfÞ5]„´ñ"„Ƀ¼AO@ú¾ÑÒ}­®Š]‚\­5�*hzhC"Jt†¼Ð“}Õ)%Yñ¹´�U°ØŠòØ”GéTuMfŽzE´iÄOKæé2óîùÂËÓBN‘œµ™žß—W!j¥Þa��äæ>6@#[³±¤ø¾Fɯ»�éWy¢„£8ë,vßS,(•‘dÀ ÎHaF$Fß™«1GBö‚§xÞ›•±‚2k ¾Î‰§%3'cC,säùš™gcXYÁÝ@æ”;)uË s*Dó:°ÄÚ†»Õߦ˜è“’c`Y’I‹LfögìÝ…â…Ôœ3!&æ,ÜÝ9Fa+�¼“D{ vcˆT�F2::p&¬’àE%ÿ qçD!`nÊ#–½:<„dgb�ö,ÿ¿iµÊQðVÁöÛàñ‚°¯ñûduG‡S·Oeÿÿî3Þy:ö;Ã~î{!xD¢'@à0<¿ÇIø¼¶œ>ëñL_sFíqØ‹Q­>ø^º³³üuº{+è.�Ç¢ñÂߨ3ûˆgÚ�¶á´úÉQ çøö1îß_{øçõPý¼½cU±ç0s�‘½?nž:1æ Ÿ¤�Î_£ËâMÞ&Çý8À¡@%Á¯ïøÐvÎc›ñÑÍÐo=ö�1|Ù ûÐNƒ}‚%ó$ šs³În¤�(�• ÑZ¢·BËÚ"’ÅP�ºk)ƒxçNïÁbš~œ[' !;�h­H¥u%õèrr�Ö…äCó2©Æêl,ñ@Úò’Þë‘Ó „õÖvé¾W{'/#Iô@p2•˜+&oêc®Ñ}ŒŸ:�C‡¸YD”"—´�®™åÃ…—¯ï~[yÿÛƒçŸ_Yþrcþ¼¿nl­°¶NÕNÕ††¼Ë Ú¼±kœè˜×û˜æˆ²(sÌ<å‰ë”\¢WH9s4ÀËÄeN\æd^;hJ¯�R�µr»­&+TœªŒèÐxP:mëè¦H¶–Ž.�FåQo|¹müòõÆ/_à·/w~}-|{-¼Þª‰k†@ÓDi‘Ò èoÝöW#‰u¤7jÛ¨½Ú~)öºa¾'1ãDH3"‘Lˆ31ͤi±˜y#S‰KšŒ2G)�mëÔ*f¶œg®×÷\®ï1sñìr˜–šØ£K^Qb´®EKîW“Ø�D–È4-,Ë•”2€ËzvcÀ7ÄD8ÌìjÛ×ïÖ:µT¿Õdm¢É樚ÔÇºÞØ¶;ù$Z!¢”•­¬¬%óMÊyÙMf›ň}ýÞÇõ Hó"Œ­K&û‹ƒÚ]ØsÓyŸ§l¤ª~Zó½Ó J2&�D†´fqV{­&[ˆ�'öB~ôüíÍ™•£L)�#w×´µ‚Hd'%X="º_Y�Df2Û[u0¢S¶ÎãQ™R§N ’™ç kÙèý+u+HèÄ ,ÓBÊÁê!@Z×¾ØV¨�LÊ ïÞ-üô§ ?üpãzýÆ2'RÌ̳p½^øí—;?ß_©[G5r�gþ‡ú'>¼+ü_ÿ÷¯üúåÁýõkiÄy!äÙÀ1¹Í­4Ü6 íÖ}5…À”¬«÷�ÚÚV‹J£ç 'ftc`ö“ÈAÕ86Ɇ4x¬•û}ó�ùf÷¦“þà[ì‰(fÕ$¡“±×%Ãuž/‘wOÑrº®6ÝZàz5ÐàrÉ,K$FËyCâ sDfÙ%ƒ¬’Þ�n² f%¢w\Ãèfgäûî/ ɾ}3pÞžk&çÞ•P3ÜúØhíA)Ÿ©å7–kd¾F.Ï™åibšM�aJ�c5` )T¡>"iʼèÖ¾P›òØßn+¯�‚¨Rðk7Hšˆ�º½Ó[¥–•:Ó”IѼ.Z­lµP¶ÍjJÉH”C‚9'óÊ[•ß~ýB’Àsl|üøÌOz&å"O�œÍÌ»·f÷:šlZ”#ÞÐ^iÕâ7‰¶ÿG�ejå‰zÊ�C8 „�ÈÃñóïÿ?â=ýå�‹tßX~Ï÷ãŸãã�ÿ?:VåŽ÷·ߟÌùç#'ùë�ÿ–÷ùsÌï+çïôÚßËáÁý/  ¾ÎΗ$Ä«0ËÄ;é¾ÿ¬„°™嬻Y}©˜„_m”©t6‰‡*�ÇvÃ_«6åöhlµ“ㆠ” ÊjàÀZ„­GºLFHºÇ»ìñûQ£ê½{8(æ¨×f¨JjJ‹ N*ä×�£Ébí`à û4÷*ŒBN�4%Ï=3MbÌWÓ®¬x‡¹ú•mî+K­»2LÊæµ8~î}È™`ÀÕ<<ßB�.Á0Ý* Dê~¼]¡Ejsæ¶Ø‰tOV•NTv8À‘ýËH°® ¥LRªéÜ©ºvÙÇeCÝxL\S¾«uX¶`§?=à ¡ï{ÔÐ’ÖáI @ȧÀdL]Ò€¡ºÄбGÒEFAÃô!µ[àÒö97˜?vÍE’Òt¼[èm¥l+µn ]µ£¥ÔÜ�¾Ï b<$F ™Ä�Kule¥÷‡k¬sÔîŒ-µ*¥¨uZ„ì~æÝÐCG¥¢º‚f‚,VÔ�Ø ©£ý]û�RoÔ²r[³$ZïdÌyfÊ?¾LüôÃ;Z1ÌeÎ \xÿþ™§ç™Ë%ðô~æÝ§g–§Z@ „ŠžÌ†æñ˜¤Gx1¤ŸlVHHö}c/E� E£€¶?äXöBÅØ|Fh“:-U/ÞuOš !ÇŒy7(½4Ú-ÐÖHmÅ ì)’�/ö%� 0aLœ½òä‰ä(À¨³y+„Í„Rµ½$61ÃÅ ¡ II"CS¿E¡F1“äZ©Õ¾ã‡/f¢œ�Ç�ÇãA¢ByP¦À#Ûœ9BÌ ‘ÔlÍ5)Ó?ä÷ÕìÃè‹~î:Ûoê~(ð¦˜ç¾ J Ñ|B¤6ct…ds}Z2y6šˆÒÊF+›!Òwc¥w׉Ï sRhL9pY29Gbût°©){Ð_aFÑ;—ÞÆKŠ&A—Cß,ƒ¬¸Ÿsrù©hÇ­FHã9D!åÀ4›Yô=÷%°é²n‘5˜!½1I”â Z—î;±­9êR]ÄôÚ­bdíü1í§N›±Ž97rŠo,)qmÒýwÇt/</ÒØÜ³}MƒË6ŠìóÌHžo‹ÿ߈ÿæcï~ÂÎuï%bßD–ïœb•Ñ)°¿‡­£K`\“³TÏ›n|,×Jb=Rz µ�ê†�£äoqÄh vKÛA“Å8'ˆ¡½¹¤àèP³¯£íj¬m‚ F÷麾¹t ðçüñõ¸¬ö =7<ÿþ|�pú<ÃÇèôåãqx£ÉQüZújRƒéóæÞïÝ~'ö0;ÝNÏc‡ÈXKŽúõøô5(ÇsÕiL‚îz€ Æ–íÐÖuiÅ~ˆÒÈÉýV»És£÷ã$L¾¢»wÀ®ˆlÅ;& NŽP¬K¹cþA­)M±›/Wê�Ô…ÜÍ#&w!oœnÀ€DÿÔ£°uÆú(r޹à×¾c…¼€ƒ‚FÐÑÓÞ#QF9eïÒzK%=ödõqbÚ�ÅîW ¤9�®™KØ Þ·Ï~y°\²uÎJ‡ºòº6¤7VïÒT«ªØ°pFoð$4Œ=ÄûÑ:a °¤Äó<ñ<_v“b‰BHÂeI\.×Kâz1�ñ)Éî3¶>*ùn¤mÛü¾%+vS½«Ùöå¶uZ>W¦ó^IÜ7åËëÆ_>ÿþÒøúºòíVx½0P{¬‡Ð¾ö®ÉfaÐJ«+¥¬¾ÌÒ” 2™¿GžqFâDŒ3!,Ä4óBž$¤”l­zQþ8Šw¾+TÌóÌåò̲¼p¹¼ÐZ ·1ÏÏ’°Ü&Æ…$¬Ôj²)%D¢ÉÐ,ÄýL®§R›­�V ;€hÅé£0Õš�1v´ëm}å±~ãöú�Ö ½b4NWóõXÓÿቜf_,®*›Ùw ztft“Ö:ö3ß?$úªbF‘CŠo|SŠÌsF1éQö®Q›c¶aÅ�Û9ÐdR“P�ˆ˜t'j-”˜©aóî»!?3rz»OÁ}ú);¥¶Fpy†21d{~¬´Vˆ!ÛF­+M6¶m£Õ�më„PÙ&“S–™¦ 9ÝQ…R P¬ûôå…G÷µ¯ ƒ4@t@4s"¤™çw?ð§¿ÿÄÇ�?s½–9Ø}ÁÖ›^á×?µnß–X¦g~úô�|ü |{-|þ|c½Ý¨·Âtíä«@Ê�ëfÀ^¯FØËÁdPM³?B§¶‚èí᛿źÚ9ìˆSí«`¼ïSG\‡Â}+¼>6cgaRóͼÿá‰úÀŸ^x}ý•oß~!F0w�¥H”àRth÷ªtmH?:·5b2(Ææ´.�ä…�Ñ™œrÛÿÊ·¾%É�*rê±°~÷�zûÈÇ=g–Î +C4ÇLüû>øßÿ?ˆáOÏ‘7ï-¿åt¨¿ù÷ƒ�æÍY¿ý×=ŸKÞ¾b\“ãÕº×A°R|°¤G\¶0La÷·~Ó óªÖ)P…Z TaÝ„-*kˆ€ùÓ5¦ÏkzmÊÖL–,:QvÛ0¿Ò:< “«ƒ0Ú�ø$ÙZÒ�Z™z~r0)Dìï Ä Ésotˆ7Z�\ƒ0V†AfÂåÅC°ºí4'æe6)#�^+­°›Ý�<`ï@¶ÖS›&½;�צIjJLzÔ*[£ö²wž«×1{?º»Òt¹òÞ ­ÖÒ¸¯�µF¶L"¥ ¥t¥Ót£´ÁŽŒÚã…F×1êÝØãe×Wöâ2ao)ìMékµD¾ÂÖÄ5ì3‡YÅHÂ�Vñs¹kOðHA`´�K°êÁÀ¯Ã¥sÄoÚËâã÷Éxwéïs¡n_�P|c÷›ô»äuì†oPûYt,"ÇÓK\ŒH»Ÿ–Ú¼Å>ª�¨–¯zEa$g.—4”;ì]ÅŠáÑ`u½H6G�W5ÑÔ6» êŒó‘í*•�•d+�¿'f Ù;ß@ûš3ú“¬¤i…_2DMLú¬hQ×%¶Â©ˆ»;*Hí„Y�-j¤kupEˆ³ ³ÂÜ�úŸÔ®m8¯Œþ¹ŒB`›£¯å2)ù-iè‘ØRAº­ë»Y¸¦±�[¤µ´+L¶Ätéï�FŠÆM¾—mÕNB³saŠ™Ëùðráã» /׉ëMž"DI2½ša Cg­‘ÆâÅŠ¥[×@töÁ@c}/²`T÷Z¹päÈÁr þ¼qqeñŽki nâ<ðÊn¢üôtáéi!Y CÙÔõލ{šÙpàû ?¼âº$¦ìÒmÙem°n§|/�”µeªV¦9óTM«¹¹ßKëuübì^È7é¶‚›$±ë›Õƒ}Ž6tôÁA`Xfaš"QÌ`Éä]…yS¶IM6ªâFÓ�‡w>U_£ÄרT7‹1‰ˆ½c Ä}\ RÁn�±B†'��Á ²Ô¾�ö‰š¡J;ºƒwSÉè�Ú .>Wö¢ñ|—Äæ<öŠ=…ò1vþyÌÊQüÏòc�ñ×êñ)ÏÀÀðË^,pµ$$dïÌkn¼Ùw™Û²'l8ˆ¡Óã‰]=’Œ½Ð[lÝ´ë�é³>н«ãMãEª#W;æþyƵ;’&¿–o>×8̉Ü1î¾_„¡îà“¯ïŽŒÑZÍ�Üíj°kõm,üû‡_ûpê’t©OI×ih8nžÈè8�ûGt^ù» “±2ÉX£ÎÀ@Mž€Ùú“ƒ2g˜#nXéEŸ.Ô"¬«8bû¸íçB °V“€ë zµbrŒƒ(r’ÊS#ËŒs¯jE„®j yͤ‰-l2ò�]{î#¾ýH’úˆèÞ„ØŒ@ɺ3m«¦�ëÅ.—±ƒtŠ]hÑÓNão€XalˆÂC2Ì!¡i¡Ë39Ã4 9Ãç/Ÿ¿nܶƭ4H‚¤D�P¢í…tuŸ‡!Ñ-éŽBJ�i‰\—̇ëÂuº²µF©•ª•®�„%G.sæºL&%D£´Âú(Ün¯·•íQ@]fFÕ|‰ràrQ.KdÊ3µ ·[aÒHl�û­óí[å×/…¿ü¶ñóo�ŸÛ¸o�µ4 6J7æ¼])cô—�°øßж­oÍ:¼š8$CcÎÄÈ\¦r°mùùi¶î3·M<\øOÿôŽ)ã_ÿå ß¾¼‚~¥÷‰Ÿ>}@5ð¯?ÿƯ_”5P{GòirϦÆ`¯„Èyb`§U­lln âìLõXEŽ¢ÿXPÃèrõ%p�8»Zw§*Œá573¹õµÊb€TyœF¼Ш�;IQ+±o$2‰Â”u—�`Z"y‚»g=�&mß/dÈà æâ› ÓÎY‚ŸäÉ“ÆÆÔ)¦ß÷ÍÑ£i_û³k?û!bê¾±RÃFš;—w�ç÷iÞ}Hf6­=Jj£K·ëwQê“Iš¬l¤*H,ô´±å �*[4é;ãÁÔVVh¿ÓÛ�ÞnH‰hHô¨-Ò[…º‘$çÙ˜þNž\Z,f¦” m+<•×ÛÊõ&\.Pʃ¡vc$¦DHN.›ªó,BW—7n„ 2Gd0ëJÑöC‰(ÖÁÎe9egäõãŽÅù±åQø›Ç¸×ìÃÚŸ¦GNm²§}ûíqGt:Öü·O9ïù¿ûߟÌ÷�¿ù‚¿ò÷óïþÚ1ÿÚëäÍOv„Ÿ¼óo_§o^0*ØNxcÌ5Žm•Qëðûw�$™¸¢ÄÙ�íÑ-Ç+PŠR6åþèÜ‚Jw2œIeƒ =.0òl÷JG% Ýä¨Ís5ºÒM„`ëÝü KSœCyuz]¥b •ˆíá½»$–2zbÔcÊ®b$b¶ À"%óH9"y�ííÚ„æ�å¸�^$¬[›Õ\·ª»t±j ÔFˆá¨mªùŒ˜ÏôÑ‘¬¤ùz±È»(íQYKå¾6¶šXk¤63h*µ±®�Ò7Bõ (�â°š�zd´A·fr£XÛô0)sós´U¤4R…Ü„œ=ùw–÷(�è^0”} �õ­FAÛþhÏô–­ð¢›ìèÁ¾Šñžì˜6ÐG>ÚÜ�äàFc�ö˜ö÷·6?Oñû$‰–̳riʺU[5CÒê¹àço @ÝÁ�`ÆÕA‘æZõaø FP06»¥–ÚºµÇµîú_Æx×*×ê�;S´{!“nFÄÕƒèA³À@J œQ0Ÿ‰ÖœeçLï”ÒΪ/j…O¿·¿m›uª^ä ”ZØ6P){z+ô:X�öBp†nðMµÓë†öZÚ^;†é¥�H4Íé¼8%Îû\³¤dÝ ”È!“TÌ|L’•<™!×B¦G3³³{܈"æ•Ñ¥>l h Vü’i®¢w:Ÿ‘ô`¹.\Ÿg$Yâôô OwøáãÄÇïøôÃ{~üô�o¯~Ë–˜äiæùºðt™¹^'ækdšì³umVÀ̓ñ Gí&«¸Ì×¹è$¶ØÙF‰É‚1d¿´ŒbÃ(h¾‘ÓÀCZסWY¬RkÅÛÉ©L.ѵk'`�ªÄK0'òÑv2ÁË Y!7“J ±íA•Ì;³B¢±Âº®:€ fXL"õˆx ß(šá´žžYŸœZˆºðX+SŒ8!®Í‹êé z#& ã¯sæå:óû _.<_'®³µK’D昽^'I¸­Ê£$JVÀ  V| ý/ØÏ�Æï� ÂÌ ¹3ŽÆ§u°;Šx×^è��ž …)G–yâÝÓ…²1=Ëã•í@�¶da™?|¸òÓ§žŸ'–9’˜¦«Éo­[%~44¶’è}¢j¤õä�‰RZ¡¶H-…V*!t“+Jɾ¼K  Ön>ü‚ ¿Kâ§™&å:[ñ*EaÊ¥]& ¶ÒÙŠš)ti–<ÕèæÃvÀ€ƒîÀ`at 8èû¼Ú}R°dÎÀõdÒ†ž&Ûé*‡Ú ß±æéáÎ÷BÏž*ú³‡þü.�æ{ž:ÉF§ÙwA¾'åßÿú ƒ_Ïëê)?ÙOc Ðテ·�¿Mޝc Š!ì»víÁìÞè±»{Ð ZË8ƒ£ÖÀ®yÇèïæÇî.¯Ñ{sƒÃJë½W—©;`°Çp’»á½G‘§BÀ~MFü)‡ÄÄ�:%�qŒqÞýûk/rìÁi€ðÖ‘bÓÞ�ï1ÀØç,O²ëßµÑO>ƒ|ò;9©pbâèx›À$û°Cy¨#X‘ß1ž�þcPdzuh+‹³çÆ{D‰„01%X²�¥#}³7vpÎX_ÞÝ:Q:A:9 9Šûˆw˜z¯GŒ^À„Ѓ×r,Ñicu³�“Ö‰M‰UiÙä*‚ô½X©>Ìe¬Á{±|oûÀ8w Û-òäPtäxûØrª‡Ž±]| ÇwOÁµ³ö.YkK"¡Gæ9’¯‰yž/™)›ÜÛ”¿!Z7óz!GÂ4Q›P¢ÒJ£×ÁÄìÞ]fkžó˜—Èå’y]X¦+�m㱉ç«Ù—)0p™ÑVLr°UÖõÎýöàöíÁVœñ ìÎsæ².—Ì4ej^o%3µÄíÖøüµñÛ—Â/Ÿ7þòüüT'“mVJWŠwÂušIÜ$»'½W6z3°{„ÈðYËÄ4ÓaB%ÒDHäi"“•TïÚŽñ$3ã€mkFîÈy¢6%Ä ‘DW#Ò™·™ùdôÖ›ã@m¾‹ùäiñ¼À;ç›ØüښݻhŒ™QÐ6�>÷%«uYÙ±VޏÙü¾L&«”�u½ó¸c]_Y·Ç©£×d rŠô9{×¾$ZN¿w#À4ݬp,¡�îÝo1q”G $4`þár>ž§˜&30½\/(�RŒ�iã(’§‰<-ä¼ A¨$Tï oÞž ;›ÌO$§€œ#mvsn1` Åd¾´î{drDb†Î([0àa§CŽä<ùš ˜Â5ëf�Kzòt0-öº=¬{6Z7ÄÓó…Ò_y½?hýÎr ¤$\/ö[Ó+"ÉÆ‹Üñ< öÊZŠïI³Çã=A�<Ì<_2Zÿ�ÿú¾òõó úæË{þôéËráõqç×ÏŸ)k§m…�’k5gØ÷aÊÙHˆ4º3˃R0?)Úi;R}½ôÌz,÷»ì³åñͺhÝ¢‹ÁµUm]U#ø8y‘ÌÌÚÈx¨"©™D…ÐQ Y*K\®á,fH“¢¡{ùØÌÌEÄ‹Í(}€‚ožryÍò»_ºõ›"é�zõ1�÷Æ–�.OZÔ:´e%.�ëKäå}âýlj—‘—�F�Bš!Ü�ºÛÐɦô§@ne39ÝXÑ´Qó†ÌÕãs9T º­KÊJëwZ¿ÚÍb‰ôh-ZœÙ)Ï\¦HʶΉDæÉ5å™M�Ç£òíU¹^—‹ÉOÙö¨è�ß…ïž§ûs=e̼ñÓ.:Ðó!)ÄH9ð”¬c}»W¶G5P`SÊÖÙÖNÌ ‰6¶×µŒV�jô‡ÉÃ僻w³j3É´Þ I€íÞAW»Ýø]ÂdKƒ {uÝîÑk£]iêŸÓcT›ý8�ÉÈsÆ&qo qâ\´}wžÒ!9ääµÐ0bw¯!ñ«jO[m<¶Îc=-VÒ‘Ð\%§Ó¥ÑåpÔ}#UêILª ºRš™f!=Y7C>c<Å$¤äÉl·–_›Ä^è ÎÒd m/Úf}ŒŸý„F®½bKÚßQñDý”†úÅV×ÇSCiF‹Ëu‹ë˜‰ñ^¼FmÙ#ØC¼˜r­uL¥Ùä(Þ&bÝÏß³ÁÑ2°ÏO¬ö�3kì7ÂÓ/ئB>±T�Á-öŠà�ØPo‚#dãº[¾Ky ®amÛâ,G+Ä›“wíêZ]¦Ù´`ïežm‰®Jòö½ � �D'‰R#¦¬fJU»RZ0viëä¦lriÎW×ê-4JÎBiƒß Ç Åì#ò{ÅXgÔñáÜ8�0Zƒ£Œj–µ6káöظ?VÛÊV;UÓÎäfÕ1] ³#²Óbk¬X¦tèÕÆ§3ŽÁ\˜,ÊYÏP»�Ý$²{�Šhÿ}±&˜î¢ªBÄfqušÁ@ò^šo‚Í¥¢F�ã›�3¦b´{3õÀÔ’µgcE˜~bÛ¨Zq¿k0F†6ד6S×èÌ¡(Ãq–Sç”4 ¹ ×S»¾ÓòB°y´µ¤`£«éÐ$L'‚ÎD™Mj¤b‰c`ú—¶®D¬Ë`Ήð� 7.ó�wŸ2ÿÓÿüŸùÏÿã²¹Xý_þ�þ¯?óã�âÓ�ÿÀ2=s™"½Áãfóm^²É£p¬…½BÇÀ7€AèÎmÇZx(0†ùX4mô Øæ3Ú‚YŒ±Ypâߎõ‡cnˆ†Óï\~C8Øj"»ž6{ÙÅ–l-"‰Ç1,�‹Á½tgä�—OÒd¬dûb¥FèÍ€ÇD“LÁ¹›^Î8 Mh70;óºhZ@)ufU$bŽÄÔÉ¥SK  <]Ï×ÄrRît]Y·b�:ÉÅ‹’0_gd²äè-ÓkÛµ‰0�]æNÕô�Ó_„ì°Á<ÏÌóÂÓÓÂåreÛ:ÛÖIa%ˆì¦Ò리¥“Kd*�`®œÔn0°öHŠ@ñmzð×’ �[Fb=^´¯EÆbîkÓ»év«-ŠQ‹´®J36U[ýÚ�DnïÐ LÞ9à?�û~ĺ�lIÓ|×TÆ<,þQ(ñ„Ÿ²Ç5:â“>ŽÅ˜§6Nâh÷ㆄ’ŽÎŠ¡1–ÐzX‚1ÜÍœëNDvphì¿Ã/):à–ÂD9�;Ý/ñB =dè<޵ÿI"¯Ñ#ƒ/§§ÏŸ’XKu¢4¢&r<â¥ÖÛ ÈWk!¡›4\‚º™ìã†Ü�Ýc=0�Ü;‚,n9bë`é¾C«j|‘FõxO$]Ò×f_ŸÇt樈ɀ!‡Çµ»üD8€�±@Œ áÛ¤ì“otéœ7µ¾ÿkÿ[Y"ñ]b /õJí•] ×'x¬ŠÄI ¥*ÛÖ)%P ?yŽñ(ƒç+_ow~ù¦tþÂZþ…Ú…×ûÊ×»(ÖucZ&¦yfΙ<%zo,9’C ‰æ‰È<]x¾>“SéÌSàå)óò’yzŠL³�b�‡ù9„þË�?ÿü…?ÿåÎo_ ·G jôµÛ:V¬ÎbÙV-?ëZÍçB¥™<$æ!Ñ]ÖÓŠGx~`R3!̨w XS6©IÚÛü鸊ù§µV�D³™¡-¨åÆS²çËà­`qÛ3>k]?dxäˆájkle3ùÞR ˜KðÉv¬3C"(ì{RŠÁs=+�ÇØ)Ûʶm˜L¨�+d)®×…iŠ´6ù£;ñÊVùÖ¾ò¸øPÛÆ¶=Q¦˜È“ æÖO4[g=œÛ;L˼”¼{Íleãvû†ªPJ3™×͘ë9Oä41Ínœ2ËIblä4íya�D«ÊãQ1¹&ÕB×Í¥’¬³qÊÓ4‘óDof¼E»Ÿ8k³ëÑÑ]j#†‚,&wÔ÷”ÝÆUL‰Ô3ÉçE«�RÜCZ°[c0ÊâAÛý»¾0Öè~Â|Ðëžaí{è±4ïõk¬Pw+¯|-_É/™ŸÞÿÈÇŸxùñ‰ù©#O}?ÐÖPÊÞ}¨ÌJ¬lõ s ¤%°L�wO ¥?¡’i¹¯•û£p{½q»=m#´�%vúä€yèlšô!3Í3—ëBˆ½Ù:šâDJs^ÈlÆÐ™ÒJ»óØ^¹=’u'«…•ÍzÌhÞJGÍ���‘dÐr‰Öf˜å`.Öe‚ͪœŒì‡„ãè(Ãñ½žîÕØ�}–w{gË™x!CYC–x-ÈÇçôE÷zÿØÇÏðÿ8Îÿ‡ü•Ÿú7|ûÚów�gN�2§jõ¼fü$‡�¼É¥¨FÞoSÄkP¦�, E â$¤Ùd‰‘¦bR÷îWbdU޵H"*ªÙl3Œ·5§cª=˜Œœvûœ¢{ŸŸ“ÑIJÀº1]ÖÛ0\ËBtÒ°8;¡�<ÁòÂÞ‡Ló¨E(�b2|æmßÁ3 ÷Þ‹f$:SÝ1ÏÞµ4Ö­³ïš`ŒÏNi ¨tc îù™�Rµ8IQRí XëÂ4ERrNm´nÑwL®ŸLN¥;˼uc?H ¾?˜9—M¨~l°ë–t_ =ÀÇÊsªÁZüÁƒ˜·ƒìøÉgN ]¨‘,�u<Šék»Úµ �Å;d´B–^;FU…~ÔþϾ2€†ø¼°,€6Û<ÿ8~–Q$° eÏéz¼—' ²Êœ¦6Ú[ ÝÚ¯•:RÛ•žg— Öé1<jS¶Ú-à­••»{¼ŒÂ´±�"�¨&ùEÍP²C Æð©ª¤ÖIÕ 4ZgªÝ@‚Æï�BQQ`É„¨#û¶{0º—Æù�±-¨'ß:ªC¶•9øj¹ƒZYM{5¸ö~«�¢‘½@åñM�P;ktd VRqðÁÿ'C~ÇÄ]Ž+Æ` €6×,÷œ%YÜD�Ò;(î¹Ã ¸®ñ{{w€8êŽñ®cAW¬;ngC�\Æ“Åè�çËžÀ�?|2Äþ–lP¤”Kâ¥�Þ7z}ÐKäqWþåçÿþ—/üù×Wþí·¯üåó7~þüÊoßn|þvçóm}SôøïñÈ)ñr½òÓ‡wüãŸ>ñ_þþÿåï?ðO÷�øñ‰üé…§K¤÷ÊŸÿüÊý·¯üòë�ß¾Tn%0 &-¢Ý¿JL’ Ó§w‚Š;†tÀ¼‚ð!í fà1¦d$ÌHÈhÈ„8\"#œŒÉƒˆ›z‹}3y˜uÛx<¬ë¶ûâ…ÈSôb¨œüêâ º¸ÿ×®)ܼóáHøÏGŠ~–R�äÝÑÀÉÎH7mƪ{Ÿ™&ûè¶@¡‡ÎÖWÖue[t50(ë䘦̼\Ð6ygÕð;@Çm­<Ú7Z[…ÐŽÉw攸Ì(”R¼“ÂÆUôîƒÈ©h¯lùÁšîNHªlÛŠªßÞî‚›AÇ´0åÌ<]Y–«�"î÷`òM)O¶7¬[ƒu³óèÊи7€ 1M S¾pY.ÌóBkX±2nˆ¬ôÞŒXáE¿Þ1cèP�”“ùWuÝÉeQY³ù[åLkfÜÜóJ‰Ê4™®ý2Olufž3¥Þy}ýjD+í•@†n`L¯•)I®µ¯´ö•Ë7áò%ðXŸQÞ[! u`†°@\ O\^&þîïKú…o_¿¢tžŸ"Ë5ðÓ§ �Ç…Z¿r»=è5¢-’ûo¤HL&?{––ª"шó 4µ‚¼M//BíH¾ÝƒÀ^ê°ntÓ»kW›¿Ahèê~s¼È©¦¤:ôÜ=ÖŽ°y„6D+ôJÐ@"Ø~6‚–ŽÅƾF‹ˆËŽš4�x®ÒÔ>‡ÄdFÃpåû1aìsýÈ_t¬ñÂ�*üý ëòø“`À@hÜë+_·/üôéG~üñï>.¼|\�¼BÞ0QuE×F×ÍëNhLæXYeE#f¢ž¯ÄéJÌOHZhùòõÎç/¯üò—ÒVb[‰}Ñq_3«« 4ò43-™å²p¹. ™mk Ñ¶ s¾0¹¯™PÙ¶ $^ï�çëÂ2/ôV)k%I Ç¼+P X±8€¤€äˆLÀ`‰ö=É0±‹ìfh·¼S`8ò#[+mbqZý!oy’ƒ¡[§Êïä:GÐ3òí�®Z»@ÂÏIOÿþÿåñÝgÝçú¿åõ~Œç�ã™?z¯cëƒpÈç ‚ÉyÎŒsr]Fq¹‘)CCB%HEM¨ÙþR¤v#?Hâf„aËåÌs ÄÕ™Rš-KÁˆèM±‚vÏ�Mp"^ˆ.)׉R] —Ðë &µå’²Ý—Ýǰv#F��æ!òè,Žž´AÔí{�W‚U,<5U“ҔҬƺ›½nxøvºyò´nDvÐ~ßR)Æüï®wžSb™g“˜‹}ÈV5*M„ÚG�É[uN탈Ò{ ¦m]Ô ­ÁÙÞÂINE¬€Û†Ô®Ã: #ß t‚oä ïr õéKN_¡�Ò¸–ÉþyŽ®ßP‚ Qœíy:$º×tðZ•à Œ'¾2dˆt׸9�õ9)覯*þ9­-t$ öÜ‘€âÀAèvn!xm:îÆ7ù˜‘ð÷Þ©¥°ùWm�柭«éÈ«¸œ�Ψnðê›k7$UŸd6H@ì�Ò•¤ÊÖ”©)¹ô�ɵUùx‰u¾=ö–r»—c)BPg•´²«Îâp}ŒŠ"mCjcHJÜ×Ê}-ÜÅôûÊý¾òØ*[1 ¬ª{xcÌžfó$Æ@ïÆŠo> z$�b$§C樶Foe LZâ4&5:àáZÈÉÍ«ïC ¶›EöÏlë®3í½p¢œYè=î 嘋o¦ÈHñ(hmŒã1G+¤ì_ê¹øQ:@9;ÜX#¼x!¦->4@÷=5Dl¬¶>ê NŒ½'%‰³CÆ“� ËÒyº&þîÿöÞìÉ’$;ïûw�ˆ{ofíU½Í f’ AÂB\Ì./’™Ìô¤¿Bú�ô"Ó«ô@J€ \‚Ä@Í –ôÌt÷tÏôR]KVeæ½î~ôpŽ{DVOÃÈÉLb´egVæ½q#<Ü�Ÿå;ßwŸ×^¿ÍÓçW<»¸âùóK.ž_RòD­R+A+x×D›S·nŸñ•/½ÅÃg Ãå9—§ÙßUÎÏ`gRœIÌ”;�ðpÇþv$îŒÛ¶RPY�hÁâvµ˜˜WY”:åŽd<™!¶‘4Þ8Ï ¬FØ,}]“ÈmÓjh… ¾‰†›„Ñ}¿m…³�“Üù�s ´$TûLG?ö§K?i·ÃÝOhÎqsÚ—Œú=ôäÞöÿ«]·¸9\ðB¯…èsÑ“a5#FMbÈ€Wl?æ(B&¼m�À’+§ÓÈìA8ªö‡ÝÀ4FGº¨w ÁÅÚ¬Xc?I†YŽÊ¸À’­À™b²døS�”�aíñ„³SµQ`[oÈß샆œ”MaÀÇ]é(X ‘(Ê„$JÐ åäâÍÆÛ?‰˜”8$⨤⨄dª0,ã¸Î 5JdØ%;ãk>ì2º4–PXB˜ØíBçUÔbÔCŒŒÑxuE+9Á•\‚!¾ÉžÃñbÝ�Ø&‡=·Î÷ì]›+š u^˜³0 ;Fe ‘戜"s±b@Ó(£Ds‡P› íè0¡QÜt[wýÒzâ±Íݦ/ƒÛá¢ÊÅŧ|úøž<~ŸO?ý€'Ï~LÎMÛä?îp§~<ˆ‘�~’*p?FFž—ʵš.σ˜xZ‹þ‚CµryõŒË«g|üÊßBÜ>À�;¯qÿÎk<|ð÷ï½Î0Œ´‚ÖO�µšµ×n£z\&†šïíÕꔪ!CEªû;nû·¶A6ô›•â÷’øøÂ]ÿ/KÎ<¹¸àÉÅß}ïýŸúšû·ÏøÒë÷¹ëŒÃ8p{¿ç0íØŸÝ1À™¸–YHÆ¥ŽQ>jXº˜%á-öRÁó5RZR³�yеð‡jÙ=ëpê I@ìA±Ù„Œ–#9[b}ÉÙ©:­«ÚèhÒ01ŽÃFË‹u]bsÁb6‡µŽ¬»'¥Á„†÷D*ó| 5B.…2�>I‹°ä™Ó|r@Pè"î­ÓÇhX tUj6Áâef^ަ½ Ê8’Œ cdšF/௅‹œ %g–%3ŸNÔjB¸vTKNx¤ÑkYüc«¦û(`0M¼LQny¥~Sµç‘ó‰R*1LĨ ÉŠ^ü¬ž7pÔz ‰qÜ“âh´ƒU\ëÁ(DªT£ŽŠÎ!­ ­ÂÕ呼TNã‚1˜M‡‘fK‚kUÔb×¹,3§ùÈ8_#2š}õØÓÀYε>ŒÌ'»GrFXȋ͛A#! ŒÃ�Ãþ6¥T®¯/YfåÅ‹+Ž×Îï_…š­Hy˜"»ÉbÉq<ãpvŸÛw1M¯ƒ>¤‘//®yúä—Ï?áêbáôâÈòòH9]Së‰ýÙÈáþ9Ã4pµ\qZަ ryrJÅ€¤HH m2…š`$�B¤H²X¶šVI¬Ž–ï1@+ ´Ûójq´vDvImÁ�‚°víYE³‘•’ÈtFY8D£lv‘aLÏ!š&†xç°V5YCzS Œ2´îyûn×Ú5 bZp‚1 ¾Ez¬Ñ4Ó Yçñ𠆏Ž�ºÃvU+ª´B¶5~Šñ|Ç­G÷˜Î"ao… 0À˜‘!!Ù|ê4 ì\§aÊ,(!âwi?!ã5Lì/'n½œ8܆³Û0ŸöÌÇ3D,¯c,¥û3Ã81íöŒã�4î©8�Lp÷ q2?G˜3RË(œ�í8&†1šoP*Ö!®iP5€xϺ†•�f-•RÔ¯­Ã®ãž×î—Ò.Å@pǹ˜F-`lcKi`ÏÚã’âöW<ßæõgç€Xa ]�¨qõív‚!�Óɨñ¥oø–ËPZ+UÛ ñÄRŒ�!X•¥ˆYÌ¡êq†­fT6¸Ç jÇx”Ñ|JIÛhÖɤA<‚nغèu³ø·_kK}bu�íQBP¸è-'¢Žˆ¦'ç-‰'¾©xA¤'òÔ7¡êHVÿ¬<ùÂlvK<¨iø-ÑêÅÛPz*Ïï«`�P€î€Õ¬BÖx~ÞØ¸nݺժ&UÌ,.…˜si�´ÀÎA­uZÔd¿‹Ý³!['æ´ú 4.5O8Ò“^æ‹4!k™¢£f[ã|»nKÚ[ëx”ñ`8x×OµùÌ·ç¹²¶ÁÚ�›@"­�{Ûf£FZiÆ´A”!fbCc‰ÂBbáÖ-åþÃ�o|ã-þò/}™ï½ý.ß{û]./_rùò%¢·Iñ.H 4 ±´bTåÎí?÷s_âç~ö‹Ü»)õ)ß÷¹Ì³ÛUà%!Ì ã‰Ã-%>Ø1�3z\È:Så„„F„oëGK5é\©K‚³UÙ–Ö:Û)•À9HÖŠ�à}ãt»í¥ IÆ€UèÄ6Ûıo²µ;´™ÍZlmNH{•¢ÌˆlÒEÍûi†|=Ÿô_´_º­ ñèâŸý^„Ž£›sÚÖVŒ"Í RJÛ|-D¢ä�ÃçÎbLÆÀ$‘G$$�DΕÓqæ4Ï,‹!צad’u;9w¬ªGã!&’#L0"J”qPNII±’bôÂ@e…¬©'ÆŒþÌ9=ˆ±¤¾ïY�ë>·0Ð i }/>ÔºX !AI¡’DˆªHYÐ|4½ L1²ßEÒi+ Š †jm`I-iE'1J§1†ƒ²ê´°\–묦3íFî„}/ ä9“çlÁ\H½Ó®da‰0çÀ’OäÒº•aHŒ»�³ý޳³=çç{ö‡=uQòÉŠùxb.ÆS~ŒÊ˜¼µ²*ñ” œrè¬ ¥ ¹Jך.ÞOHÞ6íˆOç¥/Å âDñ9)¨ôuS ò#Þÿàûüø'?äñ§8ÍÄ_|œ‡À•*÷Sâ ià¯M;r ìSä~ЫcŠ|éög1òýg/¸Î…_{í>)N¥ò“«k¾|vàñiæ0D޵2„ÀŸ={ÁR+ãnä¢òœ)µò�VÞ�O|º%ÑûËü™ëªµòìâž]|»?úc[Ž"ܾõ€GÞâõG?ÃÞø*‡Ýù�À§-ho45Ó侟ˆÅ’{8æ»%smöš–@[ë[°U§ò�tûæˆé[‡xK)d~ayõ¢€‹}®]"n~ P+ DÓõé�&ëçV/.”¶†Ý~uäÐf\k법HamY6«ºÒM©‘ZK§E?§¸ª�D´ƒk¬8`ˆ‚VØšýV Éý+øH«È¯ õ¯wµµÓlã GÏÎæ~:ç…E •‚DC_5ª³ê�Œ`@utv Ô´&nÚßK¶G­ tX�‹jÕ`¶uH‰i´Â€–À\•\Vÿ\±8¦�ɺ®×ä ††¾–í3Wµý»%¬Èa]”ÞÛ«jv8”v�-�p{ý»ú|ö=u�ø|úé5ßüƒøƒ?ø€o~ó}¾ó��øàƒç¯.¼Ï=FÎCà �;1òZLÜK‰] “¬EæÔâ‰ÍÚý¼ÔAÁŠ ‹*'U®´rU+—µò¼>*™‹R¸¬¢yõxrqÉ“‹ËÏü>†À½Ûw¸÷.÷îÞãÁƒ‡ çõ-EHjT^!$ë�„È€ñßob«œÉó‰ãõK.//MôµyK"Ä”SdÚMÆ�?˜vH3M6vµûìU×g¼À—HÔ2RËõŽF‹Ù Em®J*ÍT÷Ó—Åhå•Gíz·OüÔb:¹,,ùIJ)e6¿ HHŒ“é>´÷´k�O 3p:¹¾¾ê…uÏî˜@¢TBó±4ôû ½@жT+6Ôª®›¶˜Æ ¹ˆuò–²�R%©8ÅS1`“wð¬þ«˜f\ìšýÜÁ�«@­Â8š–Q©‰ZN§—WW\Ç#Cò9 �q2ÐAˆ�¢…e ¤EÉTjÉd�9�®Ç‘qL )¹Í7¿U$ÃÀ0TDŽÎ?]‹««û�AÆaÏaÇD"O•ùtÅÅ|�ê•(ªí†)êÙ ;RJL»=çç�¸wÿ‹ìö�P¢2 !pñâÞýÁûüäGòø'O(§…Ý0p˜‡=ìnYaàöÝsæåŠùxÉÓ'/xú$PªÅÄaH„a k cÀ±¢Õ¸¾c J¤h¢bs4ª�þB[cn‡Í~­±fË'˜k+žKm5/œcE&œÎ«½ð„}±DÊ V,±®w…q2*'K8 RA³ç²ºëþEõsð}«é»H]³J!x7{Xã  'AGˆ4KÙzê:XÉ^é:<79*ÏeHe<Ûqëá=óÃS·+d´ß�Å´õJ%LJT%ŒJ”B‚¦óÄp˜`€á@=î)×gœßnß äe&Ï31Z÷f-ÙìÞ’Y–…4ŒìöbQI,N'+Rì§A–“ІÁu Ã�»q`7&¤ïo—äeFKñî”��K]FÓµ›¢Åƒ®�æX˜aU/7¤v©kþ49…‹ š°IŒ¹Aöç_êÚظÁõÛ€ÃÅ‹ø[›�kñqÛ»›¯¹Î èü)x'›9Ÿ—äÿ¼öó~ÿŸr´Ñù¼�ü/Úáa�å_uü^ý®ŸóÚÕŸ ›¼ÁšK(lž -jgðÜjû À`±›ùS‰qI°LŒ;Ó™O&P¬Õ:èJ�œ ×Wpy¸öfÐÚ�b¡T×ãK„ÁhlKMújeL�ÄhÓ“ûŒö\Är`m­‹Ó#¸L;(Níjš´c®ôhP\ëFÜ—Ñ .7iì&k¾ÅAÝY™gåt*,E8-&8œ«æÒyª>jŸ ­¸Õü-'½=Ò�,yY\rHÖÒ›b`„2h¡f¡ÛDJ V…)dx@Ýk)E†!õ$°9ÍùÝLDiÈøÆß§ŽŒòDHðÀ¥eImš8xÖ6•ÆÕXÝA‚5I«Õ%†¬(Dý«óß6 <}"± ¾_¯(´çèzxáȈ&j‘” Úˆ üP½¡IÒhŒ¶b}âÿS]ÏUÂÞaÖÁ+>†Š·�\pt;X [×[ÄÄ)â¼³Õ µ¬ªÔ�×·!ÿŠªç o¶›WLã¡Êú½´ûpþÀ¨Õ¹•T[GÀj¤"\ £^ÌY¨-´Ž‡Þ–_+KɶDz{®]OŒÞ Š9!¦À­yk|\p}Z¸>ÎçÌq.O™S.&z©îìaˆ]ËB¶Ëm¢˜ø†ãsÀ«’H+ĸ2yŸ#-¨/J5TdØì#âŸê{XRœKÀ¶¢Z­›&øõ xW޶ö$ú˜lÍ¾Í ß+¬ÂÑ+â°q–6ãmI2¥ïR+0™Ú»ÍC íùÉÍêsÞÄZŒR§l¶%EûÜÆ‘M«Ì{`Õ G"Ê~¸gäÎ!±Î�ÏÈñú)¯½±çÍ/øâWïòÆWÎyv:ðôrâÓ'®©e@õ@`@nØ!‹€—RxyyÅ‹——œŸ†Äí³[L:³§¼ÊÔ2s=¿äùõSîݾÍîÖÈéêÈ‹ù%§ZÐdè‡�,± !0ÄÀ ÞÚZ0þsœ~¡`N¦®C¦(«%Ãj›k÷…=Èܦ‘9 Å•ì}ÎÒÚ`·{µ;®Û£Ù±›‡²º2khí¬?uCi¡Ûú�žl’õý7„W=û îlYËW¢#Œ°´}1øœ@l^-e^íð€¡úk0TSuà�DB4^a‘h¿[Ã2’ó„ÖÒéÓRbÄ�@$�˜ør‚Œ¨ Q6±ÇJaJ#u A»À[[«/éÅâÚlýVÔÍ—ô„Õ†J¨o9^8Žf3lJŸ/­ 5Cý“zçUt- ¢¢ÞÚLTR&1j'çT¥;Ú±&»ö°­\LäѦe“£%ö—"ä©TB„a˜v#»ýžÝ~bLN ‰ÚM›ß? ‰sI½�’Éšˆ‹qÙ.Ÿ;m/©j¢ªÚµ½ÀšË‚:_¥Š¸½^Uá“O~Âû?þïð~òá»,ù³ öíñóÓŽ¯Ž#!E¾8M<$p:-üíG÷y4�<�þÍÇŸò—ÎÏùùÛç¨*o§Kn‰;ÓÈ‹%ó÷^{@UåÅ’ùOžòË÷îðWîÞæñiæ�Ÿ]ðú~âWÜC�?©Œ"üý»w"<›OüWg{~øòŠ×¦‰Ûcâǧ™?yzAø…�\,™÷æ™kÝ$ˆUy~ñ˜ç�yû‡ßàþÝ×xë�¯ñ…7¿Æ¯ý I¢¡µ}C߆AF³"=l–f#6;ŸÙ­¶‚èÖ˜ÉÆf¶�v-Ì«wå8¼Õ×�nj‡^ì�•X[á½_CÃz¢+F§ ôÍÉ‹?ÕísÅØ’¶{ß�[6}ÿ±¢Á+¨´ú;B÷CZ: wäé¹å¦)ÔP–­@ÐìkßSúXúXaû¼ÙOÛz7'ÚËÁë^ívÑ_Ð}·€®à”žÅP[85I&Su!¢äšP†AØíbIGb«¯1ërT¿¯†°ö¢]�»Qˆö¤«øs îKá�™ÕÎIŒ/‚u¬«u3¬[ÉÞ/ÆahÌWxkÂ&X…Vx^©úŒÞ|>xåÁto|k&4«mêÝ*&¬÷­o}Ä7¿ù>ÿÇ|À7¿ùþö“Ï̧í1‰p/Fî‡È‡‘7ÒÀ­E�úqlçŸuá~ÚÑà\#™÷­Ïý§îê\£V4È™-3ŸäÌóWhÔJ­<~ö”ÇÏž? Hàî½{<|øwî<àìì.) =±c+Ê€h!’V¥zòtdšLû3Ò¸sqnÑ” }Pmñ’bÚD¹˜ ß¼ý@4*¯4 ÃÈ8¿vqµC˜ƒ­¡u3Û=µNm›!ŽtjÓ8 2ãD­ %Ns¡r4°R50×âôUTX½0ÐhÄ!—™e9ZÁ½ÎT28)Tcúqè IDATj�¹>^¢º4x‚7¢?—ž¬×¶ö¤e�Û3¹.ˆF‹?¥N×IÐ -¥úu7 IëLm�^-1ú,ëra3¡Ü^©60œÙá*ÅÅT-!¯ºxbD½Rb>�Œù`É,2wГ"–Ô Ù¾R B­™œ�Ìó!îˆÉžcn$$£X¦iÇa¿8A€›–¹0 Ê�Qöì'EKBëÈ4\{œ­=7!ªDöûÁ¨w»ÝH-{^^?ùñ5*OHžtüäÃÇ|ðÞ�?¼äÙã+tYØ ‘ÃNØ_WÂNxóåKnßÚq~¶çÑ£<þäš‹g™«ëÈñè¾´Öš¬=¶¶v¡’Õ,p/з=Ô5¨Ð3!´ø™žîù�Õ¬¸ÝÃr@ÍèZó¯�*m,l�‰"ÞI–˜Æ�ýÙïG¦]%Žž@ú|sV–S±nbŒ©À:Ž-AÝÅÞCûRµ5î™}_й~®QØ)`}Š÷¸ÞRˆx"ä•üÌÆŽ¶¢€­7e¾¼âúâjaÚ Ó@œ¦XËADÂ`›ÞT‘¢(‹ù¤R‘èÅ솤h Þ4�Ä)Z’=âqJœÉÙeʲPòìBô¬CËBžBL ãÔ»ªJ–¬h ¤0¢XN�šÕõ@¬0“bµsGUê©û±!tÜ‹ Á¾·îd©ÿ îëx�² R à#™5W,/I½IoS¼Ù´VpM”n¤µù›êq™¬D:Ë…´×ôÍÑ�¿^ÜObIh6®¬¾nË�7¿oÖÁÍcã=ßð�ÊñÙ Üϰ}ÁJ½ùÜÏÙ䥿âæEo²£¬HƶÑm|sèÎêÚíÛ?ÕŠ;›\‚"ýõf3ý±xôÂ]«¯ûú žû˜HȰgçCZR¥'Üw;ee ™ãqa^Z‡/NËqÄ!`üÈÑ:S œ��1[E`Í=ªºÏÍïÕØ:|}HJ5¦ˆ&–¤ëˆÛÈ΢v­‚ÍÏ® \ëÃóßè†%‹u­ˆUJ%c+°Žø– ®NÑæ×Œj%Ôæ/¯Ã¾Íæ¤Ýh­x' ’·‘˜J=Qs¥–`í;jÅ�y†Ó\6SZ ÅžèNÉÚ»¥äO®™  Û´¢9Õ›BŒ¯l,Nk!Ñ'–Ý•„U‘Òœ‰dÓ¶ó«·€–µMª^éòéI�õéy€» X¥mÒ�û,XÑä ¹­ëûüô-™Û—™_¡kÓ¦ÅnBOÖ×bÈ·vÎÖR'¢Æ^ä çÚžÅ&x%×�HŸsA¶Ä[¬êYE6yÓ•¼åñd½!Y-¹B .ú= &îC”•w] •˜ÒË6êÖ:¼m0!D«î· _û`ù$/¬œ‚ sÎä\,ГȼdNKé…�Ób¼\¹XÅ®ø\D¬=tEpmžg­ë|÷Pã*ÔÜZmÉš‰ß¶ù9‚9ºQÂ�$Ÿ¡ã1´†?GO™ö¾‘v=æ�¯óîÆ— î¦ÔŠFâò•áݬ°úâhE·l­Ù_cZ¡Ø¾Ýt¥ehs«:�V-�R¬ªa ³5Ñô&À¦j:�,ApØ%ÞzmÏ—^¿Íƒ;¯jàíïÎ|üñKÞzë_ùÚ]^ÿÒ-n¿9qÿùÄÃç;ÎÞÂp¢èlÎјÐp«(Âñ´ðñ'O8ìC¸ÇÝ;0 {öÓ=¦aç;HAËÌ‹« >zþ Ãëop÷öžÓ§Ï¹8½$—q" ÁtYb"е¼NŽÎ‹U�ìö«¨;/ëÆÙäê¨dm`‘Ít´(»ÔGŽ&«Ñ)wª†fõ?o«¿±•o^qÓ�ß:øÛß¼úÞÏu^|.¾zæf«V'Àm€w‹ásÕ‡e-vêj¢ªr11µNk TGÓh³ÏѺB‰$±NŒµ¢%£%ÝW;þ„0˜–$ïhé�Yaö 6㡵·¶¬@°„vL ƒ0,ÖþWŠÞ@ÂEOfáë¦øfï Cöoµ„¹œèݵы� U¬A�VD2¦bâÛÔD`4 ެ­Úm_±+s¨% !5ÄBKˆyQsˆ°·Bb¢¥2Œ]k3H”“ézh†@ôÿj.dQJHÔȃ‰MVÑ ÄdmÐã42Œilþëb¶1(CTvC›RJš†éÀqÉ\gŠsIˆ˜0“'mLôkH¨$ªµâÅÁ¨ãLH>øñÛ¼ýÃïðÃwþ”Ë«‹Ï�æ»øonßå#�;þò~Ï;Ï_r¹dþÉ^G€Ë%óç//¹•"Ïç…} ü£71ÅÈŸ<·Î€_yp€ÿðé3>¸>òo>b#‹.KáwÇ�¯ŸxëlÏÇÇ/rá¾ñxûâ%ß½xɯ<¸ËÏÝ>罫k¾ÿâ’«\ø›»»|ašx?EîŽÿäö-žÎ3»y²,|4Ï|xuä‡eáß]¾ä£å&Ò“góäÙÇ|çÏ~ŸÞ|ýË|õË¿Ä׿˜¦ý kp3,ñ5.&Ûèö-æ°é0GZˆ}ïWߓ̴ÍS‘FÛâ>Yïþ„•¶}ÝÔXmU`oÂÃÒ À Ûèñ Ú´uCjOnÓ|­>¥µš† kGJ;/êAà {©ëÿÅÆ°(">¦zA¥ïÇÛ‴N]pԃα ü¶Ý®j5¿¿ ‹¦†à…F­Uœ{5[QRO,‚ù¡DÒØ&µbù¼Yæ¢^ ð‹ ^ 5¥nv÷YØ"âúâ…S-ÅBÎ`~Z’H ƒÓ˜0½u gŠd÷57cÒ:jï&êƒÓœt/lÛ—û°½zãs­ÿ›Ò¦Z.©Tå›ÿç�ùÍÿý‡üö¿x—?üù¾Îü´cáõ˜xsøby#gÒ°¨?åø ¶âÿǵýèá<$¾0&þƸ¬�R€+”�ÊÂw�G¾?Ÿ8mÖcÕÊ“'Ÿòäɧýw»Ý�{wqÿþk<¼÷Ó8yñ?0Œ ‰Š’ ŒìögìÏnCœ bÞá�½ˆ³‰žz"¾”u/Ž’LpsÜ3MiœH.¼i"„Ëh¨ÚèTumÝû½Ôìñ¨ $Ä¿‚ Ä0�JN§BÑ#!gGÚšˆ½‰Ð¯¶Äè“ Œ‡Dr5ú Ö) dÓóÂ@Î ——™ãÑüÓ(ö+¥‰©*¹Ìw³ d:hHÀ¸æ3K^�`�ÇMZ-2ÏÚ×mëÌjÀµNÍáqt£Ôj¾HŒ˧¸*(uª"ÿ·A-6ª¹,T](:;M‘ùBÝ&b¶9/ ¥Ä»èE¬Ã;ÕĨÛÌÏhñW%çó|MfÒPŒµ3$ t;…Í~gÉäyöØSa™3y¨Ô!‡‘ý8eO {–ÃLŒ¾V£.lÅ�íÙìw#»ib™'ž<^¸>=ãÃÇÏ)h-¼¼xγO_pù|æúE…R¹N™«cffÂX¹xú”ûwv;>|ÈÃ×<2Xȧ…N]›‹�RØ�ƒbºMÞ ÷«´ˆí„!D/ÀÚ\1Úε㤣«Á~nº*^ÐP©®?XŒR8X·ù…ýÙM6ûÝÀþPw&HM°}¶TµŽŒZˆ.xš ±­p _¨–tŒÚÑéÒ ë‹�¥R©¡�(פ]ôylù`÷UŠƒWÖ8§úæÞ$óaÄ�×/^rùôR ûýŽ4xgY#£z ÞÝÇ-Y^댄J…8DÂ!'ÿ0AÚ!aòõZ€ÙbÄQØ¥‰te™©yfˆÂà 2 BÍ u^0%YgaH  Õౄ’—Jž#ZaH#CLÄdû¯”jYÙ9Ôlªžô¸x¼"ˆÓÉ` u+”—5‡PC[íf7T T!”`Å€ºæ,¯[½(°Õ¶ë×R}­Uš–gó5»é«�9Ùï=(óóHƒm¹kØüËËùþÕ‹²^ã«›cïŒoÏ^�‡ÿÕÈ|ëœm£øí{·{õïÛsÕÍÏÛã• ì×µ‚Fo¼®u“u§Ô_Ó÷¼°îU›"�´·ö«Øf¶÷Ú´5uÓ�¡8ˆÑûÄÝÎ ™ÑæˆÓ8×\8�…±&”«(œfÏ´4_-XQ èŒA¨‹Pe&Lï¥M­ÚóŠ}•��jñŽçb{M]ªBËýÆþ3@-°¨H?hÇÛ`Ù˜T ÈÅ(ò@Œ*µÚïš±1ŸhÏqUŒQÀÅr³0°õOR"!zâ8Fã`F¬¥¢ÖŒÖˆ)¿[5¶ª0ÆÀéF¿!«j3FKŽ©–%£Ã(Äh(଴‚Cu>UßTJµ@Â4AœÔ'Ni^»Ï5 êÍš˜úkZ¥·µ®Ûï6óö•ÑþÖÖÃ�¢šØ¢_t{®€y%²o—뇩_s›!íÇ5ÚÙ-#Ö’­]Á*àÕ*lf+Î$s#È´?·d”:…Ì&LoëÛ[üÀöK¼Ú{sxZ ¶PT�Èô‰gíŠN“Š#qKð³ø°Xc†nœ–FP/*@w1„~Míùö‹kÃm6*wn[§9sZ2ÇÓÂõ\¬õ¦¸cItGF“YVÅâêIuuàvíã`Z‚¸xQ�ÝaÊÅ߯ÐÚ�[‘` ä7Ádhé ¶ãÛ7(sr=8VŸ‡m¨wøÙ¬kΦ5QÐÞo޼nâÛ¨Ú vK˜äb''wx[Ñç~;oçknsOºATÅ;l¼¶B7¦˜�SC?!f$û‘»·Î¸wûœÛ‡=åd”Ve™�£´ž�TÂý7ÎùJ}ƒýè9»³`Afnš.ÈR*¸q?-Ê'Ÿ^•ãÕsÜ‹œŸÏܾ¯Ÿ_qu€a¯H »‰Ý­sÒ4‚ó1f5qYCÄ[»#Ñ“¾bSs±1³¢îPlŸ¿7¦­™_¬7Z”âO©TC´´‚©VÖ2T;±�mÀ×›^�Ö…°ýKÛ¢7?õé¹Ù˜}ýõÚÐ�woŽLðê÷?Üò,mÞIû‡wpÝð™‚#HÛü�>É-ímÛõÔM®ÛÜö'µ+05÷èR0Ö"Þö(kg•é¢Ú¨Ì°Ÿ‰¸Ž‹ñF_·�)‰%vÁåÔ|Ý5G¤”ko…£Âçá Ä(=ùŶ‰’�ËP"Tˆ~ĺ̌J¨ÕhÚþåV„¢»¾?5Õ–†ªq(3øƒÍ‚4 « T òU’±kR!"Ô Ñö¡ D�ÄQ©^Œ Sb!™ ^72¾aLç#çr`,°+�¦=iw`œâu e®æ`-‹wE „"†|ÿ*½íΓu–ˆTrɼóÞŸòýü_üà�ïp<]ñÓŽG)ñ_ŸßeõÎm~v·ãÏž¿àÞ4ñÆnäe)üêÃ{”ª<›¾wñ’_¸s‹_¾w‡«\ø��?åÍýŽ¿é…€'§ù†FÀWn�q6$ÆxçåovüÓ·^#†À¿øðö1òk�îð[Ÿ|Ì©V¾°ŸØÅh]+12Hàù¼poø+÷nóúnâ�ž>g©•_táß~ò„OO3¿úà._9ìYráãªüã[wøï¾ôE>š¾õü‚?��|ûêŠï�}�ÉeáG?~›ýøm~ïþ_ùÒ/ðK?ÿ«¼õÆW}±…n/¶_ú9?÷£��¸̰yÍ+ ‡î_akÛ;ZÑ þ£Ù˜n[~Ja qÝÙ[ -tY-¾¯ù>§ê¨³µ8 7Þ¸"ÉÚï¥ßÓêS~ÖG]ˆë^¾‚V¿Âº ZÁÅ|õõ,NWf÷$b(z –†0Û`çl>Åz?îù4 �îp8…O£ ¬˜ŽN—ƒš p ýÞR4}¡R#% 5ã]¾µ�…¹L¶6mƒFE¹úÚÐ�صcv®©V,AÜßÜ<Ëö\š­î[nýi°qìÝ$[‰]S{~ŠÙ¾¦ó/‹q|/•wÞÆoýëwù­õÿâ_½Ë³çŸ¥DxoÄÄצ‰7âÀô™Wý㨞˜9¾¾v�Ã-B Uù°,|ëxÍ÷6öàx¼â'¾ËO>|£:»ÏÃûoðèþ[Ü>`Ýuq"¤!F/Z-~2êÒ5v¸±6U±Žž�aØq8˜_�¢u LÓŽa´‚€h`>eNZ†‘4ŒrÚ´ÿ¯:]T¨Åã75Š� 1)à İ8U ýŠ #-®¶ä¢�—Ì u�ó`@ ë¼·Nºý~O­Ò�­¾Æk±,p @°‰¼än¯Š‹9ìl�›"HQB�—A,ah@µÒéÓÌê›]nŒ"�štM wð›5›k‚êþ+à‹;t1¶*¦SÊ–…RNä|4=Ÿ£ýï_晀2¤H,)B@5s}¼$Ì'h]EѨ‹C(Õ¹Ñ/‰Ã-Ò0FO~{‘™f3C£»m�N�—…eΔ©Q>�N3›Êb¨W©hͨænW›=*%qe.O…ti]µÌfщa‡H±„àˆrÉq |üø%»Ý3îÞ¹KÎyðà æãˆÈN§g¨ T‰Gtã M³©Ñ;�,!n(v$™^lmu§^dk‰0ëÎQ)(¥f[®£³´"§Ç‘B 1V†Ó�8ì‡}b¿˜¦‘!m ɪ,yáª.FK˜*£çŠsz¯Û¸Ul%¶Ž=õk•5ˆ¦™}{Õ‹ Úb6kŸ0‘â°ú Òò6þ\C÷i ØÐ: j®\¿¸âòÙ BUÎ÷;ÆaC‰êEiÁ—LÉæ‡(’-H�¤ÈÞ(S‰# ĤWtt·ZWaGB4 ) ©å|ƒPK@KÓƒò®*ÿB“±†d%åJ]¬(c"9�˜ž˜µç"›dz X¡°Ñ*z�ÜŠN[ÒãbV_mëþ�,Hzøt®›Í>Ý}mUVT‰]ãêjI·1ªuªVèíw­]Q¬P»‹ÛÈú54^MŸÚ ãÖ¯?§lÿÝ|íE5;l¾ê�y±ñ[oÄÞ†¼o¯Ü‚’W?ûf¼.ýì›—µ�—ÍŽ˜Ž–¬×êâ]Z Z‹œVÈ)P†ÆÃ:gXôê‰!¨ qqŠöÀ‡QHÉPýa7þ†èK:WSX^ KqÁpÚàX›HEmC�ÜOXíúš¤lmR­0ps%¬Ná«ÁÞ„©·úDê+f]´µêùºðؼ\nð±&ÂX?ÇNUo~±NHÀ‘íF›Á[“Ãk«›£§*>®¬T¬¯Y�–!P×¶©v�7‹UÁIu ]*¹H¯ì êŒJ æ×Ð(Ö%GÏW¢í›!ïci„îb°ªaø�ªnžï6)½:¢v™öüOsæ4N‹ñs5Ñm¥A²íÌÆ7j¶\s/¤¨ß“M3+XÝÇôä@»žR]ôC[ Ú…óÄBõÏ\{oŽ»q¨¶g|nûãoÏüºéBÒͨX‘oIlqnoáòÀÛ¦‘nÎg?Ísá8ÏÖV=çŽxn�26)Z Þ’ `-¹ÐF­C=E2Ü·£ºnT6/ƒ‰¬FCîîw;ÎööãE™¯O/O\½¼æÅ<Çù2Àý×îp~kÇŸ÷cÎn%t�¥©¼‹xÑçN8-ðøÉ ._¾àñ‡…w_þò91ž1~|A’#ç¯Øß�8ܺÃ7‡ÝæÅP%!ZÇLq>øÐ�›-9º>&–®Þ¾*^ÝØ_‡Äú1›VDsDkséÉž&œ×懡ãmØ%FßG7…ÈöÚî;uC·~—­mh‡Öqkl?{ÈÍn¶úgYmé«×çGWw7|�œ«ÍL(¬ñ:¦µH¬þZiX¿’ºùQ!Að6ßø˜�6t‘ v-5[W@®™*Ù FC0}‚1‘–ÂR R‹S’šÝðZOŽP(µRKÄôÜRqnÖ8†1tʳEjH)”`�w¢�–L‰ÚÚï‹wÎ%Jl>¹-2”¶£hÌ‹°K»éc²¢úÜYŽÕŠ“o¾EWý g½‹bÈ Í}¢YKwJÍŠˆ„Ñ Gm¤!Ccts7v�)M û�¬BVAÒH&Òœ�ëÀ"™¹$æ“û¢�ÚΤáVÊð¶>üè]þð;¿ËŸýùp:]fZ'à7nÝá û‰_>?çN¥rˆ�÷®®ùáË+~ñîm¾óü?|qÉ?xã!·Râò˜y|üä å)Ê9ïÝåÁƒcºÇ鹸8¡˜Ž@\ ²€æJ^ŠñmcÔ/1ø3&Þð—*5x±¹8…›ekM ÅëØ¦'†¥�C0Äo‹uQL¼×œM[.°›"gûÀÙ!±Û ŒCB´PнQ0‹¹Ñc¼­ë¢h¦”lÅo[÷Á(5BÔÕíðâWOt¶ØÈƒfÓÚóüH±ÄzŒ£ÑŽv^y@‹w!؉­/)ÙEé)Káêå‘—Ï_r8œq¶- ø¼Z3~Ä/&BÂ9*î‹ÇÏš—ÚKa¹G#2H“³¤|ÓªC�ê¨6‡dÛªî`3¢�|ªûõjëÝlua�­¼ØdÚlâ"ìs�6·9gÒ“¬[ß‹^ ûû‹xa@nƱ=i¿æÍºË×’–ãòg)[_¢½ÃoÙ8‹‚;Ž>QzaÁ‹8Íqh€¾êsÀCÌ®ºãÓ}>i‰¥N×(ë½tÇpÀ4OX6¨¼mTm¿iÞu½ñÁ²ùËz¼úïW/’Íß­ªpã&¶~Ð�™»}íæ3ZÁ¼_íçëÕ†þPÚ9tsêö³â\»PM3ÂØ´»8;@ž#¹fë`@iJ¤q 1 Ô“POÂr©ä«Ù(Éœ±Äò. õ+2`„!S€³a‰ä�-GTÔíÚîÈ|ÔõƬ±ÙšËtº –ØWÛw‹ZÈmº•Å©Ò[×@Ñj,(ÐÙ§›Z¥AVÀÒvj&ñdfLëÞøØ�À^­ß¾ÕÚˆíPËšh!“óÀGñj¼z{cD�41õ†€uâø[kuè ìÓ˜—HVãnâ�ó¢O–x©Ù…™¼�¨ûíÛp²%�ûã° ÔPÒ-@k—²Nåõ½ö7Ÿà݈Tz€7_»™ÎëÿýíôgÒ�ºý ?S²îO´ÙŠöw]?©íÒÍQjm(ÁŒ-y¾"à7í&±ëGPµÀj›ðkA’@£úm Z…Äm§zžÙ¾GíÈŽ›èäŠsë{§‘øâîÏÊQQ±6X•®CÐÇ]ñ¶_o{ltH›€Ï@ʜ˦²fsÊ�s •èE.é‰sãîÚ$ÙÕ®³b{]PíNÖ9@CÚ5ޝj_mÚÁz!¾‚ˆ‰½U}ª†Viªë8¶D{ã:ó™îsÑ�añ¦H^ÊÊ«¦m—O!ªu U ýÛ×�'œK…œ+9×N+Ô„ [¸•M-Xª; ê‰Gs K.Å;–Ú±=û!h ñ}–\yöô’˜g†zÅéræåʼn2®_f.ž_1_[¢~"cÚs÷Þ9�^¿�fx~*Ô² Z,)£gL¤æ˜3eÎä«2ö i¸æ˜§fÎý IDAT2òæù›Þbw~)gF®Ÿ_’O™ É'éHk¯,}SWCC»@cQ¥ñãY¡»n †¡�¯ÒPR <]RÍÁÝÚ-ÕœÒ"îˆ5GÍ_û™­·y+Ý€õ¯n·m=¯Ø°­ |å¬7v™æšÉg^µbš¦—›ï´ ñÆÛZ ¸@4g²ëØÇÕaÂ?i½8¿îÎaiÏ£éÛÖÞZˆ ©`�6'PŠ.¤1w‘šËR8_vnÏD !»óéíÇÚÑÓîÐyb0g£^5ŽÍÖWj°¢úØh;’‹¬a�|T £Ô[ï-ĬDµÖîa¬’4&%¤Who>Ç@Èú½=‡>ª¢†ŒiÕŽ*†žª9ÀbÅ)B%$ÐG|KÀ­>Pµ=~ü¯Q„¿yvίïü­{wxsšXªòÛ?ù˜”+¿pç?¾>�*_¿eɤ/vìBà,&>9ž¸5üÓ/¼Ná÷?yÂÙ�ø+^Dø7ÊÓyáÑ[¯3aLmáÃiä—îÞâõÝŽ÷.¯˜«òëÞ)ðÇÏ_ðƒ—üú£û|á°çí—|x}äÃg-Ó ã%t}¶ 謞@hETß™»c¿v{ÚïEVßo]Zkqà3—ysDzÁ½uþ5]!iç¹q’}´ý­ÔOhiF(Ä1D)�†HÊÕÀ .`üÏ¢ôKt*3£õQIú0r³i€Ý80&úZ« Ã)…\‹'[·�‰>‡ÈF7Êü[¼ó±?Ôf"Ô|öÒ ¾¶¦`V–ö¢©¨cn¬à]šPRß'¬0l/uµí| }¸ÚµFó0Ï ÿìwÞãúÍïòÏ÷‡\oÒàÍ4ðÕaäç§w%ðŸ�¿ø¨ª�•ûÿ`:ðûs4 ïÎ3¿{õ’Ï«ÎËñtÅ{ü)ï}ð§LÓ�7_ÿK¼ñÖ/òèÑÏ9`C;%_�µü¼Ë5¸˜©S‹¨2q'£‘aqí,ežg†a¤NÎ]íɘVK²uºÚÅ@ ŽRO.(œ;Í_‘•âk^|M8Me´¤Ý�¢¤*ób”™1ư#%£ÇZæ™y91Ë‘RÌw‰Aó%j äj]œ¢Ô“þ$„`t2••j¥QDˆõFZ¼Òb—Y­¾2B"¥‰q2Ä@Α¥#�}Y§d­B6Í&ÖŽS€†ÐŠf÷åR™½k8ç#¹œ¨õdIŸ¢P�¢&%b°B¢uSÎËÉ„(ƒiF˜_H!!A©u¦hátºD^>%ç�Ó�Èy&/3µd׆0×"1%4WjÎ.}ÝŸŸQÃØø-KfÉGj=¡db4;¥¥:�3Ô,èQu:Ý–¸Ðd„0Ò@L†ö.¥²èÀRF楒ËÌñøœù4ñäîB¨�|*\]_ƒ#aC¨ì’§€^æº8Íâ`]¹�UGc‰ªÓ¿Ù^b‚žë‰$/ ¯Ý£â{H�êTt.â©ÙèÝ"Ñ…(™(™Ôtea”!"‚Q/æ’)Ç…ÈLdf ‘’¹Væ¢j±=+ˆwßמ¯l’=L5´¯šŒ`!¤ˆS©�dj0ŸXMjT Q¼èA¨ �…|Y¸|~ÍË‹+ÎöV¢˜³L]É›xñ©ëîÄ]ñ¢€£ÁZìÀšl~”%j°Ø7ú888¨;cÑ�E¡1ˆ¶¼]{ž$wä;hJ=”pûÐþmÍ�]¬¹ûì†EÑþ™² øÚee³ÿºTÈ)ê(ª›ñ«Æ‚ºæH‹üì·)h/tß±}·‘[!>œA{|Þ_ßô¨ëëZ¬ÔƒV\ÕíßÛk¡U+xq w´Ïj¯i麗¡ä¹AËÓo³ùØëÔÞÄîúÊ‹·@ŒÕºá�¶s¶yÒo@è>�Ú ÷Üz8×{ïZÿ±É0l^ôj"!¬¯ÒíK¶Hgí×%Æwfš“Å.IL_o)J¬êàI%�J!$%$E£ )%’CB²i|öXÄ×·‚$A“Ààw/ð$O�—Y]ǧùñ¡ÚWÒ¾ú©¶Ÿmû\—:c Ò�ƒ¹Â’]ϵ®u¸¬îÇRi,!b<7æÈ«S'9g 2à-€69C´Á$Æ&A‰J†œÕhš¸C¶…B5›å› �=fø±n@Œz«�E„¢Åßgí“aW#¹4~ˆÄœá4W^^ΔåD^2%C)x•³º3æE 8×éÖPL-Ѷ®Ó5Sa{œ%óÔQÖ½‚Œrûj­Ý®è�‡k[ƒÂn¿ú¼ö$jm×°­&ˆ·V>×wu¡¬†m]A­µ4„@ô„rãÈ+ÞnÝ®«é1´›owÙ'NX›�à}ª”½l#ư¹N_(˜p°qm©Ñ†Æûh ÅÞ-и@]àªzdK¬µDöRÕ©}šóé´YD µ�×>ʦЖ3g·±8µñoŸà·  ÙuíübÞ6Ù‚ß )vÑÀöÖ{s‡ bçXF�¦«uh¿ßõ¾m³ð¢P/ hßGÁyÏB´Â€˜£ª*›™f¦ŽïRí4� ³ÇmM˜ÃÖwÞ‚Ö’9µT²GªåÄM® L+êíÐ^`¬f®®N¼÷£'|DfÐ,ÊË‹­;N× —Ïæ« §âyåüÖŽ7ßzÄéò%/žœXŠ9]"1%B²Dª­yhªp:-<~üŒ\•ç×pYwœñ.�†�ñì@”Èõ“K.Ÿ¼`¾Z’q$ÈŽ@¢d E+ÉÑ,[2A{Ñ»ÚbëÉy[g*X‘Î×›º]’Ú6oCz™ 5'ªúnÜóÒ¶¾i²Ùoe5Huóùíé‹;+í9ns ^) ¼ºÃô_Kÿÿö «û°E5„õwb‰›v²~ÔæC v[Í! µÛ�›h„�c‡öB$º±§a+†Ú,¡z±Ëiɼƒ©Žl7q.Å·\­@ '©DÔ}ضá„î·µ$"Õ WÁåæ¶N¦èÅ�1väó²T$»Ð¤X@mº-•(‘Av{e¿Æý@š"qpÔ¬1�²;¨¡£€~úCÕÕaM~­jû/KtÄF@R2®ÖT}}…õµýTÞ‘1Y÷GC ¡�³Whý=1@ °C´¢\ˆ  5§Ê~¨\¿X¸¾^¸º^¸¼Ê\ W×p}‚ã?xû{üö¿ûW|ç{ߢ¼"‚ùÕqâÎxx~àïܾM-•ßûøSŸ+vy?svà�ýÄ\+§Zùµ‡÷x|<ñö‹Kþúý»üì­3žœf~ÿñS¾z~àw-1~ª•³ÍtþƽÛ³¨Þ~qÅ[{£ :–Âoþø#¾t¶ç^DøæãKŠÂÏzbwÇ�]Œ|t<ñÖ~ǃiäÖ�øýÇO™Bào=¼‡¿ýá'\åÂß{íçcâً̱N~ÿÇ‘/ìw|élÏ{—W, ¿ñÆ#BþèÉ3>¼>ñk�îó‹wnñíg¼syEþνÛ|càoÄ‘ËÿËÅsÞ9X–ßú“Í÷÷øù¯ÿ íŸ[ç÷z[móÈ6ñYÿá¦Ù2?dk´ÙM�^¤ŒÎjcú~M?ÇÆøöë¸1ß›cÂúµ)6>R+´åÝÌj„Õïl§l´8öúÏ1œ7 Þæ²üó º“ϼWü6d�kñ0J´ š�QÍÄ ŒÉÄÇq"„Dš³Qº�¥Ž>C¨‚}~­è†½�Bˆ !1 �ý4²b°øáä\ĵd릋�(†Š†ÉÅÑ­K÷‰Œ˜M=Ýý|ÔŠà˜­.ŽÆÎ.È¥u3ÛÏ&dX)MΕ­=ßÙ D­+Íæ§%¶ÔŽ…ßþÁ§üÿÛwùó{|òìf·Ñ$Â׆‰¿¶ÛñV>o«üÏÇçÑ×Hñ¸%;_æ%òßžÝaºy®•?<^óû/_ôXãtºâ�÷þˆwÞû#ö‡»|ùË�¯ýïpØ™æÿš¾tAÚ"" Äè_l{¶d¹ÍLË®V/Töu‘QM@ñ.mz—}‡Ëˆë–ˆllÁ€êH-^¤s£JAƒ­ñ MóËlʲT/â­¾ó²³{b…ƒi9ì÷ Êõõ5áx�0QK& ÑhuR°õR9T�”ÿ›½7‹µ­9îû~ÕÝkíéLwþ&J'‰”DRƒ%QEÛ’-Ú`ñC�<ç% �÷~r€ @ÇPŒŒ‚£Dq(‰lɃ"[’5@b(‘’-Š”EJ$?ßpÇsÎÞ{­Õ]y¨ê^ëÜï“�Qž¸�sïö^C¯îêªýë_“4l,„ �õÝ)b½¢5% ±#8C9Hçcf(²ª‘«b€»ËïÄ”†„Œ�a8¶˜¬ïM¢‚j�õæ«‹$Aðjk�;2å‰a§SØ�u3¢‰€K 4b£Å¹rÈe “�²Íç�W<—’Ðiàp¼â0t׉yÉÓH)Ö›ÊÆKX¯Ötý–P ªSÏæþÖèuàúú’ýá’)(:8þê%" 1Õ¥.3ô}O߯èz‹ÝÆ¢”©�ÇÌ~?2ì3ãt‚g:òøñÀ¯Xw¯štœ*Ód ¦£XåêªëØt=…ëa@CGÉÁ[ñ5e×ÕÅ`}<Ôz#äâ€l1²JŠbr±b|yÃàÜž5r}‚ï菱BU!ÅB )NtI,)ÐA Q&‹st´ªƒ2q8\2 WlzØôâ²W‘©öS&8 -ùúÓ`Ø‚FE¢¸TR[žóžïq¡^(E-î(U®U�HmñRAÍçí�(h°8[$¡S¤ì•ñr´ÄÀ³k܇ízE�2þåÍx ¨™ ÷Ùcõl*2¨ýåEj’™ ï©íËÔªvÄŽ[˜#¦&5X“˸iá‹$€–.bD昲TV=h‚ÒÕâbß«½·€§g®2w�ܦ£ÂT,±0:‘¿J )´J��™B• ®>#4 ðö»êlºªó=¶çß0ﲈ?ý¢ y ÔÊÂB1ðÞ«œ*`j;H}h­‚¢%´nÿ‚V'Þ«ê†xc (˜3XåqÜf´Àß5ƒ}³¬•óD²#YõJhãQÜib¥ªæ˜T‹iXÂÂ�ƒ‘‘«ñ!�ô:˜}ÜÊž2Æë‘ã³kâ&’Ö‘‹‹¾ù�¸zxýk¯£Þ Q¢1z¬ÊÉt»éC¤è;!†‰•õnÍîâ”n½ é ²âjØsxvD‡@VHZ!¥‡œÐlAQeŠ„R *‹êC[ÿm­_R7^mÛo3(íÁ8cÇÚ»Y07€¬–ÐkÚ•³ßÓ6ÏEr JDШ­öÀ5·“­f(s“¥ºž¹žûs5)‹›^¾ KÐXÛZ ËÚ7ucLwP`.‰Í-9Ùq9MìºÄ�¿ü€(Âgž<#Šð� «ø­7ñÆa௾ü .�#S)¬bàöªç{ï\°K‰¯¬ªàcîðO/ùü³+>öà.›Ž¯ííøßr²%†ÀIJœwÇRJáûïÞb*ÊÇ�?xòŒÞ:ç]§;¾x½çÓŸðMÛ º}ÎX �ë8æï>ÝqÈ….þðé%ï:ÙòÞÓŠò�¿ò}Ç÷ß½…ªòs_y UåÞªç,& îEèBàé8ñÊvC/mÖüÖ�XÅÈ_zé>E•nRºÓ >qÜóOŸ>1vKžøýÏý&ŸùÃOðîw~'ßóÁ¿ÈéÙÝ`Þwäæo܇’SQ}V{Ymƒ§¡1ø©»^‹Qjr`aSžÕ7»M«ëaù‘ö»9î>¦]_A��ks¾VÍßðÝÞ&1°$”Ô÷-I.­z¡Žs¨æKî¹.ßçÀÊLd"…BŸjƒG Áš–g·�â ú¢V¥”Úšt‰<Ä—¸÷Ãú­D—XéBo,Ü¢äÑtÁKiY°^*ˆ%D�S`¬Ù<ƒ¢7s×þlÝtµàÑ«cÉÄŒ�Tî¯P%é‚ïj�SÑâÓFŽÂ{¢™_�ÝwŸIE \~ú?ÏOþ£ÏòÉ?xýÆ�o%ðm«ß½Þrâ¼g}ãõÿú•ÿ5cCà0eVÀtk>zgËAà_üòåSFÿìþú1ð™Æ|æ—¸ÿ]¼÷}åÝïþABèg,^ F+ÀÛ- ƒPŠ÷ÚšrMß~Çh…£“6_¯V ؾŸðXÔ¡Gu _‘êÍÛk}9„\ç�qé{!ö&‚IWš$©i™Ç¸¦ë¶F‘ê“Q «UOß'—ä™H©ÓDÌ�Ò f©Œ¨<œYÊíÿzD:bèLöG*¡Î·{Œ!ÙçSj¾Y.‘�!ÄB¤âšׄhÇ”`¤ $ºôÙ¢¹z™š]V59!“Qš@3¹˜|Lð1ÌdRŽCÆ*[¢eM§^\B¹Ê!W`TD,VÐÂ0MLÃÈ4™o^“¤9äi$Å* Yè;#„PP=2ŽWŒCbÊ+kN« d¬õÈ”J,-Ò¤(Œ¯@,QTŒ™îqÙ”•Ãqd-Œ‡#‡ýÀ°Ÿ…2¸?VF¢î‰¿‹ÊÙÙ†³³5ëMbµNÖsI2Û¬³pa(…¬Ùd)Ô*4­/�÷O“bÒT::‰N}^ãò@ :!­*mŒc}°lnš¹ú¨t1“B&†‰>ZÂbÝCŸ”­ÂÀö�‘2èt èD;¶«Ž®3)Õ‚%ëb°8©Hi Ãà îÊX·‰ä~j•0ppZïSlއ¨Eó�Ú#ÐÙ‚ŠJÉh*FVuî¡õ ”A8<›¸~(Ìm9|j{€ 7‚¯ª‡W�¯¢”¼H 4pÝ ¿ƒi7Ù©››z~f0°øTÙ�Àd§&êjÖ eW� ß(êJ­ @çs/Yç5(mfp‘xX²ÔQ È,õЀD¡6§1€—Vòø¬ÄÞ¶lkÆwñ|Èêý jUŸœÅ«&ÛZÍ@‡`̱¢Äê2_sÎÚªJ¶¬šU0Øgkïx¿»™�"ío4ÉžâïYµzœÅ¸ �3蛓1³†—ë/Ô…úÜWñ1«ROxX�ƒÚ¬§VHOXâÀuAuög¨•^!SY87V?5G¿¨h%ÎÒö{»p[‡1` ®Aµá�� Ö\ª8À[冱îí¾ã‰¯ô˜(^²l¿3æÐ4M J=a@¼Ä4©²FÙa—Vlúžu:ŽL×ÏÞ|ÌöîŽt²ãöÝSÞóÞÀã7F¾ôÇoRra,SœÆj‰�U—Ø­:Ö zIl×™‹[½—Ö¼ó/ðÊ·ÞewÇÊÈ(°è5äëB”ž.n@:T:KØ4£¯®??ã" 6–/qlføßë{ÛßÍT«…£:%µ*·ç’±Íiª¬�²pHª³Ó¦;MG«Îùê[ˆcçmeK[T/»&3æŸßúZ,ˆ·•8Z$š5ÑêÉÓàó:Tî—Ï'­ÞÒÁ0çÄ>nžÃ}P %ŒËÜ"¸Ù&(äbz±xÓ¯L_zÛ´» œ¤žèR61dR(#Æb˜_!$g¼)ÇÁÅ`ó±>ŽæTçÝ�’ê|G Š3âUrA „H]&uÊ1ù?þÁ/ñ“?ó |õµ7oÜÓ.þüù9¿¸à]kcÊ¿²Y“D¸ž2¿ôµ7xÿÅ)ï>1†þãqâ$Åöùo==á]'–äxí0pwÕññ—�Uù寿Á‹›5ïó¾¿ùÆ#x°Y°v¶a,ÊÝõŠï¿{‹;«žÏÍçÿä_ðmïù^>ôÁ?Ïf}Ú‚™#õh®‹Â¢êåÎ+<ù ^å)�ä¥u›Ž>÷Ò·ýÉÎÛv͘Õ0ü�Ä�½WÝ·°RžÙ/3»^ƒªý«=˜}ºåÿóZJÑš÷ðzGË P(†éh{j(.õÙ­#«ÞäÔr.Hejã™=9�P'¶ùî¦ %û3ªk~N�MH±jÇLaGr9X…äÍ@r) ãDm[òälꙥg~³5�±¤B båÝbv‰¢„l2"Ù@Å ¤\úÐ5 t‘�ÄX`µâQ4[Õ—Âí)çg~ŸŸü¹Ïòär–±Y‹ðþ~Íwo¶7%‚¾‘øÿìÕÇÀ�g¿£Ú¿úK!J=ßç>׿~}Åo^]ú;”×^û#^{í�ø¿?ñ¿ñ¾oýßú­?ÊÉÉ�圩«#Ó8™„f6_z÷ î£O�WLùÀ8B<$LH˜Pæ=OHð|­jÎí—ÇÇ3ÁŸâæ/Ъo,q5yÚýáH�Èj%Í÷ó­Õ}H)ѪtGaš¨]GßoX­:´LLÓH1®I�ï£îNz$—Þea"!¬aEŒkbÜãÊ“)%÷ã­z{÷ƒí>b°ÊZóó©Dr „h±L¿ÚÐõ'¤nKJ+—öñä@óy�œ$1ò\i]Ïi¼v‹Ïsžš“ÝæMö¨¤A#±‹tÞ|R„™ø‡"I]Ga²¯‡r,’ õ% ¶ùë•ðàãp£çÀ¯Vø©Èy5ì@Õ ™Åí}l1b•‹&Dkâ½Xe•º “PF(ƒ¢“ ¦°DÉ6ê}PµkÜòüÕž:ˆî˜R#®.ê› ‚z‹2ßX³ËóÀ×Wª—ÔÏT¶0ù`Æ JÝL øy‚ }Øñü¼7ÕfÍ~ä�‚î™ñÒ®½Ê ”Xã_›Ò¾_Cý³ºø¥¶íêÆÃVšo4ŠJ¼/Ëýyë™"]çѳßÄêžù6Ç®psªÌ6ñÒÐÄûÕ¥Ðb��l¾ÇÞúÙá>cV—ç%’ð¾!Yl�*q¸ ) «’Be¥ÐÐþ˜Ñ˜)!S˜˜ÊÈT"SŽÔ®³LøÔQûÕ×õ,ÁU ŠËÌeŸ‡¸„�'üôZB“ü.¸ü ›žÃ¨ëcP!±ŽóœR� j£ÕBA¢9Ü)´ ¦›€hÙkUù*�b ÆÞ˜7¶è•®7 ƒÔû?Eg=ÖàP¥dA³9ê¢êZtÙ¤ˆ‚9%'¢R„.�™µÛ¸’µhŠÛœ-Å k½¿ºª«Z¢2x¹b™¨æÎ€íì ”9+9÷ èÝ–A=¨Oóf\ê5³kŽ‹1“X<¸Ùˆ—6}|¨GVÌq¨ DiY¡ùëf%Âͪõ`Bq½öjk|c+ž °&1Õ�­².¤0ôfÿ½brB5!€ƒ¦¡‹ê 2³U øxQ²W™Qª¾�bcT–‰�¦Él%è²<¿ÕµºÍ:{׿}JÍ®¥5×­ÕuÃlyú¶Iϱ˭F×ÇÒ7„ºà‹Y,V1¤h³Ú+aœ2Óäs­iªÞSa.A²J‰ªlS³ïuJ—ºÑÛ˜ZâÇ~§õº´2r–FÞçEuÜi­²;ÖÇÂfÕ“‘‚mœevmjÐceÑ‘ opÖÎV7æùÿ*åU²b `ÍØ'¶7›5gÛ@ß$=RŽÃÕ5«ó†“³áÅŽÛw×lwp؃&//M¤«Ù®zv½ÐØ®3§§·N¹÷ Ü{ù´; :�÷}t¤\‰¡£K=…H.Ëdˆ¯OõFÖjs`¹ç:6m´«êI&ÿksØüWା£&jª�¡Þ™FC�QªF¾ˆÏ5—‹kã]ü«þ\­‹'L¥]¿Ÿ³ÚÑšçåíÆf—›h}–Š*½›ë\x6M|ñrÏ{Nw¼ódËÓq⟿ö&ß²Ûð�‹3޹ðǗל¤ÔŽõÎ݆G]¢¨òêõ�›5i½"Šð+¯½ÉY—øðís~îÕ¯¡ ?öÒ}Öœ¸‚ cQÞ¹Û�Dxe»á³O/éDø+¯¼@þù×ßäÉ8ò#îrÖ%>ýð _ß9ï:î¬zV!x%DLJ#øÁûwà3Ožñ¥«k¾ûö÷×+>õè ¯^íùáÍ ÿ΃ü½7Þàç>dïäŠßÿÜoò‡Ÿÿ¾ã?Äw~ࣤÔ/0T[“ o¯„û*3;¼îE5Á¾œ±a^é-èyî¥Ü˜ãKûÝ*dñææEû¹«ßìH]n‹‚6¦ÎsÖúæ…èòn~ßjFµù@•ÈVï¿6æ¼Y1P}ìê#f¢L„PHúج"Ûub»îèSdÊ…±d:ɶW»í�R(RH¨Wh×*ˆzl tÄ+²jï¥Yø¬WŽô¥LˆX"Ï*•)›$`¬þd™Ðl g?¡Vóš]ˆÑ|” µêÍlLÈÅ�Þ¡Ô™bî‹j ‚ÕüpñèÒEK 7ƾïþúï¼Êßþ_~—Ÿý¥/�˼÷}S×ó=ë-ïLß� ú³~Õ¤@¹QIÅc´Åz)@˜ ?Üoø‹›ojáŸ<{ÊGŽÇ+~ïwžñ{ÿ�—_þ ßþíçåw¼ŸÂÈ8í9ì ãHÉ4ßnILš¦Z¦I†‰¢¦u_� Éztk b²˜´&«O¶9m`–qîûç13µ™íèqŽ‘¥fÒ��­Ö·Ì>oq‚i�Ô¤€rõÙ½¢!¦lÄ@ìBî)¬ÜçL–kRÚ�âÚÑ]t�>ƒˆI»¥J…�ˆ¡VpŠë®Wyƒ®ÛXr Û\®hnŠ$¨³CâDºèD‹h•×V™áè[#êYÒ¥P\º!·ëC¢]{íÙT ^þEöÈ0Ú3Ä‹Ó8šRˆÛ\Í#%´Œ&1 Ç=]·"ÅŽ‚�§b ¤iOì")ô&ÇÖE²v—¯5ŸG�HŒxýO8iB‹’Ý–J(àr3¥T\ëÉ8y“\\v%¢ô=¤UàâÞ ¯¼ë>gç+NOW�ý^ØïáÑ㑞]*—×V…4Ýðõ-¡jó¸‚Ó¢JÐB [¥ :ÔØð*«.²î«.Ú÷]ǦOFŽœ c o׉óÓ §»5)¨6L#y<"ù@''›5·ÎO8=]sz²fšöLS6L'b4)lPjßøÖ�Ã]kÛÃkÅMu8üûb÷‹Ó¾k]BFÄæì‰[?F衆â1òx­\=NXï@2š ƒ³äÞÜw£&Ô—A(ƒ2 ŠŽÖë´©Ø›÷Z\‘çMì:Ì…*m|¬gª_·W>76¬( ­èÅØÐ°²†¥ÕçцÊÇÜAþ Þ·ÖÁޝõ|²|fr3q݉Ëê�6Y\çâ3U–¶>Y|YÐêó¥´ý¦5-^øÂ7`Ÿ÷-™º!4[T9ãŽHÝɤ”J¬h³·þ_à/­+³n‰}T¿¯ŽÛүj¸1Ï-)@kôR4Y º¦в՝F¼¢¾ –hÔìÚ¾É>ƒ©2àØK)h,>´a%9Ã4ÉâÒDq ÁS6¡bŠb‰Ø` ñP¬ßo-$š±OšÝ¯_Zÿ÷¤Àüu3¦¯Ø]%6¥p’æ‘Uu{de:ÖTô6˜ˆ(Q)±›™'� ÆZôrD¢% ºÚX°wç;Ëâ”Ñ ¢O†�-#È2e(ª™ �~Ø©ƒ~%\_ WW#)Ž„½�Ö˜3Y½ƒ<Ú lñµW|Á_†OøÔmÀ½�&¹£­4ÜJâŠÏÅÊh*èd´<7Õçé_€:OKÌ”ÙȵIÓžÜ�5û<Ÿ¶Ùg™.h«¿/ˬΛL½_­™(Oªˆ†ÔÖ)Tc+q6~ˆÆ`01·Ìæ :p/Ê\lä º•…øÏÅN&OÙö…_B˜ðÖqv$µk¯V6ãÀ9Øâ ³é©B‚µ ó”unª×J¢ì¸¶À ¸ð3?ÌÅ«G_¤µ¬}ÞÄÅÁöųYHs>ë3b®šÈ9“½|Æ*W´ÉUm²eÒEëd¨ó¸m"ÒdL*ˆQ&VÖ¢+qÙZs±ùXóñh;ˆP™,Œ¨sÊÔw߯v $Ð¥Øö8«Šíœ*Bô\^°ÚJJÉ&õƒW„)}/œ_¬¹{Ö1NO ‘2@±N#«u$žwìNëM¡ë3ÓP?#¥DD)Àº6«@'�Í Ö«D¿ê}©·®¢ O†¯^¢Cfņ =’#:Â4f €Ä7 ¿ç©ŒtiÁ a/›�ÀÂÑh£¾pÚZYkµ3{òƇ–›ºwbi¥hÍǫưÎä ™—f`´½µ~£Þë­•Ïÿ¬‹ï+à ,Þ&Ï}fv#ô¹O·sûçl ×±XÜ‹Hu1¨ œ—Ç^&o…šô³ oíSS¶³`°1ÒZo g¢z[kä@Š‘-=)º¨ «%ˆtiEL�ŸE9 �Ãsfœò, 6*eR¦!3'ë{2åÈu}êLÙÙ>µ¿O¿Žô«Hß+Ý b—‰]!­<ÎNXÙcgûzKTÇÔj¼©IôpR«ìOE]þ®ʤ„1R†hÍ·Š:ƒÌA|ÄÐ �-DŸ_Á«L3Y]wÔ¤ÆJ­±¶ï¹f�‚=§æ¨ÒâµÐì÷#û'þ1ÿéñ³<||Õžõ+©ã}ë ?|ëœ��Ÿs=e.'kútœxi½âå—üÖ�xa³â›v[>ñúC9ó£žD…•ë?ƒ1ö?rï6wúŽ/_ïÙ¦Ä�Ü7¶ÿ'>áëûéÅ{Üî;þÕ³+>yŃõŠUìYyƒàûë5WÓÄX”¿ðÂ]øã«k¾xµç#w­¹ð—®ö|êѾ]Oy×ÉŽC)\Ž'UûZ•^œ#" ž`øÀù ßuûœ7G~åµ7yi³æ»oŸs5M|Îïª= RàXLÆà«û#ïØm8éwûž_þú\tùÅûLªü£W¿À�¾x�MŒüþã§ŒE9Û[_Þn¸ž2/o×<ÚùñÝ)ýÎþç×_ç>zĨÊ8 üÎïþ3>÷¯~›øÞ¿Ê7¿ãÛÛJ]ØÉ s|´ n  Ñö:)^…âÉìD´¹,oM[¾Å‚U3ëåHBµçþIYú'ˤ€_]eö-c™Z�¨ÊÜ8n~i�u¤nݳÃnÕ�Pgx]�J[sÒ¡ÝÌìËÎ{…7¤Ð'X¯:¶k«Ø®«Þ´µ�CAŠ2%E“5/c@i&5©4R Š<è(%SeçBñPmÊäQÉ1›6dB(ÛA Hsa"“b ‹Œi™þ£ƒ{”|—âý´öQ2û#ÙŸUHÈĬNxÒÆøõÉeƒÞ3®�@oä8)ï}–¿õS¿Ãoÿþkíy�…ÀwxuÀê-3è¯?ëWx.1ðvrC5‰°Ž‘CΜ}wFwùÔáÀ/<}lMÕUùò—?Í—¿üinßyïÿŽáþ ïæòêŠãað¥cñG�`�‰%¸VfÊ™r8 ÇjkÌBÅÐSÏjµc½èÒš+8þæ)Áب&K'L�‡=ÇÞ\Fc”G'í)ÂÛWHÁz¸¤Šíã^É íûÜdbjcS�íZÕ´±åƒ¬@fy¢מØ�bïýÒ’K¹ï¥ê`†Ã‘*XCÚH—Ô’ ]¨þjŠ�5)î·DëIsJj ïw`>˜-ºnEJ+ë}à­ú­Ìp3�f/s±5/¡ÒòjLfv(¦HL�Ù -­çbê…µª5žÆ¶¥`¸È0ìc×�Àx•„ªÙÌi:2º®'%ëÑ÷=*Åd€r d“B U OЏT›\²‡ÚÞ#�Ë`û`o>R™Ì‡GÓðOAˆ]bw¶åîýßòÞwð�¿‡®WºUáÎá„ñp›§OGž>yýõÛÍž×^Û“§=Ç£M@¨ ¥Lèä vÉÎ`ŸŒ$â6V(2ƒÉY�Ÿ®¹8ß±ÛôìÖ=} tQÈÇ=‡k�»9;Ysïîmv›5ãqä¸ßs}¼â¸¿f�”ínÍý;§Ü½s‹® t]d&¯n“ 6,(Y5Áš;À­"´Œz݇[`%Pâ"‘¶µ–8Râh>sñ}_Š7Æõ·Öp/3×�\?:rG×%bèí�9ÃTe„FŒ…×á„§ dE4X²¥ö=³FÄΊ¯Òª †¶vžó|Z’²¾¹b,¶¹ª¯¿ê}Ý$ ÍÑßüI÷Ï<_ÿ*iGÝ¿ÏÅî÷é—rHO @`<Â4(e2²~kê•%ÖßÅÈ\©údÁ®£É brRâ•óÁÉ®³­¿´Üç€Î¿oÍEd4g!ÌÖVŒLž›SË*…³ªK ‰'Ä4¸,!°k‹zóóŽ—V‰àZù¢Õ­d–Ê.ÓzÿTוeO¬›˜ÇB—¯‰�*ÅH½ž9_’�hû�¨~Q]Þ.fY]°¼€z¬âc­Ï½ÇÏíkEkFC@údÌÿ�’l�ºÔ“O$« *‰PÔ{ÖÒpKð%ÓÉc~O84}P5ìº(Œj¤»¼ç«=†ÉÉ÷ű¡%=¨8»¿U‰ÝI•]« A,¾–âŠÚdÏkÕ@%@W¨µhUI‘6+V\çCuŸ’lk9¼ž"2@™,ã)Ñ:k›E™ È4ªeL¨2Ÿ�5ëqY›Ø!Ò*»h�›“¯Ê€_½ƒKŠ1Š&,k<Ó›&‚7Z‰ 1Eº¤t RRRT022㺡f™B@ °Ö)Ý€ê:o)-;(`‡Åınã!Ì‹ ‚·Õ¹Ck¢®‡jþZº‚†æªzµƒ7™Q¿2[}66u’øDêçߺŽf'HÛ±š>kÉÌMÜܸ¹| ªçƸ[˜?nküTå—T…¨‡` ÜÝ*ÕÈ œóëX¬ZRS+TÄõèÏîÎvL-®UR§‚æÐ4øëž$êL7ûœ ‹Ä@aÊy¶›5øÇƒÛfã7½0Aº0;2zYàêO[ü·õà9kiÒ2õ uåÊl±,@cUÍÓ› D|n.qêXT€Bšvæ<ÿük6¾ÉØåÄ›ßJ`Ú øM‰xã,…"ɉ,™ìIÅ™PUv@,¡DôÙ±¢’~`µÎîÑÁÉ¢B$¬"}„­&ÎW·o¯¸{Þsy³5¦’2€ÚWJ+Ò&±ÝFv»ÈåZ™¸œ…�1…@ V)°J¦ë89.ηœŸŸ²Z­A"¥$Æqäx9r|xmÁ^\£$cƒ7ÐÅšK›MÐV�¢ª&U`!˜[ ¹Y½×¥Öid$²å³Rqû²Ð8\L0]<# ‰³ª ž÷ñ8KÛsäF"À¯£=ïÙÎÌvËm!sE“ÔÏ-^m},¬:_å¹7ÏgX¼ïíþ&7~®IÛy—\Ü  -Gió|>Õœðâ;æÝܱàÌT‘`2u1ØØ¦�G%U‰“r€èCM ºˆI(Èý¤¬&iö(OÅd«cRÆca8*Q }̬RaÕCê¼™y°}ŒÐ¯ýJH+!öx/^ñGk¸¼‘/7î�Ö`´ÎØ:ê0W¬zVæ(ÈÐÉœârcê®hùðDF-ÓôÖíܖѪÎme1Š£:l‹i$(ÇãÈÿ_ÿ*ó?ùû|õk�ÛãMÀGNOù·îÝãÃ;kü©‡Oø®Ûœv‰Ëiâ—¿þßw÷Ö«æÎ¦Åý>—ÍJá+×^ÞZ“Þë)ók¯?ä½g;ÞéI„?xrÉI—ø¯.xÇvmÚì!p5N|ËÉ–7+Ö1ò©GO¸Õ[€_yíM®Æ‰�¿üöSæzœÚˆ¿¸]³Ï™—·¾|m ~ü¥ûD~ýõ‡<F>öà.Û­Aðå5xïÙ 1Ö!p«ï=ñû]·ÏÙÄÈ—®ö|ùzÏ/ÎØu‰Ï=½ä³O/yi³æ{î\ðúqàé8µF x×ÉŽ}Î ¹ðÅ«=¼}N@¸œ&~þ+_ç•íš¼w›GÃÈgß´çññ“ûüG/¿Ì¬¶üÆõ%ÿàÉc¸º~Â/þÊOóÊKïå#ßûopzzÇç›—€û3Î~QPlîÄ d±ý2×ü£Ô™�c³}©ÝÛš!ff”™ÀÒHeÆâ…ªS+NYÆÀ³ßÅOflÄ*¼µ êjb6mæ\´€BdñY„>R¯ßÎ?W ,öª_ª~e…(™U œl'Ûž“ud³Š¤h{™ùw@¢º\è4ûQ¬÷S &�VýÝìZ§s%©ÈDFºêX÷‰”±DÆâ²%()@¦y4€L“ù€ÁÙ¨TÆ“Í�Ú›l™©>VMÊ“ñÄ@ ÷WÝ/¯,•ZAW›ÈuÂå8òwþ×OñŸÿŸà«¯ÏÉÅRâ;ú5ZmÞnâ|ãõÿÓkô˜M€î9y¡.H³oCžÁ †1ó�Øñá»xM3ÿû“Ç<ôñÃ7¿Ä¯ýòÿÄf{΋¯|·ï¼‹”ÖÆx—„ˆIæH°äY "*) j %NÖWÄ*üJ!‡ÞÁjõ828Ç­”÷ëˆA ’˜&«8ì÷ì÷{b“âµÏÖ¤@vZBGê!Z¥hQ“Øpâ=!¹Ã)æ…¶j¼`Ön–rƒ@V@B¤³¾É“ÉØÎÁ+¥&7à’ŠÕêÍDŒV½™ˆiE×MÍï4’P2¡ØÑ¤K‚�äµ2´‚Ö³ #u+bZ‘ÒÚˆLP›ÅÖŽýÕ…V‘�8¨2WÔ¦ÓÖ'̈ŒÁ+ RìÉir¿Ä{N#×Mãˆk8c&'�· ä<0 {RבúžMBFYÛƒ#Eତ+ê®�ß»ï-j–_â½ÚÄí!®öPãk»w#iîN7ܹwʽoñÂ+w!9Bî!o9y:pòt`½>²Ûì@rùôš2Ž”¨€˜ß—3ä)ÙDk¢Ëþô¶ßAfÒÍGú>²YõÜ>ßqïî9›Ub•‚U‡if �„%§­Z`Ë�[çt1rYž2\OhØmÖÜ>Ûpq¶ædgßR÷¥õ ÕçÇH,)M5µ×uákÁ�©•à u -˜üe7AQ¤„¹‘q›ÿ!LZ®2×OöÏBJ¬¶�d`·d„5V,¸�±µ³ðw3žxÉלKnŠ:ªX÷ÿâ@ný°ï“5X«àgs<À«¤A­¨SMÎ݌š¥hþ‰,ÂFŸ¹ºø¡9)êØêÙã-a(#äA™Ž0 ã`U2%ÏçV&PŸÖL¥:‡†ÏióÓ,ù©Nèòkòk™b¿C¤—±w­lªQQ}éÒW«¾Hñã…ÅðÊâ`õ(õ=¤nĬú¥Ô&ÆóZÎ󣪀œTÒçò^jü´ô4¥ý}Æ�üzZEö|½õûÚ'�Xš]ÕÅgçé#T¼ÌÄGª‚Ð>nòœ/~Ëœñ…+(þXU€Å$¼™²ZܱˆKÚ:è¡~/Uæ³Æ°ª®T#Þ![iÕ8`4b¦F t]5Ü5hË�.á�\ÉÈ¥JÔÛTå�:"•å_퀫­¨%‘ŠV€ághM(¹HS©ýRµ,pÓ¿Wb»ú÷>f‰­g Pæ�Ü’Šb̓$¸NbÊæÀw�¸ª+ 6´Ia²f1He"&Ótrѹ]¨,ã:ª5’ªY²¤0Y%¹ S!ÕskÀ»H·êéz!tJˆ…°/ŽU+ÚAI�5QÚm«båÅ ¤vƒÕ¤‚\‰Ý�juƒb°ßùï§Q§ŒÓ©ªM<+`m›ÊœO½1ÿÁw™©íTË�±Zò™%ç²ImÓ{.À\Û-HR¨Í}K©‹Ìßã‹BÎS[05­çöǧгXÃu�KbPAâr¡×ÇlÇ+%7yœ–„¡6ÏðmØ2Çdzåe™˜‡3¨„:ÄâF¦h-»É­JB}ó²’×9ɰ|V�·(3ƒÑͨï!u ç±-¨mbÕÈkð©çÀ}6Ð2¸uq–ºaª;ïj‰“å=º½C£ eνj›Çê%EÕáÇ6æÅ•zíØx×ìæ²_BŒÁœÿšPjI'Âcti0±û�²¢ƒ•ÛjΔ<¶c•b?ƒ¸¶°õ©ÍÓûÑAÃmƒO}aµ›Ø¬”‰‹®ç…Ûkîì}Ÿ8 ‘õª xå@¨Í0ÖëÈ­ó®9^9�ôôÝŠ¾ëé’i*‡89Yqÿî–^¾Å½—o±ÝíÐ"ŒSáx˜8î3á°Þº~MQë “ ÅJ›k ¡ÅÛN·`Éû8ÈÒÔ�uñpK�[Æú_Îý s50GÑ*—Yõâ�ºyÙfUjcÅàþo Þ긑‰[z-!¨•´µÍ…y¾¼µ‚à­/½±®æßêÛ|¶Z£·;rcþ7Ôn1–Ôÿõ¹ŸÝ±�7‡xR ¾w¹¢ˆ�%§EÖ`3™~PÈF?¦³dÒˆt#©Ï.£¡{Ç ês^�’šÖî¤�¼jTÊP˜V�i%÷pL¶7tIèW°^C×[’ð±îrÞ¾tµç÷?å$Eî®WtA¸»ê¸è:_¶ÊÝ¿MáÑ0ð'W{¾óâŒûë_¼ºæÓ�žòá[ç¼c·á˜ ¯:¸ÿÍ;ß{z(C.¼zmrCï;;ázÊüâ×ÞàÛÏOyßÙ Y•O=|L¯lïÖ³`L‘¬?Â{NO¸è:î­{~çácκŽ{ñ üÂW^c(…¿ðÂ=v)òÙ§yó8ðtÊìºÄƒõŠÇÃÈ+» ¯^ïɪüнۜv‰ßxãG>öÂ]NRâw>áË×{Š*ï??epÐî0YÒ á�'[61òµý‘¯ì¼ÿlÇ÷Þ:çcgçüÔ›oð©k_¿ü•?äg~î¿äÃßþ#|øuÿÓ<÷«Dªž³%ëRT¢kU× c¹ÕRú¥ p«"òœEYîìÚÌÝl“ª�SD­ƒd½¦cñÜ[ƒÜ0MÕO2­ÎîïµCˆ�ûFYþâ>f{»4ÓK]�dëiiÏ¢fúØ­:ζ½õèŒÎ�Z%@« »È8NLc&Š77'%ûN“qœ¦Â8V¯Ò` ëv[åìT8;éèûÀ~('X&þq´Îýw×T-äME0É ° ÑØÀ4¥ö+@JŽJ.±uUB¢�¥!¤<FþößýmþÖßý$o>Þ·1~_¿â#ëwâÜ_ÄÌŸ¼-[ý¯?›×:FŽ9ßØÑ§rsüÇç~®€}\®ÊŸ×� /ÆÈ¿w~‡àgŸ=ás³Çûë'|þs¿Æ—ºOòMßò½|Ë»¿�íú„.©¥°¿¾æxœ 8NBJ‰äþŸ…"J$¦ˆja&Šçä–©~T»ãuor�ÈÞwëpØs<Ù�œ°Yíˆ)˜„l6ÉÛR ³Dš€˜i.#!z ÄèR²x9Ú¹B±*ñäKè�©7—J!ô¤¸¦ë6Fº‰+BtF¾^P‰ˆkl×C!˜TQ쩾“2K�-Á­“1-kUE ÄÔa½á¼ŸûŠk‚aË4ZR@u´‡£É•i•ÿõ˜)˜4CÖï ‚É·2‘º©É§šìÓl¯‹‚÷0 ±óÆÓQzR*¤8ÑEk¦^ d¯ø” ~ŽÌ~�„D·ÚSO‘”¬ÏLh¬*g—LQk´ÜHˆàB. cñ ’„42ÅD)¥Qof[Q¶»ÎoŸ²Ú$”Ñd0¿U ë“HèÖl6îÞ äqäë_ý*‡ë#SɔҖà©dC¼ÑsßGú®c·[³Y¯Ç#ÓX¸Î™qܳ9=ãöù)w/θwë‚’� ‡+Æé€æ�N”í&r¶;áÖù)§Û «¾ctÉã�.B¿í¹}±ãÞ­-©†ášª|Pšô§ÅÙU£?ÖdU¡Í‡¶s T¸·ÔøÙm†ˆx³eK6Z·,Z³RµܪK üv:;vQ¦œ9^Žž9^MlO{º°†™ŽêR{ˆÉgÖ8/8pØöø"^í�@:ª$§}Î1·¢�òÜ?¬º5Ö«ñ]K`8ð_5=ÕI�ê÷¹ª††Ì4ÃyÀÔ{}ÔÍWŸ°Þl£Òz8”Ù*MÊ4Ñœ¡âXÐT�j_ƒ}©K¢‰ÇxV ’íÞMû pY9¿¥¹jÅmMoE<ù'70eqÓ•ˆ �PÛnÕcXq¬ÅǸ¸Ï&0ƒôKÒ�[¯ �¿5(2©c¥Øš �šÜÒR%Ý^J±ÿƒÉ¬µÆéjÕGíUZ0{|Ói]ÄÑ‹kÓšDhÒFRÁ5ÿògß~ ó5{âcæèÈ�a¾ya7&ØâµŒßË[~Ö¦ °Œã—G©Ä[[–DÓ㨎y[ ÞçÂe€°èDÖ†S;FmS§~Þ“4Ðæ²T¸!C.…±L&Už3 C‹�°ÓY È}�b« ©=¸¬÷ѲJ`!3žqb.¨Ë-‰ÓõÚü�v=‰•¶ìœ‹ ÞxF•En F#$gûŠgÛëàß®*óЛJ ‹f†2g¤n<\T­A¾¢ÁúP°ªÀ¨Þ™¼XÓˆ. b©ôkÓU–hz{�a49HYJñF³µQ¢ÛDµìL@MÖ e‹;93Xš¢êU©‹¤hÍ�¼,ºv‡ž¼ >‰ÚÁ{Þ)¨ñšO¤úþ²˜Õu�ËÕ¨Í ‚åR)í»·PÐ.¹>omÚ`êòÙë}Ä�zc¥ÔAw´M{rfD…ºãù+‹ˆúìZI}©cïׯÌï·6> Î(¿ \›¶bŒÁA]&N|ùK Ä —WÉS`ò{°¦Z¾if!‹�bGLɪ <Écòï�•R¤ë}×±Ú(ÛÓ#»MæDç)q÷´ãle^B:V+EdBpZ�³—V«ž³“O¶�§)£Sô¤Ð‘b²u­™»mÇÅ­wî]pûά:òTÈljázd¬ª’¬ësox^ªÈŽ°Ôµ�µÒ ©:gëx¶©£¾~ \©à”…Ëõàó̳àR›©¶„/ÅÛè¼DÔ+T›4×’9±t�*)SÏÕøBÔÕ„í–¥�7–×ü}[S7S¿[ÌØ·¼*HŒÛœå\œ¯ÀŽ$K€h6¥uL¯ï½Áª]†´:kÌ6%K(=¡ÁVQ±±N™Ðbï{ëhû›­1µ…–lî§è½MT½?D ŒŠŽ…Ü S/Sá&TÕzë¬`µ†®‡”„íúC˜,™–I𓀤”P|¿È”"H‰V•ê$Tg¯&нÓWÙùÿFPÛ#5¸¤‹;6ÕÙöR“—~Ü`ôÅP+|8q¡êgýrÂbOÀ÷UÏìêS¯òïÿ‡?ÍoüÆçÛ#{)u¼o³áß¼w—íŒÕ~ÌÖ³äÍãÀ½õŠ;«žüúëy÷éŽëŸ|ó1·ú®1ø7)r½j>Ã+Û5«ŽÓ”øÂå5Ûø®ÛöÞ_}íMø¨K}~äÕ«=8;%FáÅÍšËqâ¢ïxã8 À_~ñI„ßü”¯Ž|ôÁ]:¾pyÍ¿|òŒuм´Y{€hó¤`ÿ×� 61òhùâå5¸8e#|yÍï=~Ê{Nw¼ÿü”GÃÈ—¯\ô™wŸî¬òÁ™´_¸¼æç§ra…òÕ×xq³æûîÞâP ¿ð•×àã/?ð¦Ìµï!gÞu²%ˆpo½âÓ�ž²K‘}áªÊÿõµ×)À_xp—]ŠüÒ×ßàÙ8qwÝsë¤çA×ñã›þâÙÿíë¯ñ4[ãÈOþî?åO¾ôþüGþwoÝwò†�&«"ˆºXH)Ð%˜‚%Öš?ãëj®ž_Z÷Ǫ1q;Õg’ÅÞéŸn“¾Ì1‘àÀµKi4�Aœ‰Ó¼5fÚÇMßêÆ�7OùÜûŸÿ¬ŸM«Å›÷�zl¡º $%1Fõº‹œ¬{N7+¶ë`�u´À<r¦ûÈ0y ¬zÓ„RˆÁª¨B(Þë(3Œ™ãP¼Œ9` La½ÎO…óÓÀ­óĪ�\+Žƒ,š Y£D¡LÆ:]u.YHM*Z#µ\Œ¦%Ñ P)¶s¡‘5Œ@"¦³îþŸÆ™a§Q Ixtù[?ùI~â§›'ÏŽm|?´ÚðƒÛ[„uŒdÕÆVW¸á_~ãõgÿ:,ØÿõUüTÉ úZ‡ÀaÑœx\|__û Ыð×¶gij[üâåS>á‰Êq<ðGŸûU¾ò¥ßå;?ôc|Û·ý0‚0�#Ó02G÷_#ë~Åz½n½Î¬éŸÅÏ¢ýy–@U,T›%­ªÃ®±¦ß¹dk*;†#;¶t]ç>¹ImNy²5€Ù¨ÊŸòD.J&Dµ>H «®GÁcí�„ÐE“‡ÌUþÀcN—Š¡'¥µ™~¾� ê`lOLÔã¶ŠWÁI1‰¬ç€O³é*5ÓFž±=_¡¦¾/T„;R·¦ï�À£e¢èD²ôä<0MâŒbMÒªD"&•R«Ðko9ŒBp[‚ùÎN„ †RÈ„ÐÑ%%§‘œ²7'Γ2…ÉHUÁbŒq Å¤UÑ{þ©7²’ª�ª¦�aó¡[º>r²í!¯yôæ–»wzÆã�«Ë£«1(E£¡$%#:�u—Øn{ÎNÖl6+öû‰}QŽL�GÖ]äÖéŽÓí†mßsuuÅþò)Óp…æ�ÓÝŠíég;îÜ:gÝuŒÃ�ñ¸g8\‘Ç«^X÷ÎNWì¶=Ó”†Ñ·Òd\Ô¥x+çÝðkŽ]5#Zï­§žË¶ƒOPÄ™§"Vê‚o,µâœÌáñ矋±ßízµ9ŽuÜÍ?® ÐBü2&”EÅÀœhã#ø¦®ó9|LZ`¨3»¿Žu=�÷¹šÆì„4Wý:jv6¸S!žè@jñ]M5W  PA­¹—€1Tjó«£ër‹Û+wøbµ�v%'¯¤a²çm ˆÎ•„Ô)å. d›˜ß³p]Ëî‚ÿ­VjÅ ¤©òMhög•ÉRþ¦ÅZ%€!”`{É>'”¾ëÙ¬W6ÄEÛ~Õu‘®Kô«žÕªc½Y³ÝnØn•Ýæ’Ýjà$N’pš ½ ôÝĤ…Ôa,ªx쀩[³YmÙô¶Ï0õL¹�ä,Öô‹Bˆ…~%¬7�¸ foò‡‚Ž”ý*„®§„ÀX<Éân�è@TieÝêLÆš ^ª&Å7¥êLˆ0—oÚ‚.•IµœØî`ÄÚñË+ æ8k¶ß:?|¬Ô´j>–±“Ââó©ÜÃiëß·hØ­ÆÚµêióáB¿°6›eq¼¶øÿ¿åƒ‹ß¨?ÿä¡hó«Â[>]�ãÌ[˜¿–G}Ïòÿz–:^7ÇÎþ¬nël”`û–t‚ô¶/ÉäºÁ“"ÁKçƒII—]¤`ùïªj`~¤D(ô!‘$A)Ö`¸ƒÔ+©+„4y³õ‘©9--˜ˆ– °lÍ™N¡Wê¸Üâ’o¦#Ò’öx—ŽÔbb@ŠZAB´.Ì’­z—9Ъ£l,uvIuXeöË¿àO–9_áÇxòôŠÿøoþ{¯½÷Z³ãÿÿ�ÿàËvÂÓiæ<|Â×ݽÍ+[µúåóK^Ý ¼¼Ýð�Ó=GS³>›f>|ë”÷ïwÌ¥ðcï<æ½;m.\€ù�·8íßúòý6ʃ3ÓÂRø²�óÁfàWÎ/¹;ôü¡Wµ2àï¾ó˜ë˜øÎ× ÀÏ<}Î篼ºÛ°ñžÓ.p§×fÁs¤wZqÚuüü³sÞ>Žü¾ûwÙµ2úüÕ��Ü:åC§{Þ>ŽŒÉz£U�àtÏÆ9.æÈo_^óÉ»·Ùµú…ç|ètÏÇïœñÖáÈo_]ãDÏE.¥©tíYðá³ÎçÈYüðÞáÞfà»_{Àù9I…_ˆßÿô xôôM¾ÿû |òcßÂ×~Õ§Ì?V…΂st¾ÐwBß;­V+‚›i¶�˜}¢TŸÜšÁic U˜S×ߺnÀZÔöÊ–®ëu¬î«rs©¯[–nÄqïr[*¢êZónÏYß mk¶?¶xÆ~ßxá¤óœíNvöÛ�Ý t>k˜ {]¤PÈÉ‘6êÓ}ëtÇÙé–Þ@{µí˜™SdŽ‘ã8s<ÎV2 ¥(hÔwÅl‹R\]^òôIÇáðŠ DÐü­`6�"ˆÌZúé2·ïw|ÅW¾Ìfð|þ·s}˜ñ~K.žyJ�…gJ†^Øï:öÛÀfP%ü¡L8´/ͦë8Ùî‘T¸|~ÎÓ'�xøÎ Œô¡°ïï°:6C9quyàé£G<ö”ãáJæÎ�[Ü>ÛBf¯Í†S«ÕbÌ-qR4¤4{“˜5î-©�S¡d*kÞœ(Äb¿%jîf{foä@ÀK§b/T /³hoÌ*„7ñ]¦ZÅ$¦ .¯&.Î�ŒÇ™œ/=½p9P&üX%Ki€¼˜ ¤©ý‹åŠ-w1€€š·k¼_j» _šz~©°§Ê�ë­Æâ5IÖ?¬ÆB†I4 >¡åQkdç5®G 8­HÀ”)“ !� )&í£6'#63¥1Zõ¡U ÄÙ·ÚÇ®˜�s¹‰áÄq9Ã%eõµÊ‚A՜ت-ˆXrÝjò T¥@Yzˆu.dç^Ä*ÊÍø«â9FWTŸTVé”>æ|Qauµå©¢S«°¨ûYu,ù›åó:;¶ÏÚþæ‹U�Ûµ®§IÖŸµ8h./ôßp¨÷l�¯ãÝjcìõû/ÂÚÕ›­ï횬òíå`«ÇLÌØV啨m¯·cü­âôJP,dõ"Ûw5p^�‰L³“ZµÖ²€å3´ÀT¬_nQÜš¢msì‚•ºeŠ4A6¶F¥, àO†¹TóhÝC4¾ˆy!Ú:˜jå@@ê¾ŬZ긶^,g¨#:í|P½Ô³2ý ¢*kZlC1b Øàðõ]r nªÒ¯x¿4/¦‚±WP²•èàË®s&ˆöSÔß*¢‹qp¸Þ㣃èÕŽ Ú yO×Í®‡ëÄûNbªÑ¬àô4ye™‹‘Ir[+½ÓO]§ ­zE CèºÎ¼S}'L£cô¨f^˜fÝ“«O­©Œ஬ðúV3HYþYÌ ÂS ÙŬ.ëPמҎ( xY’M 0ì¥ÊP®RžEã,¶èt,Å™ÿíºV ›*ÿoÕØ&œth6FT7Æ™‚[åÃúºÜ>I¡’F T6¡¾@*ÙS¿yiw³Á‘ºpß<ñR¿m«ÿ—å§MŠ˜O¥.•C¶Qn v%QŒi–Þ˦¢•%gec‹×³l�€8i€²Ø"]›õŠh`;Ç„ÈLm¸�íÂÖ�©Î·ê�ÖÆÀ2¦šŸ,ÀEµj(uNeßJ•tE+ËžbŸˆYÿ”Å^H8ɤ¨‹Y%6›ž³Óæ92ÇÖŸ¢ žaèÙl7lwNö{NÏN8ÝÃéÆq29é=;_ùs¡3!'UM;4¡N+|ú-›^Øt‰”0(hŒ+8_p!á|Z”)AžÉ‡#ù0"9àú�â=³mu1¢àjÖF±%Q=­ë¹‘:Ü*ÑW°u·´½¼€n-øXÚ‰é8¨d¬«�1oAO�)u�°»XbæÜÍMÓ€’²^hÚžYçP]¿u½7‰¾B 7W¯¿O ^_ÖŒýúöÂZøÂ_Û÷åèçʸ¯ž/7ÖÔw[\ßý±Za°À=ºáW2ð‹!‹‘ b ¾¼Ãu‚ô7$$:ÄJ@[Nì‹è]A†EŒ  ÑöØà ÓÄÄáÔ…Ç©u•ït¼JUç¹nÖq§e,v÷ÚAT™'uÿ0sBÉ^ã¦\;#S”ì4oNÖ×Ë"Bgã®ú/Vb \]ã³d®VÔõÂ)p²�ö{½ˆÁÔ05ðÍŸœÌÿø7?ËðŸý/¼õöE»z÷Bà{oßã•aàëNOØ{Ïveýñ`3ð¯=`ãoFö�çc·Ïøùgç<›f¾ÙÔþo]ùÕ‹+Þ²£áVßñ¡Ó=ûà™³ª=¿ãÕ—p"¼q}àÉ8óÕwÎT�ÿóÏÎùú{wxe;0%ÝûãÊûëïßaãçsä­Ã‘ß:á£"<™fþáÃ'|Õ­S^?ÙqH‰_>¿ä½û-÷‡¾}� ‚=›f>|vÂ{v[Nƒç'?㥾ã›Üc.…zãm¼ßùÚË8ÑçW?îT ïÝm‘/o•€Ø™ÚãŸ~ûSÊ|Û+/±õŽô”wŽ#g}Ç­¾cž*ò¸ˆ‘Þ9>zû”»}ϯ�_òÎqäS÷ïpžl½É"‰ˆ4µ¯Ù©S=d„¿ôƒ?Ãõ}?Îç×ô"|ݰå¶;Â*æó¢M–Ç•�ý‹Àò—nÿdoïf×tx¢æÝn"BÿÂõ{ñÚÕõÔ¡v3‡9ò©n÷=8ᇯÎùñ+­ ¸¸xÌßý{ßǽ»Ÿá#_ù� ý](ÉGOpƒVS*Ý�ˆÚÝønƒsæ�ß� €EI¨bµ?qf“1MZ™>Ž“ ‡Ì›´÷‡*¦µ’Õ¹'�Ú,=çLŒ‘yžH9š­Ž#¦E¼ã,�w>ЉVîÎóLžµÉ±bÀ÷xššË¥Ta ½(9à|Fì|çbÕ‚<l}ÍFXäfù#ޑ̇š † Dªx ÑëTóŒÎo5ÖH‘ŒHGb<�­o‰VÔj�Ðl_bŒŒÓHAH11Ïóí—ly©%_ĵŸÅyD ]×QROÎ3ó¡óji7\�_ðÎÛoqñü)Îö» »mÇéé†e©ùR IDAT2]iÃçTˆ±0N‘iгÅé»@ßB�ì)YãðF ”66k¥À\ ­Ö(’¨ÕôJ D‚tÉ8 x)HÌê|i8b6+LEO”(.r#ç3GÆqVñœëèÜ—=ÌCˆY’ùZñP±ŠlP™‰«jšRA½lcÈœJtú\ƒ×Ô^Ýâ„V•’Íæ´2æ&©@ïlVËVÙÔ²I)­ÈXû”k|ŸÅQœP\&»:ž�Ù@3y´æÔÅ”Í6צIc4°~±0G˜çBœ )ŠšØÔP|¤˜¢½´ßsËán@ªî^ÇY+©ŽÓf\cJûÛ‹÷¼"ÖöòNö¦yù �€ÄÀ:·–ÕßDPw–jC-Ó3R ™eR®+éS1Õ¶êuißÇÖ]ÍÑJSþ/¤B=±¶5U÷©wÅ©tƒÔ¿io&{]©gu*êÆ—é¥i\nàç\AK|^ÇŠh­Îu[1M4»¶&¨+f]ÓìPË+T×.?y1ý0Áz©þU$oVHˆÉÕ7,f©˜)ÖdÛÆ*ºÚ[ûZtv+QYãWúõ®�Šq Z‰˜Jí;ªC-š{JLÕE«h*í|-b;'¥´;õ§½XQ”¦FÔG¯vU¯eŽ•\X¢¢'ª2m^êøÐţɖk€ÝÖ3ýÀy50t¼yŠ¤Æ¶R7bg'½Jþëg›Þãųµ€ßIÐ F"®ÌÊ–']�\œ£HUn8ð‰â“ù‚|RÒ7ò^‰�>xBPßCïÃÐkGy¯�Cß9âÐ1†±5pSuS¶ÆP ÂÔq.˜rµµ�Þð—e Êúo5!4À.· TkMÔìf´¬=gM¼^ ±k#,¨LXYM–:˜õ¯ØÀn55ó]]çúé²ýßš‘ŠÖK ת ’ëøp¶gµEš¥¤¿ž²J Tõ «…X‡FUƨÇe}¼®©¥(ó–kããÆš{™%úõ”ë"SßÇ*hŠSÿ}t±g¾øf¢øÒœ¹ö HÉ£ðΉùM†F@-›Š~Î\ŠÙíÔäÂ3Ž³Ù›Ìz®Sn,¤P/€ú«eŒRÏQ-ïª E‚¬–@eµXÔ&ÁõTgcÆk‰o±~Ø8ÒRçtHIĨ�yß÷ ýÀ½»÷¹w÷>ÏŸŸóäÉS-Ú5Sµ` ï›¾g·níwÜÞ÷œì7l‡K—ăp9òuÔ&lõûg[¨ÄáèÒÓ9mRÞ‡d >àûB¿Iôƒ‚’‡ã—…Û׌:ÝTòñH<qe�ZC ÎŽD¦¤Y«alÅ÷ÞµIP…Ò%ëüªëj+µ“e„i¹`Ui4ªÉ’šb É„ˆÙ�9Á5Æœ%8XܶN+èbAqÁH5FSK¹Û±Ö›3íq±�°-L T¯›EX²-m%‘6ŸëÑxᾨ ¾èíÛÅTÀ‹E\n¤eû|7È•úþ_|¬ÕÉZ~_“²öØÒüRi –@°xôÿº�G‚Zà•ŒU³8ü«¢'Ô`LÔ1VÆe ê\(tP…zM¼mßÅeè’òØW¬Ä@ÀwÛ}ÅÔ—‹wËv]–{%š•Ðêú¶ka׺2žÞÛïæ#ìŠeYƒ™6¦ðY§j#se„s¢eÛUÙR Ÿû¥·ø·þä_çGþÞ¯¶+çEøçîÝãO¼ü2b)Ì¥ðdœx°¸Ýw\ÆÈ�?zÊ7Ü»Ãi§óöçŸ�óþý–Ó³n÷w x�¥ð¡³^?ÝC)üܳs¾l·åÃöÜO¿õˆÎ9¾ùÁ]žÎ‘ÇãÔ>Ó+Û …ÂýMÏ›‡#[ïù–—•pøÉÇOy>Í|û+/!"M±ÿ`;p»ëœãvßq{ÐÁáïßá¬ïøüÕ�ó9òU·•øøÕóK~éü’�Ý>ãËOv<�fÞ>‰9óúéž Âûö[¶Þs1ϼ}ùúûwð"<'>ýÖS^?Ùññ»·x4NüòŠm¾œ ô~:M|ðd¯ç©ïøÉÇϸ?ôüá÷¼ÌuL|ú­‡ Âw¾ö€N„Ï>zÊ1gžÏ3§]0û¤‘[}à×/¯èœZ0Ýz~äíÇ\¥Ä?ûò=NCào¿ùß{ë.¿hÕo?úíýøžoùn>úÁ¼Ð÷A+ˆ�ív ¥Œw0Í31©ç(ÉÖ>^ØëZSêÿLUSŸ³„[P÷ãe¿ÔØkµ~Ô Ïú¯n+böw¿½°À­ž»ˆVÖiïöÚFà©F‰xßb ç›Á±Û ›Þü’Ó¬=ÅJF{XµÚJÑ«i�#¸D Á«5‰x­*ª½RBßѵŠS,'H8 2$Òù¨6DlñÅ·1í®D@G­DtÖ,4ŽÇëiÔ¼@ûù8f/j%A!%õlu³Ú‰æ¹à ÌûëŸþ%þ‹ïû{|þ�çz®€¯ßìøÆíŽáÕíÀ“qf4"/óÅ>ö_"þ¿»õ/4î�k}MÞíVJa4»ÜÁ»ÁiÐæóíêÊ2Ç p˜#ß2ìùƒû3þÖÕ9?cÁã'ŸçGÿÁ_äå—>‡?ô휜ÜÑ^sS¡©+-m4ª›~��,×ІO*ø±ÜÚ1/TeÔ1@Úõ¦Þ÷‘œ�ÕŠ³œY f³ùÊ%×V¥ä‰±´œGÅGŽ®ëéºÎr݇(dßÃI‡¸ŽjãPŠÎ¥Zy8 Uµ›5ŸGPµƒ‰›TÙ¢$ˆå†ª€ŒÄõX|Ž8çÈt ä"úU¬@Á‹o`�dÍ×J@GUŸ).PB¤VGJ­|0+Ó9Τ¢–/Sœ)ÎÓõY+�-çÖàª�½Þõ{$œú¡#¥À<»f—›ÒÌ4Äi¿‰”FŽã5Îøn§‚&ñxçÐÁ ÐæÓN’Ù‡Ô†•©åÞ%%æ4ã�8]çqIi"Å J²ØJÀiÞpþüš\.øÅ_ìÈøà‡^åƒ|$X fÖCLP&ú�ãìÞÀ+‡3ÆãK¼óö�çÏ…««ïÁgºNÇÈÙÙŽ;·Nð^¬—`$ÅŠžŸãášG�§ãñŠñp‰+°zNNvt!p<x2OL‡#‡ËK.ΟCÎìOöܺµ'xaž�”y$Ïs*LsæÙù%Ïϯð¾Ã‡ŽÝnÇ~¿Õ¾”˜ý hOŽ9Y, }ˆjÅ@"‘Íã_ãßRCOÝ ‹âÞ,Dœ Šé+îU-;“dÐÆ7ÆÌåÕ5—WGbÊx×Ó‡ž!ôøâÔj´¥L$KEýJ¬‹Íjºèü΋¶ï›ÀF;„b^õK{KWì,•0ôW­¾Ì5#æ&ž¯Õµ:H¤Xÿ�út¾g·(Ã[Vš.{Ò‰‡HN&<ˆ¥›jy¦Mv•Ðv 1BL¢M¯3T»˜âŒô…â2Î%¼7ìÊD�e�ÿÖê€nRñ)MÎmî}QæÉÚ}ãÆï¬cFô$¯`Ú.RZŽ/K.K¡FÃY³G¶†élDQ*-|—­ÑñBº¶÷]+Ö o©¯1AóòÆÒ,ß9°J÷ô3››ˆa8s@ð®}uªp´~ s�Qía¹®Ï•,ƒ³ž¦HÕù°œÐ¥‚·"õƒZ>¾¤åî…¢sš%*WÊìHkú,x¤y&N£Î.h|*†±+šÆÖª (s:<®x#ŠÕ!¤fãjY&f9¨oŸŠîŸ1eRÔ½[‰ó‹šëJÝ;�d‹FDëã²ÊGôßÅæ±®e6Ž«{ÊŠ€ ¥:À7uµ•¥˜ G=T//4¥mÜR²n<BTÖÎ.•u6¨BÕä«‹¹|X¸Q "€¶,U³-$¨�22%à¼08mòä|Àùˆ0©}^‚8ºÎkùbð } ï;tuÛÉ%àQþ'§™8{+a´+žKÛ\ÄQktS'€,㲂m(©½uÆn mnv½6(žRÇ2Nl-\Ø;±�׆†]âç½�úe™¯ËT]%Ã0_-«Å>gûÙuõñ[±n²z�Y -‹1m¬d�6‘r{­4p‰fßâ‚Ðw�®·ëçT5WírrJÌ1jS°)/dl±ftµ{û,uu«qúæk’D¼à�ú4ö]Ð1Yý·#¢–ègõª^ûڷ·³«ßkIRBèñ¡óÆtÎ5r#š……�7CÿÝõªã¯VŠ@UAÖM®˜ª½FÎ9B Z'‘EšEßÃ5U¢Çõ‚Ó¾ç‰#»í–ÝnËK÷ïóॗ ÎY·‰’´Qoç<}ðô�ú½ªoí7Ü9ƒý�6»b`¼œÏå©©J]�‘Wž/…Îú0àÂV— …Í0ÓàÜÈqõÒ]î=c.<:NœxÏ�^O~äÖ)�¦œy~îÙ96ßô’û͇¾íµzó8òÎqä÷N"Üz^ÙÜÛô¼q} ÷žo{å>ûøûŸ0¥Ì·<¸KpŽ{ø„‡ãľ ¼g»±½Lí‹bΜv�¯8;áîÐó›—×<›gþ™—îÑ9á—Î/ùÕóK¾â섟�ð—×¼u8’ræõ“½ÎúŽÞ9®bäñ8óñ»·8æÌœ ë�·øÀÉžïzíeÞ:ùÅg8�ïyÏ+äR¸®ÍD \Ì‘�ݾÅç¯ü ·NùØfËŸ{ø�âÌ8ù�¿ó¼ùð“üÑoûCì¶�›Àfȹà]fš„˜2ã¤�Š⤤Ñ×äâæŠRǶغ!`•6/V"Ölm‘–W¯wíØ¥u®¼°Ü´w^%M7–Úõji¯_¯`/þ¬1�66å½WëËapì¶ž¾‹U³î9’›;HÝu´oŠ&áA A2�¨•�HRô*Øqcmz­Ìç5^a†|°¬'ZrQð–\q̶üu>Ðé~#I,ÇW¥lðBèTÜã½–_HpSBð™„õ-Ç�ÿÒ›üçß÷£ü̯¿ ¨yÇïÝløšaË]·T½yXz èõkÙû.p5Çö·Á¹F |éöOæöbï€5)4RàæœÑ[çÜ�Þé…9wã�×Ä”,~6)@œ#ÿÒÙ¾û䌿òô1oLJ¿ýðs<|ü«|ù{?ÅWô1ô[ޏÊ~;ó¿_)Z¥Jl?• JéÌwâl6aYL+‘\Þyœëí[àÄ\‡·q¬±¨Z褔ZN.bqf<™æï´a·S[!'ZeD"Z… ¶q‹öDªÀw±¹\ãXqk¨ŠÌLy(úÝÀY>\×GÍ_æ8ƒh•r)¾ÅØ©X,oU %EÈ™(‡W‹T� ôr»ZÙlV<¶0ŠóJ¬x¯àÿ<1¥LGâaŽÄ” –‡:³SõkbÔs[’Ù¤FœBðÖo­6¾/fç”u=tj_:�W8×3 gô]2»XmP-ÙÔ½«�K&§H¶X|�Òlü×LÓ59^SòDŽ)��³æ“Þ5æxqàêúˆó‰Ãñ‚¾÷¼öêËÚ³18ËU E;ÆÒ Ý0�Ó %ߣë.Èù’y:’æˆ÷‘.ºÞsvºãöíS¦iäp˜É9ãL±üðp}äI~Â4^1¯n¦óŽÍ ÕáÁw®�\ŒÏŸ3”œØo{v»-''{Ä Ó¨ÍˆóçÌqJ<{~Å;�žÐ[úaCÂáºï@Šžc�4b@1ÀJ Xæ’Å£¥©Ñ�ý-—Ô¼ék8\›Ñê QB=±ž]1¿ÿÄṸ:pu=’²'ô*ìB‡/ f›Cš$Pœ×üµ†ÛÖ_§íúÙª�r�(Hg¼âõŽw7ýà1\Έ¬¦@�¹‚¸úÙ³Vø7ñ¬ÈZ[^’uiÓãÚ¿c�gÃ_p¸âq¥0#ã!’æÚc…ö>±)¢õZ¨0^Ú]ã§*GÕï¯U™â3ÕjGj%CÃ�ŒñFŠg–U®Smr[�û»Z"JSh×cW í&y[7 ©¤áB�Ø+5§,-sNÔEÕγö´^1b$`­À^’OF@É ‘¬©ä‹}躋¹#èø¶1âDÇ›.³:ŽnĨŎU,—Dǘ‰ã*öV?W; e�}°Zþ½Šï^|qûÃ"T®‘i%^Œ’y1ž/z‰cäA6÷¡b¾]/i 8ò4�“U½'|¯½% Õ’�ÅáªÒ³"¥:‹ÔÞ‰Z÷¥=Ô ('[ƒ2Ú«, ¸µj 7ܨZ¤Vü4ç¥b ö\Õï^÷d×¾eml\ù›d—�¯Ð::K¡éŒJÖdÞg¤S‘–7Vï¹Ê¸Ë6ÖR’†ëØã¶ˆÔ »¤k¨Iq«µuLTAn¨�4N(fÇ—­L¹d€¤�ê5Ø ]Èl|"•™œgŠD-Mó™™Bœ“‰2�‹0fÑà£TË”Œ h‚+…P �ú l‚Ðù:ÀjS�y„rĹ‘®� !‰•D¹ê߯l*sš”l—,�ÑAš,a«ÕCŒISÉV¼¦žM©A™�ý™¥JàïÏøà~Ë{ùxêf®WÏ{v[Þ³ÛRP[Ÿû›ž�îm¼ �¯5 þÉ4óæõ±·»ÀWß>ãv¸Š‘ ŽßoÀü¯œ_rH™�ßQû¡_»¸âsÏ/øÖ—ïsÖç襂j#÷�/Ýå4xŽ�Ž#_yvÂû÷»Ö øîßáåÍÀùùÍËkZ#ä÷ì6l.cäwÎ8¦ÌuLüÌÓçüžÓ¾þÞ.æÈO?yÎIí³Æœ/8—ÂWÜ:ååiæ^¯}î=ßóÚb.üð›ñNøŽWµgÁÏ?=ç2F^Ùlxe;°õjír« <™fNCàãwÎxi3ðÙÇϘKá›^º‹áGßyÌÓin��?÷ü‚\`ʪj9é¯l7Üé;~çêÀÃqâîßaë¿uyͯ_^ó¡Ó=Ÿ¼w›_9¿äò8ñ§î?à/Ÿó“——üØÏ~–·½É¿÷/ÿ«ÜÝ ºÏ”H¦à»Ìà!‰cœ;B_�ka¾ŠLEAéRT¹ZlV«B�uÌÓ¾.‰YU=Nõ׋ÑrµÄÂÙÒgÉ_Yª¢j%¦æ-9Û7@P4"÷ÞÖ?SôäjWd‡)¥–/â ý“Én üódB�Lï:º]6=HÐ9˜œ½':µ Ê®$b™µÊož!G6] ó? r0›Ì$˜–­{Ï O2‚0 ƒGUMÈxr(1Ž7Žvj<…@.‰,é2õqÑŒ I™5�uV^m/‚ט¯¸‚K‘ì&2#" Ÿ2¿ùÎÿåßüi~賿ծÆGû ߺ۳­Í怳.KiÕ¸;ôµøoNñÁì1E2-//y&ÎWDïHqGIÞgÄTê¥dÒ<ÓHÊR9¥Lx·ÕÍ\9"åš’¯ÈñŠ�Z–2)‰åU�æ³8˳=%Î\<xÓ;~éΡü6wïÜ{©çôT89óZ© aÂáö‘»¯vdHiF8òö|ÎÕõ Ž~ã9½ÓqvoÏãG3×Ïfcá8:rô”(óLž"N&‚Ïl7»íŽýnGð'L“c<¦1s<8[ö»ŽÍÉ@ñ[޳ Q«Tˆ�2 ×SäjœyrxrìÙ… {·Ç—7g:—ñ’ð%ë.]sø¬Â¿b ]V AÅ*b�‰]+A¦iYÑ\2UQ€ÓÇͰX…¢9�J Å^‰ŽÑs�<�„Áã\¤”ƒÚéX…�(¯"-O‡JÇÈ™QûŸXT ž4KEóŒZÙ_-®×Ie³�³3,ÃÑî6— W© 8ÔJÚOW±%©¹j݇ÙÅÔóbØ%g˜'׬NRÆú�8RZµnmŸ“%α|«bÚ?ÂDÊhL$Ù-ogáWö à«Ë„N[9Y´óƒ ©æ8Ê|4¡~RQkÎUäWÚçkI•n$€Å�†kaÇ®¶é5¥­XYA—0¡hCñìðÙ­„½º€¨íKźꦇ}/ýGÍ}Õ†ÚY¥ì²:ï)e©"Ua†JÊžYîˆ�ÿL­Þ·|U©¢ñd'»)’Y~G«¤Äð�Ì‚Oj lù*ǯùe­;Yjû¥åá[)­Ë !„ÍrÍYþ㌌^Í*Þ¤¤ èé}ÊÚ c˜n.ôs§{Y.¸Îᦀt:� І‘ôue,Ä)3ÆÂ! ×8f:Å—L�j%@³ªÂÑæ>D*­E�Æ)Ö› e×H€Za°& JÍ;²°ØöC£‡Š ZmîèÒ1ꉃ–[èÕvEA! ZªW^ jœ1î7ÉêÎg�T^ÁëË#Õ&¯.¶Nø%�²YÞÊ]¬”Â<áJ\θâÕÿ{ã]ŸHֈȑèJæ(™1gÆ¢¥B@JàXSêHh9¢z=UvRÿó¶¸ôNØxØè¼sÒ䩤™’GJñ.ÒõÚÒ9Å}f§Ÿ·6}u¢ s2ë.(ˆ,ÅkGöɰÌGU”LtMãݳֳj2k¾SÏ_ÊèI_#úí’ÐxÉʨ×I¼°lõ²Ö&€�+f¯$ï‚YæÐ< oth^�t±-Ù¬`rÆÓƒx[ Å,bŸ¿Ô�ì)ÅY?YHq›ìÁ'zW8ÛmxpÇsû´ãÖÙ†b ¼w�à;æ)q¸v\v™s1%|³÷$q”˜UäfX`ž°s¦œÇ0tL©0ç¨L¶+tṴ̂+øœ•ºÏs"ΑìÁ9v›Àvذí{:ïˆÓ¨ Ê112ªbFKJ=f‰‰Å1g!HÄ“T ÄH‡$Ý´*ïÀm�}Òð?WÁ„Rï˵ª :x}•’�D¤dâ<«ÒÂ(ª`Ò2䈓ˆ—Œ0Qd¦È�Þwì†�m˜ÜÈF"[¤Éƒ86Û�Ùv‘MwÔ �½£;u¸Ó {[K6žî^Ïæ¸!ì:óRï o(i€Ø“G!Njõã\dð�Í�é´Á˜×À݉6XŽœQÂ]JwÜLŽLWpõäÈÙÇæöžiš˜çYƒÁ„_,~Æ IDATZ1DS£®X¤ª«�¯w³ «{j%jÐ⤖²€d -µk3`ÙHÚ²ZØ5F0¥•ɯMqI- l÷0±üÍ|VõÒ/k  D­)+ÚA*�\«Ú}µÞ·Ahjû‹³k�Àò<Ú9­7ObÑy®ž[³ìúªv°JÔgÛ/�ÐX7«O[·Õ¥‚bù›/èi'¿Ž_`€yPOÖœbSO9©�³jb5—®X'bS‰¤D 'g͆T±#õ# A{ìtbVC¦ð©ÁªRrµV—•zIlk-Ëi-õ|Û¦RÖ�»Õy­€š,ç«ÏÐ%KzÞ]Š*â²õ[(Fhþ¢£6u[Ô†ù/ÿ$ÿîŸü~ž??¶+ünßæ_í5μz|?Ÿg^5 ùé4ñ“�ŸñM/Ýct>ÿÎõï„SS!õ�³¦’MñþúÉŽ9~áù9¯ïw|ùÉŽR Ÿyû1ïÛmù˜Þ ‡i‹¾üdÇý¡ç$x~óòš{Cßì…>óö#‚HëYðËçWüöÕ5¯ŸìØxÏYxm·å¬S+‹Þ à•—ØyÇçž_0æÌÇïÜBÐæÂ¿suà÷¿ò§]àÉ8q>Í £*毾}Æ>xGžL3ßôàA¤‘_s篟ìxópä7.¯¹Š‰×¶Ä©_úÖ{b)<›f>qï×1Ñ;úß¿ßñ]¯=à"F>óÖ#‚s|÷kÈ¥ðè82—Â!%zq¼ïdÇÉ8ñêvÃçž_pßüà½süð›øƒf7ôC_x‡)g^úÖ?ÔêÉ8qoèùÀÉž;CÇ÷ŽOlwüÅGÉ¥ð_xƒ?ýçÿÿé¿ö¯ð‘×ßC.³‘pžìÙ9Æä )bä£�¿býzÕc¨&xÚlÓ(o º¤T•—¤¾P èj�µy’6RqE¶ªâÎ�©â­˜¶4Á…³d18Gïtœæ¬~Ç©%ÒH]¢ëš‹Æ™vYg/º,ôÞ1ÇІ.ãBÖuÉ{’sDß#.(H–31‰ò‘ñ„®3b "É)áGB­f� é²VJ…Œ l;òà)Þ“ýÀL†iFž^ââ„JU=%;rñ¤à¡Ó*|Q¯ã‘œ Ù!Ù„ E•´â3.h΂ϸd¢ 2suù¯ÿÆÏò—ÿö/3GÝ·øÀ99ãŽó¼w¿å�ëC‡¯cZí;º[TRàEz°¯Ÿÿ¥Û?ÝÛ‹öAkKÕ+öÁßúçR(«¨¢”òE¤O}ýý¡çÉ4·ã—ûXø÷ï½ÌÏÅ‘|ú„ \]=áïüïÿ¯àëøºOþ1 p<^1Ï3)Í`ù-¨H,çu®¬DU€x¢ôÄâ9LóÈf³a³ÙàÝÊ•YæR¼$M—xé,%�jM�¤ùœ'Æ| 8OpEsFJº"NçdïqÙ“Ó%ãX›á::ïé¼£ =¡p¾×>~C×mÔß°€UEdô³‚BݧªRQ ØTÔ�>gœÓý_-˼(µŠÐz5˜•�6MtÁ[ÿ‘jÏi ¿8ía”½ãA´g‘¯yr•T™PJ™(ùHœFæc$ÉdUßÁ(OA‰ƒ‰ÂD)#9ޤ8šÈ\ãzíõ ¶ äf­,¢ëe,GfWˆÓ޼éÁ¼éSΤùši<0ÇKæt…¸ˆ¸HïÁù^«Ò}&—#ä+%Ò5i>’òLIf•#æW)=…`Î@Ή‹ç…iDžsqYxÿnñþéŒW_Û²=ÙR‚æ'®Ì…~çèv60Gæã9�_’ósÄ t›»³ÀþÖ–ÇÏžs˜"Ç©pœœZd&¡Ä‘™‰ý¶;a¿¸uºg3ìð~ËtL\\˜ÆDʞݦ'lNéwE„㬬œ2.yJ \…‹Cáéuàé±#o7x·W±éœ\¢wQ‰�’qYp%4…oÅrAíwJ!‰Wa…ËVÕ*ÍOŸœp’Õ>\<‘ ±ƒ,©S!¹Ž˜z¦Ôq1.&Ï1:Â6z‡øE«.æ lí3 É;²ïÔÈkŸ2ÉæˆLIûD•'�Ù+‘§Mi by„æ}9†”ÉD¡ÅGcÖêˆ\•Ï5¦pbEÈKnZsK Äì¢iqKµ�Îí}«êÙÒÉTˆyQÜ/PbQà–‚Ò¤yE °.œa)Ðä¢$].E / HXˆ Óà·õ¨‘ˆÅsÖ¯AB³yIIí]ªˆµ5KgÁZj?V=&¶sÜ„Ø žæ‹PœT=Ɔà�hø™ "®–ú.¤Fõž¯˜«Šuk\©Ä@IU §ùj(�µ•l�fÄR{È––› ø²RÇ—ªW¤µ ¯°`µ"¨’»×1±*A(ÕÒªV›Ö]Ø*Ãty;c²àÁ*ž%íÔ£ÎU�”6^Ý?dùàEÄÄåJÌS L  B> ’]êMSÔ à¨ñiÍ·¥6g.6v’#�™i‚ÃT¸Îp]„©ô¤²%¦¸ºÏ7œSr Z«Ë˜¶·Ñê€ÚœØ®¼¾ÛÎYáÖ¸Æë LQ¡='E!ŸåÚ²ú—!Uâç=Y*C]YCY© +( +¬@–ƒ.^Ý^ ½õ=¥áIÒžRýš–×-‹GS¥;Sj H\'„ »™…P2�dó5�ä21ÍZž™ÓD¦#x¥^sŒjp–Î A:z¯=úÎLÍçh ÅḺÝsV5D×i‰bîíâ͉ÕËMìWb@ý#Ùð/�’SHL>3úŒ3£J¬%¨<++Œ½hcËK›`×.úš�+ë» ~¥N¬z ìÕ"Ëï,�í ÉÓEаsc³O»º¦õî½,Ìk£)ÍO«–_•Uð5ËÛšºÚx .¼°Ûôì7Ân;0X¢¾ HðЫê/¸Àì’êQœ°é;JQüì´d9Ŭjß%Òœ(17»˜ínÃn·%•H&‹êé%8|§Jàb ­Êð�ÐûŽífË~³e;(1�º@ìC˜¦žqNŒ³–¡:§À"b@…&ÁCoþ€©©2+`�RQËï,UÌh¡.ˆg@f¯´š›Þ›JÒÈ7 ª¢Yý¾(ƒ©%¨�³’9�”|¤XКâ%%]1t»ÍÀÓgϘ�‰ógG¦y„â ¡c3tì÷NöûmǦxW DRæliH•8;Oèºa‡sº‰—¹À1Q¦‘<Òq&ç‚ój7!²azB¸`ɘ &ÚNä˜8^\rýä]%M¤1çÂ4EÇ‘d)&ÉšŒ7 i]§j€‘›']%P—æÛºvyi…­Ô‚¸e¾ÙZˆ5±öÚèY|Ý€+‰gó"§••P]¯—5º•5ÖËY×î*1n€íu½/e‹—å¸}e©{BF«ÈæÅßÊj´-dâæ(¬Ûi¿ßÜ?X=þâ¿Êê‘ÿ»×ÿn�ýã/«ßͧ³m\öw§ß×Y󹪀mkV•ëKѤ£žo;®Væi°/%Ф€©ýUq§cAKŸ[9êjÿó‘s¬È™¶u¯ÏÍ»œ; z~—Íüæ­}=DƒÒ‚î:\UU(OhåK%àáà þ�óoð?ðsíÐgÞóoß{ÀëÛ gÖPøá8ñÌ@h€Û]ÇWž�°ñjw À·0ÿÆõ�9¾Ü*~ûúÀÏ>yÎw¿çe¼sÎ<ŸfØ×¯"|òÞmnu�ó9ò|šùàÉžžìytùì“ç|ý=õÈ¿Š‰Ÿ{vÎGn�¶/o6^ɉ«”øš;g|ðt"üÔãg¼o¿åëîÞbL™¿óÖCîo>uÿϧ™'ÓÌ×1ð¾ýN 2œã×/¯xu³á;_{@áÓo?‚RøÖà>zÊ£ãÈY×ñª©ý÷]`çÕæç¬ëøÚ»·¸¿ÑfÃçóB"üÄ£§¼}ùÄÝ[|ÙnËo\^ótšü‘÷î·ô¢ýîõ=ïGžN3¿ï¥»dà�ë#¿r~ɇÏNø½wnñ›—×üÚÅïùŽW_â:j¹xçT¹ø8Îüž³=W1± ž¿ÿð ¯nþ૸˜gþþÃ'­ßÁ˜3?ýø§ÀŸyïûø3_xƒg1òôâ‚ÿð¿ýïùwþùïá�|ó×ZåLGÏ”€¬{ñÖ%n0 j)½À&%Èêa[K{‹�õ,¦ÆPè~ã¬Ú§&ÒÊõKQ!—ºÖÛÜO7¤RTÍ,ñ&ˆ›ë¢j.t=Oe¦�È%Zâè•\( ¡ßègQ_ýZ$äÍBà û„ÀÐul†ž¡+t’�óqê•<ÏDkÞ™¦‰4O�&\‰ÐÖ� jJ´Z7¦#)^“™)2áµÚtN›(jµ™®�uÝq¶G8ï ¸f‹ AðüІ)3”Y“šT]²6fϮŠ ŠK”2Ã\pià?ýküé¿ðc<|z`'ŽoØîøÚaÛV²Ï_Ú\÷ho‘z{ÏvÇ…�܇À4-•_ªøÿ×íEK§õµ„/Vÿ¯I„Ó.p±"^ü÷ºbàhï3æÌG\Ç×¼üíù~ù¨ãå7þÑOñÆïü"_ý±ïâ¥_É4Í:vŠ‘R«.õçBèA ¤¢ôd9G ™yžPB¡0GÔ*Ësuuàp}EŒž’„Np®0χã5)%ÀB`u>ÍóÈ4��GJ.„ÎÓu½úî¬ÿ@aN#I“¸Éz ˆ6!vn ë· ÃçCar28_2Þ‹ö6­ RÁ¬\u V°)#bdDÑ×Oc6�Q�•£† =eÖ˜7Í9«¢Õâ.ç !ˆWA•ÝÅ¡¶Ç5Eóq/E…mV-6{!ΣZ§D̉Ôj°´°A/æ^ Â"oë½àÌfM¨G…o1©í�*Fa®èº‚ßÓu5oVð{š&ÆybŠ#¡Ë&x,xoßÏö†”4™ã¬=ÒÒ®…ó‚�qzqJ¦ \]xû­‰”Ÿq~W|Ì ¯(¸‰U‰lú-÷îžpþ(ãùæq"áxuàÉãÇx¿g<ŽoíÛ³ªrE¬�/ܻƫ¯Ü²ü¼çp˜y~~Éázf<¨�Tßy|ïIeæ0ebÂrAÊ”ä8N‰Ã43'­.© äb€mʉ˜#¥ú­›ª]áF­úmšá¢yY.eÁ,vÍH&fY‘Mµ=g=ÆœÇ ŽãLœ­òO½’2Û(ío­p!­ƒè—²BötR輯�…ižá –.SJéñ®è†§æ_è\G'ŽÞ%‚Ç{ÛN¢nð•H%­”Ý9en�3°ÑÒ¾˜›ª@«/”Ê,©�J$JG–Œ çÁ%#4ÔΩ²°P´'µü+7œÇ5Òf}9B^‘Í— &µÆ"/\BU¸. Ÿ[ò¶P咵ǥVUbW¬,¤ÀÒ AÎRÄšÚš>Ú\®6ÇÈV˜WjÓ�ÕØ©F‚ÎYÿ‡Î³ßzNO¼ž¡ Á*‡§s çìœ ô]OábŽæÈ'ÅsÈ„‘Ý0pÜm™�™‹rÅ<Âûœsç¡»Ù¤Hª)‰"EJ¤f‰’(Ñ’ypd$0 'HÙAŒØ‘aÉŒÀÃÇN^† 9ȃd+ˆDz5ÀÔĘÐLEI‘lÎì¾}ûNgÜ»ªÖZ_¾µªêœÛ­¼Èyânì¾ûì]»v køÖÿÿÿþoÜðÿK¯<àf×òŽ«¦öRæx=³êØ+…xŸ #ûÁó=w̆çw‘`²úôÉ1Ÿ;ÛòÜÞ 'Â*xî¬Z6Á“�µwüÀ3·YyÇÎÎQ„¯»b‚?úä˜ÏžžóÝwnpµ1Ïê—·;®w-·°,ÄŠ·ÿ6%Ž†È·Þ¼Æ¨¦Æÿ­‡Oø¦Wù†kWx4Œ|ìÉ »ƒÌ×_9@�F„u¨*§)ñŽ+œnÖl‚ç·ñƽï¿s““1ò‹÷°ÂT³às§ç 9Ó§D�›«–>g›†/�ï¸Þ6|û­ë„À_y@Ì™ï¿{ /ÂϾô cV;�®å^Qƒç1q{Õñ¦Íz" ŽÆÈûîÜd<¿ñð1v_õ€w^=äãG'<êxËþ†¾¤Q6 �‡±d1\eQ•¿|ë?ùäÝn‰)ñ?þÔÿÅË�ðÿã?A·jIêØö‘<&FYIÄ·°ï‹ ³ÏfL™X¼–¤ÀãB ¸BÄ/i�Ëm¿òø£}\Vÿ¿Öã2QS×+ç& Œ\áÂý:¹”)Pÿ"‹ìç›Àãaœ¶õN8FþäþίòÜg›3ðå·ë§¹yë«yó[¾‡œ„œb…g`­pSx™³kPðÞ‚#ªYÖôÛÇ!e 3±Â8ÌÅ‹cG³Å±Œã†Ðô€Ð÷=1(Ñ„&γj:�€àÉqdŒÕÕ] ¨¶>"-ë½}¥]­1r —ì+)ªeoƒälš‰ é–i¥Ù‘"ŒC‚,4Áð%ÚØZ¡@-p¦jñ|Yk[ 5Y«‹Å¶ WÐ{l(ó€[GÙ…Im½#3h¥D.Ä€sï&(yVÎOKÆ}5•¡ŒÓVã¡|§€óÙ|*©Y­Õã—:WÌÏj¯mÓ�è@çóª‹[¿§é9µãWJÖE^Öþ¬Ø“�û¼f_ÄpZk%k˜ s2]› ÈÎ…�g,Ô0Tà Í*'^X® X� M¶¿åoR@)®0µ7]\ÂO+Æ:¶ˆŠ1WÈ�‚U¨e> b¿å ÂiQ¹\�Ûs¹FžEiÊL&,�©n[ ÷Ur¢Æ�õx^ký±Îª šÑAɃ’{%� Q©VuHž]t}.ø¹8Ø—¯äGe·Mì¶‘íùÈv9Fvƒ”bÂ…ÖZ[cI ”vXÚÐ\“Õ°g%O}ªöt—Ï壎eÕG‚¹çNc^½ÆAtÄÈt×™Z E£[ܨz_&b`ñ�\jHõ¾.o§V ¨~µìYN¾/îi>%™� Ì'�™Uóm·‚� °Rý EÕ3dO¿ËH Jë¢ \�@6Æ)x¡m2�ÍbGS1Ú:(LÛ<ÁUOÄlª_9©#Nxjµj»)&bv êŠ=’G¶¦²V’RfˆXñ%; pÎå>•® @:÷=fVE,5ˆ¥…I½îblRùM¿ÊtÓÌ_w&f¥~½ßvœxžªbSêÂ|• ÐR¯,k‰à�';¥ JJ¾L2³»¶˜Ú@¦xG,]ª‰Þ[6+ÏfOXw…ÌÓˆ&~J?„ VÈK[[lWßÚ¨eí ZtÌÁÚF �¢µYï›=ÇþÆÔç>8úس…1%RVÆ”c‚ìÈÞlš¼ tMK×¶´mC,MVrÂ�wÐG»T¦Áb7Dú!2Ä̘2]̬£æÑ„ É,ŽrbÌŒý€¦du Y%bŠ=ï� h»ÖŠ™yo÷1gB°úA<¡ZJÉ 1±<1Y¸®ZÒš¦@©Qs% jÇ~r|J�†@ƒ—Ž®[Óø†6xºÆÑ.#:𽕀KÝ‹j „ª®v"¬7¸›w­ÀkRrö?>ãôñÈÉã‘G�zÀÓu�ïð~�¦Ý+ J0˰hfZ)f†>Ñølõ!RÀÑ’³cÒ¤˜T¦Àä=�uó`X[®ÕÄH%(( B1’ËÈ›ªT± Â ¥˜u!ç\À�†…UŒµ]§®,ÈJ&A¨‘$J½7ÕÊ¥ÎÊŠ¦9¨·Ôì¯:/h¶ù ¾¿˜�´Œ‹A¾•Îs„²Ü`ž(dñËÇ¥}UFû©M.Í7¾ózû²»ñÔçzù^óQƒ½úçr�Þ¬áŸÍsŽÔÕ ¥ÚvU/@¥"•ÓY T ª© ð4è–ƒlžœžóñ] ìµÊüº†Ó)O'¿˜ë—AÛSóñå ­ü^�¿ÑùãÚ¦¸Ð‚ ©Ÿ‰õ‡¿ÿ÷~‘¿ößüKb±ýX9ÇŸ¿{—÷²#Ïî­xÔüÚƒÇüг·M!£Êƒ~à™âÉð�×®ÐySƒ�Ž‘7—'1òÑÇÇ|cQÍgU>ôê#¾þÊo.Ù‡¥È0Ø<ûõWyëÁ†¬ÊŸòÜÞšo¼~€_xé>W»†o¾ajÿWv=g1ñ¦�ë[ö7 ÂÆð¸i?ôÜ<ðëÓ:Ç»¯Q ÿÝ[ìo*1çX9GTåjx÷µ+ÜèZ>vÎ阦ŒˆÿçñŸ?ÛòÞWyf½âs§ç|ù|‹á檣uŽ›]Ë�Š‘o¿uÝ<ÕSæ7<à…à ß}û/�où�GG6�ï¹s“¨JÍþÌgýk¯ЧLç¿óè oÚìñÕûœÅÈï½Ê¦Ô;PU~æÑªÊ›6kšÀÚ{œÀ~¼´Ýq­myáPxfÕñáW1ªòwoÑ8á_ù2ð®ëWxëÁ†ß}tÄãÝÀ�ܼÍÿqü„_<:àŸþ›s²Ýòwÿ«?šIÃÀŠ ‰ÍÆÓuk‚ù ™šoL 1£2Ž™1*CT†˜Ù�FŒI³”tÞR LÕˆ`>Õ™”üžL.iÒN„uçYµ&~pα‹°ã,²RÅ‹�Õ•�ÅI’¼FRÉàu¾Ä”uI®ó"(ŸÅ­Á¹©Hyì=ç P2.+>ƒK ÉËæ4šWvާøÎ»^ iâT£Vb13ú‘ܪ‰Äœ‡•·z*œ7+Ëk—ùœIvA õˆW KµÄÅ«º`ó×àH¥Ö�Á5iÌÜPJÁ=ëÀÙvËßþ~=º_ IDAT™¿ÿ¿ü*c4àð�ÝŠïÝÛç�›=îŸï&ïùGýpØßåÌ®�‡%C¨>î®;îï† ¶Ä:¹0Y|…øwûøÃH�Ë™— ï.}÷BM.†{ÁOõ%Àˆ�qqŸ“êRæL„•÷ŒãÈ_½u—ž�ð+§Fl?xõÓ=ù2_ýÂû¹~ýÍ%Žªz‘ªuõ”j³§. â™|¼Õ¬qã8”õ„Åœ9«�=ÉjÄiÙë¹¢˜§yN OŠ#d5{¡`Å{É&ålYìdìïi%T2‘\Õoš�+ëXÖlvŒ1¢@Ó¶x´€æBðBÓxBhIc,Yû‰8ŽåµÁ|9š*Óù`™Ò²Pèa’Å/ ÍqVYÕÛØT�)Y<—6BRâ�Ñ[‰)óŶm»V9'ÔµF@¸Œ“hµrÏ8ìˆâhBCÓt%óÀ OçdqMÎF²9‹µŠeì¶çl·ç¿GÛuìëaÚQðA ÁŽtwvÞDbHÉjXˆóøÐÎÉÁ‚‘JMS|ÅÕB2WÖÝÀÖ91nIqDÓÈã'Üûâ«Ü¼µaÿÐ mºlí ˆ6 H‹FOp×®Üboÿ^N�ÏØíÎ8?Kœ�žš]‡DT"W®¬¹}ó* ãpÊùYb»xôøÔ2±Uq¡AB ô9’LjOVÊ©àÅãŠá…fÇÉnää|`7f³²Q)5Õjâi"ªeì©ä PkÑL¢Ö*¬5~3·’æ!ªN:œ©m6üѲ …(V…l•í6Òï9�ÌŠ+t@ eg~ÿ©ˆªhØÅÄ6Uh¥krëm®Œ�«i0dÃ7g8®'+)Pã�Q4´’:«ø³\)OÌ`Íl2¡œ§q�Bèâ�+ráj;«-¤([ é0M…sæ—W6r OiÒX'¶Jí60ˆú¹©IÆ»X:ŠG´™+ªŒðÁ—Ô;›|*ÃWU[†Ï‰±¾>‚4eKL‰>{ÆRlxm±(ÙÒÓcúÄYÊ€–>6%(MŠŒ9PþvuU”3ƒ4 ‚‘9§ù½2=M ,ïp h)AmHË`U µÆh¢–f‡R€}­¾Ú19ó¹ÃÂÜÅŒ6courû~Žõªå`¿c½‚u­7fØiFr"ˆ§+|¶°‡Æ—Ê …ØIÉŠfV -¯–¢æœ1�±QR,Å{EØÛx6OÓ64m`7:ºú˜c¦¬ýhrdg Ó&4F 4 m-ì'�Ê¿ñ‚Hƒo:\ÓZºaÊœowœŸ÷Œ)MõRÆŒ˜éc¦­ Ð0ýNÙê€æˆw ^šIq‚¥¯× «UW”»Š>„†¦mè¼§õ6¤¨f¢*QíwüÎщ1 ±´�R+ÅvGƒÊÙ3 #''§4®¡‘–ƒ½ÀjÝІ†àmëhƒXmµì�ÕËÈäâ‹X Æ z½9dÕ40Œh9989>ãþË'¼roV¬º5nµ‡kšf âJ Rú~ζÈGŒV« Š:¹A´#'a«J@KŠÞœ–ya›Y3ÐZ8{fø«×»+VB: â -™3H)î­}ï�yªw9�…®Z•M)VB-hkEáJÀSïU™ü%b©Ý–º0O¸…uœNÁ•±ž`1h¹(u,¿8`\¼F¯1,åj]˜=–ŸÍó×ÅoÌ?¨‹-åÒë×úí×ú¥×zÔïÖ©¹¼7íòÒ| vá"¢·ø·.\æXI ™Iài³˜ÚŶŸ÷ùô´ñ¨çÏgìC˜³†.ÏÙ—ÿ¾üx�ß¼p™KL¡îypz6ðŸýç?ÁOýÔGøª¦å mËŸ{îYÞÐu¼xzvá2^i¾ãÖuD„]JtÎñ·ÌÛÿÅÓ3¼_U2>}rƧŽOùãÏÝ ì\‡¥bQxÿ�›tÞñx�D(ÁgOÏùØÑ ?ðÌ-ÖÞs4Œ¼xrÆA8,–Ao=Üp2˜¿çú5ÊÑ0òûG'¼ãê!ï¸rÀñù¿_}Äó›5ï¾vÎF‹AÀZÐ×^9à¹1âœðñ£žß¬ùÀ3·ÈÀϽtŸ› â‹�vœÆÈÛ¯ì#"\ï:Ncâ (Zo¯:¾ýæ5®v-¿þà1|[¹F¿rÿ!GÃÈ·Þ¼Æí¢è?‰‘Ó˜Hª\ëZžÛ[s{Õñ…³sŽÆÈ÷ݽ…wÂGŸœð…³sÞyõ�¯9Üç“ǧ|é|GTå›o\cÏ{VÞD 1òîk‡Vß)%>xï_s¸á]WùâvÇï>:š,ƒÎcâAÉH…x½¹êrfí=y|ÄÍuÇõ®e<ß¹]óÕ·:þÑ«÷Qà_ýÛ�ðøäŒð—ÿ,#‰ž&mÛqãú>û{ä¬Ä˜Ùî¶»‘qÌ £ÒJ?*ç»ÈYéÇLŸ”!I©I¦ É ('Í(®Ô)ðx¯e®Êd'ȦË쯡m=mÓX¡ÄaqÑ„CŠ@Bñ.ZýßãÔ ùŠx\ÈÜ·¥rÊom[x[}'¡ žÆûRœ^ Þ™M^Uû©âÕÊÞ™m]Œ¦FÖ< ’hZOÛÈ”}Ðø„ó‰ì„±ŒÈ>Z‘FÛVžÜ:³–u•TK™9QÁæ£ ÐZ¡P2ß@¥>�¥>ˆÒ.1Ž=ÞyÁ€£¦µ9%'h=ÿò—?Áù_ÿS>ÿ…GÜò�ÚpÛ[}¹XUk¯ $7Îñ¦ÍšOŸœMãA7§rpoÛ_ø{iQó•L�·�Ö;†ÅõuX¾œ)ðz…Šáia¬¾K}œ_²Z’ —Iƒg×+^Zd•œÇˆbÙßÚ®ù–;ûüϯ¾ÂyÎŒã–�ìg¸ûÌ×óµ_÷� —¹Vse•ù°rS�óHÊ£‰|R&Ž=»Ý–mMP-MSAÕ²Œ,$³àAÕ¬mrʈ ÅWYMCZ²sU)Fó9× ‚¤imé\ iŠÏq2b@I¤4�¢  úa°Ù_÷�®+‚_ˆS=7mÃ�3iŒ…ˆSö-É™hÅ;�ž\„A9[ñø)Ú.ëÅe¼£e�^¡:a®Åµ´�£~C±µ ÕúMðÞ‚#Ç@J£‘·¾+0 !2Ž;b´µ|Ÿ•¦éhÚ/ÞTéÙè„ÄU)Ä@B1°ÝíX�ŸÓ„=Ì1­£ë:BhG;X]9ó�IŒã¶¬"ãØÛšµìigmÁ"Ö{Ëúr2û7ñeÞ*}iìg§[r‘¡>yõŒ{_|@ã…õúš)‰s*`€J СÉÓHÇÍkwØ¿r‹“óÈÉñ9GÇ=§Ç=Coŧ­@ýÀá•«¼áù›4!3 §ŸñèñÇG»]i 1  )µÇ ŒWÁ©7V kàt;r¼Šª¶ÕŲºÅêô9‘ ³t&°¬–­Ü‚Ì[ˆ*v¾ÞO°“Š‘IÍÒVøY¦d $q90 ™Ýnd×GR–RTÛêt(ÞÄÙ½šyR ΆÄù0N©„@P™²æÌ9O|&U›� 9dBu™ N]—V3ÂjMRTý%&I©ÈD ØT^‰� ï/Gkˆ_2 1�jèÚ{e>ŽË‚SWÉ�BDÔÿ̆�É")k©W2‘öyÂ‹Š´$±¬½4ÕGX®Q¦Lj±‚Ìå\¬ö�íßÕL}1]±C!�âŽ��U b¥˜æ¸�ržâ¬®ŠŸ�-s!Ès‘LB�1 uüÓ‰X±kXÈ—q.±ÌŽªmc&\*Ñ!›Œàl*2BUíÉ34ió´8eê\ù/¤� âæ¦7?ÝEl`©î¯ ý,—Öʯ±J£¨ó@®äºeˆÎç­ÉÆ‚¹^¢dg5üÌÅb€a†>1 †É¦Xãu«Á‘4Mý$gÃâª@7&"Œ‘’� c4Ò¼ ¤•ÒFê©/0$&« s‰YSZ<ËwçlŽy[¨¸ÓoqùûsO sb7hò¿®�xúj½ó²\Ë/NËmÀÈÜÌë&µ3Õß(@ƒ\ê¤Ó - ¶VÔàiòà®Ë‚k‘d)Æ�Ì�M!++� õëÞ3 ’Káâ…ï?j^òã8’“Õ¨�MŠÚ?ˆ Î#^ÌÛÖ˜=Ô�<¥t'æï¡kÌÓÞ‹Ýì1AcTÆQ|šÎUÕ¶~Œ4ÁkŸ™S\Kç² ³’¥#¸b[‚±g3s|[�Ž¥ÀÓÅÇÅ»_À�D-–¹Xº¼�ÿ¦ncRGän£õÞeÕÒ¯àŠOŸ˜ÿ—¢ÔöPUýUáŒÕ˜pBpе�½uǺS{¶™U“Y5�UÓÐOëfëć®(²SN :’SÆ«‘AGÄåRÜ×ßçëÒu‰[Ó6åZcçƒ+ EÁà3É™‚Зz d,xAɱ \Îù>¡õ0Úµµ‚‚ ‚¥®f5+Ÿ±®cPÖAˆ­#¯­BÓáCƒ �Yø@ ]×ÑumQ‘HÈ•¦ 4M©±ákä É*„�2Ù5â¨%7EG”õ­\M±�vÝÚ¦aÓí±¿ÙcoMZ‚ìïµlöö›�£é2ÎG{ °®i6À„f.@ÈÐdš¸c5ôxÉéͰTê&txߘg{©�¡ )™iœÇzݲÙ;`½Ú'¸9ãYц NÚ‹xnþCúÔåNtañ²Žç×5•PÕÔµ¦’Ñõ%�Ðéì!_ëÒ¦λDvuF°ý&�%ﱞˆÌc~EnjLX=©’˜)XtS `Aæ9Z)û/“ºÈ4~/'ó ç°¼^²ØÏâe½ºóëå|¥¿ôÔ]� ¯Uß_îëé¡ïuóñ.f:YåBý?mZ7mR.gÌR—jt]¥3U¢TƋמ֧†øôëéç÷&�r­Çjsr%Œí;6–]¼NËv»FÊ{s&âòÚS÷>_—Ò&þàîó'øÇùØÇîM{ù†ý ?òÌ3l¼'©òÖ}Sû9O>öWŠªÿï=à=7®r{Õ6ž/Á¤·îïqgÕa…ˆwÜ^w“BÿC÷qgÕòÂá>Ÿ?;ça?ð|Qû_o^8ØÐ�{¿ SM‚OŸœ‘Uy[ùîÇŽNxñ䌟<>å“ǧ¼ïÎMžß¬yyÛóé“3xû•¸Õ5lB`Ì™³˜xï�+ Y9#?>áköùŽ[×y2Œ|èþÃIí?¤Ì«ýÀÊÏ÷ñÍ›=6{ÞóǧÜêZîÞ¹‰~þ¥ûì-l•þÕ—_!©ò¦Í‡…Àö"lšÀÑ0òìÚì•nv-¿õð £*ßwçN„¾ò€ó˜x÷µ+¼uÃo>|ÂYŒ<FžÛ[s�s<³Zq×s4Œ¼çú5œ(Ÿ9=ã³§ç¼óÚ!_µÙãwñÅó-§câ»n_ç4FÆœ¹ã„¿òÜsü½—^"ªòáßûÿÑ÷?ñãåÏpeÏæµ®k8<ööK`Ÿ ë,ÃP³'eGßgv}âälàävc¦�J•]RúhÙxQM ˆ|c¾ÒµÛçä û)><Øö÷ëUÇºëØŽÊvÐYQV=F Øýɪ CfÛRòø×P&À2ç;$1û£ÌàlñWÕr¢ˆ²9+`À!Î  7.!|hh[›ƒ×+�sEuFD\bµ të:™/7Î[}ËÆê{Iëp­3› âò<žH«�"�€4LCA­¡àõ¹¨y­Ø0ÉRù#’ãÎñø¨ç/þèOó¿ýäoLmû{Öû¼geu^8ÜçÞv7YÃìyGúÁƇ1ç ¤XÝ€ƒèsžæfÙå/dŒù©Yþ+�?ÂÇp‰t™€š×x\Îh�›kz”Çe¡’�âÂÄ×r—oõ’æ¶Ð:Ç•&ðj?ðWoÝágÏNøðé)÷^þ}Žž|‰·¿ãßçêÕ»%ü©5‡Jߘ¦oRHyÀ9¥ ²R/ÄbOëk�ÈE…l’w�J ˆ44Íï›IyêƒÇ»’A5ŒÅÓXÑjÅ R¾_ãÜßû¦X•Lcqä"pq5tqìåœÉ)‘£'E�†¢øÖbUT”÷0‚òÓ šg­~ÑE„WjµLøDUÏP3 `³«sœ8e°W°©Æj“ œ”íJAZp6¶•X©f/:¯¬¸¨Ù9×à Hæ=4¡‚TÑžŒŒÑ²Äùb40Æ�#¡1‘¡ ¦Wc"¦ž˜z\NF;—”’ÕOs�¶µ{ )¬[WcÊ¢–/ubŒ¤adÔŠ4GÈ#<¸ÿ„O~âÓ¹~¥#lVV¿ +¼w‰á(röø”þ<2ìàì4¢2r¶Kœ�'¶çÛ]o¸‰3‚¢ñ~ÎB&¨cäøø˜³m&icVÍÁ£Î¼÷sÌEý\¬sUÌøG­ õ˜§Cæ|(êjçì~D-Ëšð7eزD'‚� ,®@©‰¬Ä9Ãx*°j7Ü”¼è¤µ´B¡V´89!bÄÀ¡›2<Þ78ß .3ô£‰Ñ )›¢Ñê�÷™³¡ÔÖpFÒ·Á@[InrŽUT‰2‹A/.-e¡&– Ãg¦ˆLµØýà31õ´“‹ Ë <ÅôU°Wz«j±g*¤Ã´N–‚öɼ溺—ËWÌfÅU`¿Ü?—™î:Tû #J 'R¹×eû²Ÿ2jL×eVkAꂽ¡2/iµdfÖ9eòI­ÅŽ Vÿ»0ßLzû²îÂpžBnä… +åâJ!e›\ÇÅ2t��½PˆäiY]Ú°â|¶§ØºÓÁr%VAf×)x“šóÀäLëÊ¿Y�ŒÙJ«àr!›ÕÍ‚iõ%; ÌB‰ÝdƦ˭ó²²xÅcµfæ%åÔhtÆêýÓO¨Z­É©ý[m c ­¡;ÔúOÌähÙÃVC†bô¤äFa1\6f«!¶´÷)q|í/ÕêÛž&–MꋈËŠËe?¥}UÎNë=­°†VŒ·ØÄO½mšý¦Ì¦Ú·–¸ÆÔ£ÔZäR§Y§N…E·or²¡P”¥Y&\hmSǵê{—¡�…¢ôõõæ3OXó~Ëÿ–;½�nR™ÀÅ€‹ãN˜¯¶-Lj•kœ$ã¨ø¶#ƆŸ=^�k,Õ<+9fúmÏùÙ»í@FR²ssµ¨œófûRHñ¥Cg›”U2Õ:¹ñBã…UëéZû;”ôóœq´”ÁaP†�~&Ù4CÊ™íàhz!fkpȧ« Juò2)[º˜”ájÑ –7¤6Ëú¾xÿ*I3Ý÷ÐtùNWb çŒW[0WU\.^ì•�µÂ¬jÁ€¸ò¯î1…¸N÷Õ¶Ÿƒ¿ùõ<Ø{]ãÙ[µ¬[eÝUR ³nÖmCŠ,Ь™b] ÆLŽ#‘ˆËÎRîQšÆÓ4–�ª” ¥m3ÎxoxlÛ5Žw¤,“eTŽJ­ƒg…8É™˜ PËi5–×Sk/ÖöŠREH4Îã‚£šfCÄa÷9e¢WÆRkj÷Ø|ÓÍä@S¼0½©wÚ¦-,½£ÚÌ„àMÝã p  âŠjÂáCe„¥ÆêGip.£¹E}$Ç‘œF|*ºUÇÁÁ>ë�¾!xÏþ¦e¯áÊÁŠ+WZB“ÆSr(ÊÉZаf1‰ƒ°²,¡F�š±g3ö4mr „´BÓâ]3Õÿp^ÐlÅ„@Óx6{kö7‡lö [�qïÖ4~ïZæIHË[Ë1ëâ¸8g Ô3ÏýhGµL‚€O®=*€Ÿ4g“Ÿ|íˆ5SÀ<%fPY˜Xw͉œ£õ7�ÔU¥2ŽZ¾ScÉ2ÁR•Þ¢ÓyOg¾ – OVfR ü;Ça56¹8ˆÔ÷'ÒàB(5ŸêkÎ1úï=ýÙüêò^.ÌëíéòïØ"S.œØÎß0•ÅœÙQ6µJQv-%Ïj‰z¢fbfHç}å1ΟsiÛò·\ú|¦^—Do�Üþ0ràòõ[D¯sõ–±Ä?ÿç¿ÇòŸþÇDz¼Ðvüׯó'n(ý…ó-÷Îw|K)Ê«˜sÔ÷޽ɺ€B£*o,vCú���ð�·®sÐƬ|üè„àd*VüÆýõ¤ü�ª¼ûÚ²š¢øSǧ¼eÃÛ÷٦̿¹÷€·l&"àQ?,T>Vïà Z縿빽êøÁgnsæWï?äjÛðÎRïàÃó¨xÓf/Â~ðÜ^utÞÀ¨;«Žï(ÞþŸ:>%ï-™¿öà1÷w=xö6‡�çÅÓ3ìž]G®wV÷à {+n¯:ކ‘Ó”xÿÝ›4Îñ©ãS^<=ç›o\åù�þäñ)Çëß|ã꤈]{OÌ™mÎ|õ+ŒÙ ç~øÁ#Þº¿áWyÐüÊ‚€8�‰—¶;DÌrÇ;áöªãÕ]Ï~øìé9oج¹¹j¹Ö¶üÂ˯Ò:áÏÞFUù×/Ý'«–,†_8/…ažŒ#wöVv7k~óáœßs÷&^„_}å!ý™çø;÷^b›3ŸøÜËüé¿ý�ùÉû³¼éÎ º®auÍ:Zœ`Õ:òÚ!Òâ¤e·3OÐuZ»Áˆ�í�ÙŽ‰Þ[ö@Ô’¶ïMð¾Æžu|4`±užƒ½†ƒ½¦Ìk+v£²­FUŒÕÿµ¼'åÄ#}Ÿ9o¡íV8ß�1£.3Ä@Lf]œÉŒq´ÂÁ9‚.ÃÑÄîoßG¶ýŽ]J ŠK�ós›u. ðÞ4Ëü¯¶m–m¿g÷ËÇ�Ýv � 9Ø”ááýÇüA<âÚaË oºÍzeöm� ŽÄœ?>çìÑ »óÈn§ qÇ. Û>±ÝYÝ‹à!xðÁÑo¤…x¼wøàˆ9srzB?¸rÎD�Îk­ÇàÛ³âÂ�v1›²¾O´�‰þTKl)‘kÁ p‹˜€^5ͨÎ8”)á‹mË”ab“™L€AR mó@� ²;!„1 Ãhµ‹œ\(ýJÖ¬²:»¶ZŽÇ7�ì ·ÊFhvFØf�Sê!a‡óóÚÝ•µm�ä.¬Y—øGm³¬¸Gýwg•×KAvûkÖMu­ª­X4L¥ÜÃ\~>�†Éív‘~é 9�iÉ4ŒÉ1&W2ŠMØœ °Ÿ*¦Y³mÔìF‡c¶gÌfוEÐhõÇ,+O'࿞ь”þRΫî[uÆ–8îB¿Ø×|]¬�™b©T6šˆº:÷•(˜ ¾€k®.þËÏ,ïÃ’¦šÞ›ÁŽ×6yXlúZ/�pJ\ØHËvK@£ª—´0»ŽÕ†çŠRù‹*\<´^�&LÊ1§æîÅ =iÌäaÄ­<Ò¶„µ2î ŽÑ¼UKÊŸ#4ÎRõ‚¥+Z‘�–ü艡t(5�˜*Àc  b~Z#è¶žOaY[cn‡Qi 8ë1XÈÖyQë”¥áØš«4«)MG&˜J IDAT§É V¥¯�jNáÒi‚t¥KY3Ðé^Ø>.Þk­Ë4°k±í3 Xçßœ|a*U ÛÕl‡ª@÷Á3©–ŸMiQVn¤¦‡9—-+#«¢4b@M±·êðu"Ѳ8vÖ9giü@»R4ZŒ¥ƒ tíª¡éS­— É�yh¥ ÆV†àˆb„=ƒK6‘*%˜L¨Ž%@KeZªé�™bèCO Q�Ã@Œ=š¼ohJ–…sB#VN9H 8¥µ ŠÆ³Þ5Œ)ã|[²Z¤Þ•R@©5Ä• Ö Mï^ÆÒçËÀ$b¿ã¡ �AÔ®CJæÙÅ“’�ÔRsqÞ y{¸qí ÏܺMVæû�ÕšX¯<{ëÆž{-¡É´)GZ�¸ÖOJ“)Z#¬X‚&Åû²Y±Þßr°¿ãL#»s†HŒçÍ&©ihÄÔSÞ[àçJÀ2¦zÉcbìGâ x×!juÎâç”æ>WƒÕ騖ŠlX%å3U%×ïPƒ›ˆÙ¢¯ÿž:š,©]ÊÒˆD`¢‡§Î;Ï$®ŽY™<ìEæ¢ò`Y#…0uSÙÎ3rO ÃKû�\æx™ÏµüÍå¿�ÌœJ9?©J®ÅØ5›ç"™^籘*›NSËkÎLò‡ïrúl9WÕÜ·y�Ë ðBHS”!¦>ªc/e|-绸WSñ¤é7ËØµ ¦ë�§¶fï/C¨¿° C.^áùJ_ 5Êgrq³×¾F:o«‹ï\þ†fþÆßü9þæßúùiN¹Ý4üÈ�;Ü ³¿ÿ³ë·º°Úï'oÿOŸ²ñ~R÷¿xzΣ~˜<÷÷ƒçZký;«œð�gn!"|ù|‹ˆL$‹'g|úäŒ|ö6N„í¹·íynoÍžµw¼÷úöB`—}ÊYñ`×óñãS¾éúUžß¬y°ëùµ�y×õ+¼qo�a¯¤¤+³ò�×UéSæ“'§¼y³Ç·Ü¼ÆyL|ðÞ«<¿Ùã]׌Døb©ðµ…�øªý=ö¼§áåíŽçÖF¬¼çC÷±òŽ÷Þ°kôK¯<àdŒ|×í¬½Ya¤œq"ô)sgÝ1æ}î®W|úäŒ]Jü±gná�ãWï?äI±zÃÞ=:áÁnà04Ü^ul‚ç° 6 GÃHŸ3ßvë:^„ÏžY}ƒoº~•w^=äÓ'g|üè„+mÃûnßàa?°K‰¤f rÏ®;†R¤ò7>á¹õŠö9G~õ•‡l‚çýwoñ¸ox~³æV×r½mxi»ãï¼ñMüõ/~�ã”øÌKùÿÆ�ó3÷Ïñ­;„=AÚ\–‚^3ÞP¼Œ8hdGçw4+ÏFcrôѳ»Ix�oÚU‡ˆ0Æ‘œLì`jcOë=ëVXw™Í*±é{�Õ£bbåªò75aΉ!FúÁ±Ý™¡]­q¡!©cŒp¾‹ìF%eOL¾¤)›(ÅRö­fÕâÙ[„ÁœzZ…6+�šNh[O·VkÏÞ~ÃÞAËú ¥Ûóˆ±l[³®´:J ¸¢>5‘ŒL™| ®Ä碥Ø\»//ajü_ „Î#D%ÍË|:‚)±;ÛòD{^úÒøô§Zîž]ãðÆÁ+{žÜO|ùEøìçs|Ò³G'‘³¡'ª7P,9ðÁæ—oÊ1ÂééÈf¿eZºî€ƒÃëøm"¦œ‰ s¬AYç‹L–ÌÖ9}Jœ�Ž]RF±LÁ 8Ñ»I,ªè›Z{Æ.§ßpVwÐ;Λ°R™ârûÇjõÔ½‚wIlß«KdJc³iƒ‰ÓD<¹|–%áƒe )`^ä»!³»Q �£ñEíÔ\– 4�øR÷¯®)ªÒ½Œe-8µñª@žH�™,©$Á$pÕ:†°PÙ×õif–•SAÒ—«ÝÒc/ô­iVWL˾­–嘥bQuÿ5ë±®‚û:}oZ;WáZÅzêšœ¹QÚ•TAôR­ \jq.¢6.{Kj\%õ7 Þ—ÊàT®q=ß©þ§ÔÌ„ ô+’óŒs+†/¤K¸\ɟ׽3¾ë’Ú¶±gšÄ¯se¹L,óƒË6žd¯xÍ– °¸4’Ôh_j5x;ÏäÁ'‹ý\qa¨Ø™ÌT^×X°ÞˆòZ¦£‡ ¬·UfY|mÃ¥ÎÌI–ÿYmœJvÙ½)øJJh©SR\•mþˆJŠÊ°+õ¢Y)V+l(YÂØÆ\ŠJÆ•¢N$Z-XUL¸“aÌöw.ñ­Ä)•ãË%càâê{"Ñê;R2oê=[|T›–Nó åÍÖq«¶“\ûÄâûLßµ# RÜ™B)¨Ò\˜:tdäÂg³*’ ï= •\ÜÂv{8`Æ$–?;5�å%¼Z6”Ï\í�™"Ñ6@·qί\ñ„‘n$tPòh×64=Œ»ê=Ñ!MšÆÈ[ùùœ&ë‡r»kÑ7/æGëuêxNzE“¢)™·~Ê¥²�Í�Ïx‰8±"Èyb¿ìžÊ4(Ûb“ °7Œ¦Nhi¶ì2i•‡2}„.¤š›Qrsš ™¶­ƒR.A¶5¼l˪¨Àçð[’·‹Xê¡ îÞÑ’ëœ1Õ` »W¥NùŽŒ/ŒÍR(°j”U€½®eݵv}ãhés©ÔRpVâÈy_wh¼’Ôf¡v¯¥é¤u­‹_làNhœµ)ÍŽq„ÁY"?e(q´ÁAF%G‚›Òä¼3@¿¶ã¤û@�Äq$ç§Bã‚ÙñK{xgVU«Æ³jçë–ín`ˆJ. E±`…MlÐÌ©’ŽàJʧ/E€%!2,ú¹±ÅNiƒÈcœSRzI ŒŒ…šu^ðX5ŽUë¸yý*Ï¿áÈBŒI%eV�g½ ¬W «UCÓÙàO¿¬¨¸+•ç+­6à2(ŒàÜ ··b½ßsxe$§œ�ž1=)FBh麎ÕjU¼DýT$M0y·Èândì�tÒaê©rKá´”âœö(5ãF§à`šÀ)*ïŠËNM3Ö9ðaV6Ôlç\Q•\MëìÉL¼Õ÷L*3MÀudpˆ5rÍhÒ’²Yä uü"�ιÎÆ,”¹nA–‹Ãðò˜Ê¤6¥ Ö a1•,ß›ˆË{ž£.ÇÔ(eñþS¿ÿzÇsñ!ÓgË—cÕkíéõ>›S9Ÿž —³£\x=eLs bršf|Á¼`çã*‘HM�&¶¦¦òÖëüÔy_ž?G³<5}­³y­ }ùz\š£eùþüÇÄ�üÈ?ãÇÿɯOï½{³áÇžž›�‘g1ñùÓ3Þ~õ�à=£*¿òÊCÞwçÁþkï';!0Ë�˜•1g¾t¶åùý=ÞyõUåî½Ê ûSí€ýˆ#žY¯Ø/uÎbä  üÀ3·ø½'ÇtÎM™¿öà1�‡‘zö6ÀäìdS›yâ¿çÆUn­:¾x¶EÞS€ú�<>âKç;¾ÿîMBàËÛ_<Ûr½m¸Ò6¬¼ç¹½oܬ٦Ä.%¾ýÖuœ¯lw|êäŒ÷Þ¸Ê�UǽmÏo>|ÂÛ÷ùšÃ}†œ9G’zS½¾ípŸóhñGñæý=Þyý Oú�_xù>׺–ï¼u�¬ð‰ã‡ Ê ûxàzÛ’UY{ǽmÏöÖl¼çîªåß¾ú'ÂûvCY•ï-çõ…³sÎbâq?pØ6ÜèZ®´ Ïï­ùøÑ øö›×Ø �ßÄ“qä=7®òìzÅo>|½íŽV„w]_sZ€·Ã¦áxŒlSâíWðGÃÈGñö«¼ãê!?:´û,ÿýý{¼:Ž|á•Çüà�þ>ø�ÿo»y|BS6«Í…Mf'”vı‡<ÐÈHhW´]7Ùçm‡ÈYoªØÐ¶„®¥[­ÈÀö<3ŽÑòΜ£k]…$Hìu#ëÆ�3Ïý”Ì>RÄüžÍ^¡5ßéFÏn0›žnµF|KRÇnÈ�ì8ÝŽd ¤lÄÅ¥� ™˜"1§I™$>㽉YBãèPº(tÁÑvžõƲ6-›Ã–ÕAƒÛwÈj|nl\pZ¦]a"q§q]æ…䤤«cU :Ëk”©bcé¨ÿ.ǧ\À®àø?ÿÅÇø/þÂÿνW¬°ë×µ+~`³Ï×\=ä•Óó ðËÙò•mÏ+Xv€+Dá«;ûûÎzÅÑ0N`ñap"¬Àñ%ïù¯�ÿÿ=.ÿ—I�Yn×Gæi ¢šùQ�ûúh½ÙvT»7N/ÝëJ L9éeÛµ7ÂxI6áB6ÁgDÔQ?ð§÷¯ò»«žñä1¯Þÿggù¦÷þ0û››“˜@Ô„gÆ�µˆDÚÎÓvÂùy&¦-Ã8ÒV�¥Zo˜`ÉÈ_Ák‚Z`Ø[F|F–§œIÅßßÄnZBhiÛmÓudÌcÉpJÅö¤ÿ& j™›¥XÇ8C‹ÌùvGßl·§x Ì E=îY­«UGJ#ý†žÝnXÔ¥Ó…Mçõ¨:Ä5xßa?�\ìább¶q6„–YŒfk�Æ™£³²î¬à¿…c+û&εÄ®‡4…œh� P¤³!´´ÁÓä`–7ˆ­éR¦¶}ÏÞ§: κn�8hÇ–q½BrB4±e‡™e‘§iBÉ–ÈÄ8 bkOÍŠäTBÕ2C†H²œ§ +³ŒË=cßs–ŽyùË_àãë3¶ç7xcƒ®rêyùËŸødäsŸíyrÚ³ÃID¶=¸­Ö;¡F²Sp†�ôƒðäxÀûŽÍzÍzu•7"ÍÉ–“³¡�ܱįEM�CÅYÝ9g ¤b`½Ùû!¨³öëJ½ À¬ú‚Iç¥ØjdÃ`‚Ó ävΜ£qF|åÒRY+O`;…bP�,¥öÝ%b ÃhÞâ) Òx«ï�Y}eU"™ �9A Y9ï#§çÃTG°sBPOÊ:æ z°)ª�SÍ¥¨ëAËò1;2{¿H�´ú–ÏÀfÅ�,s`&rÙW…eÝ´eí‹åº1ƒ­O­¸ðÓb®Å\¯u¿]`+Uõ_qß™>·sË“px^2._3nŠ]f ÊÔü3)P×hµ_-†ä}!ܲ€¼}fõª¸º:qÌÂ;·X¾‚$¸®•ª›T¹)¼’Œ9lÌO¨1Õ|®®ìQ$fÐ\jŽ(əхðJç1Õ—cµ0o^GZÖL! àY!·1Ñ÷#š­@c-<&âÉÉüŒcÔ2ÙØUQµý¥”-í:9` Y´Q�FÝyQ£S ›–qv™Ž8“3ûï\µ†°¬–)R¸Ðßêà¯E `àS�‘ ÔäéÞ–°¢(Ò-¸]fhV$ͳ‰8Dˤ:�Ÿýþ’qÖ *K­ª<˜ÿr¼S� r̵ dV‘ÎQåÇM`ÁÒÂçÒe¹Õ·µÎ˜,¦M»^—÷ñÿñ·NïVeÊ<‡MŸ-nÏt�µþRf"DK°¢¥=ÕYÛ©¢øÁS2�ê]ß+󸔀Nj’Á¥S˜�®ÑR©¢õ˜/ÏÿO�ö‹÷.üÆÓ×|ù8=éùá?õ¿ò³?û‰é½?uó&ÿÞáU>{|ÊÍÕ2Hé æïýÇž¹Eã§1’Õ¬{îïz~ÿÉ ßw÷&�Îbæ3gçÜZw쇀ˆðMׯ²öæ1;ä<©ñ�ÇÈ‹'§¼ëúUö‚ç$F~éÞÞqõp"ú”X-ò|ß~õ  U¾¼ÝqwÕñÝwn0æÌϾü*oÝß›H„OŸrü”™P "7Îq¬µwÕ¹� üEÎpúž>C�ª]»Ö^ëÿ_ë¿ø†›×(EÇó¥Ós¾âÚ_võ�—NÏù•'ϸ³xï�k<›"·#ƒõ,à­û{œÄH*…_vÊ—îsw5àEøÇ/ßç°ÓJ�“)ò“÷�ø’ƒ=ÖÞ7~0 ¦öà…Ã=~îø1^à;ž¿M~ôÕ×rC?ü˜MJ<ÝŽZ9±^ñ/=á/ܽÇõêË<˜&^yý ßþÇÿþ?þ$/¼pUíZ(ˆKª¡ŸE3¢ú‚CQ-Önp¬ÖZšraˆŽa à5ƒ=¬ºÕ@.…óÓ‘qLxÔ^÷!¨TdL�'|Ðj+ß ¾rÑ^ìUr@û…$tQè£úG]ß!>�Š'Œ‰h©SÓ.Vù‹"êßicÊ„—Lñ™Ð)!Ð÷^ÁÅ’é“ù+ÏúÀ³Ø;ò ‡ŽîX%2È¢É(s€\4 ®„äÒ×·µW–öaÇy\<õt›}¯öSeQZ³Ëœ8{¶á?ùOÿoþ×ü9öœãƒ{|I§}E>ýôT“-йTÁÙÁ;nAW·¯¾~…�<|2Û¤i".Àâe¸­h©ï_í:žL»ã_Ü~g· ´@.“2ËfЗ�ÿ•s; „—Ÿ…70¯‘G]Ø™ Wúž§Óذ˜‹”Þp,uÞíÏELm¼Öw¤Rx6EÞ)�?}ç.ÿýë÷ÙæÌùÙ#~îŸþ_ûõÿÏÝ}O#\²Ç%Äe“�LªM>&*´?¥Vó8Z¬V³â‹ùM¢½JÄwæ5%͆Æäkœ£ë{«Ð&°G�Ž“é0kü¢à dë{¤êìJvÔæ ‰8m¹8?³1çT³:úÒ“: ÐIidš¶Œã†q™ÆH¶XUÌnÌþ§!¬q®'t{F0mlïõü×¼àš�VU*ªL­ATÙ˜l2a[à|2YŽšhcÕt.(áäR%˜`Œ™MLÚ-ÇÆËY%¼N�Š¥@)NÕN²J'«j—ÉZ@Þ{:BOp©xr&%ׯ¶¹= Zy³‹#ZŒ7æÂ&&¶“‚ûÅ2Äz>ÆŠÈ­òs¥0F}œm#g›©IÙtÅQ¬·PLCb!X6 “�©xYOsZ¨Dبª}X¥PL-DÃK̤žãW±ý×ø´ö¬Ç³$–ø p7+[�-°‹ï5Y§K‰rKr€úûö^M¼«ÙÐ3æ,íXÛqPÉ=³²°µˆPØÑ®ê•/EÉ�Fµq©q èf«Ì×wˆhä¦ÔÿÖŠñ7Ž�³}΋+‹çóùÖá­G’í8�Å“— 7«�®?[×’¶ÓzíŒXh½’t>(QàMIêw E¯Uí!õïü#•~R·¥’�¨©Ç×*JnóTq™b ߊ'x—[øZ²3Y¡Ry“Îvìy((Ž…hrvÊĤr`Ú¢@,­“6Î9SD«´R@«R�lU .$ej_�ìË,ïU½‘rW ¤&ížiA»Gw¦M½«þ´œreg®-ÿÀ#BÓwºŒ…Pl–yPæ«^o‚rùóoØÞ°ÓÉ×+ûC3 p‰iºt“ÝÅ<›í{À-bucö¼PïšH•Ó H:èPí¬=y Ä­§¤¬¤€ø `²÷4¡y‡�WÒGŒ` X•(¨SÍ(¸±@*ÑRlQDœiÆV¬‚9}YæQ”•R2j6þ�Éu6±`^!ï0¢õÙ®{Õ³^ÐZjøçfþt1ƒ+3c8ïÉþ™Ë·j¦Ù²„F¨edêl!Ų#´Á’’×Dß «Á3ôž®W½KA³¹§ÙzôµR()[‚´·êeT‘dñ®V68çé³£8�àpC@½ÓÆyӷîºkQ :<….¼Óà!§BŒ…í6²ÕaPgÆÑ÷Ž¡s¤>¨�Íðæ^*]èè¼gϤ‘ú®£ë‚ŽaV™Š˜4àÙN‰Óó<Á�ŒI«ÄwˆÑ1M‘’„­!‹Y'É¥±±ÎGè¢Ýö:_ÁO1R@B5²F tx’ ¤Ð“ãHNлLp…isÊÓGØöX {ôë=öÖÃÐv=ÊbœhÓ®2iVu[€ Pœõ°Pm=ÇD'¦qbœ"ÓI¦» ZNœbf{1RRA†^KH½·éZ•`H5žVF�ÈÖa¾ÞãF ,ÌÔ–l�ÑlÆWgÇ ¢•jcn•*k�—ÍøU‡§zµ™e±›µÚ–yq×Ì…™¦+¹µc5ª÷Ö|ÜäJ ,3ÒÑñ© Osjª;nû5à¿J•æEÚ±T2µ ÖÏ#³Dfõ$œ9ŽFÌžÆÂ»²c™Ib[1„³y¸ìnòyž¾×–[u¿ÊÎgv 1™ÝÅæÀÕ¹Q,âI¹i ç˜ækX, ¦Ê8Q(%ÑšT 6z Eêr]çÉòZ•K߸}þù }þ ­ßåó>íµ¾ë»~€�|äs€xÿñÝ»|Ï •þyaM�×úŽ/=Pbà#�žòöÃýÖ à·NÎØóž£NÁ÷£¾k@,…ýàù¶çnµÏ„ÀskõÉ 6ÛÖôwÊ™M“ÍBà}7¯q­×ìô)ç¦íÿÉ“3>w~Á·Ü¾� �×.¶|ôÑSº׸»Îñæ½G�‚@øæÛ7p¢ M_:=ã˯ñU×®ðØéá>ï¹rH*…û›íNÔðöÃNS"Ÿ;¿àM{kžß[‘ráG^yÀ[öx÷•C ð¯½Àï{“6]Ý�£¾cðŽ“yñ`�ëC߯ͅüµ×9‹‰o½s“£.ðÏ>æÉ4qW¬’ᨠ¼io͖̓mÊ&MäøØ“gJ@ܼÆÕ¾ã_¯MŸ}íßú½•Ÿú†ž¿Žä‚‘ ÄBˆŽ!;B&G¿ ôë ¤{ÊôÖÙ#¡£[õ„U�zRÎ ëži;÷hòâå:n IDATqÓ&·È.ëwö;;¦¤Ì¶MW¨€KB—t­r¡ 7 cò¤’p›B)‘8éz-VuçrÂçˆxûαZ{V+ÍÊí(¸éô+ÏêÀ³>p û¿—•è¸nÒ‡h{Eµ?‘n´˜5¨òo••l°®…æU�3O•Ψµ«Õå4óôcû4ßûGÿ6³æäïè>¸H�ð¶Ã}îo¶Múå…ý=Ä Ÿ²Lí˜ËÀÛJ t¢±UnhpŽ£¾k•Wûn'ü‹¤À¿ú­ý—AÿÏ·]þ7—>_ƒ_'B'²ÓŒøJ¯’hu[’�G�"Bï¤õ¸½x°˜7"ré»ó~ PÆÈŸ¿s—ÿùÑ1ŸÝn‰qËÏÿìßáÝ_ö¾â+ÿ€º?5ã3€ó…7ŒÓS,l¶Éßd+s.VÕ  ,R,3^¥(1€ ˆS²\•õÚ+¯ë<}?¨ä�xͦö.1f‚Ï\°eš¬é¢ävž­JÖü)¢•í8(Ú×*޶›3«~Nt]Oè{r(%5Ð)¥‰ívÃ8^°7l.6\œoˆ1Y<[} 9_¤§ïGú~ŸõzjçÐFí>hÒVg!›%ù`øÕ5?Û â´º)[%¦Êäª.|É™£ÅO S˜ã[X{U"˜bd;]�KlñeÙyJ¦)²ÝŒ\tº~ tº/ï;k«r´Ub™[ŠU?:§HŒ…qÙn¶l.ÎI邜6Äé‚·¦LP(•_õB‡2ô=WŽ<÷î=Ï»Þõvn>·ÇúŠÃËH‰çì{‘H"‰#»Ž"mô¦±½Â ¶¢Ùó„\VøpÈáÙITøÅ8·±¦·¹Éb¨Ûëp�Óª ? ‘Ja› ›hÄ”ÚïÑk³èœ�(úHÒ&Ñœ½ˆ¨Ü�+”Pèp”àð.Ðw=«nEð½fçê¢È…TR«*dzc*J:DT~äbŒl¦D´Þ”â´BFý¡ê§¤˜Ä8iBß¹ÚÇRAKð*Uó~Yp”²J5MüB«TIšŠ7Í{në¬õȨ”Ga–ÊË„¯9vhP® Ãd§²©ÿèçæÇâ¡ÆÅe‘a?'Êå9A®þ¦Éã°|ÝbÉu±CR”ö ƒ¤ýÕŠûËœ  56®„�VàÔ0Ö¢¬ƺ¼$LÚ?ÎÆ¶ªkT×HmÜrHK/™3ÃõêñÂ2YpI¼VˆDÍ¢%±ÚqTÛZ=i³æeA¦ýxµ'5c= š,³ �k(i×@‰jQR ¼U8?“ Z�;ņEÖÞ(sÚ8k…€õvÈÒ²à•`™;™@DÓø·êŠ*wWlÌ7Ñ`�Wï2§L2²Œ‚6wÞäÎfÅ”\åàJ6uíÝYÓQS)š0’”ÌK–Ș $´·¨ö(F4è÷%]\JC…*Sï¿z�HC¤ÿ e”i,‰�yöÕg»•–K�ä ‘Ú½T³6²»ê¬¼KirÍhì€,‹ Äzpóm{iÿ àÆ@ ÝM -©UM¢¢þzek¦,®õ"¨ìfkþ!¥eË" |Z\Õy—Œ�¥¢=�A½W–]Á2ƒÄ¾èCìõ‚�oúÈÉ™QÚ¹5çj–ì‹aÑP„a¬šùžƒU óÂ`“` Û¤ ÑdÚfZºdÈ‚°–ñëT«¬`äCÑÙb‹Ì jc4u¯mqiW»M¨6››c5_˜úwÕ¡«ß³£0CèJÍBÁ>;7áí‚Ç;GÍG(iÂϪwì©.ýjèN³ærŽZ;:F#‚w*ã¼C‚7i§¨ÖÓ«cë .^´±wHï`pЈ�zÞv�€œê®ÑÃZ*•²0ÅÂ6*€*Þ™üCÀ‡BW–­–lÁtªCØ÷«^Ïq5tÖÐÉœ„.«£bÁ;-“§žœ >jc#ñ D¯�ÂJŽ�C[èƒSY&•¹IdI”qâ¬,ÍJc½fEêC %rrdÉ„âHÎÁÐ#fK*„Pè|aÝ žHç3ëÁ±·ìõt} tÚÛ�œÈɲŸ‹UÄêÌäy±2"ň.cÛt±H­áµÎ)¯€C%€ ¹Sù§RŒÜ¨GÞÓ‰×}˜‘o]åNl-ÏR_s¾«vn� L—yÊ8[�8˶ZœeG…§zÍ)¬û® FQp¹iaÚ=Å L�¶î¯V¤¤v°í,#5h®·hʳs×dàê9µƒ0yŽEZ‚9¥ C–öûÅY…N®äÀ¼ÕE³ˆÌdpíI`߯ m@ëVI�%9°�®ÛY»Df;e6i^±–‹Òe) Åzdó¯®e O—–Fû¿zñŠ•YÕ€k4çul‹C¹:Ù˼ΕÜìoY8Œ¹(á"Ôñ¶s)»×¬z²û÷Ò ]›KC²x{Ž –Ñ�¾û›Ÿx�ïøŽÿ…O}ê  Üöæ7óUë=>þä„÷\=”ÐüŇ�ùÆ[7Ø3iŸ}מ—RøÊ«GˆcÊ|òôŒw°2Mñ½vÌ×߸Êí•#í@ÿÿÎ+<¿·¢my½ïø†›×)¥ð Ç�yËþ^#~åø1±” _í»ÅR¸½êù–Û7¸Òw|òôœ^„ßµh.|‘ï·ï^¤Äý‹-o;̬¼ç° ¼ãè€{{+žM‘mÎ|ðùÛˆŸ<=ãsg¼ïæuîxÍvþèã§p­ð–ý=¶( ³rZâ>æÂW]¿BçÇÛ‘ÏœžóŽ+¼ãè€û›-¿pü˜;ëï½q•“)òÊÅFI–+:æÏ­WœL‘Þ Ÿ9¿àm‡û¼¸¿Çà=?öêëÜZ |ë�›ÄRøá—ïS€oþ6+çØ¦Ä”3ç1"¨$“CxóÁÿâÑŽúž÷?w“Þ{~âÕ×ÙæÜ²ýkƒ‡ãÄÍÕÀ:hC̃¾ãx³åóò#>øoý5~êïÿYîÜ8¤8GñºŽˆS¢»s=!« ] ºžæ˜èDè|Àõa¸>àz!g�¬:â¨VA³Èœ«]ÔŒL/Z5°ï�#oÉJ (^^ïo]¿|\2+´Hp †É3%O*7Y3ĬҒÁIÂû¢9*Á±<ë•g½¬×ž„D“ZÁÐgB—pµÁ¾()à•(Ajk1@na#µSÍ.ä…aXÚaæ¿ÕNáSµOÕä¸f~þÆ÷!¾ÿÏý=¶ÛÈJ´ö»ö�ÚO�Y•JÝ^:;o–g?Ncäx£÷ì;�øÍ“Ó–!|c5p‘RƒÇœ9^€»ÀNåÁhvPŸGä Zõ_Ü~ç¶Ë™oÿ_Ÿé/õX{Çf¡½ŸKa{iuçv*Höƒ'æÒHA›/‰�—æÍ™‘ +ç蜒³ ÷ò;÷ùõg§<ÙŒ|ß•üÈÅ ?sr~íW”³“‡|Ó·|¡ï $Í*w™mܰ�¢•âñ¡W¹!©‰`s¶mŠ(øVˆëAÄ�}+•7©M#Åy\¶ÀmNh�EŠe¼ë}®HSK)Úü8ç‚s™8ybŽLÓDΑà šU:¯ýùbœØl 1O䜈qÒ„§™ÿ]è¨ò2×Aµ-šh£¿Qû/ô}&„êA{ó)µ‚¼3bò§Í‡®ç7ÛÛêÓ´f� ts®  ù§æYiLP¬QeN.icç"Ð÷ç;ºÎ‘K ”ïV¸šM,E‰,ñô´Š×±ËŒèoZã]²ŠõA+i¢¤ÒrÆ{ûì­ö ÞÑya·Œc¶ã†~�«Woqx¸‡q:c'68ßFë·ã5qÎA•-’(%RÒ„öî)Œ)Q"œžoyrrÁþ^ ¬½¹¥…)e˾­™øŸ‰¯6ŽTÇÕ2vcVé/j“hËxO‰DV)^”¸*mðKÖÌ~ÑfÐÕJW‚H,ÎÕÊ'ZqRI‹$µµx•@-¢Š·1³ÙfÆ)‘ Út9œ÷d 1%jêvF3ô7cb³M\Œ‘mÊt¢€fAÁÒœªäY�µtŽh¯¡Û¼¬ó-©¬X“(3[Q,>©€£â=ö]ÛGkRkÅ,l‹Š\�Íj`c÷ÈßÖ˜»†®K”Ép�zo±Ì¶Ÿã¶9�|Æð¨Ï©ÄÀâèß™Ð׿Ìä@µäõýEÝw�ßëqÛkõy³°¥ÊÿÎãROkb>�¡ˆš©Ùù¥´cØ©¤_ÀsBáBE@je¤ú­Ëâðåøæ¬26ÙdŸçk°ˆwë~Dý\Ÿ³õˆù”Å]Û|�™¸L ̱‚7—g–-rõyË2Í�˜³VõvØÀ�+ fÙý¡å©Öç²øÞâoÅB*%Z’ºÆ/vWJ¡8mæYõ™0‡É)Ô;×ÿÔÆ.iVb©Ù€ÉzUѬ€ URj¦+P5S³î¼›AËFé(•d”œ�X®Œª�Ð H2ƒGÁ`Õ�ŽÕʳ¿îˆû=1i`x>f.ÆÌù”8£–š&·(rË�œ4 »˜Ñ�ñüV˜6O&A³ÏXT T#:#ƒ»W°‘6ʾŠÓLØÒÌÅuŸéS«W°Ëgçëêþ¤–K:œ‘]§@xç“[ª WRÒFÛ«Þ[c§Œ$ծĂ/„à13¦2$Å[¡ŽSÎIìæE272é(�'MŽÑe¢+ÚÌÅiAÉž. t!ØXvÚÈØ%ÖÊõªã`¯ç```oo tÁÊÓPb ‚ z¯—Ùé‚'©´ûš:�Š‘u–½RDKÇtæ™Ã'š9$õ‚ͦÊYucš,‘*æIS­>ÉÄ¥ö~u4š ZÚºº¯…s´pvZ•�³Êžš¾d÷œ”ê<í:N ãlÏÕ¾Ë<©�ƒ s6F1rÍe§Œ£µWU¯žÂœÉ¹c}ëàVƒfŸóv£ÖlýÅ‚s‰�Z=U{ØH½?D™‘lãV\ûL±E­:ÞÚüÃŒƒ›k‹±»öT¯ðó‘2¿_ãùÆþ »v®Î¡êJÎß­ã´\Ëצ~£­_bk�e6TÒØÌ­ä܈[µÛ¥z¦m—æÖۘώµ–­« ÖÌ5�« KÒdçX¹´BW×w¹F/·ÂÌÄÔw—ûÒãÐÑÒyþ³?ûiþÐüAŽ�ÏØÇ[úžÿðÞó|Åþ>›œ¹µêÛ÷ïøÀ]Õî°Ù²® ‚O¦‰šqöÂÁA„mLüæù)ï8:ä]Wyp±å#�rw=ðu&7ô¹ó î|×ܻƒˆ°<9ïøìÙo;Øç4Fn­~âµcŽºÀwÝ»ÃEÊ|èÕàýÏÝb/x~ñÑËT"âÎzÅEJÜÛ[óÏNàk®_á°ëø©ûÇlræ}7¯qk5ðyžÿâ•—y#Ÿøä}~ÿ÷þu>ôwÿ4ûƒ§�UúÍ�sÝàÀì—8ŸM~0!] _w¸¾Cú r‚^‰à~¯§KAÈŒÞß1CŸ‘‚%"ø+uÔfˆÍM(1(¢G)*ïÖ‚m• �~ß1dÏfŠ7QРFðZ©àôŽî:!t…½•gØÛ ¬×AÁ°”ɸ®º„øl²"v?»4ûB’(h­¹­T8_ð8ü%Ò»:ìöü Aæl'‹ÙôràøÁ9ì�ýMþÑÿ ÷BÇ<¸ÂžÓøc?xR�W/�­=:>uzn»Þsõ�_8~Ü~õ³çÌö ^³Ö"Â�÷ ¼¸»Ú¾A+T¨Asf7Ÿü‹ÛïôV«D„;òB—·ËA—þ¿Ü/5î�ê×íìRÏ�\J#.Ë ]ë{N¦©ëÔ€tÝJQ©5Prüdšø=ý︹⇎µêë3ŸùEÎä)ßömÿ«ÕZýÉL)q1ޤ. Ú'kX᜷ õYÕwÈ–5¬¾šs=âŠtd#ñ2Ùü*O•AÈâT#Þu8ÈhO³˜´IpL³¤k8KVÈEýiÚ�óÄv+ö9=&)°^­OËæt�)E¦˜¸Ø\�/fL"tž¾è|OVšä“#)Wò!Yf3ªán2:1N’šXÐsµãk ºøú”ê·„‹\+"9OäÉ%©|•jq±V^5ÑM�­’­×KÔþ ÉšNÐJ�nE?¬pné¡tˆ ôýžêä[UGwÄiÿ¸Tª …ÂåE¤Œ%j Kֵ͋-û)‘\¤”‰àwîr÷Î]•7šFž<¹àÉc­„8¿HÄèñîçö G¶ç�ŽŽ<=¹àl³!–|‡óñ œb1nIqÄ[ãÍœU²öÑ“â¹uë Ãú %­”u¤¤ñ…,À�b"*R:ÍtÏ^íoÖÞbñ“8o0K&æˆ+ϵÄ5 •L,Y¥�œŽarÒ2ì[Ø‚SY`§×5ùL—3NI¼ùÝ•!qT% m@j2GãÄv,dâUrÚyO.z/‹IÿŬò¿çÛ‰‹Md;)6à«/€%¹¡×¾JYUhIõÎíØ1Üîý”SO)4í÷ÓÕ©däG,ëç—ž}]Û[$(¢­âí3eÎIª?Õo¨ŸÍížÓ{²,à¼Ý˜ªIp3W Ë}×Ê€9J³ÿê{BÛó2’[~®FÙõ|çaZVIÔ§æ€ÃNj&}½ï¼ �Hë¹ V¥böH{7XåBU‘Åù×õMæsn¡´ÔœäÒ^XJ= I„$¾�Íü(‹ñbÞ·��«J©Ø|Å-IO‰q&# Îg}Èr¬’öôjÄŽaÉ39Pv®a�¹¡o®½8hs½ ¤˜T­(1 ¿+):W]hÃeq„ÒµûÙ¦éB‡VÔmIi$’¬*Q¯BvVBZÐ}ÆsF’bµâbFœtî¨l‘a"•´3|S‘¶¹Jv�H˜”r� ËJ•ùÃoH–(e¾k©·|Ÿ/H Ô-”qÎmØ�´™²sW'¦Cm䀟3„*VOi¹‰Mì7á|îŸvRóßùÓÒÀ2ê~³Ì=HMÏ«@Sh¨™”E*;YÏ«,JŸÈÔ‚Íø/†+©‘ÅëlÓzÒ˜nüxѪƒ6 4§]u�šŠÅðÃ<ÎÉ!Å#dMD÷êX ÑSbGc¯;r œn"g›HØh£¡�2.©eÌÅ-š±,NK„T»kž:Yòb&`ãUÁÅB“�±›pyUJ=çÅë…ØVW‘vªµ‘êœÝÝ>VweìvÕX÷AË.»àÛÃ%�wžõºcoo`oݳzÒ4©®Ÿ¸&×ÓšF‰5Ê@„lFÑ;‡ˆ9d”ùœlÝo`jpHWAÌÒæSK¢ÁæMkNR�Ma‡ 0§€RÕm,¡Ã�¸ÉÊ³ÄÆCui“)4HVRkCrц/ò§ú“>V}> ê�Ó°¾ žbÙIdew¶n»B”BgýBËàqÒA ZzV2±h–FQãIÇzíX %ÂL }ÏÐwî®X­†U¯,2Ä4“-˜$ µW�xA–ãOQp<£•2æ,j™§ï:Jêq®Ç»Þ…©£‚6 C|˾P§¯hSb« Rû2³ÔuÎÖ  ÚñºŒêm!­wÅ2ûßIi¤€w2·D(õœ÷_WƒRiqY,=¢v/WY£¨ãÖ,©yºM²ÇîjýÁºo#ʼïv °xÍNPEò<ïëg šaA ,e„ÉàPRÀ̽z~QëhÎIËF*…¦-ÔlW^dÅ—Ýc¾üh¯/ÿÖߨ]·ê›³K5oo$»K½p;‹–Ô;©.â‰F“½"¡€_Á*^JÓéÔ}˜ÛÐdïôÑle³ÑFçJÞl¼ç+®]à7ž�òÚŦU ¼z±áS§g¼yMïëàyÇá>wÖ+¶IWÙß{ç&N„W/¶¼r~ÁW߸ÊMz>s~ÁG=å½7¯qÇôès�³E¦ñ—_»¢:õ1ñÊņ/=Üç�G<›"ÿäþ1ï¾zÈ—ì“Ká“'gt¡5M¾Ñ÷쇀%?Þ~¸Ï›öÖ¬½ççŽs¥ ¼ïÖu¦œùǯ<~¿U&oGNcd´ÀåöjàéyËþšÏXæõ·Ý½ÍàÿÔˆßsç&ûÁó ŸpÿbCïï<:à$D‚G¦Á^ |Õµ+'|âäŒWÏ7|åõ+\í;~íé Ÿ<9ãÎjà½7¯ñÙ³ íaó,ˆÊz „|üÉ _{ý "ÂEJüãWpg½â[ïÜäávä—?à_þ6½Ó,»­5ß|õbË‘ü¥7¿…ïÿ̧y–¿ø+Ÿáßüãÿïoþx«†dP n²VjVZá™<®È:hÁàæDÀ�d¿LÒl©Ü ²NìyÊZš©PÉ §v!Î>‡š3WS¦´d:JR¢\�HD[Fëqãñ¢ëI×Bk{¬¬‚êÜÖªZñY‰x™“TÔe³ñúêM¦–·õ¥ÙuÍŸ›­GÛ„ËßhöBýúù•ýÑ_ã�þ;?ÀýûOཫ=^X¯¸Bk {ooÍiL¼r®½.RfZHþÔ P›sSkL|s5àØÍò^‡]b`I í»ÎÄóK`ñ·u[)…YA§Î€Ü�¾ÞïTzœ\’ j×—*®=�ólÌ»ó¼V”�º©¨î1À[öfâ ¸³øÜņmÎÜáÏ>÷<õþ«L¥püú'ù‡ÿÏÍ>ø'8ºz“œ SŽŒq"‹ú�~ØcXí595UZ!5©…R'�Uh¿’ê÷¸Ð!Y�ïmL”1’™´±¦d #¹¨Æÿ4F•C•Ü !(P^ „4 |šFR)–Wýð¾èûç­2Áâ±´ÕÄ£q™¦Q«·¼Ãûç¾Ó£”)MúÈ�*1M…R4¦JiBûl™m‘ ÖU€%·gXU¥/&/Ñ ÓÙÑl Z3õ2ÇĘjòB‹RŒÄidŠ[ÆiKŒS±¼tÝÀ0ìáà çVP: SYìzº‰ÓD1@¸þÍæw–¢1_‰Jàh?=óÃkŒPF‚ï¸sû ïz×[‰Sd'>û˜¦S¼‰<;I|ösOyz6âBáé“§Üõ!/½ô„§OÏ™bBÄãCRrÙEr™Ð†§ⵉ°”šñ.œoÎÉy¤ë ¡Ït!#.ªln437éZ㬠>fÑXÞ*½s.†o ¤€Uæ#Z�JfÊ O&IicXÐÌüT±úË ²b,LNÝÄFA&œh“î&ˆ$Z-ßd¨ŠX_º k;BIžTœ6”žTÑÞ.¨ät.ÖÕVÕ˜3cÊlÆÈùf$¦zçX¬…aVÅ­3µ‰)ä¨JÕ*ƒo˜L)�ìȹ’…ŠX–¥]È´·3~v ,\bE;±©Ô8§¾=®&T(q÷û—HÔõ©�ÜÒ}¨ÉQ ’¬¿o6¬…|í€f<©îa΋ZâTö:;õ øGã©Ü@ù àVHWPí~SƒD°ùjs>—ÓÎ)~Ui �¥Ãp˜]¨zže1ŽÀ·íz½-v¬àp”…ê„]ò9DÖvIØh\›Wp¼Ž‹aF@ÔÆË>Ó$„4)-·sA%ˆëµÐ8|—¨×°F�Kb “¬zÀ ³!Æd éu^úV¥àQÅ=QWR>{b6ÿÜ€íc¢÷°Hõ kú‹ÚiçÔ/m�Škáµá¹;m~n ‘bŸs&”)j«-³’úW1Ī Q“¯,0h• mÞ”ù–iªóÚíU ºV‰°¸j"á|óçëÊç± ‘Y‡º‚U•¢Ê‚$ÑŒÓìf°g)å°sÖ_›aŽy»üZ=¥]¹†ÜH�œËª³½Eú}©†™™÷?#·óÜ5‘mø†ìhä“ë@Ö#¨ªBx R.p‡K›PuUFm¶> ‡2v®föfÁ[óÖÞ÷@t¬Ï'Vg#!hpb$DÕ¾Ü&-}ÉvSV&³Î”f˜2Æ.WÝ+3\Y™wڤɰ@Í$aúÔ¸ IDAT6,Õ12}ÁŒªs©+Í@TrÁ‚`×F¢sZ…¦¯î½SbÀÏÄ€Í .3À4 =ÃHÒ‘dBP€º÷}0ÖP<1 iLHLÈTè’c D”D˜Öše®é*Òç¹Ü¦˜^³ c„)FbÊæx*1¡,¤–Lª!W²@\À…¬±µh¥ÇΦ{œ4Ë?[É­OTÂ#ÅÒ²Çëñ•’I1©¥ÙBE”| ÁSõŽ�¨ ¦ V`Ì“ÎAßÑ…¾=¼(š¹')âRnÊ4.x:ï8:ì9ØóP¥xrÚ’³£ï{ú¾çð`ÅÑášnXáº`‹éD;KõmUZA¬„ßËrN%&\×!]Á9Gßu ÃÀz€œ{¼¬Q'Üû޾ë ]GšyRòÄ4%&1Ö¹'Ä<1åIK6SÑÚ=A½•ëýÒìV™v0F]6U~µVyÌhv–ê´Ê¥ )5¯D›|©Ì)Ç(¡1;L¥­gÙ¼®‹�U){´y_"˼¸fÃԔتٯeA ÅÊÔaYáQõ=[Å@F#Íæµ§Ÿ�£vd=2)e&dç‹Àç%–¯ccîô¶-‹Q_2ÞKouçXì…åÊ]/áb]²ˆ‰šI¬DN6[¥fx™­œ×<ݯ´t‚º&ê\Ò E-u%¬ê’=“(umYìs>ºÅ Õs\œëÎù¶ ½xc÷³–KCAøéÿ6ßóÝ‹ó󉻡ãkÖ{ü»÷îr«ë8›"Ÿ<=çÆ0W |ÙÕ#ö»@-gþ*Ꟍ¯^lx·Iß\¤ÌO¼ö:ßv÷–6¯Eûí,õ¥¿æúuŽKáÁfËóë_sý 1g~æø1ï::hrC¿üä„çVC“3ºj 4¨$Äs«�ï¼w‡ üÒã§<¿^µæÂ~ð�˜ ï·ž1gŽÇ‘˜3½sÜÞutÀ­ÕÀk[ïøæÛJV|ôÑSîo·¼ÿ¹[>öäŸ:=çJßqkè "ì…ÀA Èú¦Û7ð(iòÒé9_sý +ïù�g§|âÙ)ï8:à�GœÅÈñfÛ$1‚s¼õ`Ÿýà93Y£¯º~U%5ræ‡_¾Ï›ö×|ý�«lRâ§ï¾rȯ==ižâ³)â�p{5°öŽOŸžóÊņ/»rÈ:x~í©<•€øo^|‘?ù©O±É™ûðÇù¾?õ·ù�¿öGp�#{‡ët]/Yu£­MZkZ�àÉ�ö�ò&ÇV›ojeŽÌ÷~vÐy|çq«Üîß2@öµ¢+ã&Y(à/“tBMC*£®Ý±Š8œËˆLH™Ix—é¤ÐU¿I Xywç�ƒÎ©®º÷Y+$ÍV-muùÝì `„@FIÿ*ÆXýÒÈûîŽ�˜ÿ;?™iÃZ×*œÉ%ü·ùñÿüß'¥Ì¾sü�ƒ#îùÎH«þDͺö޵÷<§æÆ¿÷Æ5þù£'š•tc®ò ¼A.¨˜�€7¿×ûŽó”ÛýW`Gºè‹Ûÿ¿[ç„iÎ_ý?_O‚úþå5ã° œYc{PŸ?]þ—sc¹¯Ã `{%œ7‡~‡|Z6ÀøŒ‘Z½sx�Ívâ?¿{�¿òà5žÆÈÉÉþáÿõ—ùÖüûܸý•äIï41'ô+|·Ò~w¾›ïç™â¦Û¯ñVÀûžÐ ø Ä»6úMÄœØl7ŒãÄ8üEÔŒÀ¤@wLß+Àß­†J!N zÇ)jöyJÄIq„’T.¨ïpn ïƒÉG8–n) úOÓ¨R—x2Á²R=Îw GGÊžÚgI¥fü6’’ú·)«lQ-ÍÏ%7P7Y¼«ïi,æð5×õûfv×¹Òl=h¶6NVÁ�À{ÄJ¿RšÇ Ó4)0ÓH*úYï]è黡[ãýŠR:(í1W{gÕ^ `nê"vÎ(PœµdB³s§‘8n™ÆQ¯EŒˆIê¦4’Ó–’F¼wܹs�÷¼çmˆÝ}gçOIiC.ÇÇ[>ò‘ßb½7Ð �'�ñê+/süð„§O#§rH!Ò÷â`œ&JŠôA� ²É%m™ ¦Äfyôtd3=áê•5W¯îÓ �½Ã5r1r~>j–’¦˜ô:9í…�‹hÏɦm®Ä@F«IbÖ>;ÑÖÄln|]sU¼&zZƽÀ–„/©%*Å\É©`D„ÁÃÎð¯¢M»ƒ š8WÐy1OĤ.¿_Èá„8erRÜ �‘‹q²yéÚµ.Bµш�Ô¤TR‚4©nM  Eª$tö³Øšce™ÃµR Ø½XïÊ/@|AÝòÅæÐS×ücÇb±f�óZæfŒO{ÌÇ3Ç€ÒÂÓš'Í_ÑÙÁþ—ÇÙ>Wã¡v ìÆwµâYýAÁp/³›'EA_�Ö·ÒI Ag)!hÙ\¶×¼¼6Õô_íXªzsJ†ˆG1ÉåvÕfu�R„$Ž$š¼›2Ÿº†µeÃ!DÚŽ ß\T6Hí}>«ì¥d»~¥f£ën½%@.~Æ®W±þ¹a%¥Îõ<“) ))¡WGA%²*î „€ö¨ 56~"ª¼‘$0e!GÏ\21kâOÈç½V­•DD{ç±î«u_�& àۨǟ‰ŒI%Êô uþ•¢2öž ¶VµªÛ†_+i_{T¡Â’µ*cž“,®c½§çûv†(技 ü·µ¶vf.óg.o�qÖ �/�(5ÅuA `älšÐ;©ù±X—AƒúZ}Ç´,žÏ€Ck²JZ¶ÜMÕlµu³Åh¬æajO«#°8¶Ö–Û¾Ss¦ØLî¢; Ýó9-!“9éÖŒP¦�eÍ’ º‚¹âÔQ™ôœû¬ ”d¡ôêHر$Ë$ñQè²ÃOµa^-YqUžj¬õ&ÌQÎ)f-ϱ²½ªò¡_/fܰÔìc[»îÕéSGÌ›½±ky9 W k:x8í îjãUZÆ�wªmßu�`™oÁ†¡£ï‚5i¤óx×'è\ “—’žw!Ô‰Ù[¤#tfàm>4´ž£,A[øìlr!EelbÒŒ€T³¸¥’%Þ¸Øõ ¾ëõz|­ÐH)²^£iŒàÅœY½Ñ}Ö…4!ZädZ“)ÕŒžú˜(’�åÕ,›jd�¸VaàjfMvÚä¹ëè»�> Ú”ÌÊåhΗö�§$ÎÐ9Žö‚�‡�’#%¡ë”_¯´_‚ï=7kù›Ó£•#*M%Ѫ& ž §vZ¬ |—!‚÷¬ú�õPWBNJˆkÁ÷„ÐkÃ*(É4+°�™R$$!æH*V\Aé¾/²ÜmÎTǫΡÅ;³CÍpcÎR)i^A›-·¹ê,;ÉâjÜsLÄI›!Çhã&³ƒÒ*¬J@+.@’ƒ² �Œa®ŽÉNƒÆöYEUÞñÆJ=ËEyh;Ï\�û¸9:T9¶E–í,†h÷[-¯¿TÐfÑuÌœ]�…]fñ;3øU¯-ìpAçK[üc_ìàÄí,MK¿­�|»†eN:+Ф¡´Ž&»9cÖ aó2gù³�Ý“¢$Š×±¨¶¶Ì~&N…¿ìP4Ûagá·a@æ¿z"»Ž~ue¹Fbcû/ †éç~üC¿Å÷üÁ¿Õ*Þ¼ø¾{w¹Þuìw¡I}öì‚ëÖààãÏNÙ¤Ì×\Wb –BïfÖ}í¸{‹•÷œEí!ð.êû䌓˜Z3â›-¿øð ×Mß;Çóë+ïñ{îÜDDD¾z¾áÝW¸³x¸ù™×ñµ7®òüzE.…³˜x6ÅF*¼çÊ!‚‚…Ç›‘{{kÞ¼¿f“?yÿ˜ö÷xûÑS)üâ£'\éßt[›-Ás˜UÇvÌ™·pg½âJüÒã§ÜY­Z“äYsáÚTùs�S±ž[ œÇÈÝõŠû[‚>p÷½óüòãg<ØlZ߆þð ¯^lNxa�³MTÀÙÎCÞytÀ*x^:»àõÍ–¯½y•µ÷|êäŒ_vÊ‹{|ùU•z°ÙòlœxçÑ�sÜzzïÉÀoŸžñå׎ؤDï=?üò}n­W|àî­&ç$ÀwÞ»ƒá$¦Ö7á,Fî¬Æœ¹Ök_�Þ;¾ùö ¼¾ hƒç«}ך(?3y¢}‹šBॳsö€?ÿ¦7ñ?ûYr)üÝð^|ñé/|7xGé´ dsì�,­·cÍ*âTWY·~½‹ýÇHk sÖÉ…Òi&¾åõ†´;Ï+uºl²;ÔN¸L!Ú1iyzÉšýé(�+ô®–ã‚Éö™â‘¶@Sœ$p–U[�°‚IÔ^ùÂÒ_®ëIK ²ßÙ5xfŸ.›™WÁ%1€y‘Ïžmù÷þØÿÎ?ø? €»ž?ppÄõ®#åÜÖ7ï¯éÄñÛ§Ú\xå=Ïï­”°íWŸ>ÛùýWì~;YÝ•lªÛtIræÑ¸››^Š6½ƒ—U_Ü~ç·ËDÀt ¸¯@}­Ð\’8ûA�ÿºÉ¥uírå@)¥rMo�º¹x¸Ù¶yv–ÒÎœË ²i/xÎ�Ô­v9‹±ÍY/Âà)óøbËŸ¹õÿÃñ}^�&¶Û3>ôÃÿ#ßð­„õÁmrÉ*¥Ú¯¬AíªIòèIQiqˆú ÚT5„ŽÐuøŠ5HìéJ$¦DŒ‘œ…”Lc9k6·“d.�·dš}¿¢ïõ3ä °ê¦¤Ò›%'«PrVQ0ÒlDQ[ãh’¯‰T4 I N¤<è§•Pªí“ÅÍEuÔÁ'µÕ1E¦¸e»=§‚¬•¨€œf€ûö˜³QŸMÌÞ’4NC­Ô<äV-�s¢5x&‘óÄ”6lÇs¦iË4M*}T¢ú¡¢R®>ô„0ü€óÏ—ÈÙÙXWis1ç@²ìe'VNæ�X– +T ý <¸F°«\ðR�  ÖðP{ËŠ.ä¤ä@è”Üé{o¬èŒ z®9E´çG0­°D>ç²5t’˜íR:X+ÆAWŽit¤ä©ÙSZ*ªN2F7Ûd >RIŒ j†cs,.­Î`]ü­ÕÉ"VR¶Ì\ÏP\1s©ç\r¢êýÕ-åL™&#½Ìs˜,Ó£.©Î¹¼ÃÓzoó(¡™6AÙlŠ-Ë⨻Ÿ�8³×‚UT$'ý�[RÌ‹T™KC«ÙVsYí†}ÁA“Ò¥Å:bUµD¡Ô™&ÝGicÚ®��oë=Pmný=.½¾cŸíÍ¥­7kÇ£i‹*»¯Ub ×ÿ‹U 1S¦D™”Ð~2jûê1‰Dêd—6%TÖµÌX5;z¬GirD¶0ÎÇÜü‡Åºöy·úþòoØËŸ«›ì<ûð‡?Åþî¿ÍùùD/¿¶À÷¿ðöœ#–ÂO¾vÌûïÞjC (È_A”Ó¹9ôÜzr)|äÑÞutØä†>öä7†ž·™Öÿõ¡§È æÝ^ |ðùÛtNuí¯ö]ûì/=~ÊYL|“É ='Žc;ó+}ÇW^;âöjà4F ´ÏþÖÉÇÛ‘÷ݼÀK§çüÊ“g|ã­ë­ Â#ô^KÁ=ð-wn�sáñ8ñúfË;p¯oG~þõG|ÙÕ#Þz°ÇYŒ¼r¾!åÂ]k„üâÁ£‘Ì·#o?Üç-û{L9ó“¯óâÁ_}ý*Û”ù©‡Çx¾óùÛˆÀ&kVZ¦0•—îs¥ <·^ñÏN9žï¸w|èµc¶9ñ�çTBè§<âñ8òü¸æp/pÐu¬¼çæ0p¼Õ±zïÍk¬œã—?åÁfËûn^ç¨ üìñcŽ7[¾ô`�÷\=â¥Ós¦RؘÞòÊ{n =W;íùðêfÃ{o^CJáñväãOOxëÁß|ûŸ=»°ÊøŠ«GL ²(Ÿ>»à]Wy¸9ðž}å·ÖßñünGþÙC••yÿs·øSÏ?Ï_yùeþÊßøÞóåoæßþ#ß^4Ð ¥xjÝ\›ÝÕ ‰ýVýS½OJɳyª¥Ønñ=K4Õ@;+‘ªU=KG_¨Ñ­|ÕW�ãDN[¤Œªïœ•LG¥@¼“‹‘Î%%ëûd´³Gµ¿S6‰$;¯Õ ´–Kwz=ÿ/l'—aÌüšþ¯ŸøÄþð÷ü ÿøk|Ãj�o\ë=ú¥{¼|±á")˜¯�„ç½=§¦÷þÜzàx36Mø·ì‘ri™Ùõ.·J 8R*Ð?8GïÝ.<ô/2ÆO¿H ü+ß*à ÔªÛåfÃðÆUîìÒõªÕ�S½l8|™¸üÝZuòùˆ»ë¯Zÿ ÝW·#=õÊÅfl»H‰ #4n =¯o¶ü‰·ù;ÏóñósRšø™ŸüßxÏWÿ>Žîá} ïzºn ë{„`q³ÆdšI0@Dø†TRÔtÓÕ|ª¶½ �L… 97èU.eNȺ•V,„¥à�ÚÉišf«Xj6°[…Ìvsθ½Ðªâ¢þ¦ˆ³ÜI–°QÕ÷�qƒ“€ø1‚@Ðd1¤�rq›üÛGÎ/Î4>µß�*'3àZI· Äð1²TÉØh ÒÀ—J—jW± Œ42Ml¶§&”X’  ÚõÁwÖ§Må/°Šñ–Á-g€§óZ¹’rTRºbEí§HÑŠ®<©Nö´1)'�c1&­æÐ®Õtƒ쯾vÌGùW¹}û.·nÞáô|¢Hoð•0m'Òùd‡‚ÙÓ´¦ 89a5ÀÍk{\9ºB?¬ljéâ!i{Æ­«×xÓ›osïÞ \¿þý¥�óÑ�~œóó-gÓ]À•«{¬÷:�‰®ïY +Vë@× ''çµ6oI>Tà_,æ™U(êW_¤úcu›Ï©âw-&­_kcf·c¬ÕÛµóRÎE*QÐWÿŠI^1“/T0¿í¼‘3³´ÓŒÖç"z—=ó¤�ƒU'.W¥Òs±„Y%†ÉÅ"Dœ%Y6WrŽÃ©ã1'÷Ö‘›“ÅÛ+úY΃/*Ô(Uë ¢—Ì®‚èËJZìõJ±p¹dÅ0Êå‡Xb+ZQ`s¶QŒ#g¼Ó-¡ÕY�wL¹¼öáfù·TÔ“Ã%!d‚+W“g´2à x¯k§ë¾ YèûܪÉDùÙ{³Xé²ë¾ï·öÞçTÕ¿ù믛ì&›M5'S$£�¶F[ƒe9² [°ã<ˆ€ÀòñƒaÀ  ÈK€8°eà$ D±c[5Ø5ÑÔÈ¡9ˆd�ßtçª:gyXkïsêvÇ/�œVãv}uoÕ©sÎÞ{íµþÿµþ« �iLªpl²=uŒ&cþ¹î?bäºeEÎÕ ê>SÁ�6.¶PvÑ—�qš4§1ž˜+˺6,ñ½®Ý@•´)óbËîtìšý”e6Zð$ÑÐ}m" ä®Fª-fØ ê˜—(࣭¤padÂtêw×ë@YÍ�ï¥}®fL·»,;'Û Ï÷ï¤×ÿ4ûE©ÿŸ_ÚŽá›î‚�8¶z ‚DðI 8Ò *³€E–ѱŠŸ2 .#£jÜ‹8|gº…`Í�:À± ‚w™œ)kI¼³’4Ÿ…QÐɹC¯Ò6—bðŽXEBÕGÔ oÚ_1 ™ÕxOÒêÖj³ ®%×*QƒSlÚ¿½É õAX,„ÐI/}ïY,:–]Dz«Ž³CNË‚ÉÙ:ŠÇŒ àƒ£K €.± A•Dñ:gªã;Mš™ã(m£iú“6?ÕÈ!8úÈâp!°Xôt�êoÖ©‘k}‘‘|9´>Qzç]'x-X¢$uê‡17]Æ1ÆT¬Ñ±2°1ebQG¼ Í\RL_׋XC3½öŠ©†ÐÑû…^“é´e-®Ô5ã^„Î ËE`µìX.z}hן’#'GžÐ…\”’ GsLz!›Žœ¤¶á´=-ØÚ­Õ<è®Ò˜k—qÅÑù޾+,zlÃÒ€@'×*j™×Üþ‰×u�²5_l̪4GeZßÓ¯ã_fæI�zÝ|ʬRHç*5!½–·º:×-Û#ÕRO%ÛÔÑÃ6|3òÅä¿Lo2&%©*.¥É®š KÉä e€b›…3ù8å…J¶¨O¢s9g”ÄI€dr%í 9}Ø¿§ëÔï/F:M^"hæmž;u.¤öð³µÕ0îÉé*vÜâò´�&Ô*ÞêД6<Í+�÷,hÈloÙyÌl|�vóý˜ÙwÔDÜb÷ˈ†dU ¹èn—Y«ñ40¬•âÝ4ˆ–VR·‡š¬ãD+BŠi&VíÆ¹yj_fcpýúêß©{îÜæ—·½»ºþû~þ~ò'¦žß¾·ÇOݸ¥MCQù†xæŽ%Bëîñ^k.üp;p:Œ¼t¸O/Âùùô£'ü¨5#dÙ SÉwÞ¾�a›3'ÃÈýå‚}ÇEŒüêç|çí÷øêåÏæe#^<Ø×LùR¸H‰÷ìñ¾ÛëÉ)/ìñ¼õ8øÕ‡OØ¡õ,È¥f(ã»öWìw�›‹^ ˆEÇ÷Ý¿M~ñ�GˆÐzTÉ +=—¥wÜ[-¹¹ÐóÎ~èÁ]<𥳠o¾ëÎMœHk\{\ÄÈEŒ�H NøÐñ!{Ás2Fn¶|üæA„×Ö>ûäï;TYž‡Û�/ž]pÏí­(hF®—@¡ðúzËGo±N‰¥s|ê�G<»·äGÜåõÆ#D„ö>NàÉ“�mÊ )‘‚ç]Veqψ¥w|òî-Ž‚ççßxÄ6g~À$ƒ~î�‡\ÅÄq×ñÞƒ=Þ4àÍ‹ðh3Ð9á¥Ã}n-z~ëÉ g1ñÇïÝâ0~õán‡VÅðÕ‹+69s:ŒxQýø ÂAœŽ#ÏKà¯Þ½Ë?|¨UÿÅù3¼ôò}þø÷¼ß¶oÛ'®Oô¶ã›oP¦WR½AÝ›ªS'f›,Hh™òõÿFLaÙôzVõTÝÍô$‚+ˆR€ … Y3ËŠJ … ÏªkƒõÊ©¯ö=)0Îl`%Ú{¬hJìz¦À¢=dî³Ë̞Ϯlv‰üÓÿãwøéŸþ'œŸo9pŽïYîó‘åŠ |îéûÁsÔu píœã‰�æè IDATûîÝâçßxÔNË>Õ~U=wAíÎ�s“‚yÏÁžÊXÕõ»Zòh€;æ¼#34RÀY(ô6wÿ[�?²Çu‰ /;ù`o#J)­9ôÒ963пsnGb(NAE{TRÀ‹XÃWýýQ¸2‚´QñÒûFN;¤À›özå\¬×±tŽöø‚Éb vO·åðÿL„߸¼$çÄïýÖÿÉKú!ÞóâwhSÞN%„Īq«ìLD}hµÞì†Úõ ÞC§6Á;ÆPˆ£f!§Þ'\ˆt¡S2 VÙ:o={ŠJ¾ÄNÁÖÙ÷kèo¶¯d†aÔŠåœI¹h<ê>t„N‘j#xõ�³Iàhµ…wà\P`Ê[\ˆVÓ‡Nu±Ç¨þúzsÅ8Æ V¼Å;ßtá1àΞ5!È|H1ù»¯R8:;¯úû)Ó3•ã†a\k¢“oŠ%ÅiÜ© <’k‹´ãT?³=�*�“«´jñ È,™D«RˆiKNƒõ™P"yŒ™œç:BXâ»=žž\ñ导ÊåUáòªððÑ9W›Â8 1:â(Œ#l6‰Íf ð®£ë}ç¸y´àÝÏÝåö­»”,œŸ�ñô­Ä–-7ÏÝ?äý/=à¹w¿—«Ë?z�7ÞL¬×ç­xî¹gØ;èè—ŽÎk‚eÁ�›{œœœ“ɬ٠Vñ^ $!eG.$jÅ{Ñû–J‚ö�“„ë…~é¢ûh³aï !“Èy@$ÛÞêñý×-ÈnÁ6â¨ÒT®ŽNçŽÓDÈœcöÄHtÚß Zò]¶ÖDû„$­ì6ÍÝ\`Û!2Œ‰ ÞB™°Žlñm±êîlRB¹hÅ@i}#¡IaK­P5•b•ä&m1Ÿ)ÎpÄÉg)¥¨Î;а´ 27¦Îk’ù@èþ-»^�M×wŠªt•Øù õ\f Ä?J™®­�àsW„IÐp~|˜ù•dh®ŠVI‹Å„Ú²˜ž¾&p¨åž|'ÅÄ,#Ü =?ul„ÜÎ0R@í^Îyºv7R žâÜùl±k±¿3?hRÅæ™RÐBÓXĈ£ÒâÕi˜¾«) ˆÞ¨ÆûHû_#N\Qûë+ªVê7ªXê1Äœù�õwÔ}"‹Êa•Ò$Þê|œ**DeÈl‚‘fsÂzÞ€s ï„λ&Ñ‚§+™�Œ(Ú”<ÙÚA ]çé²£Ób`‚z¯ãçJ"8íqÚw…¾w„Þã�˜}T¢&Å‘8ÃF›šÓ†k–*.¥uàÄp6©¤_q›PF€¼}.×÷¿ƒjÇ®½Úèéf¢cdþ{ì�QcÈj àf[“«‹Ç‹%‚yc5³ÓÛï=3’À^ϪJ]Ä2ý®��ƪËyfJÊìu]µ¢‚.0õ9Ï@k»ŽãΣ�&íÅÎ0Ђ½k¿naà $ž—†ï|IÙ}vÞ«Oæ½»Ïð…â3%èøôNpÁ‘²IX&ÁEeÈD<Á÷š)`�i½ï´éSÍ¢ð~*eÊ�²G\OÌž”=Éœ_7D(#ÉÊ×ÕÁÔU\¨æšfdm�Z�všµ«à•kw×!mƒ.ÉSdÒÌ3ã�sbŒF¡ ¢Àó¢c±–½BÁùBßu,—}02¦™s‚kn´°žlA·xêìÇÄCÑ:}ÄÍX‘ºÉÌËr,ØwÁt=¤ ÷°Úš\rk ] ¦¸Òæ�ó –ãªÉIÌu¤+êšþ52PÖ µÑsËÊÊJWÛ¨N…:®:èfˆˆV2Ì$ÎjРäŽe4»¨kŒ*S±F´TÎF³\›6^1‡j9›–tVÇÊò9ëWw¸l·\Pðº¯y@ZfŽ—³lW�µË°�Ñæ›bÒbÄ“C” §5<–ö¬ûgžœ+[lÅ$-¥¾.ÓS šM~nn¸ës»®Ù±æNÖäåM&½þÔj�TŒÈȘµ×@šg Ô…f÷OP¦Øýuvš^älO´óT-G×HZj¥_óøÚFóïyÔ�®7à�ÞßÜZÉ#ð ?ÿåRà#{{ü­÷¼§‘_=¿äÁþŠ¥½þ�§gÜ^ö<¿·`Ï9Ö³R™Ã.ð§ L¼Ø¾I}éì‚m)|Äúœ #Ÿ{rÊ�<{A�¤—÷ÙïBk®ûý&áóæzÛ›mk6üÚÕšß|rÊ�>{�…I޳ã r5[Ók;ðþ£ÍXþÌ£§|ìÖ1÷– b)üîÉÏ®–|û­cx~Å¥eÉŸŽ#>>ä¹½%�wüêÃ'¼k¯É*ýó×Þ¢wÒ$ƒÎÇÈù,ÛôÝû{ ¥p£ïøúå«4Û_„O½ñˆ1g~èÁ]œ¿öø)o®·¬¼çÝû+œ8zç8êgcdéìÆ7_<»° ˆ[,¼ãwžžñµË+Þw°Ï‡nòõË+Îcl€ÙÊ{î¯wgãÈ£íÀwß¹E*…‡Û-¿úè)ï;Üç{îÞâµõ†/ž]Dø3ÏÝ'•b «f½±ÞòÂþçãÈ~ðüò[�y`Í…c)ü›·ðÃî~ý‘Jx¬câ •}Fnt_:»`á:>TÂáõ‡Œ¥ðÖ4ù_¼öcÎ|ò`�oó §§l·‘¿øÿG~í×ÿ&ï~÷��°3åK †ÙyÇÛý¼ÉÆTÝÔJ Šh¹òœ˜Žâv—^õgˆ\ç XKˆËHÞæV2Dªi ÁÑ…B×úN3¡&Â7O.q,“-)‰)ЉJŒ›Úüh™lN«îšŒ=�h�àÌ”¢^sJ™¿ñ7þ9ÿÃßþT[g?upƒÛÞC)|ìæ1çãÈ— ¼Îí‚1g>eRRÕ·|Õ*ŽºÀÒû&åÒ;ÇŽÉ*6Ôª'ꎓ80·Ú(½>‚®Ÿo=þÃ=æ¤Ì*P¿bž±¿ðŽíŒ(¸Nð\ï;0·ó!ìT‚÷ÝN_�ëã®ýÜôx×¥Šî¯<\ow"Ïy%è&çRhÃÝEÏ:e~rÿ˜ïùÔÙ¥^ùýŸcÑ-øàG~ï­r×ü’#1 ”2RŠêì§<Y6"yDÂH)5ŠŒâÁK óBé4I«d‡m"ë�3ðÜkü)ÒH8�ÿj?ËA{Ti •)Ê;Ò%¹h<ëŠú¼ÎyB0¹ 'Ø(ªËŽ¿èL.¢æz«ÏÝYõsÙŽäad»Ýr×ÔæªÕ«ÕÎâWïÞ)ÁÒš8;±*fMXJYÇdÙÒwê«ô‘u|%#’)&É”Úè}h…`Y–1FÖWr °Ë*wê‹»ÚÔ^´<—$k•LŠìâØ!r(y ç�”rˆ1*QŸ•©í–ôËÆÔsr†Ç¼õpËÉÉSž>½Ðó.YA=ð,pÄQI†…ÀÑAÏsnñ¡¾Ä�[ÏðäáS^–ÁÑYúĪOt‹D؇瞿Í'Öàw~÷ œžœðÌý{|øÃäøö!«£ž‹³ÇÕ¦¨„ ‚7[“’&¯xï­úH�ZÓOçšwdøZ©ÿÎ본Õü 2‹©g8e;Žb›•(Ó÷–ù»Þé«p¢L¾ÂDZÔ MÚ}ѸZ�}gøU‘Ò’èŠÝw‡ª,¨²„É5'ÓpN°±Ú­h #"MŽ©LÕkª~ÙiCí¹ˆŽMm©ømµy±XU‰É2&ÛÛ|TªÛVI#7»§æÓµDM•¢¤€7Üxê­:‘BõÚ«[(6^SÕIi’@i~_ÊTpßH«¢M‚5{¾Ì `­œ©^`0²;8¡ï]r›# ØfA²�\!n@C��èsÍÊÌ*˜È�Jx±TÑýÒMUÅ#ju“аiP�05pE&¤U,äYÊÎ<ð(6—¯Hazÿ☪êwOp6-s²�#³›>-êwz´³�Y™ÌÎaö+oK«ÖùBñ:  �ä 9:É$ ¡ÐȨY‹ˆÉ£²8Þ«3Tƒ·ŒhC�le:xœ‡”‚YFçÔ)ÇÌPY­–…¡«^Š–Ú‰U xs¾ˆ¾3�K›äUÞ©òE:TjôJ=>ÒEÌùÒ,ˆ‘˜Ð㬩]Žêœ#l‰¸‚—Bœ'”`±¾ÎCɉ8$¤8•$òI›×ȵŒPœjñdñÚü+†,ĬeÕC,&inÝ €4µE«–Hª³fÂeoDQ±r]o¥OØ}™p'z˲)µ"B+/œe:k¢¾ê³)ë©iA*çoò9Ê×òì&*V,³&if¼Ö8‹6Aw´’²šø¨oØ7Q›0gÍ$ô²· ŒÁ·æ]us§£ìÐ5©Z¦&ÿ2Ó}«†ugÿœ¬˜£QuWëÍRDÇ¡f­;½VWçV+Oš!WK”Œ‘ÉÁ°À°äR{�‘’f è1mõe!f͵�˜\—4GLôëÚÚ¬e%7ê¼.rµiÍaš*i*©ìŠ­_±5Z3Oªù®[N#Lê…×usB@¦JMÑ ¸29!EËj²[ÓÞª­Xɇùƒ2MèúïiÛZ.ÌΩî¹uS-šý°öU³z8F È�)cFj��ºÑíxX6+Šà ÄËfÇZ¤9�Ÿš¥z��U]He~š¼ãô©Ù s^ë¾7Ý€¹Ã0;ˆìÜ~ñ¾ºC |lo�?pÜH€eð;çý1Îs�Ë9ìû]`Ì™_|ÂÇo·æÂ¿ýôŒ�Þ|ã�^„Ë9F>~똄™¿ùø„OܾÁGŽÙ¦Ìo?=ãîrÁwß¹IÁ²ý�ÞŸmÊ|ðè�Ë%w—=Ÿ}rÂÝå’}ö—1ñ o|Âã­JÚ¼÷`�W¯Ö:cD+9jEÂíEÏW/®x¸Ýò'îÞ¢÷ŽÏ=Qù¡÷ðñ[7øÒÙ'ƒJR¼t¸ÏUÔj…ƒ¾c#ßÜ|ûÍc‚N‡‘_{|‹û+~ü¹û¼zµáóg8àϾëÎÇÈÖ²³bΜ ™g–Kž G]Ç_8ºÁÃÀ¬×¼õÖ9å?ùŸøÔ§þ:«(©ë Ôhf+|æ?Öu` ¿HÙ‘7+¶‡è'®Ì;É0J|¾=Ð?‹¤x¤·^;ŒË޼Í$„äÞ àŠU „B×e‚Ï&Ed†©êUÏýÿšôã Œ¢‰@#h=ʬŠ�*{à�ú«"“�/¨xmO¼¸ÜòWþÓÄÏþìïðb×ómËï^hŸ €/]\6ÀÕ‹4É ¾íè€/Ÿ_6À÷å£n‡ÞÇ¢ µëc›s#*ðÛØå‚˜s# ¼·=o̲¾_k8[ÁáºGÎ%m¾õø£},œÛÛ"o_/ÛkÕuž,¼V Ì+ ®W"\—‡ª¤€·ïIͯî.{Þ\OÍ…{縜}vþ7€µ�—Ï\“zñpŸ¯œOŸ>‹‘1e2ðƒË}‚8þõé ¥~÷ßý_¬–{¼ü�?ÙüžL!§È°YÓ†R&€X:ß1¶¬ÿ€Xß¶i�w(Ü£™ô®®_WÀ+¨¡ZöžDRÐBT¦B{l,S}$—äÖ#.[å¯sZ}œ�à ð¢ýœh|ålÿÒ„�ФT¥X•ë´j¶&1ºM�ÚR²#ŽÆa “ÛûŠ�“w±ïô¾3­ÿD Ùˆ� ŽiÆ}JˆdE,cÛú'hº�ƹDJÌ ÊíOPýÛlnSGN‰aAFºNï•HÍ|ÕÄ=,Y㺨 Z^c0I¢ü¬¯•Ö#yHqKLRÞóVe�Ò¨ó( ]èq¡#t‡øî€˜=W™ó‹KJ¹d³Y³ÙnÑŠ’ÌbÙ±Zu,BÇr±`³ÙpyyÅb¸ï/<ÿ€÷¾÷Žo3\nñ|Ñ~7ûËÀñAÏb%¸>qtcɳnñ�oìÓÇÁÞŠ[Ç7¹}ï&G·÷yè#ç�¾Áþ~à¹wßæÎ`÷ÄwÄò˜1 l¡Œ1é�Ú47Y8Y[¥ßQB‡[ÐïãÊ@Ö 6þ!ເ'㻕ê‹Ç‘Î{ú½#¼ï·—œo/yr>r~±fµÌ¬VpOXô'ÚS k­yÌ0ÄÂvÌ c!FÐÞV‰‚·fÕ�<Éböq( Cf­ õŒ13:U&÷2ú¹hå îi’ ÄŸÈ�J”ŠY´¥>&0¶Å݆�h|hDž}*[ߥ˜�a,m–­Çª’[‚Ùå&ÛQƒ1sÿõ »˜%üX±ã ÍÂ’úÛÝ^höÛk{qó=ZŒGÍ�dªP{Ó@ü™’E© ©F ˆ‘2Rµ_S®ÇÂô3,+MCJ£*1PcF‹å™%¾*eøØ.4ÜPÐ~ŪÌ]M(œŽÖðˆRÄ$ZkRb�+SµB­ê—\ó9êý�éE“ÍŠ�£d�S*¶GÌDzÔ{ Ìá²:ÇÔ§¶ó̆�Tr€kä@}/•øšæ‰ânÅλÊ;eB*$#W}ÖÆêµ¿í·’sT"§8:ñ¬:Çþ²Ã‰úçÙúsÁgú`Ä@/ô�æøQ`á2½$º eÄç%ØÜ«2êP¸\;¸*8ïd"4!zFš£øP½�…JˆÕ{œgóc‚�Ú}m7©Ázœ¢ýJçóêºûl?S +é¤Á&~+Z“F'-û¾eÑ)P< `{±nb³“iŸ±,F§•™Ï4]ÁºJëÌmQ•L—É@–æûÕE5{I™!!ÒH i³t²#:j0Ò®‡|mŵ¿L7½}i™Kf©öjMã°[ô$¦?Õ²²<СÍFñ tQ‰)@Ê”.�‘RZr—6åÕÄ/Ða©• ™b}/ÞeºÎ̘†{Ã�DµàCàj=�׃51'Ëš‘j¹œ6ØqF@TKñó<áI¥PDãëð’NèL¯@<´Åá¬ÄS7[´Ç8²º Yë%Cç#%†¥'Æ ®›àعÑ2|ï¼fÌ8³J…­1ðœô©:¼IQpÕ+K”˜È1YX(c! …¸- ëÂ8 �c#2_TËP;+»6-sU_?jö¶ÈƒwÚð×k/z ²ˆjÆÂ0Â!ZC,:Ωˆý˜áEÇ!Ûs1`ß9•ØÓ´LYlJB§ 5£\—­kìz%^ðBýÞ1Ae¯ÇqdƦçD뺮£wÝê‚mÄ(1cëZJ¦ÆRì{ª3e×S"¦Äz�Øl1ÖR4cÄE¬\PÇ/YÿÝØ % ’|Ë.—¢:�)EÜX�˜Ûf^ nut¤–ìeƒñ�±×Œžll±ÚDÕ°+z^hP Žˆ�»¶Igëq�ŠéKgaŒVf6‹íÔ|ÛÖ#ÒJAï³ê“z2~£E(N¥²ª§® ´õZË kÆu­Ú&Þ¬Ú,³¡’ÅM¦ÒW'iN‚úNwN-C ’¸M&Ȳ6*Ó0õèЊWªm«à<ÍÙkÀW}]ƒÝF.Ô]³z‹s£ToÈì8¹Ì6_ýœÞw«pš“ËsR ©­f̈Öx*QPŠú�úý�0ûåÑ{Ó<£é¶×)XçËÎ7ßëfzç=®¾§>_·Ðõ`ó¿ ¿ôK_ãÏýÄÏìT üwï}o#†œ âx°ZðæfË6¥&ÓsG>zÑôúƒs<¿¿G˜ÿ?øÌ„šAyÖŽu>F~å­Çüè³÷¼•jX§Ä1Úèø»îÜ´a(œ#Ï®–<»Z²M™ßxrÂG޹Ñw¤Rø·�žòþÃ}^¶Ê„eptN�SJáŃ}î-¬¼ç‹g<³Zò�·õ¼?õæ#–Når¾~ºæ�õ†—ŽTé}û8ŽºÀ£íÀÂ;~üÙ{8>÷ôŒ³qä{ïÝF€_{ô”77[¾ÿ^à¸ïQG4'ºwÂwܾÉ^ð|ójÃEŒü‰»·¾pvÁÏ.øÄ­cÞ½¿âÕ«5ß¼Ú�Já]{K^ÇâÖ¢oM0?yçc�mJüË×Þâ}‡û|òî-ÞÚlùÜÓ3VÞóÃî’‹Ê.ÕÇ&%Þ¸ÏÊ;ŽûŽÏ==ãFøÑ÷ræ_¿þüȳ÷"ü‹Wßd,…w­–<Û­ØZ)w£ |ãrÍaßñò‘6þ7o=æ*e~ð% ~á�G\ÄÈK&…ôÙµe'c$æÌ�.pØn÷=x¹æé0ðݹI/ÂÎ/ys½á={ü©gîðù³ ¾vqÅ~û.ë�×8�‘OúËüõ¿þOø;ç/éü6ßsÊàÚqwžÚÚš•éN9­õ7XP]Óó¤I;;^³­èšjL](ø>³Xö0:rÊàpÙ[õ•'Þç–=œÃ¹lÚÂÅÈíêwkP²Cšú¬>s#<—µ/ŽÓRzMšpÚÅþ=UX¶À”RÆë¯Ÿñç~êïó›Ÿý&Ÿ´~\ÅÈ�eO/Ž× 4=î;>vó˜_´ê€\¥Ä¼qìç-ëº6qU9 •KùÄíüæã“öý÷—=W—±�ÃO­OF}Œ97Rà:h|Üwœ�±í�;¦õ[�ÿ �9)ÕyçÇõ¾× ˜*ªdP}Ü^ô<™Í gÀF}O.åmÀmj}1ç&_´pŽC³ù søtÜ­X©¤@gÚßõ\÷‚ç]{+¾·Àâ¦ãgŸ> ¿ñ™ÿ�ίxùåÐI ÛudsuÎÕÕ)›í)m)(â­r:¸Ð’¨ª^7"8j#ÞNJŠßBØšoå4ƒÜ™4«e)—”†-›õ…f`çÈøbý¬?AAKÀ¹ÐKV ªÚÉ”1E“OÍt}§=Âï)�”THI³˜E:•b•ž>dºnËb±¥JIÑÒMu&ÇH½.¡'ø…JÓØø¦‰id õšèFž°µ¡”d•µZ`FôµþuѪt‹•késM¾qÕo·*Œæk}#Aãä˜IiKŠW ÃÃpÉ8\I3hæ4šì• ¡ÇuKŠ[‘ÊBj“Ñø)àÜB?·ôË@¿ìÙ[õ,—�Ë‹ RÙrëöøÀs¼ÿå9¼y“q+Ï¿ø®[£CÊWëWÛÃг¼Jï$Ôc†Ú©jѲïXGϓˑ´¹dsyŠ”bJZ¥ß÷ËÕ‚.ì!.ƒóŒyÉ…ó+áô²p±u\Ž�õ�B/,S`!=®_ 9’‡‘XCJ cd»UI ç‚Æì.€hãë”Ðø¯hR\Œ™q„q(FlH‹rÒª~Àbõ vó“*�ç!Ьsb f®™ßâ8ýNg½!A�Ôš0 V}\LI Å�f#î*FQ §ÔÏ]¦Ôï³¥3årÝÏgÆü÷×2ým÷oO{‹LkTŸË„[Ï~¯­}û´B§öó�F Lñõ¿J‚dLGöˆ�º–'?R,¬ZÊÆm׬çaÕnJ ”ÙK(Jì4̧Ƭ5^¯‹TüFf?õïÓï²mÉ¿’É0 )FÔµ›8ÇlÌmï¬v·þ¿šÏÒ¦\+ª¿<í óÜ•Šy·dBªM‡‰õÁŠ=>xº H)”¤çŸM^héaå…ýÞq¸ ¦\1zbôÍ•­I6N%”Ä„Ë]Iô’XHa�̘Ó ˆ]"ú½"j„¢‰Â1¬OI'K6¿Ä·im7N«ôõ„/Ïn�Dm4 *Ÿf•lo�ñõ¬ MÄÉ2o!SÙ°ÔN è÷h£¶¹jB§¤@%,k±XvùDÔ¢hF´�Ì-«U-(H6s*È’g‹Šjôª’)Ъô“cw¢Ï“µìkQÁuèc×ÒT‹üNî¨ì¼m÷¦×Á�ظ]ÓWh&hö¿élâ;чC³ IDAT ®N 9JtÊð£ùn±@RÃ!EToÜŒº·d÷‚•ñgèC@KÎDÇ$gOÉ¡õ¨}r.ŒCÔ;c¶tá8‚÷*䬉SÉ*xZË>ë†Ô²ã„Jm˜ª ©2kE¦Lãbc[ŠfªŒãÀv«™ä%Aò ‚ã´¼´–è ê$’ɪYYêµÛR 9&Å'=ðVÖ1‰z•ðJÖhH¤q4rÁ‘ÇLã6±Ýh£@!á�U ˆ# ™þÅ�tA5ûc,ªƒV+'ÚÆ­¥¯â.$tà:Í~M™1 ÛQ3ÉSÆ cÒ瘱ÆúÛvÖ˜hñfD;%Dã˜+ ®óL mìMÌ߯¯öƒpM´ú7±€D•¥§M�ÇAË©´Ù‹§³t˜¬" î&…㱊Óù¯,i±j•lò9©8b†±–g&¶C&F± zf›M-ÅLí‡ÆÓÚ8›<–8màœbÆÅ„�Ií—a5Í`*+••­ ʲ5¦¶ê¨âhkR3Ä6± x*A(h†HNš%3&aLznN£;æÍ 0r@7ôlëÍ)à 2ÁV¥VùTP�³ªê(¡úž)Í«Js.¯›Éê$UR .>ujEN�;õ�FtÌ62ýnÝè S‘’XbY´ …J7ga–!¢'eáü’z²eöžÙ¥Œ¨(Í;©vO¹Ný½f/Ô=¤Z3é¹eâJÝìZ@’}Iµ‰ó›gäZ#ä­±¶´TŠÙõÚ˜]ó#ìgwïjš·¥´lËùDs1fÚóëß~ý×_ã'þìÏpy© Ç‡÷öøkw‘õ_8»àÞrÁý¥6Ò=î;Öq ot]#Þ\o¸¹èyמÿ¿{zÎ�÷-ûÿÑvPi Ub/x¾ëÎM¼ë”è�ãã·T–ç•óKR) äÿÃË+~çä¼�ñNàÀûF@xþäýÛìyÏÙ¨YÅï;Ð&¨¯¯·üÖ“¾÷î-ŽûŽËùâÙ�Ió€J­|`,…«1òñ›GćœŽ‘ß?=çÃLJ¼|tÀ6g>ýð ÷W ¾ËH…h�H}|ôæo˜ ÐÎ.xf¹àÇŸ»O.…Ï<>á0xž?Üç$F^ÝlؤÄ)…µÉ£-_¶|i V«žÜ~ýT%)Þu¸ÇÂ9>vÁ“íØš,m;°Í™­eÖw�ö5ÛÿÕõ†!e~ðþmÂ+ç—¼r~ɇnññ[7øÚå_¿¼âéxa¯˜öÞ±I‰§Û‘ß<â*&¼sü«×ò|Íö_oøwOOéœãÇž½Ç�¦,î1« º¿Z6ÂqßñÛOO¹·\òÜÞŠ…÷üË×Þ‰ðÃîÒ9ÇÏ~ó 2p»ïy°¿j’^„×׃çÞrÁ�÷ü×Ï<ào~ódàïþÝŸãû¿ï%þüŸÿSµ*LÙo×éæ(¶¦ÙšJÌ WבÙZ™­ýù‘[ÆO«ŒÕý@œŸqÞÑ÷n锨 ‚$‡dÑD…T+#³VGÖŒ8Ñcf-ÕcZõ³ë°=©¨õ=+1à�pY „à�à Š×d‹æ0ØþÂïþþüÇùïó‡ßxJ/Â�ïòá£CøÐúäqfwΆ‘_2R`/x†”ùÆ¥Êþ¼{Å&&àzÜwÜYô|ÑÆºÀN6Ф‰:çf3@³§_>:h͈A5áçÄÀé5ù¡oU ü‡{ôÖ Þq±ß]' æ�ë}æ�ýà[“êzüõl¬¯W‰Œ•H{‡Ï>··j2V ¶|._´Í™­/Á[{YY,i2!¾Çu+²ë‰¥£Vç§”‰)iÀ+©l£Jz/,W=KJéÏ…£ã}^xÏ <ÿü ,÷�xtyÁÉÉ%�Ÿ±Ù$ËûûÇߤà¸:?çéãǼùÆk\�_àŠpö䔯½òU6—O/n2¦36—Ä£iܰ¸qÈýƒ;ˆë8}rÎp•8½ð„KÏ&8ëG ±oͲ¯I«‰ŽâVl¢prÙ^l¹8¹DJVùZ‹U÷öö¸ycÁjÕ+玣l<)fÎ.3g—…‹­°C‚mÌì�Ž¡ô$·BÂÙm‰C؉í6³’õçÚ%Ð’Uˆ�ï1bí 7Z’À,~ȦڠjÓö<�£B‘bÙÛSvëPÁU±l=iqÍdžÔ¯ñµ¶ù;Z}^ãz­ ÐûlÄ€©8$iAAë�ª–| k¬Þ$njÜØøŽŠAØ Õé.óæíàå´ðê›E/ó}¹†‚?RJsávž-V*LZùYQª©b@S;'ÿ.Sf™ûö�;­—”'b �j4*†iö¸¸ÖX˜2=×inœhÎú¹ikš}N,Q²&®Íc'9©T\´Þi7Lí¾Ú~­h0lÂlK¯S©ÌââæÿNól"3,ȵsm0t�#ö‘BuƒK{ßœh**ÔëÐÄaíâðÞÑG×9-xÍ�§ÄdýÇ«NØë=ËÐæÄ“©­è„^ð�ÃùÖKCL†¯wJ0, ¾@J&O­QÏÃeURÅp-¯?Øuålóª”)Þh³ošúïŠ/ÍÖÞ ÷gÂgæ} ´Ò.²ó¡YL#@`;VT£Éq(MXÙ®¢Z{œN˜ÀÔÑ—Ñã”' ¬U6yÅ6=�&Œåm”�›ª S¦å,벤<ÃÎëJŸ;uNù‹´ê†I6¢¾ž&Sq¾JÄOÇhsÙŽ=_}í‚æ#";O3k³sà ÅLÐÛ||¬©¤YÆ6ê9Ùa%t½ Ë€[xúe ‰<ò˜)#ÄAeiÈ ,ç" @¤:(à‚#A5d9ª¡óÁ5B`›�ê`�ófÄR,ÐŒ‘ìŠ9PÚ$Õqí¾Ñ Ô¦÷ä”Ý8ä¶½÷ÓŸòüþŠ—ÌßóŽ«8ôüþw œh#Þ›}Ç·ßÒ>Ÿyô”ã¾k= þðòŠ×®6¼k…·ïÝ_Ñ{íã³ðžyp�…w¼r~É:¥v�Ÿ?»à•³ ~èÁ=VÞщ0¤Ôt±•¼8æFß©DÊ8ò‰Û7à›W~ïäŒïºs“›ËžÏ]^ðÚvà¯.xux}x4Žœ¦´“áúÿå±tŽ›gO¸7Bàž<Þ\ñµí†}q|øÆwºŽùÚ[ls樻ÅíE¯³D„•w*;´\0p{±à3�žâ~øÙ{xà—>átùÐ %G>v¡dƨåç!´~o¬7œŽ‘ï¸s“ ÂW..ùêÅ/îó}÷oó;'güáåš×7[þôƒ{ èÙ|‹¥p¶øÀ�Cnø×¯¿Å½Å’o»³ÏUJüÆãD„{ö1g¾üÆ#þêÝ»üƒ‡)¥ðŸýôÏðÑ�>àÅ÷Þ�ì“Ù¼]Q××Õ¬¬œºšÌ>·]tךV+d3%%“(ÔOŠ+jãÌ?Qî°fï‹õ$ŠÓ£Hˆ‚`–æD.‘”#-㈙ý.ìUWY‰þ‚øb‰AE¥E¡Ò䕚 —ëûd²Ázp~î—_á/þô?äôlà çù ‡ÇÜtž²�|½ŒtÎÑ9iÒ-N„?vóˆÏ=9mwùƒÇ‡|åüªefŸlÇöÉvhŸ¿»èy4Œ�\zÿÑ�g6o+œKáó3R¦> ¯ÙžU›^P’bëñGû®…·Wü¿=®Ëo»:Î1–In¨a¿ œÌH¡”wíîœZ¥€ RUµ×Àƒ½e#¶m¶ÌÅ‹æ2U÷=on¶mßøÈñ« ÏpœùW§§”’ù¥_ú{8„÷½÷HŽˆ$„)ä Eb‹mœín"Sl©x�Ú8mB\IJ ù-)l¬·€Çûžà{*1 Ô¸JýƒšÏâ½£ï¡Ó dg�ÁÅü<ƒZâ“«hè‚fïÝÓÅ }¿Çr±Gß-NÁ/¿yg¤BòÄ(´kÏ6çz‹'ÛãÀ·¤¨IJÞ9 d‚W‚Ä›ü«÷=!$|X’s$í;—f¸ÀN£gu•-ukpiaÎ Á{ë·d±\â}ÏÔ@·  �mO0y¡  gÉ gòFyÜ�Æ i\㆔6VA°%¦HLÚw®Ôªþ®Cº B«)ªßïTª‰ìT–'«PNSäêê ‘DŒ¶›+JÉÚ�¡ÛCdE„íUäâjàb“(n…ï{Ö[ÇÃGW\ O¹X_ñ‡¯|ƒ×¿ùˆóÓ+ˆ™Íåš“òÉ[Æ«s–+ß„á|ͰZÓvt¡ptÐqã0°ÙlY—L/ ŠŒaTb X}˜%Ÿ:¿¿bL‰#Û­c{( Ÿt|Dj/½-‹Ël ŽÚ?/ÆÌùņ‹«È…1MÜ‘܂Vd·`¤c›F®¶…‹uâârär•ÔOç;¼sÄI©0ŽZ5îm¼Ç•Šš´çL‚¯b€õu´�´èüšâ ý]FÇ9S´*¼Ô·†äÑÆ,;®Œ305cIG5î)PpäâL%¢hëÙù¸æ#h/‘"W×�jÂVfÏ-±Êâ6©‰H2-¡RWÒ,„{‡‡ÌÞ;=*¨\}+¦Ü¯¬vµ‘õ{f_Ò²ê±øÓÎÏYÒh•U®Ésµb FLígvrÅÆ¨V (ÖhÕâ-Ôªÿ–pYÁñÖÍï‹a65‡¬Î v`Ë'Ë5‚nw¬Ý¼ÚÈy&0ƒ+­›¤Éa1#L;iš—vzk§±žË×!iX�ÌÑOk‚]´§Eó„‹žyJÅöc7yÕ3w90áˆ*._¬RV1¥Uâè]$uÉŽ ™ýeÇþªcoXô,„Й¤v&“ «¿·Ä‰GŠà]¦/°· ä´ ÅİI£ÊÌE#V‚UÒötd„í Va«v?gU�ˆ°¤¤)šÐû$NÚ¼›€„2Ý’ŠO”Z%Âî¼(»Ÿi´0g§Zµb e=IÝ ¬´ažÍh_¨˜Z™M¨Ù,í_èQÿZû h8&œmšÕV)PšžÔ<ƒJªf~3Ó Ô…¯ÌZû®:™óî{§Hf–„ ¯ª€Rsêýy›Uj—7]PÍ3K$³ìâºÛ+iúÛm¤)Óšõ�‘@×;ºUGX–«ž´‰ÛDÞ&Ò&7‰¸Ñ’LAû ãTt"E(^›W‘™dÅÁ ¾óm¡÷] ëœ¾O¤-àv¹¦W¯ºg ¸J£�-0¶ëqh¶fpè÷¸ pJqädìtVG¥êŸ9çpUòÇ©±N)2–¨$^,Ðk¡Ûv+lÖÂ"@굟€x�HÄInä@]@ª©Í³²I�T�|GFR¢$)YàjÛwô§±wªß£ÚýãYå1²· ÝéŒ tÔ;©àsÔê©Ü•”lñ¡à3¤ì“ Å$ƨچcD�ñTbfLµ Áš¼,«yšúΤ´ –GÙ¡bõP¼iÖRªB�Ÿ5Ó|6'2$ɪÿ˜‹fÌ—d= .)iƒ3ÐÌ&²Ól]9Å€e�søê0MN‘bùBJŽd Ÿbt¢ 1Š1+)’°L‹ÝkÐ u¾Å@”’=¹8¼—š‚19\ßü ÌÎÙ´$“–$Ú� ÍqæUIÎÖ‘]^lc­Î�³y>=™aHŒ±(1Pd39y¾Vs1™,uÖÔ†»lÙ«NÐþ/¾�W¹ÚójwŒ+޶&Ó (×1ª%ŽLÙg´‚.;§™�Ø•j®L÷QK 'G­èèåRí‹m�ælÍT®f6~rBwì©Íݦå?OG°ŸJŒNä@ýʉ Ñì‰ZuA{ÿÔ{¤˜ £´=“·ýÔ�^mi�Y¥�I+ Š ’]»gíüfÌz•`“vê¾<«.ØñªËt¿êëöçë®yáñã5öÇÿo¾©Ù¹/.—ü·ï~ž}ïÙ7¸¯œ_²ðŽç¬¹ðÕùÆzÓ/œçCÇÌ¿å;­ ïÉ02äÌ=«2øúÕš¯œ_òƒÖŒ8£™èó>ßs÷Þ©®ýåyÖ¾÷é0òÙ''|ïÝÛìϘ3¿ýô”—x¯‘ö–ìÙy§RøÈ�#>t|Ș3_<»à={|èÆø¿_}“;Ëßaçz#q½¸¿ÇÊ;–^%QŽºÀ?¸G*…_|óû!´ÏþÚã¶)qÔ÷|a³æ÷®®øü°æþÊ]“›ø£zlræu#ÞññÆkô"¼°XðÒbÉÓ§¼:^ÚßãÏÝç<Žüü�Ø žzæ.±žlR)Œ9¼çî¢'æÂÍ®ã•óKŽûNÉ‘®ãçÞxH,ðCÏÜÅ‹6`Î¥ð]wnrgÑóËò.câÞrÁ6%î-–|îé¹dþøÝ[,�ã7Ÿòtøðñ!Ÿ¼s“Ï=9e�2O†��Þ:âáf‹ˆpÜmÎÇ‘—oòQ>wuÅg//99Yó—þòßãW~å¿b±P)*‘>yÛ“C]líÔß3UÝLÔ±¦`EØÓë™Qѧ¬{cT³Zeœ\¢¾GJ­û«Õ?ê·ViÎÚO}œ¤º×%KdÌ‘Bn4…«Rh¥6Ó³&ôF ( Q¬ qVR £RCu_,b= föøÿÛoð×þú?eŒ‰û>ðSG7xaoÅB_¿Ô±½³ìyqŸO?zh�øÖzk #z«$Ða';Àý‡Ž�øì“I2èÎrÁÓal ëW/®v€áµÉ��‚·7Û6NïÞ_ñêåºYÓœ[�u„¿E üÿ÷è¬z >®K]Ìǽwn‡d¸žý?iú™±”R&àÿÖ¢çé0¶ù¹g²hµA{áí••XyO¦4ɠà’q߬$C)�Ш�Ï<~B.ðýË}¶¥ðKgjû>õËÿ Ë~ÉÁÞ-GDŠ’¥ h އ5óµ\³SšÑà *)@ D7ýïƒÉ©œ�f=«Žw�`ðÞú¥…àèzO×ó¡ÄüIZ´â»Ê\¨_|`Ñ-éB¦ó*+ê¼'„}·  Ú@e‚%¡ó±U¢8¯U¾@¨ A3XÓ÷R ã8�bÖÁëyˆxœhï7€2Î'RŽˆ ÀØüþÝŠÙb¶W¬"À5ÉÝR}cèCô]Ï¢ï(x�y«¼)–”i‰™Î9•;ÍÚcO²‡¨ºùJ ¬IiCŽ[rˆiЬ¢1N´¿[ˆ÷ê[Ǩ²:Ι­Öx2–¤sÃiÂË«5) C0mîȹgãfäâtÍÙù†Ëm¹.ìs¹ÞzxÅééSNž>áÍןpzrŸձÍcâòìœ<\±9ßXróöãeäòéýrÅÁrI„ã£%çÇ=§'œ— …H¡£s™²ùœ×Þ{®£”ž!lÇȸõ ©‡g…ÂÚc1¦‘.L9Y«Ã×Û‘mLd,Ì¢k$Ò‘¤g(�MÖ\n2—ëÈÅÕÈzc¡ë„.hsÞ”4›5YB[.b2B…aÐ~¹()Ñâl,ªØ“ôJsœ¥Ä@t]³c•ôÕ)[“öì88]Ã¥h†y1ÛC™b³VAcòB7Pù ‚·{¤¯EvócÙµ‹ï*p)5æ� JkaÉô§ª0=Þ¾Ìþ`é‰ú²[dö2»‰´x~ªô´ï·‹põZíæWä j.“&š¡zÓy7—Î’@ó¬b ^@ãZ²©Gä6Î<$ÍÍDCÓ¾3P¡Þ{ Øžz\¿Uê÷é± 4[ ´Úx©ä@©Àüw–Ù@ˆL1ñD Ì3Dª2ˆÌÛßé_ŠJÍÉ�h­ßF*Ö·ªªJ`ó(kW-Ì+â]•ЄΠ‹Þ³ðŽä{J*8<�dV‹ÀÞ*°\zúÞMØ€,1'bNøe‡_õúÇXð¥à²Pž’;âгY÷ Û‘aˆ £ÊT#NûtñÁÔOlOrÎ8 “ ³½ªJh—J ØšU|ÅÛÏëU®¯1ÚýßÁêd›}¦>U¼¼sŒ§€§PË‹KÉŠ¹�¥g×,µ´¹§Ù|¤iEÛÉÎi?©(RmBÙŒœ½¯Þ…*»Ð* ºî¡WÉ sæJ» ;~~&ºjMÏ­¹FÃóe*‡¶g%æ¤@Ù=L@×ΉNœbÍ��œÏ9pcâéõµÔr&L§ËºZ×sì¼à�f³ûe le)}$v#còX�⬙°f)»” ¹P‚²áŠ»:¢ı6ÄU9ýæ\“rÉÓuéíµ÷ZzT‰3ÒôÖôªCÐNß‹.ÐwÞœÊ)\Vð8[–…èÙ"˜~*àÜänD�Û×J4)J¨™KºeeÉ�•JÉ€Y�?j¸48�5ß9¤ ¸® âñÙkVw² ÞRpÙCÖŒw¼Ðw…¸eƒU_rQÑûšÑ^)kó°”’jû›hŒêPˆ ˆ‹8 x§å·ŒÚwcL QŸÇª½ØªL/ÐÖBk Fe»…) ª~€:æ¦+gYu±×u,6æÎR…ÔMY*T3Ð%{ÈZUä¼§_.Ùß[áJ"¦�œ´'@pB,¡(8=õ¸Ñ™¢ÃVˆFˆŒ ½æ(¤ì‰õuJ Q›9Åh$ƒLs·ÌæUíØžE Ÿk‡ê�ö!ÐËÔH(çBÌÉú¡×fÞ³Œ÷:u‹Uâ8Óû¯¢nø¶)ÄT&WäÄ™æª1ËŽÑõ†ejÔ†5RKÅ�ÚpG‡5X�+=Í¢€u—hY9ÙܺæÐÍW²³:ž“Y�ˆ-‰3g¶9:¯Ú»Íœ2›3­Ü2ç ƒ«›‹ØfirKj ®‘T3R@¦›Ùý™ ìxt¶÷”ùóü3P·±OÝŒµÉ{–)ø¦Ú±\7õÙ‰Ì�]Ï£\;7{�‚ýMJh¾Ûþ¼Óä½m×–¡3Ìö²Ý7_{�þn³‰üäOþ¯|á �¸Óuü÷ïyo^n8ôê€�6XœƒÇ}Çq¯@ëkWkžY-¹Ùkfà¯=>áÝ{+¬”8Ç–5ðÜjÉý…ýmÙï± ý/ž]DxÑ@þW¯Ö|þô‚?m�u‚çÁj©=zÁ�që/ìïq#¿ùø„o;:à壼·=¹(¸ôï./ùÌVÁ诿ùÚŽÇðï{ì­zîÜ>àÞÝCîÞ>äøhÅáá’® ®ê¦ÉNªpzºf½¸\œœ\±Y<=¹âÑÃ3><ŸH°wx ¥ð¥Í†/m6;¿ßsŽ,W|dµâY'|c³%§ÌŸ¸{‹mÎ|órÍ+ç—|äÆê™C¾zqÅœž7a�2›¤2J)g†ÿ‡½w º-»êû~sεÖÞû»žûé{7HBRKBB��A`œ²1å`‡r.Eì8ÆN9qxˆS…‹ÂvxpÅ…+~H¹‚+ØØ Bâµ$�ZÝ­V÷é>}ÎùÎwß{¯5çycεöwÚy¿hŸÚç»íËÚó2æÿÿÿ�ðÔöÇq`<¿wï>�m-øªÝm¢¿òê‚sµ‰ò3‡Gu­]éZÁsèšÀó§ç\�wï¸Òuüâ+Zð­7¯±ž�ÞºM•mztkÁ߸ñ?ü¥/r#Ÿüä—ø;ÿã‡ù'ÿäûÐj¯1™”2�{¸Ú–22ã>ÛÈ)þl}\V»Xü>˼—¨Ä@¢UªY6¬u{!¯#y��ä êKhÿcsÍç’"——� ø—V¿ IDAT‘L°§�»^E2PÝ_½@ï]5Û5'¦Æ´Îl¢ùûµ¸Œ@æGþ÷Ç�þÄ/ðdÛñ=;ûšß"Úp¼Ü^[®¹mDÀÃÖ˜µ4g}Ç¥=î®ûúóVÛ°ß6©©ü@¶‘ÚïZœÀ¡‘lÛf ž�H Å ë~šÑ —Û¾Uù”ÛVª,Ì—o:·))£dPMH°›sŽ™sÈ×_n¾ÖE‚gúÚçúJ×r0ùùðBŠé:(D!%žÚÞâ‹gçõñ‹ 2H¥–à$jïœr¨}6^̹ßUÖj¯mùo¶o�Eøµ“rŽüÒÇþ>øþ¿JpÚ0± ‰% ˆõÑ2£@‡:$b›:Lü’„�ð>|‰«º¶¥ë:‚oñ®©}É‚U”¸¯�Þ;#21FrZ"âí´wZÚ·ÀûTa!ç¡�&Á%\1rÎá½Ð4žœõ·|0`Õš½S,¥CãÁÁ©:@ŒÚ¸ žÐ”*áRçå):Ýœ)c5ÚR%7ª~·h¯4ï„Æ›ŒŒã¬`c&åHJ^̇· ]m¢Yp˜ZRQý»œíO†S†áŒÏ­épOJƒÅÜžÖª‚¡(dúØ[|î 9ãý¨«�×^Ùiê˜ÎÎzÖ+Çù¹§1Y¨ãÃ�?~ö6÷ï÷ ½ãî�C^~í>'ëDÛ6„!pû`M3?Å»†¦»ÎC_áÚ•¯¤_®Y/WÞçèð‘Èz5pp/rzzÆñÑ9÷Nxü´ç ó¶÷w¹öÐu†(Ü?<åàî}V«SÎ΄>í‰è„‘"Âê|I„ Ÿ³öcôsœfÖèº*RNm«‰_"ÒJcÂ,¥ó\Ýœœ­¹spÄé©çpæ8=ë9>Y³\õ¬cÒÄ©‡yOÛ6t³Æ*Ãó˜Ä·Žd¼Åˆcű7_c¡¬ÊÅb326ÒFl-¹lªæòÛz­ñgI>3LF×àB×» åq�Ûb^ÁúÞM1Ãe²äŠk¨ß3~.|­G©”ˆqóæ&g­™’\«‰‹uáùЧM“ïÆÇÈ?o¼�+.�««•n#•·"wönd«C(™—­wª=®T \¬à¨W2²5†�º²ííO3,x˜In×ñ-ã)5æ+kÀÁf(“kÏãHˆ ry¬÷Î7õ—n2¶cl>Ë‘p.±¼>5LæK ÷b$6(ëh#’7,É)é%Y{­Úgv¶È÷PRÌ‹öR ñ ï2mº­üÉÁ* `k˜ÏÚ¹‡® Ž�‡®ÃK¢‘ŒR¯&9f•O&Aí…¦ ÏÎБ4]¦�ž( >4*µi8GNŽ +s%]Ò$ÎkD¥ŽIÁ.†ô6òubåÂ×É#eúØÉ¬U#Æà[jV¬šÃLÑ1ÆõHúÉF�EOgÕÎðræ�(&çŒ-)Á–°‚ZÃQ Dj™ÓdGê�“]=~h*ˆ)‰�©5)€K9˜�ÁÁ£r{^�ô{Ñl)o»éB�“NbÙ z�eŒ*‘ ÓR�É„©u@$ÙF,¤@&;Ñ!ÏÊ*WºÍh¾ øY€u†U†.B;Çà!õ¢J‘8#\Lš±Þ4Zjèµü³÷žÁŠ.ð ì+1`U%v˜i9”Ô¬sïµ�ÕFv])Á2ÀÌ{¡ ŽY˜Ï[³Ž¶ ´M¨’Bκ¾7­–£B&çhMe­L'ª£9ôJhæŠö:h[Ín ^)˜”"gò9êl*³èˆn\SF 1 s‘†TØ�f„ä$�¤Ä€x-E‡—F‰Po[˜Ïê”'BÒJ—µt1{]JŠóe-ãL™œŒ6rŽ™„j`B“i²V”òÄu’V CªM™bËŠÐC%Xψ¦Ñýàm›^ïÓ¦�ΚHcóZe¨„@íbëZÙ_©0�«Ù#IÉ�Æ·´Ý6[Û»Ä~Éòl FíÜ.�FÞB/z–Ê¥BĘ•ˆÐ¢Í—ų·ÏïF e†uŽKfS©T±Ù ³8TÆ%«¼—6P ÌaÖHÕ KM¢(WB)‡²–n"%ëQÁrïÁ´””½%6.UòÆ{¯cÓ0Õ, BdŠ÷M¾âð»ªëL-€§ÕUÅ¸.Œ®Šê`f ó¯ÛXªœPi<­M•Å‹¾ìP¯}ÊóÄ×ê)6®JÇ/›.bÑœõ#ÆYm­�iö¬ª‡Ý´Z <Ç�/ •H®ÞÑhÇs6²QF�À bÀŽ�âà‚²:¼e°mÝ—³ tžj‰pÙt›tÕÙÜðB¥’múø\Iâüøœ²v-0Ô_ŽÕAvñu¶6»ÍkÙ¼�ÑQÉ9ó?ð³üú¯ €mïùßžzŠëmËõK ú/S"Š°Û¨öþiŒ|öð¤öà~¹:f6©_syŸà• ìSâIkL¼N™ÏóµW/1 º�~ãÎßhZÿÛmSß àÉí-ÛZEøâé9On/x«U)üòí»<¾˜ó&“ º½\s#�1ðÐl†ß×òÓ{ëž�¦á»½‰>uÿˆÆ¹JH|òÞ!¯®Ö|÷#7(zÍ�i—ƒf�¾çê%®Î:NcäãáùŒNÏ9Þã*�÷ðɃ#všÀÿòøãüÝ^ ‹ðOâ|ËßÈú½ïdÜ~öÍ” Û06£$�f™•ÇØ-:ˆ®[êlæɨÝI†Hîµz0Åd¶*œWb ‰õ22?=9ý]ҪߜsÝóY4ãU«Ø‰Dv`ÙB´§Oñƒj+!QŸ˜,ÅýF·Ö°Çêg‹d~è}„úS¿ À[ºß½½Çvè¼çö¤¹ðÓ{»µR@Dx|kνõšuÒq{þôœÁˆ‡ö!¹½T³þÔö6ÏŸžÕìÿw^Ùç ÇgœÈÚ¸1˜‚Ÿ½Ðw H]îZ#ªôµæÞ³hB% N.Tñ|™ø�w»˜ý?mH º–Vll!.6–n½&ôL_$ )P–Sydã=»ÖÉ~ÛÔÞ/XeÌÅ×jœãr×n<ö­û»½..J&½xv΋gðg·÷8L‰ÏžŸÓ+>ñ[ÿ_÷Î?Gð™Fóo ¸ÎˆKÈÔÇDj•~-›\L5 D�œúÉmtM˼�Ñ´*)¤:êÍØ¼Ô@o°ÊnW2e#ëuO¿ŽU«Üû:f³ÎÍ´ù±Ú�T†!øŒwÑüh­”t–Ú„`×m¸U0Œ¸‚rš4pΛ/›†ˆH Ë£>{•«°>]•3tÙ\¶Ñ¾æ<ñýJµ�$#A3ü“Ä|½lýñb!X_>F˜€‘ÌÌ¿·çæ^"ÇSúB $­ˆ¹'§hþŸöüs¡Ñq³ä!í™ {%ùDð#©ƒ‡à<Ž‘ÄÐ÷¬Ök´ÚÙ1ë:¶æsŽŽžýÂ^zù�å²çøøŒ»w9[gfÞã£çµûk²;ãòþ—öö¸¶¿Í¥íúÕÃꜗ¾ô<’Ö,ÏÏè×='ç+ÖÊ»÷޹}ç>Ñ5Ü|òI.]»Æåë3bμüâËÌšžãxJ¿\“Ü ñ3„af=Íëëó¨kÖyg”äFç¾imCh[…¡r†¬q½ñ¡ÌB­ÏI8=_™6è}Ýg–k!ÅÌç7óЉ% £%!$°31 ÚW4&KàUÙ5ç¡í„Å"�r‹ ž¶Ë¬í‰×¤L•“R‹Ø”d\!:]/•¨KÜ™gn0ªÏšqmO@Á#ò„€›ÄîãÏy²õ6í—U+ÊÌII9*O¬V ÅKÀ�œVæ•ÁŸV‹”k�r�M ‡-4¼ Ì—ë­‡öH–Ye†êbü, ÎÕºI&c ¶Ü-X§lÄ ð"å:�€‹”Îà®,ªl�P!ü$S½LB+œpãbv:�#¿7‡�p¡$gSâ½û ¾T)dÔâ;;ü‹æy�&C›µÙet¸\2ãî1PX ŠÏ‚xGv0 J†AYi=+#’œdïH^2Çè—¦,…(%T%s¶à”Þ©ÞgãmãéO×Zs#¼w4—™užù¼§ÚøƒéÅÇèˆCfèaE"Ùʆ<³¦eÞv&}¤tYÛ9°@ëA<�4“õ¤%•ª gk-eð�[f�~N‡£Á™¼‹Š¡Ch=3Ä dT×7Š“ÝØ|´â NÁÿšÐâƒ'Ë@gÙ8úÚ9Ã3ë!±Z÷,W=ƒÉ –Ÿ²B§Û¨ZnÔ�Ó,@gZýRr“³­U|.¦Ã{ÍvXÜL2¿Í�–¬ À‚•ûæ¤[,y!fO¦A\‹ø–쬷�hs£à\”Ìòi<©Eg(ŠUFDX ™U/:¾âYOú.há‡X¹¤àR&H $µ”«¬�ï8œý¬ãß4Aåœ˪wz¦¢ç™í�­Y³ÏÕÞ ”^^×™J%BSµÕ:m\¥±†ÚKA[=çb=8Jö~)³+™#•�µL•œËA#¦ZãjÀS"Í4ñæøM2œF휺ç½/fSõþT×RI!œ–.g)Vó^KF f'Ž›ÃzŠ8JBí 3©Ê@ÕDùr7~?µÂF¨ÔóÊØ&�ŸÇÏ3¾¶Øl¡�m˜Ã7‚}Óƒz´5ÅݸØò}a>J5˜öã6]o7ê{�ž­=7�Ÿ»8‚Lÿ¾ *°ñ·×»–×ûý8Çÿóÿ2?ýÓŸÔøûO>‰ ‰××¾'C$ ¬ßiÞuy¯¾ªÞvI�úW–+f!pÅ@þ—ÎW<rÆn^ûè—ºv<-[<8ÇIŒô)óèBß^®øÌá1|è:�sœÇÄNϸ2kkeÂ;.íÑY�Ü‹ð´]Ç:gþýÑ)oÙßá+v¶X¦ÄoÜ9à-{;•DØa#ûôéK»¼1m“�OÏyx1ã¯_!¿ôÊYÌylw‹sÿ>;:â3ggÿÁª€'¹Êû¿îM¼ï=oä}ï}oû“̶Z�IäÕ7³u5ú<Å®˜ÿâ6�1 n'Ùë|ÕUã½ã‘›{<|cÞþH�}ÇX8yztÎç>÷ ŸúÔ‹|ú™—xæ3/ñéÏÞâät³Šà…õŠÖ+>rÿ>OÌf|­Ï¼õ|ÉÌ9¾ùÆU²}ù6<²˜³Ýµ$Ò[“‰¹¾˜±ÎÂ[s~çÞ}r¾íáë̽ç^¹Ã�3oÝßåM{;|òàˆ! §1òDXp­ëh½ãæbÎs'gœ¥ÄÓû;ì¶-Ÿ¾̽uÏÓû»¼çêe~ÿàˆ[çK!ðí_翺qƒvû6ó¿û)ÞÿµOróÚÎX)`Ò–5(–Ö¹ÒDÒ�[gbûEP"¶èºÂs�ÕïÌ9“†Dê#qÐÄeõC“=F« 4˜,DkN¹V@¦”ª¿›%‘¬ÚSABM8ÑKµPW pPfÑ�N[ž’³æO¥‰‘5¹N=”€ÿëÿð_ñÏ?ò)¾ª›ñç¶uÿ_ë:ö&šíç1ò…Ó3“ÕSï·ï꺹l6¡®7æ3¾rw›ßºc$ΚµŽ±âgî× Ç;W¥\çxl{Á §#@û¦½þØœ§´‘1¾Ê™•5� ÎU)FPÛ6ÍðþòíOÿv±ïÀT2è¢ÜÐEÉ !gOÆŸ/ÞâD2è`Ü/šÀ�¥>'æÌý~óùèßmÎ&zÃ×íŒ,ŸfI–[!JöðÁ¤¹ö^ÛÔŠ–ûëž¿ûÈ£ü¯_z‘×k–«S~ïÓåÍox¥OÈÜQIÍòO3æ°B‰ÓÕ9ä¡ÑDiðXf~IðÈz‚ädeÎ ±'K¢ïÕßL)‘²VTv�LJï(•D†‘³5CZñ®¦ ´mKfx7ǹ¶Æ¹ÆAÖ$5t4͜ҴpÀ4™*Y¶~"¥HjcJ"ŽóÓ¬ÊIÐ4ñs³ä 8ª¶ß{•‘òΑ�&÷ål€qI‘¬5Vä ÉžùB+6�µ³‚S Ö\a!Å5i}FߟZ¥À’”ÖÄ´&Æž˜4n!|KÓ̰ú]²¨Æ=HÉÅÔ*fç,³¿¥ �õRXÇm2«Ís}ðàbj8=Íܾ}F7kHY´á®4¤Ð±–€„Ãó ÍÀÙò˜{k®î.9Ù]±·Ý²·½ÅO<Æõ«; }$ÆÌáÑ wŽ8]ž²\Ÿqxœ¹÷Ú‹­#º™'®zöv·xò©GxôÇj%Ü;YrïdÉÁᚣ“‹OMk§Éƒxõ¥³ÊNÒ~èU~664–ÌQz%:—i•þ¢è¦4°\Gr^áˆxZ2�žïf‚WÒÊ{A$Ò¯397ø¦Õ5akO'gF³U° ݇©6¦ÍFˆÉ„Ü+±IId×­Æjæ‚ðߚȼÈUü©$iY2¢½‡â£mÑŠ{)ûÉ9#-^ËZÑãJÿÂ1º)1Qµ2ö9'QGÁ‹.ì¯ñÓ¤â¹>‡Š/jEŘe= õª¦´oJcvç’\Â÷QùÂêJÆù(¿w&ã&/[®ÔaŸÄ3ó%†d´Õåòl¤\›kò‹]²U`±ºlÄšÎ|¼¢ÎRp‰ ¹à2B†ã¹K�)\0õíÊ-®2LEqÆÎ'Y¬ë¥Éc*$£$Õ¶+±¦ÉNâ 1ß´6ð+ 8¦Üâ\®8]ΊW9QI&ïOBr�#¶hèZG3ó¸ÎA+Š�Ú¡`ÔÖãç&,ñ¸¦Bß8ë$<#ÌÚeb¶Vk¡ïB ã¬ïgl=)’á*ª"1’õ#þ4žCn2’eě˜Èä¾áQ\=^ç6% DdB �^Ѭ‚±A�«º×bŠÃA29›‰DÎx�_D´�ZÎ:iË,NõòËŠ®U Yû ÄTe„F€§àã`d]•ɬc‚å”uF ÔE>µ…(½²«ä€Vh–”LH‚Zs]ü(ÛWjÿ6Kd À·1Y2±6åjk‚]XpÚøÍ.#±Hž 8"Eá;è ©˜9HßCŽ‚D µ1°‚�Rz9‚§qžÁ8¢eUˆê ¦ˆ#UÝ®ìU¿ÌVÌd4¤Ó£ÁöºN»×,�"ù£ÃÉÿx‚wtA»|Ïçž­­ÐæºÃP¾:†Þ±ö‚$�ÏF6x¯-ÝœYèOð H–¥‘GÛcWæƒj/Žt¯_‘�#1 ¸d|›ƒ<‘]°,mk¤ÚKj`CÛ¨&�”{bv´Y‰¨dÿæáaššOhÛÚpØeÑjŒRt$Ž> Ëuä|Ùs¶\³C*zlÊe{߬a ì3jèJ)šâÞx­VÐϦB6y*1‚WNÏ›Bq‘sºwÊ—s&E« ñXÿí'ÄäÄ5¨ÜM²Ò0OB5#]èp�ßÛ^Ræ7“¬*@ îzÈ,ûD&�¬aGR æQ6@K"KF»hÆÙ7q¢T74Ð4дBL õs¦˜lN+”6:E%ûÜl“Pl�Žw¶‡ÜXÜ©Ž`®äŠÚ&}ÿ`�Xs9�'‡³C�LŸ‹•êÞ œŒ›5‰güëx𤬕Zmšø Ö—±‘* ddi´Zl¢´e©Æ*Ä€x‡äšÇnƒ$æ`Ž÷º%ŒÈÙJË5RعbBpô ²áN?ŸL~‘ǹz=Y•r¶X:N!ÆGŽMÃ6yǘ¨_ãMyà1#@%Î�ÝUXFcZ+ÐÊ¥I½<%mdóµ_÷asÐ.>F6¾þäO~Žÿñß®�øŸ}”÷ìì�d,¥j_€$—Ζ<¹³ÅÜôûóÎoÞß­D€‚�ãsÛšó¨É Ý]÷\éÚÚLø¹:ëxª ^>_!"µùðÕùŒ7îîldMàC«œÐÏ–t^eJ@?rV«†œ9bf^5 ßwí2—fGýÀ*åJÜ:_òÙ£“ZµpwÝóÙÃcZ‰Ç¶tnmÍøéãC>ñÒ_·2`ogÁ·}ý›ùÐ7¾�ïüÀÛyâ‰k¸.@ëq]Àµ¶·Ì¬ú ˜Ð­íUñ‰ì׆¦†fò¯l� �Q�í͹®7÷ÃîVË׿ë1¾þ�àþJ6» <÷Å~÷¾Ä'~ë9>þëÏò‡Ÿ{eÃÙ|q½æÅõšŸöCà—Wg¼o�§v·ñ¢ëäwîòæý>ðÚjÍïÞ;är×òM7®r°î¹m•÷p©m8"�÷|þø”G·æì· —Ú–Ÿù6‹&ð��ܤϙ_¸õﺼÏ�ùŒÏ×õy¿¸l’!Oìlñ»÷y[3ã]ÛÛ|ê쌻÷Îø¡¿õa~òŸý«`¥ú¥jÀ‰#LrQ«¢Ê˜Ié�eY<>‹õ (¿Ÿø¶®ößICTr *ˆ@²3-d1cn~Viì™Ó˜Éc¬ó®™TS[“µT³ë(@4Õ#uÓÿ¼ê©z;¤ª:UD+âüx¦¬†Äý~†ìqÀ×Í·xÿöŽùòŽMC}Om/øüñimÎúM7®ðìɯÚ\—¦ã ÄÀÁº¯„Bë øCQZÌ8‰‰3Ów¿9Ÿ±erRØåí÷r+¤@çu J¶xãÜMb÷&ÒEÀ—I�ÿˆ·‹ pŽàÜQ/ØÜ‹Ùÿ…Dp<ØHú"ésp¡OÀ´J䢔Ôc[‹±OÓl·ie€32ì®ýîbo‹«³ŽuJµ!ñyŒŸ[€Oß;ä¸~“{õ÷bä|yÌ?ÿû<õè›(R”*z”GÿÁâ61…rµ÷fÃÈú5�Ëž`ÿFbÀS‹]ÍŠÄé㚘 P$*À|6§›-˜Ïgt³y•ö\¯×¬V+mÚ 5žhÛ†Ù¬£if·@š¨ŠºV¶j²XÎ ]·E×eºv†Ì¢:L%‘ÉyJóÞœ#9 “ ªl±»IìM¤*xGµÑŒN¦1 € ÂE:&8!9}Éh5qipî5®”¼"kZ+M;£igh\³é³9,&Ë*(øßŸhµ@:·†Ã=)öÚ;! ÙälßÒ5spž,Úä6'­^Ç*9@ ´w·-óÙŒ–Ë"\§ÉD¾1yÎÎ2}NÓzBÛ��ÐK …NºðËL¤ÇÅM>átÅùþН|â]ßãÆµ]óÇOΞWnðü_åÅ—oq|ëK'îÞ9c±uÌö¶ØÛÝf멎�Å>Ððü˯ðÂË·‰ñ5ŽŽNµÙ´[@Ö×ÌÙ)Pœ)ï„àÈ9ÒZ ›@fA›Nk?8h›@ãZ¼ÎzÆI«ÄºOä¸F⚦ۦ�ymXm£VÇ«ÚéûDÊ�Îm¡Í|“©X¥ù†‘‹G s+Ä=ãþݨø‘â”JK°¢Ñ%6÷&+U®²xƒ–ìeÒ>"XÕaR°ß)Ñ!91 =‚Ð4JOª² Y¸MÍMö’­ïGV¥óš„Å$~¢>Þ®lC® ôJqŒq\.ÉyÎ)ÿjì*“Wxà­ ŒP M'±P•å‘)îUĦôzô3da‹óÊgª¸ÂTê‹;Qªáçx1ÙìkŠ<“JJ’�T ^1PŒ 3:êhfS ¨ N-® FTµB‚âW"¹xšãÏõ^ö: 5/sZßk’µ·~¢¦RQˆ.ªqNK2´ÉäIN–XZÈ ë1ã2È€CTÚ« t4­#´@‹u0–Ñç vA%ywJ ¸É]TÅ¥éͬ¡[@·ÈÌW™óóÌz­ö8[?ÌæÄÖ«ZH†¾%©º;Óÿ+T"u¹ºÉï ÞVPë3ÿë}2—Ó¯M3Þ6°5˱¥1Ùd&'Ù˜› N½Ú<þ­hHû‚>#Ö·`²h¼�èˆ5n­5\6å=¥€*“3[ ÀZÖ`y¯Éª®Æ¢0…pV6äb}€>ÐʆÆlùûÔˆÃú½�k€.†þ–ì�ÂôÕ)·Ï£×7¡1Sµ„mŠ$‹•'‰e`8ü¨üR—".æ³V=� ]Ѓs �à…¦ŠMÚ{ѵD ¬Vêl¤80ôkRì=Ë’ó#$¢™¶æj”¹ª¯û¬0ƒ¢º¸Ùîâ‚àвÆíY`oÑ1ŸÚN¯­ñÂà¡k<©õÄαn‚À¯•&ÙÊ|b¬ÚhJ�ØÈ IDAT›M~`óxß(8ënBš8 ×€ïp®4ÝQ]M'‰ÅæéÜ{çp�5s)ÖË|vÖtªºìˆ’²Êm”x\×H(MÑëAÞ4­þA�â!Fb^³ê#ë!jƒá ÑÝhßë²ÑN÷>x‚¡–4yh�B“q1iGÒ"‰TVª³³C n2-zí!1 e¶ 0Ç'©qªì·hQÌ‘£ã3sLR\)à’à“®�6[�‘�Ã1gë�¬2@›-÷1‘Ð5½Žú˜˜¥¶ɈWKœ�麕ÁLM,B‚æÝÁ”r$&­I’*©2Ù¹P½˜,µ5%«GãìðÂ2û HjV‰÷¾JЗ»êœNÞsª’Lˆ^,SD´ép.NŠ«Q·nyÕ‚3z�G³wãçØt«Äa©­c{OçËAô&Øu'u^‚/Î@É–P ]Kg§eª¦yí Ygõ ’�&dB™'AP{ºõ0(¶Ù\)‡iuxe¬z竜!å›3:¹�矽™Ÿœ™öë’ùç6^¨<Ç~ŠÝ@ û~ÄꤾÞžoµ¾~q˜‹s “¿M5ý¹Îë4)æ™×øÁÿö£õ±?pãïßÙå,F¶­2à,Fž=9ç�V�±¬N‘z¶½÷ÚepŽ!g†,µ1ññyöäŒw_ÙÇ9ÍÎýƒƒ#>xójÕ;h1¯U o1 >ŠðÜÉoÜÛá©�-ø…[·yÓîo0Rálˆ,½ãa};Þ°³ÅÍù ¼¶ZsyÖñM7®R¤ŠnÎgõ¹Ÿ?>å$Fn.® X^›Í˜yOáj×ò­]ÃyχïÝãÃwïrëuù^¿²Ë÷|ðkøÞoû>ðî7Òu��ÙSf *Q)NýŒ²ù�È­>‘M’¢J2$‚�$�„lÍã‹=ÓåŠ�0–éã<Þ‹_i¤89k…’�µå}òúO}çÓ|ßw¿šÀ½Ã%¿ö;Ïññßx–�ÿú³üÁ3/Õ5u”¿ztįá�ãÝÛÛü™í]Ò�h€w_½¤Õ‹Î±ßµ¼¶Zs:Dž¾´ËVhøÂÉ/ž�óŽË{¼w{‹ÏÜ?æ…³s®Íg¼ïÚeÖ}]wI„•5+.Ù¿¿uç€'¶·Øi«˜øµ×îÑzÏw>rƒƒuÏið7n>ÄßzáyV9ó³ÿæ3ü?ÿâþÒŸ}9Ù-K6é^š¸Wx@\%r2{‘…€£(¥”¿�)‹éq+¸¯`–·f@™Û*P²½­‹lÙ¥¹Ê ŒAT‘³;û4“jôÉ )]ª=‹�Ví56).¾°5”·h9Ë>ñ?öÓ|ô·ÿ_Þ1›ó�Å6dá‘­oØÝâ·µ/Ia¿ki'r0Ÿ:8fmDx€ÚS`O‰€ßßúÐu~ýîA%â´¶¸½Z×ïK¶ø½ {ë|UÁá�¶Q®#‰pë|³ ¦�­÷Ä*s§¶=8^�HþòíOäV2°ëÏ"Õ0ža‹ªÌèZò¨ý/ì5/ëøŽ­aï`+4œÆÈ`1Ø»¯ìó)«ŽyùlÉ?ôÿÖKœåÌéÙ!·n¿Àõ+7(7ˆ§hS«o`IÙ¯gÏømù|%œñvm_�‹ƒRü)4¿zR(2¢÷— Q=§bR)Î8$Ö}O¿^+@*RÍaß{V+ëàp&$f'³#¥t,{°•Àv%œ³¸Y¢U_H)Ûr \$3�d å—’h¬¤>£¥°_×ìnJ Aås½o¬¯�~^W¥rö£¯˜”Mª ¡ÄÕ‘â8—Ç PrI¬Ô¤Í~XÓ÷çĸ"æH&i¥š Ÿì¼É ${< Ák#ç6´d"Þ‰jz}Á7HòHòäèA¼kñ!WÝùRä‚fÒCCN^+Œ�Ћ׮5ÞıJÖnÈø˜µ¯LØYÀÖ<ºÌÞåKx¯=vöw¹r=±’@ "Ï¿xÄ+wišž¶.±·³Åâ©=®^Ýãñ&Ò΄³Ón¿v‡,+d8Cdnš÷zj§1G×6Ì·4ÀžÅLŠ9õ¤¼b�ôl“R5Zð�%žeÈ:nmhÚ†ØgQ©­,*M%11kVé\[ chDÁasޤ(ÄèÉY´ñû¢¡é ´àÁ…¬é6±@JÛ“‘Û¹œMß:mznóKv¸\“+t�“X_L‡HÀ‡˜4t̉aPyU‘¬Ê,Ym|%±$«ôSúi\£#N2Á#¸¹�ù›â#¯× ÉQ‘2ebkÃÛLwìE@cº:&ÌVùÙ'Í‚*tVÕíG­˜TbÀä3񿯻Âó@ó`W>³þW2÷ÅöÍh!ÇÀÖ)Ω”d ×4W+‚’'ÈŽÝ}AiòxR6ê$©Àb "ãÜ;§O®ŸE&v©ògæ´±¤£¤€¸<~ž²EÊ 3¹¾h‹½‘ʆ9´Ápp 98ÚÑšæœ Nˆ]£}äbb%™{úõ’8¨)âôÀuR‡;PuQcIp6fF¨Þ$•åÎy GÈ$è\{<�oØš{®ì5Ì:ט2�ËFdx²x$7¬Û¬Ó–a½êkC�8Dsn¦‡€n‰, ZF¾i 8wÁƒõðñÒàƒâ69i0,¢ †+H©þœ.#Û*—E-ïgÄt¢DÖ\š4±5á¼é´;U¯kšŽ®1CƒjÛ§œX*%ÔG!&W‰% |ÕõZßà]@\ÐFÓR45ËúÖïr’SÏY 2yú8]³!dÉæò �!è:wSR‚ [ƒG[ŸâuÝ ‘œÎX-W4>|fÖz泆 Ž>QªÑ.ä_2‰£>fÖQÇ OBŸ}Ô†MQTÒ �4fœ`NewÌ`xÛgNtý‡0!”]óY¿:Ñì«„eeZÇúœµé”jðã[ ò¸ ìŸsÑ&DA;ÊË~ g§s™²6†”Ñ.ÃÈ—¹:ŒYõZyg:¯–©êýd.±5ìÆ@[ñAÓ¢¬™ST¦þ¼qÀLœ<4Õ9ã# )àŒÑjo†Ã€>׃‘Ø©C©s"NLÒʲg²à%©`÷JPM÷ôHŠó$”&çe,mh)Þl1Ñ”¯"†ÑÊÆãô­”t©}j&NŠ›îŸéñî'_'¤Àô«øqÎm6©ågÈxèK}·j¡7Þ[6~~=gbóï+þâ÷þ,çç j¼ww—ÿòæMŽûa£°b»i6H�Ö9¾ÊÀû/œžs¹kk¥À«¦í_´ÿ·šPuþA³@¿ãaâïZ“Ç’íÿüé9¯®V¼ïÚ@u£§Y�øº«—Ùk[Õ·O¹JÝ]÷|þø”÷]»\5Åçî}Þsõ2-fà{mSÉŽ,»®ì#«”xálÉv¶y÷•ŽuÊüæÝßÙâ#G‡|äþ}ÎÒ&È´˜wü¥½‡¿úçßÏÞýÆšKÔDqÙXR÷&×0?ö$ç”H*O7î!³W.{\rHW6›׳ >–JõR‚™ “e ?KΆyƒ4{;ó® \�·|Ï·¾•¿øgÞÞqëö)ÿúþˆõóÏðï>þyV롎íï�žò{§§\ �ofŸ£;‰ïùö‡¯€k ƒ¿ùÆUö»–?>9EP v•3�l͹³^óèbÁg�Npßpí2‹øÕÛw9�‰w^Þã‰í-~ûî}î¬{¢oºq•/œªÖüÌ{Žú�³˜øŠ�-câ¯Ý¸É?~õþÎ�üK>ð–'¹²» ¹f»¦hUZ°”PÁY™}!V4Á!¸LÉ2uÞª=m1Ĥ ™’Ï:æ¥i¨CF_ JVŸj¥oñI�|Ð_;;/„àÅŽT©ÄÀ\oÚQõ4óØ÷¢DµJh²ËéràûÿÁOó±O=Gë7-ßué2©W`ô°ïùÜ‘f7ÎB Ï©J=µ³ÅÙk6õWìl±×6å±{mCBí©ÒxÏC‹ÏžŒ„Äžl¯�-ùá‡áGn½LáàèMìmïâ\3:2Õ3-Áv´�gƒLŠ…¯hæ©bK™£¥ )1Xz‰eIdQíü”³ ê zë…Uâ¯v´O׆È0 ê‡aÄ¥aª^ ¾�sqï”8Ðû…Ư¡!¥]Ñ|1WÉ�,‘,=*çc ƒÓìyAIƒ”\j4s¨�ØÎ@• Lµê"•ì±¾’,dp£$¦%äd³_ÙÞ+1P*ò½X|9‚Š*ái~¾%#õÚU¿$ç5Â0b6bÒ­Ö¿¡NZ?£ipç³É²¢•Î)ŽDBòää!7xß©ZA$êuàp�õ�“99†È Þ‘¼V9&<>f’ °N¸!AˆË3¶g‰­n`ÿòœfq�64J DǕԒšÜü*¯Ü~•ç^|�£“Ûˆ³è®^™óÔ“ñØŸ`ÿæ.[;ž½mÏË/ßbÖ ôÊ~hl�+Y_ð‘àÝ,°µð�'%èW‰ó³ž8¬µ*/jb…JŽÌp¡e°Jóì5®o»óyÇšDN½U®£êë5Áu„ÐÑ4žà…!ö¬V§œ¯VôQÈÒàÂÉ-ëa`ˆQ+ž¼3p=é¹.Ñ¢pÅ àJæ7u¿šo �J\A­WÒª5ÞÊÜ„ îÁ ¤@SJ5\ЊW6©+“k�Ådµ‹­œRB xàÛM2& h"ÖBAPù”j„ЦŒÁÕŒ|—';RL’§4¿(;Ûh¤‡Êv¯–§â6Åk/ÎNËj9Nð8Ÿ!¤ ¬b,ºHJ†¸š�º9îe¼&^•j#ï�É÷•AœÞ\‘š~€é<;�˧½²Ó$‰9n‰4DòI1VàË[u�j)6øÆã[)“mŽ�'è‡�Ùºg6ë˜÷I›7ºøW½à’ÑÈÀ_2ÇE¬wVVš’Úè!¡kÞ¹Ú¨gÖ%?lM5A s4Ù«�• J†YÚ€Ä@hC mš¦¥i:|pV`ñwÒiŸf´“"¸`öB)‹·Œ»G’S§/aŽš"6ï!kÀíBÖf€ Íþëc2�û‘1Ör)+‹¶tò¸ilNªqhK9&Qiœ’äiט+¨ E…ËÈ G�qKéŒMVŸ`Ar®±�·±F;öìETòËá\¬‡žˆ6°.™«¥¿€:ÇÅWpUY«”À臨r]AÁZ)`GΤ­BĻȅõ�8_EÎW‘ut¬XõÉ*(1{†¬½)2ÔÃ7–:aÛ´zB�z1{æœ×q±Cåܱ,ÎÉg40nšS0nÞ2ŒåûâÒŒ�¯ûbM¤Dªô•6´R-¾õ38;Èu~eÞˆÐ_œœðn¨ª½¿3©¢4Ú³ ­º²Ëú©_³8-Û{ÜÄ�}åGwCœÃgí+¡>ÍèTiÓùÂÊ[†™s8Ÿ Þ$:\ÉzÓî4Â@".P½10fk”]=ö~åš$ËÆœ�ß�U<.“ÇØ¸cÁ¬®!sx&•fãÁ\®ÇU²zô(§óP²Éy˜EU@lnT4¼îM&_&Á¸<p®§Ïþ‹øÏ?¯ Æc³ïñÇñ¨ö?hÆæKçËÚ0à·ïòÍ7®V'æÆ¬Ój5»@ÐÀ7æ]Õ_þÕÛwyúÒ^ýùÕÕšKm[Ÿ{c>ãÆ\ÿ¶Î™­&ðÞëJ|þø”KmËM“#úìá1wW=|è[!°3iT¼žïxø�5N"µ¹ðç�Oyîôœïzø:Ϋ^ùNN¹Úµ\ŸÏ8ʉ?ˆk~ô¹W� zç;Ÿà¯ýç߯öïc1ƒ”�”LÆÍÆýÿm4Ô…”µ�bg“dsòí‰)BÔ9™ýpX3b Ò“8v·ó€$zˆŒ XŒÐÊú¨G¡Xò†iÒ;Ê€D%�B6ñM5ïoóƒùøÁïÿN—k~ñãŸãç~á³üÜ¿ý,÷î+€{�?{pÀÏ_½ØâëÓÀ‡._æÚ¬CDIÅgî󖽜sô)ñK·^c« |ðæ5ކÈ3÷øÊ]•®*SâœçörÍÍÙŒ$Âã[‹Z)ð�ׯ0 ž�ݾ‡ˆð®Ëû<¾½àã¯ÝãŠÀ»·wøý³Sî�ó·ì_òÏÿÞ÷“í �ï“ÊýYF™÷bºêàg³Ñb²÷‰à“5eó8Ÿp¡Ñ(&3˜R•¦ÓJd§Õ�Ús"×l&•åyØyâÌ—öÎãÉõÌó2ÉîrS‚ÕÖAq³Å�:ܹ4¸×D‘ãeäûìÃüÖ¿ €míò–nFê#{mÃvwøÔÁ!çQ«}ð¡küæ�ŽúÍF¾åö¥³¥e¨:všÀÉù‚ýOïïòòrUŸûÈÖ¼J–�ÊÝYmVëR`¿kY¥¤Ù¬(‘y¹kxɪm8|4yî‹2À7@hï7zŽ|ùö'{k�#²Ä®þ€ÿé­±Xd*Å3¿PMp±r T£x‹¦©?\›u•Œ‚LÖvéOQžÿøöbC¦êê¬ã~?Ôk?‰f�íÖ§\f?²µàÕóe}¿7íí°Ž‰Ï—œ-{þúõüÄkÚåÎýÛ4¡a13ÂÝMmIf”0óFÂR3M�eC;ÒIµô}  �¦éÐê_•bÏÓ–Û›–júV93ô ïׯA½k}ŽTÿÖâzWlQ´æ‹þÂ]{u¥´¢– qÅ0¬q>â\P™�Ü“óš”׬V§ôý’”z„„óÚ{ÏOd-ekôeçœ6±ÉØ)ýÇ4^І‰šh‚UyAéûS²º‹èx­×+mäÜÌM[c‡2&¥*5笉T"äËYÇ=%˜SÊ€ÎK×Í™u fÝ‚¶íhšÆøgSm@”(‰*‡Ôxý 9:†!³^©Ü’ä.á� .)Àì X2XFßÖy� A¥¹Ñ³)4Á–šzüI2ÇÇGÜzéEÖ}Ïéé9÷�Ž2'+ÏrÝpxÒ³Z†¼ §>Q4± /øFh�ÅÞŒýË[\»²ÃÑq0¢iÍ0Mhµâž@žÙ̳»;cwo‹­�9NýjI¿\1,—¬ÏVœŸžs~ºâì|Íùò”^Ô‡ ]‹o[†^ȹgè×zN[FIŠyk8ÜXï›�í-._ÝcÕ÷¼v÷>ǧk�ëÉ„ óÈ'ÆØEAÉìKÃÒ± d &;ÓE2.;•(,ГóÚT:t„f†­VÙˆÆ|.�™Ý‚Ø1Ÿ¬ÊTéˆY7coo$±U\Ú‹§‰ž.9Ò ¤!C^ëk–d¡U‰eèY¯zÖ«ëõŠ!bŠo‰Á¥¡:"ºvëôMöoY·eߌý8×üAܸܲ¦·Æ7­>·€ÖâjyŒŠ4͇I6¢•:H¶ƒÛO˜¤ÊfL3níç @¢û8i¶ZÛ êV­ &ÄÀ¬Iù‘ž†”ºF“@*iwKÕ½‰lL  ˜âÔðBDõŽŠñ±±(×Q4cë`;6䊄5ªÖj‚`×W@ )Z…•ì•Ãæg�¢TÞ ]É¢¥8-zØë$s8úõš´NÈ`,x))5ÐÀk ’M²ðC$æý@?묙­Ð¶Ž.9ü2*';H*EJIj(y¥j s¼V©‰$Ͳs™Æk�Ì:¼ƒ¶mX,:ºvE@ƒ'˜ö£dGJN›%OŽXã†4$œ@Ó4´MC×¶t�Ê9¯Š·þ ¨‹éûi$.â‚JáÂ&^cA¼ê¢Àªq™’?|"IPbÀæ=‘I¢ íbJ¤¬%E21ž!X/rË€væ�fÛ/ƒXF Ú6&’�Ñ )Ž=ªq“€â—ž£ÎjÀÆrÚ¹j4’�£Ùeš&Øaj‰¨–8¯Ž„õkÐö —J7± ™d }%;•GAAðaˆöî�¤¤«wŽd¤‡³LL5N{'ø'}̬z#Ö‘!yúèXÇÌzbvF˜^¨Ójœ”FöW·ªL즘ï(]­>ªQ=m¬\È�â¼�6¢|ëªI¡Ø83ðÅ™šjÄUpÆæ$eu82YËcIø =5Š¿¤U:åÐ.`�«¦#1Á;Ë™hŒ:ìb} èW†@˜\§Îw²fÉÅñÓëYÏ[ƒÊ´oD2ɤIµD²ŠCQ‰,£Â“ƒ^s©âð.ã³õO�Ï. Ugñb€2ÜÉrŸT LÊ` WŽBDÆu1aí/²÷µL·€·SçN.Âv¸I¶Bùk!³DL܆ÊgÆ,ò(ŒÇÞtmnÝÆot.>góçÿñßã£}€…÷üèO°"·—+Þ°³mÃÕåö-7ˆ?� ï»­‚ñ÷ûž/�-ùêËû@!ι:瀞þ5W.±°×Ëo·ª‚eJ<rÎ[÷w ä~ñ•;|Ë�«õõ=°žHÞ½u—óm•m»µ\ñøbÎ;/ï‘Eø•Wïò¦½ÛÒJ„Ï�0 ¾öH¸jd†sŽUJ\™u|×#79I‰|ëÿúà`ƒðÞñŸüù¯á‡þöwð-ï{ áÐãNÄH-­LN™4.î<#Fû šiY}—ìÆÈ* HÔ$€˜4�³d;ºàé³gHžGkë%”†ZQ°ŽX#9P""ýBg×*e�ŽIe¯)Ñ-ÖÉ[•—%`„ �&€l·žïùö§ùž½…þý>òKÄÿù’�þÊ3öéå9Ÿ^žó/îÜá›÷÷ù¾k×xîäŒW–+<ðŽË{¼t¾Ô�/pulß^àQ¢éKçºÆfÞqk¹âÙ“3vš†o}è_<[r¿pÀ;/ï“%Óxç�ã3‡Ç<¾µàxˆüͽ‡øïŸ{ŽeÎüܯ}ŽŸúè3ü…÷>M2Ã�Xi”±q²¼P$òhs|Èø«Ž¶óW}hG2‰öê]úœÙn4c£4¾Üµ<ºµà³&çä�ã}×®ÔêP‰ Õ4-ÏuαÛއXå[¾þê%ž9<®½¶‚fä–ŸÏbÜ�…)¯šñ}h@`öHX¦¾ØüöË·?ÙÛëõj)·‹•³àë<™ÿåVH�Æ$ƒ¦¯•Eêü nãïÀ)cß�E´ÞÕ¾�.æÓËdªŠdVpŽÎû ²âk¯ìoT»4ÎÑOoŸ­ôÉ(Þü• ß}é29¼�ˆðê½WxìÆ4af1`1é% õ@´Ü4úý.è=9¢Yø‰` bó®e>_€óZ½Û÷,W&Ù“\’Jæ> •©G\–ý¯R<Ú?«àEgºô+R@š«Îœór1­�XÑ+�×ÄÑ÷KÖý‘ž,=ð¤� Qü• IDATKb4ÛY Å5ƬR®Ž¯.ç„/ÙûVQìÚ5+}LVË“ìߢ—]É,;Kµ²½gµ^š–ùÂ4µ'1ÙØÇNÑâ�”8 ²žW1%ú~°±ÍßÒ53æÝ‹nÁ¼›šŽ&hõ»7‰Ûœë¬Õmè”äA㣡O¬V="=Î dZŸÅìý(g ¡Ñ» ?w´¹cÿÒ67®í‘âÀÉIOЉõù™Í ~�s-Mh™Ï»;3~ø*�Ðk ÞÓx­ª‘œˆ}dBŒ�$Šw;ëß§Š*N%A ÈÍ92dí'2¬c­n0y£ÆC°ìªq/ àT^½M‰ž~ ŽHŽ¢ ©#ç@JqPù¼ÕjÅjµdµZÅ“ijR—GÞ–_¡òÆù+ûWÊX^¼�!¦]¦’øñë  Û–9WÐí<A'W“}•²P #SɃq뛺±€Ç‰«¿‡¢ÉZ~ï`ÈøXؤò!.€'“Í«àœ³øÇYæ¤ML®QXÕµÇFê€:¾fW�Y*¶ ^€¡4Sgñ)_Õ€ŒÆ¥<¬d­ºÍ ^˜7™i¢éÛ�RI[9LòÆ¥¾´YqñÑŠDTrÞZkä@¼á`ý šH#™¹ʰǎN¶˜9ÏÌVë̺šɳ$±’Dtb™Ã‰Q’Éá] kµ À Rô3å±YžwZêW Ø²¬rÊôÀa¢Å[p°ì„(‘HB|Ä5¾ðh&žJ øp¾³je.½xï�`¥leG6å<¤Q4=kµ@tگϢ%†F è‡ÓrÛÆa;,�5rµ\,G5~Êo)«§í!pdç!)é2dèÓD?Ò^S •×¾yÌHtRƒœòmp4ÁÑz“2·C7çÈ #óêGvo|u>FÍ3u’•üñUo¸(ÑŒ2F¢˜ƒ‹eA ĉ–™€d«2ÉõÐï�^å­‚Ï´ÉѦL�×,Ð~ˆô,×™åÚW)¡Áî1—¾cU…0Ñ“·Lq5cÒÙºJ9WrE¼‘Þ3¤߃š±“Ä#Ò v ×íï,h©€±ÙžœKÑcÌõyšÍ©™KÎ6¿˜qö"¢¥)f/\u¬œÙ±fkÅhd±fS xñÿ{ï{ÛvÝõ}æc­½÷ïyÞçÜ{ík?BBHl‡¼ÀIˆ !¤�@‘*A#P[‘¢& ÔRT •’H­@-­ª(”!5)¤¡M;N%ŽcbÇqì8¾ñãÞó~ü^{¯µæœ£Œ1çZ¿s¨*Jÿñ²÷ý�ó;{¯½Ö\sŽ9Æw|ÇwPJ@r ,µ¼¶úųím`zà HM„¨D-9R Þ²³RÉâðBv�mZ· ¯åiÌIÅÅø ÖÀËá‹6$¯ep&O&úìj°R¤(#FcÞnÄ’ ­‡sB TçifÍW“[ÿlV·ý~±Ý-Äz|Í‹è¶hÎV+9u¨?©vWPµ¦u[°M|æWA'çr/*ƒÅ:ëk1/Ìͤþíòñüž ?÷³wùóá§Ú¯ÿ×^â‹Ö ¢ßDÁó‹”›|ÐÁVVþR×àJ×};gtŽßvý* ÉA92�ÿã'gìráËMžh*B’ÒÖVçßtûûFçZƒà×¶;~õäœßqë‡Ö8ôÃOžq½ïÙ· µ7îo8îbóQû­ë8.R敳 Þv´Ï k>üSó•ׯðOOOø�.Iu]à;¿ó·óŸü§¿�·¼å–μ© ]AV…2²éÞBc™sï*Å%è3t ŸƒêØ›d@ñ5yåuþÁ%­ˆ IׄÚ!�Œ]ÈÑyÓÀ·™« Ø* 2edÒÄ€únQéhû xeÉ%�â!.µ³«¬*_´Ü6 R†]1�Mõ+�÷¬\Ïü]¿•?øžß½güàßÿûï}�_üØ]ÎKáGŸ<á>yÂ×ñõë}n¬{>ðè)WúŽ÷ܹIôŽúÚ²ï¾u�«}Ïûï=ädJ<G¾øè IÔt�×¶;&)¼qoÃõUÇ=åÉ8ò[¯óÒfÅÏ?zʃaäJßñõ·®óɳ þÄí;ü7¯½ ÀŸýŸ~”w¾õMnV ŒIоگ̫ٗlAfq¸Í&Ù8/˜©E²i¨[b ÚA³\­ðNŒ€¡™¡V²ÿ ®|ž ´ŒYŒñï ܪ5\ÈbûàƒÊV©9Á3¤Â¿û—ÿ~þWï�ãóÖ~E&:ï9ê"ÏÆ‰>ÒJŽßzE:Urå-‡û$>úT�"œ,˜Ö"Â?~í>‚6„M"ÍžÜÙ¬8ê:>^�Q^ج9™ÎÚçÿùÓ“ ªMšÍ9î»v®z-Ÿ4Vvµ5K›ø¼$�®Ô/ÿ:ŽÏ×Ç¡_ô¦€×W ,“U˹Ï÷x~'|þ\šLÒÏ_ë»KÕWûŽ“)5é©¡dÆrùŒ5)° žmž›�ÞZ¯JiÕ/Ñ;ö»xéÚjR@e'„OŸÏI´Uܵ¤B<_z|È/<~Æ»×{¼²7ðÑ‹ JÉÜ{ô*/]qAf0ßÃbNõé«Ï¥~D¶ë¨ÔNž¡³ýEH%›eµ�N($2‰,©�êðw«Ž•5±ë ä(etcñ…ÉLWvþ–”¢Jý R²®¸EbaEÑâš ²S™·’Ùí.Øî.Lž¥$²ùÝUjÆ´54˜s—Í×6‚�+‚—eÔ$¼iÓ{”=í\“Ǖ�ÖË é"›Ï/Õ•ý}�’y$&ÄólÌ´–À4Bqå_&$O”I_’²öý©@¥Ïà&²ì˜r¤ÈDÊ¡¨!èŸõ'Ý“#æ‡g\7â»d@e17R»eLd7RØâ]$;ýZÝ�!CHJ\ŠÎ�è4±-™ûO Cº ‹™ØeÎ.¶œœ�œïàbtà3±ìðA«ËºÐ±Šìo6lz6ÝUÜ´Ïtî ë�¸Þqë¥5oßÝâèÚÇW/xúhàé£�ºTN躂œ_pzÏ”íÄÑÑšÍ:°Zy®_Ýpõ¸çú­n¿ñ:w^»ÆÃO89»àôbg=ìFrѪ¥\Œ�œ—!B× N´ŸÀ˜UKœ°âèp 8îîqö´ÃMƒö]èuO‚c¡HalRW­ÐóE‰PNÔ¿P 9jb« ôý/Qã0çÁi¬œË„s‰l#©<Ú‚ÉÅV<®àK¦°Šžýà8ð'¹Ä~H\Y6}æÙ4àË`Õ£�,½ÆÃ&pz¾êW/À.³§5¾©d6 \¨ØÙ ZתòØUVú'/ýÀ[¯ÈŠ1ŠÉ(™Þw#o1ÇNõ{ëÕB¡F{^EkÍÛ h•G`N•=c‹ØºÔŠƒÊm®>¡Ìq«[D—ÎȘv- U÷%+fÓ°€R {3 ¨ ‘”Œ�¨¤ÚÒ)™®Ý¢Y­bµ¹ææ±{póx`Å’ˆç¨ œkäÔEd©×éju‹ú´׈•Ùb_Jû~íGcDÓl��Eº1¶ï„]tt�§ï<Á½Ûãrž˜ÆÓÐb$`:ÇÕö§ŒlGäb  ‰2$íÏ®ó°rsœVñŽJÆ47l/ºÌ:ÜJ˜Šî)ëäÀ8íãnÚ!Ó$á¢Æ‡Rç´8„ dûŸÉ½PDTÊ´É‚Ê a‡°•Â` }*ºx1Æ€S§VuÅ@r•ž±þ9iàoÌiï4°oÀ¸3F·ƒœ crŒS�ÚVªépâÉY´bV€5¸„uÎ+c#xbpD!H rN¤’ÕÀ:p.b FOŒÁæ±êˆzAsñÌ1ý4ÓnØeÝhÛ†kÍár»÷":¥d:° {ÆEYµ�cvt©˜–g‡HÇ8MLÓÄn„a„q2©¦" ¬neo PF¬�’f¦ó {X ÎšÍ Ñ6*qŠ0L�%»HŒ‘T¢Ù“ÚÌ@aàjFKÎ)¤ØÔÄ€@„›ÃQÁëf2ši1›ZUR}£:¾Í#°æ�ðörÉÙ3Yc5-I^0çe.jo�™�a@4;Z°LÖ„JuìfÖ—™¸àZ°‚5CrŽÊ�ÑÍj IYsL§ §`L§àÝ<¿E“E‚6@+ʶ�+êÀÑÔ!T†—3©& ~¤x¤yS3[¥öDñ ç³V;TGÔUGÑycõMˆD�Sê šv®‡­©RQ³­Í¢…@¤6�®E¸Ê¨ÍEï¹&æŠ,ªì9–„2Ž‚íg5ÃY÷s ^…\æ 8àädäÿ‘a5HùÖ«Wù*ãñ’iý‹¿vvÞ¤wÞ|°GçæóׄÀ$£ÝÈ�ÍŠCK¼÷î¾öÆ5ö¢V ¹° ó•¼i¯m�g)qØÅVið‘§'ÜÞ¬›ÜÐ'NωÀW\Óß�‘—öÖ ºÚwüÞ—îàQ æ FÞjÍ…?òì”ÇÃÈ7ܺÎq2M|öbËË:ï9è"‡kþÔ+ŸâÞ4ƒB]øcôëøsîÛø¢/ºI‹¸@ö¦¹òô”"Bà…—®rýM7¹rý*¥Svýöñ 'Ÿð™Ï¼Æg?w—{sÿá3²täÒ³+B�…0$âJèb�22NgêÞ!Ë>›�£k®î¯8]wÈÅ–è'ú¾#ô‘‹ç¶caœU’&ˆ'ð9âRõé½)Q\t¸à‰]ϪßÙF“éusŒƒd²KŸ)! .’s —ÊðW06”Lžý9ŽC¬Y6#8ŽÜ–(™Óñ„<œª|¥t¤²&K‡ø‚¸L•Âã&U:ÃqsŒ&2c~ Ô*°[•Àå @ym®Áp-& ÚS�F�YÊU0Ô5Z/aöÓ–vB*ΨVª�g¾­©¸_½Ç%��rQŠá>zÆö•õ»X§¥!púï¹á̉ g\T„E,ë"âzÅ©Æz¯)ÁdmSj¸M•=�TŒ±�ÞF§�È‹¡©÷ÝpÊåM-þŠîX-¾­ÿ5_9U¨r«ujïÁ*ùë]Á9!zǺóß tAãë®ëXõÞJ„0âØ‘óİ»`ØV«=M TcȰàlg 2ô¿Š°Öñ—:ù|Ý-ùk m]£=8}ú\ä )Dè“g;mé†3Â8@´gH§8 E˜a%%{¢î‹Ö3¤ˆ&àûiûf­öm#o/…‹E󼥈°úL"Db�ÅTÔTV}¦6OuMÍw]¸USßy§š² ̼Jø¸Š  `™¯m2ŠÔVܦ+èZjVq�½/'3»³±u‘ZÈêð(ìÌç¹lAÄ‚W×~÷¦$g X›4¨0gøÓT¥e»¡îzø,Ö/ÀibÊ-¶“ö,ªVW®6+ö=Þ‹”�aŠÞÀH´ò¨6ÎV ²”Bý¼‚÷•qn ‹RXšý®Žy-Aõ®þ�9°v5�°ðkÍ9pNÃaÕþž }+Ò°›uöÜt/+j“Ës>÷bŸbvÒê©ëoç°^˜Ï²üs½žç‡~±ÏÙ¿û?xŸü¤ /õ=êÅY9Çf}~ç\K œ¦Dï<+¥.ópy°Zsaƒ6øµãën^cc² àxó�ö(x2NÜß |±±ÿOSâ'î=ä[^¸Mggå={ ù¢w]=BPðñÞvàå½5G‡û ¹ðÞ{yçÕãöݯ]츶h„üòÞ†[–`8O™Û›5ßbÉ�‡ÓÄÿxï?öäÉ¥1ûŽïørþÒ_ü|ñ¿@“=¼áˆÊôµ©VMIë¾ëêz® >W÷ {fY÷ˆ([à_;MªŒXá-¹P�Jµ£�Q"5,j+Y÷![¼Mr±:}nQq"–žªû ¹Y.£É«« v[v Im§/à³.Z¤.^3_s€'Þñ¶øëßûoñ½ßýmüµüIþúßý)=Sàö#Û-Ùnù²Í«GOˆYût‘_|òŒ»Û�—÷6¼ãÚ1¿zzÎyRMùUð\¤L´‰îEÎ|öÉ _~õa— ?~ï!G]ä[^¸Å§/¶ h~ÓþÿÑK/ñï|üãŒ"üðOýsþ�¯}oã¦"jCê:re&×,­‘5®ÆÚž‘Ñ)´|Ûö„¥Ýñ5Ñà‘ Ûó÷¢Z¡&¼ÐtWQ�XÍÃH#÷XKC».±ÒíÒ|p­rós41àm/“c7Â÷ý­áÇátÎñoóæõš[]ä‘%â†Rø±Wï3–ÂõUO.ÒdO^ÞÛp¼êø°5î¼ç­‡ûÜÆÆ>û•Ós¶ É  êïÇÀµUß4ÚðÍ/Þâ½V5ºgùÅ>ÿÊ2!༭U$/îmxu!ór{³ædœx¼l [�/$þÿ;ž¯XP»^'ù´yQûõØ��‹”Ûî—EÈÏ}öásý*ê¹cd*¥õ˜ˆÀžUÈÔã³ÏIÕ •utεäStŽ·òQKRÂ듲FÅ5Xå²*‡Vÿॽ5Ÿ>»à?¾ó"ásŸ¡ˆðì✽®ãp³Zm•D£Gó~ª?ÙbæÊRÌ_H±jpë¡>¡1DEß_ãHï{b\Ó÷û¬7‡ìí£Lç8o•®q"ô ¼7�JÖ¦ÂÚnÒ¸L|«\R–«VÄÐQJaÓ™ÉÄ8ï•5iäl³ÉL㎭s”’‰!‚�A•§¤ýÌ&1 LQ¯¤Q�ÿ”'#›T‚Š}­ù©Í'ÛÛ3úÝJÙmµq®0“ÉjusÎ ÔS´Aì8L㎒''MAåvÆAãžaØ¢µèÚ@!xýŽÒwLÓHJŒ™"§:•”25ÿV‰nÔJ¨Ò5�B2¨&ªÏQt,ó”HÎSºHÞ@¼LJ9�ú\ÒHíñØ­ýz­ Þ¸"t]ì´ùtQ�Û ®ÃÑ3p÷ÕGl/ž°¹yŸ½ëÏ8Ø»Âñ�C¼ì¯W\9ÚpëÆ1iH»À³§™'�OŸNœmw\Œgƒç|<ãt÷”óñŒÄÄ­a`}x@¿ZCÏÑÑnÝJ:œ#å n…¸žÓ³‘³³‘äÐì{ج`oϳÙwˆ›†-OŸ>åSŸú}ÜðôäSVqZHÉøàY¯V¸ˆ©'Ù\ ¾#úq�lÕß2™Î¼@èß#­„‘ƒ£_{b“ $™˜“ØuJT[Èé‚§_EBp”’p%)?DÃöœÝtγ§�9;=#çDžì<¹X�Ú¯¤”S5‚Ysø¤Åä:yì× KTÿíR·Lع+LVãíªfàì™U’†4ÐoqŠE¬õú¨h�ãÔ7ÕèH*¼Q¥^*ËK}áâGµv]jT• ^Yö«µûhu·víæÅï7£?š=ß“½·íI)—?hC~9e!ÌŸ«XI­>}îÉÌûÃ¥„ŠzXÆ”õ«khñÞú岨oº¸‘ÙVJF“³YqÕö X¢@1¬Š‘(éCT]eÒ˜™†D75V‘"”m¢\LŒg#ãÙŽi(ŒC&÷Ž2AH*³Ö•ñQp!!’�2Û`—Ñ  ï«qâÈ Ù±YÖ+OŸ NEe^½Ó �d=!‹Îo•Åb.J öR¼,M[OËÙ<§å|{­²Eêg–ÓJ?[àâëS²A}8 {2$Ç2QmÙ[œ±¯5³l›Ä²TÓ9u|í Lö�‹e»[R@ƒd¿(�®7ß” ¥OnˆË"o°‚õ,~^dQœf~Üb „º2c,– ûüæ£MäúÕ¬§ÞªU*T?VW†[~YµK�ì7>ê.zâºgOÒ‹ö,Ì_‚6MuòÖëªÑ¾¶Q/Õ{ÏäÎ!½‡ä {\vHŒ ­HÎ{ºˆÝŠ~½f³·¦ëWêLdÁ�7Í@—͵øt*£tŒLÄ’éÒTp.á#Êð÷B0†[…=U«ÀÀBy4Þí IDAT‡¹À`Žxð^å *³7,zZ¸`š…¨¤ƒÒêu¢T©Žçæžþœâ*³à‹Ó{µçW¥Dê"�Å[m]Ô®9JuMêò·þ !*h ‹ëYlªþq‚÷Úx9Ä ð«l“Íb€@FÄšÃXÿ‡èiŸq&ñTÑ$Ûï­ÄVoÝã�%cê&Ñ$tê^U´¹wÎ ~YnnÞ|“Kr˜N‚1Ò"�R"¥Ä˜’5ÔfÀú±ç×Êr]ÙÆt)³­Ï¢ˆb:Ήmìö <ΠNó$øÚ@¹èÏš¡¯÷߯`ñÍÍŽPÀÆ–—`n`†ÕYæ«>ïæÄ]6é²8¿: ‹{«æ¦Ø(Ûœ¬ÀÕ’‘¼ÔLôN+«¼7àÏžT5s,¥–Õº¶ÁÏSsN {çÈA“µSu¨Ê%†«&7ä,Ÿ*ÉŠÓÞXåQ NK©}?f¦‰Ø^à]eÎÎÕ ÕÔÏ�>kª¾&\Ûúja—ss�ݲ5]‰�¥wº~½Í§ÊsâÈN û9öêôià9ƒËUꩃó~ÆâKÏVښٿѾñ/ÞS~è‡>ÁüÀ¯Úðñ{_~™R !Fö�íÿó�ŸñŽ«G­¡ðÙ”Ø�±%®õWº9‰ÐyÇ—Zᕳ noV­�À'OÏJiI†Þ€ÎzÆÈ7ß¹Eç�‡‘è}“ úäé9§)ñŽ«Ç8`;%>qrÆ ›½S6ùW\9ä¸�ZM$Â×ÜPé¢GÃÈkÛ_v刣.ò`ù™�ùڛ׸±êùáG�øîÞe»›ÞùÎ7ðßü×�oüÆ·Óöíº}/ÇÖaÒPÁˆñÖ€«®aÁ’ûu®~Ž3ÖˆI�UI)4é©ê'ùú“:Qt{ɘî¼N}tÊÞ7?K²oXÖ%x8ÜÜ8ØžOk4ìÔj…�Ùêl Uqv­-m¥ÆÁgbñD«*óM Ôb׆K×d.vÍÂ�ƒžÿì�3æ;'?ø#¿Àûƒï矾ÀG¶üÒö‚o:8¤ë#ï¾zÌõ¾çÞvàhÕñ±“3¢sü棎ûž¿û�mÎ|Õõ+Ü^¯xß½Gœ§Dï=¿åÊ!¿ôLålœsœN‰(*×Ñ{ÏkÛ�†‘?|ó&ûþ}Šù‡~Œ¿ò§ÿ¨%æÄ‹Kϳîð4ãIµM èà’f/Zb ºÇ¢×WLб®ðà4€¬6ÎIQ©ÌÊõBsÕopf¡%5ê÷ A¾F|ÈÅ„þìYŽ þÒþS~ìg™èß´9àMë5SÊ|ôé)½÷|íÍküÒ³Ó„~ÑÁ¹ðô©‚¦'Sb�6K¸˜?õà1 LégÓÔÖ7íoX‡Ð’4Giï†÷¾ö I:hò*{1pµëøÜBÃý�׎ù€IœNÓ¥å{oÁÒöTpP�ã¾»ü>¯cÿ…ã_ýñ|"àù¾i1�¼s ¸ÿ|Çó ‚Ÿo6¬~‹~þ¨‹—ú\[õ<^HO�¥t)Z›DÚÜØï.7*¾¹^]ªv)fK—÷ðÑÖWC/¡V\[õäŹ�ºÈ­õª­>}~qiWy­~œøc7oò·î«Í¼wòŒUwƒ>ø×�bbÎFí P}9ïÎ+Ãtš ÞeB,¤l¤%ñ&%‰1=ÞE‹×´êjµÇz}Èf½Ïf½¯`²�ÍO©C1YT�Ujd§Uº�W�ÿ-æÓ=SDuýSJ­¯Ùn;P¯ý�6ë92¥‰qJ`>n)#ãXHY«4‘î{Z�ZÙ—s³ÐitßtHϲ'RÊVìÚ5š“"´æ æ Ê01�‰­¯nDn±�&ô|ŨɦÄGJ)ÕŠ„úUÒ3�Ú;`7 ú,ˆßk\Þ¯•ƒ ™”,¡‘ ΋ö ˆBNÉbW×Ô44¨~ʼßyó—Sʤ$Ú°S ��.M  %�ä’PŽQcõ¢¾Dpž#«Õ†ÍzCɉÝöŒiÊÊn7¿þìlËÓGwÂÁí\¹sÁ[ßö%_»Å×s°wÈ�›·Hodê(cϯ¿ò˜O|â.ùùb`;$Êè8}zÎý“‰ûÏóøôŒ;÷žríÚ®q°ÙcÝõìí_áö�C¦œ-yÑóäÉ)�W'ììV+ÏÞžçð°çèêŠÝxưÝñàÁ#ÎN?LŒk�”„A £ƒ”´B%Æž~µ¦÷ºŸ_œq~qF×õt±'§9Ñ„Z*ÚçPL ¢8­`w%’‹·ý\ÇóèhŸ½ƒŽÝtÁnº`;&vcb"SR6õŒŠ…€��nÕã‚gÊ vJpL%srvÊP&>zÈÓÓ-¹ôt}GIÆv¶(1�ÉäVGI›Ëu&Ñ^Žu®Õ¤Ô"Ê}.9 =áê?êïÅ9#sWX»¾áóai—‰cí}¢±Û«Ïg*.`qù"iÑ’&TQ@˜+¹ØüÛgŠþ©‘*Bf±¡«1b½Æ6*õ]¼¾ \“ä9å )iü±T˜ol1&öÓ¤|\­²°÷T½˜9±3�¬~‡Úòœ¯ñ‘ü†!ç Ÿ”ùZZb ±juô¥4DŠ�³Qgƒ^@ýÞl}*&Ù“§B y(ÈP SûM)ämfº˜.F¶ç#ÓXHc!LÂ4fâ”èÒ„ä'nåp}Ad"%MÐRŠÊ”›Íňº=ž`rŠð¬ÒŠÍ´¦Ï‰8t^û·V2–”€OÆ1Y¨±C†2Qœ»ÔÏáÚtiQÔ¥± Ä66a™çÓâý8ˆÅÏç[>5�g-bÝ ý¥/]|-u‚Ö‹œY²xXº£¹â‘âq9k‚Ìb¥™N©zãbRw×Åb56Kfp¡Pœ¾ê­8¯Á¹jÚÒts]ôör³èz]/" HΣ±¸g·x‹‰íêM,’fxZõDA#¼Zj^‘ÓúÓ ¡{ÝÙëwÏ›¿ŽE]M~^Œ^ÇÉ÷Q @Öñ&;­TH‚Ö‰^C±òÑd«â(àç(äN´”fí‰èô&'t9G‡d{èÞãb$v=]ßÓ÷=«uGì¢%´1’²7tœTCËç“dR™˜r${eñHv”TŸ¥›Á}Œå›=%9r‚œ%;+‘òº�çÎi�o Så4‘å‚V2`óDûj¨ƒëL«‚‡%k~\_ÖcÀ’Lm‰y—[¡Š LŽ¢Nt¶€[J =߂݋�’¾r¶Ma ˼¦œÓéÚ\]u?CˆÚ϶7£­z¢¦çtö„Z1PY¢®‚u¼fà¦n,­ ƒyÓhÉŠô¸ö™ZT¢s®Øx-Øõ LwuŸ¯ )Æl0VRц[)kÓâbš÷³›Ñ¾zþE3žuíV#8_¸.Ñ™mmE&›ãÔ(ZV�žR“E6>uÝ·o«-Ò4ýàòµ.÷ºÊ+(=ÏAM0U[aîó¶PçŸ[¼¾¢¥e,Sü¥üN©£o’òºŠÚ{�çjI�Z•ÐîCÄd6žN´ß€—ÆîPF}uà¬È€«įÊ8QGE«1{rPGÇãm-:R†”æFEul½ ~œ{]r ”ÊäªìrU€_Ì_+°ª‡•†ÎcSœÚ]S•õ«ÀE)s‚¹Î¿°6XjO�4E=¼š¬/³£­g×þ÷y&XÛ§ª›[?ÿ¸ËŸüžoý®;wxëfÃgÎ/ZßàRRЕex<ŒÜÞ¬ñNuißw÷!ß|çF[ã�×ul9RÞvtÐÖÒ6gö»È[;-™ügó®kWšÜЯž]ðÒÞºõ!¸±ê[³à*ôÍ/ÜÔ÷žžs­ïxqOåŒþكǬCà]&7´+å8t­ïøêëWpÞñg_y…Ÿ;=mÿvx¸âû¾ÿ[ù“ßóî–¨­,¡æãH{úl‚´ÊE©ÏÅñš˜·J©Àrɪ㟠’U{r™p¶xDœUÁiâ[‚úÕŸÖuiå<½‡U°u¯‰ýù�˜ŸeS¡öK [æ@I²ú ÅÈÅî¡Vß³¥’õ~:�•sÄ"֣Ŷ_>ø¹Ÿ�CïS³�zïx6Îó]ßþu|×·ソÀ÷ýÍá—_¹‹ï=;å½g§üþÓS¾æà€o{Ãl>òä|Ûî(‹´�‚ŽÇãÄË{>»Ýr¥�üôÃ'¬½ç«®_e<ï¿ÿáën\åÆzÅ�~îI„¯>ÜçG»ŽûÓÄÇ>ýÿàŸýs~ÏWsÿŸ×ÛÿêÔ*&ŠY zÉ`²^+Æ|ÂÔ•³Rí¯ÇQj²ß¼¡âlwªÍZ)geÎ!hÿçÊ…Ñ }ÚµIæ@hß�,µÇ€#×Ä«$þÚÿÿ'ü¾ý#ÞºZñ­·oðc¯Ýg*Â$ÂÝÝИÔÞÁ?£ˆpÔE®­zeðOÑ9Þsç&ï»÷ éÇ_é;&)­™ë«ÛÁ$÷$>M‰Ó3u ¿äø�O�ž·ïúâ£ΦÔYäRR/‹´¤€·gSÙÿ1Òyפa¼ƒë}ß* €KI¸¬cÿ|pÁÎÎ("Ü}öŒ7^¿ÉfÒŸn!Ci}E0ÓïëP !Ôd¢í5ª|¡sšð¦à|$Äž¾ÛÐwkºnMŒ+púÞ„Yr4%Q†¸¼Xõ²ÊÑú`þimŠ\÷O<¥Ó42M“é¯óÿòì›!¦±\€4WG;§ä¢i‹­ cN hcKí‹PÈÖÈWýÕRÉ•…]{�)ØU}•Á¨W8¯½J©cõ:dGS$Îüb«(hñL|¼zve¶ç ÚòÞrš˜œ[T#dJ™ÈeR¼I9ð'ºËÔ¾iÞ8Þðçݬi.E{È¥LΞqrÝJFI]©]¯%‹†Ðc¯½+LZ8ÆžâÞ”\v‰3Wpeâ,dvç'àN¹½º`ÿšÆ…ÁyÂJû²ç yÊ)CäѳSVÐí Ýž°£�“0¦DJ#CÎŒÉñôéŽ+GÏ8>Üçpo�½Íš.z|Práí[7Ø;ÚgïpŸû÷î±w/ñ��ÎV±go9Úl¸z°Ï0Fʘ99;çää‚”/ð¾£ c"%ÁûŽà{º.ÓwÂz³a½^“ÆÄè'¢W’£x•V倀ÏŸ5.S5”ÀdŠ&¥X:°—£ÃÓiW [Ó¾’hK�ý v�ÕÞß9vi¢L;Æq ��cȧ[η;F°^{Ú+°T°¤ÅˆÒ@ÉRææ¼u~Í’Ù?ªvÉq‰à¦ó«Niîé|ÌQO‘ú=50Zž£Æü\>êûŒ¸[ €˜£%Úõ5Âg½_¤þ¿ý¬{Quï[µn6pí:ëK*ˆ€[`´¤À²üò Ì;D»[‡)²dû0‚¨�ö�Æ?‡½Ë'R¯U+Lk-zõoa?Êâc5¡SOowc×(—ç€hŒ=Wr¸ËxEõ‘¥Ž¨%lürÑ*‚jþRv¤ÇLNB ޾‹Qqñ<9†‹¢ÒB~Gžœ&\§íŽéb`ÜfÆQ×$àìEí;œ‚ Ñ7»®2õÆåw¢ÉtGc‡'8‡H@‚gŸ ƒO ^(K@ìFÛkˆwLkÕ䀫*°x3¸yì[Ÿæuãó° ËèeÕdÔFbß;}u]G¿R=íR„<]ÐŒ6—<™n~¡ˆ:H)O)Ô&(®8­t¨È˜5Õ© �iƱ¨SW´IŠà“ʆàÅA‡Ð¹`Î�-žì”®u*WC.–¸Ññ“»R=×Hý)ê×ÚZ’"d/§ †¯€Q-Ã,(xY401Y2R&Åœ™&˜¦Â4•Ærm½¥êTuêX©ùšYšZ>¥l[óu}Õ ÕŒ•·Í¢ê¸ã+ h¶Í—ØïN«#ªÙ©kª`ój‘1ž¯kî{P�ee’ÏI† X»Åš´Í¢˜LL©rNÒÊ‚["²îí¶û,Έ°(�½dmfÇÄîʶÁú§yåi…HeÙV·`iBs¡o[“…2_ë̆¨yy;.dtèí.9DRÄr‰2�M½Gõ¦šÖß ç‹÷ó½Ïw+m=Î_„=›Ønö¿„Ê$U¶½öYž]ÄQ²5%¶{¬ÌûV¬å½)Ð-ǾP¼Š£øÚ€S¨ºÛšÄr¤PˆÑ*‡¤6ö¶õ“l­>×€Ð[R¡62vV¶P ó”¨óžå4\t‹ë¯/ >eÎE�o{¿EÊ8§É0v¨Iº6(ö°Þ âœJ°Ô‚£º‡6¯òÒ,˜'ÓóGÛç—ÿèÿ…ïùîçÁ•Öøòý}þÐ�8àå}•ùyd�YkRàs[ŠÌ½êZ©Gt®%&‚s¼d@ý£aäé”xËÁÎ9žŽxô”ßmÀ¾sŽ7íﱉ3ÔòÕׯ°Í…W·;ÞbòCÏÆ‰Ÿ|ð˜÷ܹɯª #{aöÞyíŠ:Y"<›/mÖ¼´Y“EøùÇÏøÍG|lø¯>õ9N�¿ÿÛ¿„ÿî¯|oxÃU³©5)/õ)Ò ÎÒù0?WÍUƒ nQ)�lí9eÄчäŒËÊÖ® ¥ú Å|(G¤Eë­j3˜¯› ¸>À*4ãè&�×V?Œ…“.šõVßyÆ,Aª=¬9­M}•SЭÚg¡e¹wE÷dïµÌ=D­$±f¿®dÈ 7Ü4ÛÖì&¼ƒoûm¿™oü²ßÄÿúO>È_þ;ïåsèý'OùÇ§ÏøºóSþØÍ[\_õÆÈ¯Ÿ]ð`7ðŽ+G¬¢6~åì‚ë¿óö >vrÆÃÝ€CûSl ô€8ϧÏ/ø²+GÜFð'nÝæû?÷Yþçy?_ó¥_Ìþz¥É~Q{·Pøl![ ’5Á¼08M:¨´D Hµ9¥Ægí™8æ„­§&ö• á]­\Ò*gI_¬O‹Ù¢`öÄ»æÓK­´rB­£ lá|ïø;ïû¿{ï�·t==ŽyõEàÍû{<§ÆX~ÇÕc‚›¨vÞscÕóëgÊ”þ™‡�)¢Úðá—­rãjßq¥ïš„Ð*x¾áÖuþÉkÚè>ÏÚ®,jçkïÙæÌ�$ýÒãC>úlNô½´¿áánl,îóçÎU„–Ø�áRqc)—€jM þËüø/ÿo�ÿ'Rÿu—¯½oÉ#x}å€0ËC=Ÿ€¸ÒuœLSÛÓ˜O?¿g™€9© ÕuÒæNç/l6­�0p© f¶tªÓ^dÑ{Þv¸ßÖÀõ¾ãÉ06ù£_?»h ïTéánä�_ã×v;§Änyr~Á�ƒã¶5 _”tTÄ-È6ÅünZ TûYy§ ‰²ç>ôt}�=.eª‡ 1®¡³˜eÙûHš¦rJ…qœOçð�’œº°Ö'U“é&ÌWA|ï!FjƒáÊà,’U²Ålm) P{çè»ê:¦)“¦�”2M´VjyƒÐ|‡s :¹šÀ-™4M”lŸuZ5¡ —Úzõ7~tRž˜Æ‰qœGÕÀö•¹ï±ÊYcÊ‚%!l³½$QýÁ¤›±&§âQ 0M9U¿SÇ�qÚQ“1j5eÛjEðÑ2Áª ²Ý�AžAãtAA౨¿.%�$‚/V©¦q½·¤Q×­Y¯÷p¾CÄ+ÉÀE|ðÄnE*™‹í–a;rö,�‚ÕëMâE¿áè`�>nfh¤F¾PòÀäv”pŽë·t{«#œcÚj¬*%²„áÁ�_°é³î"ë.°î{›ŽƒÃ/¾t“^ºÁµ;׸vû*GǰÙÛ’ÏGž|æ‚à„M·â`Õq¼Ù'¯7ôaMŸ2N�8¿8c;1%åjÄ]X\GÖ\¿9XÐÑÑ»^KN“'¾‹d¼Uf(•œ¢I˜œÄV[«RïIű´wâ”) %�+^û¸  ¦œæ;Ä.²Ùßà%±½8c¸¸`{qNß;ܪ#Ia˜2Øe"I@|gî°Í×K/O³Œ–VÍŒòJ&©•÷fg�ŸAlæÐt¢>¹aÔˆ1—a5·xß¼\æïbù·®a_|H„¹r·žZæØkùOsRÀè¼B«ÀÑäkEæoA¸ƒÌîøRú§ÝËò&dq—æÇ‹TžÒx®â0³_ªc»HD\ŠUm?˜Iáõ½¯‹&ÍU»#Æ5­Êõnæ1u¯{6“Ðh²ÆÜs‚@mN.™\¦FhކèÈ® %ÑEÏzÕãWŽ5Š[nIä<0�B¿,°)¤q �£ö|É�è]èc¤‹\ARÂ¥¬/YÄê8Äy“ÊvV)ްë“s*ëíúÈA܇µ'GòÐ��„‹ O†\HÕ½(bJ ÚÛSE ¼î/~&ð–“ÚÞƒ[Ðë|lø‚%z¼& j þÂw¿ë{g´¦>d±¬¼Ï<¡º¿˜*޲"ñÎ@Uß@––-\€g5pÖISÓË5>¶sx=OŲeŽbTâ¥ÖÐÃß•/ríw,·Š€€ï#¾ªßh•ºÐ*%´Îì6»mLlP]û·Å¿·Åµ öæ »}æ¹—Ã §«­~¿Ìç¿´Ü.›Áù/n65)àê3 öÓ7ðÛ§ãÖè¢Ê DgP ÏÆÄ.íù;c©UÃX Ñ;V]`½îØ[¯Ø¬zú¬”Ð�5t!°î"«>²î#]p'tÑ<ôÑÓÇÊ + Ñ)c·Ðü'h¶Êì†Äv71IH FÕ(¬ZùuN»–4�3¦é嬢˜pyqU+Óás„È ÒÃPÆÂ0ÆI˜²�²2&¥Jž-ÃWýyì%¦�^ÙîÅtñ­OA†);5aœDÏ?‰jç[¨êtV6гÆÍ—~çgg¹�miVƺÞZI Në¬m¯Ó±‚E~Nº5Ð{Nè ÚέúgóY@¤ç¨à~ƒ¦Í鮯 ÚÖ°å½è¸R™_-Y 5“ÝV^»fu&ŒE”«n÷eǺmX" è|©ìòºiæ¢ì¢º:U®£På`Úê­NR±ÅEZye]ª�`ìæ±vÍÖPfL®z?­­sóï�JÚ´ºþ]%w„Êú¤IDë[33]Xõjnׯ¼ˆjNg“˜ÈÅt*½ý4É q­p)šìÊm Ô9d}#–ÎH© †ùyµùV.¿æ¹Um‘Ž]K e�iÕM1Y!7ŸÐ¤JJÖJ¦ºV¥Tí\·¸ÞùºŠÌ÷P6}ù& µØ?–óË/×Ö¼O‡àUÂ+hB¯&«µ±˜«¹Ð…ý¶=sYAÐ’íqzÎ;¯ñ%LJ|èñS>}¾Å{ÏW^;æ³ÛiÊœyxu¦Äùväo{‹Úº,º'åZ6ïUŸY²%w)óaŠ´šP�÷¥êìó§g¹·ºçÖÖö³YÙšÁg™{àT(©VxåâŒa¥ÏnÊŽ19¦ÃT_Â89†Qø?æ—ø›ÿð'x÷fŸ¯XoøÖnq74Ýö·0•Ò´îráÉ41¡óžó”xu»Ã¡ìæmÖŠÞuí˜MŒ (Ý„@p®�¬E„_³„ÂaŒÊžÎ"ÜÞ¬¹Òw Ü]‡ = Lí‹\Z“YPð6Y¢rBc�¼ýè É �6�]V$‘ç-éëþþ…ã_íñ/ßõsÏoùççÿþ< õ0ÆKòD›Zõ hUÙsøKK<÷ÙÛ›UòëQý,PSúÌš×wÖ?«&)Þ°·&‰´ïÞ�‘ƒ®ãÜz ˆ�ÇéÒµ<F]]d½èŸpØE¾ìÊQk^¼K™ßyí*ï;ÑÝv8ܻª[áMzµ½|dn¼ÔkVPXe�X¯÷X­6àÜ¢‚Wï]õâ#ÁÏ!ôÆŒ^cßb–6¦æ§”˜ÒÔl�óšôÄÀÔ6ßJ.Ââ4žAZB5牜F%œ¥±1ò³ýô>cÐlA+¹§i2‰žD‘l¹}Õ[õõ¼ÿ^ªô”Ù¿óSÕÍ8!D%Ëõ+ºØ£2ð5žH­?Aª0j)IÁ/«¬×¦Ä Ó dNè³R³Ae IDAT÷΃ù1D­7`?ø`1¼XòY×CJiR�l•qö^�&”É|´þuœV`T_\¥e#ÞG¼õ¸ÓæÐº�Å ÒB¡ë躞¾_ëkµG×o€HÎ:ϼ�š„JÚ<7O#y))A)t±ãèxŸ7½å&oúMw¸rå›Í¾úà%q~vÆÓ§�È)c`,™â«ÍG‡Ä®o1µ6³öäɆµx$Á8 »Ó¸CJâö�k¼éÍ/rýö1×îáü–w¤ó‘ñtÇÕ£=nÝ8âÚ•CŽöYõ+ú¸ÂÑËžårŘš8ÉHʸ\è|G 0ìÒ0iÕ^Šx²Šx£ëZì-6>)“&!§ZåÚ<ѪˆiHÓDNZiŸR¡$kž[41ƒp|¼ÏõkG”2qvzÂvwÁ˜±ïÙ?<¢¸À“ÓsζSä(R“:&é[“Í_™±ˆþ[Œ¤ñ˜ÅäŸÇÊ¿ ¯`FsÀÕotš¨ÄdIÈÁ5©ë�Õ¸Ó>?Ö]³ÓÕ¯š/„Ž\Žî–×TÁüúqWÁ>™ÏÕ’ËÏZ_¨‰ÙJFœûj.Dl©à¸ˆo±0õzjŒ[ïÅÍçŸÁ 'YŒõLŠtmÜ¥>ÃçžËoä͈Jµõ‹záòwÎ?°ðs-¦n±UÕ€šV:e!ÅKɤ¤ýª|P¹áUðçIY±Ãa˜¸¸8?ßqv¾ãìlÇùv`œT&Oû±tj·}T;›!@ì¾s¸•GL5ˆÎ)Î¼Š„®ÃÅ` ?ÅpWí �‚׊�€ :MÚ9êœÓØÀYØèƒ#%û´D³ÙÿjÓ½íYSjBezIêë”Òý3º..Š�M¤Jžu²j’¾Î+ N_Ù¾úpÅfL­8ÐÉoयˆ‰ÐÁµ€°6€pRõt3Å@.‚ƒ¨#ÒôÌ 8Ó†­ú�N¼ÊÕkÉ«^nKÜœ©I…6)¥]"Î-’ò³q[Î~×þ²ày¹]ú{]jŒkÆ¢qo#Q°+­!G3K³Th]1€¡N·øXC¢êÃ4z|Ö`¿xÕ´rIpSQf_ÔFÊ\Å’Çå€L¤ŽœÔ�±£ë{¼“” ' �û] t��öÁ3Œžq€‚ö›è]!ˆJ'˜$1bF__e·�SaÃ.1ŽÚˆ¶6ß­N©·Ä€–7f\BËL½:¾�ìœ]Sµ˜4‚õ(¾�ŒS‚Éûi*š(lT§‘¹dλ å¦8+ê0¸XÃ\© ­�*eÎSÒ„�²ãs{–Z>T¹‚ºª.©,Œ®Åæ­­ÝÊ^A;lj´ø¦Î=[C¦çÓ¤Þ¤:{Wªe}sÕ€.ŸK«Ã®ÃÀ¤z­†’¶™,u#5ÐÌë¼® ¬ê[£ak8œÌÁËR×AõÚ¥mÔ ®%Y Ç¥®]mHfëÜ+¼¨Œ‡«Ïtvú}qhñ‹eÒ-£ë€R׫íÒ {ú&¿\Ïí{-ˆ,¶A:ÛÔ-ÏÉ&U§ÃÉçb½6ÇeP»šûù9/ÁøÅnmßPAÍåü°{BÚÛŸûj›ƒµÌØé×ä��¯>—Ú»&©tÊ ¾,‚=»­�ÑNÕÂhTåÊnÒDŒWgºÌNOeÞ—bv½ÚJ™gÍLÂlæÄ۔Ħ—÷Vžg�½GœÌ±�¯>aõkòjvähÉ87›÷º?y·¨{1ÿ¬‰{g“@°ùºðºæÒ´× ·—û÷·|Ï÷¼¿ýý�ß¹ÃV+X­.}¦J�N‰‹œ¹m@ý$‡?å«®_mï=ì"qÄ|émD<•ÂiÊ\ë;¢-ÿ×ýG|ÝÍk¬Ì0=Ú�¬C`m:÷o:Øký Æ\¸±î¹±î)"|äé)o=Üç†5þÙG�9î"_~U%ƒú@f�7îm¸¹êÙ„ÀÝ퀋žÿòÞküòÅÌäü¦÷¼™¿ù·¾ƒ—_¾b³Ú½åþ^­Â TÌ#[�„‹çOí3Tõœ½gÁtRpb @¶ïöæéÆ2!”(¨¬¥@4A`óÓM& ´ÿ@¶Åš—ÀÄ›dö{lÞ7Ãl@¾V x¼h5ŸXõV.š(Ÿ LÅ]J ŽIêUµ1O×yÖ}ÔJ#Q©B�V5&k6er¦l‰G“0Lº—$ü¡w¿‹ßóÛ¾‚xïÏòwÞûÓl‡‘{iâoܽË�?{Æ¿wíA„Ã.òþ{¹Úw¼ûÖu~òþ#ð»^¸‰>b:ßC.¬Ö�½8™+ïøøÉ1âþý£ÛüÂÙI„ô�ñž¯|o¸y}N‚Š´€°Mÿ…kæë&]�t™-çmŒ— ¦º¶«{*Ò*÷¬µË¢U–%A[üíTb7÷<©sT|KÔ*qA˜RaJ™) "™_þÌ]þÆ�þïXmøšõ�÷|üôŒ,sõÂÏ=|‚˜�8èbk6\Çü½vŸ!+к ¾%>ôä„T �s¬ch’)x×õ+|ðÑÓæG¼ýø€OŸo›DËù”ðó©Øåܞ啾ãdœÀú†½5ç)_’ Ú‹—敵]�*!Ôy-,_²ÏWÞ¿Ž�þ…ã_ï±|vËc¹ËÛ^|;!„¿àfÙå.#Ö]-KdµÞ°Z¯‰]ÎäP³tÔµ1’&u·ð gÍq‹õõ·s‚´¾PÀÔgHY«fñÙ|3cAT9\T=~íåštd™&¦É˜¡Îb‰"ŸÈSRÀ;t&M©ºýÎ’!C³Ô{Ñ+/µéo)ˆŸŸu6R¶dIýjÅzµ"xO)‰qÚ1oªs›®/�moM”2é^R RÇn±?8¡V«Ûè‰^ 'Îô®—UÎ>ã�oï-1¨»aŸ×˜Õ|šbŸ‡à<⊈2%C‘ÕzM×­´2¹ ÒJÓÈ8l™¦�>:úh=ï‚�kìñ!"¢þÂ8²LÙ¼S™á,h¯½Ž"›MäúÕ#^|é˜7¾ñ:/¾p•ÕÆ@Òéœ<�û™Osç…—yÃ7_¼Æþ�›Œ[OÚz>õk÷ø0Ÿ$È3.¼0(‚�ìo6ô] §-’wx¯,›Íšã+¬ö"ĉƒ«¡;¦<›ˆç…M·ÇñÑýjC‘\½[áŽ"žŽƒýCN¶gœîιϸØ^°;ß2n�«Åqqú”´,Ö…ì=Ù$f$d|ìp]o9štJã`(¢Mšñ™T"LŽ4%œK„ ¿ LrÁ•„—BðÐõž¾t«È8gÛ ¦q¢‹=«½#ö¯3¤üRÞQè(%Zò"ëpso�99`¾mõ_Ì(\Zÿ û5Û s�­âå2 ¥+'X¼¯ñX T;V}s Þ;Ï}�zñR<Ô§¯`|{s ‡�Œ6rñ.Ç|G®Ù¤5Ÿ%Äkôð³÷®Á¶-WyØ7ú1çZk?ÎûÜ{u¯Ð½HB<ÄÃ`�ab"�Jb\e*)á�Tª’JŠJçI 'Äq9UŽÿ„$Æ•¸¨8®*å‚€ E! ƒ‚ ’PŒdIô@º�sï¹ç±ß{­5gw�üct÷ÚGò�”Mþh^-�½÷š�îžÝ£ÇøÆß0Ì•¾Xaàfã›�aŽŽúä~LÌïÆÖ >í†ÑÔ ö¡ÉçŠÕ¿7lÔ}ÏÍ”©Úig_S}&“E­7kÉÆÁl‹š�±ó^Ú~h€�ÓŒ'HíMàYÏ–Aà„Ö§P‘: ‰�ÌAXÔ“8ZsI"[9µŒ20†1Ä€½‘ÀE°BoÊ{I⬜!T^ì„}fàB„’&ˆ]”l س0žXÆ82btðK�C^‚P0ÆË8`',ÃŒËMÆz’`jɘZâlïÀæ8I $YJ·Ùm0Ê=�¶_‚,¦«îc=£ƒÍÝ@CDµX > /}�Ž7�4Z�YR° h¨ÁjH£8}ÈV4*ÕC@}g×�®DÑÖ5¬É ý†¯(šSÆæ¦T�¶ƒjÔ›!ý„¨°+cC¶Ës?^¶h€ú`@VKFj€ R§ÖœÖkì=hkúŠ—ÖǵvÁ'‚K‚\™•HÁd¢SöpdÞK¦„3nF@Ác‹À–H¦Ì-ª(iÁgËX/¼gÂHªl‹Ò]ØfCOÆÒ}©R©ŽWî~èêÉdBÁ.¶9S¥E¥Sª^suæ¡ÎÇe 3úe¿•ñÍJåm·ÂíÖ•RØ.%ÍãcÖl‹Ü9r6º%�z%§5?tûfÆK3jö…Žœ#qå ¬‘YVpQ™t­³~Ò9ÙG´ÛljrÀÖ«8¨Êˆ~ Z[Qù§KiÅ'íäž³ÑÆJ”'ªSOo¢™€Q…Ô¬–+J«ì¬ï¯†K´;Ì¥ë“ÓTÅnc§î@©F̃£8j‰h�òg ;œÎ]2¸µ+ÂI*×ZÈ]ßIa¡%”ÛÕ¨Ø*v!4UÎV'4£¶¥¬?[TOu�šÈ6†Ö¨z]+[c½U÷æú·ºï`wÌ«¦h'èþ^ ÜúÚüÙõütê_ w—´Ù÷ýù÷ïP}Ûj¯)s^¾Üà øš08WŸH‘bs lsÁà¨:^¼\ÕBhS î]®qSïå‰ðÍ·®×{ü€£iÂE*xn%÷z´�ðÁ‡GøÞ7Ü'DU 2øŽ[7P ÜŒÇÓŒ;‹wÆ—)ãÃ�ŽðÇn^¯5 î§?ñ¹—p¤ Œs„ÿ‹ïÄ�ÿWß¡úÅU§|©ãHÁÓ¯a;—« dû½Î×.’©Ý·“â6çL æ &Íþ X†£:Ž8@¼Å@$°þ‹š¡"Æ¿ªlH or[ç™:¹HjmÒà­%RåUVßEæ,[—“:À­à®‡*$1†$pÎ�’¸ÊNj iÝ´ÍØn'ɪ+,Ns}ÞœI×uÄŸ{×wâ_úæoÆÿøó¿ŒüãOþ`½Æ�Ý{æÖ-¼Ó9)z› ¾îÆ5¬sFTGåÉ4ãdNøŠÃ}Ù‡™ñË/¿†7¬x×3wðÒźÒÔü‹Oß�s„?{ë~æáC”Âø;ïù üùúAÍBj2m'^¿tÿmû‚½o�Ò ±©¿ºn‰«Ü°¢ñRǤé¬ý^a[€ñ°œúig/¡�”uË"€d3΄í”0ÏŒûÇ'ø~ñ½H¹à­Ãˆ?¹ÜÃW];À}¥d€o»s·SÔ‰±ÛÿÏæ„÷½ö©°Ô(Ÿ8J”çV Dç*eÐáñöë‡ø�ûu�Aœw�Îò=—Þcá]ù¿PqáƒD]ÛÞ|o½­ú sʲ5žYŽx¸�+À[z�¨Ç—œÿÿƒw˜ºLŽ«BW C3PÏ�D;uBØqd.ø"úùÕºÌ_�§i†%ì�Ñûš {]Qku팚Õlm]8‡§W‹§Á¢£Ã€�*5—Ä ަ©öé…ƒ½ÇÖ×ݸ†�>>Æ:|Ûr… gxeš°�7¸ò:Þx÷qÐi†!³îp)”Q8�‘”=" „ay¯¶L©õ¾XíÌ–ÂHUÕw` 5¼9dϳ¨c³Ù$†Mêt“»í¡ÂPPD£‚”&͘‘æIk šlä ܇"ök „qX€ÙÚ„0 „¨Ù¤™ÁÐì`°Ò˜’èþ&ëk}«ñ*Ù qˆÇÁ;öð a ÀvKÒæ<#—©Ra2wûˆéî8*cco¶ŸcÍtpÎE¤ö ‰,§8JðÌ2%PÖZ Pݹµ0ÑßÙ—úl³©È> +¡‹!M¥¾�Ó6bCt•yš)È�(^É\&p*Ï­fClrHÝ ç ãðÎ#¶—^æBb¤í„¼½Àñƒ#¼þÊ«8Ø¿r{Ëöü H0¤uÂë/?À|™0RÁ6�Ї¸{{+ ÁašæÙ¡ðÁý ƒyFÉÃÀˆ×GÌwW giÀÞjDJŒÍv ä€H#VÑc^ŽpX®nð×°MkœŸâì䛳ۋÎkl×3²6 È.ã„^Ñy¨c`‹”6²þØ�(Â{Ñ/rN(‰Áe â„qP– ’@NÇŽ…£½”„è–CÀ08„0'l¶p)X�{–{Ã{0Ž(PØ ½2³ÔkTÌÅæ­Ù“\í(›»\mϪŠq˜íÚI½žm¶CéÅe~Hö�¯2�»6Ø.°Ñîk€v]ÓLí\î®×õ×™OM¶ÕgqµÉPX°w"˜ü+]ÀvkkQ›Mì|B,µOdX•v,2¥øÕ±Ós-Îq#BµÖÂÆ&[z@ŸDÎöÙô_MiJg×0ê; îšfçš…„®÷èd¿Ê'›[–  èÕ9E‚1¶æœŽ þ0gÆF3jæ”1Ï Ûi‹)mÕ9Ð²ÃÆ¡`1”ìÔÉ©ø&Ï à“àã®hVÕ@£^1 ÎÌÄ`—eífBÙÄò…°œ<0ExFç±ôgaÂéå,Ö%I}‘){¥+…îÑìéHœœa‡\§ JÖgÛ¸Ô·D S²¿·Ú +¡Æ¹À•ÎI¬>ãTЗàúQm\±ìä³nHh/–X .Œ“©¦ÏWpÞ&®±¦¡ |]ËÐí~@ Üu˜GŸ!@6 %¢—«�F50³"(Æ�e“ÚV5ÚXµ'ãÀ2£¾s¨EÕ4Œ‚£Ÿv×!Á´¸¦ë Ÿt¹É·¦Û˜Ü­sO÷óËþHÈ%Ôìųíÿó/½çë ž ?°:€'µðú¦µê'gؤŒàö‚ǽË5îA@Ïo¼u=:©‘Øo¿~ˆ{ë >{v@(~|§Msu ÜœÌ ¯\ŠÃò…ƒ=L¹ÔßWÁã0†êÈÌøÇG§ès8\Wú²c¥r DøŠkøäq;ÿ*Í«ëÝ¢±ÙöˆSbýE"Õ¿tü³?ˆƒ£°ºü›S ­ƒö>¯: ¸÷4áÉÌ�Rm8àÚw Oß^ x¸™v®í§ÎEʵ®À*x\¦\Ûúüþ ¯®7µÁIöòVm¸M);N@œò€dâMsíÇS‹{!àÓº–3ޝÈþí�‡1àbNøŸzÿÅË/¡0ãÁñk¸}ýìï]¯ëíYÀ$�‚¹0œqDˆB¯�d즤Y»j[*Pײèv©0Û^g­kRF+Ê;cš&€2 „fG(�Zô¾¨ÔÍÉàUgÎyBÊ[åÓŸk6@{¼Ñ¬Žwº¨krqõy¦}‚„j†³ÙD¢«Å8 †ÎE ¦k”/>©Û•R`Á\4Á°@ŠKaM¤1­`µ‡÷Aj †ÎhŒ´N�÷Ai‚�2(’Dòj±éR²èI8q2À«}aYB÷”qq¹Á£GÇŸ:ÃÅYÀݧqûÎ óöóæ 'kL—y&0E€�ÜiRÆè�Kl®`@Â6:p‰>JF‡¦�0Íâð cžfŸœà0F„a€ [¸P°Xר0bØ`»Ùâìô¹ ˆã¡òÿoà)ãÚÊaÜ¿†Ã›ûˆ£ÇÙÙ?<Âç?û ^yéu¡šEø„QÇšP¶e³ÕôÀ Æ æ-j† ¼Ð©Ì%%p™áQ€8Â;�à%³šØ"ª3¸l݈½…Ç"ž2Àâœr0.…îiÎB§œKc#€‹³¯6  óÂh¥ÙØŽ,¸•N˜¹èQêg¨M—oÓ‹Él*ê19Õ]`�âÚiT{´Ó™}Ö VìX¬5p®†W»x§-voîž!-o87À›¡”Ä*E϶ZNÖªøGcT€:(ä9ÄbG°®½{CqV Äf3<;åQ‰@®k×;4 ¤ïWé5Í+¥ŽæÎCèÊïW°LÃSà†?ô6l�kà “`WÛDÊÈêÿ€R1‰¬J<‡” ÎÖ‹ÃlN3¶“ÔúÈYÎ;xï0çŒ9œ�œ Ê<£,¢Kð˜€à³C( €|”ún^‘0—ó&/u ÁSAa¨ÁïgÄP°€¸ôà°ô�ÄÑM\àœÇ˜ N‚¯RÆœs¥uö$TI‰�P4xªF Ñý!Žd±õœ3\†*>Û»m‚cÛ] œ5вêà,ÎæfÌ4�U�i5cÀ&ƒ³ÅH꟪ˆš…‡±ìΈU8¬0ŽdÐ�zwCsºp€þè²êDÔvËd ‰Æî©ž˜ì 1®¸HTWM­+ ˆ¡ÝùßýÊ30mÜ;PK7`@`»aH4AÑœú]]©rm‹Úv$UŽ2kZ[l0�7;¸"¿K‰Eq0|æJ"¡ä †0K�€°Yéw²(€€ò«•ÃÞ^@#âá}Dô¦ ˜&›!zÄ襈®óBÿ‘¤(iF‘ÿM%’¢Ò!Q~bDŒ޲Rìxq D' žàMÙc¨c¦6†$sh:P¾â˜7š–eRY÷\£ë �Ãßi1�F‹c™í:¤ˈBV-*Ä”lSÆ™[th›6¤ÿ“H@.\£…nÀ¦×±ðZê:’¢ÆêÜË)¢±°¶´:º™Êew#6ð™l 4@¾ÎÁb,z6µ¥ìxÑïKÎH%cÖš=_*ºks_[fæ`Sà»O.®÷�ÌýËøMõÚ@ê;‘T4ZªTP õ\£—©)…føh{“òpj“«³G˜ÔÈç‹«óTÝEU~�L°ËKeO¡‚?P§š“€ëxt›Õµ½+ý·doÙT5jCå-+ÄÝfq}áÍáL€í4œƒ µëÍéeë—h¬Ö\$L²yZûIk Èu]� {ç¶•èv ê5ÇÀǸ*X`…ˆµÝ6µwÐ~ÑÃ^F©Ñ È,NðÜí_6‡,Ú˜m#±ùÖæn»§Í‰öâ¨j¶Òæy.øÑ}mÍ»ïÜÁ³ÃP?�23nhtÿ¶|úô_£´@áòï�¯8Ü @ÍyÊBñã69ãƒ�ð�OÝ®ç^ÌeÙÆèën"é{Û”òžÿ IDATR³¦\ð±ãS|í�CìiM‚?<Æ›öjáãk1`îDËó{+<³X€™ñ™óK<³\T‡Ãßzýuüo÷ï×Ñùú¯¿ƒÿëÿ Þøe×ê˜5W\ûÿö–¹þü…¶~¶¬=×±C‹êSahÊ¢mF-"K,Då°Äà€…D~¡Fià…W§®g€rm=Ëß®êžk$SÛuýg¡0˜ÒyÊ ì€DàìÀì…wÙ9I«M¥Ö™“fÔ©s «ŸËÖT®”x_0ÌŒŠ®%un•–�°™ë)cš•V¨8-p,ž 4°mX¿é-_…ŸüÑ·âï¼ïWñËü |j»Å_¹ÿ*~pº�/‡8¡’f¯Æ€ó9a/|øÑöCÀÛ÷±~íþC€?õÔmÌ¥àý¯? 5ÿú�;ø_^{ ðwýÿÆü¯ýP�Úªu%t–ú%¥‚øMžjÑa2çxÛ3L}s�Î׫²u6 àúÞM'™@ÊhÕÂ&÷EäH&³Ð'æB˜™ðÓ¿ú+xõñ®;�ïݳuGøí‡G¤àø~µ êÝňo¼y ¿úꃚyq:Ïm_ð[#3ã  ÞU.ÿUðøã7¯×ñÄð{'g•ÇýõÍV"ôx´�êõÏ­–xår]#ø¿êÚ^ºXã\_Û¶Jsu Xá`s0„€¹”J‰p}*uð¥L�?ꃙ±U 1hÛ<ˆŽvê˜%Ú»m®Ò %}W醜þmÝ9Îæ]°ÝœF…eÎ""ÂÝqÀýnžÜˆq§îÀç/Ö;ú¯Q\9"ÜâNm‹·îãÓgõþWœ⸒gÆ€Ó9ÕºWçÿ­q@fàÁz‹ºu ?ûPœoŸ{íSøÚ·~k­1ftÂÞŠ¢;Ù£BNø0ŒBÿu (�PQ,÷°Ú`Vû¬ôµ®Ë˜K]s ´à:¥ nÄ1¹ÔÞ, x˜žªŽW¢ÖLù›´ËA)—TWϹ0�åɈp0ݱT²ª>Z7ضj2Ý5 Lå»Ör_¨ž)v0ÁBŒNa¾ÿœvÌDDlv¤8ƒkm6+„É& dE~G ÃRŠ»„yž�/žà½ê°jËØœ®ûIQgCØÈ­ƒö-€áQ‹34Ë1Àùˆ”ÿÛ+Ý®ƒÐ!‹_$ÒÜ9Ù_ZöµÌ ÖwšP0Íç—O˜·[œ¤ËÛ ù&‚ßÂ�öqxpŽXŸNغs”LàDàÙa»^c5Ž8ÜßGž&Q�JDð–ËÃè (eëc¤¼Æz½Áý×n‹å>†e��ãjÜ.àm§·žÀt ŠŒaðPš&xŒË×V¸õô ¬–¸ÜÜÀ£Ç‡Èy‹ÍöiöH³ÇùÅ„óóIâ$Î0—µ‡dpSÄ ¦Y<¢sX Œà�)'̘@”…&H©½“–Œ©/Å”°ˆ#VËoÁ¼x†�ãb€ëÍ„‹õ¹�‹NšÙ`¸RÕyd¾Êò)VÜôŽf{›Ü”"×*¹ÙìiÔyÈÜÙ–¶Ò3‘ßÕæ²Ô �½5H‘-4²Ùd@F•HÍdbno#ÛÕŽÛ5v³±MÏ­j›³yc:aHp#åpYñ™ñM¶T[XÔÙZÇj›½W{b¦-ZOTÇ,â̬VNßW}4W{»YÈ}¥¶…ÌE¼Ú` r>ë"*sA™æ•>hN¦+5 : •¸o 4Ábg´è‡ [†ƒ¥…&×q»·žë\@Tžm­Hª A¾¡Ž©½a›³û¶Õô› Wz/GòžœQï°CvÂ¥o‘ž6¥§4£­ÛX™±ŠA/üäcYusÈ `ع,^Þ\¬&Ãnñâ«ÊBÿަà[a¿×±°{¡¥¼±°«RÑcém$ÑÞ1\‘(–¢iÔ;í·|ýú-U`«'¹îëͱH ‰$uš"­‘#zsèé]a�¨–ÈܶñSuØ\›CÄD·ŸmmpÛðuÈåm=‘1 ÆËUUÂ8zØ"­lm¨Aãõã€JéÔ+…¶ñCsz*?­ÊZrš9’•÷´(/¹Õ’Ðæ™CWe®ÍšF… ð3Qs Ib£ˆo´Lá[=ïíg{_U”׿Ù>н÷¢{D–(nAòl¿kó`I­¬í¶ï›’eàrÍPë÷Õ~~øÉŸü>ñ ‰*|vð{È,‘€Dýö[ëè\u œÍ û1à@£ý?{~�ýj�àuÎ8ŸSåþ_x�o»s*7¹Õ¸¿Ù"•‚gWKxOxéb�WÖü‰ÛBODNŠ]c¾ã©[ðDØ–‚“iÆSêDx¸�ð;�Žñ§ž¾�Ñ;$fÜ[o°„7þ§^}ÿ§#ð¯þé·àÿÛ?€ýý¡ŽLSËŸ�XUwÀU™m‡-È`˜ô–¨&‡Ê—ìƒös–zI"ÿ‰#`pú!qxhälÑéZP94�¢›{’‘o¥Ö‰’4A“(½i˘Jœ&¸ä$O59€e/uÞ!'+x§k!3Jbù{6¹â4AR6IfFà0Mk/¾¥) °Ã¥`½ÍXo3.§ŒËm®Yâð ªj� :êF×çáñîïú~|ëW~þæ¯üþðµW?t„wîíãûoÜÀK—¼òðoÞß÷߽…��âµõÁÍø¾7ÜŃíTeкd\ÎÏ®0ƒék∻1âõyÆgjßýÔgðö^�yaYA¶fÕiÌ\PÈ8M¡Îz�ºóM•V—0,3¯M½]ÃÚ€#›¡\3;tÙ“é»M^×Âv,ã�š]æðsø>þ¹Ï!áOïâºsxçÝ[;´J¤:‹ÇóŒ÷¾ú ¡ ;š¦Jôö뇘J©4'‡CÄÝÅP�Ð)üÁÙy} À‡ÔqçðPÏÝ_{ý¿õðq}ö‹ám€¯9+ˆh§ˆ1áù½eÍ$€·ìáó—5Š{Ó|€aæð¤ô�úýU:›/ÿì�Á¹�"¿ÑQuØq ¨—sÝ×ÿU'Â\vuÁ‚Fdl·vúÍqØ¡Zz¼/æV ¸w À+J!´§E�­«à±ô¾Îîæ”¶Î,ÃÍæða ¸5OÌáÿçñI• /]¬±íœ!vîèþ•ë7ðþÓSÜ›&¬7çxõÑ‹xö©7¤à²f¡:bx%J R06†|ˆB=–%[¬°@Ê·«@“| °37g¥Ü©u ÄN´:D’),@�+È^Cª�9rEêÔ•"‘í˜K-;rÑ.EJ‰EG ¦íÂqB`å¿pì‘4š´Qm´ ,y:{ÃôRùÈ ]‹ð9 µÑ4 =Ž/ÄhÎJ®à(pë"¼O~i_e¼¶½ ±dй`’ä„ú)ŽF¡�ñaý#1ú‚÷dº7gpvxA²ü½~Œ¢Æ[ÎÚf„Bg=�1×ñpê�R€œ²Â:¬æÔn•>ú`€§fú×½^ô!x©�TJ´)Øž^`{4#æ-°½Ä³oº‹»O=‡½Ã;xê¹·bÞLxí3¯a³IØlR‚rñ/àhøò„Œ¤´„¸qýÆnÝ:Ä8:¼üÊçpÿõWpr|‰³‹S8ÿ,nÜ8€ˆ‡+¸äÓ3äÓc¬(ãÖøå!önÝ…ó Ì[)0ì ˆ‘°XÂ�ö–pûÏ]>�âJ 8=¹ÀÉéÎO·8?ÛHt?óı/“¹d¤2 þá–áp1Äk*˜Îáp…½åJlçÂaÃk¸Rp°ô¸y¸Àb`”ùœ.|Â80 �pzv†ã³5RÉ /™)L^õH æŒ1 _kúÍÓÓvBaÁO ¤—)+õ %;ÇX4T/B³ó,4ÖtsÁši�‹\g‚ÁtB3‘ØäŽÎM1GEon÷l{ƒÚÅèìçŠg =€zlEZYXìXç$_Øû€bu¤”4+Jdœ=»UîÛ.Úþ†©s¢bfsz wRÚÝÌT`ˆ}ÙA®ÜÝ¿u¶‡ÎÈ©pOµk;Åó CüfÛlÕ†É\uì2;Ôs­:î.zOštËH ,À‹CœËœ Òœ”Ê™À\”õƒHau¸V0ݫáÖ65ÄBñkÒ}_ÊÁå6Uð€ (KKqæ8eÖ€fõ2Ø%uèe¸ tCäQï=úŒÑel]Æì²dòBj¤ ¨ç�.f':‰ÝY*®¦CR1{ë@ÑLãÒÕK f²˜àÚËa²Š…G‹“@2 ôªÜ_ÛfN�(N‘Lé;\ò;VŒ®Ì@!êN2ÔÈ(‘“ɲ¾�c¨‘M&ÒˆèfÜÞÒ÷awQ’í¶=Q%RVðµt}QCLEŸz»©=§ëº´Gîe‚k·ñvS ®ä ©Ùïjì]½Ì“ >¬`‡ ÖÐ&šrA2qœIÀÜÀà@@�ÍœØ ïŸV.¥[rϘúÙEÒ5ÇeD´ˆÇ@ÞÃù—€�\]”.¸`Ñe"ñ �‚ƒcFDP�Í� c 1Jªœ­aÍ@ppA …X–†í3Q}ŸL"ÐK.H³C𦉰�¤¦Áœ³î(€Ðð·Ì؉bWݵ2QS}/ÍàÈlÙ¥(`[¸* TÓYm»0ozQŽG‹P”{88Moí&D—ÙÐÉ}XÑ]ϽEj‚3®Çz7‹‡ÖµÓmœW#ñÛg ×yVçhéXÝ ¤æEͰ°,5žxÞo3»«EþX*èÚƒ¨¶å]]nÔß§Ê%Ýìy¤+޵Ðv©BuÄÍ“¯ËhÏ• Ï�¢¯JLk+ƒµX¤dø.UâŽÐdaNËhY…‹&ã¢*5¢¸¨Í]_Ûèé¯d/¶PÍ4*º}_ezEIoÑe6ØØ8-&ï\s XaNá|l/Fƒ\wÔ&Sæ™H³tZÁ7ñê·±¬�ìôKÖ�(²ÒæQ!¥£NáêÈ:š¶n ÔFö�\`âum¢îZm=éZ¶ëœFFHý‚p"iWU”WÌŸU m/Ò~¾ê@Þ])¯Ü»À_úo>\ñ¼á x^£ï™‰Q þ2€O�ž×l@x“¿<ìU>ñç÷Vum3€ÀÃðéÓs|ùÁ¢|äÑ1žß_U'ÂÒ{ô,ÌÏ­xf)ßO3‡ˆ¯Öhÿ�ŸœaÏûJôêå¯o·õ^7‡ˆ·_?@$I#õŽð'ïÞBfÆ_yé%¼ç¸q�ÿ…¿ðMø«õ;áöŽ�jg_Ñ®ºW¯M¶°Pñ!ë¼·ˆ(H&fbHE,‡¨nÌ¢ú±—l8<0:ðàÄ)�V€�fm“ÊÛ:å½®_Õ±T¯©Å‡!2hH(A ¬Ë$Í’2/ž _ë XÄ¿¦}êÜ'4EsÉÀœÓ”a)º®36ÛTë9ë©<ø¥9È›c@滕P(šÉøÜígðßýïá—>ô~üÂ?|RÎøÍ‹süÖå~ôæ—)áÁf‹ÀãiƳ{K|äÑ1.rÆ¿uKïñ¡‡GØ–‚ç÷WJ?xŒGÓŒãÎüµ{÷ïÿo{Ó›Úkéç‘‘* @�-dûƒfÍé…6læŒtz£ªEp[ÉM]•lTñ©{L•Ul{ŸD÷B€}蓟Ä{~GäÂ÷­pË0€><Â6Ü"ö‚Ç‹Jés}ˆøÆ›×ñ[K1xo;ÜÃ'OJ�–~°�$Ê "³_¹\ã•Ëuê_¼Xã5¥îyÇíxår])Tï°p-8â2güÎcqD'T'F§rw1"q«p<žÛ[Õìæ'¹âÍYáuï2 ™ˆð†å¢RRP½§kù’SàŸÿÑ;€ÆÇoN;Œ²3uç_¥‡ºêDèÁøë1Vª)Øó»uz§€J¤ÁQÌ"÷%�Vøð8'”"uQRÎâp!BtU/$uŒŠüd*˜i üëä¼Pà@õe PÑ=JIÝ_¬7JÖ¿“:XŠÓÈiN˜æ-¤vOÖBÆR÷Í€B悜²Äˆ<¼‹p p™n-uF  «ãLµhQ‚Œ}ðƒdy„L^ƒ…4`ˆ Á›žÄ>æ—“Ø6\¤fß–žÅpª!ŽïÀ)µ Y‹VW¨Õ–ó“À}ÔóŽm Ë (32ȱ¼|ŸKAž2OØœ^âb�gŸÆþòö8x¼ü™ÏáÞKŸÅÉÉ9ÎÎ7˜0‡ÕÞ \¿>`;L™0sŒ‹fC!âàú ,q|v‚‡�ãñãSœ�?Æáá>nݺ‰Ã2nDˆ‡Kaà«Ñ!\÷°ºu€—@( %p‘ÚŒ¸7ÀŽxz}n(„³ÿüìçç—xxÿï38E¸2 )³BJ)'l'`½�‘9ÃI&]E ÊEêgD�½å€ýÕˆ4g¤9I�@OpÙ Ø_xÜ8ÌØÎ— Þ`12VK�½eÀœ Ö› \\\"ç"z©çJSÈ�èaˆRd›5ÃdC%3æyF.Ytj•Þ��8¿ŠÙ³âÐ5/“£YP�%ëË]ŒrgƒôòµÏRà�;uß_Ù/Dq’³Í®k&±ýÕ6¶ìC;G.9%…Ì53‚<˜X�RBÁlnqƒÔl�«�Ñ£"‚¦þò„Mz•jó[g±³M/lúäÏ"ÔþwEÃkmáv†õÕá³1çÎ^²±îœý§Ú/5ÄTôdk $& $,-E�rªÓ*&0M3¸ˆãH»eòpNT$ XƒI*õ´ŸŠI3é>� Ê”A›$í‹T³¡H±.�QCI_„).ƒB†‹ Šm-c`Œ点pPŠÄn¡@ ÂEw×L±0UÜSèÃKg ´×Ù‚�œ÷ €*�:Œ×¹z:Z°Œ…äßåšÍÕÓ#ÏÔ7_ÔÀ©ÄÙN¢ÚzoQÇ× Êè7*©s7Ù á5'A¿{ 3xŸðJÙ)ý¹m‚3œFË3zP¥½N�ÐÂGªlê"¦‰: yNJjSrvÍFtcÙY{µù_@"Ô¿õÀÏUEþV=od„ö]3"ûF:ãvI”bñðc-DhªŠ“x¢ ‹pÕøçlÜë!*?²‡ø'‚ƒ‹!Ë%SÀ¢üåÞ$¡õ@\nÆH¢ðÅÈÈ1XŒã=!hbŠ7够6&{ +ªÏ×É$žYR�æ$�Û Øl¶“pJ„P'2ñ+·´H2SÎì «·° é¢Qßâé–idË8�‚:TÝu6ë •Èf´ÍLÿµˆz+Îik¥ ~;×–¿Ò»ÔŒ Ç0J!W̃Jm¡E}èjŽ…¾Æ@�ZШÄÌêß«WÖͳnn™Áœa‰‡6‡ —VÌÒžP�¶™Tß®Š0nJ»už¤Ÿ\ºbi&k¬Göw0ªCEÛ—‹e†h¡HuŠÕîus­¾%¹5Ç Ø€þþ­´vŠøUO³c”NüɲÓwßÉTûkâ¤{Ö³ë<í”—î0_jý»í,“¹f[Ù¸è¨ÔéV*3‚¦Ãd’Ÿ.œWqReAd¾Õ~ðæàsT_U-îIê¤ã‚Ì™³:DJ�—½´ƒ‚fL¦(±Îín,m tFK¿=A³%Ô�ÕŠ:±9Ðþ¢-5X-–JÂ2çí®TB�Ð"´½¸›GòލFÍÔíÂ(’êGäïîIÀúŸüÎÎŒø¾k×ñÕËF t‘3.挧œ' ñv¼M�§³DéYaâó”ð‰ã3¼Ã¢ý!‘›ê–|‹~—™±Í‡1à0\¦Œ�Ÿœâ›n^GТ=:Â;ïÜÂJn±r†gf<¿¿Âóû+lsÁgÎ/ðæý=<·Z‚üúëðüÞ o9ØÃ÷òËx¯:ˆ€¿üß~;~ìÇÞ�æ-¦ªŒ“Íü=L4§¼¾‹Ì☠0±Z6®³nX#S<ÜAƒ ˆ ø‚f¨,Ï4]ÆÙÂv½nDƒK;è:Ù㤠¤“ŒA˜BÀt6!]¤j¼*炎a'ïT1öUçÐ9¯ÙOáÔ�)Ã!©3¡ —ŒõzÂz3a3eLYîÏä:ö¥Æ�Ïê*•©ÎÕ ¨ÙrDøÞoy'Þöü—á§ùçñÚ£GÈÌø�à;ñ|ÜÃ!8‡ïyæÎæ„OtÜó×b@p„m"9|æüO-¥hî›öVxÓ8âóÛ-^{üúä?Á7åWªÌWÙQ÷sÈÞÓeîÔLæ@îÕ\Q¿;.Z˜AgW©.FªÏrÛç+u•ÞTöB#¶(U™û¦{|æ•{øÙ÷þ*à‹Þ:ŒøêëH…+€þeã/ì¯j!ßmÎxùrݤ+þÁýG`fÜŒÎÕÈ黋ßpóÞsïõú¾n�^]o•VøøñiQ¥nñDx³W5à·oàcG§쟊è vœÎ©:ö‚ÇEÊT}v¹ÀÉœ*ˆºðƒkÅŒ™ù‰¢±æ0™«QÞ_:þùOÔ ¸2ö¦{÷‡�s5S`tB3Ð;ޝP™SÀëú³{�ÞaÏ{<îDƒw;Ž�Þ) Î1àæbÄÃ.³àùýÕN]�GÛ ]BDÍVqDاsªÎ«o¹u¿{tR�'×bÄ&çڙ߹>{“3>y|ŠUðøžë×ñ«ÇÇ(%ã_ü8¾æ+ß ïƒ¼¸&Ã�#qx‰kt”¢¥“óðÞ!ƈ4J_  @*ÈÝ“=¦“˜#`ö(kÄq£Á¤ª˜ž‚—èùœf¤´Ýj�Ù9FŒRôvËÒœj$—ìCÞI´²Wú ûˆNØÄŒÌ©£�ЈPÕW™3ŒnÇûáGE.Ó´ÕïÃ"<µ v.V[!¡OvÕu¥×>.ÂÃ8b¥"{¬›Cu “ê}s&¡tÑŒw¦VØG‡[ô¾ÙVqˆâ ¶WJùϢϳ¹‚:F8€9�ri0™ÙJß8'ÀÛÌÖ±Œr@J(̘sFš'¤i ‡ŒEtLjë×öp¸·@ „edÜ Ü'ìŽ8¼¶ÀÒ�˜Ï&‰Èu—G3NN%œœ%l’Ô7r§gxí1¡”›-!grÛiÆæÑζ[Ì\¿v€‡Ç¬·gŒ££„Ïýác¤ìpç©CÜyú7¯â桇÷#âµÛð¼Eä­¿b� . Y,ÝB½#�áÖÝ,VÓœ0¥Œ;´áþ+ûxýÞy£EJ±„§%¦9a½Ùâää?ÀÅå%ÒÌðÈÀt‰y^c{yŽi;!¢_"¸Œq rÈ.(E8ÙÙaáq¸°�&l×—\Æ�ÃöV¸v¸ÄŦHÍFž‘YæÀ0CÀ”)£‚ü!ˆÃÄl½’…uA²H�Lœ€1D¡˜rTõ’Ì‚?ÔéÅ5À ±Î0,‹¡”T;†~3�Þ`ØA[S½±[3�TFU=Š ï0н"+¨¶ž Ð@VÎ0ê³z¦sšY!Î7ʘ '�¯•J¸³XûgU¼Dq­*¤nÏhëׂaý¿RG­ZúÕsPõR³‰H)vÛ6†TQ�Óëú{Z'*}wà?€Š[Z4�~gr£è¼2lÐk ?‘=*+­)3I°¥µ‹¼â /u_Xc¤àÈ †­³“ŒÚœ�4eøµô'äÚjVwp ÇðŠ}³\¤0##!q€ß4x8ö`.p%£hK‡ý9 éù¹d$�D¶ vçH‚xµ®L}›æ�'Hp­~'Éz‚‡¢®µ H1#éPC&mÚu‹xË©­1Båt,£j6‰¸�Wé‚"ãf`ïÂb�ñEÙNhõÔ1ÀÞ�1›®æ)§vŸ�Яjÿ’-79GœP¥N¨�ÃnÙËøúGûÝ&²‚5FÞû&K• l IDAT¤ ];ûµÐ;¨]ЃU»Ú¿ ˜ÇGþf5‘BоhÇø#ØÔˆäÀ&}¡>hpð£‡h‘:¤ÛÂ]e‚Eô›b�«L­¥}L³£A_ÇÀ"L¢*N¿¢ý\º(Úí+5 Ùún)—­�6F º›c S úC”§[ Áb–@Bíå¼Sîm[#t�Å1àHœSò1±�h¤óßœu±û_]Ôu ¶­Éý‘™dÙ T�Œ6êÐçpMí°²S»ùDõ?mKim Òµ ÙhuR9€²î�„ ³^OÖ ¶6V?A"¼u/v¨ãð�¼†Ÿý™O�‚Ã?òôSØWJ @è:ì÷GÛ ·Æ¡Fûÿþé9î.ÆZw`wÔäZs L¥ :‡çÕ©ðù‹5ö‚¯ôB÷7[<ØLøúRŒxéž^ŒMm Âw?sàáf‹‰oPÊ û›->úøßó†»õÙ'óŒ™ F¤¿õöM8"üå—^¯�HT¥s„¿þ?}þÝçëД疡Òr^®êÝÏôÅþvUp˜,Îf‚V³«s€ÔЮJ¼ê=4¸E�H€oPjykMΰÊRîÛCµ=⽂öÙ¾’½ž"�BŒF×3�fñX u–íb ¼# ÜmCp½d)%šÒ£�T%$$É�,Œ\2朰^OØl&)¶UX£Q…Ö@(ÌHŠ‹Ã“u–y'@8@â  ‚gïÞÁöÃ?‚ŸûïÃo~ì£Ø2ã½§'8™güÉÅG8ÚÎ8K oÚ[Á;¡ ùØñ)Þz°�g– |úìŸ:¾„#»ž¾ƒGÓ„¹séå—ïû��àÞòV‰æÔ>7yÙäq�2ÔtÙ¨í#ºV�mÎ^e¥�¨Ü¾"+MOéjÚ]Óµm¿§©ì'²ÿ•Âxtr‚¿õK)g¼1D|ûr°ISQp‘€ÏŸ_âÓg�Ãö–x°™ð§ç ßq÷>±®ÀèÍ+Ž�Ó9á#�ŽE¦êÔûð#qÖ=µ‘4}Ãr�7î-ñA¥2êÈþøÍ×…Nhô¢¿pá+öñ �”$Šû÷NÎê=LÓNÍ‚‹”q¡H �Ðö®n�ÃN”¶’®~éø#<®Ö ø§�ÿ¢ ê�¾FÄÕšW‹ Îa›s�7Û\vŠ ¨çÆ€³9Õs£P®Ôûa�vûaN�Ñ í�eÄ€;‹±êdï;�Ïëµ;>m.^Öì–…÷¸9DÜ[o0ëx|÷3wñ+÷d,üàµøí³3œæŒã“û8>}wn¿IÀkF£Âð^e·GË�V=‹dü¼Çâ0À«o2Ž4ŸšL6ÖœMϲ"¢bOõ—k„9šS@Щə·H“CÉ%'8'õ\‚•t”ª­B,Ø�Pt:xRú žÓÆy�b öBÊ5[€K“SP¥¨½¡u¢< à¤ÊbÉB‡ÊWtãjSé»­—`ͼˆ’Aßeù0ÂÇ%†q…Åj©™Ž²æbÙ W¿Ú³)e¤ÄÝ9RœÓ{êÞ ï>Ô½Èêõ圚‘hÖ‚¶dèœÔ/ˆqÔh\"©í@(R�ÐršESÉ …ûbÝEaÑr'„ÐϬá‰}„sË×°Z 8Xx<½L¸½ÈãÒ!ºÓùŒ‡B›‹‚õ&àrp¾öXÏÛÌÈe‹Ì'�p~F„àA9!]lqz¹û€“ó .ÎÖ8_—ç„{÷Îqv>ãèhƒ“ãÏÞMÀíŒÅõñZD¥Þ!0yÝÄÉÞœÙÊĶö,´P‡×V88\àr»ÆfÞ`µ\bµ\âàÀãðÀ!¯x0ø,†ë˜¦„‹‹K®.:®Í@7LÜœ5Ò¾ ï2’d’šA(hÐÅ1xÀþÜà]4²ph÷ $u�€:¯H d$�ap. ¸ˆà#†aP¥t”En@¡‚æÏ4ï¦ERvÊ—IRTX?Ó ¬'Æz*ØÎRüp²ÂÃE#Q!N­Ð"±-/ךšP½‡êýä&Œe‹rèÓZ-ƒÀÜnVõ/¹Î—>rýʬï¹ç¦Ü™ûõÛ�…ÎgÇq ?×"ÀšBš­oÉÈÙj!(€ÄmBVJwßJ㔳Ö�{±Ž›eWôý—z ¥£ ê»;üŽó"çÆ?o »�6v¯bÙ0uÃщɨ¸dF2'C=Ç h•J5ÔŠ%÷?£ûNRÛJ±xzuéÜ(hÙ$’{â[ºùÖÐßxò¨^Û÷§ÿ˜íl΋ê¹Jeck^箋c3žÔXªR‰lj€wˆÞÕôbùˆ,¶R4Á“;÷Á#D�AŽjt×V«’ô¤¯˜kq63Øä+i£<÷Jf™qf²„ª¢ÛÕÒkϨZ�ìe�&EÄ©e¨³²±ßqÝgkVN `·ý@Å¡ã\¦�p,Q'•Î2R®îçòû»ø×ðâ‹çDøswîàÛ¯]A€ü/Ö; ÿé=ÁS>à®ám{¸9øÃó œÎ w#¾ýÎ-ü�•žßxóNS3§Rp6'$fŒÎáþf‹×7[ìÅ€¯<ÜÇýÍI@Öw=s)×hêý(üâ— _¤„—/7 X;®uÞv¸�ÂŒ�´O-F\bu 0S)õ{õÚÑ‹18e‰Î�«ÙvìŰþ®¿(ý„êÿ¥ã�ä°4ÿÚø—/ò%Aö�>S`¥Å¦í¸ ú']Ÿ„V+Àާ–‹'Š÷ôFÛÒœ£wH…볞ß_íÐRÝY (hTV‰[Al@æ›Íá;〠®÷~ãÞ7Ç¡Þ�ˆ°®Ò>uvÖ>8m·øúÃüö¹8Î/Žðܳ_-\ôÊûBD ’-à|�ˆX"ÉÌL¹êÎ!Œã(Ž�àAäÄ(-Kjt’š3€ŒÂ%Ÿ�óŒ”gÌóŒ”æÊÃ�´–WÓ©¥p.Cƒ|¬Æ€Öèõ«R æYîce‰Äö>*5O9©ƒ`zuå÷‡w9MÈó¹ÌÈ%U* ‹¤±Ìfï=‚ £’)¡õî¼¢>D© zˆØG¢3J&ƒð¯[�¼€±!ކ@®ÑÑj �ðk“ň󓅢7†1Q¢ý�fˆX,¢™´]B]3'³ëf*ޤ1Šý=Ä¡)¯úNŒ*”5Ë"gÉŠ0ŠØÎ¤çFÎÈ%IHžÁyFá\’XÛTcÀr1àpéq°Œ– ‹\º¤mrØÎ„Ë-!cù%(ì� p ýŒ€À>‚u kˆyäB¸ÜÌ89¹ÄÙÅ„í\P8`J„ó‹ g3]àÑë�ðÚ«÷ðàáCŸa½¾Ù„Å Î/�g‡‹Ó5^»÷¯¿ú'GgX_l@ Éx!ª4Ç!˜Ž3Æ8à`y€ƒÕ±¿·�å"bµˆ¡ÀÑуóX-F\?\b¹p”@”à]—yÞb³¾@É3œ&”<e O‡ ì(yF)3ö÷÷qçÎ,—û˜ç‚£“ <>:Çz“‘9€ÜˆWðq ò#BXÈ|%Éšn#Ù&Y }k­ ¯™©!- +6sÒyÆÓTàÜæ•Ê+j^?§ò¢Ã^ÁͮڱöÇZ;±ÛMî.~f¶e=O?ι.[" ‡<Ù3KŘ¥þ–ÔÈÈI"­M5›†_ðÎóZ­Ívö“xÔ~Ý FÞÁõçÎnÙýÞdcNM‘{rL¨µ¶f Ôñ®àHûÛ;�¾tæz×o³é©¶ŽÁ;}5¬¥ÖÞTg蜔|N˜SÒq¶¡!ç½Çè="€�–CÀj1`1ŒcP9¯}ìNŒ2K�%å"IÙšù�b™Ã®¾ÉD°yMEìHñn'{¨® ç| §ôê,µ{Ø–âÙ�97¬Ê0 T«ÐÚ¯X·bFýgX‡w„óÖÕØ¬+ˆÀ òW@›»su¤+%í^o÷UÇ@�þ'­Ê]”דÐ(ƒú𤯫sÕ 6,´Ÿ¸dQQõ±¦Æ™1Ö{ƨû¾›€Ô n\]�Ü]j}Ú‘ ì°S�TÚ.ÏíŸeàh{4�ߌ`»Æ»õ‡v_ï,‡/?£ÑjTÇDÍ™.òbwLô^–Q9* ò¨}k«ÄºsE€Ûý à2‰—¯¸ÖWq hQg@õDQ63é° ½‘÷ÅemºD‹xàI¨%%M论îVÅQ6Zö6^¶h$Â0§‚4̉�ažÛ)c3L3cJŒ¹s Hf�‚Up‚„P̰*e\_§6¿:¢d„5¢»ãõR›¥r´Ö@wÏÝEaﻟ ÔÖ¤žoS‘ê_[ôx××.…³‚£®n6æ` =wJ{‹à¬ÂO7Wb•h.¨ý`Uø³‚8̪$Ë&”+m êZe-ÐDhãúäa€G/yFÑ1²¿•nó1Q(oˆ@�°ÌYyy]¬Œc:.\:yd#Î�2Ì­ýhï±¥ê’�ÔbÏÈk2€ß«z'¶˜âšäÐ(nËêá¦^ô8b�pâvwªc¡ Œ¬¤Ô<´Û·ÚYB�ÁJ‡#Æ‚œoX kª_�ü"OÕùG„ºé;ÝňjïÛæ´U5†æô�×®c¼óžº>%¡ÒÁíFa°Š}œÂÍAãpuÜÛu5;²Ð˜!™V}èK–k�v݇­þF¿wXäZ]Ù…ÁÆÕÉ ÉÀþþ/½ˆßüÍ×Ï…ˆï»~£ÎçÁ¹'(ƒžÖýÇÛ Ñ»Zløñ4ãñvÂ[$²˜˜w ð'´Øð¬€È�:N¦Ÿ>¿Ä7ݼ&s”�Ïž]ààæ5,ô¾°¿Âõq€Õ;°úÛ\ðONÏðµ×k[~ãþü±×jbyÏ„ŸzõÕZSÀ9Âÿú׿ ÿæU[4èuŸ«{u¿*ûs¾ØAOüÖ'ÿ¿ä½i¬,Ûuß÷ÛCUu÷ïü>ŠƒH‘´æÉr¬(¤é)¶Å‘?ØH`Ø@l!AâòE HĈ'_<À ÈVâ8HÈ`š°,Qƒ)“”,¢ÈÇ÷ø¦{ï»Ã9÷œÓSUí½òaí½kwßû$ð ®÷úöéîêê]{X{­ÿZ뿦L©,ÿd �¤ûXg�ŸW§€3$ ɪÙúWÎ@Û¹¡� †”ÖpÞê Á�E’Ñ–”Éc�úîWܦר–”  A#(Ũ[\ HŽè®BÑX-°î¥}0©�¦Iu$AD1ƒÊû0ŽŒƒ>†q€TÌY‹w9N[Ò¾�ȼb–w1eðÙÄß:É7•ç¡ÈœoûÀûyáÖuþ·Ÿúî>|Ä*F~ô­·ø�®ÝäÈX:gù�‹+Þ{xÀÅ0pàÇ·¾ÿD“ܯy,˜Œ&� é9Ëù$�ªÿ&(éUÙa_„’δ|¿9s1+*ž JÑËXkAdíÇÿë?ýG™Ã?<áÀXŽÏõ¶åÕ«"Â2¾ôä’6ѰXcJ±á,3r‘Ó÷.x÷bÎϽýPp*SEæúÙû "4V ¥û©ÆÀqãyßá¿zö¤ôÓ·œóÙÇçÅñpÛïD�gÊc ×Ú†ÇÛ¾€¤99âåËe‰?m61–úÛK½„|äï…×Ì�Œ·ÎÒ»Ã=ÿ¯ûa�)ÅêS"’m{µþe5ð¾ìÓ uV‹Oîò§3–…Jj÷»MŠ$ÜT÷±cy�j*Ï1o GMÃY?e™¼0Ÿí ~soÎåÎeP>~ï­ëüâƒÇe÷i�ÃV™o,'*/g CŒe=}Óñ!_¿Z•ûxïá�û�·Vk^°Ž÷Íf|m³a½¾ä�·~ƒ÷¾÷;Ê}:Ÿ¨åŠ,MÕ�(ÑTç1Fu/ç]ª½%È0ª¼ˆ© ,’.’�iŒ$,@u~‘ ’ÕüØ-~—ÀkL²E1Õ•Ë€‡s&òJã#c.ð™FÐhæCí5oÊ�X-ôëÀ¥Ê® b$Æ!�§A÷Uë0Qu‹ü”³æ�ÇZÁYƒX¥VÊTE¹Ðe¶yÂ8¢ûgÚ×ÍOdÉuÉTÆOŽb˜jî„�äk2€Æ ‰¾Eßó¾-TF*†uï%ë’Öâ´È ¤}Y½²�“@)Éa¦d’4N)…´}¢}4æÀ° }I b±Áb,º¬Ä*k=…?E lûdÀÙˆ5�®m8Z´ô¡!O´ âZú`6&éšB43G-#F»!ú Ál4ZÆ1ŒcH㣎‚ËõÀÅr`ÜŽŒ}Äš9~>cyyÎòrËùÅ k.™7+~ÉÍ;Ü~þ˜ß}‹±¿Ã�çnbÚ#¬ql/×<~pÉk¯Ýãââ’¶m8>>ñ´~F{ No=Ϊj½^áp`»;¶: �ÚÇCCc×ÈxHcfÆ2Ž0_̉iÛ‘î"²Z­Ù¬·¬—+V—sí³Æ&Nöˆ·×y¼ÂÐ#!à0.ܾy‹Õ6rqïŒåå’¡WŠ+-Üb\‹õ3Z§µ+ÂÐÀHÊ0õº>œõ´ÍŒ�ÀZ‰—)höiŒ2•òS–�Ù;¯ô���ŒÉ“)ͧo˜ê9ã ;vL¥óf¼!gÆç-(D�´£Ôe2aY^&:"AD¤Ñ1u�IΫú§(µ“�ŠOx �u4)QÌ@u\E Äq°D'+ˆ7Ø.b{¯b|æ A³:“l;…ÃlÝi¤5 N™Q£Á’Þ+M�¬p­€ÆQ"&z$:R"w|kÞ¦{kL²´8v PNÁÃ*³]3?M¨iÐ&H$Gœ§Åi¦…cœÓ ñê¦VNä TÏ=kL):,Î&jú4Ùj~¬’µ09rj‰\-“r×@Jɉï8q÷MûÉ,K›°�§c€ê TRDöûJÒÏåßLÎ�¼F ¼–<¹s¿Ã._;VÎSýöîíŽWý™�ûw»Ã•"û‚ýí|jZئ|ïé.©t T”Èç$¹®¶kLDé÷ªË”Hc¢òó¹,àMI‰Î¨s X‚DDF¥õ12‚„Da`�q `-Ž\ÆE !X†ýˆR%ÇÀv4 Á–ÂÀ¡ŠÖΑ{u7E,j�¥T(·DŒCv d9]MñHî¨ñU)JpÙÀ×ûÎÝ›Dz55ôo=?öÊÖ×�1ӈżùÈÞ ÀO ¤Ä¤Ä×~>1;/ Ø5­�ÚºYHR®óØ!R6N$Óûäèÿt…œžkRn5­vo:Ý�äõ\>Í—‰Šhú,æùhL™õÙˆ(þøÔ œ :ý´$=mÞ&'52ͳòbê÷r#2­´ !*¸nvæGNq6É0Èt¢Y.Ærù\m¢Ë¥£§{Û•€1]#÷�1;­.ý;¹*ú‹rO;wUdbídP(’iâ$�}ŒZ„M¢Œ*ºFÔ)ä\*ª“^{WT™"Ãò\ž”•›Ya+ë/µQ .Wœª&Ô3fjàÄ47õ·s:iQ %;LT±Ê¬rZ0;%ZY¹!!Œ¢NV‹‚§)Â@Rº£î¹yÔ¹@4˜hwiSuv©+P)xÙq€‡�äG¦‚ÃÿÞí[…Ö'SåãKO.ùÐñaYë­³…N”ëÿzrlB`æ\ùþË—KnÍ:Ž“#à¬W .ƒûÞñþ£Éa …~èÍÕo-wR1áß¼\òxÛ'CdŠÍÇGŸ»Å,e‰|ðø�¿ûð!ïáCò4ù«ÿÓGù³ú#SzÊþ¤H3ùéÃì<½óyõ˜Q6™Ñi�[ƒñ™:(’ ‘çJÄ“ÊÉ©4õõëÔçœc¶'ÓöZ4Ic ˜äBöhÚ²s«Ä ší ¦s¸™§™7ØAFLpÈhé¬ÅzÑý3ô3blÀû‰FÈ»û.B #CRØc¥«ˆÀ8Jʨœ3̺çHô•F£Ëœ%D�p÷ÖàmŽ~· A¹‰û H-ˆ©5z”UOЬË{óÍãþŸø!þî'?ɯ~åeþÚÙC¾óð�ÓˆGÛž£ÆóÑ;7yår‰ˆÐGØD-„xàQ ¼�-µœŸñùW¾Æ7¿÷}d°¾ÂkÔH(;‹-ò*;b‹žPö¹,ã&�kÒ½&ù'’à”¼§™¬ÁMù$"ù·MúMøùöi¾üê×p¾kvÀ±÷œ4ž7W>vÁaãy÷bÎo^^ñÚ0âŒá¿x‡~ö„×— nνۡ广ÞpÞX4`5~íL¹þ?x|ÈÕ00ÿfxÏçS-€>ÊS…^?• 'mÃ(Rh}nÏ:nt-_J”A"‹óÙÎ÷¿v¹d¨öìûgûµ¶Ù¡za1ç­ ° ÅâßïC¤ÿׄDÈÃÜ;RÔr/ÂE< #o�gãÈy\…@ŸÖ×UÖ[cè’ÃçЮ{Ïuç9qŽ#c9rŽÖÂ6e�þv‡|úßéØýkÊ fï»ûŽ€ýcˆÂ°«Á•ì–ë]»3ÇrÑßœYDx²W³ ;Þ± ±dÜèZ,š1ª[ì;~ùáY%Ç'§ÂqãYx_ ;cøÝ7¯ñ‹—ï>ê»Ìë¬SNþÃ[·ù‘×Õ©ù꫟ãÎsßD×`ŒfiÁ/©ì¦¤&%é~Çð!íVu*‰B?l3€Sô2vu51Œ„8T x²ÈUt F4(¬ñ �÷HÓÐâ±ÞcDéû }¿a6%s¼¨F¤b¹©Ð]qH¢§-flR=­S“ì ˆô`ÖFœC �’ö/›Ê*Zi0Ûд-m«ºMEƒm –ÊŽêF½ÿ0(íN Q)©bœÎ#:Ä9å´NÅ>5�ÚOfÊŠFS¯îšE1DŽxÖñ¥c2>98ÍÞ•šÆI¢à°�RLYê´Éá32šD4` ÇÇG,æsÖ«5ËåR9í‡1:oL Œp¶¡õ–=”Ʀßöœ�=a®ž<æê´ãñÉŒã“#ŽŽ麖bÚ†5 IDAT¶ë”~06ÛÀ¦Y®F®V=Û­Ö«èÚŽEÓÒÍ,ñM£E“ƒ‚kaúíÈv3°Yoé7½f@H i��É\>>ćÄ1rþè‚#W—+NÞxÂѵsb´\^¬xr~¥m�ãÛíˆo6³æÚ5ÇQhÙnÖl×—Ü»û&÷î¾E×,˜µ Ž×99¸Á¬;b6S[H)„ Œˆ=ónÎ Ïßàðä�õøËõ’óÇgœ=zÄý{¹x²äö­C^|þ—O.¹zrEç=m£ôGÛõÀÅÕ�?dµ‰øî„Uyøè’ÇçK.¯¶[¾ÛFŸ²U~«»È%ÓËpxt̵k×¶úí†ó'g€0Œ’ñ°±Îâ½Ãù†£”N!¤=!­ûìD�bÙ¥÷²2f˜íÒJ·š@óÉ^Íòl “,?Pþœ²Þ§kî³èOGŒ JÁìSP£S') RG›IX˜ªÃ&Ù%c’5^!•9R÷f{²o$×t©"îÍ$»‹S¦v¸”×�3s'ܨÊ\2Õyõ!¦`Ï6Kª~K�ÿÔU*ܤƷvöž¬çf8¡Æ! Î'Ó¹©½ÉÂ'Fe¦Qjp[�"#Âv°¬7`› m¢ÆrŒaËv;ÒatBð†Îl° i“ñqÑ@7å?9�ƒ$G† õG¬/0(~d$àZC;ó´†h›H×5è0˜=“?ÕÆQ#ç†iH-*[E°1㺸”ñ�»Ï«a1­‚ÚÜ,€¥@=6VGÃ{Lˆ9W BŽÌ΀o84E!Ú”o!fgŽ‚lv¨�²AX¢]ól±@âæ2Å8J·´{j»)¯êé—§]ŠÖÛ›½9«DÙÕÛV#eæ2Yr$%"+M9H? ¨”]A«ôŸd¬¥QVî¬0™© uûÍΫ�¿ Ù㞯MiWY]IŒï\Eò÷ë÷S¨j-|Ëœ©#ïMõ~ÕŸ�ÔÍüW’"ü2qn¶~sÿ"Š(XC.Žm¬–ƒ0QÐOQÇ2†Ä±&B¢ )\ÊQ‹%JÊHP0Ä2Ž Ø…Í`ƒaFÓîÍP()øUKñÔ¡Ô@A”VF#-âÙ/S¤uyXJ4ˆvAšóhdIêh“A½�‰ÏͰßåß|Vd“Sj@Ñ=Á%>بT^’G!5J’ád­K“cÀÙl¬¥ñ2õ=ÔíÐþÉ<¶YRégï2µPÇ´‡ÊÜ”4’É€X›è„²2šÛ0íaÖ¨S/DÁ†X²Š `mÊ"ª¦‡…â40ÙÙcÒßΔ䪲ASf—®%Ô±�xÕ蔊SAÏßþ?^æ×?ÿ‡áÛçsþȵÝl�úøðÉQù �Rs ‘W—«òƒ:¾ýÚIi×íyWèƒ@¼Û³Ž ƒMÏsóŽÓô{?ÿö#¾åô˜Óäd0Æ”h^€÷,JDò“~à¨ñ|Ë©Ö$øõó ntm©;ð¥'—8à‘ƒ¿v÷n¹Æ_ú‘ïåÏý™�LzIÒM&a•÷Ôz�̇Lõv>ËïW{l Šâ§d9óÝû$ïdÚ§ÎIŽãÌ´Å–Q˜&ƒÙyìµÙTmD˜è 4KNR €¤‚�ªŽN¿aŒA‡é,~æ‘yÃÔ‰EÐŒ ®ÙŒôaÀ˜€³ë â ð‰‡S“D‹h¡Ô^uü@Ê­F¢Å¹†_¤§³Jy¢FAN÷ê˜ún;V½ÒQŒ¢i6Ö4É+—2LÎ&’¢§zcø“ÿw®�ò峈Ÿ¹ºâ†ooçÜèZ¾x~‰ |ëµcϧžÑÇȇOŽøÆ£~îíG\ôÿþÍ›üwo¾ À?ùÕÏñá÷¼[œÕ¦¨z“$ÊûÂnTUÞ�ŠVmb,Å#hjÀ¿ÊVd�yvdGÁäˆ †¯|ýe~ásŸà÷-ùÖnÆû|à耟~ó~™Q7º–vi¢ìŸytÎå0²ðŽÖZ¾x®Àüõ®åÝ‹9¿zö„uˆxkù·îÜä—ž•Ú›w¨y^]®¼1Ü™Ïxsµ.üß{ó_¹¸*”*'MCa™@Óóa(`m>~=Ÿ×»–m…NåZÛ0sŽ» DÍãRoíEqg`ÙÃiãw ÎzÿÔoÿN=Œ1yÇÌ{®$ðÖ8òÛ ¯-·ÜëûÇÊ¿ìca-šÏù`ÛñœóX§Ô%ûz¼£SÀ³s~.X·{_§Ùw äׯæÎ–ìPàÿ²ê/ú½BÅé34Î*MUúíò•‹©.À‘÷@ÄŽc h»»žêlÜ[oʽ½ïè€ó”©êD3Õ}‘â8NtX9áÝ‹9ÎY^IT`�µ¼¸˜ñ•Ë%ß|̧..Ç�W¾ö>ø¡À¦ˆEâµ9Ù©?mŽò�…£i( ’ lû-›ÍF©ô²ÞÄDµiS€1ž‚‹²Þ(ÕØ×0ïfÀL÷ÓÒ6š± 2ÐVë+Ö«+¥ŸLY ÖZ¼ë´Ø©ñˆ(e« e ’œ’ìÕ”A�·Å(�(= ‰õAÔ.Mýc3Û6í7ê˜ö¾¥m:¥rÚ›õâ¼K Æ�~»¡ß®Ùl×ê �´3g;7HLœõ1 Î¦Ðµ—bÒ¥á+vAÌ{< ƒR6ejc<?Ùm©F�µ‚¸ˆ1ƒ:Fˆš hMŠ[РÅ9 Ž�Í 4MCÓ5sçÖ-ÎÎÎ@4[dµIÙ^Mªá¬ÒgiGè\Þ®V\êã·{­�©³>–;­�êΫ˘éaгÑ—ï#µÓÆêë¦zšÎÉ÷¡÷š;#½/fç«O9âü�ŽºM¥£yJØü–ß­� sMý¾;O7ÔÔ+#ŸbE�ÏòM”¨ëjQ©Î–Š+—#bZŒ¥ë—yÞrzi& WºÆ0 Û!°Ý6›‘aÐ àcT¥{¨“ è߹ƀR ¥‚¸hæB�¨<…!sØïÊF�Ú‰*%¥9'ÓtMG-Ù Ñ Fy’!oS¯æ©)é³ NWg”õVÒˆªé;í~±4´xÇ‹".äh~ò÷Ës-Ä«óMs#dš¯úç³òfc¡ ª=ñùz&mOo€û“fڬ˦_6”ݯæŸÈ�¸wY©2*¤\cr¢P6ÙÝÛΫk/¿ƒ,_Ÿ¹žv~Õú1¦”x‰‘âؽÄt�;À�€”Ô£¼î÷&bjl6v¸§�ÓßÓç¾™VÿÁ­ýá*à½ÉõZÍ&EÈeÜj��`œnp¢c¢ABt1Í—ä€KtN…Ï•j¯`šû¶šûÖªãP-Ù�’‡âÔ͆TÔ6ØHÌQRÖVëÑzÁÝG&ÓªÒaEµž–š¦|’>Ok™RÈX£ VÒû)B ìºŸgBî÷4¬ÛíÈý—>(ù˽uS©]Ò‘i~î­·Üèš’p¶í "ÜJü­SNîúøŽë§¬CÄ&º¡mÏk«5ß~-S ÷×›RWà{nœz’(SqáÕxùjYœ›øÔÛ�øøó·ŠÓáÈ{Nš‰¾èÛ¯�ð•Íš¿üµ¯•¹÷Ãö#ü—ÿùwåIÈÞL³¹~¿~/ƒñï´ÏMc^Ù5eÖ²R�ËŽ‚ìôŸæIÆ*TÈë)çåٽ福=µC’®%äP&¥ªÜoý0é×t5¢‘‘´7k±È2Â8ˆâî(çeh!4„1ц…¨Îü1Sö]”É�<©Aß( …ó)z̹²Æò9`Òz†!Ð�É©ˆ¥ m#lÃv°ŒÑ`lâ#ƒD†à�Ý`‹(48ãøýßõ]¼xóçŸd; ü£«K>ë×ü‡/òVÒþ�[×9mšRõ!ðÚrÅ»s^‰‘ϼж¼Õ÷Ü{ôˆß|íë|ð¥—&g² êd|jÐR-Ê(%ïâ­ÌucòÞ¿3rµüO¯§ZyÆL¯Ããós~úç>ÀMçøÖN×Ý"Ÿ~xÆ­YÇ2´™èÃ'G\ c‰Xþ]'G\ëÚÑ?ÆÈ2„²BŒüÔ›÷ "ÜìZJaâç3ÞUà}G‹ ôk—K®@kªï¶Îò\×ñÚjM†U¿ÿö ~ùÁã¿¿"Õ¹°ÇÙžœ/.æÜßl ýÍq£EO3ðEvj¿ã�‡ÞsÔz„À¶k>{~Î[}ÿÛñçœSYc`·ÿBß[ÅÈg—K>»\–÷fÆð�‹~×lέä(¨]ûÑþûVGa? ;›;gwê,¼£±ÌÙ©M»À¿@9÷È{¬�Š Ú¯�ÃÔ�µS¦Œ•ÖYœß¡úðÉQÉ~�䬨&r.DlPÄ&„Òß}ã”Ï<:/sþ…ùŒ‡Ûžmr"<ìûJoÓBàŸ}¬t]æÖm~ùò’Q„»wƒ÷¼ï{Y,NS¤®«ìå€WàÅVv‚F׃ÃÚç<­‡à…±‰HH:“Vpè–¨´°uÆ@þÒ1*Ô¼ó) ¿¡mš¶Á·^HŸ€F‹uº��A”G:Óõ¾Ã Žç}rD«³Þ”Ìu]óF²8 2€L|àaT ?¦@ ëF,Ö58Û€ÕŒç[ßb3Ÿ<¦è¤’ì+C@ÄcPÝRï=$®ý1鮩æ\T{Éš¤2eOǤÓgtڔݞj5„1”�ÂdÒÃʼWÐÕµB´!E@‡Ä•n’b+Xq ¸�"kSqOc™Ï:泎®kqÞÒ´ ]×1!EñJªo`‹£(SFï�c´Ž0xí/Y­GÞK–[Ãã'=MÛÐ6-cìÃ�öÂ)¸OÄž®ëYoFú~d³Yspx@Óµ8×¢# ©FÒ¬mh,XñNhO׸2÷Z³ åÆŽ`”jdÜŽ,—=O.zúõ@, ‚åêªA$2l—\ž�ë\mÊl“æÈî wqÙy�ƒÃž²áÓÞ‘ÏSOË3 avpˆÈ}l†[ §vÜgYw•gšXêØHŠêþsmÃìô“~$I§6{cm‘ꜤO[Rö°²0jP”qZ`Ø8e1.׉ÛÀ&lÙ˜Àrìiºß8Æ0ÐoG,‘ÆÀÖÂÚÁÌ[f­e±h9r–ykqÁbG \M$6IÎi:µÖÝÍ4XÇŒ½IuD×pã;Ü:~%0ÆÀv ˜!@Lr9É[¼Ríi!vÁ:«ûSHð}¦l/shš?¥šàdnî9ûÊ&ª IF«¥=´ê(ayçÉ”'f·xžîÀÕ\2iSšF;«9ªºMÏœœûïýVçä†Ä§k,T}`êÉ�×]Ž6ÌiÌýf«Ÿ™¢Œ DhêTž !Øêvkµ[?³�õRšÚ »#šÞþ7ê»Ý¯þl·WjpáiGM}äûÊ`eú¾…ÌaVšS²3¦Ì“L§ ‹W•Eð'ÏrR"�cãh¢K)’9:Ϥâµ)"?Dú!²é›íÈf3ÒÊ©8ŠF#†hr}�uÄÄߘA4•n”T$w'[ !í+å×#¥¾JR ôÓX-#¥.BAõg “r]oTõ1q‰eÁÔ¥Ó÷bوعŽÞ@æ�î$+ør˜†jzÎBG5Í\døév§bŒyíìÝ“TÓ¤îŒâШ€í´aL¿ÁÓÏ¢´*±z]V¨)w>õÑN›ôü*øié¤cìždª§wêõSß·IÜŽõ'òÔ}¥ŒÅª9±(MÚàü½Hýý)͸48‰Ÿ©êËm±O­÷,·Lµ–s{SòZÔñ A�“` cêwCÐ ÜœÑLã ¦Ø`‰ ÎgªŸ€FçK%‚ŸîK’’f m�µV�G -d§Ñ¹&Ö4ÿ£Õõ$9<=r·D�{Ñ{WÇ@’[ÉôrvêŸÒÊJ¬›2ùÌ$2ó2 iß�29Usgî×LGWöXÊtüó˼úu)>8Ÿó±ë_½Zñžª®Àiëwu1áå0rÐx’áKO.y÷Á‚ƒT ø¢h¬¡Kß¹Ö6ÌÓg™OüÛR]�W.—ܨ膾rqÅù0ð=7¦,†Ã*ë`æèÅ;x£@Œ1¦´ûþfËW/—|äÚ1ÿÕ׿^ø”ÿðÇßÅÿüßÿÞj~æI²³˜~‹Cöž'G~-ÓŸ¥wl¸_)èV÷±œ"Yödg@r€OMœÚ�4(&:¡wj¯þÔdVÔJ´Ù9¿ÎIÓwbÑ˲cÀµ.eùYdâ ôV tc¬:Räå8†>0ô=ýfPÇ�¸$Ÿ"ÅÌýŠ‚2 MkiGÓzº¶¡m›’UWê×$‡Ã0Xú!”l£~0t l[˶©—e#›”�6F�`�wx6­Ñµô-ï{á‡Nøë?ñ\,W<GþÛ·ÞäÏŸÞäÐY^_®ùÜãs>x|ȵ¶á7/®xùjÅ�÷|ü¹[|}¹æOݼÅ�¾¥YŸúç¿Æ7¾ëÅ:yC�™ôeá×…® ø/Óþ—y¥yÆ È*ôŽS ú¬èÛEüúaà'þñ? z^ò âè„÷.xa1ç³�ÎX‡Hg-ð…Ûü³Gg;ÑÓ®’ _½\Ò_\ÑXË�Niy2ú�×Ox}¹.)Ï/f™h€Î†�þr2zƒ?_ /Ìg\�c)¶úÒÁœm[ê�ÎO²àŸ><›œƔߙYËI×îðÁóÉŸ¯ØÇÛíŽ~RÓ¸xcŠnJ¡öx/büwÂa€k]Ë¢ñ|µßò¯.øÂƒåoKŒÔ4sf³c×9>¾Åééóܸù.æ‹fÝ]w€µ ÃгÝnX­W¬VKú¾Ozňa@@†aÅryÆÕÕc–W¹¼¸O߯v~s#Â/.¯øÅ¥Î¥#çø�Ã#>ÔÎð1>í_Îã•�…w;ówØýëÏò‘çÂiUДëjœÀágÕšÈÑüGÞï|~gÖ±¡Ì­:#Ù)�åAžg×ÚgmqdµÎò¾Ãƒ'—/®(á¡Ào¤uxàsçÊZZxÇ÷ݼÎ?¾÷`ÚÕBä�]¿Îßô‘È«_û¾ù[ÿˆF‘Ÿt!¥úѬiˤckĽÁcMKãZ¢‡àaôBô�c'L�4}?„€�½PަWJÕLQ£ðmÚšìh¼Æ)z‡o¼î)v¢¸1¶ÓóÛï[ Äam£uœ)Tvd{KbÒ+5š_bŽ€×;ÇTèÙjaH›¨k�op¾Õk[œ�o0Ʀ„æ ÔË‘çJM4zß»q¯Ô#“ÀrÝCu?³VAXSE—CHT�’l;›TFÑ>ã®S-×Ñ(¥Ž–ÅâKJ� Ö2šœ=†ˆ˜ˆqàð©½Z/ÁZ¡qŽÖ{ó‹Er (o÷lÖ©óÅj¡ê2` Þ9Ú4¦14ïé­ctžGâØ³\¯¹¼\ãŸô8?­ƒˆ,ö�Ç5ê¤1¶ÅÒ`Lì۲^÷¬–k..Î9<:àøô„ùâk;D¼: Ì:�›{ººÎ²èZ泆ƒÅ‚ƒÅ‚ãƒ[-Öt³–f6c}¹áÉ£K¾þÊ=.Ÿ¼Æv½$ô3uŒGÂåÕÈj¸<_òÀ_2³‘™ ØØã¸qýˆç®¿�õvÍz»áñƒ%ç°^ |¨ÿ·îÜ3ú9Ãhy|vÉÕrÉr}ÉjsÅì¨ãàà9|r t¬�fx'ŒÃšífÉzu‰á‡GG\.7\^õŒ!9oà»c•°Þ›­Åcl x¢Æ :Ué$es:ç“c`Éz½"¥3BHŽ�D;†a€Qå­o¾i´èªØÙn2ÍI=a™p�LƒRœ�;¶v^gUøìž>T°£bëÖ6ö$£ß kÉN�\[1f]˜É¹‘,Ù"ÇöÁü¿ÈÏz›»àw¶!³-+’‚\ÍT;QûÂ&\'ëHUvä~@r¿‚�ÔÇu�¡|oê¼§ÿ|GÃ*�]þ‚ì;vO†S±$(FeÍ.õQ�XgÁ&Ð_ÔeÅ"�:ð€³)#yd3âfäjØÒ­W´�:51*¢5ÓˆXFfÞ°˜yÀwM°˜à°£A†1#±…±×|ë0Þƒk´þ®wSŸ !ÕxS–o mc‰Ñ)¼€bŸÃ8°ÞÆÔ ë}qHáµ[5y-Ù� U²Y€b_øin§Aù­¬ä�Ï3"¶;Qvx§*RjNß ˆ¤—j Iž&Ó„ØkŠrHUÑT{ò§[¾¿Q>ã ©w¢ ©¯a¨ð­Ï0øÔP©¾œ»&îD£éÇy\e:mç�üY~£¾F}ħ{2Ïí„ô�D¡”îIœ¬mumCŠ,”X�¶7g-ï=:@Dø…�ùæŠnèå«§�/N…ïøÀÑñµ×¸Ÿ¸�¿éOø;ýãxï(FQnSŸ—×0íEº¶LÅÿ>¥çª‘�åÏ®Nôôó~ðBQÂÓ—$X‹¯¢q’YGJÊŽÜ-G5ÍîïéN›deehHi¿žãÒß%Y! Ͳ¼½Q«ÇÖDšt^ã mÒ·ÄÒ;Á™´¦GMáw.«3–\5£TyÞºÎ2›;ÚÎÓvžÙ¬¥�µIöKª?“¢C` }oRä‹aóÁ1 Â0FݧôýÈÚ W2B0äØó\ >ËT“¢>_¼y“ÿôßýãüÍŸú)îŸ�ñxùÝçG^z‰»WF¦‚Û‡ÞópÛsÐx^¾\2¿çè�›MÃÃaàµû÷yóÁC^¸q£ŒGÀ’üËrÓìÌ•½ý€IŽEÉ{Ún¾ˆHDæ`u IDAT’c‰>pÚyL*:<É¥<í?ñó?ÍÙ“ÇÌ�å�±I6ö!Ò¤ZÇ�çÞ~Ä&F®µ "pùþÃnÌZ>�¢ýgùÎë§|êíG Q�ÏÛ~§ëçÏ.4¢úùÅŒ¯\\±JÜã{î¿ôàq¡:jü?üÝõ–·%Jk-Û‹⥃9oo¶% üÝ*ÏrvÁˆfwÔGv ´Î£°Nß]$Ný½ËaãwÀáßiN�Ó¦aÑ5|¡ßð÷ÏñÕÍæÎ4œžÜäää³Ù5fÝ)Öâì Œc¾8d>?`qpÄÁÁ16¥¿õýÈ0lØn7l6k¶ý†¡ï 4êøkÚM£à©±†·R]“ Àív{Årù€Ë'÷8?ƒ'go0 ­Óeüä“s~hŒá£GÇ|[7c&ZŒ¾†ú÷ûÀþ<ש©é‰öé¡Îß�2ÈhínÖ»3ÞXM}»Õ3ò1D)YÏÏg…â àÝ‹¶}iûz 3ýÖ6IJou-�ú¾´íLJlB(õ?¼µ5¾86!òK¥ûP©ó…'—|ìð�Ÿ>;c#wï~‘}ä÷qrüàÉYÜý°Idj·h¦“êKZûÊbpXãq¶Å{¡ëk\Ò£"Î)Pc­Ö �X•ë‹e�%JH™¥£R/%Þzk,�ïð¾¥iº”� Þg^ÿ–•ç^úq«@‰ˆÞ“¤Á¡ÇXGsV›¾L q ›¾eýv`"®Ñ=,¸ˆ%ŠÖÆ«tL!‚1.É}«õð`g¿7D¬±xß2Ÿâª,‡_ÙK‡UZ"ãp‰²I)7]±­Å Á…‰âÕ¨“_BÄQÊ—d‹x§Ž—Á¨”Õî’}#D$ŽÄÐCOõYD0ÁdqÑ—bª9«!ŠÚºÃгÙ�Àv³f½Ú°Z­•.W$Í›ètSÁelšc<¾™i}‰H‰¾E†­jDbCP*RëÁZl;g¶˜ãý ïfHt„Ñ Ö±aØ„ «>pµiÛ+Œi°¦IôT-'ÇœÏ9>l8>jèˬ±Å1Õu†næq.iYÆb|ƒŸÍY�p°ö ÂV?CBì Qƒe D £L�S×2;9ádvƒvÞðæ[÷¯ßEÄâ}Çv„·î�†-î¯Y®[Ž®½Hw¸e6³¬6Â×¾ú:÷ïÞãêòœõÕaŒÎpÆ2ö[ †Á·-óƒ#\sI,›Aƒdœ­X�oñd¹fµ D\âfúU*Æšh•óÁ½i�˜²\¬xuÖ(Íã8&ʰD4+$é¶1D¢ iÎÉŽ5ÙhªtÞ)œ¹Š„zæ¡z{�Ó’®7]-c�¦ ¸üYhø4ÖRƒûš ÅX¶ÍjÌrúå)Ë î€ÝÙ6Ô@6·#%eÌÈÙ©›4€F¦ûØÛ€²¶_ð•Üv„‰ª|Â2–9ÕÈÎ;]�ý1a²gjlp<ž:Êܥª¯íbÓˆç€ÄTOf7Jmñü&­õ'Fí„Fë Î�AZO <¼�°i‚a3êÇ8*�©�7ã0ÑàG¡ÙöÈÒ0—†YЂâÆZ­!ÓlH 3Ð:LH™£À‘Q3­cÄTÓÅŠÃaÔa ±Ð8Cç ƒ'†Ñ¬K²3Ù–A”2Iiå’+»ã¼ß¯Å‡?�ܳn÷È�ªA©„Bž�Ó„Ñ™�<¦F01ÈLï;Ì€êw'á�_=Kü‹ÜÃ;ÝW=Õô½ÉôOý“îcúeMK‘¥ØCjçÄGœ„€µc¡ô�©² òàe)V5©¦Ç˜Àõºýuëeï³]a7ÂÔ¨®ôLy[D S˜cÕöý/íÐ#Uã7uhŠT'à „[$B3-R†ŠN—ɘl@½Ñ"Œ;‘AÉ€­0ŒÂ8›>²Ùú^!b§ur¶@yTŽ� L™1ñaFQÇÀ¾·; 4`¢$� •c@7“( leÙÆ��x¦c`§Ëëi’@ˆ’ÂZ2ó¤xÙŸöXï áþoÅ)Õ-o/»¿ÉεBR÷Û›Ó†‘”¶›Å|¤ê{Éë(ýS⺫"=圉D™º—Ü6J—|õiµN`JUªgª³§ìyêý©+&W]¡ªªŒT½œdhÙO“WÝÉø`þ ŒNéÓZåI€ú´ör_Ví’zÌeç¼͵?ïTŒÙiE—±7å*@ŠX’" 3Qîñ‘œÎìt]M§³LŽ› ˆ†$2%�»ÉWªeRRXk< ɉ\!)ZÉPŒ i\l’E ê›ädHéí’ã«§~Ëk©ÔþIAûшòÁÚ<*»{×n­ ½ÑRÎ%ç´æ}"÷ÆI„Ti�Ì»8¥¼Ä²>þ÷ÿóÞº§@Ù·ð=‡‡Ü]ox¾¢z2h!º ¶/œeVQþà›R]�ó~`ælq"Ü]oX��÷0FÙ¡k0ÀGŸ» @#S·=oo¶|ääk”Žè×Οðý·nÐ%º§w-æ…ê4´ìÃÍ–w-æü½G�øµDGqzÜòÿü­ßϵ“.k¸ÕžY¯3ÙQ�ëCr [Bí5cÑ2U�¨÷Õý}ïöBØWë$‡Ln…®9 *0dÃɘIÎ=CRU¯«ŸBI@¾æ´R¦ïNÚÔ¯.e‘õg !íU+Ј Þ¤Öª.à­‚½1a„ѽc¢•Ãó*2‚÷BÛYæ G×yºyÃlÑÒÎ;ík (ßsÊ †±�“c b0Äb0„Ds4ŽÂfÓ³4 ïa“Ç®ÚvÕ ÃéÁ!?üGÿ~ì“Ÿà•»wEøo^�ÿìös¼§m9pŽŸ|ã‡�çîÜäI?ðk)’ý÷ܺÎ^¿Îÿrÿ>ÿô‹_à¿ÿJo1ÊB›ŒD#“ñhöu¢¤³ì8°e×!�DWÑmòÎSÝby)â⳿þ‹¼úÆË4Æð‡Ž ×jüÊåsgù¾›×y°ÙðòZeƇoчÈù¹™gÃ@DJäkágÞz›(Â{¬*`òý‡ ®w-¿òèPù}-�]¹ÍŸy|žä‚:¾œ@ÿCï¹5kyåjňÊ»s“tïA 4XŽaÇdÈk ‡©ˆëY¯²èƒÇ‡üfEír½mX¡Dv¯Cd³$gpxŸ¾Æ§Z7û\øÿ*�µÜ^ÌxyØòcOÎøÍ·×Ï>¯;ॗ>ÌK/}ˆçŸ{/m3çââ’«Ë%ëõ–õ¦W 3j�ð!­+ÍŠÕH³¾ïY¯×¬×+Ö›ãГ9™­ÓyŒ(§tA£B�@Ç-ÔxÂõ;§Ü|ñ#8çÙ®Ÿp~ö:g^áüñë„ ã0ˆð‰‹'|‚';Ç;>å|CŸÆ-Gûï�×þëðŒ±ËN�ýs¯EM³þƒ¡1†ÚÅR;`Ê:Yx‡1¦ÔÅpÆðÒÁœW¯¦,‰}Ä×ÓÚ霥5¶ÌOkàÛ®�ò¹ÇçåÜÓ®å|Ê}¿zµÚ®žôC¡:úÈé_:¿d�ê|ß�S^[mxsµæþzÃݸÁ�?x€ˆð•/ÿ~à~¥`I6>–q «À6$ÈQ(4Äai°F4²µx×h¤·œwøÄk_8¸3˜Tía9j~ŒcF} M£ô<�ïh|‹÷CL΂”IеØ0‚îåý°Mõ "àÔ‰a\¢ü™t€˜²˜MÙ�u2’@Ë$ks±ä6”ëVånƒ•¤;:Œ ‚±ëÜÄÿLÖÿÒõšÆ)P?÷t³™Þ‡o(ŇKÝlâˆvÎ)]QrÖE‘TÃ+çÿ8HŒ‰¦/ˆVçLÎÞ0&QRõùc‰aPZ˜°%†¡D(ÛØƒ ¸Ø¤ÌðœfˆVköH lÖ+ѬÂaT*§¦Á5-¾icË£ŸùVeCé VxCý½zŸ¨ƒ"õ^b2òs yé_¡ã•11`MTìn€Á �FŒŠqï‘Aév‡ ÄqÄ àû F²ó¡ë,óq .f3$ǃ®é®u4Né¦.WÑ4•.m(c,Î�ì�q„�2EŒÃ“ÆÐZè¬atZô>ˆ),Yç¢0JPV“�è¨È‚vöÜÜŸ¾Ûiðl3/©b·<5Øfw¦ç×u”ž™¾šÛ3]5MϽÞÿM²QÍôÝ<9wî€g,ì§VÆîuŸù¼÷Ýì±,‘ì6Q;¤¯˜‘—¥–Iv¶ÎLÕ³ðI×)æºèû¦PDLm˜^E—ŸÑÔºOÌþ';�o& ²ê1 _-ñÝžª.´“þ“ïçi0dÚêës²°·/$‚ñÓé=šR`Àc‚ÁµÛ>`mP: &¯X´% ).™+\DŠ—[¹üE£–ÇQ£ CÎúÐ;Wç”1¥þ@v hñáÂ6¢Ê ì¦1•¾I@ǘÑ ú¦ôÕä 0‚$„sœ}€¿7â¥O3` �KjÅwº–ì ŠÉšC%øŸúýIÀL uV¤'ñ?MéìŬTÏäõc0Õ·w*óÝeÅ LËê’Âôœ—¤¾—�‚ü˜ÖE†âÊùic2;gW÷±ÓžÝ¾É¤D)"q«Ú�0I½©¯õi¢šÙïw3ÝoþN«Û�?¯#¨ 5PåÄÌ@yÒë’È”]'iú-ó›Z.!9$­û$ÒšÊ*¥îQ%GUt˜ô¿-«®8ò(åõuÓÏ— A(Èl^;“%]?$S 'LJÜþQï]%ª�HÓ¬"½Ž•¹¬EÝêñ3¥3%ñôj&US„L^Çê6Ò­ýè_ýbiËŸº©ý�Ùú%Ô8n|ÉøÂù%¿ëô¨|>Š0ˆ�Ý µƒa¡s¶d"|éÉ%/ÌKñâ7W¢ïON„“ÆïÈ’¹s|ü¹[€Ò2´Õµ¾|qÅ:„R³`=^½Zñ@"?öà�öœ�ÿõü7ùà{NÕWŸú𤋮ÈëQb¤ïQC\¤È°²;‰f-ºŽ?óþm~üÿ#¾üúkDþÊý»üùçŸç›i‰ÀåpF�¿Æhôñyßóý‡ümû€mŒ|ñÕWùØw}/G‹LÕ¥$r~’”y•¤VMÃF-·v÷+}_¦šITÎÃt3íH|ý�¯ò¹/ü"_òþ¦¥³–ï»y­ÔØ„Èå0”Èxk ÿüì‚!FÞq³ëxm¹âñ¶§³–�?‹O?:ãáF#’¯w ~0¼�"¤l{Î’Ó±³–Ë1ðéGšið�G<Øö¸üðÉ"RhPT^Në$Šðï¾� Ñþ!J¡n9m½+­Þt¸¢¾±W\8fuưðŽËa,ëç…ùŒ·ª(îÖ6•Ï ×#øWå0À�Y Þñ3OøÔo?Ói1ŸsûöûyîθuëÝt]‡÷ž,«¾g½ØlGÆ�w-Ö7tÝœ®›á}£6KµM…O™ $'*È´'ê,�&S `M(× Á0ŠÁ†×,¸qûCܸýabˆ\œ¿Áã/söðeÆQÇå"~üLçíw-øØâIéw*.ü¬cŸöÇïÙ0˽úA¤œÒ6eþÜžu<ÜöeÞŽq7»+ˆ§€7Z49gÊÜèZ†‹SÁõ®-¿…ú ˜j7omYÇ�ç{n\ã“÷”sÇD¹�çÅ/?:GDh¬¡µ–ß;ŸóÿÚG,cäõ×�óó»\¿þ^¢hñÕLÍ­Ž”è‹l»äσ‚Ì�¦6-Á9¥wU6Þ "OÇd!�]Z»B#ü� `›8Â(ô å÷Æ 4GÆy|Ó%Z—¨‚fk'ª¼¶K˜ìfÉùl“ŠïæŒfIúYõ“ÍQ(�Ù}äkšà% !QÉI­ÆD¿iF‹w–ÆÛÔO-]§‘Ú!ò. ÕÁd:bL*2)É>HT'Ö;¤�æý/2ÆPœ“’óC�·:Þcè ¡O�dËöCŒ#&Phu Úµ·#cA¢ÚæcH«…a Èf‹oZš®Ã·-¾iSæ‡SÊN£à¨3Úga ÖÑZchœ >â]Ïè­f„>6¬GK´Žh<1Z”äHAḧ1�H¤¢º ·qv̓gX6súõŒ£¹åpîh¼>6«ÈF"ã°e¶¬W[®–�]r¾¼`Õ¯∱†yÓ17ž´Ö@Œ½êôq›(R#Ñz·am–Œ~]Ï`V¬úsú�Áš¶ƒpµ5°q Æ6˜Ø`lÃØC!Œ†|*ÄÞbñl×=ËqŽONÀZ.—+®Öš9Ñ‹Åú޶i˜· ó lû�ÕfËrµeÜ% ÊZ¥zSí C‹¡Õy•¨¡4¾) ¢ûÛ8dÞb�Ð÷[úa ÄÊ^Ž1©ÐvÏŽI´ÅöOóµF§•Qlß¼Ie°¼ÆLÌî?TZ±®÷gàXù7sDþäP›"ê|Š\$ÉÕãBÌÙQÉ®Èv«ÉN¾L®¢�¢Å¶L´´VRÁ[Ìäàsê” A1¬ô¶ÎA.<žõÃ$œê ÍÒ{¥/RßZ§~&eS™é^ë7I�2ùaØÍß3•ÜÙÅ3wlúbÔï62ßÇ4™Êx²Ówq˜ +�0&âQš2o,­¼Í¶^ ¬^XŒEŒÓŸQJÀ1Q4N‰¤»X:IrEècÄÖ(Ý�‹<ÑúÐ3Ä‚� ŽÖx$±‚&D"6€ÃªS(ÉbGÔÂÆQ�ÔVF<­ xcR½Ÿh[‰l‡@?F†82Ä1,ªL(”¦ ïÌã7¹ ªéð ³÷©c×¼–i”v¢R«Ý%7`÷Óê/Ù¹Ôn»ÌÓ¯…rÍÿ_Çoysït½´¨awòÖ·8j…&œþHJÇdÔ×}“…Q¥M˜úõ^KscÊÇÓòʆìžðÔ½îŒaõ�ÚH6åÌÝå[_§4h‡–hGÍ{‡÷Ó|1)ãÀ¸©Uü¦k: �h°#˜&â\ Øë xATéJÄ!èæ8ŽÂ˜„±:2O£*&¹jaÔÏ­›xC˜œcH�(ZÐ( A2.g(UÐeÏâ ¨B•%M‡€$½8ƒEa¥TUÁDö�ïì¨7¾ÝM3Å C.{VŸ¾¦ì¼–$üöhàLõù´ç{ÌÑÕ²s­½ÖVN�¢€K:3{~‹ƒBª+ÔkIŸ- bäM}´§ç‚kS¡Úüù3È9dzR9ýÖä ˜Þ#Ó=uLŽkójËFÆ~ŸêúÏÝ0]ÂÌq:)²pJÔY »2ûéñ(c¿wbvíg•èæžŒ“½ÍCÌ$}vU›¡D'…ĹÑ4æÇ@Ç'›#êÑkZ7EÞçó§8�¤LH?“àÒ„ˆ!–y()jʈ¤¡Ü—m2 ³IN=7õvÂ]ÙÊԞ온—f¤8Ä¥l cS–@µÕ%ÔOlšã’„OÌãP/Îü·ð>ù_úªF4¿§ëøîÃ#J´ïrYŽ�ÛÉQ "\CÉvœ7S �u<Øl }GøµÇç|wU'à¹ù¬2xoùƒgÛž›³Ž›³Ž §Þ~ÄwÞ8-Å‹¿¾\óÒbÎajÊóÕµ¶A)N¾íÆ)ö+_)@Ìò§¿™üýß@¡_Úß+“ažÁíüØ—M&�O^oïFT²w˜öó¬$¿“œNc³“@¸£ÌR­Å4I*�|O0ðtëóu«½oA¢ë«dª˜Ä‘¡°í‘õY÷Ø Ê+!§îÙ>Ej“=åX'øF°ÖѶ†Ñ{zÛ2ŽÚ�ÂVtü­‡®1Ì;˼³¸ìh#4]ðqgù™hpƒÁv¢ÅDâ z$X 2aÙzpŒ„«QèC •ä*ò,¤zA`׬!Cãò£€ÿûS?˯¿ò2#ð7îÝã?¾u›o9>ä¨iøÔÛ�bä;®Ÿòâ¼ã÷àŒážžò�cä3_þ >ú�ߣ;¡±(pªúÏ4ryÖ“Õ¤elª‘7“,«RM·,²J—éwÎ/ós¿ü“ÿso3[vÝ÷ýötNÕ7ß©›M6ÙÝ$E‰")Š–%Ê’mJ†lG–lÅv #yò�—Ažò�<ù!0ŒÀ1à ��†‘�e[0lÇ¡EI¦H œ$ŠÝœz¾ów¿¯ªÎ9{µ÷>§êÞv^lÃEVWݯªÎ°Çµþÿµþ áø¡Nɼ]Jü“·ïrÚ޽'æÌ× øøƒg'Üê;¾p÷GÞóÑÓcÞÜl 9˜ùÊ£K61ÑY‹·¦4½ÕwÜé»òŸzÏϼï6ÿè­» ¤UÐbÞp¾õäšXÈ™uð\O‘ëŠ~úæ9ß||Õ@ÔWŽ�¸7Œ­–À.eÆXE)pÑ®bjÒ,7ûŽ`L“w±(!ùd/I˜#À�ÑhññßbÀà ëžw%ó·>à›Û§³Ž�oð¡}Šçß÷1Öë›MJbš)iQHƒ#gØl”,˜€ïV¬VkºnEׯð¡C‰ ´ÁÌEC8g0ä&Sˆ§K‹•R€Q²FO»b+f)KO]êªXÆu¿¾Ãû>øÏ¿øY¶WïðèÁ·xxï[*[|isÍ—6×¼ÒuüâÙ}±Õ‚µ°œÛã0#à°V@ÍðF5�—Ùo·ú®�9xš zw!dÆÉ‡ŽÖ|oAN½ÿhÍ›mêã^æèuL\ÇR¬»|·^÷§.ÎøþfÛ² šDe»§Ä?yç äå6å–-óÒñCN�{®ïyßÑŠ¯=¼ä/ݾÍß~÷]@øÚ×~…Ÿù™ÿX W©±%‚\"²´u%©äLyVp½Æm¨Áûž:ú¾§ïz:ÞœÉì¶[v› ;Jv‡3t’›H~bJ‘)MŒÙcFCÄÅ‚­ud„LT Ð‰ê'%ºŒX$[6»ˆä ¶W¹¾ì¹~ÜsëbÍí‹G«Ž£UÏåy¸�Ø�;ÆiËf»åz³ãñãk\^s½#XÛ±^wtÁª>EÃ8 ã4–q162¸-3˜Ñ±K�y²½Ï°u8‘<"i‹‘k:º>`“‡¬µâ¤õ¬]á]›Œ³ˆc»Ýq}µ!ôkÎo\`œåÑ“'\n¶l¦ˆØŽÞ÷¬OÎ8=?%‹°Ùmq——L12Œ;ŒD@ðVpÎ"yW€Jdy†’E ~ÕDŽ#«Õо_о÷\_Áçì2KYý?;{T G)Ç7%Û¥­²Åœ. ÙÒÕbààQíɆOÎù´uμ×cI Ô×åIcʘ¤ûÙ\DÙ4U‰9£‹êé¶z˜Z‡Nç™5µþ¤”8äJ 91ç±Îƒ1Ęñ)cÙ_�ëÛ9užÎ¾pµ<¥^ÈÒ6%K`ù´Mjbq¯ÅÂ4 …†v¼Ù÷ØÃêk[k�Q[ý£eˤXûÀìý¶¬aê$”}Â*Ïcm&xKç<Á Áé®2«íz 1€qe/Öµ+ç‚×µ ÈŒõfô³ÀUVH—Gv–)ŽÄ‘¨5Ú, 1�mÆÔ(Ÿ)c’Ú?Þ8•VφHÆÈ„É“c!"�ÉJ:Á:¯{м™°9aóy"¡2vXK¶ŠI.‰.á (¢:'³K"­©;Öìÿh¿SÛÄœ�îÚymý^R}ßúù•]€"‹+04p¼ð§�˜güsy™{Ÿš½{ŸõJêb!ì·es¶4ª]æ«i²ó ´­¯nŽnÑÃKC¯Î™6«ÌþõpM¶bþlŽ¥6û {pðùWÒîvvGçOö®ü=œäTE IDAT€³h7íû¥³»ßÒ¦®T �ð¬ë{GåZ³imlbÙ@Äá Z€$©¦± u$Îr¹§,ªƒì¬h:¬Í%ýF£öÕ–ÒI¥YV ×,�åSJáS¤EÄ/£¾÷šFæ¨ÓÚªK š%&_W‘’Q£çƒ=£Åe^×Pж—/£íóU\®¸Ëó÷–€°)¤_3÷4òМ‰�ò¯°/gö| iǪ÷_�W®�ýua^™æÍ þ5×tÁÌíå«uîéyf8®�øEåzORïC£!æµsyÏÂ^G.VÕv{mÃhG]+«±3/ÒûͥסÁÅu-ZÜçâ>–FŽÙ»¯ý±#ÿYà×ö˜×sýšì”Û+ÊÞZRÇv™?µ� E�<·£jŸ:S4ý˜}¯zŠb8YcZW-P_בâ ÕŽÑ9["œsØ•(ý"¢ZŽÅ ª··W$ô O÷ºÉÔñ2g(å4+‰ %L!Šl͆(Ç7¢BMõ^ê)¦h)•”Ûœ!YjÚ’ØÙ˜ªóè¯þwsm�¿|çW1r|+"zì=Ç~&Œ1|àh À½ÝÈÍ>4áû×[zg‰Ð[Ëy˜3 ¬¡‘×,¼Q2ÞÙ <§&Gt¯owÜ.ÇrÆð#7Î9*òD"ÂgŠdÐÃqäÑ0ñJÉ2x2EþÙ»÷ùÓ/Üá¿yóMŸùáÛüWÿÙ�#ƒ(ûcA¼`¼ƒ à�`ÎT!ý:¡êÍ·±e …׺¶¦*/ú[ �Ô6h3yjk™á)'C˜3=0%yÁÌûžaAÜÖ9¹ –×P¾#‡[¼m$RÛ÷ëId±”ŠÞ™2&d7‘7#i»%ïFMuÏF5xmÀø€q�:àsŽª™›KñÁ`ñ¶h>»ŽiȪ½Jf'ŒL8c‹mÆ™¤@améš,¨Aö`e޽è¬îÿ…0â!;� “A¥D,1ZV“aµƒÕÎ�¦L2©¤H’7Mb0S‘ëÊ9ã üùŸþ!¾üÍß#Šð¿Ý¿ÏxþÜÑ­ îRâþ0òâÑŠï\mù¥7ù{ ÀoýþïñÓ?úãxqêtШNæå£ÚIûkLËZ&aYC”(mÝ~Úf9/xã4ò�?ÿ0Nô�¿tzÁyðüÔ�[|ùÁ#ÞÝ \ÇÄ}î&�ÆØÀÍ'“’†5#âÉ8ñOÞ¾‹1†:;áÁ85É »u�~³H€­—³I‰úö=†œ9.QMU2èΪçfÚ¿{çøC7Îù|Ébxk³#Ê DÖïvÖrì=DZ�÷�ܹɯÝ}ЦÀy )Sá߇ø7{&‘vÏ7ºÐ´ßA#¯·)ïiÑÿÛ�-`�JÒ¼-‰¿öî;¼1Ž{Ÿ{ßóò+Ÿá#ýqîÜy‰#ã0°Ýn‰)'•ÑB†:ÙT«[pU¿½ëéWkú~­EU�Çz¯ÜNp"¥@88oñ“%FÕ!�1áŠT–µJâwÆã½aG¦I�P» �£X&Tj&8G•┲>Õ=÷ÆÅm>ô¡!Ç�·ßú*¯ïK\_ëXùö8ò7î½Ëó>ðÏ/à}UÁõ` ÓÂ&> ~/k¤.ÓËÇ’ÝÇ@ëbÄœ[½ g ]Øûþ!ÙTe¯zk›Œ"tÎò±Ó¾úè²}wí4zºà_}ü¤Ù]Θ–µà�ácg'|}‘Yð‰ó3¾ñøI#<.§©‘¦\×ÛÎþäùçÞ=¶9óÝï~‰»÷¾Ãz}FŒÃxEÊ[„cUkÙ”Í.‹0Eáz#ŒãU)ŸZÁGcc¥ÏŒQA¬ÙG¬Á[•´- =k»Ba¼’�c‘'*úøY&�h'«­5ë0ÖáB×@5 £Õ¢j²ŽÍ.Ï*Y[²^rdÒ9b�ÃW2 ÖyŒÑhüÙ2��¥[o½ÇbÆ-ðòaórÊL’±ƒ~¦Ùë‚J·Hq¤”›œ—½�3S›LKJ±È¼(�cŒú¹%®Ä@ý÷ìUk]3D4„-i›T_´Ìg Α‹ßZ}!ÍT‰˜<Ï£\Á]%¬ó •¨Úîv­‹f‰ô�ÕõÆ0E2P G²9á¬×Ú)ácfLcœp>`}Àø5bWê”–Ÿ/2·ƒY̼尸ßfœ."ÀÛí.ÏQG%æÏUm—›X=GžÛ¢<÷¶>©mQ7®bM4VÚ>]´äÔë´ýç÷ËÝ~n›ŒW«èüAsËâû{ëôrΗsî�-irFfq¬§ í­Uû�•›¥úNµï2‰’ ¾�]“¬Å«*1`«=âހ58TÏ¿¶|ÓêmÔþ6#•Bf•ûËeí”â1fÉHNíÞMŒ‡{…@�³˜¶�éü7-8½’XiöR%6œ3ˆ£©8Îw_¾ºNjZ &%¨’Õ|Õd�I‹¹.Uè¾ð»wùÕßz€Û!ðs„ÒWY„]Ry�úøîõ†—Ž�˜û}ûÁãu{¿M‰µsœàÿ+/ùÄÅY-Ã÷®7Üê»F"Üî;Nç: ¾I½±ÙrkÕ7áw>fí?PH„MÊ,… N¼ãsÏßâ‹WWü£G Dö�ãþ+Ÿ£ÈCB,“1Î!-ƒÔY xW¼�J Ô¾�yŸò¦îW{ „,•ÌkL=†�÷^]� Â]#ß—NxFÁ/»ÐoçjϲG˜å߇+†r +/NKݧæC”¹Š Æ ÙŽ¤ÍHÚŽL»�´‘¤3�ëÀ%-N¸(~-­0¡Gs®'¬t\Çè#f;1ÅŒa™°x-¢HÄ0©CR ÉfܹBòÔë×~1E{4[€ì §0�Ë‚�Ð�†¾ú 6áÌ„÷ç=‚%Û25õ]ˆð0Æð Ÿýc,_úæ×¹›"ÿý»ï²Nð£7Î0(aö�ÇϯzþÌžçÞnàŸžòÅ'OØ;¾ñ�ïð©�ü-î¥å›K?ÈâµÍ}YðG%£­Ú�hDkÙ6¤Œéº‡ü¿¿þË<¾TàôçŽO1èü}íêš]R)�Þ9~ãîC"ð±óμç·<&Šp<Ÿ{þ6Ÿ÷>èÀ]ï~aÿÚ“k’¨ŒØÚ9î#÷†c øæß¼|Ò¢îäâœw‡�WŸhM�1gO3¿K©‘7»ÀuJ ¸ÿÈÉ1Κýì­áöªkÄ€¿õàñÞLøn`WÎÑY3GÿŸ¼qÆWÎì¡üÎå�ŒÌ2úpíl‚ÿM= ¥X­$þÊÛo¶bëõq|r“øØOó‘�þ$«Õ±x%>#yÇ4©sšR*r Æa,Ö8B·âøø”£ãº®§ë{gPôÉ}["½w¤àÑ'Ç0v[ÕvwÖ*émð¡C÷Z•ÂÞBÀ­ôI:¢tô]Ϫ_i‘Úb<-ma)EÈsZóáÿ/½ô“Ü}÷›|çÛ¿ÆÃ‡ßà�8ñ7ïßåÃ]Ï/�žc³pì]òµ-÷}µÃ¾^Ö!8-¤A}|`½â�ÐÓžìUi¤@ç,cÊÄòùË'GÜÆ&Qä‹–tKcÊ�¨Wø­2Wî¬z†”Úµ^t�Ö«&1Ex0N{wöÅ"ÝuäÓˆ¯›}Ç'.Nùü;÷Û5÷Æð‹7nòwïßC$ó•¯ü}>ñÉŸ'¦1nIi D¬«¤’A$‘¦‘aÚ1Å `Jÿ$RÒhxï‹„�Õ ŽÝnbFêž$%ƒ[òRŽF£­�[|O׬µ*›'†a Æ©Ïuž½W•Ú0x_²J è¥~/#ÁªRVY¤DªeQ'–ÚqÆ(í¼ÊxdÔ7T ³xFȪþeÝ(„@ e¶-�±Œ’2£L¤˜Xõ=Ö”ºAÁlKdšJÛ)«�¥è©j¸§"礄€,RŠ?Wð´"­æ]IŠ„PB…2Š4”SII ŒúRLœ¥[Ž¡ÇÏ$’š>ت&|%¦˜c$mÆ)’º^3•ªwS©M³FéÚŽ,]·"t+º—Q‰½Gƒ3K‡ÕÄW©1Sêù¥âÛi}cÆ82†1'ÆíÈÕfàj¹ÿ0Ò»Dï9îÈÓŽ1Á” SÓŽ$‘$©�$–“£SŽn®8= Ü:ï¸sû˜;wnpqã”°²¸Þ�L"™‘!=aLW¬W°Z «uO·ê8:Ysq~‚ωaë•Á±^÷œ]œá{ÏÄDÚîH’ðÞrãæM>ô�ç¸sç6ëõŠ·^{�·¾û6›�//¹ùÜNÎOxðx˃Ë<ÙfÕ­B©·Qðª*Ñ‚½ E—ËzŸ5ˆSít�w®­oU²,Ëíû½¬äº®.BÅÆÊçOá—óßësI T?8gQP¾*Ô �§®Ee¶)k¨iÇwÖá­ÃT©³â£xç]×j�`¬Î�)ª$S*„(‚(¯Ò •=W�Áa&ã«\žˆ.ÇLš2Ó.2å‰8Eâ8a½Ó *ïpÞ¬J™¬öN÷  ½8õï­Á{K ã˜QDÈyÁ9AÐBèÞyú�'aš Cî$0Far‹¢�øêKøe‡tsëRxzíá‰Oͺ†ZÎï뀯?9Ø€êKÓæ¯_Ø“G�ÅáçAgÚÁdþó3.zéÓ×Hªæ~™ý¼×BrxÄYËÝèLeåŠaQ&Âò’šÃ·×¸¦[ÑN_F,ÚnD4œ —iQÁ¹F*,#ŽËß1UǤ ¶ýûÞë“¶W°uÙ25Êã°¥Á”úçÙ\îAWûò½Ü2ˆ‚D!AœÌ “-ã4J0¢‚ÿ2g64€/+˜W3$Ï×£2EJHŠgÖ|²%²%S𱤽WãgÙ^mT– ^iÌóòYÛo¿¸eÝÜ–@”iÆå³¥ƒ„°®ïç1-Æ,x:Ù[\çë^.Öå¨{`¸ ÚžºØW^£ÊÅ´¹¹Å›1¼¸äœk-…g�›z e[Ô™ÒfÌÜßåœóy4RaŸÈªÆ*íu9uöÏ;�×å 8/G²÷7ªÓ²èƒåX˜7¥26)Qõí$Y7åb¬›\7éyù[ì�íÊ–m"í³ºî.¿^ %yêï½ÆÉ¼F2ßëj¿<«Îuˆöû ʸ—Å-ÔqØzJÿ§Ît ß*ëæâ ³(1àZÄ„ióÊ¢)ßNl¯…�YÿT„’ PÛi1¦LÝýêýÕÛ®›R-ÄfZ”õ¦~¯.YJÁâ‚á—5§J—µ€ªÃÇbm5mM.ó9£he=`fcÅÌdi�W•”(íûWÿ‡¯µÓü¥›·ö(¢ú�壒¹Üc�æ2Ev9s§HM9óí'~x!1ô‘ÓãF €ê…ƒJþ<‰‘Û}DZ÷$>ÿÎ}þèó·ZÚâULœå̪D�~äô„Îê(¸š"(5 &¾|ÿŸ¼8ÃÃ_{ã�v¾ÿò?üQ>þþSd—¨OŒ ޲gLÎmî¤m.�n U�}YôG]ãZ£•¹.u|•Ïêâh¡’‚4ÂcZö-bP¿kš¬ÞÁxl;­Û´·'ïMüƒ^®v”,ûC«Ž²Œ'(E¯rФ¤Ñ†ÒŒH!‘pF5;m-X#�EÅd„lÔH5Á`½ÞZ¼1ødð#2Æ&`R`_œÎý¶­–û·¼Ñ ¢§îÁÌ›ôT:MŠ“ŸŒ+Cß ÁGF;‚¥ëЈOZT��‰I°1£e•œü…?ò9ÄX¾üû_eáï>z€³†_|þß+Qó‚Fßnbâ—nÞä‹O¬ûíßÿ:Ÿøð'JàÂ’˜³(¯¹¬uØÍõ‹(륮+310ïUµ�Íâõw¿ñë|ÿÍ? ÿzÁ‹«ž—×kŒc×üÖ œ5üz‘ Š9kqÝÒÂcÊüÚ½ìRæ,èþ�"ôÊÉ'Þó•dÞê;~êÎMþá›ï2••»´_ ø_ܨ ¤µœÏýaä1ùü“·oð…E´ÿû�Ö¼¾Ù69—·v»½Ñ»‰©é¬¿x´âÍíÐä†~ðì„ë÷ ú…Á#°G À ¯KDâv!9süxüoš¸ÓwÄàøï¾Ãw†aï³7^äãŸü“¼øÁÑq‘3ÛÝLj[æÌ4ER6Þ÷8—ñNÁ•Òb¤Îº¾'„€u•Øœ™²FÖ`ˆ˜"ã84�íi˜â!¨îmèªf¸FwêZ£zÈâ2Î;‚wëèû®íùRHúœ&bœ˜d$�‰T5ªE¸}ëÃܹý?~“W_ý<÷î} €×Æ�ÿúþ»|öè˜ÏÙã½6«2?µ^E%¬1œyÏ£érØ×•¨ò•KRà…õŠ·¤ÁyÜMs- {dÅó«¾I\|ææ9ßXHhM×ñhœxTˆ€£B|¼]ÎýÑÓc.§9è4xÖÖµÌ�«)òµ‡—{îè¯Ý}ÀçÎNø¿Ügáõï™W^ù ¬³Ä¸e*Ä€±J x«:Ö1%Tߨÿ”29E¦4’óDè!ÝxkÆ�Ýn£Qø¹´¡°ÚZ‹óg=ÞCè,]ç 1 @uÊ5^÷ú9à£ä¬rñ%Úªï_}›¶ßpWª —M‹®¯1{Ö:|-�sÖ\ZP׫�FÛ2'«a‹Í˜J½â9§B¨D-´l„,Qu±ƒÃª0Ž"Í©ì¶ab)kÍ€ZxaeÓìÃÅþ©¶N“ÖÖ¿ÛZ¤ddG%ª}Y¥Ãœó¥à±¢-î¯ná’ÈEoW’lÀ[_ŠOûbÍ,$‹Ý‡qäz»% ‚fÈ)1î†)2DxBX­{Æû¹{ÿm.¯v:O±˜­#Å‘qç8==æäÆ)Gë#‚· ÃŽ÷#W×[bšéN;¬_s½ lv–'WW Æà¾ ³ñBT}öÔ�D:o9>êU§=¦²öVCG3P ¥øn©5aJ”~]saaƒW¼¢õÌÖðìñÍŠÍ^Zç,.$|vd™ô°FÔ0¬íÓ€¦Ú-µ½—cj±Ž ‹ßVM¼j|š½)±·AµÌ*Øy0rÊXh¿“º9Îìë’—«?ú—‡ir ~’ÚÿË";ŠQêí-7óCVWÚ8¨ú¤MÏo霷k©mpøo=�iÆ|…ËÍpžÌû E�ôŒuh1á÷>•ƒ-¨l¶38¯àQm_ Ù³ÔÏÛ?^틲!—¶2’‹ó’Ÿš“‡+GáßµMZGÏm½ÿ“zMÕIzöm?õØ3�ÌÁõOÅi†Øá—õMŽ�ãoßÚÅœ1MBèî06ÐàíÍ–³.´‚ÁkïXɼÞk)p9E޽k™ßÛlñÆðþæGÑÈÉZ—ÀÃOÞ¹�/ 14y¡»»�mÎ|¨H='~ûÁcþÄû´`²Ãp£ ¬�åo¾ý6÷ Àñã¿ÅúÙFm޲ŠAI€(˜â,‘"Q#e!ƒæ0WÜ î+‡c¿y¼¹­Íb°­{u,›5jÇŠÕFö24�¸ô_Í”›5àæ¿³|rðZ¿ü³¹Ê#,³µöˆ¾…�Q‰õœÈ¢ÅñV£íСÉB,2|Ø™A“È&•ÚÄšÓäô½‚ÎXB¶tÑaF‹s`\Fd"g‹?o­ H¼×gé[�W‹À…ºÀ/H¢óra2ô×°ê3�� n¢ó�U¡wø®g7&vC$åÈ0&l!>„f ¿øS?‹üÖ7¿ÊëqâoÞ{“2/ñ‘Óc6)ñ¥"¥óÇŸ¿Å-ï¹#¯¿ów=æüü¹:We½Öi^3Í"C ®“• ¨ã­¤×/n[êZÁ¼ÞÞ¹÷}~÷ë¿ ÀO¯Ž¹ã<Û)ñ¾›+�¹øî·¯¯1nöI„{»‘מl8öŽOœŸòÝëm+?só&�Æi/B9ʼ¶?'~å--|{«ïØÄÔ¢Ÿøâ”œçâÂgÁóÒÉŠ´OQ‰ âøcÚoÏ˼¯×¼vŽ»uÁ?_È õÖa™©´o>¹nv�1†]JMFæ¼ýàñšwvc�Ú.Å5—�e��gküëy\t�óUÏÿxÿ.¿yuµ÷ÙÍ›äãŸüS¼ðþO`�ÇZÏ'ÆX´ÕÇQÁ‡:FDpN‹|:«‘jº¯Qƺ‚¨ÞëäM9“ãD+@ˆFÞæœˆÓÄnزÝ\3[ÆqGŠHTB ôô«€w…To™xº¯%“ˆ¼SG8ô't«[ø Î²ºB¢æib!ʼn4M »-ÓT4ª�!8�±–óÓçøÑOÿ=|�W¿ý«-ƒà76×|y»á/œ]ðÝŠí¢®@Ìûv^Ù#ô;:.λÀå[ÿw…ð¼Zï­É »eîÔC9Ö±w¼°^µl eÔG­Ùa 8cÛukøàñ¯•ß J|õÑ“Fp¼³ùaŒá�E±í—��xõꚣ‚Nâ}wøÝ‡�¹;ŒÜÝ üÜÅÿàáCrN|ɇ^þ 1�LÓ‘1I‰ïA ±ø]µŽ’•.Rö IDATÊÙ$ÆqCL#BÀ˜€8‡Å‘Ò@ÊÖxÄj¦ �&?é:a}|ÌÑöˆÕÑŠníَ׼sïM®7£#¦LœRó·Ö!sÜ�sûâˆã£Ûí5Óö!ÃvBòã…[7Î9>=áÑ•åÁef.yu¬òýy3–½vœ‰ýW6¶‘‡'*%ÑX¥¦?™òYÌXÍ‚$‹”H[+…()ì ZâYrsÚX(QÒ å¨½½£œk`/­¦|s+Œj(»…ždÏdSŸg­Žµ}‘ Ö`KÊ»whªa14j »u¦~¦mŸ^­ËGN:¦³-צ÷ÿ·ùU²h’ôŸ»¸Áq‰Æ¸¨À=¨$ÆòñþÌ‹»œ5z¶ÌÛ/?xÌ�ݺhß}8N…dPbàÅÅqAÁ� üçjÎ׬J4îoÞÈ‹Çëv-ÁÙ½èÉ›]àsÏßàÞnàÈ{>vvÂk»ÿç}½3ü·ÿÉOàR>jÉÙy�³`<ûÃÕK‰>/ã¤Iù”/UâÒØ­‡ëüÏk¨)ç­c¬f T’–5ÑÌkƒÈ¢%+øÞ–¾:~êÞ[×Ôýx®î¯Ë=]°y^ûD×ÁJŒí�ÃÎbƒ:î6 ¹ËÈàl·c=¯B»…ð׈£€1êpÛU‡YyMi � vk·Æj¼{kp�Å”zÆ5âjLYÁRe¸LÍ»ËR!Tê/Z¸¸Ó‚^Cˆ–£caÜX¶[˜&aÕ «ôkG¿îð»ˆu0FK !B¶)Y†Œ±ü™Ÿþ“Œ1òµ×~�MÎüý«K~> ;{®E{ky8Œü;7nð¿Ü½ Àï~ó«üô�ýL“;Ó&ŸÓÍU—yÎ8¢é43“²"u •7eÙm{ÉfwͯþÆßCDøX×ó©õš•u¬�ãÿyç"§nœƒH‹öÿèé1??埕¢¥»”K4ù¼W~íÑ%C‘ ; ¾Õ8öž¿}Á—î=jÅ\?vv«O®[´ó;ÛaïXw‡‘»Ãˆ^99âííŽ{E~åSg\N±É9cZ?À.g~­d8Øì¼z¥ é�.àŒiÇ:öŽWŽ�øêBwýѸüÖû°F÷–e�Û«ž{‹(uê_×Ã[ËGO�ùGW—üïß{kOæèôì9>ý£–÷¿ø©t¥¬×=މqˆLQ‹‹){˜Ó{«:ﮬ˜fOUr@@e1RF’.l‚!ƈuS“‰ÇQkPÑ,„® t]GðºøæœÔGRŒÍÌ3Æ|`Õ¯ñýŠÐ­[ÖVÕ™×HêÈ4 » ÃîšawEŒ#ô>Ä+xXl½Ó“[|ú“–¾Ç·¾ýy6›‡L"ü�Çù@èøËgê;Á^´ÿyš^?()³+�ÆÍ²ˆñ¡ÜÐË'G{Ùª8¯Ñ×15R Ö¨òCϯz®RjrC·ûž•µ­xqxw»Ÿ5ò;%ûåFˆ"íZž[õ|øô¸eeNƒo¶¸¿~ïÛ˜ðÆ�Døù³sþáÇðÆ_áÃù,"‘˜v䬙®ËÅHÞW·ÞZ‡7¡€éj�#„De©¬ñ%jµT¢ê}èû#únMÎy4ƒK3 Œ³µ#1NÄ4‘ò¤²¹Xÿ 8ëtߪ²µ$!¶ì-¦ø8YÁïj«‹î1 ¶šâf5sz¹CÝøU:à\W@š™È%;À9l°Ö’“+ uF¼""#Ó™¦‘Ad™4«ÇùR¨·Çx�µ�[]4­T¥ò|êKWŸÏ4ò¤’$3!Xô´­Êº¤4‘âHJ#1N…‹Ã[‹õN35JƒPjv•`›yLTÕ€Ñ1%ÍpH ë>tZ Ùi„EÎI%0bÔÚÆaEë0ä,Œâ˜ŒodŠ ¼§è¢Û*×Z|[¢Šñ VI�JŽd¤Á+ÍUËÅÖÍ€‘’UV+¼ó<�bUjK&RŽe xÃv˜HÓÀãG—LÓ—Ã6]³:_“��òH”IZãüü‚³ós˜&®H£aÜ�$ðÞrt¹¸¹£_wD™ˆ&]&æ ™Ö8ÉLãȽ{÷YûžáÉŽGsu=0މ$°Ýmyôø!›íS4SÀ�‘ˆ5#ƒ!˜�uHœ¬àôÈh!Óô“Ÿpzì8¹8æý/ÝáÆ�Û<¹îyøXp6²½~ÌÉIÏÉÉš“ãŽ�Nxüè1î?š1FåP¼›ƒ¾f]½\ktŽ˜"‹S‰.ÍT+¤À{P0œg<}´ƒ=Ã^ú\Å[=ÀÍ–ß™ƒ=猂ú…ªk•s¾Åþ¥8’bÝY 1T2ªœ)…b Åß(€°1@ˆöeŒEVOhT½¬ ×îÃPAÿVOÀÔz B |¯ÝKógç ãfÅ•ûßÃ[».îÖŠµí;jñ÷ÅG{«l½´½O”ðÖh“5š‰.j7½W�=‹óëUnκzK3±Qý}ïÔ®P1“�f.;Ázï9^YNVŽ“^³¼‡œÆjÝ‚Ð{º®+’iž)YlP²1¦ŒÄ‰œ„œDëà8ÁÑ‚íÎCßa:¯ü�6N¸¤rs>eìhq‘–1à}‡÷=Æ) lj8v;ÇngÉ6k6°bq7­UßC·sYd ̈Ù3Ïš-å7fî̧&Ì(㣙§�¾— ¾¼ŽåÀ:x] ŽgP_–Nò3o콸÷›/vpÌò;ÓFTmìFt,¾+:¸öïÏÌm¸ žŠÓ­žb’"+‘kõÛò^ª—<Ó¤y‘(¤Ekÿ’™Efeùãì±<—mµß"û}ºfþê’Ј¢)ÿº¶•Œ‹™ÀŽúƒTAuW˜àœ ÙP�(úÛl`Êäqb&â”™&eÓbb*ä@†˜ 1ÛRXXŸyùoœf @G'J!*Úí›ý¬�Åâ4¯Z¦8<�PC MûÍœæ©lr�2Ÿ79]Ð ˜ÜÚø�¹® Rµ`ö‰©¦™j2/Ù}€^_ËeW�rÊûùì{çβ0Œ 8O/öÌò>/®¿éq/¹$–Ç,ßW㮼.ï¿9³5Zå`GiR—˜ùóºÑï-K{­»ûù ­³´Bä òÎu™”Á¿XÏj»›y\ÌR;°L£65ºJWyÖc7Y—ªU[Éu\Mñ´ýZlRø)×Q±=BÀ¼Å{ƒwg+&]ˆkÔX©Ëqqòj’\?[[I½W]%ëõM1ó?ýãï´qõ§nÞh­o ñ“Þ˜–ð h‚W­ÿ]Î\Ž‘õZ9c Ÿ.�ëã¥Rw`—›˜¸Y2®bä‹÷ñ³%Ú¿>reCЂ¥®›˜¸�‹R(ô‹÷òSwn¶,‡¯_^ñÃç§yÇ_óÍ’ýG¿ð|òƒg¤±ÄÅ‘0M6ÏbJZr³I’€+ë{RêX`�‚aE6À,ÇîÒÐ.‹¦){·*Ô½\4š^ê’/j|VCÙ4J±«Ìƒú^JOíÛË•àpÁšçýá\«k’”èw]tÍ·F#Þ(÷­$ŠÅfuÐ%Iº‰4%œqXã1>€-HÁyƒéKq]k1}‡Y­P)É`{O·î±G�v2ELΧ²Ö[h¤N‰‚L '¾DQJÎrdÂá x#Ô.2e¨uÉrtlH»ÀvçHÑÒõ†nÇGŽõq à7 £g³³Dqdc£aL0@çó/þ±Ÿg; ¼öÆ·ùÚ°Ó>|SÛó³wnpÿøÍwùìÙ ÿ+wàë¯}�Ÿøô×BØËž,C)3›zUŸ6‹™3òby/WseÑßÅŽøÂ™Ý°áŽóü™£SœÀgoßàršø­cÎ*ßUAÉ!gþù»èœã†QH¬‚‰?|qJ0¦��Ï÷=Ÿ¾qÎ;»»ˆ(™ûæf׬%kTšHÐÌ€µs-ëà,xþð­üÓ·ï¶Q}<÷‡Y³ÿ›—W-z:X˃aäÁ0b�áãg'|ãòª­?rqÆ«W× �{m¢l%‚µL97²â¹UÏ6¦Ffk8 a�X¾¯Ç£L0{Àò¿ªÇûÖ=×ÎðŸ¿ñ}î.¢×ûþ˜OþÈŸæ£?ðGGZ0ß1&¦˜Æ‘±Ì΂wt!´HÐlJrnÅ#X—²–|H1¥Ø©”¡WÖš"ÿg Hh¢Ã˪¬úP4á�ÊÿLÃvÇ0l™J?Y«…Œ»nÅz}Œq=ÆÚ¢‘®ÑÔÈDÎZ¿d·{Âfó˜íæ »aCNSÑáµ�µVˆ.�H´Ž›7ÞÏ��þ{¼ñÖWùîë_"¥‘7¦‘¿~ÿ]~áôœOô«–%Oÿ•¨ûвhï�¾ãÁ¢¸ð¡y(Tǘ3†Ö+^/ ?À'ÎOùê£Ë¶.<žâ^Áë*dPi¢GÓÔ²~øâ”מlIÑ;GX÷‡±e»Tàÿ·j&ÂGO�y4MÜÛé}|øäˆ›}Ç·ž\󙓾|uÅ8nxôðunßyYeS¢!çIŠž¶3©Œ ÍŒK$Ͷì<ÎJ‘*ÑÖÜš´¬QbÀâ@Dk x_¢-}§Åî�+û¥Žuë,� xŸ§¡‘[³d©FüK¢é5zßHÕ¹wJ jG%ÍH¡øDUîÖ¦’·�ÚAH©fÔb÷j‹™9"-vT/DÏOÑæ·5ŸV¥_¬±ˆ·ˆô“àz"Ž‘1ŽLÓHÎ) x¾c}t‚ïƒ^®SÀ=Æ¹Ž™aÜJ0äT‚æJ€]­¿`]P€Ý)q(Iy"Æ‘8�˜¬àQ ÐId¢•B•Z× Fuë=§µƒïð. Ã02Ž»a‡õžnÕV=]¿ÂSd9S)’.Å–ª¶¹eŒ–”'r°š�Ôè}±gì¼OfAÒ\üÚ:)}e�ì¨R/•bJR"ѳf d‰Ä4‘ã„wBè§ÇkN�=�]ÑÙÛÍ5O®±Û]³·ÅO\m¶\oÆqàúêš)nèv‰M ëxðø’íöŠa{­×¼òʇyåås´:åxuÂõå}Þ|óDÉ4×­¹óüóX—� NMfŒ#ãõ†Íå%�ï>à�·Þaºž8YÝg·Ý²Ûnx|½a»›¸÷ð!ÑE®¶—„Þ6I‡ö­7‚7Â:$Ö~dåzgØä+ÆÝ=dzÈ­ÞÇû_¹Í‹û·_|‘8^puéÉiàòÑ=Ž�N8>>áå—^áå—^᛿ÿ-¾ºù*’Á´¬mcCn2¤ Ò(þ�wZl×Ç”“ÊM§"ù\lq³ ÚZfƶsÞŸŸ¤ë8©nb³—€Y<—ÿ®~àüMYúÓ%KØõ‹ºR4X+1/$©D—±šX\k´ÄHJ“fE°1ªM]üÏ$fÎT7®a/–±ÌpÌ¡|Ð’h¤€1‹W}?«ÐÖŽù!íØõݲŞ…´c-~½w4™±�}ŒiqY@•UµFkRxoé;¯þµ³Å¶‰84K)øRKÀ£�b®þ sS¬ÏZðÎ’½ž(1g[:£‘|¾ƒU°­G�á(ÀÊkq`1㮸>`ûœÃæŒ�ÝãºǦnbÑ 6µû�2!`×+ìʃ· 3ì4*A4 ÞQðh¶Gè;B·×alG&Òn"lsHydŠ#Áj99ƒâ(PÏ-x™GLí�½NÝï2ÚŒm�)5ªq¿ÃÛË¡»<Ÿ©@[ë¨Ãì` í]ØüYÊ -ÿƒKzš�š?4røƒ:œ«¹PŒèg:ÞÕ×/Ÿ©†Ììí5¦.—´#Ù¿»ÅáÚÄ]Ü¢4R ·§Y¼oúÓ©ÈÔ 2 …Qˠ݃ H’mýÑ�zòð½l¡ý%¶~VÃ"ó¢x»•ˆ¢(ýLzͦf D0“`¢4vTå ð©Åz‚J(d /¦ŒLBž„<)³š£S‘ŠÙÅ¢ ¦H •¿II!•â0I¡jš‰î«of›šÞ9/¤RæÉü %õUrSÒšYÞ�Pºu)ý³'ù³¤ˆ�úZõ&g�ù ?Û¢[ÇðþøžÏ]ˆ¯Ò·MÆ�ƒùû b¯f*ÔM÷�7kˆH¹Ú9÷É‚–ðY§zÿÂ<çñhö�ß>3ÅX/†¿9¸æÃV’Å_�,usšçy¹ö6·–‹–¡eñ,Ö³åÒÕÚ¯|G#˜Ú©]]�ÉË/ÈÓ_<\m¡ýIÅ7›jþ|ï µ½tM«YQÚíe“­Ç)Yû?›¯g�ù·‚Âuý(Yò¼¼-–×9¢p^3gºd4–F’êŸ#óõˆÔû˜É§¶ÕùžÅ`Å’÷ 4"@£“ Rm¬B$ÔÈLÕd-º¹N#¬©8¨Ì$B³½ !ÐöÇ}Ó´Ž;Õå5Z€8kúê?øÒ¼õPA‡OóÊJ‰€GÓÄEíúïíž_­ZÿWB >ÖÎ5Ràá8q£ ­.À«Wלzߊ ë?�–ï[´%*_>ѯovĜۿ�ß¹Ú´L„à,/íEWþñçôX_¸¼äw®K!Æ‹ÿÅðI$.¢ ÔbµÆÚF(×È~)(¬XiaR@q)à}- Ø.Ìk[š KSÁt ¸9F2 Pg�P“¦½Vˆåš¡`Š S7ÍÈ7j—ƒç¿ü±üƜٳœÅ‘©s­íýe^9 Œ–ÚB°˜,dï`L8cqÆa\ë[À‚É—­f8‹éô±VU³�è°SG·rÈØ‘w#Ä„C#™�Ó(P¬jýª´Ú ª,vªYË?š}ŒËà2â³ÊtЯ ® ë•e”Óè¬V–£µ/MoØ��õÐa\ưƒ�‡LN¦i`[kù¥Ÿý%þίü]Þ¼û_^ ;>Õ­0Ƙ¸Ñwllj=>æ·®¯Ùì6¼öú«¼ò¡�íõSÝúj­€*%TÉ‚½{C@Ú÷–Òu |õ_àî½× Æð‡ú5®�p©Zå/¬VgùÞõ–'Sä¢ ü¡›üƽ‡\°ñç^¸Ã÷¯· (Ý¥Ìva+ÜÛ�üÊ›ïÒ;Ë ë5÷wsÍ‚Ÿ¸}ƒ'SlrCg!pÑ…F lbâK�ÑQf™£�Ÿ_õ3z{Õññ³ÓVŒ8Ë,]T¿óP‹ [cÖ4@ÔÞŸòõGs�—Ž×¼úäº5ãýaÜö‡”Šü‘wl™ç]àrœ–]0ÏÝE�•s¼|zÌߺ—/\Î×mŒá•–O|òOÑõÇ èY0 €$XðA#ßBðï4¾’¢ûžÖQ�\4ī޳)d§¤LŒ¹€1¹Dj»&;¢À‚ÎÈ8�º|”‰¶„�Vr1×=›9J-gM‰ßíFÄlÈÆÛ;"yB 1 yd¯™¦-) J€f×TŸ­F>�Ðì™÷=÷ƒœŸ€ï|ï_ððÑ÷HÀÿýä1_vüù“s û™‡õ$¼)î–\’0KM�Ï�s«‹q<Çε1�™I‚ú¨Y;¡€”ä×=¶ãÕB2ðþã�ÍÆ7/¯[†‹�Vc`e-8ZñêÕ†TŽ÷³/ÜáóoßcW¾?faÁ‹ðí« ßzr�3†÷ÆM¾\¤«¾ýí/ò¾>޳kÄ‚5�B Þ9 É(˜šÎi y[Ÿ46Þ ^ ¿z¯òV9'¦)âœf’¨Ž}‰ìN5"]ûÙVpÝ$ª$‹+Y—ÖÚ&³a¬F×£„€¾jAËn/ó©{J. ¦`Œ%7à¿Ú…¹d(è6orÆ"½Ÿ•¬7¥@5ès3[5û¡îíÆ*m:x¦Ñbœ�ƉaÜ�ò@Î#1O¤œp]`%Qk¾U «™ô’gÛ¢–u˜Ù.WØ¡N‹*[ßæ?¥^CÍxÅ$½WSí^‹wº“-䬿¥ìPY¯ÍZ�“:/µÍsBîHsjoÄÉ6'Tö©’-eÜé“� 6kF£%•¬Ì„XpRmž"�X%[¥dçJ^]¶¶ü AB"å"£bÜa‰ˆ�#ø¢fМÅ�u–,™aŠÄ$ŒãÈ.ALŽA2Ó“ˆ{û1O®G†ë+ÆÝ#à�¥“øtÎÉqäø8óöÛOxûíkŒµôýÄú(p|²æä¬ãìÆ ×Y¢†a`ûø’>põà’ëÝ5[?â%üšþü×;VcG¢%§ç§˜.'KŒž.±îNðN"gGÇk°\“§#ׯ2Öu¼ðÂ)/¾ÿœ;·WœŸ9Æ! ©c½ò„ ×ÖdŽÖ=7ožsvvÌzÕBÏ�·ˆQ¸ºÞbÍã8’’fŒ·À’"Ÿå½›ënÂ&¥HŠüjŠ«7´5rÿÍþ¿«¾ †T aEIýA›$ ¿XâuÿoZµÓ*jhŒàÞ+¡×uÔ %*~‘˜V(BH12ÑZã®äê#Öy’+#JìäEv~ hZ`´3N©7Û¨L­'° Zû˜y­¨m0–‹æ=P,0êy7_f�±Ô€WóÔqªU;w—@¡©ëJó»Ñ@@k !xúUG<]p ™#&G:“5ˆ°ÊÇ:0ÞèÓ™VÞ?½bKITf0‘!"¦Ljé3C0Zº.8£‘HÁ`;‹é ÈÖðÿ±ö®±’e×}ßoí½Ï©ªûê¾Ý=ÓÃ!‡Crø)Êe�z˜–ɲÉ�í$¶v>$ßò%€‘¯ùœ�A�8¶‚�‘@@� VdI6aQÖ[¢%Z%ŠÃyvO?îíî{ëVÕ9û‘kí}NÝž±ãÄÔ­ºU§ÎcŸµ×^ë¿Öú/é=n!ø…@­eDP»%h…™é0:�ô:1=å)ÞCÔu/HÒ{èœ'ô^×1z<ÔWCzœeGÉÂÐ{bR¿~ èÚ&ižy"ô0§¥°Ÿ�$³ÉB¾*…ÍóÙ»ë³W�A©)6¹ëïgû�|í÷rM¢êNu"´ *“H^?�¹SQàšàη(ø‹}¥1Ûn6oNÏ sâ(´DV˜œ@¦="•&¨,ý½$}mß墉ݛV,jgeCÞµ™V#`Ê�\·:ZyÁs#WǶ:çÍ-ö¼V©Ù¾™©ªÁzÈX`—½’‡Åš‹”Š+”`Óßh‡ÔÎÈbY ÎškÆ‚ØçŠß‹¬ebvDã"bCZ“>£eN¤\ˆõ™1kSœd�Ί1Mä)3£ŽD†Z†Q� ø¤IfÉ”•&¨V Ô…þ= IDAT´À€‚|͸¬«W›w6ò3ã”Y`í9¾~Jë<Þ~3ÈæwyO±ï/�ú•5Þb¦”Ù?n]š¬ØŸ–IÞÎa_ÝÌùoëör­b òz× ‡føÙqÊì8³=·±¨ÇÓëw`Ñùù7vÆz>Ó*o_èý®ùäóñng³.Og¡×5~ss¢s5s]#}ð㺎š]GÉûQþò¯Þëõ% þ¯6ÅL§·±žª jó¸ú» LûÚ×#ÆWÊÄYX•_a2¸ ŒËMþP�Þv2õî¨20¯žÉ ®4"¥�€µ| òiƶÍi»�®j“¨vLp•~B¹« u¦wÝìé�kyê9bóÆ>¯ÙçMIg¬:!3­l2�‹­Ÿ9¡Q¯÷ïÿò·ÚXÿôéT-0 €òlƒêÅ!¥FñS€¯?½às7¦æÂ TL¿íhjäXJáÀú ”RøæÅšO�5`ÿ«gOùØÑ·­šàFöÄðö¢çö¢§o¯7|hµà«DøêùSn÷=¯®ÈÀß}ï½ö»ÿòo~ž« ë`�šy_,;Lœ®µ-é¥V“Ô˜¸h HŒê§Ì ã÷™*%aºÚdÙÄCÜV�´¾**FãîôU¯ïÿ ˜æKM‹Ù«J{?K¦>ÞÏ>ÁtМûWö¶*29/©”nAkmÅyµ¥½Cˆ×Ü|¥ra*ÉËI×a/\ðšé„¤RÌ"½àJ‡Œ¶ŒÉl…¢Í¡1¥à- 9`t ׯwºÆV1&¢1_±±—L |úúú^ð¡|¦ë`±pd=»1±‹™n€>:ÜÕH,iPzBPýºž¿úþÿðçÿ�Ÿ<â×l)ÜxzÁÓaäãLJ|ÇÉÏ‚ð{ÈúÃoþ>¯~äSívÕDƒlɪ£*µÁÌ& Úßvçl½këNý¿î?ü6ô'¿…?}xÂk]Ï÷ß9Å¿öè€WŸ¿yÌ?z÷�бÎvC-äaå¿öðŒ˜ wWK–N—ù‹Ë_8½Á?¾§¿ráµ£Cã ëüËæ÷",¼ãí« o_mÎñyËŒ®‡?÷âm^__5*Ÿ¹¤œíÆ8�«”´ðÑö)5Àõ$N¯ˆšKáíõ~Öv¥nY×o­ð"¼z4q¶ë8ì®g“çzÂÿ¼ztÀ½’ø;o~›gó¦Ç'wùÔg~œã“±¾Ú± t úå‹EÀã–õzI¹ü½×€€w®ñ˜K)­�ȘUîÆ˜(Wè®ïp6÷SŒ·XAÙ:–Ë…R™xþ³fäÆq‡Pð^ÁœR¦„'B×õê“å­Úå1‘Ë@ŠÏX¯7dY“åÂpÌDJjå‘€÷™ÒAsc4Ê£¢Ô5ÎJîȾñˆ¼ŽŽùÜwüÏÞàõ×�qÜð§ÃŽÿþüãæ)·f}ÓæA õ•Ã9°ÿáƒï̲ÿw)ïÉ×cl”@µb¥ÊÒÇŽxçjÛªƒ6÷®û¿L‰ízÚ7À>Ñ€Û ËO‡±õøðÁŠ“.´€Üõ¤€_¾÷�\ ãaÓæÇ�å‚--@áDøâÑw»Ž÷Æ‘³³·xrþˆÐ­´•¢ t�g±Xà] ,4(à�Þã1*­OíÕQ°µRÄ“Ymþê肾_0Ž#qܯ¿&õœÌïjH‘éÊ…”'}ð�Šã00ŒÞwtýg­zÃÅæD(µ—]1úJÃ˴ɯUš'ãöމÖP>© ™S1ßµ1Kõ·L·CëUà,P翨úX…E‚H"å�\F àdaLøÓùoYÕâ¼SV“Ϲ6 V�¾ÒŠèg³€I­(È5© rÖñ�YP&˜¬ý±‚3z�ŽÞ{$Eܬ—\މ\2Áy¼x øŽÁrÑê�š!3ƑͰ#�ƒö$ò}· ïz‚Sªà®(�¯m""Ù©a&)#ã@q €æ¬ý�\MæÓÆçÉ*�Wú,•§=§HŠƒ5U¿" k$ ”qÇÆyBñÄ´bŒŒ£6$ö¡Ð/;º®£8ÈdF :OéVÈed›3�Ÿ&Öë+"½÷àïm¯Þ%tç„nÅz3p±Öލ>·oV7¸y°âø…Û¬Ž–j¿o6\õKÊ6òpù�m7p°:áôô^¸s‡7N¸Ø<ær{N;rx±“¦aÁÑÑ)'7î(ȸa¼¼«UåÏY:çëcŽu~P’eÝÿÄì­zJŒZJƒ¡ù‘9%²‹Ö#Eu[J0”DNã¸cØm(%áDVm*N«§4¡$¶jÚzµ‘qmÈÞtŒÍ{õÏ�K§eÕÌ~�°‡%"3¬¤íìÚû¹ï4ù9ò¾aýX�J¯:Ç1J[¸fçmA A·öœT=áèúÀr¹`µèYöJ!Ž% �¤D­Àn~p¸^ûy¸˜INç>’­ú›†µfcúˆ¥0ÄÌà`tBŠž’{¤tV¡è,) Äe[ï,¡Ø¤ tËžåÁJ)Þòħà|Àyõ©Š«%^¢û£èk'à<Î'Å ¼ö9Ñä¯UÏÞx²õ]pÐ/]§•y�ë´Ÿ‡Ñ9¶J»¤8üŒJš×1¿ñÍ-³ïËþ�wu�®Bàf^øþcîÔ´·Ú©Žš Å²î„Æw;(&'�tþ*Ö;¯ÙNÛ2™¹�õ¢4z_ù)eüSPP5�êÈ2¦½Á©*¨Þ{û`~³r¬2ÿ|¾?êBjçó~×-ÐÒÖt{¯Ô+&oû»×yêf4û˜s_2- u[ô�EÞ+¥NU†&Zïs•6=VÊJqÊ[Ûh³*üìœS†Êå_ v¢À:E�W¹´RˆŒf+ÈT¦^k¤d¼Ñ† ¶–×kjô4ú¥v ± „™àÕ2ò6çš.f[ ó~uòhP “kóö(Ü;ßð _½À¡süè�ä²·,ò`»ãVß,[`H‰]Ê-0 °€)ˆðÄ2fkuÁULüñÅ%ßsz£ «ö~[+vI/žtúý6%~ãÑ9?üâív�÷¶;nô'vn;mmQ�QAϽ‹«óÎlïÁ9zçXX�® žÞ !¦/Lj,Øî„ÝèÈűÙƘm$0�¨_,ù÷~üoð¿þ_?ÃÕvÍ?[_ò©®ç¦xJÖ&¾öð�cï¹H‰·î¿ÎÓ«KŽMVç=Œ2ˆim(UÿÕ5ϰvWkpÖtÃvsÁoÿî?¦”ÂçK^ë4·‰‘X„`ýzçøå{yaÙ³p �Wj‘záW1µÿov�­–¼¹ÞPPpü«Ož6g-ˆðË÷µ�ÂK«Kï…ʇVK¾ûÖ ~á�÷(` * Þi¯'€ßx|Î�r»/ä_xÇgOŽÛyü™Óþàɳڞ‚VDÕæ¬·Œæ¥nûÙǼsµÙ£T εÀ@*e/(4¾÷¥÷ÍŽÕïKïö‚ÿ ïøäÉÿÓ£‡üê¬JÀûŽ�¾úýÜýÐw�ÝvTG¯ï瑲 ó‡�ÓÜI!¸Ôf¼sÊã,U\Å‹'…isI.n)qÖ×Ëgµý…l™ûÊ í�ÐyOzBÊ•ŽÒEµ‘lÉ”¬Àd¶@»š BR²éúLÊz9�Œã–D"•h½v!RJDdD$â$á¼:îÞ 9Y¶ïÌV2à&Í‘¸ÒÔjN™Ó›/søùŸâõ×�'OÞáªd~æü1ÿîÑ ßµX’f͈{ïXˆÛ Œ×2(æAa "xnõg•?:h•5÷¯¶{½#ªü Ú³àÙ©á¨~ñ6¿úðl�ΨsÂ`SàÝÍ–w®ÔFY8Ç6¥Við¹›Ç¼½žäÿ£‡-ˆ°�i¯bÌ™úÞ#þÊíÛü�÷ÕžxóÍßæSŸú1•%‘ŽVt¡Gðx „ÐŽ”FbŠ”É9ó¨<èÖ$Yý�¥¹¤C Zì¨]ì¥&ˆTú2.TÞE�s½ÅÞ5{ÔwB<]·T*¡º0X0Ö t.ªƒÅ‰îSKæp¥&l¨\Š 1‹6Ô͹ž'Õ¨µ„ó.#Riiòžß¨¥EAz)ˆ9ôZù� #ÐRz':wKŠ-0†(Oy‰qØ�c›�ZY‘âHŒ‘”(] X¶¾]�(M‹s½Ùµ®­Gõ|5I ÃÚr#’4¯vk»È%S�Úä4ɯöç)Î#¡Ã[SN©‘çØ;’†q´„¶€ÕmPè4È€3ÿ#•QRªÄœpÉÁ(8—§ëŸ˜O,9“Rd’õ8�:ÞY2Aµÿ³õ²ÀüÅ„Ìv§àÛÎD+Næh±äðèˆÕrEß/ÈE{ cÔõ#%bÈ)²ÛeÆMÂ¥Ÿ{Xè|xzÕ±5tdG*B,B!�$dáY]-¹™Á/Y¯I,ÐÉÀîêˆãÓ6Wk$d²Œž,¹û¡Û§À&­¹$– ­Ðt‚sKœ¬8:¹Ãñ�»†O,yðÖ–gã–ív@ܾó"Ç –KâvÃvsÆ6&<¹ÉýGKÎÎ.OJŽa€‡�®X­rv~¡ý"\a±pô½#¥CÖë%ËÞ³ñf«‹×ÀQ×á»Ä1Œ#iŒ­‰µÚ‚–ßôþ”°hÿîá" ›¨Z °—È,Ó�®YÌ“])f[Î!¹öÚŒOs,šìËT!³Ð9W,I1‹Ú„cÊÊv1Âu'BGvÚ»¯&ŽhsábI>BÎÞìb5|¯C©ÕZ©A×ZòÜœ"»ŽùgÓN×YöÞið´Ž›4™¾¿î„L8EÕ5û£ZšoxZE,F(V½«M™­A°=i dI”¢×©½ý¬É:µBÀU² ]j²&2!š ì$R*Èد´k¬ }Àõ׉ú}ÞF%›Ock‰÷ž®SÚ4’®Ù*—2�X¡8”ÔkBCª£´¬Ž’¼V™$­æv¢Uw‚V;0& jX¢t­òä à�qpŒQZÂF©÷®@h%ÚÀ™'?WG[õ£fs�<-ææ Ùq“×&LÂqíÙ@›ì¬k;—¹lÊìY'ºEƒ« Í'jÓ30©.\ÿ¼}9Ϫ­R\ÿáÞ¿ßÿu2Èl�ÑóÅi)ŲýK™€à .VãÕÆÂÀÿ2Òxù¥òñ'75 6P½‚ìM)‰LÔÞ£³¢Ãj¼öžâuvU7;¤*0&â˜z©µ‡OÍÌ'E ` Á‡ä�ì5P`TA%: d8$;å×rýb��’%-1N |•¬àÅU8nvO‹Æ’Ù•ÂX2CIŒd¢Ë ºº¸+mеqNæÄ$ Ę!ZÓ!}ZE®€ÿ$e5Ëo/�µ)ji �}^êàý€™ØÌ)„æÿO��*ðû+›"³ÿêvm�d>®ù9{�By.óhRòÓ÷ {ûg–ÙgÐg2Æ®_sÝ´BÛ5l° hs¶.H2ÓÏíΦhÕ%|å2ûá>£à®N³ZacA�âZÀsXë¢VÁ4šz�N²fÉM ¶n(Ef%Žbã> ѨfÍ�e ´Å<›iTicW‡n#*�os«923#¨j1z‚¢ËÒTŽ‹n£�”˜Ó2H/ZšÙOU˜Ö¥*-n¶…]Õâ©‘ ›f§èæÉþWPÄõYAv¦ïKNdÉd7ÝåùÄiÕŸ–ø½.+¿oЧ7û1šAá²Z³foŠ_ h¶¢/PÄšGŠUDÖÍót ´ê@ç­øB)…>ö¬’rqöaIïWF:�–ÛŠàûŽ«�°¾rìv™Þ{v"´'QÍT�V‡Çüä�ý5þÏ_øÄùÙgOøë7oñš¿õøœ¥÷üÅ›7ù¹Ç�)¥ðõo}�?óù/Qm�ÜV‚lŽ×îb vÖ5¶ªŠQ!Ø–Y ¿ñ;?ÏnØðrèøÁå9\rè<ÿò©fð¿vtÀ'OŽøÕglsf·ÙñÓy‰oÏñ7×WtÎDð"|ûòŠo<»ä x^9XñÖÕ†÷¬éé�¼x›7×W-CÿÐ{:7…Ìφ�_yðAix.ÇØ(ƒ>srÄ:FÞ¾Ò@ߋ˞�´ž)·qæÐ¯Úw‡Öж‚µ çxíä°eRƒ)·±­%2ëYµO€®£w–}ãX¥ª�PŠ´Y§)r)ÿÖ‚/,zºUÏñæ<ž�Ï7O_áµOý}¢\è…€”ï î„ÞŸÒûSÉ/ª_Šeg#‘dŽƒŽEÛǸe›®ØŒl†K„dEÅ9oµ�ˆr«êp¾g:zì˜ê3hµn@R §‘]ÉDgü¿®_Mo= £­c𱂇¤mMRça¤äHf¤õi¥�s:Õ3�êN×ÖU 08¯} R²@È0"Îñ‰×~�³Ç¯óæ›_%çÄ?º|ÆŸ;þÒáI»CÊ ­ž[•æçÖµ7úŽœ'¹Ì¥ðäZåA Ï�r£ô9�£.pÏh€ Z±2¯\ø•�UµÙšTƒh+ï¹³ì§ÚÀ—^¼Í/ߨäÿl7ìÉÿŸØy,�ãtÑqo³ã2Fœ_zá¿þŒ'ãÈŸ]Љ0–½{_ãÓŸýQDà±?å¼)–=¤Å`×6œ‚õã&‡uïÈ-J^ i@ä<+½ê�i äÆ>È6š¡R¦ÚÕ:ÕXÑc¾_©y�†7¯J»é:]\¶,�JC™t· Þa™†Bè¨øk£Üi0hÆšÛÄ@ãèw³lîJ[”�îËyO(™ZúY³oÕˆP`4Ï '/ôÈW©„æe[˜>[{ª±(®Ê™�gÆÊë¥UþÕûªSEå,Y>gm°.¥�fÜÅ¥PÍLqÚ¬¯­eÍ@k£†H@HMöÿ—þF»—?e4B5(P��Ú'`,…ûWÛFÛS~H}TÊ * –½KáO/Ö|æä¨mûöfËÇü _9XÑÍJnõ·ú޼qyÅGZõÀ¯><ãÓ'G-ðl9˜3¾üìï Â|þÕ[üå/¾FŠój˜†ô à«ls5¸–e²_jõH•Y»×b@¸þS¦÷”f š˜ÏæÅD‰ˆ ÔÀ‚Í¥jR´Ý§:ŸeödÒóuß2é²I;^›o3]šç¯i|›»m”@­šL6Ÿ÷bšÇ—èЯ²9e™âr“ÙÖk±¥÷;ÛGQ[Ô~˜'"Ím(™ÿVÔÁ*fWV½SÔ¶q–eVšËd¿V}Z�_.«ЧÃÓ9OÁ‘‘`YÊ!Ð-;|Ð}¬×…E—ØúÌ®Ú�…Ö{(·î¼ÌŸÿÒ_áËÿìç¸Ê™Ÿ9{Ä“Ý!g~òTßüÖïó¹Ïÿùv�k ®Y¶¾Ì*—öÖ0€˜æÖÇ¿üã_ãñù}Žœã?8ºA/Âqèxõð€?6à�2ß|vÉqX§ÄKËž_º÷' †�…ÖõãLJ|æø�_0º¡” /,<Ú ÿÚ“g\ÅÈAÐÀbÍN¾Ñw|ç�c~ãÑ9»¤Àæïœò{gOyh`æÅ( ðÎfÇÛW[œw=�¶;Þ0š“ÏÞ8æávÇ#aot�Þ;Öv¼1ç–ù\W¢$¸½èÙ¦Ô‡À Ëߺœ‚!5�Zo\£n‰³ó¼Þw wn¯jáÿíÉð™“#~s{Åßýö·›í‚Ï|ö'xùÃßMÊQ¹‡-#ŒÒ!Ò³\±XÓ÷‡ta…fT{[/E"šqì(2 �µacØ�[¶» ÛáŠÝ¸aŒ^ÔoIÑDN 4ÍÀóÈÚT3›'}¨ <°§$å¡wà]QV²Ù×~Dɨ«”×·ï=.| 6m‹†ê HÎIç‹‚…ê£h�e©7—Þ2¼§cUNÓ\ôÚÇ80F¥_ ÎÙ�_ IDATñâÝOsãÆ‡øÆ}™íî’o ;.óþúñMn^ë3ðârÑÀxxžZjþÿÂ;v)7Š �,[ ÌÏVÙ Úsàzß�Ú“ã£+îm·Œ&§;: ç·m~Œ¥4ùµ%~ɨ¾nôcÎÜ·`ÞÝÕ’]hŠÎ9>|°âž}ŸKákO/X'·Ÿ#ß|ÌWž=#Æ|ƒÛw>IʕʻŒ]7[/1³Ïs)¤’�®UWÉY>–hÏ)k¿ò&+E£Éö^inR.„"ˆ(/¾7:© 'N3@C(ä4’K$Ž;¶»­f–Šf´k6¸4p½V†a¿ßì‰Ji!u]+:Ÿ5q-SÒH ú¦a˰½`¶ÚD”ýÀ@£“4yQqç1FmJ[ 8OJÚûΗŒW®%ò¸#¦BñQû1xgYÇ#Ñ‹S3dEH¢4JÓ˜Bð•Ç@÷YuÉ-à‹"JIV‚ ¨ÿ‘r²5LléÖÊï•Ã^÷QãHŽQƒ2à)I3k% òI�ï<ÝÂÑuﶤ˜ÌW°¬×™>ÀœDúŒi ¥Y#ð~EG‡Þ/•� erŒŒ»�1 HÐq+û…·f±jZºn$-’ÚÙ$ÆqÃ8bMÒÎAWÈçéûV7ÑžL«~AJ#ÃÙl®ÂÀEÙB‰ÙS$ ‹cduˆy™Ê£Ÿ"•UDÌ—Kââê’³'ç<|øßrtc _DºP8¸é¸õÒŠ«õ‚‹‹‡\^^±Þ½À.ž²ì:–Ç^&¼a4 RLäq$æ5W—ÜÞ2fOöD¸ž‘¥‚÷=ãî막gÏv<¹¼âÙ¸årÙm)-)eA) ÎÎGÎÎÏîïF6Û+..ÎpŒ°<"§-^2�7ðÉÕTPÒ߉#R¯­º«_e6k±õh–Â:{¨·>ýWÿLÆxÕm^—”É›íßÑ\†æÃUw!›ÝZÊÔÜW£G³õoFÏ'¸`T˜Fã%…ìÅýšÑéf£–�SPc¾¨®JS§'_±Úø³ @�Úã¥éµŠ=T¼³píýõDÒÒTÒF¹èál\йY0tÓ »hηݟҮ¡Ìö››?á¬çE)Þ’$¢VX2Á;Oï‹®gÑ9Õ%7ºó’Š%ÿkcéÅÓ fë:‚$:èû‹Å’~µ$,;í'à”9EP%•FO,."¢Á†>xÆÎãûŽH¢d!`Lô1©­“hL)8”ñ¥w”PÈxMPJà²P²‡hò�²U(5²ÆÌT>|0¨eH�®SŠ2NœQ É\º™¿dÿ2=›³h%u8fažZ4gÖnöäðLÛÖŠiŸÍm¯mrυМî–Y5“ùêÜWÔ-Õç•™g®¯“ý¸ï4I~î®?ʵïKûû¾ç_'©ÍÔÏZñC‘ýsiã$vd†lg£�°E6iQKÃâí y·û™›çT„F½Ôp‘$ꀷó­×QªŸj�¢Lí í|ÊÔ`8ÚÆ©�£Sª‹dÇ+*ðqLÄQ³t�8“ˆ%1få �1ÚÂP•ôÄ_8�,ú¦�7pó¥)©s›rnÁmÛ`UÖc ßokV\³ìYAÆ:à¯jqºu…÷ü§Ï§,Ë÷ Tà{.]ûò6Ñ'�y?S�kYý\Wð×÷yí³¹¾.3y¸þ›½cLˬÌ.eÚ|v.ÿŠy¦¶d]g {� XMÇ�^Ú¹Ìæÿt mµzŸ1˜�w½àL00lŽ®›.içWõ )êzÌß™1âkÓ¿º8ïEËgû· ‰©ôlAf€¥�j©s¦–äé'nRÑM˜§ýÕÄißÐðiÔpϳDÙÿÎM¯Þ‹ò{G×¹‰6¯Év¥3¡õA)v¢®6H² ¤6÷¬§šC”BŽÉ2®ì:ízr‰6:S5@17È‘k^¤~fx¢Tš’Z¯ ß ¦ÿìè®DrQjÌXt¸köCmT¤‡ÍÉbŽUɪ#ÅM:Æ€Z<¾ëŒÿÔ W™²"�ó Îdtüê·ð'ï©Ãÿ‰å’wSæ¿ öD¹€6:œ@³ A3 {ï82€óÉ0r#=ÐíƒH«¨�$¸Œa H<FþèÙ%ßçÔN£ðtŒm&|ñöM‚(°0æÂ'Ž5 ±Ë™MLüÇÛqþ³Ÿú»A�Œ©H±fïL‰úÕ,¨K¼41m‹Ùtòu¬U•Ú©M(fr^ö•ÚdHL6J‘^ƒ³õ;ÓR$ëÉ´ãÌžm"N²šû:aÒís�ŽV%P5þ~ÛÿoúUûfZ\÷޶¿u¦t¾L')ÖØ¬8¥êݽ˙�WÍ8ÁÒw°è¿ÝƒºN¥lœÂ  fôVû¥ÚG šÛ¬m­È§4{Í(  À�tO +¹†±°\9–+a½`;ªsVdßlác¯~Ž/|Ï9¿û{¿ ÀÏž=æï¼üa^]-yûòŠO¯VüñfÃzý”‡ÞâÎ��ì-/SÏæª²L"[77½RÇæþƒ×ùæ·þ|G·då=¸#¿xï§}Ç‹ËçCäO/¯~òC/ò§—ëux�w-0ðh»ãÙ0Zæ”®v_1®ÿï¼yLÌ¥qýüè€Wøò{�Ꟍ#Þ‰Ñ~À—ß{Ä�2Ç] ˆð®eFŸöŸ<>ä·?t�õð€gcl™Ùo­7ìò|Ößv"|ø`Å·×W ÖAõÏÞ>åΟ6:1Ê4ýýEŒ\\Ö5AÇó‰ºw=O†±�µ‡ÁœÛ|¯W ü Ïk7Žù¯ï½ÛúOœž¾Âàort|‹ÒYð.hCPQj�àaI‚óJeJã“j�[2âÜ�9ãŽÝ°ájsÉf³f»½b·Û2Ž¥„�¾s¯AS0BG)Æ�qA6h°@ç4KÜ;Æq •-…ز\¡šGö¬Õ1U’ÕíBÏryr œ€…ܲ5ŽÉG!¥)�€U":GpgE�Ò‚#Ϊ“Æa§T£Rz¤¤v›wÊ_î\ ?z�ïýÞŸ?úÆ?åìì-Þ‰#ïéûÆ-æ+h ˜‹Ù‚ù‡ÁÓ;ÇùLNNû®�ñÀ^P&š*/ÂQödì³7Ž[Ÿ€M®A=^¥¼‚g=ÆV¹ðù›'üá“gme{i¹àé›Ü>F.ftE1òÛ6÷^=\ñx7¶}}÷é N?á…¯ÅÕ;oý>§§%Ç‘1%6qè,ËZU¾­ÀX)m’6”n�õÿjïvÞ±è”Oº>ÐõJ1£Ms­ÒÀ’ KIíi9G훑v”n7¶æÆ"ŽR”o_—ëJõ��²Ñ,ù\)ß4�Q0Ä\(I¤²#Ç�1 »aËvX+})%!X/*O1[½€RfUû¼Îõ,z%�J(-pm9€ ÙÎFÕ”r2ZŸº>OÕZ¤¾±ß)µF.Jtã¨Õ1cVÀÞJÕ$A«’Óh÷Ïøúí®Vj±~-3'âhã–-I/M‘œ„è ]è軎à=«åJó+œú1Fåd/…#^6ˆ\i”Ùm/¸ººÔmræ`yÄxpÂbyÄr©¬»11Æ-©Œˆ+kXºŒ­O(…È+‡íV¯Â>-ÈißµíÏv·}Ûÿן^ðòjÉ û~=F¼8íð7úŽ/ÝP.ÊkøÝ§J×ðîfKç\«øÖåšÛ�´ ‚Cøæ°ã�7 X¾r爿ø=/³Ý�ˆ`ü’–)ê´(ºIò| W=›±‰ÕÒmf†¾å5KßA5$ëÃö57~Ëì@Íñð&°ÅꊲhÅ\Êû;Ô(¯6vŽ®´*•½ªI`ª‡,TpbÿgcpýËç×t˜È¾ŒÏu«TÍeò+8k©RÒ<ÛFÌÞ)0}¢gnÕ:Vã¯ûw Π¼t�à Ñ+³fßU7f1»•Éf5»§d­ö(’µ ’"ÊIÜSÀ .ü¢§¸�ëÙ¥L·‰„º¾à|¦H|>eàÏ|×svöß~ãk¼Gþ«{ïðß¾ö�‡�Ÿ¸y³ÉðoüKîÜþH»ýæC4{¢™¸–(RÊ\8˜Þ¸Ú<ã÷þàËüÐê�XðñÃßq㘟ç=R)\¥ÌÇŽ87¾þÞ ïl¶Ä’¹ÙwÂ>½ —ÂIøäñ!¿ÿä‚‹1â~üCwùýóg¼iAƒ]Ê{tbo_myûjÃÂ9î,<Þ -cÿûnŸòh»kÙÍ/.zzI™·¯¶{fæo=Ö&ɧ}G*¥em¿´Zðу~ӾϨžšÿöwŸ7‰v"<šõ,xaÑï´Ÿ>9jÁ €Ë˜˜SÍ醮?VÞ·þÿ&�»«%¥÷üçß~�ó–!.|úÓ?Âwá/Ï„Òa*Xï¤z«„K”²ñÕV� T@ö»5›Íšõú’ÍvðÛSB$|§�¹ƒÌ²¥Õ©2™’öëR'<7Þ{Oè)FbÚª}dÍ‹éÐ þŠƒ<ªµ|Ç¢_áÃ!>“r$¥�œ=);ܘ¢ ¢ù0X-d¥*ª³Qü”ek6@ŒêO¤˜ôx¡'t=]·@³%…–|á{þ*ßüæ¯ðÆ›¿ÇÓœø{Oó·ONye¹l@>À±ÑbÕ9pëkrRƒG!p•"µ(å¤ 8¤õ€çUt x³k•ÍíEÏÒ9Þ±À˜>s|ÈïžM}8ÞºÚP3ö�&ßKï¹Ùwܷߊ?þÒþɽ‡Íò^z�wSÕŸ\¬ÉE«n†À“9;{‹õåc\éÉäL)£Ò}{¯Á£Ö¸Úz[Ô•2{­Æ®ÀT)5M4 ©±Y„äÔÖÖFòÀzBPù ¡k‰$u˜ú·X†mI”2’Ë@))fve7ÙÝâH±ž�ÑÅ¥¢}6Ò–’w YêT¬,I¶>$#PŸewŒiC̃V@–÷€<ÝQ­F¯Å±µA¨w‚[thÏ�A%_…ú´ÈYÔº-úÔùPý?õIcÔyÔª) <Ô@\&¦‘”¢‚ecDØáÜ@ð½õ1­°-¥ÙK D·ª¥’]{¯þŒ‚b‚åþQl ©^)%*ó@Ñ þà}è&úÑ\Ø¡•1R¾>ád HÄI¤_ øŽíUd»Ù2D�mÑÊ‚àÉÅ)±d¼wVm¢œöµ?ÆPŒÏÞ(;¼ëñ}@JDr$…Dô ¥7ÓàVa³ÛÁÓ'ŒãÈv·åøè�ã£V+¥Kê]ö¤âY¡¸@— ¹8V‡¬܇Â8j_£ÕRX-‹E¦ï%¯‰qdÜ=ãþ;ïà8åî‹™ãÕ- ‘Ç�¥OÜ8ôœžôì.°år}F·XÒ…%�_Ò,ÌÎu ãÏv<|o˃÷vtá„ãã'qÈ\m"ë«HŽ#ïÞ?c ·N�X�¬pÝÏ a·äüñ†.œ[A©®A)'¼!ô,�¸yr‹ÍzÍÙöÛí@Nç<>tJå¼ze%“ŠU�zãQ7{Z¨øC™9¬3°Ì€íVî]•íô¾Uá7»rÚ´À„q2³ó+,6�g¿´J  Òëz\¯ç50@M^À*ݤ顚àVÏIæ9H.írjE‚³€¬8G]µ z ³§qŽýFm÷Zõ<ÌÐŽ9Ç^æxL§ H�Z"Ü*f •ÞÒð¬ÒnË>àPf÷UìUíã<±4¿,Ö$ݶqSO$ï{BðZi<£#,eJ cVFô„ÑMrægè0)Ýœ ñÞrµ #0BIHI³+0öR^ �ÓDÉØrÌDëI %!ŰæˆdýÍ”e‰�âlX§ñk‚â‚ o­ÓÀªÊ×€J0ªøæ;›Ï;! ý±Ë(fx™ØÐ£–ÁjŽ&Ì{‘¢&1úœ;Ñó @­H¨¿Û ̲mQš†&0uÖR�bž{N§~?{u³ M€}7ük�ézî×®�òþ›ÊüÕMǬã1㊥kL�eäËÔd¸fà®O­¨ŠAŠWz&›ÄÊ͘õާbåùXÉ¿EŠjBUDy±²m[Ç®LÕ%±h˜¤u™5IV:!»Å©‡LŒ…œ¤‡9 9*oî�*5m&ÔŒÉÒ—*NóÁl‡9!å Ô€@½~[ ržz Ä¢ün Fë+P+´¼W¬y±î#ÏÎe/óß^³)Åç«êçÌÞÏiŦ˜~·ÿ~zmòUf Tý´�—.×%õÚyÿ+euö›:Ü@=?Wl1`vožÛKSÀ{å`ó¹ß>xŸ=Tû`eU5ˆ2}>�$ï}··‹i}î(¡ìÝû¤}>åÔE¯^Ƶ@@Sfú‹ºÀÖ³›SÖ×­düˆ�ó¾JºVŠ·wµs]R5¶Ì‚*#)Í2Ì qö;¸=yªNFiƽŒŽÜî‹•÷u�£ë4ÐGg¯Ë¾c¹èé*Ÿ° É8MS̤”­¢GK¾BçqÁiF¼•&ç’Ù »!·ê©BRSCœQ©qTK6ÕH���ö¹åQ/ Á32Zƹ¨sḭ̂¬Æ_™­™B!´ ¥•ï¹¥¤f¬¤ÎY£3>^W%€GRŒ:)á‚×J Lgˆ$­‰|¨MYÑÛ“½ðs¿ñGÎñ#'Or6cäp(XùÉðmFV™#ÂÊO”AߺXói«(h¶ã­Y‚ÏœïÍûVI0äÌÛë Ÿ8>¤·ãýʃÇ|ï­›Û¹xÙoäýÚÑ!³s9nö=ÿ»Ñ°ü'áÓÚ_¢äF/%^¨ÔÓD¤]�$mú,Šd#’÷ *iv…MÄŒÊóÜP­ÿ´ŸÍ á¹Íc€� ¤6Ò5ûIѪ¬I{T>A >‹0•Öˉ™½\âª$f;ßLrS,׫˜ëãÙog2;7žÔ¯[O7�Ó^P¡4²§ö´ŠÃ’lg£zæ ÑÖÎT5Œ]K+Ñ–z\;§2%.ä¨M"IªÏ’ËÚ¯´C{#ÉREì:d¹Dü’âW°ÙQ¤B"fË™a- ÀTÀ.8¾ôCÿ!OŸ>äüÉ{<G~áþC~øÖM>ßþ‡û÷É¥ðæ[_ç{¿ç'fkÆì™eZ’Ú¸O÷bþ.çÈoõ㎅_\h5O.šÍÿòÁŠ³Ý€ø¿ß}Àq×ñ]§'ä\ø |þæ /,ùE£ ª‡<ðŽgYK±¿òðŒuŒÜZôx‘FÛóÒjÁ'��Z%ÁÊ;¾ûô„_tÞ²ýßÛn¹§ ýo]^QP`ý¥Õ‚×/¯¸·QGêK/ÞæëO/žkú[�¶�ŒuáC) D}yµäÉ8¶Ìè�®X8×Î5æÂ6íÛF4­U/õœ;'Üìö›Æž\£•ù7 ðÚÉ_¹ºägß�Àؾ?à~à?æ•�~m¬§™Ä 4-1G’‹Â¼ï-[N]V™+‡¶$ã8°¶l¶Wl6W ÃŽ8jÆkð=]XZa‡“)–Ù�R³Wë\k6.Ͷ3·% eb†-š�Õ!^›Ñ:ðAƒ·‡s¶5»Ü™ÔF±Þº. 1£œæ˜R癈‘1%"?ŽÔ <G‚6`Õ¾Ç�qŒ�¯|±XÐ/díáS)¼ëøÎÏý$GÇwøÃ?ü%Ö9ó÷Ÿžñ·Ê-NfAòšÝ/&‡sJ¬—V‹½JiºWgÖ\†œhÕA­XùØÑoØü¸»\p•Rû~ƒLÇJ¥´ @íáñt¶/'Òª :'œt�ûÆ’UJá+Î(hõŸwÒæÃÝå‚}×膶)ñã7n(Z)Ü÷ë¼øÂg´ÒÛQé œÚ[dÒ l(ÐzµYÜÓ¨«ã0°Ûl(T VÍ@Wµ® €VèªÌ;ßéZn¢¯ês²ËæKV¶ê„œGrÎ%rÒLÑvRŠjÀÖ©ÜçJ99@IFýáw~+xKbš©ôµm˜œ¯ô†ÕŸ�ˆV¹=Rm Z­#µÕ#©(í]gABkj*f½[ó$M¸I¶fµArʈYù¶d*ÅQ¶ 9RÒ¨ ¾Œ”Ô‘]G×-èú¥öðzLÕpÓýÆäWÿbðaÙz €þ½÷¯Ô’Õˆn„\”¶(;rª×�ÎÑ-LoùÇÀ0hpáÕ�Œ—>t—{ïÞãÞ»÷X_nY¯w q‡ìÖ8¿ÀùŽåª§ë;bNŒ)2 Õ'ý"ã]`1C¶d'1ª*çY- !xbIEç[M…ØÅ�¼Îlv[.ÖkŽ×Ç®V,—K¼÷Öç$1 #1gº~ÁÁrÅéÍSNnÜÐJ®í•á™—_ºÉ‡?|ÊjU‹ò%>ã½ûoòú·¯pñî‚óݹ޿<‡ãnà•—oq÷ÎMJqļáìÉš‹�p;ÜåÎÍ#“Ïn·åéÅÈý¼ñÆ9}·åÖ-O–äXxölͳõ–a»e³Mœ?Ys÷…Û®¸Z_°Ýíˆ>±+=%En´äËÝ6“ÓH‰™´ƒÎ÷Ü8¾Íñê'Î=äjó€!|ðˆïˆf[¥¨¬ ¸ Áœ:ÊÕþ¶ÊMÑ&vûßÓ»eÊþn‰Š{ölµ¯UèÏ\xJµö ȧ­'§­¹­‘«6ßkÁi5§+ö£´vÙæ¤ÆflîW,Áìog}óT-•IMGãï/ú»š4à$hpQ:"½.×lÔzÍ5(Ðlh{¶DjÁhu¦Á’6(Š ”R´‚¨ùÂ6dã�šk¯þu­€œ‚…æ�›ï<4äF›[«f÷«hâDðÒö[D¨dÀJÅ$8¼Ñî8b2ê¤5 Öᮽ]´êËÛÙNÅ”:®´xöÌ™1E¶ƒU””ˆ“Œs¥ÑÁÕD3Åü4Ñ&Ç‚`4©¶ï¤``ð$œé`¥f/FÏ®×^«C2“Li›6£·¦‡ú{“›ÚØ…@êw¹–|¥ YØw ™yœ¯U0±Êy=!åíµÊ�ö;sRÛºX�e,òÆ´·×ýy8á]ïç Ñœgݯ^Ó=ÔÏ:ˆ6!EP+¬e Οð|ÖÝ8̳Ç™fÅ\ßHû3ÿPö·hþ³MšRô¥fºE´Ä*Fg}r¬¯ÚìR¼³ €† sg›¼–QÛ²ñÂT )‚‚ûα5¬SÃh1r1 #åÔÁ/zŽ­Ñ°ŽuN�åîÏ)“²)ûh§”§Ûæ]Á{g¼“mO1ù©@¼. ‘ÍÒXjÓ×BPÅ[&0g=v� ê¢e�†-(c¦vxOYì •¯|^Ð$¤(�˜g M?®¯U¦÷ƒ{Á�½WwŸ IDATßLò´O™s].÷£³5¸P'wý¿�Ï�ß¿îÑý&§e:ƒëûº¾K©†z™£m(ÓI¿ÏµMÓ¤õý(Õ0®›NKxu§ënGhçÑÝf¼ÿµ¾ïç{Vðzt¥Usm²ï™4ÝW¿ž+‰™AÑ^í [}E3pÊìwe?P3^Øî§kœY6s}Wª‘a´Å¦Î)OuÊk팕?›Ù‰eæïõx€Å±è=‹.°è}çé;ÏjѳZ,è;uþ«ÃRr »‘aH„ÎB'„Þã‚f£kÆy†UŸ˜~+¤x ˜+Í€ªS³­«u^�R«'Š­eYß›ØgA×:»ÞB½äRm|1±`ýR5àYêö¥€J˜¸ «4¦8¶j�*‡šO3 Õ¢éÒid¦x×në?ÿúÞy¬ ÀÇV+îöpï`/(´fÂ÷7;^Xöˆ€§£òËVà?ˆðI£õ©bü) œ½¸¶ï'ÃÈ;W[¾óæ1`�×&Üß½ƒ Ù_9îZ#äÇ»�w7[¾ëæ ^40û›�žð¹Ó~íBÁ¿£eÇOßGc6 L/N "OknM®f PûK˜Ó�™2-Ì6Ø+ÿu %‚r8î�òm QõÁÌz¡zzߘâøoq6Ó�sã¥Ú6³óÓœ�ª}“s[@‹M¼‰¶gnÒ j�3kîÕýÂó6 4¾RK}ÙÈìü›SSÇjâN®Æ]iA�D©‰–NÛÊŸ[``Zår©ÃWûµh­¡XFT½†æX¤LNš%\’ÎÉä2¹zg6v!;Ô©ì,ˆ_"~¾�Ø2¦Ì.Fƨ”†VÝô¿>¦ ‰>,ø ?ò·ø?~þ¿c7løßž�ã¼ã/ݹÍ÷ò»——ìvîßÿ/ßý„®q�ê±:û÷@Ú±¤�¥PøÚ7þ9Ož=à†óü­“S>rtÀÝÅ‚7.ל #øw>|—¯YöÿÅ8²p‡\¤ œ|çj×W¼r¸bÌ…³aàwÏžÒ{Ç�¾t‡7.§æÂ9XrÒu-ƒy3·;*Ô5æÌÏ¿û€R /¯–$h Q?~tÀ�Å¢UˆÀ�Å‚7ÖW­úâ«gOÙ%Í.tBkĺôž�®¨4›äGîÞáË1UÑ�§ÊRfÇ´ªà*¦Ö£àc‡¼³Ù4Îö£.�ÐJ'€1—½ L€nç\ã�‹ý¡ÍY?èDøô�cþ›÷ù3ê ;·?ΗþÜÊÑñ‹–gT,N9¦cT`[»j×FqÞ€Kßä£ÎmçjöŸÎ£ínËz½æêjËv»!§ÒÀ4CvÑ/ðÞ‘Ó–7ÿeoök[v�÷ýÆœs­µ÷io[u«a‘¬*Q"ÕP„d‰”EɱY1%Òý yÎC�ÿ!@€¼äÁp�€ ˆc˲dY²éX E‘ÍPl‹ÕÞ[·9çžsöÞkÍ&c̹Ö>÷–¤ì‹}Ï9{¯v®ÙŒñ}c|ÃÀÓ±eÊ6Í~±ù„b¶0J–¥”Uj(nmÎŒøÒ[$¥¦ï»š™\|Ó × KKžï™mµAëqdÈ%“¦‰Zï©‚ï*¿Òás0�îDJõ>4º|µ:àððHkŠY�ú5\øÄ'>Ïz}“/ù·ØæÄ?<Äqr‹{}‡G¸°L�‚FܱèKR´–hÆÊÚù–)àD õ¥dÐÃí¨ÏÎúR•Ì " &Tó]>÷ÿöÁ£fžt�mL-‹á�ËM#ŸDÄÆ¿ý?vrÄ÷/7�û±Óc.¦Ø²zb){Ylv|ñø¤ÕIyøðܾù&^,×Û9¤fMæIAxë/US ³�yBIZ 3U’gœØ9“´ÉZß ÊA¢ÿZ¤ÖûÁ‚LÚÕÀl—0ŸÇŠo—ŒP%iwZ8OÀIe"Æ­a6 •¢ào× xçg¿£ .H‹ 1] R¦É6TÛ¡†.7PÇMõ–ë¦kd•X]…&ç%5øME{jtµUhKw³kªd“I�$ª`”EJqŒÖÞá§~c19‹É0!K »€“}�Ž:æ"Ãv?E¬ªR::[Ÿ“ÕašE$M"('­_BÎàƒê­7»¡à�§ žapF�2—¯}ü>ûÓ?Å_~ëÛøày÷ݸ¸Ú0ƹxB] aŒ£‘º¾—R¡'NE§j“xêÐ"Ë}?Ðuž)OŒy´~VH1*'ØlÙìFvcâr5²¶„ÌG+¤œ'ôëêãàhÍñÉ!"‰”¶›ïÞ=äÍ×_äðDèÖ W® �2ôgÜ/’7\ÞœmÎðA׎X¡ï¸÷Ò ¬ÖÇ<|xÆ£Çg\m7ì.¶ô·N8ç;\˜â—áÑ“-ï¾ÿ„.$v㊡_S l®®¸ÜNl¯¶œ�_rþôŠ\''…«Ë‘í8R\&;��9=Y3މqŠ””·£f‡Œ@‚ô„õÀÍÓÌååHß=aŒQƼJ1lÅQ\‡·0S͸¯v“ ÂáZ�¹Ù:ÓŸ®ý¾4w‘çHÕ,Íù†5Ìï% af~ËdU›µ ÁG~ÆÖ`±¦é[lnÖõÊf¢_ç<™mç"̃,×}¼x[Û;uBmn\fçÉbÞ¹^O Õ[$N臵{U (KÛž¹±[3j}˜‰‰J~.È�†y#.kf¿É ‹§b´îpÞi &l~\.‹~cuar•¤²›q¢Y÷ M ˜/õº‹Ö‡(–ª]Jõ!îJŒQ3ÊrÚ!LJX!ˆªtO›£Íé<Å{¤›;dŒš¥ÔÅB5à 탓œŽƒ”©ÄµŽ Á¾³ŸƒÎ § .�›:JÒšU½�œ—öŸEÔ×µZiz¾‚ R.‡G¡¦Ì,ß‹Wõ?E»T�rmc­ù:²Ø·Ž"ÚÀiÛxRDSØÛ‹SVç{QôpïÐB u��ð½\={Žy»ýí¯ ¦<ÿU�Uö?+¢Ža¢Õ À~J‚Y?W#]ñŠh8ýNÌØ®zp�œ™CI‹Œ�¢,'¥UÌ!±v¶RAbA&•j’Gv�’U ®dI(±�m¡­`|ŒPÓê”UßR£@�3Œ`fÆö�tkq' ¢“AVÆPe� ­ä>E˜bbŒèµ!0%•Š)·1”9`ýþ£²ì÷gˆ�6hlœÌ¸ÈÂÐl´Ç‚`¾·ÅX›?·‘w}û¹Aö^Ï#®ÿþQ¯= ¿åÌÍû‰m#|ÄñÊb±½öýGJµôyÔ–ôë{ÕÓíý\~÷ìÏg·|Î &ÀòïJp.>¿>¡]¿ÌÖvÍ»Öí‹™¥@uã¬_7 ÑN$mòš¥ÖÚx(³‚Øê6³öËKÒë×tÃ9Õ·¥ bút,‰l‘—‚Gç5#`¼k�-ø3ô�a¬zßäƒfb §ë:z#rÊ춞ͦ°ñ‰ÍVp9‘ãHÊ_ ˆc𡓦[Kò”1 1WÃFÉ W²¦ü6Ã%›Q¡Nb2ÍYi Ì<Τ,ž°uB/E§ÂJ„4àBÛ3a,΢Šª”V@,ƒÁ¢ŽœÇ›þjð³|5Ê|ÐgÒõÝÐ!Áë"é=²ê�Î7 Xk.Àoýáw[wû¥““ÖŸN±E烂ù7¤Áí¡kQÀÞwUn¨~ÿ•ÇgüÔ�Ó½¥5/~¿ÑwÜ09¡)g:çZñâï\\òÂ0´kyëòŠ)~ÌH†ã¸ÑÍÒFA„_{é.ÿóýû ìø~ö5z�.Å!Y˜¦5ªcÔ£¿‹X¶‡Iö©ôD=ƒ´!X#Š4Ò¿ì�bÅe]ÓÜbå¶ }ž…ë„]Ÿ¨ÙØT›`a€Ôa\-ÌÊ`'ûÞU²¢� |™Ay×õma0Õ wËù (‹‹q ›g1OÕÏ–óÖµ9¬ö÷z+{_ÔV¨�»·m^XÓÙlšl`Lš³OÙ´4h1û­ŽCuʳÆÎyQ+è´7•›ý#³#R¤�<ÄXy½®OÎ!}sHÅA*Ä1²ÝìØlv\m¶ìÆÔônkwšSc�}~r|—_ú…ßàw~ÿrž3ÿ÷ÙNŠð«§§|ùBÁ¹¼ÍK/¼¾Hü0›¬¥_Ï=K1çÉ¢äÞ»ÿ]¾ûÖWø÷D˜bâÎIÇã]àÑ8±òŽ?}ô„Ë)qÇ]àO�QJáÕƒ5oò¯ï?$­»ðw_¼Ã—°å÷7ÛÌ{615’àGœ�S“zóø�£øŠe5äRZ í‹…fÅU+.]�}÷} _(¸í;(Òä’TîYmÝœ'¦iCŒ;¦8jGq*ÝTÏ“ Y4¬[3×¥h»‹X–ERâ¬Éh¦Lœ›­cJ“‘V Úû޾_Ñwƒù*Ñ£Y Úª]µ›FvãN¯;Í i)‰iŒ” „ନ¹f›L@Œ;6›B×]ÂŽœ ÞwéA|wÀ°:"„s 0ÅÂ8î�]Æù ÌïIµƒ9ªÉ2PUêXm1r ¢e;$HêG Y ­¤s¤w ÞѹÞðµõSqlÆÄG¼Oš�ev™ \í¶&GRxzqAœvÄiGšÎIñ)�n �îzį9:œÛ‚l >r¸¦òf"w™£ÓÖÇkÊ*àV¬Ž ýš“þ�pr‹G> ?~ÌöJxðîSŽnÞåøæ œ/t]ÂûKà »œ�mð¾Ö’˜_è×q,„ÁÑ­{Ö‡‡ø~ÅjŒlÆ-»¸£ë=Î÷l·;¶Ûĸ‹�¯ÈEˆÅóøá#¾÷íïÑ�”#Ó8qzzB»ì³‚ºj2j‡xcU[jx†a}â5ÇÙ¿æCSWB³�aiXÛ¸^â3¶¢`+³ÞüqióYÆUL㎠7eñ– :Ïk´ÎÌk÷2ë¯âØz_åqÙûj‰J›7”PTÒ¿Z­króušó1_KÝ¿™ ,Â*gøa¯m ´{_b{^�ùUUrYjv’µ[ FT{f>n1š\jв3<ÃÎ`¸a“^jÏxqp�𠣏 šAe~œ'u ®!8¯RâLmD¬^©Í«Ål?Ë×ùZð•ßÖ, ‚øB˜ýóóÄŠ¿w¾8­kÖ¦q"M¡÷tƒÇwnĨ}ÑTdÔOdѧ° @²õ7·Wíû–YFF³ "£ÚAY¥­öÃÍ“m Ff0s÷hŽdÕd–hÖ|ÍÅÚ7Çé–Ň²8·ÝìõðÂå¶æßjŸvþö²‚ºÔœ¥#.f°Ôï ‹ˆº¥íüõžë¥îmÙL>â—k[.¿_•ÈESØjß„I ÙCÎ3“­AýÎ:®í_ŽèQ�q¢�Ù¶bµOjÄ­^Gy–°ì)Izm2)ÃÔœþdEQ–Žâ‘$””È­Øï4)(_µ=eï׿DÅ<µÐjÕ#Ÿe—šÕI)5…HHÙ‘r&&Ó+b™Â4‰žßdƒb¬Ä@± ñúTRQR@I´eÁ[ åú{{/Ÿó¢‡,¿°þ´˜ õß ·/ êÏDZ}×1÷´Eÿ•½þ"`ÿ»™´°ïŠðÜvšJ´c•å—Ëã^?Ïü÷eZÇóþØY,G‹ÍdƒÅéÔ¨[n3÷•½û\Ìjy�Ë›�y:`±ÿì¸å¦‹ó/žS1Ç`i dc5…Ææƒå×qL±ˆžRë.Ô¨~»’²04dq s‘-`\‹0T g$¡éþ'Ó&!d¼�‡¡s¬zÇjåºÊÜ+Þya:V}`è5s ž>8VCǪï�cfÛÃ¥�t2iÄL'¦’ â餣™¡GõFEÈÑ‘&aJ¢ä¦5Y�bɃ*B[ 2Y4s U‘å2¤íše–«Ä�J i›¹½n¤� 5Dƒ‘š‚µ¥ißûÞ‚ƒàÁ{-Øè¼EŽÔËbúÒŽnÕÓ¯zÍ phÍÓ të „AÕVJ*ü_ÿæ­¯üÒBFèèZ¦@þ§œq"­ŽÀ&%žN‘,‚xFzã³7OSKY«ðîfÃÇM¨ÿúþ#>÷fËL¸ÕÏY @# ðp»ãöjàc‡kJ)üîûø™Û79í;~ûñã¶Ï?øü'‰¹ÌF¬h€XÁ¨B°ôºEƒR)XöB­˜Yu\‹Žålä@qÚþβš)Rê°o,/ç'¶^Có'D˜%Ë«’aF)-È ÂRçÓ:gˆþ^’EܰÞtŠ­&‚YåJ(x3œª5Þ"òKëÌ¥Ú`{V¶½vܼÞì[uómçýX”“2ìPå)k¦€*#˜EðÂ^†D%èê¥× 5¶g …ý‹X�U’Éer€<R:|“Js¸U§…ø¼çÕH‰q7rµÙrµÙ²ÙŽì¦B*ª} ª)<¿ºìh?yí•ç'?ý‹|íßý!ïĉ7nù•Ã5½c)\^�“&WjשvZ1²§”å£0ƒŽÂfsÁŸ~]‹ÿh?ðê0p»ë9ê¿óÞƒç woñx7òM“ùì­SNChQÈâ„ûÛw‡�÷¶[½çwßÀ”2¯¬Xy߀ùOŸóâjhÅ…ƒs¼~tÀÃÝÈ.©}ôOžr“FЋãk�Ï)è|óÊzàëgOTá×_~�ßÿàCÓðöõ½‹+RQü8xÎÑÌ?qã„ï]\qi ê«kÆ’0ºË¥OÅúl%Ž»À&¦üw�•÷-à°Û'–¤€žïØ]›#—¯»COÿÍ÷¾Ç¥íÂÀO~æïóêË?nã7"Î�N vÊ)3ÅÄ´›Øm5Ò9¦Q£àsïŠEd(²XœjJ)|ëúnͪX¯èû‚ð¾3àQȹ#ç�©Sb@ÿd²ª�®5 ’ÉÅhñÐ!–dQ� ¦6ÙH›'«ÔHI§Ä4%-J]Œô›ÍH,”“êÒÇHèœ]£§ö¥ RB1iö‘›“ëìn€ŸÉÑhaÚžÕúˆã£ªtKœ ¥LMÂÄ9„¹’=9'nÜ|�ÏþôŸå7Ù¦‰ÿåì1ÿÕéMÅqw5ìõ›éš„g•Ôô¬ ²}oY%Ÿ>ØnÙÙ:ðdœPtîs?°íï­>ØŽ�pxóø�‹˜Zíì|õµ‰©‘Ç!°Í¹e½|°ÆËL*Üè;Þ8>äKé=åÌÛ—W¤\x³å‹''üæ‡:œŸ¿Ç�£è; ö! ®PL¢¢eœ@¥Ä¯Fã;ß1ô+†aÍaJìF�*ÆtÍJ�”èiËŠ³)_ ©$R5,‰‘ …”&rMK'Y6ºjÙ—Ñè;“‡­vîr/@‰ì-í¨_]ëVµú!BPÌ”4Yqχ¨ãRš<®Ôì³éÕµ`GñZ¼7Xv„ëp^AæÞ˜=¢²[9càUUwÐvËidÆñ dCœ´/ÃFôœY׺¬¶q“Yª vÎ¤Šªo�&4Ÿ7î è´8r¿Zú�.ôšM€É…™ýQJÍ€i²Ì+ -¨=�äQב£eýX†á%Ÿú~K×�øàXùŽ):¶»LJçVˆ :͘ª4Z¤€ˆ(¯¶P)Ùæ— ÞU visaÉV0Y2NŠÕ)¤IÆ8ïÔ¾•%£8rÆ©PJĹL×|'¸ –BÙí˜Rd³Ùž(!â¥wO˜ÆÇ<|Þ/„þ«£\‘²Á»‰¡ÓëÞ]nÝŠpÜq¸:Áß>Æ€WÍþ£ÃŽÕif7 —‰«KØlϸ�oàW=ã´"ç5¥¬)e`œ2;Dv@d‡‡Îul® }çèWžá g 'ÅO’¯¶÷®Ùlœ|]f•+rv¤Òqöø ?Öý�®ãøø?d?Ùî2úÏYx”¸Mt׺pÙLXçÕÿt&É%‹ Â*5½Èa¶«¦Òþ6¯*£:Ù-Ìûº®Õƒ)KlbéóÏ~¿õͺŽ9'fêêœ9Ç{ÖŒXÝÙ‹F¿×¬žª v>ýgãÔdÈ4@jLaÓñÌÌû6à}ö ®+¢´�¹eÀ¨îºÞ ‹=¤,ÑÙ æ[@°¨o-ÕV7üB¯Õü[7ê³Ä¾«* Ù»õ… J—œ[²¶¶�ÚÞiµ ¼s:÷#¦)2å©É(Š ¤@ð„Î Þ{­·XD¥ç\Ћµ�ø€óÞêÄp*±†x\ï ½gÜy¦Ñá½Ðõ¯šBæóÙ5g ÙhÏ®ÊW!J|$P}áëµLl,ð) tS��eBÇD"Ub Ì?Äät VŸ*3”ÖïÌWk²<Þè[Ž—ötÔ»žƒõ-�P{ôÖÃ`ZíĶյÔëý „ý£Í׿‹ ò¼}ÇüÈWùk¾ÿèýêÙšTH°]d°`‹°Œ�fsY{ù6©(Éi±¿5èÁ€kí˜e*À ê1+y¹0ÆTKXO Q�(–!P¯Åi§#€‰©ÇS)GJ¦·�ô Kué–fd„“úXL ΘPªD1PÙ=ú§X§Ì4f¦©PKŒSa cÌŒ•(–9`Ù) (4íÿ=¬Þþž)°¹][6Íb8Õ}êƒ}&Û`9ï6{´´÷�륱¹\x–=éúô,×öû›¾æc={ÎëÛý߈ vB<]§…ˆ½/š…#É¢� ‡“ïN4µ×wžÐ C(ô>ã|q ¡;A"ä)¹!„Pè‚.Ô:虳'{­'âPª£X”WiOÀ™ã¢é{Ê—¦yŠ¥˜S5?90cÅ)¨ˆKöÞÓ-Ú¡ó….@4SÀ;�ÅÿjdŠˆ9ê¾ó¸U‡¬zŠ�´®@ïõÝÕðu-Ò÷­ï<áÛoŸðÉÕŠ{‹¨ÿz�çSÜ+F¼Ë™NÔÕü®uêë¥õ,ósƒÕ x³c—S#œhÄäòœçÞ@õ‰ƒH+\üáväá8ò£–)0¦Ì_^\rkšñüówn±ž¯]^rߤ~âµ[¼qï´CÕa§kA‚¥Ö^–ê¼k*j³möb~uÒNV¨¶�÷æòâ Ù¼+”ZäÒt1Õ�¨’m1¶ö° a6èJÍ *z ©v¤š)$í’f¹ÄæÞìMûiu|*Q^ÌÁ�qû®fŠ— IdÞ¦uf³§Œ0(Õ�¨`c®Q<²=víûÓÞ¼Ž±Ðê¥X;ÛïÍQ²¨|èñ¬uQjÓÔ[Ú+ÎÖS]µÄ .è3w^%s(”àð¸1ÑOÉ|Çj}@z5§Ìn»esuÅÙ“sÎÎ/¹Üì§HÌB.¾­Ž Ø)z…eoöÔ«ù™Ÿú5>xð}îøCþéÅ9g>|ÌœŸóƒ·¿Á+/}ŠWî½i—ÿ|›µ’PuÍ)%ó§_ÿgŒã†—BÇ¿xÂÍÐñ wo5½ñ˘ØÄ„:•:^¾{~I¦ðêÁŠÃx¼›øáÅÁ9~ýåø‹³§Üß*ØøÂjØ+.üh7rS#ö¶1ñ;ï=@оU à³7Oœk`|¦¬à|2[é÷ÞÀ&eÖ^¥sjtÿ�UÏÝah‘Ô|îÖ þàƒ[Ë<Ø�{u¾sqÙúÈIßñdœ8·ï?wë_y|ÖÖõÃà‰¹X”'&¯2Gat~¸Õw<§vÞÃ.�riò+@“"zÞ뵃5ßÌÿÓ[oµàŽÃÛü­ÏýǬW7)ybÚ]‚C·j ”ÖÅQ°`Ö8çHy"¦‰5âY�ðÔˆ‚*™³? ï:�èîW¬†C†þ€¡_µB­NjŠeWù@'¢ÑÈÖ"É´Ù›B«öQAÈHLÛíWW—”’ft]§ÑÔ…¦Õ^ŠfÎõ¡4ÔÛº£Y#Þkà šÙqbšvlwâ¤ÑÏÎu-+¬fxW‰{ IDATM8“r&9â½¥íºž>¬¼ÁJLÔýè¼îï­ ©ïOÊ™“Ó�óéÏü¾ñ¿Å&GþÑùcþëÓÛ�¨£¶DÇ! 2g¡8^>X5ðh™õUI‚Î9zïZf€ˆð™Ó#þâÉ,7´r�û|çéeó@ƒs\EÍRp"üôÍ“½ÂÄ?zzÄ.®šLÖÕ[PŽ $ØÛ"«+lG¾ccóçïÜäåœfbàé{¬Ö›Þ2NbŒÄ42MWĤÙ&´jíÐá\O? tÝÀ0°^ÑÅLì2>ìð~«…¡ûȺdy�€ÕR¹ q³>3Ë.·g > 9)�&Å FIªYŸ«|HÉô_^ýNg¾g´Œª¬„YåÎÀ_ïÁ-k,™-9ì9;Dz3]Ëv›×‘eF¿Îùâ„Ðí¿}Oq^ß¶Öä,øÌœuf‘­9�„nM×Ò�¦qKœFRšKs +±%^†’µ±Øš$^£d¥®Ed”,�#)yd™&•‹Sd½Ö¹FZ1ÓY»\MŠBߦ˜H“’��M’cÒ,\Ñ:•ôpT{^•rvŒSG‡gœ:ÞzëW›¯óäÑ?zÌ“³…]§mXŠ˜í Ú—Lª³‘*e4Z1jg2. ˆãHœv*“U&Ëü ñƒe`Kƒ�\ptÝ€#�‚(¸líàƒÓÄD¢æu”¤ÑÉSŒ&É• EHpÿþ#r|ÂÕæ’_äô8°2ÓÅÈöbÇãG—œ]myz01&ÇN:n®9Z (•¢Ït,”Ø‘ËïŸóðñ‡oo8<}Àù“ O>¼äá‡L#xé ~àðpàè¨çÖ�#î½raâƒwÈöò’ÐmIéœÃƒ›„ƒ™€ë;î½r‹_ºÃµÍr~Êûï~‡4ŠÖ”2�õj#ÏRà…L²C(¬¯ÈìÆŠewUo¶LHŽÍýjfìð6ÖFY=PÃ+çìߊÓèÑ�hñcÍ€ÊÏÙ–:èš�^Mj‹twÍ–Ö,rLê¨Êü`À¸[\QÜŒ¯ãÆ|‡øÔ¤zg!�h”¼XÆM}I½îkÊ -Ãð#€‹™tŸ¥ƒŽ!¨íß`Šj‡/�°²g£S=ßöüe�˜ßv'MB°eµ¸un·¶]<�¹ðŒ´vn$æåŒ#¨mê,¸ª–×5‚,d�Ω%á�S„!h–\èè|Ò)aèg¢°Ú"b�‚�[’¥¹Éð’É.ëµ%öÔx²˜Ô{i>š¶¥×ó«GQdκ ,´e©Ö?TŒY¿(QÛ¸º§aôZt'Êž˜CR°”Ѝ“êG�N5æi=¢¡à¥I é ©ÛZ¤‰,ôÈm·J*ÔaX;Ö¼Aí çzéh5R¡Ì}®‚rËÎûœ×þõ/α÷šÉk;?÷˜U³w¹Ë ô£Ì~%öd„ößuN-Ðtû »×èW‹DvEß¾ÄíËŽ8)ê„›¼RÉ2k[×[+�Ö‹Ž $KÛDóX¬Ó—ЮYUI„œ„h¤€ú¬Õˆª®vt'ç ˆÃy›0�Eî;gbŽúR|AZý€qJŒSVr`*Z@¸Hûlœ ãT ˆTb@ÿιÌóXÁöÿR! 2ÿ]�¤º´,êœe0Ov{}ûú5ØØ;ÎõŽõ<aËþÛÎú6xÊ’¤š¯]ìBž×·¯wí¶8P¥n–üó®rïô‹kÚ;êóOØÆw[Þ­ ÷ï·”y]­{ì.‹¹æúóiŸ^»‡¼ø¸žµ.¢Í©ã¼ÌÛíOX²ø½@q ¬¯\Ü¢cPŘçãÛõI�Ú]Xs•ö7H5§€Üˆx'4CWë�‹m[‡dö«Á³^wއžaèú޾st�kE‡CÐ@\‡FÀx¯µ ”ÍÖ¨ÜD2CX��à;‚Ë8‰ŒS2¶]è:>ゎ�U€Ü e,$W Oº!ÔZF„:ià%C6ÂE4êW§R§µðn"©äI•hZô‘&'TŸ§“hŠ÷H8‹*è;Íœè|¡I Í(ÖGª�Ô…€ïí=tÈЩ!Lš‹÷ÎÞÕ ÖÿO¾ôÃÖ¿p¬úþ×%„N®eT ?—ÂyŒ{2>ßxrÎgnÌY�s„Å@º·ž³ v)3xÇm«Ið­ó ^;:`eÆÜ;W[ÖÞñò�F½1ttn ƒw|áÎ-@#OºÀ©‘ÿüÉ,ÿñëŸûT#°éðj”v® ³9z¥$íËÞ,†¦Õé÷Œå\�¸…u-ŽbS_TR¨M9³þõ²GïÆ'š>êZ¬ŠhÃKuÍIf½ó8õûêp,feÿ–R*Iç„yÌÛN�°¸®çÎY€ØgeÿðR§VÍžÑk0¢­eË©¸y­MçeËžIÌäÉ4œa±Öcv¤­ó>Øõy³G|»6±“æjØÖù¿Ô¬æ ØOj¹‰®hóö޼ºXȱ¨�•]èÌbbw¹åülËÙÙSΟ^p¹™§DÊ^¹§Ú ZáhчºÌ³Ûçøå/üÿçoÿ�ìÆ _½ºä�ÕªµÃ÷øu^¹÷æ~[^[oæ~¦íù­ïþ ÷þ|~u€î =¿÷þBàãGk(Ò¢ýôô˜WÖ+~ïýœtŸ:9jQÁ- Ð;Gï_ò”1gnö;\óÕÇJ:ϯܻ«rC»±�ßn17|Û€ÊN„Uð<�"_y|†ˆðs·oò½‹ËL¾~tÀTJ+rºK™³PŸKá_Z–Âiß1¦ÌF@¼z°biûvÞñêÁºj•[Y®çUÿÝ‹pBÓ{­›R�šy°|-e\–×wý%v¬rq¾W4ýî�×ø…/üžžqŒ”42¦ ºm¿¬3#âéû5]דK$å‰iÚã�Ü�Œã–<&‹Vžš“\¼ï{ºÐ³Ö¬è»B\¥‚ñ–]%‚H•þ˜×Δ&b­+Ыë«ÊëGRš¸ 9 )�ïéºJ 8RL�S+Þ휧ëz�—�PÛZI-BÜ‘¢J‹ìv+ž<š4‘ǾÙFÚ~*ë¢ó¶£ïW Ã@½�qÍÊHiÒbÄæGˆ7[ËltNÈÙG;oÜüŸþñÿˆo|ý·¸È™ÿõüÿåÉ-<:ö>´±p™"K»5•ÒH�µwlRž3֜Ź`paí—Ö-k&ÎòU3gNû/Ò²c‚ç“G‡|ýÉyÛ÷ÁnÔÀ;ߟY·òžƒàÛ¾+ïù[·oð‡VD¼”ÂÇÖlbjDØ7Ï/xå`Å‹]ÇÓÄÓË@bH9²Û�*²Û0Å-Wž,ð#¥tÝî»�aX³ZY„Áû-N:B7Ò¥‰J à‹©&ߨ[@£b/qøæ´BI^³I*bžµ�cÂjY˜oWûŽHÖ¬W/øPm3�`§Xa]©çš-®«ä€Ž ¯÷]j¦Í ¾ SÇ‹3i,ßÈ,õ»~¦Í-"‚Ž~èX¯W7�ýФrUòFï[ª#e‘íU6i7Œã†íæ‚q{Õ"ß)…\"5DÃe¬HsŠ(ÙoÒ˜6'ÕfŠFòa 6È.hñਙÒ2 ¤Ùjs‘ÕB×yR#"ôyç<‘ÒHÎ LÚw“æèèBhÄMJžœ‘q�¾ý�ïÿà¾f�“‹”]ßãàÄ@Ö>彂ó8ÕúŸ¦1MZ×%MF¦k&4vÛ+k;­QÑy-`Ú¯…ÎHÝJ²*éèºïzR2½òb¡ƒ"Vo1GJ¶‚¡¥ 9S’}¢Düý�xpÿ i:程ðÂ1þÆŠérbw1röø’«‡‘GÝŽHGéènÜauTýʉ3ÓâÎÓŠî¿Ï_~û|øV춉í&QReÅÐ÷t¾çèð˜_8áµ×_äÍO¿ŠÈ–ïŒÜ÷]â¸!Eaè�9< LüÔñòk7xãS¯BÑè•÷Þù6_ýò–<¡òØF ¨/hv¹ù„Ù²t\kسT ŒÜKóz•’#âjqíêÛˆ‹NoDmß:ÏaÁ* SåHK)–• äÀu•†ç\Î`®M§Ex‹³¨}ó5(·©³4§»’i5  ^·­ÁFT¢¢Ù gF³só5βÏõ×/ýY[¾*̶Ý[ûlÙ–uûzÂÅá–›�KC=ÍǨ+eO†IŸù\[¨… eö)äœkÆ0´?hÍ‚FDåŒä„ocÙã}õ-s͈Ôù¬c¾óô} ë}ßÑBßi“s…–í]É”Æ$ŠËsa#É’).þ dáV•"JE#\ÅhuMò–]ÝbÏ ØiМŒjª30Jï(~–ž¿V|xÑQœ5lÐèo»O=©åîHm]u0evšåyÇ•ù;íÛó¹ìê%K¢*hR_ÕUŸ;ײ#,~/ö`ZðLÙsz�9"¾Ô�ôê^/A·ùزø{ù*û—ñÌ÷ýÚŸV–9G£µ¶ªÙ±,ÞP¦Ù Èµ3Ø•ê™\26KöRD´P§ó^��’,ÀP¨2KRÊìhW`¢’{úkÎ2¤Eõç¬Úÿ5Ý3–ªœ°¼§R%$\²‰ÍµI³| 1`�!’ª]TZ&À”…˜ Ódï8g h‘áštaªujÑ´)�ù–Íš'›ŒnþÉG�ןñ³Oÿµßù—y�3‰§yâ®Ç_ÎÆÏ?Ïu¾‚.uŸç]YYôóåú±¬rí÷ç÷ðF˜ ÇgÙýy/½/ý??çˆË¿´”½k�·{f-/û×ù7#dŸ€h›ì_Ïõ#µÓÙ-Uà^p œA Î.x´È¯kŽJû Uê<\‰Y=wuC*AX «Úju!®©³:–”1^£Õ:Ój”âq%áH}p ]`µê9XŽŽàð °†¡32@š\··ô϶(;ÓßsõÚ³�ÖèzGßkšjŒ™RÉC+>„hÁàÁgJee‹YgŠ!Ðßœq\'¼Ë”ì˜,Te×ÙR;s)ÄÑhQÇ+Gw¡É¼Ôã;f>T°¤*û—í9䤯e*…©Îå�CŠÌ¤€÷8ñÓ”Îcâ‡ÚzžšˆEñÅfsP�ú‡o·žöóF TR ÷õu9Eb) |‡JͯJ ÔñPI…«˜¸¿Ýñ‰#ÍH¥ðÍó >{s&^Y¯è™*oXáâ1e�#÷Ö+NûŽR ¿óþ~ù…;íúR)lsæ-€ø/ÏÜtNøÕŸzÍê�é3/¶fWÐ#W Éf‡ëv)«m!–ݦ˜¸ŽuþÝb¼H#ƒ–sºJ4;l1÷Ï…Ä*ÙVí ,¢Æœv Ø/´J€ÔçkÆ´SS›ßô%çf\L ÕFðzh˰ïf/¢=Cqyf´>á~öïó/¾ô›<Í™?¿š%D¦i7Ý,�/[×kÄm%>|ôßüÎð÷�y£ø¥nñÎՖ˘¸Œ‰/¾p/Â[—W´(ï;Wƒê÷öNøÇï|Àí¡çS'G8¾iúŸ»uƒ}à_¼¯`¼wÂ�®kww)ódzµ:ákFÜz^>X7íó“.ðË/Þá÷ÞÀ¥v|4ŽŒ‹5ögO)h�€Ó¾ãþvÇS‹bþÅnñÇ>iÀäÝ¡çÉ85™Ÿ‡» · v)7PôÎÐóxœûÉ£®bjõê\½|-I I Þ18×"ÀA³žG8Ñ ŠÿáÁ}¾º(2üê+Ÿá3?öËì6;JÞ‘x¯‘ì>8�BŒ»ÝÎôÕÕÞ õž³¾½÷äÔÛ:¨y´‚ÂtƒÕ èER è»Þõ€úÔe'70b~"j[ .;à4#a–°I$[oÍÞ$Y<99RôxñP:œðΙ£¢µ4 Aó©ö픓œ!FÇ8:bLÄ11M 惣 ªí[Á~'øÑë¯äH*oSý£ÍfbŠW{Iš¡ c¬ê=«ƒï‚Íûž®ïyõµÏ2¬:¾üÇÿ�Râú„ÿôäF#¹DT¯xZØ”¯òݧs?8é{6 ÉŸn¶{6ç&Í2W/­Þ[2~óø�w®¶íû˜ yák_ÆÔúÿißq>ÅFH|úô˜ó)¶L…Ó¾ãÎÐ5b æÌ·¬VH•ý©ÄáKë�Îy�OJáOæ"Ä�ÏÞåÖ­Wa‘8‚&•à›�¾Çù–É^ C"]“s ÙÓå€7PÝ9�¼V‰Í6©2>"ó\Ü·Ú—Ë’<Öå"§¨�(1’œF¥—I2e„’©d—öÍRY”°gEªÅ[F‰Jû8é(Å1M¥ÙªN<Á[ì³Õ”pSÁüéæïØçbÑë&µ§A 2:³qTÚõéMvÌ€%G0¿ÝŽïÔß÷¥ÇûçTŽHëƒÆqÃ4m´C2i# ÔÌ -fgåjOaØ€J3‰h ¬JP8‰¤¸eÜ]Úê¨ˆÔ ¸erõ¤%3Å‘1n ìMÄ8²Ûm¡˜Ìeðô]‡ïz|0µ¢ò<82ž1b޳qîzB¯…™‡ó½f@UàµáBêÕÇ4Íu ‹Ö2hX®ó ºuÁû¼+šý<Ýê�nu¨óWŠŒ£Îá’G:?QBÕQßµ� çÕïH Ã`)ï´Þ�tZ++¯ÉiË\ñçéûœ½v—yývÛïo!~ÇÓñŒÇ[®xÀƒËßð˜ã[Ç„ í>M0Ž…§—O/&>|tÆÕe$tž&ú~Íá­5»Mæê2‘“jÿ_œ�#ù’£c_¿É��—ï�òSÞ~ë.ÎÏ9^pÐwœœxN×'�á)¨$\âû!ªìJèÀ8>9àöÝ[ø¡c,ÿä’'Wv$ ¥3ÿƲwÍòv5J\ðEe犨´ÖwŠV‰�:ÒšIiϤòT_Ÿ`CE³rÍêe1.xß™åx²=æÜG|]�Ú9P]1.ý±¹¦ÊU }޶º¦P½Q)³í;GáÓlõ9hsÿu 2|AÉLiǨ6êòŽ—”eó1K­ÖŒè9£z¶vË3RC³1]±6õãdñu«;Û€žz}yÁyÈüÓH6òWƒ½‡uï8Zw¦zpÝWÔ–I©£dÇz8:8:zo5P—äLë`UŽ Ã.D•wŠ©¶Xû¶gäE³˜‚!¿5h«9§z07ßs*ûþ[m—¥C'`¼q {.œ(æ^œ †9í‡._®vÜÊDk´y)1à‹#5ä´9•ËÞ2;¿óƒ²Ï—à}[4õæ……$G™c\ Ÿ°v˜åyêÏeF­»öYõrmxݯÂˣ̀[;ûµtí¼óŽÏiÔ¿êU{—¯v€Öé2Ï! %ZP`¡9ªÕ&Òâ:U‡:·CËÂjRCH  UÃyes[âÅ£$['mÄ€MJÚä¤ ^ÎNÝ ÑÀüTætÎl‹²s™X„Þeð çç…|fTK› ­¾ %ª‘AQæWë d¦X˜r!fQ ¡VO@¨¹æcMÝœS8+ÛWl¨Sš/KÐuÿçßôy?;5/Ú¶ÌÛ<»Õr�³ñ² jT×Gžù9¤ÀõýÜ«[|°Ýõy|ÔÙžY~ö>{îy*9pí ç"3ÕÈú+ÚæÅ¬}¾\|öÇm;â_K Ô6–åFÕiã^ÍrN(‹÷òŒõÏlà¼jô×È{MqS£;ȱ¨Aœ4ú}.:hŽ—­•¹b¶±oïeoªÆK1†TPG¸óÐwŽUè\ ¸B-:Üy«4�n½r‡žõz`5 F˜cÝ  ä¹ZAsk«º�ÍË!]×…ƒ8�bi$ß3Ñ´`s* >#½Í;8†ÁÓ÷�Iys ‹¥+p“à$“¢Nê9,O�Œ¨¤ŒcÜ«q#V€Ä°ü¶„Õvwb\©½gY1)µ6ùáð8E2U—P‚àMJH:aÎ�SB€ådU™Á;v»Ì¿ú£w8òž7‡9šÑÝÚëðZæ€iÀÿƒÝÈ�¾kóÄûÛ‘up-›`åwW³L‘i¤ÀeL¬¼kÇg³åé[qá"šÅpoM뇕¨^%žŒß�FÎ ùÙ7îrûxeØ´�Ÿ¢c¡lX·˶QãQ ˜”¥I÷x –+Tcp^r5jmžÏRT�GÊœ.NiÛäEA°ÚµHµ¯�·\ªëV™e„*©Ÿë‚"³4_Í–«°ÙIèâ×Ì.;Ièë6v¦±ßðòL+Þ¨•ݘÇdµ™fÊ^y67míiót›Nk¦›Í“V É"æÅÅÒôÅ;­•QSkµº$MÓ¡½†¥,›Å5ù¢6HØÜ?†ëñø1Yí&Q½ÎìõgTÇ}#WW;¶›ã.ڥ뵑ÙNX\A³¬ï`¶rí#¯¾ü)ÞøÄgùÎ÷ÿ|oUùؽOQc§XXÕè+¦‘]ÈlvWüé×~—R ?Þ¯øL¿Òèâ¨R]Á9nô�oœ=å2&Þ8> ¼{µå"FVÞóë/¿Àÿóácr)<ØîøÔÉÑà}6*xøÂ0p™�wpÿ!�s|îÖ ÞÛl›–ùÏݹI)…?¶(dA5Éëó¹˜"ÿø�÷É^\ lsæÛ’~ò耕÷M2h~xÀ[W›Öo_X œ�S«% 6ä~-„ç‘�s|üä�ÿî�·yoœÁâ7_ÿ9^¼û)./.(Y%Мó¬V‚÷+¼É)ÅÙl®ˆ1Îò7}O×Ë"„(Eƒ| jçîv“Ú¢QØÃZ…¢Þi€f XÔlÉš•³7„]ë¿¥ÕvNsÁКA ¶à©Þº$eÈÉ“¢#GGvÊd{×·õ¸ä2Ûq“°3;Ûl÷ì¨zš2Ñ 猵‹^¯× À÷ZœUk®”F^8“ëS°nd³½âüéS”À­‘š…Ù.5R�D)úlB*0¬V+Þø‘/�ÒþåÿƒwâÄo_<åï*ï�ƒ.´è`�Z¶ËÊ{È?xÇËëUë§ õ}–6ríÿ�=·J\y>sã¸t Ù4ß>¿dg}úí«M[cÅ®ãƒÍ'ÂëG|ç⪑f_|á6ß¹¸â]#‚›3‚ΧÈÏ�5bàÃGßçÇ~ôï¨;=iä6>@òdÑÈqï¼ê-;o¶•Éù A"Zs)”@.�ÎñN37B´Z9™¬•Γ¥¢P¢õŸT >·>à* X„#yJ$IN�ÏIF<^ÐhÍF QéJ—U÷q­¦€úºN}ÎR}T%(¼ š¥ Ôl–Ùv˜m}"Š5躑­ w)&Ú“£½'Bñ7´UÎu8TË~é£ ~QŒ,ô�×,V­×7*˜Oj¤sõ„+9PªS+èZiö‡šë ïí“ìU¦)&RܲÛjÑàY÷Üê8YÑbÅr‰¤Zó�Ì8nÙî6¤8!¥0 =Þ1¸ÐŠO§”, p ˆÊå’Œ°¼t`ã;‚JŒx+È*5ðCI›R2w*�¥LZ Ùy‰#8�t+:¯sÁjè4j¸ tÃ@7¬Ç‘ívK#q)Éч ¡Ã·ÌÜlª�–9¬¶KÔŒïzœ×€¨\&Jé@¹¬HqÍœñþ;ï3n27ŽïâḠãOŸsÿé†îýY}ç ë@¿Òóïv™q,Ää‰ÉSЧèz­ãr¸>åö­[œŸmÙ]�“c"–‘‹¸as±ãô¦gÜ}ŒÕp“—î�ò9ï½õ=.ϱ;<¥œqr{àè…Co„ exóˆ —ønGé{B.t]1bà�—_y‘n=p9NLâé>| ’ –)à,pJ}F)EǶ8ÍÊ)‰T&2Z³­µ·º…xª¨0Š…Óiÿ7S³f e10·ùÂŒ³-³hm¾©lm[§ã#š^þŒ�497ó9Å"ÁTZlΨ¤Àú[ïU˜íÞŠ™,° º¿�çedÿ|l³Û¨Q1žæÄ,ðŒe[^Ç7˜�á…]®m³ Ï‹Ì ú©alú%­H\½3¹Žl~ºn_3´…bEçKJ`DŸ—L„uï9Zu } ë<1ª<£ÊŽ ^ÁJqHɬV‡=롳JšëÕžC5pjãÚïÅ¥˜‚K¥[ì£h0†˜µvÒjÉ´ô�:/‡QÏå”`XºLõzfRjáÛ9s™œ VÈçš”Pí¤ó�jX^£'hº°s”ïž#wýbö:Îs~¯‘cö˜«W‘ ˆ—ý†`·ö;óx]žGæýÚg{5 ˜�ç%`yél,EýÝÆb�ØÕ,þnOvïïåÕ,_Úô® Ú¥†TÉV\(˜ eÊú3Ö(y1CKš±®Ë¬³´,‹f¨Nµµ­PLçRÖT³ç[Z ,XKm,ª^‰6EݮΦæ4¤¹Øp*J¨¶kaʵ°¯Õ (êxø"$2.eB‹Ž.-µkÙžâg:Ì…‚ÏàBYaÓû̹�"-2¢.fÅçlz­QͶ(mÞªìaCÿ¯½fR ìw5®u½½Î¹ì¬U¿«?ʼp´m—Ç­ÎU¶‰üZßÚ×Ïž`oè4@̾³¼Ž³ïíh?K;ÞbL,‰`¢þ IDAT€–*m.ɰæ4¶ë]L$B[âçÅÐÎU …¹¼wÿB5Øë¹?j|>Û.Ï,vm¿ºÐ-úŵÕ籺Qw¨ú�Á£ýC`=ô¯ƒZ Ð¢�¢§LŒÅ¦%sp-m±>+9£‚Xÿ¬Ñóõ¨æo©:ª6mz§‘ÿ*i¯E‡;]( !3a°ò0xTÿßxªû¢ý2HjM7¯Åž»šNª;® › s¤RŠ™qŒLS$ÅB"7\¼ë{ÖÇ�¾ëé»NÉïI1'M‰ÖbsfÜqqR£w@I·0JÔi-¦‡œ³£$G�2j†£-y9ƒ¤Hnö� Åi–D)%ަo'øŒG¥\ÐTqç}#¤óªé´èþ�sµq^³=áßüÉ{ìF~úð�ðü–†™‹êý„¹ŽÀ;›-¯¬Wíï£à÷æ¡—ÖËBĉ•÷íøö茟¾5#~¸Ûq£ïÉðâÐsÇä…J) Îñ#F|ûé%;\·L�­XI„ïù·g ã—~üUµ lÜUr®EePå™*Y¦_æªYjÔ�‚™çÔj^d‹zÓg^5¨5ë¥éÛÏ6Óµy¾'¨¡Uô§JÔI+þT @eÚµÔlIK©ÓŒ1;Èy�>Úº»?×,È$l›Æ—yí¯çžíVÔËbÚÝ{ Ü^bÛjÿ¯kgyv�È´ÅHœ§Më®f TÉ š% m\-®•ËÐéSÚ"ˆ®m§©ó£×¸‘,”$�„,F.8×Óu‰ÐB¦ì›½#Öß4¾ÄÚh!0¬s”ëÏ~ö×ßûá×pâùÔ'†7?ù3MáRïÖ@¯ ^ˆJqdöµße·»â¥Ðñ¹õoÒ9×äAþöÝ[tÞñûí?æÌ§NyïJÁȃàùÆ“sJ)M®ë�<"–›G‡Ü^õüÉÃ'¤R¸=ôüÝïðÏß{À&%b®QÝsÐÁןœsá0xn÷=oo6<Ø�~ñ…ÛüÙã³’~ü耇۱ýýhœèdÖQ2N|éÁ#øØáš·c*ß8>¤iE”E´V@ëf…&�R�W#­�»ÀQ¼g€láÓ§GM àñ8*†¹Ø°cÙ«µpwè[„8@ïcʬ¼çÞñÿíßâ±¶!ô|î'�“ã—ØíFµ_œFñ‡Ð3 kú~0�d…IuÝœ³Ôþv#ø5mWk Dâ”ɺ¡gèún øA·+ÎÀC}{ç)d˨9ë˜À¤»ÌÂ*à ÐËV+ø ˆêXS2ÂI1}ÿEt°úZ¡.ƨ”ãHL;bФXÉ•ÙÞ*Q稪Ûîú@ê|ï4û¡_Ñ÷ƒF‡0g ¸`樎ÿZX6¦¬²„âY­Ö&Bpt½#¦ã´QP88¼ðþ€躎®ïèú^£ySäõù%ÎÏïó½o‰¯�[î…Àg‡5±”Ö¿�»°W»âc‡kîov�ljÀ‡½v)ï‘Ú/õX/®v17Ù«Ó.pÒu|×jk¤Rxër¿fA•: Z3¢î{«ïøÑ“cþ͇š �K1’b¾ž?~ø„)g‚�s-ëठüÔÍSΦÈÊ9¶9óþý¿d7�Ä\@<¡XûB¿ ¤2R °W£Ê=©vÓD7ê[ÛÜëZ,fÖÍÄ}�SŲW+)Öt{—’°ã-SÔ¡%5 _<Á{pH)�[QY1 �w O°y\/%ø`cvnÓÚ}Zÿ Úe�´–ž`ýY�yŸæ ÃØ“­^ÈLÆÍq1FÊ4‘ÝH×{ßµlŠ(¶^Ä ƒÌ,‰¡C¬ øJ-šœ“eY€fëXaæš™¬¦»ú¾É}ÖHéDŽQ‹Ҥ˜kÄCŒàŒøYf 8IÕZR1ð^è:ÕàÇ-“eO]^^2Ž£’!UK\ø¸¾-÷¡Bñ¸>h€�SCœ3lÉð%(5óRÞ¯è{ÍÂL~²¹_ç@ŠàÅ#¾§}è q*„®$†.ÐùC”„2œ!%ÆÝªûî(bÙ‘xÒh�'ÖÖ®êœK „5‚ ÏeM)±eO½ûÞ–/å¹¼x£'‰mY{Á™�“caÚA_D#ô¥§àáïryþˆ¸½$�[\ž†žƒ¡&Tgz™8½9ðÚ'ïñøýçNìÆK..žððá@¿†õñÒ­L‚ªP3=°à©jJ�þ§­5Ú½bG5Ûw)�Gͤ±fé‚Sá‹Ù¬þ� uÄÍ�ÑÈŒMÌcj�(4b “M‚ªÔ€YQb Â³º½˜®b?2Ûù˜ôTÍ–¯­º‚µKiíÓ‚aš_P³˜ìÞÍ­˜‰TT{Ñ8:'UŸÂ¶[9Öë¬7¿X»goªn§Ss6ÝY¶ÖÞ™ŸÏ¾7¢³ÁG í× $s¾kPV­%£5ŒTyÁ1˜lÞ:ÀÐ{­{(ÂÐ ‡+ÇÁ ô½ÖCLAkÓd›7SßWJêzïèûÀjè;ÅG‚×úsŽb~–:©ë][›ç¢RYÎä\5HLªÛÕöÌý¯Í‘ìÙd»LB¶ *×|8UPY ¼4ùáš9?gTÜÊðß\וBÞ/>ÜžÈâ—Ö§,•¥:”KÄ¢îSŸzƒíëçouÛ2ŸG„Zb\ ݬê*¶´Dü8¸‡‚ {ÞéŒB^û¬v¬åÑ®;¿2o¿Ø–åXXDöš¤ÝÛÿŸWÓ!3C9-’¦Ä¢Y�’FìT¡}>±2feÆ Êœ6¨ú\ê4Yž|ÈΡ:IË< ¶çÁ>SVß&—‘-C !¢©¯SªYE‹gíð¹hŸ/:ØZ1H«‘PlÀë³™'Òê”'¯€�ó&q%sñ§ªa™*1PeŽJimÕœ JËÀ¨Ñœûï8oÿÚgíA.*\ë[ûŸ›+cÆßÞ‹~÷ ip½»Ù‡¥{÷Ì5,{¨¶w¹¶ÉbAØûªìý:¯»¶á¢¯-w.{sÇþøh‹O}®R'•ùdÑÓÚx­°ÓÝ“FŽH»ÔzÌkäMù¨góÜ›nû´«¨Ä¥Í z*Ýg^KåÚ±JÅÃÛ3¨„wBª÷Ôô¶.4b NŽ8Áäã.i?µD*ãléÚ©\R@¾€FQY–�éz-sßMáªWéd‘AÐ ½et>Ó¡¯Ùz_è\ s¶Á_u½Úge~ôNö€À–Bi\‚7 ]ŠÓÉQ òxID2±(ØÐya=tЛŒ�x§®ã¶›È8&• (ÅüÇ„“¤ }5ݹ¶pŸ3¡Š‘994’e^óÅœ$•KIZ¤(ëþBVr ®™%Rò¤ŽWL82"š™¡ER�FuNk,²+ b[·Ëš9Qi²ßû÷8Ç玎ZW½œ"«à[ÁPÕá^¾*)�Š:%µøðÙ81–Â]öS)¼¿™%„~üôxozÍ oSâñ8ñÒzE@A�õà!¿rïnÛvåÝÞ|óéS�ºÌ.¢IþÒÓY[ù—?ó NÜ"¥×FS©ú쵈”9¥è*U¡r–¥Ñ¢9äÚÜ-ÄXšì…‚ý5*qŽ*MKÃö´@‡*—P÷¥TJÓ¢Ùëï¥Ì6�³¹äÿ£ìÝž%K®ó¾ßÊ̽«êœ¾÷Ì`p#®ÂEH�¢ 1h)(‡Í�Cv„/a?Øá';ü7Øþ ü¤GGøÙ~°ßlɺP7PI‘„I�¤HCÀ`fz¦§§ûܪjïÌ\~X+sï:ݰìꨮSU»ö%w^Öú¾µ¾Õ×WõyµöõVÚØ‘ÕvÝøj)‘Ë5,�ÄBºµôÔR uè¥�É: ôä!Í´6�eM\ÛüÝós ·�u"Ô>_¯QöêåÀN¯omèöñ6Wmûsy0·y"­­Š ’<ª;Å�q¨ C%ÍJ(âÅü|=qû£gl{¬3ª;ª•ŠÄÈ¿õ—þ}¾õs³_]mŽÚ:]Û ¼Vh[øÓ·¾ÃÓgï2ˆðžßå^ˆ|þÎ9/VùÏçÌt¬|ú|ÇóãÌT ¿öîÜ?÷ðsUþÈ#ôéõG'Úç)CÆ ì‹‘xÿüý©(¯m7äZ{Í‚/Ü9çÎù}×ï #_x�'‡#G­dU~x}Ãì há·?|Žªò`x8càWÞx�ðÞ,}4\ϹGS¿}³ïra"ÂM.ý÷_ºw‡ï_\õï¿tïϧ¹ƒûS­=²,£¡‘›˜«öŒ‰&oÖÞÇx8½È,pB €É£�§È½³-ÿÝÿœk¿æó³ûüÒ/üGl7÷9'Ðè÷Ñ ¯ŽÙ?[ËhS/¼éÒ#1ZdrÓͯÕÉL,­e:fòT)Y Û�íæÜ¢dÃ@K1ë¤@ßO¦0SÊÌÔêhAE Ñ#¾iËt"H4»¹T¼8|¨ÍŽ�Á$R¥Ð ƒW7¦­x°%O”lÅ”»¯ÑP²Rre»Ù™|H-ÛÁuć´éœ͖YÖ“w‰îϨÌ̹0Í‘Èn{F)3¥Îl¶»ÝÈá¨:!¢®¼eÏÆsÆq$ydo©•Ã<3Ï3_þÚßäâù{|øôÏø‡7WÜ�‰Ï§Ešo¸e¯ÿøp\lÛn: Öúð[—×��z~\ `<=N<õ~øÆvÃû‡c'$¾rï'>lu¢Õ iÄ@«÷˺Ùä‡>¾Û’kí}ü³wÎø™³ßvÒmªÊû‡#7¹ð�ós~ûò’œ�¼ÿôϹwï"i¶‘ JF)]z:f¦©.Ä€?G¬0c“³…¾6u®Õ›+à:Í� Á^›ž)…i²¤ÔײêÄ€¨�¿1F¢J0Ù­uQï Šš|�”¾�÷ScŒ.k‹ëØ»ìDH�L„ªÙ¤4b°"Ø›Í BÎ3µ–¾ôÅ)+r ,k+–QTÂLàHˆ£ÏBŠf§Ö•� n(€¶uÆÆª´à™àQ×5ûüãµZâšc.&±cëo\ÐZÈu6r±Z‘óR‰ª¡TT"©øÌÑ‚‚€„À0$Æ1Qê@û¡æÌt<2O–Efä£8A9@š!�«q_�Ä(# CrþTrÊp�fz„�…@$ÉHMÙ|®V€Y=P*cã`óY™ó)†Áj™ �2+‡ÃD.•œ‹T¢÷aµšˆ¥¸%!�VÏ*Jb,ëÆî«äµZ…wŸyúáŸ3ÄBŠ•¹Vöº£Ž6æ*–]2O…¹Â¦ çç[¶ã–’­= 8�¼öè_üü§ùÔ§>Á'?ùI¢(OÞy‡ãua˜ ˜¨óÄþù3.Bäòòž>ù ×/>bÞÏÔ途™ÍF9»+HjÄÀŒ[>ó¹7ÑéC^|øŒÃñŠ«�ˆ*™=÷=âî£×L:V[çXešz`t›³NIh7g«…xUÖ²w Fds‰;ß ë�ë”K~CÓjËžqÙ½F¤uo~%ÝÙ¿o}Žß©ÞÊè¾�®$õq†¨6¦{AáîoT·„ƒ]°8 ëmÁêì;hÕ/Ñ�‹Y³;­µVß Ýÿhãg…Y-øÐ)tòhþÆ­¨!éxÎ˾J?õûSéu”FcY�T¤!žÕÈà`5M·Èn0leL •ÍçÛÀn„Í(Œƒ¸º ,YÁ¶¥adÜ ¤†€P@gð,3€VœææUíÁϪ ©šßé§/Úú„c34bÚÛ³V#éÒ¾—Ú$N¹xYšÝ2´u�EFaiîºÜ7i ªO²Á5 [z°Oô¬A|o—ö¯'}mã»õõø¸]3`=/®çàÓbn­mnÿööZߥ÷4#êå>øòVëÀ£Oõô»õ1ÅǦÞú¼]·}tk2÷£¶ïúÞ¶ì‡ë­ùÒu/c¢�ùÓ}¿t�¾Áê _¹]ÛK»Þ®‡)ëökm±ŒÉWõ§íÞgÉè×¶jkÓv¾K¬Ï½“7DZ ˆ¨×X ÜlÆj@k G%Gå @Uf/–º�$n`4¦!Sɰ"JͰZŠ1µ3¬¥’µPb¥Ì•"bRÑ4cRP†ã  Écì«Z{u [mÜIYšÜ½ŒÞG<ŠÙ¢ð¹É7îS±/–ÕÚ}¨Vó ¡©ž-eaëÑXî°KŸðpu}Yë 1TR€½øx-–ÙÔ"t‰”b‘†Õ3œ[æ‚éñ©Gƒ7Õ㘄1E6)0F€„ýÙ¸o3̬¯4ÃЊ­ÆpïžÚûÌòV±ÂIb¬À?þgVxø •ožŸ÷Þv[2HX‹÷öÞ\e ¼8òúf$¹óvçÖo£H'žM3÷†Äè$înº¸ÃµY›:)0y$â§¼ñ“½i£Þë\Î3¿ýáG|ýñ~|4°äs»Ï'Ý%{ÖW¨êúظƾ“±e{{öupm‡ÔeÍXµyÏ�ò†nEˆÅ³ìzj¹¿ž ´¹^Í ñl»lVˆ"¤*H H5g˜Òo¯óPkãX{b‰x¦€ö>Hs/Öóµ®Lª%ûs‰8Zâ5ô©°'ûÕ6vYÌ Y¾_¢œX8Ûmˆ/ĽŸE3[ÿk7¬‘ üésÄz6¾=g¯õ†XÉØéÉËÊþ\vÕôd%úø­Òë3ÔR(se>*%+h$H²ˆQ±¢Œ�ÅDcÝ Ë4F ¼PÚ$¿0&·´¿X"Ë6þ¾ Jáƒßá{oý+¾1ny�Ÿ9;ã7ž>ã:¾|÷÷6¿ãàûÇw~åÍ×ø ׿œ3÷Ç¡ƒ…rqÅyм±Ù (N3|qå$Â}Þ¾Ùw©�_xtγiîE}¥PÚ*.ðbžù;?y‚ˆð¹;g<=N¸ÿæ£ûÌU;ø¸õ"åíû¹*¿óìy§¶¢H'�g)ñ¶Kšœ¥È/>~È?YIrñ2fsµ"ÆQ,*ìX¬.‚_p�ï>_2ÞÜnxoìr+—ó|Òs­�ØÄÀ±,`î&޵rwHÈ&ñßÿ臮-÷î>æW~ù¿`3œ“sR4 ÄÄ�FÒ°aFÒ0R%xñsÓH6à.¸ÔNÅTŒ¼è= Nµ’óŒ Ã@JƒKgŒ&­ƒÎ}FP|N+ÔRÈóÄaÍqº¦”Ù IÛüb€|ìõ2v»sÐ3bLඬ ï¯5£:£u¦”BΑ íE“›dKÕLÕ žM“¼ÆŽÄD ‰qÜ1Ž;»':¬¶R`ž-›«eÛülN}^E�3ÇãL©µB†Ñ‹ŒÎ¤Á2ªfæ¼*!F“+7F É@àJw¢K­„ùæ·þ+þù?þ[ìožó÷¯/øoî?"yÿicçnJ̵rðþ¹‹‘Ç›�·o–:·d©ZB` Âu.>v"Ÿ=ßõÌ0bàéqêÄØ®nN$ƒÈ?„ÀgÎw|ÿòšÙ ·¿öÆc¾ûü¢×¨ªä•­þöõž^Ý0„ÀÛ �üéÅQ„_tbàý¾ÇÝûŸ0}öêÙ¢bšñ*jé½wƒhR)-„jò E[d°tI?iQ·ÍáP v‘f†#P«g—*e.–% ˜­æoc´}Z/Ó�Î J�Ô:`r:F&f§72#³é'äÇu§Ä00Ï“eK÷¢Ý¶FÆd²Oâò1YÆŠÄH~ 4ßÜlFmd“˜qcþ�L.9;ØhV¨ÙIšl4W+X’�Ølmc"„‘ý~æújOÎþ‰G±—LÖ+(‡­µOŠ´ÌÕÊœ3–„a«#1"Q‘X‘¤ä|ÍqMаÙDª%8Œ]f¨–�¶ pçî^{|��ì Ü»ËÞú!?úá� K”BŠ3Cš·•Í]Ï q8€ì©5“â`òtç[v÷ï°½'LÓ@Pò‘Ãþ†ë‹ ®.^ðp�¸™PmÅÃ+Ó|àòò’ÃÁ÷¹‰œ�oÙlD*×7W\O™Ëì­ã‰N¼™“î-f¼};Ï̵ڑøº°Ôhëßz}_j|8âª惚´¨©hW÷ý8ºúE#Ì—mßû¼ç}^4,àýÊ3êõ=£ô¬7#±{To? ÞMš£$ÐÐÖÖãF¬sV¯}ü²(­ÚZ›ôÜ&ú>àt_«ï—[Ú­×U·iÛy{Ú»—»CûoݧôÕÛžüJZTºõöõ¹µ6Ôå^>ïvq'Ç|Õcz÷Ù\Y…оòv/[Yïÿ¿�—²#þ í ¼¼˜½r{áÕ÷Ã\ÿ¾e±¨Þ&ôÖ_«÷­Óˆ:Èìmá€q �<¥v;&¶›ÕŒ…F  æ@(ʬÅ÷i¤™ˆ§Ï:Q#F¸1±DY¬æj5 Wj%‡B�"�"‚‰@"Š0$qb 2Dœ¨VÄ3ø ,’!¬ï±÷‡Ö¯êz½�¾í²ö¬nK  �H¤P¨"˜à¾Â.ÀÎj1D'6%xÚn1€ O•̸³"Ë&qÅk�äêÎò`Î�ŠGó¨9GÍA\b-¸~³]Æ„Í+Þ¼ ‚•P¢?ƒ˜T›IºÛûF $—UR7Nûœ.í¢ .ù&®‡vu1ñ;¿÷>÷RâsÛ-U•YµK��÷V`ÿëÛÓ:o >p,¥güÑóKþ⃻ýý>gÎb°¨<às«,‚¢ÊYŠ]®è_\òÅ»çý\þäâŠ7¶>æÇ?K‰ÍJäþ8ðï~ü þîGõϾõ¥�›L}5ÐÖŠVK7ˆc°è^Á^M?Õ왺ù—q¯}½_gE-ëÄZÇS‹ÝˆoÅ YÓl§%-Øæ4m¡zV3ÔCïþ�§õñ¡žÒdkì¥ÍøqlÝ»�½NÎ · N{¬í*è²…�P§MÍ'ëÏ ¿zÛæÂí&é ðbGÉú­1—µ{yè+v|{!jÏváÖvë“o6ìj/b2-ƒ1¦Ô\ÉSa:êld§wNîˆ7ƒÅ3pãÒ–Ú%]µµ?IP[ªñú:d¼`Û9PØ®øÎïýST•onvüõ³;üòk�Ø—Ò¥D&­ÜM‰»)rá…{ï£Ü¦Z¹?üú‹úýƃ{ AøÎ³<;Â'Îvüü£ûü_?yÀM©\årVþ˧Q°‚¾w†ÄŸ;¨øå×ñí'2×ì¤Ä–›R»ŒÊ¯MÛ<c¼·?òÞþHá+÷ïòÖåU&鵇¼w8vÒ º½Øû\ø§½|oHÜ”Ê�œ4øÄÙŽª•÷\BhŸ:Ûñ'¢*ðÃëS©–z÷ ÂèµZOùønÛå‡À$ˆŽ«ßkåá8r•„ÿñí·ûy>zðqþíoýçÜ={@©––‹ !9€d@bˆöÞ@µy%#´‡µV‹æÒa‹¨3I 1À; Dß¿EÙ[Ä¥6»VÔõ¹k1YŸÃኛ› æ| —Œ:•Ý‚šŽyëãªÕÒé-»@¬ß[$\¡ê„Ö‰Z&Š8)©‘Ê<)eò(h�[ñ_µ¹Á´èÂpÖk%ÄhYµª×(̳õ—67ùÐÜÆº´¿9r<Î iÃ0l8;;c·;#—L.&#ÁÚqHG”âm?8‰0ôöÊR³I«Ù›Ý}¾õWÿk¾ýk‹ë’ù?®.øOï?´ì ï}¸Þ¾ñºN.µÌ˜ÏÞ9ã½ý±ÛÞÅÀB'¦Z{Ÿm�F¸=².Ù.¯mF^ßnz �º> |ûýQU·DéY ÷Ç�/Ý=ïµCª*_{p—ßü`frpö«»eÍÿàé÷øü_økT-äj™‘�±+Í; IDATlÕÒ#%Mšj ¸í`*Tî§Ö™ª_Ù pvÐU*Är5Nì>4òBšÍFHMF¡õ“)ô¤¸”ãhr[© Z´÷ÉL©39Üե·¬ÖTï?&M$0 ž©ë>w°¬BÁ³ ‚õ}YôL*¬�g‹d/¹ý½)¸ÏYæBž¾T+ÔB�jóÊ-`ÈÞe”‰R�¦kö{Ëò¨e6 Œ4xfÐ@)ƒKoÚ^j)ÔlE—[µ Å4Þ«ƒŒÁA®F åœAMÂI$:‰8¸”/Œ›-ãf N\VµþB $¼]à 6w¦#‡ýž‰#0{& †[„ºJ@ÆÍ†S C¢Ù-ð0HûÆÖïªK�–’gRj£xÄêS”lEÛ�X5©ÉLÉÓqÂ,ºÈqªÖ7šü¹föÇ#ì©l£eIƼ£Ûªy†(¨ë—"„ Ĉ E¨E˜J&­ßÇ@ �Še(Ôb2Ë›qàÞƒ7ùô§?É—¿øy>öúcŽ×™wü"›1'`� GâY&n&BÚ#rcÒZáŒÍöœ³{[ÎÝãüA`>ì,‹ Ìö×\]¾àââ9ÓtáªGУgíFö‡=Ïž=ãúú@­•q¸w÷»³! ûý ϯžquŒË�N ô€�.w¹á3ÁåyÜ®œ\ôà7ã;¿+;¬ŒbߊPê¾´ç}»/]=‹¶‹uW–†•¹Í[¤‘—ÝßnÑÿͤVCïâ)IX«UÐàR`-]}pw°›Ó žÏè»-K¹=Ìö\Šåš­Úƒ¬ æ‹;!i›HÛ=(È/âdIyÅúbÁ™•&õÓ”$×3'ÐŽªøín¦µµ`sAì}!«{(ŽG¦hྑ‰ó³‘ó³-wv½1p¾©lÇÄf$*Ch’Èö»!¶cˆÕ"ÍÕŠˆ±’bñÀãÖG,SáD]F=ȧBˆÖ�r™™§™¨Jòù3h³ý«‘%ãšç‹SÛ¤Eög#0U �¬&AKTt?Ë– úm8(-ˆ*t·C ^·ÒÖXõþ�NîB›H×༴ÏWßc_ú›¬ü8=p½Ï°tÄÕNú¾¬»3î(­¬NÇð#1}¶&/Ô;‘ö]�:X¬î jïòøåhÄV«Võ÷ëHï[ÞoßÑ)¸Ú£§m mBê Úi+œ4Gs¦C@cDR"Dõ¬`í…žû$(‘„¥]%ŸÄ›hH–EÖ¶s  ViÛ ‰Ewt›.³„‘l¿í»©K»­ä�ÖŒkï>.Ý“ ”"èJcVC¤ã\+°ÝðÛ<´k‡ÊºÕ-3ûÔ u8ø‚i~Å1 2{*¿6pÈ:U' 0" ï]ý^ö÷§w«¿&·ïèZòèUwû”xj ÖËÇ“Þ0·¶_±¹·�¿tg7äÔw~þ¯ÆPÿ¹Þê›ë}®™ç[çß&#|œŸìûdåxEKhªO”vÍ ‘zåHù©‘eÑ<áOU¹}Êí�e›Ûçµún½mßèÉÜ!·~Û÷¯«O´ÝÎÓQ;xiF§)�7Ä@®¦ \óDÍ“E"yÚœ¸+«èfk �lmi…ÍÞ±Ö jSk«ƒÉI¤È8D6›ÀnØm#»]b7ÆCÓÔ1´Vj²h·CBk£@¯=ÜÚÃŒ25BÁ�#mV�®f[�`°?m TìÙŠ.kâAÞCeuŒhN©äl7ºEcåâŒ5¢¥e3UÏxª¥vY�F¨IUWB V" c2)¥1¨ÕdhÆÆ# –fIZÔ²kÝk»Öj$„äjó| ó~Ú87�–‚Åïþþælíô³gg¾Œ›[ëp#ªÒ&°Èƈ�`R×ó)1ðÕ)ðI�öÿhšÈJ—:ÖÊ=¿à›�ôm�iu.ßxpo9N)½¨ñ\•ß|úŒ_zýI„?¸Y@¼¿ô¹7ìžT¯ ½ÖUuÚ4" E‰R)]ÊBÝ1¾¨ßÓrkÌÓ§1¤�#ññ�ƒûæ—¶¹ïê>G*hµÔgu¹)6¨�.³ìŠöˆd!’+¾*1Vb(‹òQ³;ër–ksØ–g·¼{ºÑ­¶^¯ÜkR@—ת•ïüÞ·™¦÷BäWÎŒ`ûpž¹œf>q¶E^Ì™ôÞ|êlË×ÜãGW7üØóïã¯óbÊ]Êd®µÛU¨r1Íü½wžƒð‰í–›\:Øøsï1«òG®W~H|êüŒ]›´Ï!¾ûü‚¢Êà¶äo|ð ÞÜm8�‰·œ¼x}»á?äï¼ó¤_ß(r¸ÿö³U+v*ð|žy>ÏþÒÃ{üÞ³àüâÝsÞººáÅdsßå4ŸD;_çÒI�GãÀ³iî é§Ïw\̹˯¤ØÆØXà„hû‹¼VàÁ�xK3ÿ³*{í³üÜW•@2€LB—³0k—’hž¼GÌ–Z™óL-–ý`µ ,P—Ak#¸Ô¦Õ$牔Ã82Œ‘˜<'x=­2ŸØ³¬è®iyG¶›Õ-)‹š°Ž6¯…àQübk­ä<ù[LªE—HiiÅZ™)¹¤´úyÓJ¶Ì/ ¤déù)%†”PÙ¢a‹ÖÈñP !ÛïÝQ¯µxä§ÛA{ÍòµíÕŠˆç\½}iH ã@(‘X Niø9'R²ì Zæ—,›‰NìD¿öE¾ñÍÿ˜ßÿ�ÿ�?›'þÕþ†¯�K&ÞÜ"«EøÄnÛ³_ð1²úß¾9œa­¿ ð±Ý–÷ö‡N"üÂãüÁóËN"„õ|¸’ÚxŒV¼ø‹wÏyzœzÐǶv!ôñpÌ…w÷Çn�+Ê?xç}+j<+¤ª¼6 <�g^<‰™a3 ¹ö`¯ ¶.ùúTj�’ ªÎäbbð~äBÉ]ÏßìZ�°T:�ÕÝ×F¾E#ȼï¢Pò ˜|ó…Tæ^/E©FÆ«gº6_)€ŠÉèäbQÀÒ‰Žö[¥ÖÙ Ô·Ý7+»"Á2!,KFP;{_ ›iYŠ“vU»TXÉÕjz¤D«[ÔÓš™7Pgʼ7{‚¶,j'ªU+ó<1MrÞ£x‘Þ`R¥)Åž¼gQó.M§&]S}¬š$&&ó©¸ý¯]Þ²6Bà žF„ZÀRðl¢%ãiủ¤�ˆÁ²’‡´aH[æÍÄ4OÌólµIË*ÚœY=‰Ii‹È:W× ]ãk>8¼Ü‚)´aêJµf“)UЖÙ)™ Ót`:¨51çd¿ÓJˆ31ÎFö† µ†^Ûı…œ'æé@EHC¢ VgFdì`.™R‹ãV�@[?‘a ¤l¡l©LÌj’¥¦êPP�vÍ5Qk¢äÈt„Ë‹ƒ\puyàx,Ä`×UòD­´Ü ù’œ_0MÏ™òE¯Íru­Ü\ÝeÚ_PÎj9ÒŠFWÍ¢yv;Ðki9ÜdžtÉÕåÌqÃã�G�ñàÑCvww|øü’뽋î³gy/¨6ÇUZa`[ ƒx�ÏŒQ“P² «æ_Ërß]a£Ö÷‘CÃÌ:~ ßï/tüªáo†QØ<ÕìXÜïV�„h¡6E]Ö~¿›ÁhbmÇ ’¢©V8 ]Û:T,“Éê‡ø¼ê5|&²91¸�ÙçEÒm5iÄ€.õ6îÎŒôñ�gKôvéI&Y¬^ ¥í·+<¬q=mÍÓì˜6×~žâ÷¡;º¾�v?£¤öµ@Å‚üÄýñMâ8 ã<àn"›A¬Px* É0•!Cˆ Q­N€ØìPµ %/2ëµxæVIVõB¬&ÑîCOïQëÒnxðž ¤@¬J¬b¤@)KàU-žñfó­Yê=yz²sUÝŸj�o8^ìéF†'�¨ölAû͇óõÒÜÃÖÉï Vc`qºn=º¡%t —öE·koqÕýÖfû]÷Þ×ûo µwY�¼²tÆ„·¨ÔµS»Þ¯ÿ¦1�- «µŸzì7ääd–g'ºSÉ­èé_ºŠê¼Ý¯x¬›eù¬M.ެEIQ[ç Y*Y ÕªNWm)ÃÉ 鼄-�°"G-�¨¨±É cæCŒ]$ÝÈ6 Gñ(ÙÖ6€Q{Ûw9’>§ÚDfE†±z%¸„Ý׌†nr .s´~†¾@i“ïj²‘•œT»f×è RR „àÑIµš¡SƒMt =•°±È´[¸¤”­£H_¾‹§}áä[iýèåmÖÄ�¶>«œc!]^îPzÒ—m™tXX€ÍF ¼TËàßtU¾ÛWfÒtGOÎeu‚·^O÷Ѯߞu!öx•ÌϲèüÔkXõäÖ‰¬ãLO·×“ö|éDo]˲¿Ósmø\èDTÛj1¡§æV—0K"†@r]N­•y:’§#y>ºcËXðsiÙ2mL¶Óô§Ãj÷ªÒ¢ÞÛ&Áå‹6›Èv›8ÛEÎw‘;»È�³hu’8_'‹ UÓL¡ú‚ 6n¥6ðoÝPNƉ™!,2¢-bˆ¥/yd¼ÓÛ¨f #!�05‡­Eâ†E5¦€l‚*1ŽÇê_ ÔJœMW؈Kã�²ÉxÄ#B÷¼µL<0É Ž™$…A c61²ÛÁ¢ÉbP(lwb ¹í,zr“A�2ah€Ëý\�!Jå·~w¦¾z¶DñµÇíL�¦ßß�ÆádûMl¶ô¿»?ðñݶýû—×¼±ÝôߟÅÄÔÄý·�¸ÎF.´L„L~úÜH…çsæÉáȃûvü!ßxp¯“ß½¾îûýÆgÞXÒk¡ƒæ�¬ë ^·wé{ꆔ×!Öî„·G�àµ=,ùDúšž4Xí ìíߢ‚<YÌ©‘¶úº­’‹õï”0†!ÚÚ”1I¯£cñÝ$îl¨R©R=yÓ#zc·[V[m=ƒnWuC=®æ¯• U{ãð²mÆb5ÀÿÔL¢g´ ØgFºÁl¾áò£f€5窓¾?`µ¢t§ç¥¬2==¶ßÅ~ò¾šô ¹}êv]Áj&ÏeäO!…È”+)X´P –ÑU´I)´¬"г;Zµº­ÓNe›÷û¡Ô•Ö§vPì�ÿô;<ûè ; ü'wïó…{wùävÃ?ó¨ùOœíøùÇ÷ù‡ï}Àe.$mÞÙئȿz~Á\•O�ïà�ý�‹9óh3ò—?àwž~ÄU¶6þ wïðö;K=›fJµÈÌ1þüzÏ[W7lcä wÎx{èãú¯¾ñ˜§©“C]j àù4ñí'O”³”(ª]ëüÓç;TµË«¼¶ùü�sþÅK�Ô– Ðßyf¿=O‘ Ò3’?÷è>¿ëÑÎ`¤ÄóiîÁnïî�'E”÷¥tÀõá8ô¢¯í·OÇÞ“J­¼¹ÛòÇþ÷—‚ÇŸ|óK|í‹-•yš ¤aÃ0Xf€e „4 *]ó[=Ê6Ï“ë—@ž¢V ÍvQ�È=H5˜ó‘qŒìvvœ˜ J%`û<&Úb²º[êÁ3CQÎI£PòÆ#šUc—í-s ðB)3hAK@‡:ô"†B¶(9ŠEAíØ-Ê/{Ô›Q"»Ígg;Óm�‘9Ìe$Ï…9ÏXTk4¢¬4ÙD¥e ÕüBiÒ[-‚O,øŽˆ„J#q°cà@�¬0"ÀØÔ%gFDŒ Ñâ3¼È9ŒÁ3›Å}¦È—¾ú«¼ûöðþ{ÿšxsÅç‡ Sb¤ƒûªÊ{·È¦F ìb¤¢]ªênJ¼¾Ûðgä+VÌø½U²Àw>|¾äL‰t`#Ÿ8Ûößüâã‡üÖÓ�˜¼Ï4Í'²XmÛ!ÞØŒüdàí›="¿óÆcþàÅe¯Ùñp™kåÉáÈ7ÎÎøÇ/^ Z¹ºz—G�†9+9Ûš'^ËÍjîò4“s%†2¹![´wbpŸ.ùÚe‘êZ¦�ù¡µÝã~û5˜µf¤À�FÓ¡�ѳc²�á)8ØV¨d¦²Z h>i³�KÏÒ+ZÉ5S)DµLÝù°yÛ¤cè÷ºúÓ?Üþ  :uS5P<@až ¥Ùõjµ6æ¹Â@"õºQ�¨0ù›=yºáL®C1�T ãEM*Ç$3͆HNœŒ£Ik5í~›‡f:v¢FæÍó‘iž¼`rA¢FóJõlŸŸf‹¬÷–Vô|·Œi“»Q›×Sâ0áŽ1$—XÝÙ|6MÇã�ÃaO®…ÍæœíæÜ%Ú,»ÏˆJ –´¬b· dñ‰æd¸H+À^P ä–R¨²doǤTÝs˜.™s N¡»w!B,ŒiÇ8ºœÛf´ùG-»‘¹Ót@�y=ÀKðz,;n�¨5¢!yÿ‹8$XÖ€„q$Ô-µÂÌDT!Yë™â¶r-�ã¾pñü†Ÿð>ÏÞÆûOž±¿™H©�RñL®#e¾¢Ÿ“q8>cš/)5²?Ñ7|ôl俣×9Ž;æã5¹NTò’ÝH¥–L™& „ÁïE�vÝpy‘9ÜüÚãÇ|ò3ŸæÁÇ^ã�÷>àÃç7\\_"^W�–í¬–é†60Üæ»$Ñ|i™˜™ª–¹!by,²˜ƒ'~h“貚?Ò‰|nY2ømrè�a�+¹ÞD¦Kà£x-¡¢–ucöŸg…°g3‚¬PYU–lAiõB½Ï:)`~¶ÃFÃÁÔ[ ù*âÙÄÁƒ\¬Äýïö¾¶l„ê!™ÝàwÅjm¾Í´„êó¼²î, žõ*)ìf·‹Òñï–ýe®¶öy>‰�\ †€qÙ1³uÆ$ )1Vl8EËÖ7écaHÁk,ùšíDúx°x«y"ç¹Ï¥˜|O©‘Xƒ&†0˜ÿÕ÷î-Áá}]Q%&»©(±˜ ’I-¶ Ëœ+3‚xbBÂ`ó•ÃÆ¼&›6B`H°‰ 9¬Ÿàü\ *§6'Åû”.¾U»MI¨ë[D¿Së÷]/}uOW¸Óíí]gå­@¿Uí ×2XÂ~ˆ°j;¡_Ð öxûÕß( ¶Dp̨‡[ž`=eå´sŸÄHsúX¿_œØ˜ëzot<ÚÒr^ÚŸœ¼µÌ�hAcRE“O\N ØâmQ-ðA­Ó¼ºhqÙ!Ë?rtJâÊ1_§=Ýjoáô½:¨QÝ`«VL'ÏÊœ!g!çJ)�R[•u±‚Ù!x€§v| †•¶^ëui¯Æ÷¾¸ï[¦DŒVÀuHVL$¥VÜÅÀÅ^ÏÀAÄÈ-w²¥�ÉI<½ß}ÉèFX‹JïÄÌ+æÂe‚\ïWO¿o}Èߟb6ý —±Ô6¸î¬�Ô‰.Vy[ÈÖ‹ÆÉ9­Œn7×{mDÍË-t Ú¯¾å³v:v³¥o'àZÎÉž'dÈzx‰XmÒ¯w5Ãy/£¶'Ë—·joVûé©q/ßÇ%šIé²X­OŸ´qëÓ‘–Vˆ§ Ö¢”\ÈAÈ‚9T“¥Ñªš,CtÐ%ˆ9"–†ŸÒa°è$U#Z€�.Gí  �§(–Þ=ÄĘ ðÞŒ‰Íh„Á0Xô¬±ê­Mj¯%‚�Á(N¼µëQz4èJAJ T¬\ƒ.@n…Vh�’Ð\Ð<“¯ú¢z–‚ýdDÔô'£E`ÖâÄ|QriY–$<ÛH¼ÀˆïÓ$—´ÚÂm…ÏLæi3z ˆ!1$eˆ3›1°Ù&¶›�ífd-ŠÁ"8›¼š³Ã‰ƒ¼D¥7Y“1_ÐD}Uÿø­ß¿òÏÎ8”ÂvíïV­€ö>»ƒ¹–úÁÕ͉,Ð:k,Ò°õô©V61°Á¢^ÿðÅEϰ}]óù;ç]RècÛM×àË2x}3¢˜–ñÇ϶õø.ÏÏLÆÁ�eË’¢nèY±mºÆ0RÐ|Z€¬ÍëÕ#\Zª~íRÍpÄÚ X½o[>ž­�-‚¦­íËÜÞ‚,@£Í‘­Ü­ßתh Ä@ƒgêµþ¿D©˜s¹V&]*ï¬V!Á×ôU鶴ðÙ²¦Ø¹.”(èI`7šºã¡l¡®¦bY½J·©'G°c.¦mîÖ>ç··=ñm½÷c¯AŸöhq2ºZ`}f–e=êÑ4Ý2XŽ+JÓ4ôZMâ&á�§JÍfÿ¤8ZQ²‹^Ì™¹8!…vé†f–"Nx²zÊEå7°÷‰6Ç­ÉèöxÿƒóÖŸ}€¿q~—Ç!òØÇÇ6F¥°+êûx3ò`„müúûþÊë�¨ªüÖS“äz8œñ•ûw»dÐõœyëâš!·Ä›‘o?yŠ_¹‡]LüÞ³ç(ðænË/<~Àßößεòh;v°L2,×Ê&˜üI# ÎRäë÷ïñûÏ_péE€¿õÚþä⚟xôôu.'3Û“ÃÔ‰€7wž&ÞqPõË÷îð|žyâßßÛ;1�UO4Ø�ž9p7% Ê�Gÿ·º(Mº,¨eýXøÄÙ–_»¹âo¯¤Î¾ð3ßà/þ…_¢d¥Z³B¦~QI+$º¹ôõÊíŠ^8O-k/bbh>ù’[K±¨^ר•`Ùrí9Ï{æ©°¿9²ß !±·V‡ “Ùßã`Ѫu<8f¤Öè4µÏ…-PÇ¢ýMNc.Z#µN¤!’’Ð ñÅ �ÝF¢×ËèxÅÚÂ@Ü-ãpn gŒ¨&Š&b¨h,>zE£Z;yB.Ç›î|í6—;Q€ïÌybž > î•\É¥0O…iòlÚšOÏön@B–IÔ`á¶¾Â_ùåÿ–¿ûþLÇ+þöÕÿÙÝû=å,Enré-_ºw‡\-ŹÇúß—9syyZwà{Þ‡ßÜmùè8õâÅŸ>ß‘DV5;*W·jüº‰wRB¡¯o7|úlÛI6TùÌ�3Þ={æÒ^\q9g’·A«Ññx3ò5'Þ{ç{ìÎ_s[©ú½M€’ç#³N–Õ‰e}”<ÑÈ�"ª¦ïoÿNÞ`Qæ¡Ú˜2ÃïIÇ{—uÕ"KÕmã’ ótdšö.'„G€f�øn2�²ðÓbvµ‰5—Ì\ Á£¤ûZߊö „eîX¼íàá<Ã!©d:ÁïþyuÊŠ…{€�$ÆqË8nl|„`™Ey‚Z¨e²kQ«Û�8éYôÑA¤ZZQ×еó­MÒGB$ÆŠH“³×@Æ&ŒD.“WU‰D´˜Ýl6½0a¡·–ÁëÂS¢ªtù¡ZZ¦ĦÇîŸ� QMV,™ŒÙœg†ag²iÑÈ‘%ë ýݣϻ۾P‹-x¢v‚ ÙõKUj‚T3Œ\®E»ª�ª‘_A!©‹‰†eh ¨éÿ§tôz3ót`7è0t¬F(�EÀk –)êMIPB‚bMÔÈÙÚ;i! ŒAÉA,Y±Žû#—/®)Sfˆðââšy6¬j!Æ�ó;wØl7„d>̨NTƸc³ l·ÑtÖaÜ œÝÙqÿÁ}ö7&ys}8pØÈû‰Ä ‰«7\>¿á£®™ö ÙÈ›ýþÈ“÷ßçüþ=î¿öˆ1m8ÛÝe·QöÓrÏì Ãæw“ÃD1­÷õÝ<ÉÎÇÖ 3ŽkùMKiw[¿ƒÅøgÁާí}#ë–µ`)2l†oÃ�º=î2÷3Ûï|ޝ‡)B+8Ýæ6Sðæû©©fÔÐü ñ¬£fwkƒP–áÖ÷k�®]û ¤ÂÇ­ƒÅÒ�ø5¢Ë_þq¯g€ñæ$X{u o³ÚìdYº±ô{Û>6R£‘ ®f…àS ¤¤ŒÉ€ÿZ¢Õ[u§zqÉÐO‘,#š3ó“ÎÏ6 ‰jDZöªÕU*Qª.ô¨}–¦é?´ˆ|ñiÔ�½¥a‡XZ;D�iµì-�¤t ¤û˜Éï] Èà€l÷а`q 5¤ˆ¤ƒ@Ä~cÆóV1[¬ù`¢Õjtý²–‰³Ü“t:ŒÜ‰ëC²Í¤«Ô—ÐÎ6øn}ܱxô¤ç,û0Ån×»°®^W“�wô]6Çu娙C·¾Îõ�~Ú ü”ÏTkì+¡ÛËFíûÕë­ýt/Ó=‰‘�ÔªY§]Ôµ “Zj“FË84\Àiilg´‚@Á …æâj+Œq{øòò¹5ǦšF•K”›.ã y¶×yr�9Õ*n CTŠÈ""tí1° ƒZ U]²pV¤µih-iú®Á`H�œÔÀÌd:ëÁ•.'áû¤³³-ƒ`í¬ß®-°4Är×Ö½¢ã%ëf{i|Ð÷Ýn¦¬w@“©¹=>W©µ'ç´ŠÕÕÆr»�­ó“Il¹ªö6ÖoÚ>W8úê”^u‘·€ù*ù1Zjlÿ°õí 4–Š,K+tRä–!ÞÏo¹_/ëÿû6Í4ì LÛÁBö¬Ï© –U;¯³jº“÷K?�Õüå è‹eñ„ŠE¯O3R ”™yšÈ³9F“¯‘(” ”h™A1„hE U¹˜~fÀ� kp’'šÓ[ð%/0ìÑ…ƒ§õ�Ãà ¼cuðœ.‹VÛüîÄ@�àë↹�-’¨µzhÑ[‚­”ÝÁnMêã¢V4gjž)óDͳƒ!bIÓbr p¶ð† HôúM^,�ª4<¢Þþ&Ac¤Æ ´ÑÔ%›â@r™¥Í.±9¬®U IDAT¢®lRb» lw#›í†Ív‘w�P)¨½oWhb[´�Ú øA²ø2ЙíÕÓÎí·¼¾@áK»[ú‹j— +@zgHý—¥_ßòh¤@UKßl@ý³ãDérCû\xûfÏ—îÝñcÓ ·Ç×�$Ø—Â\ÕŠ×9óÏ/ùÖkû½~>ϼ®›ž-ðýá� ¯|ê5K­÷¹Y›ã‘;!„îÜg©Z"‰æ¶†b©¯ºZCÕfƒ6æ �³íkŸṮ®jŽkÔe~°õÃ瘺¬ý¶Ì/¿Í¹ž±R*šC H�ÄdãAâÊ@°¤ /·_Úºìë¯}è _7LÕ»Tq¢i‰Æ9í?Ë8ëÌÊÉ4^Y]ì•–ž*²Ä=e•%[`ý�6OTÇãéýü_ž¯WçûÒ:³|§«-l«pjÁz@Y=�#™„�“†yªö3y@­�ën;²�„q(¤Y‰!‹zà�&^ÉïùòXR�Ûœ�zM 5pÊ�‚5™~8Þð{ßý§|iÜðæ8òå;çüëç\çÂ'϶|õþ#~÷Ãç=ºýW?þF—ª /¦ÌT­`ráÃiæï¼ó>g)òɳïíüÙÕ5øŸüïÜø�¸EØxª¬Êåœù—O?"‰X/U{Í‚/Þ=g¡k™ÿÌÙŽ/Þ=çy�à¢ÊUÎ'Öõ?yò”ªFplcè5ÎSä›�ôŒ€ÏÞ9çbÎ^Ä~rs`^4A° ŠŸÜì¹v`ôïñÎÍ¡¡Ê©•,õ„:yñ`Ø×Ò#«‡øêƒ»ü¯Ï><©ò•Ïÿ<_ûÒ/‚j4ÂÑü©g ã†#ªVÿÇdü¼—æ%Ò7FñõÖZ,Ù¤Ù;-µ½ bvnuM÷ˆHåp¸æâÅ××{nnŽ iÃnwÎf³a6›� #1 )^�µ�S#0œŽ¤f£äy"ËÌ4e‹ ÎÊœ…M²Ahzç`ºÌu«¨KÙX3 òÁëlˆÁ 3·§‚Ëð-ä.Ð$‚RÊÄqf¯×g:å6Oµ:�m/¥p8(Å"³‡d29ÏLÓÌáxäpØSd«[·›š$ƒeê»ÌIl £ûg*ܹû&?ÿ—ÿK~ó_üOü(O¼5O|a°Ì»»ÃÐÉ(0�=‹5 áÑ­"á?ÿøÁ‰„ÖaUœ–L<vN@4ÂîgÞãG×û.ôÚvd*•kïãÓÌ÷WRDz–ÎÏœí¸È™'NÈ}ýÁ=v1ôº_Ûíúß<ù3½þ#œ6#ÛÍÈv»!†À~¨ÅÀá Œ˜ç£û?•:&Ð#2H"H²1L’£ÿ<Âײ ZAù`Æy'±´švü~ÃÍÍ¥kÿ)`‘ïÓöçÀ»ŸnY.VãcÊ3¥¤dBÍ ˜X¡Eà.êÚýìv_*-²¸Rk¶HP,‹(¥¡Kí1©ª)*u£ idF·‘-ãqvé­™ZŽärDuƈ�L©H.[ÖdTb„"&‰™+H¢T-J?E¡´('BˆÃÀ\,cYs%äÄeyÏʼn«-âë™Ë¾Ä`2Nã¼vdžã\©SñŒ„Œ„b…=£áU—ö³ºˆVû# V\}ÎBBd øS<¨Õ[´±¹òÝÈSüU|fs©áf›Ûži�OP��I£z6U1é 1Õð„Š¶¸n+ŠSb 2R —Ìñx´{xþ:¯WÐEA¤÷bX^r_lHJJÊv6c@«ÕNÊs%O0D«50F bŒ.¯$¢–½Y+š�Ô¬h�Qíz‹P¤XF°T’˜|š6¹Í`u�b€8Dâ�l|Œ¡E~Ùkô¶“Ö±:Ðcx‹÷3©îh0ì¶Elº/’�HH È��¦ Y�‘œÓr79�0ÈËO±Ñ*–µÐ´X!vÿ§ ZûýhÈï 1ðSý-iÝD^úª÷´µßvò8uÕ^–ÿÐ¥AW¿Xú§Çèõv–U£Ër|dq’ZѾ¶½ýt_´¡«h旜їH�—ÝÕõ篖šQ;n5ÍÊÇî¬RÖcÇ�'K?Y22l1/¥23RRÄ£ô x�ÁëoÐ" ¤1 Tݬø­1ãQ„·Dó*Žà!òÕS´–:v�Z«é‹êrýæÙeµt5#Ý™WE‹RæÂ|œ»±RD“j\o½EE ­ƒ›¥–bW[D §J’®Ñ¾–kõ ÔAˆÞÛys·#þÁõžÏ�Ÿ5L“;)9ác�³;)p1gî¦ÈÝdûÿþå5�7#�D8”ʳiê™ ç)ñ³�4˜je¡g´¨à·ö‹fÂçßx`… ÛZV1CÖ×<‹Øòú1µ¥‡»Ü€GÝHÅ*EµÍ@¡÷IëÏ<à`¯°²# #À}ž°×ŠKb…eæVŸÿ›¾²9PO±Â¤,‚C#Š9d”Eÿ�6—â‘Lë¹³1-úØÿ¶)M=óÅv­v>=ÊILV¤//°­4ÍIõEVÚb Kÿë¤@Xˆ€uäLôYÍ«U‹®}F�d±oèwfY—mÓÓuäd²möR3 š è¶M?ž¹Â\©SEg#D)‚N�´339a¶› S±](FÜ…j5›j¥ëjwâXô¤¹ª¯Wëµ§¥È7"ÁÌåwþï¿Ï4øxøÎïñÕ{wùÂ�3¾ï ö¡T—x>g�‰ß|ú AøÊ½;(ðÇ—TU>}¾ãgÜãÛO¬Ðè>>眛œ{¡âýâ’C­Ü‚XÏ‹ù’×7#Ÿ¹sÆ÷.¯;Øø×ÞxÌ÷/¯N´Ñ×ÚþOGž�D^ÛŒ<ŸgþÈIƒ¯ß¿Ëu)Œm3ðx»á¹G,KåO/®ºí$Ào:Pù`‚ð�ƒ¦Ç�/ß»ÃozF„wSdmwýáG'äç•¢"ÂÇw[ÞYé½·ší·W9SV¿ýìùŽÿåÙ‡ü½)ðs_ý%>÷©¯P«¥7‰³R*¹`v»gÆI5�ΰÊâµ9¢Z±T,½Ý}~p2¾�÷’ yΠ˜ä†`Z-“`žöì×�æyFPJIälÙq-pÆ"l=¡“§`X|>mZê®§­æ1”h×û�A)C0 F�t—[®:ZÔdS‡1n0]ð€Ö@”�qp�ObOÿ·¹Öe%¨&YS¥&'\+JéqBŠ3"â2'³�q�"Í.ÝXJq)°K´`†ª�8XhÚ=hJÛlŸÿâ¯ðÃ?ÿ¼ûÎwùµ›K>{ÿ1:¸~oH'™�6#ç)vpÿeÁ$ƒ`© Ô@þ]Œ¼¾Ýð£VP[„/߻۳|À¤Šö+B¢ ߆ÀkÛ‘·o«³ýê'Þàן|ØIƒ16+}êVè<‰pw0¹­7wfsìkåòò}Êœ‘4t¢Õù*jÆê4ªŸ˜db�� ÔLÐÙ݋Պ=ºDÚœÚl fxÒm¥%ZÞíUïŸí©ÚjF5÷ÀúUQ%¸Þ¶{~„j,·�g¥TLª¥ûÈm]iãd™ß›¶ø9.�v«b¢î{·'B‹ìô¸ÆàA!4ÛÅÖóI= ïÍ/8?yýµ<~í»»gÄÝHÊFV ›-aØsœ3‡iÏt,è,ì_˜?:òã·Þã�ÿà<}÷†šRØ�6[bÈSáê⊞|@•‘ýõ� ·ÞãçÜÓU[W¸M œ8 "Þ¼¥÷!?Wÿ[: ¥Ëû—Æãj2ö>"ÞOO#å—kX [/¤€ô´É¶­�÷*Ç�Ö˜äåÚ_zèú�Õ³ž2XÎOE ÙÂhýZ鯷ÛÝúÇzZ7G»ˆõõ¯_íW§¤ý[�‚9Éxù°6TÛ_ÝH]úDp�‘;1Ç¡ÌÊ<5À¸I–&�<2XE{$’ˆéK\;7xjÜò›’µ±ü+½|е±ÖÚï­ø5—\ 5£2ÈMG/„*^ !Äh)nÁÑ å£N…ù0Ùü •#uˆÄa ‰ÆUK›ú€‘ЊpZJH v ‹¼•u›[hK¥Ì…2¦ÃÌ´ŸL“Ðë°ôbæ˜Zªi%¥À\„9òlšÈ¸é�è £2n”q„q°bÃcÒ(ÄQ-"a£È™ ÛD¢´¨ˆêF•Z„{ñô¾\¨“"Zè:íÝz”%:ÁÔïþé³Þ¿>µ] �È>FïÈU-øþª¶Àýñ”4øBËÀϦ^TùÓ‹+¾z)FüþáÈî|×÷ÿÙ;gü?|½[³-Éqß÷˪ê^kí˹͜3ƒ\!�x¡ $S¦l)$KË/¶>�?�?ˆüà‡_~°#áPÈMR )š²$ˆ€"AˆÄ3˜3ç~ξ¬Õ]Ué‡Ìªîµç@kbÏ>{]zuWWeeþóŸÿ\ ÝîŽ&UñýËkÞ;Ýu‰¢ýø?çV¯L8‰‘¢Ê·÷‹ó{î2çJkí~¤Í¿j ªÖ›£ª±=:Àï= `ÝDÚ¾èóÖlMí¯…àá@³Ù¾6;äÛ´å› lóÈô]ÇÒm¹ÅÕ�îV1`Ç©˜~qOÑ»¬Ôïêâ2uS)ËfdwœyâƒTK¦æ‚5]¶^Mz‰°:†KêhQ4Wgïx²Öéj~Óíu5ÕÖ|¼q^¾/Õ în­ü@­Ý¡6]A¼Ìûõ.×Mk¿öE}Ì—Ñ\…læ\Ë>S¯3y*ÔBP¨S fó½Äõ‰[Ýñ½‹«ž€ø[o½Á·^\ô¿7Þ0®=^L3ÿÎ AŒ!Ø$„îoFµv}÷{›‘{ãÐÏàb^úý5œ–d‡¿|ïÿË“Güæó…-ýË_úOxï“_ ”Ùzh¹\G­0Ï\‹7¡ŒCd¬T )mLÛ¦CÙ$/%¸ô¥Úž£›,1†%æC6•Ñ�,Ð%PKa®Öh´” (xßR¸½ùi­­ -ÁƒVé,CÛS÷�<_½€1d äDŽ�œ‹7(J6°R=+êÀ¬úrHHŒÃ–q³³œD—ïS$%6iG“ñ[öj3JU�ñÝl“¸<Š–ÚÏ\J!&Ò0Úš–@©J©3â• ¥ÖÅS\k‘»ŸRCíR&µ.€È:.¡ýKˆüÊ_ÿïøgÿô¿ç"ø'¯žóßœß9šgk¹Ð§‡‰§‡~”EæçÓ§'üøzß%†Þ9Ù2×Ú+dæZ{¥ >7þèéó¾/sé•ïœì¸•b_)·Ø÷ÏþþÃ'Šõ(‘Õzx°Ýðævì½Cn ‰¿yÿ.ÿâÇ�xz8ð3''üáŵÌ̇ ÆáZyR®ËX¥I™m ½‘å 3¥ ª%¶ýÕV•u‰‰ÝƷ꿲"4Y)‹ÇMÓÜdsZܵø¿ ‘ Ùdõ ÷êÇÆçšiý·¹ÙI.ËÒâ¯è›vü^[¢+ú|÷xØË­á­­ûZñ¦½tY¯\ª¯ýkòaB5£,‰¸væ­ïbL~uÁ~¨FƱŠcÚ«Jµù‹xõBhN€%‚bœIºAcFÂlþª¶Æ½‘’Mß{JB.“5?w2Ug¬?X%FeˆP¿o™i> [Ô¯¿õ}Ò¾x:îaûmU—>S»n£Ö¶ æØ“]CÞW]ë£5ëÕR\aC±è[©R{œeKÕª=∠[$íŒ l¼³ƒÚµÝJ$†‘ ¥ì]B)SËDŠÉ˜ãb`‡’ɇÙh'œ;Õ™J±{LRöd·áÁ›[îœ ¨&./ÔyâêjÏn·åä씜 ó4“6™±(È•ÄõTøèñsNß<åMI¼yÿ-¾ôå/uäêÕ_pëlÇÛîqÿÁ=Æó3 Ѥ Š0ÍÊÅÕd=/&eàÙÓ ž<}Áw¾ù}¾ù�ïRËÍ;6à Ûñ”“ÝŽ“݆Záá‡1•À“ç¯.…’G#iú:¶ä¬º¼õ"K>'DjïS$$¡ÌBž±9–=ÌÓÛ¾¦Ý–»<\¯Jë¬õµ…×U|¾à# ðo.¨".Q·Ä xâA•Ò“QP‰ªÖûó9¬xð^DÉä¸gÃñ¨F ”–to.¼'Ç Ã7<ÏV$ °àö›^tÇ.Áˆ± ö[æíÏb5VºÂ?Ž�´aª–îè‰Í¶Ví:Z*Â+a‚ÝßÍÙ–ØnNvvÛÑC ažöä¹2…È$c2YßäŒf{íÕqÉÉO/�í’Å<±"…+Còd“¨Ë8‰aC4>:jE2ï1y«Çl”ü­ñ«®p£0+š ʼn�aˆÄ1"C‚ÑÉÛªv¼Áö¾–ž°žžHxæ=?ÔöÓÚ¥šð$Cu"˜k"¸MOP¥p¯O‚u*7þnÛæú_º>Ä�‡ÿ4öœÏ?}üq3>z—ŸÏú¤Äÿm±–܈%ýs+ôUüùeòË�÷ÿ„“ûØ·ì¤�Þã9þl78ê5BØO]~‹gïÔ7±µ ™ŒÝÆRPÑÞ¨qªx°±¾Í`ùç›!Áå[ü§± ;»F µÒÂrŠ;XÚÁDTšt‘C«k0ÇOzéPŠjz‡ �ñã¯ïO+¿kEÛšA· _H)Ëw°Œc.ÅôK;Ãd0H»ª6&þÊj2vL×á?6‹#Ÿxë�ëjJJ¯ý½Î¬¶»±×%­£Ëí‡_VIs`¡æ->Ó% ðºŸÆ|ik÷5×°ÇöÂ1ª¾8¯=aPû:év¦Ÿ´Bs⪗T¶�ÔÕ¸¿Æ 4Fü2&¯ô£qZfN¿ ¯}´¼úò„®Î—ר éÏ·£g¡­5jí|­{rM]jÉ*Ìy†„R­\ó”¥�òÞ©Š•ŸÕ¤l†HÉ®ÉW›Ð*p¼W�oºÞœPÚšô±lò6R]>KÖx6=Æhr=í¢�ºª9ÚRVgq5'¡rµJŠ>tîø˜@§Ýà ±³tŒ©³²Ÿ•¾ÑÕâL¦v]�v›€-yƒF ŒEɵ2çÈœ3³K´ž»m`· ìNÛk0<Ž�M Œ1’!na'°v‚œDdklp úÓ6d�:¥T˜š�¥¢Õ.ÖýÌt]ÓP-‚þä/öê{cü\ç{=ûÂjNY$�šdPêԓ sf*…7­3#Q„Ï{Ÿ�öh}^Í™ ©öÅ4ó�‹+~éÞmŸþÂìì—–8ø[Þ@0�c®Úß;,ºÞŸ~ãœy.4²%nE;i�„KODZpèëÒ¥@ªkî£>$ôæ|mïl6c)Ü“n·ÌÁ¤'â{è &3Ñögñ1xr»%õ¤•-#Ýþ5¾V¹¯%z2Ðïw Lð}ܤ’ÄÝ)é6£)†õÉZ‹_û2é›ùtGÁ+ªÑà³ÙªšDBß„ª»-²8Ä��]Oc©°¦æºœ¯û¦9îs®í]žl‰�¯·âˆ>ƒo>Ú Zœ>ƒÏƒû_–hÔV­©XÎTa_ЩPg¥�A#eJ”�ML$aš S†C±ù%AHÉ*†*�èI�9 "Ö ¬•¶‹ÛÐ¥¹»W·HkY—½Ú“X ¼ÿð;üåw¿ŽÿõÙm>»Ûñk÷ïñ»=árÎUþö[oò§Ò)ðã+o‰}­|ëÅE•Ïœžpo;òý‹+ž&“úîå•›¾&×`ûuÉüöÃǼ½™\þëß>~†¿x÷6¯æÌ·�9üÞÙ)wÇ�GÎè¿®•ï_^Ý­¯>|Œªò–KŠ4†þ;»-?}ûœ¯zÓä¢ÊýÍȯö¦ù üñ“\y!‰ðÐC|îì„o½¼ð¾5ðK÷nó�g/;ˆz¨õ¨ŠÁXQÏRâ«%ÀØGûCo>¼K‘(ÂóiF€/ݹÅÿüäÿb•øÊÏý*Ÿ}×’µÎÎ`s鵆uµT£W÷Y“°†‘µê½^çris¡fcU¶&Å�U§j60IµÉ¬¨5û4¥õ2|ML.cb É“—«úã&�ÕXœ¦Á\Ñš)óÄŒIpà’ mkîw@µï¹!˜„Ðv³e;n‰Ñ’ÒÖ÷¥’bí Ù%Ù@A�(n¿í³”D)J€<[ÌãfËfØ ‡É™ÖbÁo«6Fpð8[Å ~;À@TŸà•Ö-¦k˜öÎÏßæK_þ¯øúÿ¼Ÿg.kåÔ÷ã6熸;G=:¾xëì¨7Æ£ýþh·ª‚(ÂÙ�x1ͽæoÞ¿Ç¿~ô´{¥»d ö6§í÷<ò×¢9wé¯ÏŸŸòðúÐ%´¾|ç¹Ö~.Ö³`©:¸È…þÁGî;¾¸Ûñ‡þÞù‚“íg Í~ÑHtR†19,-ÔÙ’Y‡g³•‚kÌ7Fx@�!Œ3ê±d²�Ðåø|†‘ÓþÊQÀÐd€j±ù@=úÝæH#)%UëBûÎE‚¯ hD™–€2y›Uï>µq0àÚæpôk±9iÉ Uµ¶˜D 1Ùyª-pžHüøJ@£‘bRÜãHp­þVe¬Þ¬6„Á*l„7¶¼U˜´NMˆNH ÀlJb:ÌÖ0;Ä€&ˆQÑ–\#‘¤ØŒ#§»Ä�[§¼q¾Ò5O?粪'C¡¨PC„8†Ú�ëÅõÄ?~Ä�·Îùäá'''¼óÎ;³gf¢2Ï °®^% 5¢EЦ,âóY$8qpÛt;¹þo¹¾¾h¤á�˜­jø¨ÇÍÇë˜ ÛѾÞ:&h7*Õ’#ÕÆY¤vÜÏTD¬—À˜„ÝÙzR`·9=1IϦ‰U˜UI2�Rd’ûýmOn³jq@ˆrM䙋íM¡¨�wˆÁ¹Ð¯¦LÉ*ߺOÒœÿ.WséU%³u ,¨Wü¬Æ©¦œÕ_´"c„�À,æY\®ÚìÕ’€’–”Hb} c¥%j,Éî„·ê1(Ðd›@; kñ¯ìtWRB²ú»Á7rãùŸôïÕs¶s­¦Þ2m®šA§¶ŒÊ뎳þþUt»ÌN:ÚÓ¾s}5²>‚Ý(;„ôg{ÀÞþë‚Ñ×��®Î§yÂÍ)² ¿Î~®«luÿŒê’Ö,Ú¥ÉJ×P蟡O¶˜¶c5�Àò%[ÎÜ‘°$´iã%Gâº7}ê&`1.k�GV ¦ ŒC/A4ç&„Átøh�–Ú­q¹“`Ý1ªk 70í¶¬á‚Õ¹µJÕžxhnbŒ¦‹klßÂP0°Ï�†U4`ZÝ!]’&à|OÅØº^ÞÇsûø±ºÆÕ´…ÅPËÑ|]6—‚×¶ÅôïhŸ½ùs“½¿ŒGŸYêB–û¾N =ãz¤ïª7€vi�Ñr½¢-ÝÇjLýUY±>>�Ž&æ¬Çk¨vÍÍ>ü„J„£G{½1*þÚÊ4ÜœQýZVÿ^]…ŸÂMÛ÷ñóY®ÿت†Vººú> NÜfÔeÝ×´M±éè%†Áš€ÕšÝyëຖQÐh šbÀs­Þ¯æl›P ~ìdº¢›A“0D±RÍ`åšAZú¶­g¶xÅC $c9Dw²ìÊœEUrg ¨kÅRÔ™P&` x,Ù0 ÑšðˆR"¸¬BHâR%«a/ô>-;(j•C) %aú‚+©¶›1™¦©X@jäiµ²æR˜rbž#µfªf¶Û‘Ífàôtàô$1Œ-á›X‰ƒ c$ì"œ8ôT`—l~Kü*v®ÖëÌ+ �Ì~z²‡Ñº¦!Tø÷«Š�ÏyÅÀ:)‹àò#KuÀÃýÄ'VB÷7›£­ïÖ�Lg “0¸3Œ~ü?{þŠOžîúñæZ=a°ÿíqà\2èP+c]~è¦ÜÐGûO§¹K }8ˆ7¦È陿 „Źö½ji$ßô‡[O,sŽê*1@c§{‰n üU�H¯~ƒš ïû( @Ð�O FÔŒu›H)Y@' ®3ÞVt ¾®Vw £¦‡!~„ÕìÅ>âìÉÀÒ× oì>.^ùãš§Ü¿hßYuIäjÕ¹º_Ù ä ;×–Op`Ãõ–4 ”`–�,ï¿q‡˜`;ƒsCü·4ê“Ï3ðöÇûýòXYí~üö\+! ṉ–Za&ÐÉ~3‹“(¬áðœ¹Ø?Í…ëCa?W³õÈÈZIÑ<èA#¹$ØŒ ÙRWÆâkä 8ir–Bv–xó!ìt/®.øƒo|€¯lOødxkyÿzσÍÀráÎ�øõ÷Dø™ÛglCä�žkþ¯Ü:ã§ÎOùçï?D�§ÓÄçÎOy9$ž&61òõç/˜‹ò`·aŒA<×ÊÛ» _¼uÎç}ú˜¯¾xÑŸû«_úUÞûÄÈy¦”™R²3å[b@\E Cbˆ¦5PšÌ‡å„39g—Â4ÿ¼æLqå É4Ö1ð«K ˜vñÀvØ0:饔™Ì̘F¶ã-•2g´ÌäIOh0V¤ÍFkæh€‚±¬s·§`œí¶o—2‘ó�9ïí÷¼gž”%X×€–˜qÏš ×Lß²ÛmÙl6�ÄTJfž gbœ¬j9È‘`±õï0¸ÄG!ÆÑä“‹ÄÛ]ëÝ™ñ%Oä(ã­™®ÐЀ,5²“Ú†�Ê@ë?Vr&óÁA†ä÷vcGGê ÝÁ†V=º¬¥éökWŠH„0C%ëäJ�X`á–›°unò< ÕÁ¤’½WE¯T!IêŒtª“|»ï%Ûžq¸ÞsØó?„À·¤8’çÊ|Á÷¿÷�—Ï'"'[,�; DÎÎïð©O}š»÷îrzvÊŸòøéêu¯"Â…€¬\%j%h%ƒ:Ùs$�‘4F¦R™Ë„H ňzåoK Ìr©äÒb{éD8#žáÊþÕŸo¸‡ý¨ûΙȒ`©?²9`>´xB¨Ã%ž°ýÑÒ "…mŠì6‘ó³-·Îϼ‚!ry±'ªÉ-²Èá$Àv_UÌæ´äbþB©^)Ó®C'¦… � ¥}þŠ4lÛüsKŠ­±¬–”\{ãŽõñqf~05#í¹—ŠùÊRi ãSPƈ%I6‰Ý&±£õí›ÁúbTÍT±fÁaŒi´>)9¡Òb·.¥^m‰æP1©å¬VEyOx"$T‹cB²÷G+U±¾¸˜ï }?ŽÌìDßT¼—@�%C#ói¿V9‘uðë è2ƒ£.ž@ÕçU«VóŸˆU™7Ò–ï`ô:áÜç¼z²+4›Ø*\ZLm矎�ºåñºg�žëι¿ãcÜЙý{-¸ogƒ¯¾³ƒg¶“Ú|Z@¾�}y‹TúŸþQ;ó£S?þû(•׌G;vÛ�Ú ÷'—’‘F¹å°ØW–�¬y˜…Þ¯ý»ÿ4kÐŽÑÀcYË7YÛÀôð°ëöMqÅ€hS׆ɎglæÔÇ¥ m+«DĆš±k§¡ÁŒc€ ‘`ÅR(Ö䨬: ¼ðJ�!:s'è Ñ~ÿMêÍaò,4#àÙqmNJ#°%)ER2VR©ª.àf-è8$šA´)Þ€oíÓàã“æx-ˆ!mÚ‹¬ß¢«¹Ù'ÍЮ_?^ëŸöôêu¹¹>éÎpmkÀÏŘç«Ì¡ëäO;®ökZç²J�CöõÀ¬Ö¯Ÿ«B/•o×.«·ëš�¯>¿û:ÐÇ_þRVÕëáYý¿sÒGbýêêÝmLµÝåufs}Þë;+ë13öÁ ñQ5C·U-Ð4þ�†$ŒÉ˜@) �sKÕî<%QR4ǼFùÅuƒf"уñ†¼bV l7‘Ý6²ƒ'èÍ‘,I°ô QˆI`â&‡‘“Uˆ8Y¢�†! iŒ„â%¢>O*•\�E�­J Ä@’DH6!—gke¼m^x8[€ª”¹’'«¢hìlÓlTR,^Ìö¤ès-˜>¸šHe/7mLÎ\"sI´>ãv`3lO6ìv†”HC$ÅbÀÏŒ ÙDÂ.!' Ùtãx-EŒ˜YV^§ŸÕÒ¶j±Œ�瘵ÄUô(1ðî8í—ØçrÔgàÖ�>-)�=IÚ@ÿ«\x¸?ôfÄ`Mƒï¬ä‡~öÎùѱîm¬Ñb®•ï]^óSç§Ý¹þ£'Ïù¹;·8õï°Ý%,Þ=Ùñî‰52¼,…gÎ^|p넚³Ѐwéêû_2«=.ñ¢:_Ó½§L_–¶jj]I‘µä«;N,Îÿ²æ¸wÿ¥À&?çÉ�ö\ˆ^*+=ÇÐŽi ]¯Î НŒóïiÝ–ŠïÒµñKÜh’ÎÞ—uRÀ÷}Q,ñF‰Í)U«(� š]<¿híÛDZ›º¥ V—J�…ÊÍjû~?Vô‘®µ'Áúdî ‰{PmìT¬åLoN–“cUCèDK²âd 1i÷–˜Ag5)‘š™ö0”ý>²Ÿ”ý\ØO™Ã\8äjÉB¿î ¼“0‹ Tr­,íă3g]UHRUJTr59ÞÄÁ*þÕ×þo¦iÏg‡‘Ïl6|éÎ-žO3ßyú‚(Âßyû>ß»¼bÖ=¨r–§)²‰�C±Àâž<çÝ“—9s:$¾úá#¶!ðËoÜáPjúÚ“ l¼Ê…—sæ$E.ræÖ8ð/?zB®•·v[¢H.?±ÛòÅÛgü·Ö\8ˆð¹ó^æÌ¾Xhýí‹+.s!…@b‘%9O‰ÏŸŸòÇÏ^˜¶9ðwß¾Ï>{ÁcgO“}y¼yͽá$%®rî@ÿçÏNùp¿çÒuÔß9Ù¡Àû~]s­üøzÏúÑ’;—-›œz–olF¾ï êOÝ:ã{ö„ßñ¤€ˆðË?ûk¼÷îOQÊÔ+ßh>¬.þ`�hicŠV¾®Š±÷ÛǪzjöcغW …ˆˆ�q¡³bµ˜§2¤�1�l† C2 ¤-³Í°¡lfcA{“U³ µÆÆ^NoZ¼îs¨¢Ì¨fj)‹&»6­öÂ<˜óÄtØ“óÞÀe‚**’ ]úç@#ˆk„§!0Ž&›`àañãçHöÆ�­R•ÕšW�aÌ=�Â¥hæ]#1³Ã11Ž[ÆÑY˜a&„Üÿ] &ˆ'G–yÒ$ŠbˆNz0¶pãpµ¸­5¬\Û©þê/ýc~ï÷þGþr>ðá<£Áöá(BQíàúO�ŸòíW—ÝÎÞ¯ò’„{5ͽ™v›Óm=½½Ûðx?1yáóg§ÌµòƒÖ;CZ�({dU~Ó›`þNë÷ñÎnËÙ�úúØFëýó»Yo’Š%&'šEþÍãg|þöY?þ‹ÃjÀMòΚ*MbÅ*2£Y¥f“|Ì•é0ëÕ}1 ±íÄ@!8£¢÷. ^!æ×£5‹ßb|`R4)Ä0ôûÙÖòÚë_š¯TkDéû¸¨Ú^9[2/—™3ˆõΊµ.€XˆVEë K* 6ëBt1ò‚¯9ûisÒÀE�å‚"Q‰U¬?W1©«Æˆ­Z ¥Cd3ž˜„–DÛ§âàɉ®¥èL!ÏιI 7íëânOÉ™iR(…T3T“ ªu¶DE±5Ü-ÐD-ñ7‘çÉO7‡¸ !y? )+Y0öÌì¶¡’ñ^ þQÕÐD (mñ³VÔ{‡uF__ØÚ�Ä0 ±ZÅ„ ˆÏ�'‰æã¸ B«BªÚú[78Àf¬KbI$�’•HnÆ Z'‡‰<úçÔ•ÜŠ÷|ªE¨YŒ©|Ôü§@´ª™`Ë4U®®31döûÊœ!çÀ~ªèu&˜`ƒ“‡é×9¸¸¼âÕË—¼|úŒy7ÊÕÕ%,‘7ïÉóÁzÅG¾äò¢d‡°(%0Í•)Wæ6ÛS6›½­Qö^d÷÷‘c¨ÄP‚² Ê&˜LÆ5��F±‚ß.ww›c‰�T”i¶½9Wó¤ƒ÷ñÍ~ *Å”+¢ù�‚8×·m÷óZ•X…¾žìQ�ð„/˜¿�KÝ´½NFád¹u2pçlã4@ŽÔƒõçµD1âš"�…n„:K¤Zr ÑÈ­3sÛ1=´hÉ;g««ÍYmë”Vsc6ÕTb_g ¯è1“»Ú—!b‰Á9 ËPS¡UJµ¾¡’‚U‚Œ 6IØzR`3F6C0,Â%ÍÀeÍD$ýwUµÊÏU—ªäR=é!H¦âI1¬0T5Â}ROŠ‘4Ä*1´I¤;V•êÄ%K?^{®o[ê¤b¯m„¾&§Ú0mñQ—1x¯¡A°ë8F�•¬6,’Fue×¼®^©C]†jõö(+Ì/ô½¨9@ÉÓïË—¸áü8×uý¸ ú…ãçÚ]�î<-i*wž×ÈZ­¬È›_º¼óæYéÑ«öôMãß.Mº�¦ƒuË›Z zô­´÷÷­¿–»7ä@¼,£¹² …[�åôZ Û‚¾³Z•@«ÈêIéÉ�T_»,ÇîÀƨªÒåAŽ?¿gáƒGß„ÚKþºz¹ ËÂjd@õ2ÆÆæ0'L<1œÕв·ê xl“³€^!`ƒ"M-ÄÏ­K;»7ÍiËf¢Öø¬––Á-”*ä²T'´Ìdg5wV©T›—>ûÍóMà'$ÑÚì¿�=Ñmõès`�(ëå§ýC´dZKܵ18Úlúó«ÏÝÛ#hõ—tƒÖaY' VÇo÷}Î _@]N¤Ÿéñ’Z¯ ×jy-Ç[�·°ØÿÝ’6Ú¯WVkðxœõ5¶fâUR@ú—keÿ�îûë¦À [²½|ÿDOºYb Ußèjƒ^ÛsŸùjýªƒ„–4sǸ½¿ÝZ¾V—�;;•Ê+´èß½¸7néÕÝ–‚%Ž’´²²z«kˆjÕ� ÛKj�“¶í5é[ã²ç®»&ô�£1¥4:SGz² Æ–©‚Lž˜A'¡Î4䜹¾.\_ û}âú�8”¹èÊó±÷=%!–¼ËµçbAPRˆDi·Æ>“½˜æk³7Ãt;üµ?þ=ž>ÿˆÓø‡'ç¼½ÝðéÓ‡Ö,øÖËWDÞÚmØÄÈ¿þ’ëRùüù)ŸØmùú³¼òfÂÿð�|Ó¾½'-Ô×€×¥ð›>â�“-UmþÑÓç Aø[o½Á�.¯ùî…­Ã/œŸ‘‚ô$ÂËyæÛ¯.cè÷﫞$øÂ­3æRùžƒëŸ?;å�“-¿÷Ñ“¾ìšnñ¤Ü¿üè S)½ú�® È¿=¼³ÛvÉ€¯¼q‡ÿïñÓ„>9LÌ«æG�U ÷6ï€ý…{·ùæóWK"`°$Ãäæå2ç.ÍòÙ³SþÉ‹gGI�¿ö¥ÿœ÷Þù"U祾ºØ‰¾ =°¤gð¤~´XÉ@…j Ý sÌÛú¶UÔ€e˛ԉV#Õ QÓÀvLŒ)ºŸmë DEÇÑ �WÔzn cÊÇ!šmóqÓZŒ-)ŠÉF46wÎ…\f²÷¨%÷j -Åü‹“k=»ÚN“ÔZ²sn‹lE¡:SJcˆ‚±(E*!FÒûØø™ÒŒ”ºýj1˜B Œº€ú1ƒ§€ÍÕjñ¶¯ëÖ´ÖüÂVíIê«›#,€š0E/í¯ÆÈ{ïs¿ÂŸþé?ãéÓïñÛ—¯øÇçwÞ9ÙvF?pÔÄè͵׌ýfwþÓ·Þäw>îï�gá1Îw.­y¶±árÎ=©ðswnñg/^u±/Þ>ãáõ¡Kt½Ê¹¯ °Ê™ßñïúÌé Ϧ©'Í~åÍ»Jå�Ÿ½`‹53Þ×Êóçpqye !Æ!’BDCµ}‹!#Þb¡¨3[=–T¬GŽbqž5¥ÌKÌÒÈ'´Šx¯ # µtºû�ªN²i>9 ѱàá„«2k±j ]�.ª¨$BÉÄ¡0x§ùù ë?½GèÕ½ ÆÉ9ˆ�î9OÌÓ�\fJ)®¹ï•µÅzk�+2·Êžb€ âöÃÀ¸9ewžHˆ8دÎvy±ýaÏaš8=9gHƒ%½Sôä—íÏu%�vØO\\\RçKWˆz¯ÍÔ:Y%¼!q-NÖS‹ù!s˜H¼6 8 =~!YÌ3D†1vµ°f*Ñ�å~�f B( ƒÍ£�HZH¢+Ù<íSÇà�…Ì( ’‰•aØ@-ÌR‘ªD¯¨îÒc.¿F“.ÒÙmG[;F@*%3gë){U–I[Á –Tâ0ˆ'Mg>.,¯Š­Ù±³X1Y)ñû#ûë™^óô#—W3¯.2•‘¢‰¹Dós—¤ >.iHìN¶ÌÓÄGRòž«‹üð;?äâÕKNw'ܺuÆ­[·† ¹ÂÕÕÄ«W×\_O̹²ÝXõÉååÄ£‡¯xöôšW¯f¦)@Ø‚Œ¨$Kä=|ø¹d^^^ò©9sq¹�!EO*Y<"®±Hma;1’L$I¤P‰£²!¢YL»Ý ²Y…¢Â\„!æ¢LYÉ­'HÍÐðlϼ’¾ÙõÖû³…ú½"'d{,Ù{Hu–·íY]^“D‹R‘PIN6Âù6pºN6.^ ›˜™‡Ò+þ“(spi(µ”•�‹õõјñHD^•”û~j—ᘓIxÆd ,³¿‚vlFBX‘4<þ¦�ÍPCÃcŒŒ§ºôL4ŒÍJj±,XeW ‘Z#é%90Deti¥1Y²2 ˆf#/Õ‚PL -,6¾í+m�¶dM.µ÷þÒ"Ì%PŠ2Ga*£T"™$«ª¯¬ÕBƒ]mo)Pƒ'~Zõ@�Žˆ' pL¡™Å ËÖiÅšÝKVIæ2g2´æÆô$CPñ¶³6Æ�Deë“íF åÄñ¸FÔT�æ ‹»V£¿¾z¬*t¹ßòV³¤ зœDsd¥íŒëcu@qym Ø­�þ“*ÖßæÐ>Ò¿Õ_½ ¶Ý¤oþôO½Þ¿}9ެ¾m�´G¦º~‰8 -Ëd™Ê†.ù‚l½g1 =K´Š,)®.-Ñ>'‹_Ý* �Åêô!÷sm™=Y±×Úe8{ä¨h×|”,Ðn‡nÎ0]wÏ×osÕ†ºæ£´‰ç­¥4¸j�’‹’K¡+ÙŠ-XtVŒ‘˜ªÅûíà~•¶ÿ®Ê„ÔŽ_K%ç¦Ù…1ó\fyí¶ê�Xj7\]&B[cº1ý�=ú,‘vn®�voVÏ¿ÈÇžlëÅǽfY€×$Ö«âæñ×ëK±º¾"ú¦xc}tP~u¬õÚ]”vüþþeµ¾îí«æøi‹n FÒÑ"éçÑæžý½bæ÷S×þûcCÒ0¥ÕÝ=]ÆôøþN•£¿��«õËò~‘�v5öF–’¾Ù‰°¬‰†àsÀ€ù!š^i(ȦØJñ`ƒƒR‰ !±`ÊÑZ…œ-Ø“'‡È8ZÅÀf„!³>:�C“ü2¦_ÆDØ&Óý�±ÛI Öà[ŒÑbN€®l‰Ï˨3P„¹˜3ÇDÚ$Âv@ÆvìàUȳDœ‡ªHq�­TWbPkDØ´Ç[ó² Ýž•ÜÐJøW IDAT·Ï–Í2(Rò%Š—­&û=$K/ÅNb™þ1Á&ÀÐ1@46óàóØËü„‚Ö-“±A«¯hg‚0t;†Òåß´Vž<½âå…7��ø})lãR)pQ çi©xgwܨøtõÚEΜ­þþ³ç¯nT¬Êl�;ãÐ+ ®¼B¡Iýû¯xw·í?›f®sásÞ—àÖ�øüÙÒ³ ‰ðb%±ðàÖŽTV=H5Ö¡U„4fÙ²‡7` Ÿ±¯tUõf¡‹ý4ýX_ƒþ;D¬úÄ‚ãÍVWlÁs5`ªH ä¼¬_»õæPÊŠ”€9ñ1Úñí;­ùVˆÆ¨1±ò£ÜYoOYÕ@í/‡“¶½Ã÷È6­—D0-’±j�žh ƒö³Œ§Eþ»û‰ÐD†ÐÅ—èþ£0`$”æ9w’‡¬ŽÑ¾¶ûŒ~”Õ>Ñ8MËýlI�à˜„¢N¨0\RÌÿšñ^+bØ$5Ã4U®¯•Ë+e¨ì'eÎÖ€¼åN ¸j:ÔÇlë‚ÒK±ðI¦/­Õû0xUƒPH)”Zùöwÿœo}ûàç·'œ‰ûÛ ¿þþC61òËoÜåUžù/ èÿ¥{wxs3ðCgú^ÍÝ*')ñjÎ|r»åkOž�÷ÎN‚ðï?G�/œŸòÙ³S~ëÃ�¨ �öþÎ'ðo=庘„Ð�¯ö]_?áÏ^P1ñ®Ëð\æk’ÿàÝ·øÚ“g|xmkvÂQ"ýýë=î÷nv~­AêÏß½ÅW{;ú™ÓÆzUÃ!—ãæªÐAÑó!QTyî „ïmFîoÆ^I omÆ^…ðç/^õ`×–ȼ»zï§OOø�Ë—ü–÷~åËŸ÷Þýi¬!p9ŠYTú µäŸˆí‰Q€šÉS¥U=Å”HCBiNµíëvŒà;ø¤^e[-ÙoÉ“õîߨË/ˆ0¤„0BÓýÇèÆ48sDŠjQ“ý㚪{æyfž-�g“ñhÓ¢&ãMQ|<Ä™�ž”í6Ø­•ÛÛdƒfJ ˜ê_!gkªjÕ�N°jà•Ët­}†VÁP<†q{JrI üqÌÖE!ÄäúÜ«æÀc7R`×¶ÎfÆJ^m5HDÅú"@0 ÎõVƒ"¡“'wWÉëôý€*‹Ï\¾³ÉAXsK{­Ä™ ÖD<×lÕ “�—%(ŠlÅ*Ým]y¯<šk ’ƒ$b4É.«T°ó©.)j••y>p}}É8¨î€�à [-ïoœcìÖà|šÈÓžY÷³Ç$.ó£fsí•rưO˜š2ÏdOJÖ€’ŠMB8˜±X$7Q$Z‚»*N,¬5§N¸ðï²HÉmAOœøÞìrâ•¥Ny6¬B›:Rt¢ê’ĉî™,`“dÀ%]Ý3±¯ó~n9S¥£Û~Ÿ'–|Iäl½�P“Ÿ1¿ÂU4,÷·V›“ÑŠjþ«…•ý<3_^C)Ôš˜ge? v(#f–‚º^…l|OO¶ÜóœÓÓª*Ïž>åƒï��~ü——œîNØîNØîN‰iC©3û}åúº¸ 7*%ry™yölÏÅEápˆ”j‰YÂat‰ëÊ‹‹+«—€Ä�œÕ$àZu€T†QI¾¯xxa7Âv ÅãÒJ’@¬ÿœÎJ�Ú%»¿v.Ö/î00?•ºÃ~'ú�Ié ¡mvÝL XºªN0éM««“ïèS«&´=-zÿÌ1Á8n�%n�œ�N7jM¢)lS¦ŒJFs¦u\)b×£î—K¬¤¤„¦¢éÃä”"^ ¥æ£ªÏÏ*­ÊÑÏm [tæi»©zÜZ{"Á“4 {±£ö¹–T1ÿ¢1Ýc žl¼¡tZU ÆÁC°·¨ß('Û: ý>'jèjÏÈj•¼sqß½Ú(¹�#Qr¨$2C,~_¬�aLn·%X©eLÈ ˜º�ÝØ–@¶xÍ€ÿÓ4ØñžVM QŒô×è¦Îâ±CH^Þx&¾‡õ˜®ù}‚y*é^·3k*8øí N6ì ðêEwݓյ²ÜͶ;ö÷ðÆaVÁßúÀ«¿W�–·äCÛP�зåÒÚDì¯÷´==7Î×ñ!]©×œÖÇ/³åmÐ^ƒú}ì‚K¬Âaõ}­‚Ïh·Ã K´«â¨:Kr`ÍÞk,8×+s̸—/Õ–E÷ ©Å¨â!‰�z0K4v�ëNõR|¿Uc%7†þúâåè|d•Ä›}À\¬tl.–°FmÕ6éàLMgQõÆ�Ñ\›ÓCc ÐJ…R„Z„œ!Ï•¢ÆF+U,[ìFZW€‘% 5¶Y±…]݉´’+û’6åè¾|Ž‹¯Ÿ6[–æPíH«�óA;Z?ºzmu‘ +£½ZcGk�ÕùÝœçÚ�)«Ï4 æè÷Ox¬³åz_³.¼°lùnähU·ç—Ú]˜¥àÆCVgØv·°Çgß¾ªKµo]ÿJ7oõö× m?¤¹a=%¼z~ý¹ñ‰@K¶`¥oÁG�¨é•§Ø@l1gÎÞmC®‘Â�lW^SJŒÓä[ë $IlÈ%¹Þ �Ã4˜§V=#¤¤¤X-±�lÃn ߨ†²‰gÕS „!PSèMq ºŒA£¿·ûXMËÈFÙõZ%DÆÍHGâ8 CZdV´B1 B�…[ýžµYÅ}¥X¹÷œ±¦kÃ"MÜ̺-l D�z˜¡Ä+’±„ã��!OÄ`¬è”` 3üÄtV-ÐXLjr ![³“:ÏÔy† R �Gqö@c ˜£×Ê»¿óýE÷ú7ë¤Ð“s­&ƒâÏ_—Âu.]àP*g+Å¡–¨¾‰ÜõïÚ—Â.¯{ßUå/^^ð ÞlàÓ'»ÞŒL†,!ópà�Ý–!Xaåï|ø˜¯¼q‡ç«ÄÀ›·N8Ù�^jNs-Õ×nð¦S¾¾€LC:xÉjÛüDZCZוW Þúª•V"쿃:ÀïàAÀ÷™LöFת•’m3VËš¼ˆ±?„˜Z@a†E¨„d�pJæ„ÚS»ßIœ1¢æ|Vû·DÎZ#R|Ú6G¨ýÔö¼;ø¥{•}-¶¤@ÍÅ›’·}õ†Uì6tíD®ljOB4ÇÆmrs:RÕªˆ!2ÄH^¾|Êï}í7øÕÝ)u{Âñ‰|ãÙ Ôר pž"C&A2ÍüèòŠ÷ÎN1F\å÷=eÿÙ[oðá~â‡Î²ÿÕgŒ!˜ôˆ*s­<ÜïycÜðxšxk·ã×]Zäóg§¨,²?_¼uÆ;'[~Û«Æ`Úæß �©V ð¯=åªÎ’õ—ùõßÚnøôéIï EøÕoð;>îMN_͹�øö«KŠû­wÆ�'‡‰½�_yãþâ¢3úïo6ìkå*{Ã4s•»¡ªü©�Áƒí†‹œûëoï6Ò%†¬rÅNäÝ“ÿjÉ?}ºH´ý�Ÿÿ|á3?o€´f${¿ùÈ–”w†+íÞÛœ³X¶0ç‰9ç|¦ÁˆI€˜«Þ|›ÓârÖ¬4 Úä+ZbVÉÝ‚X¯•*)¶ „ÐØð4—sžÉ-qá€Ýœ«±•ó¹\õÊ>kºØŽ­!jÉœ•y2Íø"•š‚al±�gè2†ê�yÁú¥Â<£ß×oF†!9KÖÁÿ¼Z⾊jÍ6žs¦—HR!‘¢é 7õ¸Mhšö~gYÇdÃ�:øÖ÷ ppupàÐÒÇ¡¯hYyÛj÷@;9H�»ŸüYÞ¼ÿ9?ú¿{uÉ{~§�åí!ñô0Ñàú§7€û©T›ÿï��ðýËë.Wñ3·Ïxt}èÕsUÂJë_JO œ‰})½šæS§;T—êš³!ñ‰“mOÌ¥òõç/)^�€?ñ$Â'O¶lbäÛn#ÞÚmùâ­3>÷ò9ß¼ºòÏ_pk÷€ Ê0Z¬Y+š³õÔ(3"‰(¦¾Ù4€ Ìc\ Ñ„¶I žém û¢ÆÖ*7̾ŽÃ†¤�·-6ÐêR4^)Ø€ŸvW{ö¹ Ç��O,^Ýîr5ºÞ´Óš¯á ¥…{vîâ•dËwÙ÷†`šñ#2‡ž,)5SËÜ¿+a•9‹ÐL.³WT$DÓd †ãÈâ ®ªˆTªÎ”r°Ÿz ªéæ æƒ& Pz¥Ù�„q P-ÙbÄlŸE½*JÝ�Hh·ª‘÷t&ÏJpéž,y‚1zëÁ~‹¥‘¯œ\ÌÌE©5Ø>�ÙHˆÆ4×Eƒ½Ýfq–±¹*æ»H€ZÔã¬j=ÚAfÓ3ÏÕÖvŒÆtnþã:"Œ>¶!4ŒÆ€RªšŒ«(FªÞ¯lÆú(!%›­-q&Ö@��,qÜð«^Õ¯v¾¥äþºIÉ*¢ÁªÈ³ qìGJ�F,²ø©Ö‰ÊLaæ�»oðÓ哼õ‰sî¿}Êþê’ç/.xöôW—¦ÛŠjA6¨J¨uDÂŽ˜2•Èœ•ëƒry ¹nIÃ9eJb؆-­©uŠ&Óòââ ýáû Â~o�¬‡42ŒÂn—‡Áä~(&•Œa¿Ý@cw„d„²qwÌP“3ÚiÂÂ4[R IA4#ZÌÿ– ‹©·ƒ°Ùc}Hâ‰ÌVq¹TµDGÎÅ¥›Lâ·”J. u¹oêɼ+CRNNg§‰Û·¶Üºµe3FÆMe:d"3u˜(C¦Ls˜¨ž9ŠZO�àqJ¬ŠOià ¬2Ó’,U+ÕÁu�m‹›_¢ÁûÍæºÝ“ÖÅÖ‹6eŽö=Uœ1ß*n"ŠÏ7#"4»‚¯W“zÆ{’`êÉ÷õ'ëÔ,[hv:kHºž§xÐßó:ž1п³J�<[¦ÐX~Ò–fOvܱŠ1‡½Â ƒïml¡/8› �Ùcˆþ{Y;~Ž>ßëe1–Ë:9šÂG@¸�éʸö±æø}íÜÚ« ;~yŸ®¾¯%8ÖÉ®¶.^ôü¡~¬ãÏôæYꀋôËñµ.¢=Ë"Y‚©ã±Z/³¶—5Ü“}âVa}þëà tƒ�Û¶£g^s�úû4ôQoLå¾|Vö¸­ïæÔõäÇc‚I¥hZ¹ihÌ9,aç:ˆAJE¥˜^!‚8èjeÒ&s³ÙZÏ€ÖDo“’%Ϫm˜-4MÂ49+¥Vg.+›AٌʘªÛ Êðý1B2–¼ÉþÐÙÃvsüÇ�ƒ&wH� Â#C äZIÞ„8�#q`WM†Õ²€"P²5: fû¤9k˜ãV¼‘cž3Óa"F’cˆôʲ¶)è›rˆXoƒö㛹$,a�â€?þ¿y0T—²Í× %acQœ-LÎè쿳7°óʲ�’Í—€ƒÄ6¾M²1'¾ûƒ—}µŠ�¬µÇ«9s¾ê+PTYaþìbì’@íÑd€>Ú¸= ]âãé4Xz lbä“./ÔærK \äÌ(¡K}´7É‚Ö\X�ÇûC—3ào>¸Ç/VÌÄûwN8=Ù0Í…y6Æ\É…àÎâa;&Oø^Uª9ä´ëZ‚u ÷¸èA²Ûê ­ÒΓä€4¶m ¶%FOØQ¬ý�'²'šÄtaµÉõ®Ö…bÛ+>Ÿâ}Ù<3œ9}fñ� â²!¶?¨íí·Od÷©~}Ýw©ý´.ÕuÎ^icÆËÛ"»Ýé'N7jmn–ºÇÇJ+Õ÷Í”VÎj¾¯.ç…ÙµšßÇʬ}}ý,6TûÌ1¿K ÖHyªÔ}1?Šè­ L«•bÕ�h"¹û¥V*•dœÝo©´¤¨Ùx` ìT|j÷ÀÇI�ýík$H …HÉ3¿ñ/ÿOæyâ�4ð•í ŸÙmù“ç/ _¸uFá�ž½àP*¿p÷oïF~ãÇ�PUµòko½É×´›´ò"öµÅÊæ¿ùü%¥ð9—{¼ŸøÞå5Ûùï<àÏ^¼"»ƒp6&æZûù¿˜3ÏŸ¿â,%†Ø—Âï?zŠ?÷6�ö‡®ÿâÝÛlbàß<¶DÀ¡V.K±uàI¬ßüà#&UÞØŒdÕ#móûÛ±_G ÂÎOyz˜ú~ü^^,���ï\0¹ �Û›‘‡×{r1&ÿ¯½ý&¿ûðI÷©¢´d—=>¼^ªðéúè0ñönßäÿûãEªå¯ÿÂßçK_øŠ¿/›,¥ÌD¹æ6"ťޥù9æ’ÉÓ�ƒ_OE,10ZÒ[qö[´f«½¹r+pÛ¥ÖT°†B a†:x¨¶x/!4-ce3J]À kzé`Ö”TUܾNæ—är½²fCŒ5’É΢hµ†ˆÖ×ÔöêôÈ Z2 ºo]k‹'ë͆Éþfë۞ߘâˆ�ËóDö�5gK¸ #1$´U`B­¦iF}ÿ�qcA�Û5gŒ HíUb}}wÔ½ò6då·ûÞðå/ÿ=~ç·ÿ'~”gžÕÂ]×¹o>»cèÍ„øéÛçGZ×ÙG·Ôן=·×Öï亮}½ýÜÝ[|ýéBxw·åáþÐ�ÿÇûe]‰��A„Ÿ:?åW½ñ÷¯¼y—Çû‰oûz‹ºÜ ÀóÃÄï=|»+Ãýáãv:;ò dŠÎd�(u&*T¬ÿÆ0Œ˜£É*DéóZB« Y|P['ÍwkR7YÂË_è2U ¥L½q0ÐI'½o.ÿãag_ŸÍW´Š±¥µÖ}ò,>‹�«ÇE ëàhi8üÒHqɪ(ªFÛžlD¾ ,uF‹ZEAõ> ªHÉLóDŒÒ°!„Ä’¡w¶¯Ëÿ¨Î¨NÔz —½ÉõoHŒi‚8X¡�’²j¤„Ô*šC0{ šÁû…h T15ÄÀüR (ÖVE*’gRdï/R´R™Vɔַi‘ªµzß‚êñ¢” “÷f߈zü%-¦r¼¤‡•n™ÅÈŠQͲ½ÝÖyˆ¨šÏ¨"®Þ b(æÏˆš Ó’©aFÊ<[ƒeLz ­]ÑÃÈ…ª³ËLÚq–êQ�‘�Ôªù^É[+älÕe!Œ¤�,VKƈVj�©õ@ЉP'¶Câþ½»Ü¿�ûoßáßýó¤\ï ‡I9àúZ¹¸È<{rÍ”'ž?Ÿ¸¸R*ÂP!Œd ìÂåµPê–8Ü&býÒpBÚœ’K9‹%°÷‡™yzæ1pr¹;89 œŸš¼­�wEªE9ÝÂnãkÆó’*›M`ÜF�Õ¯¢aPÂa¶ÄEE´˜‰bX‘øü "¤Ùn*Û�2Ö wHö#´jþÅnÔj¤Ôi®Ì³’seΔí–ß+Ôã¶*ã(Ü>�ܾ=rûö†[·6¦ž*I Q¬É9ÅÈ;y2¹©Útú-àmA •U„XµDt¹¢‚Å êU8Íj‰_‘… ¼Ø°6&m‚Ú¼3¢à«cÇ&·à@¬ÚÇýʆ¬â¤èÉ�!‰©çFÓü7ŒÃ+êX¨nñˆÖT[iøF w*Mr×ùýNЬ=>±x¥R1›•g(% $Ã!RbÃ#ƉÆÜ3tk•–UBE�Ç�­8º6<'O«si;BGéú££a¾ )-¾Záfý«÷ú~FÝžk¤÷{£Ý“~ò6—Ò‘7Äê U�nVéÖøèdý ýæ¯eDy[뫤g@ú�½§—޶ týa]ÎIœÑ¦-=º”vs–ã­\÷ãsk`ÖO>a~â£'–÷¬†Ë�ùëuõ¾%¶°¤€—Àw}2e9nO Ð×Mýti™¡à¥˜jhŒ uYƒ¥ZàuÎ�ÖfÌ�·2úöoåu‰´99–<¨*d ¸â CxænöNFÂÿÏÛ›=Ù–\ç}¿•™{ŸsªêÖúv£ � �IÒ")˜²IɲCá‡þWôäð“ža?ùð“ýì�C¤B4dQ@Ò „ b0‡z@ß{ûÎUuÎÙ;3—ÖÊÜ»ª”_ìÓQ}k8ÃrXëû¾õ-_TBt¥nS‹ƒŒËâcÊâ,°“Õ+ª—÷µ>Å=߀ޙø¶ígêlU¦±hÐ`ë…'[6€ë;²üû·<{©õL¸öÃêáÞ¯íu ýø—ü„ß^?†å<~Ò1¶RYÖzÍY½^ýšèµ÷YUE´©ëêË랺öþÆ-`ïG­Ë”ïSB—Ïü¸é¼^ï–DÈß_®ÙqéµëñqþÖöž¡�×®ËÍ弑þµ(Ú1†®mŒÃhv>ãhÖA1‰ñBl ¨Uˆjº)­Á8ŒÃÈ0ÖŒ0´ÊÕõž 4bq·©5uK¡æÍ>Öô'9¸|mhÁjˆ�餀µùû ^>ÅäX]�ækPWáH‰ •XüZ ½±^ÃïÑŽ�P“%@ÌÛh£ 9ôàCÝW;%«RìMÞL�h«‚2~?‚‘� aJíð1äÞúKüÜÛk¢g �¥ÊMéÊIµÒ&$gdÎöo)ÎAŠƒ¦v<´/±µ=àDŒÀ´o fÕSokR–J‚ªðrž¹½j&üÃË=?}ºý')2„å½î;! ÀóiæÎ8ôþô?w~ÚßÿÅlvD£“ ¯nÆkŸ•Dø²÷xûâŠW·›^Y°¶zýÞ-NOw¤ÃÄQšÇµ÷£IÂnLœnÇNr眙ssÊ ôż… MP× t’–¯û¾ã{­V&‚„„›5L I’ÖMÇÔ¿ð<{Sº¾Çº:8T C,¡Kã2†p«¿ÞÛ#ƒ­y±XŃxÓ`W ,ò�XQëf×eUæžK÷ºoJçØîy»>«}Ï*ªsÚ“’弬¾-¼µgË¡�o÷^â™�‹/-Nëq_iW»E·lôIÒn]©Ô ˜ÕRö©Á«°ž >ˆ�aLlv eDʆŒ•o[‘µc`*Þ°¸%gê R'u«*îž`c 6%jwž˜¨ò¯þäŸóáÓ‡Ü �ß<9ãWîßå0gþÂÁ_½—ÛCâ{þóE™yr^Ý <:ÎÜGþàác¢Àçnßb#¿}lö7_¼sÎýqà÷]5|‘3_¾sÞm{å»Ï_òä81zÕŸ?yŽ_ºsÎkÛ ÿúácæZ9K‰ßxíßp»¡›{¶?xyAUØÅÀ½qäÁáÈ_<{�ˆðµWïñìÀç§Ov<Ÿçþóóœ9^-jçc©ü‰ ¯ï6\Ì¥Û«|ö씓»Ý�×*’øƒ)d© 8·SâýU3â_pöÕÍÈ»ZùŸ<èû;¿ø[|õ _ó hÊÔ"æ[«®´­eB("ïšÊŸ@ž«YåÌ35Ï>äÍ% ^\©k6–¥�7—rüV=€æ‘ƒ5ËŒ!õ9ÚÀ³! лP6@Ô<ÙíE²ÅÙÔÔ)bé ÔÃB¨ÞŸ+`õÀ6GÁ�Òf»ÑÓaûOÚº‰U¼ˆ=�„8xEŸ)œUTL˜s6öŠ8Ì]!m¥ÿ)%†a`†nÔ,š2Û”ÊV-Pµ0Œ•f-Ó}�Ûò-´lyT³«‹¸@–çt¯{¯t0¯u@•Wîÿ4ççŸàÅ‹üÉþŠß¾s—¨ÖÓ¢Û:îVè¤@“d4áõ݆¹jîOÜÞ«YhUUþúÅ%ëGk~’LÐ^»‹�¯½ú _ÿàQí&ZŸ†&üÎó—ÖÿÃí†Z��³”øÒÝs¾ýô9Ïæ™OÞZ↫«‰C %ë„æ‰)ï™Ëž\��Ȥ˜½UÄÆ®„„Ä„„´,ùmêsŠN ´ÊÓ˜A"Ùíeš¥D œBp…}ÉÌÓ�i:0½ò²Wø˜ Á{f…!t[©¬¸H ‘\‰îù�ïV×ÿ³u¶�·µz¥�$³Ú¥½Îæ•-Äad1‹I·ü�–»’TÊœ'B>€Tá§/3 IDAT#]²%¿J!—#Ç9�É ;ÿ4·Éu&—#0›u�ZƒÙØz¸ÉuK�ÉyB80Ž…˜P«¨i½´XeCÎ3%ɳ5&nîÕ t#ªƒûÚ PÀ*”Ü®«õ"C襄뒮 f¡Ck$ÛÔ¼3 ¾[r¾&Çm‚ʦ¼µß5Â@<¤>™…Se�èv-N4µJ®"æò XleFîT­-Lõ@™'ªšuS­s%Õ«b²Šo[¾¼ïMê'Ým�w¨¬¾§07 4XÕ„UßX™¯°:¢yO-{ò| †#ÏÈ{ï¼Ëötà•7î³ÙÜæîÝ7xþxæêåS./áÇ\2Õ÷øÑ»Ï8L~üî»|øè)W‡@oÇS$n™Kâê ¶¤� c`8 ŒÛ-ÃfÓ¯o 0�[ôÜ2†Àf“8Ù%NOÎo1 ¹B´˜ÂýtTÎvXŸ·Ñˆr• ± re¹ðÐúÊEE‡YÙ$³ª bZ®ã¬äÚÈtõ—Âf„qPvìûdý¤yº·µÚ׎œ”M‚<13g˜Š‘"‹‹•„ƒç‘Û牳óÈÉ­€¨WFDeLBñêngó¬”Úˆ�Ô˜*³ ”ªÌÙÈ[w¬*ƒ�È3Ìhï]ÝBÒ †�UÑæ~Ž'›¾Ÿ‡.ºêއ8¨­mtÚœh°¦®7R].ÛŸ•pÚ\Åðã,®Ú´NÖˆ»•Bk]DÄ!šUZ°œ[Š � ™P«Û zÞìy`ãeæiŸ³`?1FÆa`W1…ÇófÙ£¾÷ûšÒÞGì¨=Ä)#š]ì©¡ÿåÚXºö*¹ŠôeÊ ó¾*¬S#‹±ú•×%öòõÀزÁsÔkyÛ »ÚúPsãI²¢_´eµ\;âžmë*¨’å‚èÍ÷\]-Õë¿×�>­'SÝ.DÍ{¹ƒ/òýZ®^€ø6ØÛ)´¿ë‰h³ëhǨ«¿ë�çÞ|ôL�Ž˜ú]lÝ¿EÌJHZB Kb\ðä]û÷�XH VbÜ®yû­�°æuëºYYNjmVCÎXz²±& ?T¿ÜÚ�vk¨RRÀU87}µßB;o[?¤ú)éBt¶΂3ZN´ý[]qÜÕÖ¼|©;?km�þ–¦¢E­Ky›´M�£�¼¼ªTj‚Ô¬o·ú˜¹I¨ÈOm¼¬T›-�n’�}•/<íä®ýe=OV“e=dÿ–!Ú-ln$!Ëß®ÿ‚@®Ï€¶¨Þ×ÛkΟ×ÇŠ/öžpõsê ­�˾‘´cñ±'Nø./[ÿoùŒvŒýV¬–Ëçò·_³å|[²îðô ~UÆÕkÿ©5¤kJÑ¥:Çž½©oJB‚7¶� c Öˆ+%û~mœk5 'ª¸‚o`G6£•ÁÅfkp�ô�n“ÕÖñfXÓ$Ì3>ö””  bu?öÒ¬öz5^Žgûºzs]¿NJ6Â`Q н.áà{€!"j< VJn]‰lãm&²êAŒ„ä�«öꂬÀ]†d¥´æ­l Lk|n€ž¤ Øœ5Á ö/½ÆÈsmSV‘…h60íIêÕ3ÞWÀJ› RLJc8¥�µ6X}Y%©Xù¦ï}pÕåu¯™kíßÛÏJAÙúïí•íÑH�¹V¢„ÞgàÅlM9[_‚ªÊ£Ã±÷øâ�[׉öÜC­|x8ò©“_C¿þÁ‡ü'Ÿx¥+µ�ôþد|À_¹sÊénãq™’³©u“7ªß ‘Ý&õ†ò³ûUÎE™ËRÙÓöÁÒJñÔˆ#ñªšÂ5Ϯĸ±6�«PÝ7^[õI'ÜÚØ¯îi™©XcÚØ8µZÖ‰)žʰ"óýo¨zŠF”yQ,nfùÝîC—¡ ÐZWÇ­ƒL‰Ts¶õ z°|���ZÖ|'j1@C-.‘Nà n~ëÇoj¯ï4À�Õײ“ú>Õ~öÅÚ>iùÛzw’uü¥@s4˜ZœbC­jÓJ9ìݬ)kbܶ$0„ù€�*¦bOcBPr­n—Ø®³­A1F¢:Ô®N4ú=°ŠËïþå·ùξ À?:=çSiàvŠ„jóR�Gû#?xqÁçoŸQªòì8óW/.¹¿Ýð_~ò5¾õôÏ\ÿùó[×Uå½ý�Ožìx|çÞÌ8—ÊAVÀÞÛŒB˜ÍÞDvR`.óm—LÑ€Ô@ª¥W±†loÄ€öYú˜u0F¥ŸâÖ›ìJ¨.tqâªç}0Ï3‡ÃûýK®ö”•ýN#Ë‚$RÚ0nv¤acä[l_ ‚Í9 ¶§𪟖׭È�Zìk{f°Ø@Ú¼ð¼‚…Ø ÁDAæAY®çAd‚f³L¡�ód1¹W Vµ¦¿Ì¨ÏeêÛ¿Móæ/u6¹j�Éóž„Ùí/š†U¾gWšÏ„˜‰)’ÒÎȼ¨[ÍÌÓ‘i(2“¢‘•M�SÊlvŒ9“5Ûáó¤UÞ•ºTá P[O†UoÜÞEÄd¾íF d bà:ýºWmâ·I³x$8Ðé¾Ï 4EÄ­JAÌ߉ªöžÖj6oy\ø`Ê~«Ðš´PêÌ4üZ�©–«…´Ø5‰[Uõµ¹a1YûÚ+^Ö|TU •É^#·ªÔÇ~æŒÔ )GÈ*”/Ÿ>åÁ{î½z‡ýÅ› #'Û{ì¶Ä”9N�ŸL¼¼ü�¢p8ìyþâÇ)“ÒŽa<%gHÜ1×�él͆%$ˆ‰4Äaè{R#¢{K˜>LØn''§'‘ÓÓÈvtö¯léäéF8Û §§‰Ýé†ÂdTP™™ëÌ&»8€cPÕ]#¶Æ!ôæÎ) Ãdv‘­ÊnZU\`3 »M`»I 12¦è)réóº…€&F x\æ"LÕújª.1`Rªl6V1p~+²; lO<(¨™*mœ¥Øª#ó ¥F*VQ%ºׄ¸¥š�ÏšízÓí˜)1yEÌÒ·‡�Äg¶:Ví'ÈŠèÂQÞ,Š©=Gj¡z¨ž'©¶ŠNú42 år¶C×e-_}߃ÛÂïÄXEµ.¤@H„IŠcæýŸ«"¡tr,H肜ˆ}Ù´ùÛz´xb]`9ZõN¨®�Y¬‚¨‡ÝÚ÷­åásZ‚]ó<^ …u5×M Í%fÁ¸ü/¿Z]ºvg-õ@�0ºz¥Ç‚Ñ­?aU1àʦe7]}qã€eý² ®Е)är£×¿ð×-”Ð�¿~®™µl¸]0½þ±D‘Õk)píB‹oý@nƒÜøù'<ú{zpÚˆš,ˆoLÒî¢ ,ÒúÆQ¬É¤æóë%j‚tcH-8o¥N TKL­Ü®Úħ±â+Ö©Ÿ�]Èêìf)J)–çR;˜»ø”ÂU{§‡»êÕ¢jKNšzj¡‘è@„—ØàЇb¡[ˆÐÏÅJý=°Ô@ÐꪥÕJ¨Ä*$oŒÔ½> ú—kG•(|=ñþ¸Û¿\ »ç"xgp·`Bº¢¾Ùд¦0R—„ë#ÖW3‡ºåØrõûÓ¯×* Z“:ÿoÎéæûÜüY®Ý¾8³>]ÿÒUÜ£±èRå³4Ÿ¶ž}4Å�W®èêCþöcþø{$þ?i7üÆ9uàcÎß>ΫuAäúM²¥@¼L´ùø¯’g\µ,@LC`Ì'q³IlFa36›ÈfÙíNv£o¤P ()†”H)2 V=¢侦-K�ŸïjÐ0#%;‰H¤VW1´@Aý<@j¦Î…:HuõþÊÛz*Þ¤'¨Ù ù½e­‰��éjÄV$íŸÝÁt·?¡�D¾VTµ>¨c1:øÐ–YquA»ö­D¸Ý¯Ø7x³ö{ åA8�¥ª©ïì6Fµ˜:ºõšéþz |µ9+! 1ºM«ù‹i"pô2QéþÓÒ˜±Xyød±Ä¸—®WÄ)0aX­"ÒÕý?º¼â§NOúߞϙm\ˆ�³9[©r£˜Í ÀããÄYJ�dø`à²T~Æ­Kjµ*±õçþý×ïD¬é¢ŸñFÄ�Ž/æÌ¼šÓ§»‘qŒ”)92§@NÁ“*HÁ^Vd ¥øû”îÕ[«©ï,Hn"Ydsíþ©©¶ªV×NˆO{¹ñÕ^·|Ý$– —ëÿ®¾g®cO$n�ïî÷üÕÅ%CüÆk¯ðöÅe׿r÷œ¢tpñ*g»[*—9ó;ï=@Uù©Ó.sîÄÏÞ:ecïC°‰‘×¶Þ¿Ú{¬¥üÙ‡O9–ê!›t»¡ÛãÀÝqàmÿyÿÙë¯ñ;ï?è1À±Ô0üߘRŽ¥rœl|ö씿¾¸äÎ8pÿã»ïömñ ?ûþã_þ̨Ç="îåëêB'äTgj™ Z3;#‚³±0¡JK¶£ØÞf‚RkÈGˆD5K—}Ì?¯ïC´­ÛöV‹Kû¾õö*vœ1FâúkKÍ‹›x¨©]E21 Œã–”ZêÖâÃê9DòJõ5£Y¶)ïzX³«úZsOüõ­„¦©­ãÈ8l†�ƒ¯VÕ'a°¼«Rn€mm¶Nò•j`iL‰ívÃv»! ÍG»¶>8[ºòÚ¶'2p«ÏÒp<·½Ó½‘sž8�ì�¦y²µDZµa‹�—´¼ä™’g’W3ˆ¯òçøî_|�iºâÛ‡ÿÑvÇ.FÞ<ÙöùðdZšm}ü!Ez•Á_¸}Ö :0RîÙ4÷´ñGWKO‚ Ö|øé4#"üÂùñüe'à~íþ]~ðâ¢W×̵’VkñÃý‘ûG$îo7<;N}ÿê+w8‡¾¼xþs>RuêöAs=0×U²Ù ™$Ëþ«Å€v_';A#+ ¾Š�{«ŠW}b±ÜW0ËÛ—3ÁdzÑ:.¹¼zÁåÅ3..Ÿ“ç‰R[£ç`•¥ãÖÅ/ëÿsæ�ô{Vr…š1°P}®•™Ö££c==ö´5A8 x¥ ‰×À¸˜·Ü ë³d�M'ŽÓ�ãqÏ4˜ËL®nSãUUë�$v Á+`Íög:Éy"åHI‘Z„Â4ÏS_[·2[bÚcŸO¶^Ù|H Z_DÁrº� ^™¨M�ì¬Å.Gô<)Äh$BÎý:¶("4@KµWRIHƒç[ÁÁÍfUÅ*W¹*>ïÎga½Ø<Öì}¬@.f¹”ó@)™šgˆ‰çÜÈ qqP5B ÈùÀ\&�Ê8:Á$ÞOÑ®K�IÃ1õ¾yn¢ ËRëM¥Õ‰**ÖзÖDÉ5�F$E„‰!V³ñ’VÙ–(ÓÄËgÏùñßcˆ‘Þû€'¾$çÄéÉ«Xã3ëQ§$²=¶JŒBØeK [` T³ÈK£XŸIZ¯Gë}3¤äz0!R‰†›1°Ûm`!ÈŒPˆ¡GHãÈ„Ý&q2Wõj �±r $Q¯ÐöUYÃÙl-¿†ÀpuäòêÀqn�ï­ba»Ùpz²åd·a»ØŒÉHó Ôy¶ëZÌFÔâƒ&¢Yr¾¬�©Fæªäl•ÎB!Š5-åä$²Ý()z_É2’l°�H·Ø‡�9 µFæb¶ES†¹˜p7…�ª†3Äh.D¹BЉA66¯ÚܚЎ[ƒ‰¦Dqp;,å©êM¯K¡?óF øq-ŸÑ®¿ŸI?¿~f¼é$‡ôCeM |´ŠjõÖ¾™¶1ÕØãeAd„N tµ‹+Û£˜âeˆÂ�ãÙŒ‰Í8°a³1ÅvÙnv»ÑÀ;*I`ub!tÅt�ŒXŽ%4Õa`µÙ/'eÁ§7Sí̺j±5I¬áQ;WCA¬ai-B-Ñ­UZôî7ÅI«ôòë†àMVøÝîƒ+¨¼$_¼‰,MQïÊfÀÈ5–¡Šª+Àª–8JÀT™n‰°�cÒ¯�ˆø:D;¦ h\­Qíú`§Qñ6 Z$£­ù¬Oˆ®NZÍÓªnA¼TA0ñG5ÿÂVÅýï-áZO>‹´ >^,1îÞ -P�C.ÝòàÙÎÕÔòµdr™Èyéc -7÷z=þ¤õ@ðƳÕú7„`dRð†±!¯ 6‹Uù•|dšŽ�æ?¢ºáìÖ” ÈÆuY dd³=ÃìfDÌV 5‹¬¢ÁªBÄúo9YR —I)°›I¢$2›AØnìO•1)Q&•1v)±"cÆAØl”a¬Va;j Ôjó%P-–.>p¢¢!¢20Ε8 qPBÌ GÛSb lw&»}¶åìì„�ï/  +“R¦BÉFÒ5=ÄÖ'ÇÆz!2ibÊÊ4)yö5¥c!990Ž•0d·—±¹Õbè †Èv %J ¦ÊÕ~"3«Ûi%´¥ŽæY Û"£Úš`· &l¯ôŠñôµ­s­J Ú>q㫳T+1­r ­7&¢ˆÁæp•Ö'eéuÚÜQ¥;ô´@ÜjÙÉØZ=€fX/¨ž[4lˆ‘”³Ä*†R€$JÄþ¤1@d•“Ó­íØ�î`ƒ9È 5[UŽ´>WÁÈ‹ž«· Æâ5”H¬Î¢~Nf µV6–’%g¥fbȈd_ÄÄ6M<‰¼s»ƒ"+ß&ìÇÌ l‚õTßçSheZ¡)Ï—ñ­Ô^Õ”Që÷oS–×µ9l^ì/,à±`Ó|ó¿Õö~Z1p£Z?‰fÁåù`á"µ[-ÙgZBÔ‚“šÒ|Yhji‰vOw;ŸlAf(Zð,¤†ÁÛ:PWkAª©UB…¨‰Pc'œæ¡+½"¹›õU»nm©mbÚ…Xñ»'m³l+ž/Â~]qeSY-'š ÉB 4bÀ™üþ%J%ó<Û%Îv'ÛÈÉc²æ¿§CàtŒœ&8‰¦¸0¶Üšôtu¿¬ÿe”ô“s�R/e Ësµ£‰«{¤~�:‚g£Ô¬ÆˆU IUbV$X%CÛ$m(¤FPõM-ˆ„‘â]V‘¶óùº"VÝÀn°y-2®NfHD“�×\ÐPí"~? IDATÐ H¬_û�¼ZÅÑÆqŒ„1"c‚lÌHíÕê÷W÷›H v€× n©P÷Þ€PWëõ Ð¬ŽŠJ„XÑÑŠ5ÅgIЦ`Na¹OmíQ³ƒ@„ïm.wœ˜Jeè�ýmwÃ2¨‘ÇZCè6>ϧ™¢Ú› WUö¥p›ë–AëñõÚÖšîKåÙ4ñ†S©ü›'ÏøÚ«÷úóoéÚþù%oD<×Êó)s;²‹ñZÅöyâXfæš‘$Œ»‘")XÃmQÛßJ®=Áµ&cU]ÙÚTòž)bJ¼�ºÏ·ÖB+—U¸Zå j*þR3Ù¿j[”=XsÐ æ[Fo@ÿ¬&á"I𢩥–L”èj.'«õ²–R‘\�æ�§.X©®@W�?k[ZY<×H ©Ï3‹ˆ¸½Žv<@ˆh VÕÓü5{|d‰D«Xˆ2ÒA[å6Åc°†pƒÿþFìkÛ²˜ª�å—k‹A �¨kŽH ~®N›_R Œ+R˜=@�OD&Œ$A´ûUkaˆ™!N qfHÙ*7r¦è@öyP*L5sÌ•©¦\™Kõ KS9Îy±¨o´�ýg¿ÃÃÇ?&owʽíÈ÷^¼äP*¿ä=7¾ÿâ%ûb¶=ÿ蓯ñ­§Ï äß¾r÷œ‡äx:M\äʧOw<;έ|ã眤ÈWïÝæýý‘�ÿÝûw™jå¯}~e”w/÷œÏ癹VþÅû)ª|æì„})|ÇÁô_¹w›!„Aø™3kTZÁžûìG' 61ðoÜ^è•ÍÈÝqè èIŠüƒ×_埽ûA/¾©ïùKfµrú]Œ¼œ3/g³gùê½Ûü»§/¬âøÜ­S§n™²Ï™¹.kÞ±ÖN œ‰—n3òÚÙŽüöÛ}½ùÒ[Ÿæ¿ú•/pÜÿ�ã$(#6jŒ¶/h¦Î{BÞ™ ª,UlQR�¯›�„Võj¥Ò•pQ+A•¤ÊPAƒ�=ÆbÖ¶ÿ¶(dQŒ¥è�r±¦�Z¬†q%J3;�ºØ‘Š©pMÕ×Ì>j¡ÌJæÊÄÈE™Kfö~U!;X¯Bv[6*U!Y£Ë�|í:I[ –.¬ÛŒ…! ¸œä ¹õ@¢]_«]y]T{¬¢yÀ×P™� åèq«�¶âÕÓ"F°æ’ÉÇK4_QPª(GÑ<ÒØ Ë1b·r1[´lVkó¦=Ìȼ‡l÷²ÛCj”••R³fSÂ�ºNâÍ7?Ï»ï|“Ç%óíéÀ—Ç…DÿôÙ ùò²Çª��eeÿÖÆ?qÿáqêsí‹wnñ7W�D°\|™KO¦™?ôj£Ód„a³zëì„«\xè= >±Ýpw3òÍ'6w§Zyp8vÑ ªüÞ��8|}·!Jཫ=CÞGÍæ‹|ñ˜ÝÉI#A7€S9gÊl„wЉP|%Ò‰ª†ñ¥höZÄlÙ´U|U¿Ï^åI&—Â| `–‘1ÆEåïã/`jÝM˜È)SÆŠn•9C-Va“¼GÅ8&˜óž©5Óv�¬ƒÞ×+ë C€’¡dtž(³h¹xŽ­9¦ÝÚf âU+.Z z I#›L´b4/õÍ@óè/óL™2u>@ž¬"QØQhÖVmݯœñÝÓ쾚*=#Tj92OÊ�ùÈ4Ïh=öj›¦€­j–s5+Ìz|JRL{)¹�óÌt82ÏSŸ],noHr€U¬)î<™8ÉÔÀQ*ÖFE|^[0l`¥N•©(uVJÊfçR ÇQ"ÅÝf9¾«ÉKñÜDÒÀ°ÝÓ`À¥TFÔŒÔ óL9Ñ�ÉÁÖ Bž&ô8Q¦™Zf¯î�ܾlfÎG2{4d;#Kß22U…jUAaµvj±5¨Ì™šgÛ‚Ýçš-öE¥ QHÄÞoJ´Zí|ÆH1QæJÉN&çJ­¥Œ\¼,”òE8?|ÿ›sàpT¦Ùˆki� ÊZ�#`2k¶|«fF- ¢Œv)s:dÎv§»�mƨ¤XI1CA¼ï…yì»'ÿÙnF¶ãÀ0&†Aˆ› +­\PA”àã_±j¤¤&¾ …±(·ŽJÚ ãUàxt‘I¨ cf³™Ù�w& ¨ÍTÙ™âW²˜åBóuµ†•Bñ²ÇjÖ7QHƒ2 JHÁ•;–ˆç<tv0lÕš‚inYe›ÜêW”ÖÔ­eV†k£v=]åÚõ®žl¶F?F ÌÍ}ìù$·qÓ~·öÜõ 8±�)XâkûÊvní"·O»QØ BŠ•!ΆÄÙ(ìe—”aóÓ Ú9Àõ²½ôqX� M¤ë_¾Ü‰=ùZ­y⛽�¥P[¥€¯›¡Bn �jéÍ·1pD£)«Å6x©1Þ¾“£Ë’½”Oã` Ú<@T–` ÜÓè) ´fK•�š"ºø©>ŽÕ€|ßÌÃh <›)RÝWÚ¾'µªU«°±Þ2€A!iʼnÄöÓ¬„êûŒØ¼êkÅ„RgQDP—ŸÎMÁß<§1¥¸Ôê zEÈHUê4‘K Î†qN%3×bö� ‘‰É„M™ž_Q'\8P3h&� ±ö1Æl:)$ösa?›/ð\aÇÌVg[#=Ž©j¯Hㆠ;j¬Ì‡JÑÀx,.µþ®(,îe>¨óÁÁ«JÍ‘ùz.ÕE.­ªS�œ¥šªZ§Ì0ïQ¿«_º *ö!À��º¡5=;=ãÎ�×yöìÞ›çkÄ@³½£ ´è?ˆð鳓^9p{zq°*>:fWõÄûŽlbàsg§�Üøê½Û|ûéó^™ðrÎ�`øáåo_^Exc·áÇûc·3ú»÷ïñÃ˫޼ûÎ0Ex¼¶ªBÜ¿|Âéx‚ˆu‡-j>�'S²šý�¢š1±¸ÅeQ“El•n[gqÙd‹�l«©ó�‡#9g†aÃ8ŽlÇ-qÜ0©J³df u¨°�¡Vk?Œ‰”b2Ö«Î&=tPÙĦ` 12„„Æ)R´cÎÔy¢NÖ€wÎÙDf)ÙØž-§Žapò¯åª˜%`5 :úgÅ!Z¯�º%…­TÊ ù5ÏPfD ±í§M„¥nOB«dsݬ“øì·*�JÍ•¹ÎPޔ鲋ËpËAZ¿ µÜu> Ó% ”q´*­¯Jáxœ˜|,½Qø8ŽÞà¼5.6QÑT&ò|DrDtÓçð2/±OL=\¦™B¦¦BŒÇÙöä6K)Ì¥©1]½,jçSgµÂåq„pJ�­ùâ+VýQg¢[PJÎÔéH “I��"Ì…º7 )­SÇT'æ¼g.“í³!ŠÍšÊâ ­ÑÅ›xuh¤©Hµzš�[3À¿�WzÀ ËÛ‚ >À€dó¦m@Öržàçïóhˆf±ýܵc‹iV3ÖT5韢I<‡ó˜æÌ4¬Iœ¢±�sK´ °×R´`z†ä�Ûu¹µ*)rTæ©0{€¼ì+ˆÙɈxRƒ£“æÄeçaܼ3uD%u5·àS݃ââɯ×`¸Ý­¸’—s x™%~oü?£¾©·DÏÇIôróÖ§ÝWS-ïÕÚèÊ¢c‚äJŠ(�1)»MäÖé–ó³­y,Æn§P8Ù�ì¶›1’Rk*ÌÂgºj­�QÄ{Šˆ[¦,ËÊ_»Ykrx=¼ûË_‚«çƒ˜U�•@z©n­F<ö9Ñ" ÕuV|Áð䥮›£C· ÕÔø7×T]Ž1ø}êVc!x3 E¥m|ø)¨Ï[ëG¬Â!y�€qpÇ*c‹œW[ˆàÊÿRu�b?]]O?¦Ðß%çÄ!RÅH“�@²ÀGçB �¦®k=7‚ŸÄñXxyaI×í­\W„aª_•Òû×H WdµÊ€[«çþàÅŸ÷>€�Ëã3g‹ýÐä•íý¾ûü%Ÿ??ë͈¿ÿü‚7OwÝ¢è»-Óª¡è]÷xp8²Y�ÃÅÅšÏmmsà¡)ãŠ�Ä*È’ÈU½jª+ö±ÐËL}·]ìת-°n ÕÇX[WÜ~b ‘4 cMÖC -Ì8X_}?kïáeÍ{Óò€B™§¶ª[JTò<3�¨°&Œ«ê�lJÉÅÑã±RЬ䜩َ=(]<ÐׇoÔ>6EÌ"I“Û25Pfô&žQÜîg‰)rkP6Ò1Yp,ÉfM.†H Ø#_¤]‡5Á¼·R1 ¿)Ò)£©ªúö¤Âã hŒh´�!�’vkݧ†HжÕÙ¬Ær®™Ó1[nSaš­òφI`Ý{®ªB©–oæ e¦Ìs™�b} +&¨^å‚Ù idF’W'¨–¾^Õš™ÊLó@läDÅ­LÔá†WXœißW­ +Ës`^}í5îß¿KJ¶=|ð�gN¦K˜+\ ã&±7ä¸ÜÏ\M€9ÎÊ~Ÿ™f¨¼’Ó+Vë´à!_P†ä}ˆ$v8ádgv='·6œÝ9åôd`»5ë)ÔüûçyO­n©“¬ÇV#i›£÷¨¡ù‡75­‹¸zÝ—çví’‰X7qKÚŽ~�=_sb™ÀbjÒp¯ÖƒÎ?cytЈv@ݸc¥*�wÛ¾Ðl½ Ò^½GÃý\éÅë5™6²Î&¨-ƒ�µ˜£X¥•#ØÔ’¨9Xe@QRm­ú„R…)+CVÒ\‰sa.î€j‰ YÕæAQëCR,L¯îð"ØÚ=ÄÈÊFdõ=ŒÉz'ŽƒYÿÙœ3›.(®CФ(î>ã�ük ÅH™­J[´vQ§¹‚˜>àvÙ-×ñ�/ÕÒ�€ØqDaŒF:6‰”°fÓÃ@’†±µü ÃYc.yIû[s“h¯±X"ÒúËv+Ÿ>L>°;7rã{Y=o™oËóÖùÑ�—÷×ÿ‡Ëq¤¿åY Q ý´›§Òý¹oÏÍê¨ëÚ™¸~üµ¹ö>ëO–~ß>æ¨ÿCoðÿãCR=„�½G-×rÿÈ‚&\îu6ݳ7 nåbVXì<:î¡–Ï I©¡Rƒ§)|ƒ×æµ3Ï8�c*‡ÒI«ð~ KI�Ð<ä½JÒÈ5Ï«J Jã˜íïsQ¤T&dˆFHƒº²ZYUÖ—ÕŽ¥ù¶{Ÿ!içUÜëw½à^¿–ÙëKXíþ‰ÐÕ]ª>Î× “_„ål¤¶½FW÷^ ©�:A່ý¾�ŸX2ä/ ëE˃^T’1±)† –€•jÖÖPÓ½U�8LC ¦H%WGó{«Uñ X ¤¢1ä­Ñ'XÓ¯”¢yâoG¶Sw˜¯¦7».•9`V@½¶ƒ5x“¼hÇcZü_ŒUµj˜ ‘ ‰‚Pk¢Jì�^Qœ­6•¸¥m \|Â[¿‚ëýÛh�æËæ|%¯�ä¾ßV¶œ<Ж¡dw1Æè è")Y2µIV«Å@ƒí'»Ä­Ó-·ÎNØŽÂvR( ±²Ý 춉”„!²€s²^xSáÛÍßÞ7ËFêõˆ²'ÆëDz‰´˜ÆG«'ÜË$”*®X.v ‚Nzí�—�±ÒìÔš7òâƒjªùÜõIÞ祿½@«H2ÀÞÁëhžêJ+�·ŸÚx0Çx ¸´2;'«­®ˆíšÄÙUTµz%EqOåv"–ÄJJöYëuy½5õº_ \”yžAL‘˜R2P<„¾]½\ƒ'^Ö~óÑH�Ü·ÇEÎlbì$‚ªróÕ�h„ÿ+ê?™fÐÅnèP+õâòšÅЛ'»~œ¿tÏ,Rö¥p• ¯lFRŠKå÷|È?|ãÕ8J¹Vypy¹Gs¶þ!õ1Tsq0|ÞÅApÅ€^uïÌÒlÙdéïÑ,ÝÄÇTžÚ Zoω!Ø1¤¶¥úüq¥W-ê–>>:x¤ôDÜIÛÜl2°^7 –TNJŒ‰"a·ìðèVÂÀ`I{Îä)Sr1c®¸zv؉úøêûV†kVÁ-¬bO¢ìðÔÁ»†Ý²¬ý>J'Ø$5À7¯|YTÿ²¿Ï-FÉ ³Ç*U Ä¥Ôº&úI”ìB…D;°Ÿ ¿¬Vd[ÁöZ_�°pò–Y{&ûeˆ‰«ˆK3ˆ$p»íñŒ�o%ù=åBÎÕŸcd´%û•¯ÿáÿÆq:ðZL¼¹ù�WïñgOž1•Ê'v[~ãµWøÃ‡�)ª¼uà­³Sö\G~tyÅ‹9óÙ³S¦Zxt8ðöå%oì¶üæ'îóÍ'Ïyrœxüo¼ÖUÃvê•™Áµ‚ò»ï=à•ÍÈ[§#•E±üë÷ïr™KW៤Èý톷/®Èª\äÌ7=éÀ?Ð-ƒ>svÂiJ|Ç_ûÚvÃßyå¿ûþ»VªJ1�‚/‘òáSªÁ±‹Ñ�Ê™!~ýþ]þèÑãž~|útÇÛW�Tüñþà–:ö¸Ê…f# >±Ýððpìë—ïÞæýýžOívü÷?~Ÿw�b¾ùÊ)ÿôøm>õÙ;”pÁù‹ÄØ33eOEYJ¡ä‰PfRµF�±(%(ó E� ÔÑÈÉ )mHqpð¸RªÙâ ,D¤ÛsÄV:Ó7C]å�V [©W«Þþ,âŠN ¨W&7eš˜£©™m�k= ¬_IôXìÿaíMžmY®ó¾ßÊ̪½Ow»×â¡!‚%‘„)É¢©Þ Y’'²C3ÿžhê±Ãa;a;á‰çÈ#;¬7!J²Bì$™"!‰�@‚^{ûÓíªÊ\¬µ²jŸûÛaïç�{ö®]mæÊÕ|ëû2½SH«w¿„Þ�ô 45¬ARîþ´x1½y­¹ˆñR+smLµ9Ñ‹Û�\ÂBõ5ß›SxÇÞ IDATÚçUkÙôW– )I,5À?nR4h²Ñй ðXÓe³Î­Ú×80¡äA »22 ;r).�VÍf&1éºtÿ±Ö‰¦&‚¬Ò:¦*!¦£åwÜ|Øæˉ ó-ÃÀëo¼Á�üÈg˜žïY4qy3ÓÚÌR•e–”‚Èà ªl€Õ¶IpCRÆlô¸ã(F÷™'#œìàä$sr’9½Øs~ÿ”ó‹=û³‘œÚD]…Zg7¥^ȉ쾩 Å 阉#b3µØLœûß…Âz‘°XªãX<‰•8(µz�Çý{›Ÿ-�Èv½ö ïjùáw©<?ÚÏ6ß+ysÍÖ™Û±¤ÿbl u10Í®GÈÔE¨UX*”æTà ZKÔšf/ L9¥z÷¢X'õÒ”Û¤V@HÖ¼l…�ÔsC1 7‹ç=& ã¢ê9 Oö�…Zæ)uÝŸ$Ö-`ºÊP'';öã``H„ÛÖ¨³Ü;uj`µN¹’’wó§nk,LÙ—ÄXC6 “2f»§ëppíß°ÆPñ#²‚¡}-:NˆZ�ÉŒ„ç£�Ϙ—Êàm¥©¬Th³( •Nå‚å,–x3±wKŽ‘=y ©w¬4õÂi5óu'S¼^¤”,Fá5Z—Tˆ?›ç©´¥²L•eò$½Öngs± åúÔ¸º[‹œch–ìÂwfïÔÑÊþm-¨NKÒ„¶4êäÇ]\W!ÙÚ¹Ö¢·‘?·>ú�NžD,2ÈJ ”-Òß#á�6¬ ƒØ\t/Æipmu0ƒGf-¾§çkñRÑ( TœúÏ’ü”°Å‰æˆIÓTh$œ ¤Y1ѽë®*hVtiÞü !Kø FÑØ*,³>­&j]ªeÁ8|kоZ‡€ ˪ç£"�˜„_ûÍ_äƒ�ßeáo^ÜçOÞ¿à¬v’˜hœæÄï<É['{Æœ9Í™_xÿ#ág=àbÈü²‹ Ÿ�g¾òð>ÿÐy¾ojå£Û‰{cáÃ[áÞ0ðÕ'ϸm�/ß;ç4'¾öü’©5ÞÜïøÙ×ò ïuÑ“iæO=zÀw¯‘ <žfžM3»œØ¥Ä{·¾þâ’“œùÉ{ç|ëòªÓ˜üÜ›¯ñxšø§2¹©�$kÑýÉaâçßýÞ:Ùq5¯‡/ß;gi+úùÞ0ð™Ó}O„.­ñ‡—Wî ™ýú­§/|ÛÂ.%>Š$h)üÔÃ{�V `·¡.²ï>çO<¸Ç÷Ñ|íÚ’±/vüïÿÕ¿Ëg?BÝ_sñvæsù!�>{Æç®M0\òˆz÷lm•¥ÎÌËÌ4ÏL‡‰Û›‰Ë—·<þè%ÏŸÞ0ߘ yÈÌd§¨¬æçúzhÚ1`;Öìæ K܇Ó|ºˆç*ª'ÊZO–ªS& Å»:ËŠzAdGÉnPØ­šëвÛ³‘I ÕÜp;a Ñâo.†ë4ë*R�é..Ün×§ZI=YbÞQûÍ¢JÙÄo¦Ã0£’©ŽZV¤£š{|‘ }œªS‘äâú!ÒׇxŵÖe2=ƒyb™g+†'lMp´sŠÀ_­f'uíh즆P·Nm·#~Œß+§“T5dt$iÕÉ�ÎÎryù„¯O·¼}bø³’y8½ÆÌþñº‰ú1™ømt œäÌ�œ�ôÄ>˜îÆo<}Ñ÷ñ½ë›®AuÙ¼}²ç{×7ª­KõSoðÕÇÏzá´dæM‡ß÷®oyïæ–’†ÂËeá_>yÎkáóòâùGÎQïBÏá·y1¦µ_3ds­#Ë20-&ž¬KèÐb wA }= dOJIÊ„S R$|ÛDkÞ­€qÆ·ê|ýÍó¦^酂ƼLVr _…W¢FCQµ±Ì¦$ ñ¢×<“J&•�Ò ¢•vþ“‚.¾&™Þ€J]㘵l̪ƒ ð½%é�Îå�Ót4A?Ú ê¡Ù:03Æ»xBÜÖÅ,ÞEÊf Wó’ÇÆ7%»ºu¸nb÷/¶Õf>Oƒs]‚bMÂ�.\£ˆÔ–ú±‚j£ÕÊÜf¢‹¯ƒSFÔú¼$¯>·D p'7Õ”®u€ÛÉè¤0p‘£®F÷$¼b1–dÈÄzaeð“±N…è4—¦îËÝ)€õc^ÏOXÅTµZAÙŠHæ{j7ŠÍmOä(Z/[!¶y¡w •e<%•Šb›ÀT3W‡FZ@’bÀK«ç'ì‘«ÙGÏ¥„Hì�…“ÜØge·ƒÝ˜Ø�Æß~²Oœž$û½Îî ìÎå äÄsQ©&†Ý@Ö˜Øó‹ß©ƒN"S¾Æ†=7£BÒìà2_k“ߣ�OÜ)k}¬c·az�ô8/bXÓ)`�c²Ž§5@ÞXcÿªw¶�~@¢(:#1�1_x±{%5‘È£�[´:šÇ“ƒÚR¯®MûT®5Ѫp˜*åÒ­Q7ÍUM£Clm­ c)L³0/bE¢*Þ c÷;ðuäó©#o¤´Úþ有¦QYô©2¬ºGA‹¦ÕµÜÚ‚h5pê–²Úï\)B)¡Ï…;^-T“3h dLÐÚ²J.ëÁ²æ=°ùØÁVÎQ$E7 Aé‚^?JQ4ñŽU'OhHÛú3Þ<}SköØý£È¨ç î¾¶Å«Xý au÷û¯îï“;4~éúï�“²å^­8Ç{÷`¾Í+†ã,ë‘Áþ¿é�cÞ9žÚG7ìÿ¯×�]é'þûÎuôê>àl¡Óä‰MˆKy² wªçúÍVAíÁwÐ\/pos?Iÿi”¾˜ÎYi¥9O[³ÄÕb‹RZ„\Æ m¶æCî”@ffÅ~jè9Kbê:�°ž�6fq‡Ë[ƒA •…%62Åo]<)nˆY+¨!ª#¿QõVÅÅ�뎑öÆ”†-êPÂPDrxm×¾³ð`Èûµ¾†ËA,ìúêX™EwÍÚ‡FEáÏM´ßíØ� !«�æ,–t3c±â€xËy’ÖÛ³k']fCŽ ¥11‡šD–Dz«Ø0¿ÛnÇ%›Æ€zÒ+‰P²U€Oö…”óbº‡¤LKµ¢QU 0‰s3îݦö}+ H*^Í^ѽáLjÆ;É�dm§ˆµÖCDòÄŠS¬Ñ”JǦ&�g†òt'[¢K@Öß" Ε|£6¶¼;KÞ9±Ûö;£:Ù ìG+˜ðÍ@fa,p²KÜ?Ûqq:²ã ŽHL8Z°ç˜¬è`Â8¬NÊ6¨ÍÖET;Ûû¹| †Óc+Új·Ž’é~³ZŒòÕ™qLÎQ, �Æ@Öscó¹ÏSu"9æ_EáÍy›“e=5w„=±ÀævÔ}£Û¿ž€�'Zfza`Û]µ t;?c†ûý‹úI¿G&ÂlYÄÖÅÊ Á#�«Á–ÆÚ¶³Y3‹šýž+Ì :Íè4…nA›XÒ–lhçËRØÝù;�½‹šs¸sÇ©)|x{àí“]ßöôNâÿGÎNâ±1ÕÖ¿[UùÚ³—üôÃ{}ÛgÓ̾dö~üÏ_œ±ÝÛÅP¸,ô�—üèÅY?·ßxú‚×vŸ?;=¢šæÊTh%Y� ‚ÑÉøH»½Å5"Xš7­%“s»îHVqtl<¿‹Òµ ìw…ýéŽ4 ¤!ÛM©�å03ßNLI9´™Ã¼ÐÚ„Q®í(£Ñд¦èdë¬Ç’Øïsj½ƒÁP7íóó $N5„ú27æƒ![³âXŠ'»ïx#Î ¨Õ: |±&‰ÑæôÊqâ hÎÒ“F�Áî'ÙçmXX»o¢ó$œêð}4�Yq~+ Y­ ]Z/¨ƒ $ 2{ò@„6UêÁŒº4r†a0ÞW Ü\£#™€£-§&V&$w¢VqýóbBnÑf½4KF-54"š''ƒ>È>³ÏÅ×Î5‰)Iùþ{ßâ·¾þ«üø0òÖnä°TþÁ{òÅóSþÔù¾syͼ¼BDøko¿Á{·‡žØi­q=Óézá—>xÌ»‘×v#Wµvý¿ôækTùÕH�ŸÀ;§§üëç–0¼\~çùKŒ…¹5>}zÂ/|ð1ªÊOÜ¿à¼þÅã§(ðÎÉžŸytŸ¿÷ýû|/iÕà_=yÎÜš%êsîâ¿Ç�ŸytŸöÑÓNôÇî]ð­—W¡üÑar”µ=Ó÷onyÿæá3§{>¼=ô$éWÝçãÛ‰w=™9¦Ä.¯–åªV~õc»æäà‚ &zcgÇ�ÿñÙþùK+bìÇÌßýoþ:_ùé×™ö3u?qñvâô�Gxôí]#㚸iÖY»L3··®/oyñüŠ�?xÆ·¾¹ð=®¸|¾p½À0îXÒŽ.ÞéSØÙ‰&F-×O›MD—Ú“i$n¸”ˆu§8ŠÝB»9 ÉùÈKɾLùšìí¦Ú %[+™րm‚÷6 "â]|vÒêÅŠ$Qp¯59í¤»ùÆ œM¼Õµ¥j�Xæ[–éà…�Ú§Âmˆ¯ã‹º(b*T#Ñ<™]',^n-h. !œ|íW,�;·J«ËtË2Ïž¸Mä’(¥t~ôœ]DS[O¨h3úÒZÕÊZ×X6�¹Ýÿ0Áùð#UM�|uRÌW¸8Àåå¾9MüåÃKåÊ÷٠员çdÏ“iîséÍý:­Ø¡VÞ»]i|þå£Ðz0ÌmÝ×§Nv¼}²ç_ùçAöîõM?Ã_ùð S«ì²1–ÿ�S½¶ùÂù_u{sV2?÷Æ#~åÃÇjãÑÆw¸ºzÆóçö€RR§–ªÕb´j^–‘ZGR)¤iMK„Xkk‰º`Å-§EÙÛx,œ‰¤~m uY6]"7Ìó-´Ú&O*p*ÒDžÝñq…iFjíISÈsV[‡/t%œ²³Vh Õé}Ê82îöh@]Ó'âAlÌ‹.=úÉx«¨­3u90Ï·¦÷Q" ¯\“¹òqê×!Xçrd5{Ìê »¤ŠucG÷‹ÍÄ•EÑùºÓ@JŽ’÷„u%ï’N«ô]VèÙ B±Yh@©-P¥ÙÜŸ±ÛÉvL¿KÍ)V¢Ç´?lh¹ãõ_Ök_×[…f‚Ô&þl÷@‚ÆÁC6ßW{ì§G¹ Öª,s5Jã ±¤QHF›S,ocvoñ‚�'AS²âN#³T,‡k>}Ï‹e� |2Ž(ÙÐH0HbÓ´XÚlàÇ깕€#'Õ¶¸ÖÅÌ4- cF¥ eOϼ‹ÙæšSƒå@Ìæ£Õó7„p4ˆwN�u¦å’(Ca7$NòÄY®ì÷…“}b¿ÏìO g§™ÓÓÂ~»Q8»°Â@>9Q‚–GH m)›NSYc´ž?cŸˆvWYšiÄÐ;±…þ`Ûf€nQàq")”ìïÈá÷Mz‘¡Ò³>wð½î$€P^MîF¼nÒã?d½®Ã%M�šìïE¬H´øX‰Ù*"(É:Ã7m˜žç" ·�‡f>¶(eñå% MûS¦æE˜g˜3Ì‹u@FCÆš0j�ÓI­€W¥‘SóPÀ 7COÈ;UˆwáXaÀüûª&æ›\ĺH&é·Ñ€[Fלr*ízk³1Q´¹�¯é6�93‰œ•T¼(x”Sðç”pÀu²zKöøÈs­�m_µÙFˈÛZ …%^ð9ŽÓ�ljÞQ[¸ÃÝñ´}K~À&ۼͫö*²µä²ÙéÑw×dIwäbÃÞ®Ÿtºë î_;¾à•çwûsü²{½ùÞ6©òI}ùÏêÎ ¯¥öëPäè6È'_ÝÿƒWXºa“ÞzßbïèK¼Ksc­ŠKŒ»Ÿ:ÕŠÜAå©‹ü±V±dóƒGÁóÛÅ4û!ígiÖš? ivîn?ñdÑ?H²4µâµ=»ýQ´nK æ×ÄþÊ•‰õ Yð{âOΙìŽz.�œgrn]Œ)9•Gt̳“÷ô¬A7¼åºæVuzk dIpM†óªÉ:Œ¢‚£D`þnÀl|´õ [çÏ/ÏÚš×N‚Î[늣"ñ¯uªµŸC,ÐÖ²� Ùšpq[mNÖ6™Ä¹q«R½;e ño îÌ4%æ9³ÌƹhHœÂ0¸ñL€¢&>‚ºÃ Œc%%e,�%+E”avÞælªïû± .È·Tut† -9G›ií8ƒ\‚’›ò¦hj,yfiÍjL>'Àª½I}ŒãA]$¡ˆ®–�Ýb}Ñ€;Å):]6NQ/õàÙQfd§Y»Z†œ‡Ì~7rz2rº9Ýì=é?¤p¿3%UÆ;׊XaÀí”´ÊqªŽäœ‰n P Áá•ê�OЏ�a¯ecç}€GÄ” ˆl Ä«=Ûk�ÉöÕ)å|Á8²û[ó®6Ž$’ø¾Õ<áÔHÚ�«ª+ê9ªñžíHYÀ´Î*E,Q"x§ttf?¤Ï7/"JõûÞycÐ4îì»Úô¨ØOÀ®zeÊ êUJL`6gËN.•Ô ¸sec,Ù>û.­qùrMDa`ªíH|øå²p^J?ëGZzQ ôQøøöÀ˜sGÿjåãÃÌgN ýŸEøòýUƒàó®;pµTµvº¡—óÂo<}Î_xóµ¾m âþ¤Ó 5è…€iZ(¢d§ËËÅ©ÇDMóÄÇE$x$59(‡æ÷Þ9±ûn}|uPŒ�°¡cI¦é1ÃeÊ(”AÈdPdp»�¬ð‰w®Y‹°#UOŒU<ø”¬È¤, »“‘ý~ !%¼È×wŸ›êÈèL˜'+ò¶ÅfL’DkÉ êÉh=z^!´v<2U×.Ò¨÷¯ö$‰u )À��]¦èÚQ»ÞÆ`!æ»Y¤bRû#øñšÛ²Šu%´˜Dn¿\?@4#Žêd±.œ¶(mDmÍÖŽþõä@ÎàÉ ÿÎÜ;”Õ™ªp}­\Ý(׸™àöfæövf:T¦©ZRºoakX³�:Ý‘ªÊõÍ¿ükÿ+ªÊOïöüìÙ9ÿΛ¯ó+ÎóýtšùLSÎJ±"QJüö³,ª|åÑ}Dáë/.¹­•/œŸòçÞx�öÑc.—…Ëeá+�î¯ô"<žfæZys?rµ4^Ε¿÷îû|útÏûß¹º±† þàvZ©HÔ:ðâõdšùå“€{ãÀÔ´SýôÃ{Ô¦|ÍEMßÚïøòýsþ‘ ßÖÊw®núº“€_þð1M•‡£ñ¸ÚÿÍýŽ?~ÿ‚_tfUåµqäÉaæà>âן¿ìç™ w,þØý‹Þ…&®ú»Ï_vtô¡5>u²çŸÜ\ñ÷ŸZB3'áø¯ÿ é/~R!í*e¬FÇ&aw£8?÷µ,&­5öKæô°çü*qñ0svžyç­û<²ðüñ³§ ÏŸV^¾¬¼|yÕíBx'�$õDvFj%:XV$iœ“Í— º· ª I‘²YGÝo÷y…ÁÚ*m™�ìØÍ‹hžÜKîŸp›õ©zÒ ïÆµ55øüi®·€²Ô…e90/&(ÙŒ™qlÇXcYu/¬‰q<�#pÕæì,´Q—…CÄ¿ÿD—¯bTkóÌápàp¸íˆõD!Kòëm~Y­ÇFEQmQ£·iÍÄçÅç›-ònŸ=>èÔmã+xvIüþ]œßã=ày«|X~æü¼ w|ùþyïÂx>ÏVñWÐ%Ž�Ï=ñÿSïñ{Þ!pZ S­\9CÑÇ·æ>—tê¯/œŸòlš{á‹çg\”̯ù¼_T¹œW@Âm5MEyçô„{yMè/ó�:_[\-qâwRçú7�\õuiY*IóJ1‡÷§' ÚÆ˜´ª,Ë„ˆÒ¨¤%¯�ý§ÒÔ´ æùqÒªäIå$…$#8‹ëÅ©ää^›ÙöäIžŒ ~SÅ`ŸA³€ ­ ó”¹¹±‰¸4˸%1PA[*IaÉ…,FÛ#Ä8n}ÞX±¡wbB ákJ؇ð-5Ö¸‡ñ€Hë‡�j±æDd’¬ûÇÎÉ|›jÕH/ôà�×벞)ësè[×ÂAÐl†í€ ÿ¾ú:(ˆ??í¿»…ÐÔ €€'ÆR*«o+Ú 69h 90£¹VB° ÐT0Xb†x3¹îSêÅØäÿïB�k˜8£µZ7q6m�R¬³É4�¦&{üà1„b௺4j�-®KÖ'µÎ”¤�]©nßí(tôq£Q[&¥Æ‹Ïøþ{…2ì�ÌåÕµue©uF†ÝlŠu%ˆß‰µÇ„Â}Õðç k옽TÆR9ggp~–999=9=+œž†Œ;Ì/>M¤=ÈØÜoô}u�#Ô}yuK•ˆÕ¨–P+«Ï qä¼bjôµ§úq++b3†›t×5摯 °@·�-ÇŸùØÝ®u‘×Yÿ½Ù.OGyVz¼*tã÷*jŠƒ¬»íù?lÎWLßÑ©Në uV²VJ]§#MJm6gsv=I*…FeF™ˆp¡±T%%£«Žœz<@õbMB}]Æ3f“ŠÃEêB¥6ÞJ²nò¡  ¨P´BATÝF[h¬D)yÓ-‰ÛA5£dih-x�¿eïzô¹§ê¾“x@$%—ÅÅK×B]z›ç(ñd8éwFÍ¿£W:Ù~oͳDZc›¢ÿᯟñÿW¿q÷¨ÛTùÖ&Î(Þ>:†þ cÚ›ýf­—ûêô‰�n·»ûZ?ëSåè˜òê9ô 46þa·2öêÚÿ¯?´ÿϯˆóS2Ô]C‹z5Ü,¿+‹à“Eœw?†É¶Zê­ý½½¨à•-ÖJhÜ+>ôà_»á•ä Ô,höÖ0]E=ÃY0Ç.÷$kˆ ‹ZUN«v¥zîÌS}=°ª­@oMv¹œ)�Û·’³UáGCåb† µÊ<[`_ "n‹Ô¦�ÎZéÖr¸ðjzð½Ê¡ –©%âTW ó³<ù¸Y¿:ŸšOÑx–^@ˆ[ß�î, þÅþ]6Î~ßí^ŠFÂt›85£™¨&r—”1ãjâHWA¤ÒæJMŠzp¹Ûev»Ì8Ž”a ÖB]FQœ+Ñ9QЬcÊ“5ß�”•2TkSe)J˜’2EºË IDAT/F›¡C ^%3M•i®4M4 QGコ|©¸RȘÐp¥ÉBJÕ«Å Á ί@ÊÆý‰?CüŽ?g#Ú7ÕŸ�öΌԯ-Š‘œêâ~Gá ÷ÏUš‹?gvÅ:8Îö#g';NO†^Ø+d±. t&Ke”’+%wV«|»#Ô×ù"_ÎÍæ²£úýo7Á5ñä·�ÓŽ–é6mû{u$̫מP`Û‚Ù‡¯OMwÿ—C�šm«ñÿ�9Ý\ÂF[ñkS¹ï� ‚ÍÞžN8Õ›m“¬÷dk½û#.uM¼¶î˜w‡SÜÞÞ�?u4VŸÇáÑûñ[ŒÃ´™£ëgx'�÷®»]À(†r‚T/ ¬É!»ýV@×Wk€‰ô²) GbÂ[ÞÿçÓÌýqåþÞÍ Ÿ;=é?Ü�G+ß>g>sjÁ؇·ÞØï:zø÷_\òú~ǣ؟¯óCáÏ¿ñ°âÅ�_¼8 õ˜“ðŽÓ ½sËÃÍyôü†!Ò$»¨Y‹ÓûX×™6+d–¡�rŒÆaµþâèÿõ™8Åé´’¬-±Ã Ö�µKŒ»dh’¬”¤4C¥gŸN]3(fÈd±UN y7 ŽÊ³D =ÛŸŒìNGBÐÚ:úš‹]EÁ´6ãåž&·“ë XËÁ‹9ÀjÁQ“ÈÈå)< o­®k�¯Ž¨˜0û!ƒµÐÎ ŒÑ–íN¿¬Îtw�ïÆ?1ߢ�`‘(š™ïb¾Pˆ5‹¸Yi šÐŒ4�–Ð%yQ@i34­·{«Cò¢@ç2¶¶ÞeN,³%š.ÖP•ËëÊËëÆÍ,ÜLÂÍÍdÅ�ÃÂ4U–æ�G[GgÀÒÔZíí ˆë(�_ùõÿ�ÛÃç)ñ—O/øãgü³�žðæ~ÇÃq`̉_þð1ü¹7qhʯ;]È[û?r~Êïzò}ÖÆ]]óúÞGŽÿØé„~úÁ}NJâ×>6´ÿ�žŸñ³¯_ð�ß·DýLJ™¿wÁLJ‰' ºþèê†góÂëûE„ßyIS£éù©÷øê“g¼\ ñøso<âëÏ/ùÖ¥e¯æÊäE„$&þÝ늟;;áû7‡Ž2þso<â£ÃÄï{ãánä,ç^x6ÏüæÓç„FY~ÃßÜïH"½áõýŽ/žŸòk~�ª*WKõ”�éáIÌ,ædI|»-ü�?ì6å¿ýO~Ž¿õïÿhoÊVìóޤXóD-q4ứ$†”�š%-Í¿NÞñ$Ne‰ûl"á¾Fª,´Šñèg뢭´î“XB K†é²ÀtpäšýRˤ–:b0éêK‰-[q ¹_݆hm®¥"D²VRvÚ^�—™y9˜`«©1›ÏæÀˆèæìXY‚ߨ}^ON…Æ£¢+Â\MÀðÀ5ÝÚˆ¬…ÌæµÐ½rM� 0ôº%Qº.Uó8¥ë¶¹è™6ÿ©ÕÕ®`µMrÚIºK v,çk�X„qØïN¸=Üð�yâs= vÙ’ŽÑIpo(<Ú�|;t Tyçd¤Cð�ç—Ì¿åû^D8É™·NL+$ÀEí�7ù…÷?î:7µ ¾ñâ’E�ráõÝÈû·žO3I„?ûÆC¾þâŠ�½Sá³§{î�COÔ:Ó–C‡+$·É�M©"bâ“Ûâ@�¤à�—ÈŽœ‘Ñ Áu6Ë¥:bÝ©u¤?ÿŠR©m¢Ö[BØÒ½…œF²ìL»G’Ѧ’zaÀºn=.G̶‹AnµæÎ!ßùïÄb!°nˆiRªÆ\�7?IÄ–aÈx’(â;/.ÕHŒ»~¥¬HTÚÆ>®݉1ö.bË3Z¾õ8�qŽA$“%u�„( X~(`ƒæ¹6tðŒ6v=Ÿè䶘»öŽ�¤Mžì:D‘¸·D„ÖUO†ÞL{ÐrÎ@Þïe£$Ø ÙÖê*Ì‹=‡V]¤™¸7Q0=;Ù�«MìÑ©àºSv®µPȱ—y�˜P¼›¿t­µéJ“ŠÙ©¦�Ü6Ý™y™ÍWJ!ʪ°Ì´e¦ìJ2±T°NÚ!{˜ÐŒ>Æc¢çÏŸp}sMÊ;H#‡Éhœ�"ë4“¡GRŠÜ�uÔ$G�«�[‹�…•Å 6Ê.WÎ÷•{gÂýû…³‹‘³‹=û³�“³BÙAÙ)id'0¨uTw1ß(Ì*&ºëðuwUŽ¢I¬ÈMÔ}pbF¬Ûö… �íéö‡í¸yðýhwÿ~5«)ý¬Žß[ó‰ºùÿ'½äh›;Ì^Lê~Í/Ac=ŽÃiêHS«�Tµzl¶u8×™²Ì ®ÿS“ÅIÄ;è’hFÓÔ~²¶N'ÚT: ®çüÄ:°]µ´MzÌòK9DšÅØC±bÞn0-Ç$J«æû'ÿ^v}4[;‚¾¹?§™îÙˆªÔ[¨sóbµwfµÔÓ±.ö\HÊÞE-^ts4j0´ôt€?›È=W§7óý[~A-¿ á¥=ûµ(ðêKûzõ“öú¤úö(ŒÉ:ûDУ¯lSHk†u&²~¾9�ýïxB‡@J8âöæz´˜BÊ�Ó>º*]ßôs?ªȫ۽z ïNöOÚÿÝ×Ýíõ•¿dsͯ|5Ö¸ÞÃêU6ß Bg[ Ô‹òJaÀmÂùyýº¼Ò\,‰Üâ%“Aæ´VãjBjC¼z ®Tn¨9z[}UÈM‘E`çÙuÄxD'~WÌwñä¿°3û±°ßv»Â®J*”¢^H¤Á3;k‰\,y¿½G=ù×%6̉i¾ÈÕ~>ëóˆvG_˜ÅÈÍׇ¸‡Ö©'ÔŸ®® DÚÎ#o#Z?Õãc³®?ÇKÇfû£ ̲]“Q 5çm«në’d†"þc±o£[j–lÌ ÆÑh€Æ]öÛ€¶Â°{âôUAÀÇØ¶Ã¶OX¤|åͱä÷Õ*Ähk,óÊœîüž[p6ºS¤ÊM­œmîÑ ¯( 4Opäþ]øÆËK¾|oí.âxýøæ³¦ÊÙP8Ãw¿÷ü%_¾Ñ÷÷OŸóå{ç½(qVr×7:ü¨­×öþ³kÆ"¤"Ndu1£­°î%­êTCšÐVœ3Þ÷ÔÆqóÂŒú╜Ò)¨ƒ†"ŒÅ¨ÙÆ1[WÕ˜ [1ÀºõÕ‹rAs‰u+n—œ‘RHƒ¡Uòn$ƒÙ˜R”<¤ü—]²u< €E:×?1ÿÝÛ–Ù aÛRr°€øqdUÿ) zIÍ4Qš%óÅ“l¾Û GŤ!¡CœO^�[0‡#œº[-oË×N[§ãMG¿mÇ¿w�‰±¸ ³ Kò6éÁ�ꎼ6›rsu4Ó©“S Úe›×ß\)¤¤®!ÓÜ8Ì3×7 ×7�Ã’ìg®Lsc©Í4jøV·ýÕ;@,×Þ5BØÿúwÿ)ïôm¾8îøÓ¯?àû/¯y|˜¸^þê§Þä;NwƒSmL oîv\µÊ³iæ÷Þû�OŸî9/…Ëyæ·Ÿ½ ýÓoñ�Ëk¾ï óœ¬Óg—3·ÎCÿ[OŸóé“>ž& ƒi?óèsk%ü¥‹3¾|÷6† —µ2Hâ@ãÁ8ð ïÌÜL$yŸR×xûdÏÏ<¼Ç?ôN�E•ÏžŸòt^¸qÚ“o¼¼êbÁC¾åƒ]NüØù_{þ’§þù¿ýöëüîó—]äTÄ(œâõøöÀÇ·¸ïÔJßòsùüù)/ç¥'Iï»¶É QþÓo»�Çÿèoÿû?ü¶äE – ÷q-Ù;ëË’¢PmŸ‰$ ³i+i†\O åâ„݃ ´d$)7Ó5~|M]ŠÑŠ4C¤b¾ïÙéž‹ûçè2rx™¬C¥E²spÔÝJ÷@,e>߬³Ám¿6ÔÖHÌ×f™‘:‘ÚDá€÷Ù":[AB„ÁAºIZ&�˜l¦IÁE >“Q˜ˆé†©¡æ5=†º,ˆûšêtiª_”ù·žT¥âóÕ¹®ãòr û:ø'þ¶ýh QTï@Ôæ šjîÇÒfë¶’+��ÝçwM-T�XzQ7üC¦‡�b×%îôU~›´ÎÏîq{¸áÝe¥úÒÅߺ¼îE®‹¡07åv²9p¹,=‰ogHï–ym7rµÔ¾¯·Ovœ—Â7}¾Ý�pøï}„ªrât˜1ï>u²çµÝØmĘ_ytŸ'ïÌmµk}÷ú–É�UDøêãgüø½sNSâª�Oò„¿ùçÕ}èä÷E )ª~)ª «F˜=ð(º¤¤Å‹-Å…em¯>W; |ïôP�im¡a Ü�œ0–Ä8Œ ù(–xr \ã®�ŠÅ»ŠQViÃÆcV„…¤ ‡6Qg?N›‰nxE�ÏÖ †%§bÕÜv#‡Þ†¸ÿ™³�HvŸÂXlûc­Z’,:ä¢Ã¹u?eò±"êùE§=ÊÝ­åíÇ¿6à¿MÖÅÖÍÈ¢l€*wçàqè‘å”Í^71¤ÜÙRmí\í®ÜùùA¯õ~ÇÞ·a±¢Äši_qÛ¥Óû\°‚¦ÝÇ>.ùzžÇF©>/E\¼8“Èä”h¢LäáÑÕdÔ’K±IF¯éûŠ8…’2c.¨/èt lª}¿I¬Ûc’ÑcïŠQ eA›Ñƒ¥d…�\ (l6Þ;sï Ð]þ,.le Uñõº­l¢6,ö@hÉÁYY�b«O~„rôÜ-FW‹÷Fk¥Û�×Q¡D`Ý¡nö«Åݑط×;Ÿtçj};gîîåîãUÖÄ…lÏc}Ý™3w_rôå•­5 ý&�ô�-WßIŸ¨m{ç ëVGóͯ!®å•×'Môígwß×Oøü‡Mêãëß^EÐÀôÙ'µÞÙm æ”6­Îgg×§â¨ï.4¬ka`zKVøÛ�­Ææ^¥$h6©BZ°q̤ªäÖèíÏÎÛkâ%ê­yö»65ÑšYI‹)¤×Em‘{ðS.É’Á¨ ¹–Ä~,œì+ ì CÈ^(ž,¡$7¸Ú£*µ#ùšZÅØt’UI[¸8æ4êÈÅqÿÅ+õ8�ž0cÐõ>Kd¦õ¹Ò‘ tü£#*Úëò%›…)†ìvÀ¼2äÝp‚x "};?Çnº}·ñváÚ:tŽLr‡=ù¹‡7ê‹]_ô«9ö}AޤM ²Ã¶~½¶¾ü®q·äóÚ羡ÖóE¡Óœtz£ÖÛ’i–t ™í¡{#©¤tG[ÕN\_ÐÂù(ïË>ÀPÆÚ´.}HkþXnûJ"½(Ð�ç£ÛƱçf©Ìj¼Ãö]ŽŠŸuÝ��o'†$=Éÿb^ø£ë~ò¾‰'àÞ8ö‚ÀŸyý!`Å…ªÚé†.—…ýôÿÖ�xsX;¾ÿôšÝ`Éó”¡d¥d ÄŠšÝhI¼€©Þë“i‹2Œã¹-†Ø3a.\ØzE~ 9;ý—L ¤`Úlb<ßY,‘˜²Q€Ø˜õg[@ãZM;È“¯Ue°·'i†]îȉ5<ø’�19×ÿJÑ%*¤¹’çJ.˜714]دžàÏB+Æ;ÎP"N0í µB†(«ˆ[h„ ð ÂÖÑŒ eÕpžMõ ®mm‹Ï“N͇ôDyð¤¯ó sÈ}N˜¸Ï�!Á,0 ÂÄ…½p£ž›«a'›Û�T¤w$¨s”Z[½Ùº,&X¹4ë9,ÊõíÌÍíÂÍíÂT ‡%›¸pmÖ ®£ÔÔ ž¼T1@BLK_K>øè»üæïü2ùäœ?y~ÆNáS§'¼\*¯ïGþé‡�;eÐYÎüêGOhX‘ígï=äçßý€E•nüñ·îñ/ qŸ’¡ý/—ÊûƒðòŠó—.Îx}¿ã÷ž¿äéd8ý�7ùÖåu·w×ËÂëðþÍ�ï\Ýðöé �†ÂGÓÌo:ÿøŸ}ãO§¹w-¼±¹(¹4.ç…¯={ÉÐ)'à—ÞÿÅ´Iªj× øüù)_º8ç½gÈý¹5K|‰t”ò?ùà1³šJI‰~ÚÑÔϦ¹Ó§„-zû<ñŸ}çÛAý·þæø/ÿóŸõD“Ú¼+.&› н¨i)Ùû>pŸ±yÁ@³Í¹E­²¸¸wÆîµÁ8zSãã'1þá © þµfÚCxpqÆ;ŸºO½-<©^8/zuZ‰N›”‰d‡ NÆêΫö.Äê yÓ&S¨,·$�Òl>³ªM-ˆ$F’#§Q×òò m 6íÝlFãh|àÑ5YÕô8*�*j…�6S=Ags>¨{V;¡±z‘!§LSK⊯µkÁÑ’ê~Es­”¶Eh nES“¶öÞ@.ÚÔïQ¸D›ï8*{Ñ q±�6¥icQC‡J·oæí�É&&ì@ átgsß[Ön�ï^ßlü%[_Á’„÷†ÂÓiæàE´?ÿæküÓ÷y]âZýeIþI„“œ¹ZþÐ; ¾òðß¼¼æj^úܼ^£ÿÂÖâmçÀU­üü»¶ö¿œ×}ýïSRâ«�ŸRU¹W W“iI$"ÞQº•:]ƒ8x! -(Z¢›Ü»=-¹o‚¿Ú q $KXeµºƒÁº«›N»ÒÚbcªÎ´:Sò@NVØ�g¨fæÙ Ade¬“oØ™ö™}miî{)™JÖJ[n˜h‡ÕÉÆ—1¨d¨j]íâhüH*û(`TDÚœg?!R6"Þ™¢¸æ�éð´*ÔÙÖâ$N#æ )iÇ Ášà €\s0DÉÙéxìó ç±81upM“†ÔXsÕ´Q\NTÝÏö£I2°S±.¦ð1­3À;ÂR†ùºz„ã¥Ï»`-HÙº"Ô0@œ'ûï€â\AhK¡ÕÙö×ýu0�6Ožn}±ÂF.#øcŠk?)m9PÓNiÕ»—ê ÓXÚDÓë~†L²´ºW�áí ݯµáÑnó­ 8ˆƒ¶Àr@ë-ZoIõÀùÉȧß>ç�G÷ypqÆan|ôìŠW7S�M/£©uI,p;=‘`넦B’Á,–È/ožGØU¿§‘�NV€^E4ü«‰qhœì•‹‹ÂÉyæä<#C#�qZ:Ã…BP¶õç(> Öû;õÏØØ–ØbýÖÚ˰�!û]�¿“¾EõCt±yý~¼ÿßþuÌý,îæ6�ð�£½þ´GînP÷m,Ý�CZÚjÈÚ …jëSn�ÁçåPŠ��[ƨö Ëú§�Œn:¨%ÑœGTIÜNÍ5Ô”¨%"0”Ân(F‰6/½¨ÐÇ Q££ŠukïX9Ž…¡$T�¦ÍlP²å5hÜÌ´¥"‹w5ªë’$Ÿ{2ƒÍÛæyUyµ@Àµ()7×*S"9¥þïmÞ[ŽJ.¨R}ý[6™ÀOz½ú®Üù½�!¯n¿#ÇŸmÇæ'{û*ëa¶Ì8˜è'l7çÎ~Ž"»�Þ²÷ìF¶˜¾ŸíUÊæ—ÿ/h6Ö7ýz÷ølשո¤þÃoØñ=úä-eÝ* j¸óî<¢t.ê@Á®§Ñ ¸¯•m·‰ÑŠâúh+‚¯ a¨U_ãDûym0çD³ÓZÅÚŒš�ÆŒÌÙâmíèœsMMÀÑÛz[ƒÒ”²y–Ù F½˜hKêœfu�:ŠÀ¹Árb¿3DõX”1«Ó'Rðzm×²4£Ž�¶Òù¸IÞ¦âmÙˆÐHMH˜}h ¤*4IÖ) LŒNéæû”ŽnОµüžiOlÆð7Þ{�;V»Ívz�,Šïʺ€FÛµ#H’qßÒ„æc®ÅŠñ[&ß~̦Ý�€’”2˜PRNBÉb©ZÕ_ÍÌTVÇ=eç8¯>&Q† ;/*Ø6ÞÊ%Ð4Q[bašÍ)¦BŸ2!ì†ß[s¶Ö€±¶õ¹˜Sâ vILLª©·¶²ñ69b6àsµVÒä– a”kqqý#žŸí=0nR§è²W,Ö«#g¦Vý£èÕì¸ ~þ(†|ñqß G$³×¬W´GH_çî¯^€°ÁnöP<@v»Ó“äñˆu5¯½ §êkGÜófÁÚ—õƒÞñ«ðç£æÇJQzBUÒæœÖêEíþ[Ân;—­_�£–±ôD¿FëMÛ"T"@ôÂI Ô…ŸÃÑKúsP‰ž(›Ÿw¯ó“^/ç…‹MwÀå�¿ßØï޶?Û|öÁÍ�·6ÂÄ¿ÿâ’/œŸv„ÿ]¡â{CéE�ÛZ�~È(‚~ïÅe§PãW>ϽèpVJïESë8›­8�›9ù’ÔÒ›ÙæÉ¢†^]šÑâìò@–‚£â”‚º W§ òŸm}2ÌR‹;$€·ÖEáõí%¿ø«ÿMsæ3û_89á×?cH‰¿ñΛ¼sàׯŒgŸÇ�]NÜÔÆT+¿ÿâ’»wÆãƒÑ}ýýïÀ>'þôkhª]XôG/Îø‰ûü}OÚ½\*ŸN‰7v#Ϧ™“’ùõÇϸ©VŒØIâ÷œÒçS'{~òá=~ñý�˜›òlšøéÃé ¬“]:åVøÕÁ‚ꂈ¡TUVdªp Ã0|UM“ ÕF­ ¹Fwžk Ö¥Þ,>Ìa?p]›�º€«b¥N ¹�÷¢h$,ž�¾ÆµšU­¼3ÝŠâe IDATGƒ`À¸ßK5Ũ•þ±ƒÐ$|Q‹�¡šŠfd'Èšmî5Çô´ˆq6”—,X<ì´3=ÙGWKœ÷ŒÃ&ãâäö|L;P›ÛÓðÉY ²8´CÜ7nmõ¿ûËA:k€m׻̷vŸƒ*'ЍpHVÀé6H<ÞrŸDB�Âc~šuÂP‘6÷‚Ô:Qëè�xX™—……J9�£�]O’‚Q­)$*‰Ê2ßPç²ÈL<8xtqΧß~Äç޹ǣgœŸî9Ì÷Ù ÂÍmâvæZ™–Æ4+Óû¥®µ ¹ÛIü>ç£õ�þo·úÜ™“vÚÛâñÿég'™³Sáü¼pz^ÏLK€ÜŒ2rhHÑ®‡©É5'»@›¯Å71–óùSË6ºŸ§ý?ÉÝó÷Ñ(ºÙrý^_âE°ŒÄfý_Ø+ï„§ ›÷ïÉöøw_ÛÄòѽYÔ¡·W°´~Þþ‰|Â~$Ʊ‹ŒÇØVŒÁ€”+„•t'Т0`4Ryj�©(ùy†aÏшÙrŒ¶9%%IeY`Ií”ä`«‚VX²²˜ne^ïvIFo}²+ŒûÂàl¥˜_@3ûžg õ5?r›ø<¹oa4å�ƒuctä©9$™Í4b¹®Y¬GyÈ”!ý™„ùRÏ�?-‡—:hÁ‹Å�4>awÇÚj×nš%Ɔô˜l;/âoyeß¼²�°Æ ½û{{^úÉcü“ß\?Sz2ãƒãŽÒQÁ€ã)v„†Œv{X#Öø£ÿýIøøœ¶·U6ïonó�×vÇçø1­{=z/¼Oçèë1Åf0w�Ú‘¡[Nþ^È6>P½å- ¬É£õ>Æ$µÑ#!Êš°ÖáfY�Þ…´$¨™ÎkßËijAAnJjáà+Th‹P¦ä¤&´&š–YŒâÁ‘ÈYl1GqžõÆ ‹¡Ô‡äμñ,²%n¬�¨‘² …¹7`ñ›P†l-â)Œ¤-$¥&¦emÅJ j’NiÓj8ô\wâ|Ñ1úíÆÊ<o}õó1"c[Ù,!¯ OÓ¯‘ÜU;â<®!ÜwÞrrh5‡V«Y®,Ù’^ƒñ!7´‚P±ºzuÞ×X~*BµÂL²ŽŽa0Z)]ξ­Za Xa »c ·”Â8ú³ö¶pŒçæyí4Yíãö y÷G8¢¨=Ëôg× Ø¢±eÃl¹VÅ„HÅ��©’¥yQ¥²%– >_‘ͳˆ÷»ó¾µá,‡Åv-¶ tó Aœ®ÄŠ2Ãà¹Å$¤”] ‘²Z!ŒF$®º¿íq]pPMÈTî& êúOë&Ûm¹âïuÛ•’G»Õ-f·:~kË6ûZC„~¼õ³õœûøß¾ó@Y¯Ý[ÍWCÙl*Q4õ"²ù¾¡*±&­èÀ Ñ£u*l·–kÀeÏ©y»®x+”–cYH°¸–‰}Ïéâ^9ý�$+x®÷Òï[h™TµÀºB½›`ÅÆêÔ q¯‹;”Añ÷­o±íÁ“oŸÚîvDâ^UYT{a`ª�o_]Q }ãÅ?qÿ¼>}º7qO½}²ãí“M•?¼ºæ‹çg½{àj^xX �—…wŸÜPÆ¢ãî]x‚-MÖÍêÂi"Œcf¿W´¹ð”íšú˜0TrIfÆ’)ŊɆ ±m«˜M“!YÁ|—­“§6ó£) À"H_¶·Þ$VÔ¶ì!„©ÚÖÂÇX`ÉñuÁV™°Z•Åtcœ·X22dÒP�!¢6Y‹T¬´æØ:°¬”x-ÖPUo>T/l¥µ@˜|ÝkwÆb*îüÞµžò;j¢_§UxÜ?Y|�•XÍG© ëJ[`Z0tñ ÊâüÎVdm4æ:3Õ™¥.æ˜ï RR¿þ(ˆ°À‚Âè„T0Š 0¡Ý} R%Þ»¹åj©|öì„Cm¼{u˯}ü”/žŸñÚ~ä›/.yruÃ�„¿ñÎ[|óåUçÒßg£qDXÜ>üÆ“ç|áìŒË:3¦Ä/}ð1cJü…·_çñíÄלäGÏÏxc¿ãû7·(Æ9þ�ËkÞØïxïæÀÛû=ÿð½�’ðå{$Y†Ÿ??åÇ.Îø?\Ó aÉËýõ 7NYó[Ï^ðr^إĘSÿî£ÝÈÏO»p±éÍ×øêãg]gà¦Ö#Š”ï\Ýð‡—×$àÍ“Üz’ô'Üã{×7½ðpiÚxáèç©6ö9ó_|ÿ]¾{°déç>wÎÿòwÿ§Å“jæWKdøÄù„b5‘ìþ”ÃÞÜf¬ÅµÍ:×¼r%ÙèÅRž8½hÈ[o¼³ãSŸ9åù“[žçC×'½wàÑÃS¾ðÙGüÄ—Þæåóóõ××3Ï_¾„z ém{$ïѼCÉ41”oPŽ•ˆÍãV+ԊηètƒÊD“…,"v»ÌŽ¥8í…V–f”oVÈè2ЖlE�¾ü[$ž¥Ð$™GÛ ¡±eŠß&:$ähÖ-d³‹ÑeklÖ¥úO8¸BÃ>x�ä¨pž$ì¹¢ÚêwG 8aIEõ®Õð6,q­ÚOU¬‹8@Öùd÷"ö]›%Aëb<ð]'ÆÑ¯½àà~åö^HØ�'ÜN7üó›+¾4ŽNo OOX_Mµwé|úôÄæ°Ÿ÷çÏO9ÔÊ{Þ]SU;�Xg^íF®7¸Ïœžp1”>WÇœøôéÉѾ~ûÙ &5Ôht¼¾ym7öBãk»‘¿wνÇ+X ÖÆ�Š»A­SÊH}×Õȹô—Þ�fnZ²ñ\ïúÂúHëTII:؈þ,íÿbì]žmKŽó¾_VÕZ{ïóºÏî{»/ ‚I‘)J¶$Úz9ì‰gšyhÏ<óÐáÏÌ?ÁáWØ!‡Â¢DëAðaššE EH _¸ï{Ï9{¯UUéAfÕZûÜnÈ»c÷=çìµ×³*+3¿/¿,äb�¢U3Bõ~ÍWOR›Vµj²gž½�Ï\ {K¥Ñd aôD¯­+MNÚXz¯©½z¸å7‹6 »J–zh¿~qÖ,«q¢Pj¶#XUR-…’‹Ï³Á%{Ro¸i÷séßç»±{îY­–S¯êê|Íux÷©›ßÚô0œfÝsÜ ÐJÐEV«åòlUìm¬7iâö³‘ËœØ}ß^9€³|£ûAB·Òã1÷ÁÕ�;ZQé׉û-yªÔ<Ñô€šòAŒ–w0Þtð*À€†Ð³Q½wHó3¹‚KGI™È5“‹]sÍ™ ‰³Xö9Ûõ¶û’’U´‡&ÇÛP—LÕB¤¥P¯(×/Re3TÞ½Å�î<|ã÷ïžrºM IØ„ªÆ$\^ÁÕµr}˜ØOÊ„ƒqkˆ"feÊÔYKh¶ÎÜÎÜ4òJ«ñAHˆ‰Sç° Â0˜ôÉ6r~pzf ‡å$"[YrT-¡›ÔóU…êú¬Ëøo¹÷²ÖÉÓ£—Ç�6æíû«ˆpµ¯ѵøíæ«Y"e±Õ¯ÇÖëü@Ûãz+ymûõ¶mEl1�¾ö�›{äµ}g0�Ï­Å·ËêÛì¬ïI0[é9‰1aÒ›5Ø[� ˆs%�Æ@Ú’÷6«è•Y6B¨2sªä\ ÁH¡›a`;$“ÝÌ80=ÿ$Ç¥$ì¶Ûmb3&†Ñ•¢��V©¿Šó[_‚ç’v™RqAB°˜üt„1!Q+¡ÌP²Ç&L^Lî*áÜGí$ž[¸ù¨@Ñ�ìAÅ+¢í¼Z¤{µê•å™êÑo+/j5––üÀÒŸTWç%«m–‘óú¸¹ù²mÒk ®õ`Õ_íM^ûáõ�¯–> o”ĸûöÚD•ã·Üü;«äO,¾Ák×´Læ›Sy…róF}·#=õ?æ[,†ha…ë곘tÖ�q%›\Œ!lr¥7 î @gû­Œ.÷¥Ÿ�Ÿ�²0l¢ª°8öª¾_-Ë黳ÛÍëªLfIŠ€d�bêlUM¸ÎPg5Ð`²$—59±KH±kšlF ŸàaAØX±$Fk™Ô§êr-Vin—7•Šm*s¤yQdÉm½¯Væ]«˜~±Z“�ܘƒ.%bl3ó®ÄVR{( ש^æì‘Õº�,`à ›Eÿ€Z3³¶0c†Zm–aÆ`Ñc¨¤PIÞù]|NQ‡Èf ¤¨ ƈMž•ö«?loKäçÙzXÓI �’1Ö½´¨N¼R®ǚÚ%VÖ$Ôœ,?‚*›Q˜·-¥$ÌI(Y˜#„cmª%ÿ¥Ÿ™UHD_ €&8íúòKy:ÞtØJb‹T’Rp`A,¬ˆ�÷åXËä¶g·,ë‚52•^•`LÿVÛ2gt€ªU¤hL)‰±±4Ú΋¥¥<û[= mC¢,kãJ·²•È«/LMç]Ù\KŒè2ŸÚ_ù1�­´ŒÁż®–¤eþ¯“ÙLY9[G†òØMë6im·»)kãŒÕÛ�ÛOÍŸ‘³Å™ãÝòªÿëUEkÆáQy¥ÀT[R�ù%«›Ð‡G[ÔÕB &Ý2xr–9R–&…7ÆÎNjÌíF_o:8�¡d³$ü»Û ÂÆºnQU{�0i�›}ÖyÿMG Ðõ]´ ÿùœyr˜zá!ÞñÊ€öúÒ� ®²I½�¹”ÑãÃÄ÷.¯ù™»·ì<1ù"|<‚U<GçÌa.üù“W|úÁ ÄR°OÄAר�M®@¶“p=^Ã�F …H ÑA�àŒÞ»VgÿË6,Mx“¸IÖ^±"m¬V«éIôêMÐ}>!nšÚ…¸ä–­íaIä÷õ[}œú‹f_¥XÒÚ¯º9O b\ú�4À©U,ôž+}ÀØúêà˜åç|,ú¸Óª&!W*�Æ+ˆ'ïYÆj_DÄé!�¯ÁþS/òÔÕ¾ú ¶ëëå Qíí¶µªZb6)ÃR¬ŸQ©fC(Œ©�¤7–šÔ¢h¶~GÉ”ÈæLÿ¾ùïÆ„Ê½bÀ�¹ò\+&�µæw´YüÕ¯ÿ:ï¾ÿ-~iwÊO_œó›<""üå{·I!ðÿüÀR~?ï6oï¶ü“ï€Ï白8å|H<™f61ò¯Ÿ½ ¨�jcHüþ“g\åÂOÝ>çÁvËï>2&oáï¿ýfןjåñõÁì�ûï_ïùú³\Œoï¶¼{µçù<þÞÛøÖËKª*‡¢œ aaˆ«òx?±/…1F äR;cÿ‹·/Ø—Ò{üØÅw7c¿Î©T.sa�Ù“ÿ¿öÞ(jre ]2è�í†OŸî:ˆðcçg<:ÌdÿîŸ_^uAüw°¤å››‘³!ñß>úpiçsq1ò�þ÷¿ËÃ7·K•YKz‰øzÝì« Ì¦yÛluu¿­k®ž¼ {5ç·UûÊLÚ%vw#oýÈ]~bú4—O'^=9P&¥LpvzÆ­‹ >ùÉ;¼ñÆ–ÍPxóaâÕeàj¯H(Ì® =—Bž(ƒ½Åç·¶õ¢-ë­L÷ ê%"3!fNN‰û÷ÏxðÖ¶»DÑ™R2S1ɬ &Q2 ä90Í…)gc›ÎÖ`»–ÈáZ9\W¦ëÓ ZÊHë &!P¨½¶Áü¥°`œˆ%„êÑ]ìÌÙÅËZüåæQ­ÙÉÍtÊjÝ“ kk­Õ©®MŒôß¼âi£Ùºï}Áªm�ší5]x�•ºÝï)ˆµkЂû§�JnÛç»Í ûéš;Ñ*hÆØÅÈóUeÀ—î\t -0-@ï’ÖNcäeνòà/ݽÍ<}Þ{<Ünøpè}žM3/½@°êÂß{ü >s~Ê×ûÞwàçïÝf*µÛ˜›¯sæž¾`\�ÿZêòÌÝÑ3žÛRï¨hm aµå&T¡šä“J¥f¡æ�‚=ÎÅŸ]Í2”ÞÔ;4½(h¡”ɤ…ªK«±~xE©eæpPr�I9ÓŒÈÆ¤Xë„´FÔÕ{”Ù+µ=‘¯-Ö®} …°ôDóçoî€Å/Švÿ²55ö˜T �œ+5W“ðrÿg%_Ý}ÓÎñ龦o×úâ¨ô\˜"ºïIKˆ‡nö<ذG):PfòC¦Ã¿’ªÚåZ›”ÇÒÇÀìo­If'ªÇr‹¸Oîß Þ¡;û,¦˜Hw“ÕIY¡ûðµX"³ù‰qP’ŒÖ³0 ¨D«tiÂ&«Z«IélÚFYôч!ep.r•/¹œ'ªzƒõ0‚³¨K»·*Ô¢ä\ݶYLű¯›m`“FR¨ A¹ŒW\ª²…ÓMâo^ð£Ÿ}›{·O8•(LIU.N‰�ݰázׇÈ~ÎLY˜f¸>×\]W.Ö—0—bÕ7±ú=ñ¥°.$¨ Br º“ÛÖ�k\pº¶;eÜxÂ9)’ê"wí}0µ ÀUÕ;¬’œþ¼Í_\âñ%¤qÿ´� õñ�Çôžl~½÷i�¸–× rÝkê'ë—t*ÍGíc<»Ýã£>oJí ×?ÿ�×q0óýf„Ÿ÷ Åοå Ü÷G(°úWI£‘t7�tHf‡ ô$¤Z/‘J6Æs1` †ÄÆÑjþz“[³ðÁV÷Ä$ܶ&Á< BpÅ5rR³ïžmÏ»ƒ¨‘†5zœå׌¶£8Æ-iïy »?^½âWÖÈ~­j£ÇaîHô¸»ãU (:(Ðn»Ê‘M“eg7å £þ±Û­‡�öTÁzˆ¼�-¿”Rv{­27Ñ‘›scçrs�úC~õ…ý¸©F?}ñÛÝfy+߸yÌõ©Ýüùµ#|ÜÕ/“äã_7®_äã.àµ}¿nŽÚ.õè™#Çà€ønAGh5®ALg¹W èQi‹½ê ãy|²mS]3´»÷ê•êb¢Úä;ª£aÛÏÅr!YŸÅPÈ"/Íãü Ô¨¥š|‘‚¨Šæ0e…šH’–Fž ]óI"A½¥2¤Ê8@„RêÊ™±âåèÎL»×ólúûI„Ö`°€Vc @`²ûZ™«º¶#®)ìáLp'†F½ðfÅÙŒLéåŽh¡³UBt#Ñr6xhâÌh#cy"±zywu6A°ä~ V�B%Je3¸5VsJ�ÿñ¿ÿe~ê ·ðˆÔ†_6mèàà™õŽ™9^Ä]]u¹-gŠ÷Œ°t®IØdwÙ�Í–”6¼óù7¹ýÆ]Ê+%¿ªÌW™éjfLÛqÃéÙ)'§–„zóad™Êȸ�Ùï…«ë‹W3y/ÀQ‰Ô¡š,£UK¢xƒÝz‰èKBÌÄT¹s÷œOæŸùìC>ûùOp~±CÉä23M3ÙÅ¥¦ëÀa/\í÷\]¸¼ž¹¾š9àpP^<¾æùÓk^Ô‰ùjO-è†0ìH1P‚0©;šü£8fY¦—$¨ª³Wks·@Ç|Iw° éI^íñSuÍïÜû+Øcœ0`v¦›'wœ» -þðe®xòÒÛ¶}ð¾@¶¡‘�pV­¸ °ùîVIh±` 5ë\˺l[cûý—åðýÕ@�èɯ²y°Ý BOÜAøôÙIo ô¾$íõ · §)q–b¯Ø„À/?|ƒúî=¤»H‘Ç«˜ûÏ^09xq��I„Ÿ»w›o>ÉuÎ ë8½Ö^l³Ž>ͧ\ž›%¡Ða!üXÒÚª`왌N™“Å!¥Óˆj$¤¡ 朙s¦IOÒÇ¢�—Zgæéš)]3¦=)Y£ïl-�‹Í �”�! ˆlH!±M•1dj�­—G1€­º,…H!—"Iç-‰àRFÚçM_»[jkl)–b½Baèq©é` Ї^;é ¬6WÌ}X.®Äçµ Õ3AÖ"Û¾½�� Õǵ  BgÆ[?À­/A­•yΫøÕçN«l bÏZ„â~uUë�gñ¯ÝŸVa°9Ölî­‚¬ª‰z‚¬+ÅÖ§R¬ñuð$¦ˆZ%üfDC"W[Ìj•é@©Å°Þš©AI¢Dɤ œlN7R4’ÞÓW…úò9š'2³ÇìÁ%™Àµ(Y¸÷ôª…qˆl’€N$­Ü;»àþ�s6IÙ$xþxâùxeÀÀ.ò©·nó©O½ÉÙ6ÂtI™3ó<“N‡�á$r²Ù0�$¦¼u)!8ÌÂõ®ðâræÅåÌõ^¹ºv` i¤!Z%¿Ë‹ZŒ:Dk¢<¤¦Bಸƒåbv[Øm…acºí&¯åó>bHPós›û«<œ{œ,·-P;ŽÇ—øpõ¶Ab¿O‡° 'W‰Ü#«xüÛÇÿ­½Öüa¯ÕÉù<\¼ëøT1fåÍï.>ñòÛ¿í¸zã-¯}Ú�v. ±×õ[–ü^ „!"›D˜u*ä\¨Ù€CSÉhB´~ ¥(%›}±R$Jðœy´ÜS#_Tó£b Öô} c#giÏuªWy¶fãý´oÆÓM™Âô®\ï-À:(¤Ü%ƒ-û½"8ù]l?]YŒÖ?¨?’ÕMÕN”nyPjEÜÜiÿñõw°ï‹'ýÅ�Mhà¥wí•hIqû@—`|Íhõó¸Y’²€¾q¯…² ¶ª•Î ]WÏöÖ®Eì+=¹�%ŠØn’,1RQè¬hPj4æˆvi9퉳Z‹±û¼a‘¨—_úd:rvÔ¸ˆÑ‚ I©ÉnMi {¬\4¥èÉ ˜ƒ%‰#–Äέ««§Ö€VÓ.J°äAVfW’ôä«z`襱`•Iˆ¢9X9’{†²²S1µ„°7š�-A_ýø¥;VÖd)RK4-þl•)ˆ'§½yfPÆ$Œ£5oÇÈ8Ä®›=bŒu/íŒÍ`ÇVgV7,‡°,¹¦(¥o¶eMì¬ÿ¦}îâ<�$Õd””æ$+Ã(ì$“2ŒÉ4é²p8T«þ˜ Ól`Mƒ\-9}¶¤«rl·–‰ßHû)BéYÃJ19”¬J¡ôOÓ‹_’U ¼ñD€HXÚÛt[ó`õÞÎñç|¡kk‚4v{Ÿ¿>®_[ÜÛ�ºròݘ8¹Iõr;_¤¤é•²Ú]Ó­>CCÃÛáXñ¯�ónâWçÞ¡#Ó¸œ³Ò®©ÍYìú@Áе~c[®[Ž@cèÙÅTÏÛ©·ë¯¨7ìRP+ÿRZRßëüUÛ܃5-«çà' ˜µŸYùwl2tŒhŠÖ¨¶S$ÝñëΪ!¡°rW�h¥ÌÇ£Y–Û¢Š¸ïÙÝ%q¿–áh¯&t• »ûQfUr­�ýp>Gßm @“+iÛJå½ë=Ÿ9;,)úîõž‹a‘úÑ‹E>H1¹0é¢÷¯|æì„]Œ(¦þKoÜíû߯Ø ?º[®ï«ö˜ÿèo}ò(P°u°9€~¿v¼û IDAT�ƒRi†Q³InXUS+ã ¬a ÿ‚'ì;¸…àòAÖ[ÀÿMB .×׌#,œ.sÆðvOr¨%ïÄ{ t«VOسV—œZ椭½dErA¼‹ÚØþJ“ùa´» . äcÈ�~Z/‚¼§½zai®NQ­‹“+²0N܇!ÄÎ]œ_wÌk«B`9º+¥Î ó¹Ä2ö@ÖmFYÖ^—}©jVª÷]—I¡˜Žm´ÀbŸ«%ÄÖ©¹Ø:Ÿ‹ù(s±¾GEJÚþUJµ†ÃMvèÅËg|ù·þ7T•/Ž[~îä”OÇ�gÓÄ'ÎN8 �ßòœ—sægïÞâÎ0ð{OžñbÎÜÝŒüõ7îòÇ/^¡ª¼ÊE9M‘m4I—W9ó•Ç×|þì„Y•ËRøÚÓçDþÞ;øÆó—<:Lì |ñÖ9)úêÊ÷WøúÓ<Üny:Ï<Ølùµw?$ˆð³wnQQþ•'¿tû‚·v[~ÍOÕª7!°/…¢ð›>fŸKïÒ¤DÞÜnøñ‹3~ÓùCüâý;üú�¸ÊÆþþÕug(‘þÝm<ÜmùÎå×ÅzAü­‡÷ù½ÇÏxéA§)u¦3À“iæù¼ìë4Eþd:ðß}øaßæWþë_àoÿ�·Ñ}qÛï@ÕlàjŸîÕõ—£Ž} ‹ô¦s„–Èn 6«Fì­ŠII" ‰óÛÎOÏ`ì…ùº0_e‚1%„€„=ÛÓ™{*g ÛûÜrÆÕ«ÀÓg3ï¾÷ yr`ÊÅ’–+?@«ÐB!ÆÌù-áì仨�ÀÃOÞæSŸ½Ï'äM>ñ黜žo€B)3ó4{5�ù½ó!pØÃõþÀ~àú:s½/L{˜ð䃗<ùà%?ؽàC™¹¾V¦ÃLuF¼j²5Z›íòy[-)‰ZõŽÖb @¿ç>Ïi �7µ\¢sÛ�bIwOBÖ&±Øý£r”@(¥ù+­2°ÙÛï’œn!×ÑÄí¯ ù¾æ?hðu©Å«íðõÞ J=7äòd)ÚzTlìJílÿOžîø — xûdËóiî’YÏçÌ ÷çPjæÜ·ýÌÙ (|Ç«kÆ \ŒC&U~û˼:àöÖnË6†ÞløÞ0ò ÷nóOÞý°ûÏ/¼Ñy…c`@qª¹°º¼±¦ð->R—hiÕ:ÍG­DI­6'ŠzœZ ª‰PH¡J&Ïv©û�­±:3½–‰iº"…W$Ù�†B[×�åŒÌ'¬ebÒÉ™"Ó´gš®™çƒ7tuðB�”$¢ˆ:�äÕ ¡ß§µ8˜à–Æ+…TK$«A\" 6´¡F´Do$ëk¡ËT Š¨öXÝoÊžg1â€` Œí¸Š‰èºÔ‡ÛÆ&Ýc_—.ÓeãÛ™µ‚õ‘s"˜{É«|ü‹»Ö°ë‚‰Ö{°Wü´ªe`©:}lik\]Í–¢~í-úµöO×ûÓõÇ_H 0ÛW±¥çåŽNhù¸¾f¬�Ñ÷ão²¾+'!F.fý^m¼Z[—<½à Ý“(Ý È8¹×{ DûÌzFúw]»¬…m-hñ�IVÇÞÿ2¥Ð¥a›’€ŠÙ#õªi$=Ï‘Ùíµ|Jb=¯žA£¢É$‡Úíh=@Úů팳”ûßUëê™{tÒî—K©·^‚ T±Ûë~ÇŠlÕßkʾ¶s€…¤éÿJËy´muõ%]¶„IG£¹Uµ¯&‹ot<ŠûgrT1°:`hõòîãËGÑ(°œÖz77‡vÿûBô[¾¶Š+oîçøç£QýCÎûãþ¾>çöý#‹ñC~‡~ÌÕÖ�Egë„˯hÏŒéH–J7€Vå# ²*¯ïÛ•8k[ŽVgÚ–¬þ¶2Nâ¿ßç*ì´Ùãr”V#Ëw(hDn"gÅjRBÞè­UD© pÐ|¢âåþْΨ@ŽDâ`‰_é©¥®’Æ0Ý;¡ÆpTj 0¸Œ‹iéámUܹ©¶¶rJÄš0©� ÛYÙÏ•)T&5GZÅP“D^pwTª•W–j%µ¸“„!x)Þ ¤Á4)�yfÖ¸z傪±Äó™§@cì¡Ò:»IØ$sP¶c`3¶ûyŒñoÛE†d޶ITy¯?v†îlÝ|ÕZ�9Q!•Êœ�妵X“j‰(qUú¹ @qçQÝTŒ‰)1nìÞçl%fûýÌõõLÜ+rí%î˜ˆRIÖ.ÇMUsûÝ�Lî —BÚã –íY)V’ÌU˜«%JM}ç0à‰€C_pB°J�1:00xŀГ·ÂJ,‡VUà –¸²9f‹šˆ.Úªb³µ#+«9ךò)R ö€D—òö.ÃÔ3[°jÕ.w¥ÕÙ@7í— @Xœ!gj7PC–…[ÖŽý+®gêMút±OËøp‘Gæ¶‹¥žÚ�Þ†­´yqü[u Æ ¬�£D£Øÿœô·$*XƒÆvþÅ6X£;Õ = -ܨ³“ê èÐ(T¯ÄÝÀ‚ŸêÁíÚ¹yëispùî²þ7gNïœôï\¯€�C­lVàÂ&†£C bì Ë µí¿wµç�ݦÏßg‡™!·< 8ÆÀ;«J‚ ¼¯Àóif›bß×û×{žf¾xÛš¯û ´gøï=|0¹K.¶}}fû¶_ûö=àõDsoäל¸ :@ QѨ„q´À³1X¢D ÚW —­Ñ¶F„(„–ÀC4‰¨ä“¬Ž'«±¥ÞþÕ×hOþ»³/²»%±j‘Κ«¨‘¡¯�’™+!+¡,chYÛñýé¶ã�t’æ_¡7y”�!-×½‚(JïÓ�¶Ú"ôdY{�í¾Gµ˜×½ª[¿[ß…õxÆïe¨æ/HY¶?ŠŸd5¯öj0UPü–[3f×5¦%ñ@ÉìK±Ö˜¾°éQ7€æR™K1¹ fÏ„–¶w©¶þçœùç_þŸØ.¹‘“!ñïܽÝåpþÒ]“ úÓ¯P`_*e0Y�—sf_{úœ„ðù‹3Âo}ø„ªÊOÞ:ç³ç§üŸß{ã[¿pÿNo>Dx÷jOUÕÞØŽ|óùK^åÂ.θ5üá³\Ι$Âß}çß|ö¦ngj³íðlžùþÕ5væjÕ<¿ûè)"Â/ܻû×ûÎöÿɳs‚_ñëœ4D˜U)ªüªË$}âdǾ–žèüÜÙ)w~Ûå†á�í†ï^]{Ò¾úä9מ$�"]2è$EÞØløîå•ùBÀßyûM¾uuÍþ�?ë²)ÿÙòþÓðyêÕ¼,çÉgÌj®>7a9ôuÆœ:Ÿè^% aÏlx V¥"b~ZÌÿ‚øÙi²Í…!¦œ@J1 Ï×îͶpgLìÎïòƃ[\½T®^ ï¿wE’w!?åÕ•p¹73b ›úÏæL§0‘âÄ'?ñ€ûü[ܽ?rq;qñ掋‡gœÞÙœÃ(„Z³Z"LÕÈX»"œO�’JJ ”œ¨9ñôý<ýàßûîcÎv‘'�÷<{:s½ŸØçBÕ‘Á“¢è¶©lî»±Ãk_³,v±†´ÍOqÖ¸“2ZÀ¼T‚ ¸Ö…-h&X Á–~œñZjFW-!�¥%«6ÙʆW.‰­äbÍ]ƒ¨¿q¬¹Š>–p0€BÕìç]ûù‹RËë ÜUù£<ñ…´¬yO¦ãfÛmî !0áÒ¯)üâ½;üΣ§}Û»ãà•O–Ð}ïjßçEáé4óÔ“ù?vqÆŸ]^uîgïÜâýý¾¯¨v 0°Š…üý@àí“ϧ‰?r€ï¯¾q—ß<\õmUÜö h©ýy©ZuÇàT†µß£¶PtS+h6ù œ¼ß@!äŒê@,�2JaÊ397½ù@© £ßš ÏhQö¼ ¤x „�ûÛ…8ÃvC""U…iªÌÓÌõõKÊtI)39˜¦kªf÷ýC?ï—,ñr ú€Q_;Jµ(p²ø¯P«ZÌZ“ëì~q¢ÔÌ<ï‰5’j"†�‹3âàã[º m½o Y‰ÖPtÃ0Úœ•Ñýu]Æj�Q�,+“UåH&�új¶fĘ\áÌ®=¥Á{ ´gëõD>t ¼ u)ž n>“�¨qÕ?kY¹–jƒR2u6y½èó4ö¹j€LÎB,3µ;WÓ%1‚�ª�¤N¾ƒí9Ùg[îÞ:a;F¶›Ä¸Ý³;9tâúås®¦L™±Ø#X b³=˜Ún¦Ì. £r:Ž|òÁ _úñ·¢2$åé­Ê³ ;‡Í¹}6®^P£RóÑÊ£'÷#E¬âq–JeP¡¤H#ó61çÈéN¹8ƒË«ÌÕufÊ•C.‹ýõyc ¥ÄàU!1F“Ð Ø5S!0Ka+c ÖçIñ¯b¹âù[çú&цûÃ^!ÞÁ„FêfaE‚úH"²è>ö‘¿¾Î%öÂú‹¾­ö ^‹Ñþí/]ý«7þöż¨ÏÍõ ˜w Ò\r=úmÅô¸ß~rЮmÛ|œ¶»ž1^�«°º'ŽR¶ä�ƒ"¹¢“¢Ù+âÔl�‰Z<ÇP*µ(ež©yöØV{ì-bL¤H£+{8Ъø=GÃVQ¯·üQ#ì˜ ¶xßR–#ÙÛ&‹íÅdšÍFÚú‚�)k? Öâ9³°<ÏõhñÉâ`ÁgèçbÈñÑ#óïéò³ûwÍ?:Z7��ñh†3Üþÿ¼Òñ¬h[”[8ü° áæxzãx_«8òµ×ú‚Ú�²Ì…¥ñh'zã¸} ½ù‡�;èG½n^K;ñöÐäÆv7÷ss‚·¿µI'=¡JgŸjm� n4oÈWôÆ-²lÓ«íÒk`m&tõÛú¬o\ëê¶„š®žáq1–,²+n¸  ËÚ_°À«ø±[1ÚgZ¥#lš1‰õÖȶÝzŽÔ¢Z“J) ¨:êh‹P]š ]Û=D{'†$2Æä�†}ëÂvÈ6AØKd °÷GÑú‹4°áȬ˜ Õu�£XÒxLÂfKào“5ö&gMï¶z@Uª’«p[(ÍĻ޶TON�C`3Z/�Íh Áf ¾ï°”FA5ƒª%•Åš[hE몑Íq³äq Š$g<¤d:›ÌVª©ö|ÆÚC4 ¨BµÅÝ;‹&E!h`À×”%«k|cMxCeΦó „DQµ„8Úª¤?gcÀØø©¨Hƒ’s€ÓÁ�耲Ÿ”C†¹JgXˆ�®SRìÉ€500:0Ð*6ZðƒbŠ2Â8Ø¿ƒk—‹,Évcÿ,`‘ ëFZ¦õ²ˆËÂÂó9ú}hKÒ­ÏRG«ð¾šÕŸumfå€,S  õ¼èû{n*®!,tT¿�˪)¾úb^V}7šÍ¡Š-ˆâçÐÖÔþPaq ;Ñçkcýãì0_Ç:•¥?t ÌÖn݌Ѣ~Ÿ:Ð ¶/‰â âx ,ö××Ã$Hû¼Ã�ãä¿w›UmaT´{Ó­x‹E?½X’û•³¼¹‘€�«¹üªÎÓÂø`à­ÝÒà­(p»£I5FàWŸ<ã‹·.ze¾˜CÕŽÿp·å¡ï{*•1†^iðG/^ñÉ“§.)ô�Ë+b>wf2(ÛùÔvK›�ð'Oa¼qp ûQ Äi%¤˜,O�ÈP Å‚çÍi ;0`ý8êâlùºÚìˆ7jé¥^ê=}¬ÒV|[é dU–j�ö윬†k »ué)c=OZqLé46ŽsE²�6[ò¿�¦¥ÙÞU`ÐÖä$ˆcVúZZ™p ưqPE}YoAS—[¯Åºnu�±ÍÑv*kÊÜi¿çJ»ïXÀƒWÅ(&ß"žYÔÚØÆÎÔõý‹ƒÁ�Á_œýHáŒFE(50íÓj.�›Æ°z��â}ÎPRªrU—¬øÝßû5~ðè{ "üÇç·ø÷ÜgToì&Ö�ø«OžñùóS p•3_þà%÷·þî;øîåßxfý�»lBàß¼xÙçÜŸ¾¼ä­Ý–÷ö61ð�¿ÿ'1ð3woQ‹òµ§üäísÞÚmùçïý^Î3ïœl¹3 \Ι] ü¾'ñl7̪|í‰ýþ3wnq1$~ëÃÇ(&ûõËïó[ÎþWU><¸j’'"|íé Š*ç)ñöÉ–o¿¼äÙË™(Âß~ûM¾òè)O=¹yo;òjšy„É |¸?ðø0u ûP+_ñ¦¦Ÿ;;å‡Co.ü…‹3B|ÃÙÐVɱ^ä„÷öþ«ïýWnù—ÞâWþ‹¿ {_SÝ–“«U¶f% ÈL÷eC‹W|þJ°u.Vg˜*&„‘QiÌðÒ�0Ff(ÆšlŒò�0Î$Ó4±R°ÛónäýÀõ«Ä8¾âÉã—¼xvE-…iòD™b~Š*èºgáì,ðΧnñ?ý î=Ør~;°¹H‘0*„™¦í,=k/Í ðÏ‚K€zô­ êuäl§Ü>�lGe7À‡ï_òÁî’GO<~6‘çâ}&Ñ+º‰õ±Ôã]|V“Ô%X¥°U·=Õ›ýƒ�YÜÖÏ–@¬K¦B4¢:Y%z•h]Š˜z¸c>š�u56y­ MÁüpq¶wÕLÕLqíùvÕv^fOºÞ¸ÇH1DJ-lý¸ X»ôDý›Û AÉ 1÷6.³%à«ÂWW=ø–³û/†Ä�]~èö8ðswoñ/¼±bUAë%ë÷ž^±ª ITJ8ìÓ,\�T®ö…ý4³?Ì]‚«ÙÐ4$Æa$Eo”ì1R«¨1œ+§F“7n1šö„i5¢hðq'FÚ÷cÛZÛ|F÷midÍuòµ®òRÝÍ]å¥ó«´ÏÕ+i[~j5Q…£x¹ Ì%Ï¥«ÿ¿Úß–Zn|ïo5/–¿/ x?V¿ôó] s»Ð�zéê(m·ä ८ípí|ËÃh1¬t;kÿFKÅF±ÊøPÑY-'¥Vq¢#àqJÉ…2[ŸŽìù�…˜§>—qH¤1ZÌÅ+ºÂhÔIÚOGÑ1>=~©žD‘ÌÛšS]2ÜOYˆµr´6é_ï·ax]Ýb=›Ú}ŽÕùtVŠ,ã´ö‡Ó´Ä„íz‘þ¼Z §ÿo=XT(Zqv›G¯õX_Å«ëÑ-ý7+Ú—×ãìæ¬èÉ�õòÜϬ&ò긫¹ýú÷^›Á³ÍGmwsBé�ÏnNþv¬›×ùq“õøx6ŒÁ` Ó`åû�éXŠ%)| /Da7d±½eù¹•¶ÓiáÆ5|(póü>úJÛlûèçh?µ†Ä͸9CªM„–°hßh×R‚ûhjAQKº54!šK�ûbeI½ö=©Æâb04Ó–y[ ½D®-^1@��: ”Q(%:{Z=áÐl„›QF,‘�°Æ|s5ée«о†FˆÁtý­ÜJ Z¶ƒp²‰œì»ÝÈ8DCIeW¬Äºª%!æ\ C�Ø¿ÇJO>�É ËëØuQSð2¿`¨lò O¨�zOd„`à€*/ÇÕªHƒ=ãÖmžM‚¨˜öäX*CÅØU1ù_qQþ¨5x£e B±¾Œ%“Œ£0çD)æÈ‹‚b „*X…‚xõ–1A”bÁ»KK…IÃÈf¹ÞdÆëÌ�›¸Ú®•\J"W˜æÊT*³3˜ÓˆC\évÛÜÜDkòj%¡JcA¤`@Á˜`“c ŒÞƒ­&ƒ!æôÎ%S‹¶ÉLÓÄl%±½¢¦%5BÓáäxZ™)�eQZ&±û!¾påJÍ¥—à7 ßRJwÀU›yö°]ë‘“oŸ{C@g:›óV²ïÍ?k+M=Ð¥_×’èY×'5öT¯žèà€ƒ žXVÌâ‰_¯L©Å}µ+kt›´4æuVBiN‡¿›îz Ë»•†x"³3ªQd�®kÞ×GYª#ŽY?ç^ÖÝo]s ÚyÈr¯Ú÷ýuzº,Ýk` ½ZõK“‘®óß^ ˜ku†•àù4s]JOìWU^ÎóQŸ‚Ÿ½{Ûm°]ßo\¼/…Ÿr ¡¢Êÿýè ý�»ý\ÞÜŒ¤°\Ì�yÕAUåñaâ�í†M |rùÎáÀ_¼ÿŠ_xxçÄånGÚØ²ñ’Äd´ ¾T« PêìuÊ�eI:ƒ¥´=Û:(Ыò<™]óΗ5ëû¡}Kˆj…ê üÖ„ºÖÅ¡ôùÚ�?¡ ]k•¾¼»ƒìß',k­�WiššâŸµ‹m¤ƒhc_$¸¶¬—ÛÆ°Œkžµ9¡�)sT¬‚‡N°µBµ,´'_%G˽¶çW]¦C�b ‹ªËó fL!%[¢²–b¶ªè[ªK)"˜sa¿?˜NpPªf¹p˜ S†Ãll¶ª¦ç\IÀÏZmm¯âzÌf…ªÖÞTÍ*ÙàϾû ¾ùGÿŸH?rvÊ¿~üŒ¹*?}÷ŸØmù­óbÎ<Ønø…ûwøWžÈ9Í\åÂ&DN\êëÛ/¯x6ÏüÄ­s¢ßzùŠ¿¸ºæbHüï<àkOŸSTy™ à»–ÜÇñ¾TþøÅ+>{vÂólêÍÿì½p1$~þÞm^ΙãÌÞŸ½s‹]ŒüÎÁWBÞhÍIkåWßý�¢ÊÃ݆C©½ÉéÍæÂÖx|ÇŸ_^÷J‹o>Éu©ÖÃI„?ð ‡;ãÀƒí¦3Œ‡ø;o¿ÉÿõÞ‡œ9j}“–¨æßxSä –¨¼Ì¹³™âÖ9»ùoÞ{—ïO–üüܧÎùŸåo0d9š[4)HíëeëÿdˆÅ|²y2[爊ñª–Ѝ'=W%0âÉËiØ>¬çHY@ûžÜ¨=I²€’€ „(‰­DÎnm¸¸µåüläòòš$µÒG²×7¿¦ÖKNNNyøÖ?uÁ›Ÿ½Íù�À°› ›ŒŒˆ�}ㆦ1Ù4ø|,Kìš-Q# hb{^H’\pëdý»—ܾõŠíŸ?á0?¦^e²Zõm¨�\1éÌOn¾8à6gæ23ŒÃ0¨À@“©Z]~}šŸ!bD‡Ò‹%”–[bí@r)ÕúþHKÓpÚ•¯cÕfÔ¬,ÝçPRœücö®Ö‰œ'r9PWãÂnu«HìµÊ€O1Qj᥯á︄PñuõÑþpäÒ]æÒA�wNv¼{uÝ%¶¾xëœÇ‡©Klþµ×‹9óØ· �YµK}êô„ K3ã;ãÈ�œ�ð»^‰0×Ê·/¯º½ _þà1U•‡»-»øÁþÐ}Àô“«ÎZ_¤0}­ ^%àv_‚Ý÷ífÃÙÉŽœg®®2yö8%6yI¨ eÎ�„¦âc¤¸vðù…?d+)µ˜Š"ÆqKL'ˆ ½‡[©Í3eÞ3®˜ç=9O4 ´ˆéc› NíÒ²=Võ9ß–BÄ“L)±Û Œ›bÉw¹ºâz_]L`é}!žô• „ÔÆ©OgËe 0ø:\�F¹f‹C=§`Ý5ÌH°˜qÙ+¯ô±œnÕJö¤½j&D%ÆÈfÜ’â®t­wY{õêq÷߉«¹0) l·[g ¦éÀ~/ÌóÜŸáRdqÈvÙmwœžž²ÙnÉæ<óìéSæ9Óä':ÉÜÇ\¬µW-•y:ØZ.“ÉÌ&Æ�Ø #ÛÍ–Ý80†Ê&*gÛÀù.r²‰ ±’‚çÛ‘['·aÊH=yÅÓç{^^e.÷•\÷Fèð* óµ cªœo·NvÜ;L&èTH\•ôå¤ IDAT!óybÃvÁØú)ˆ$@°ŠG܇K„Pü9ºMÄÉM!¢!¡$v%2•Èn£œn+ûyà0eö‡ûÃÞr12#ãfc÷͉4¥ØºƒõÆ‹iiï•¢ûÂÞt5xå…‘B|­k~hµgÐSGëüN‹g�*Vñmb�ã"°ªåÛZÖ¤ÉYK¾…Å?XX]þéi­õ?êuã»ýµúÞQ|\WŸÉêC9þ•¥"íõ�ô ØÍ�Ä«ÝÀ›çÜì¢û+­Ûbs–Z4ÞN@<*Ѳy5BÔÆ‡U L6þ‚Ûõ¶ß¯ ˜¼–S$¦V¡¼:¿FÔÅš‰K­þU»IF(°E¼êÄì�‡#Xãñ%d©Ö“ÅןÐ�›ÐHÁãQíìA]œE|éh‰øÕXìcÔoéÊJþj•äí¾®Ö&­ë1äƒAýé­Y -о äÚ”%?V»\ïíûêãÏ_imÈí;«ßõÆï«IpŒR­X|Ä«M°î�ê�“\>“ s¹†×Oü‡¿ŽÏíæ'}–7Áo|ÞïÇÇCVŸèêßå:Y°(¶`¶.í¡=ÿU¥@{Ø €E>Aýk&¯Ýªn~Ž.ou^7¶•Õ�zý¶;šg®Kò®ÒQ�°z†´Å@¬âAeÕ@½ÄL¡ZÂX)æDÍuà$¸n·tƒï6>ú9Ä€&H±�sKvyù^„à‹™úŠb øØAu¦am̤YW`$zB; ª5ø¬Ö`F4c–šr‚dè©e;ζ‘ÓÝÀÙéÈ8Fp&ˆÏc6Â4k_KÔ{¨G2ƒ'žGíS¬Þx¸.:÷AºüvÀÐÕVIÕŸeµôg¼|Õ@îÖ„Ñe}Äž­8€€ˆ'Xj×õ�Ú,Bè‹€bKÉÜÂ>µqby´@ˆƒ5¡ÙD²'‚ºö[Â,@÷Xª'A«%B%VBt Ÿ!2–@ΉqŒl†öl†Ì3¥`d.p˜³½s¥" +qk:”­IÞ&À¬ª!«¶¨R¢Uil« “ɼ> € v¿[�1C_ò:æ—›3£�ä×gãâ·4çIi5û¯ù>¶ÛÛ€³”lŽ[ ZÀÑÆ‡UXµE×òTÔ+nØ?Y’Ñmhu0§z«Ü0Æ_s<©Úüiÿ6§Ä“Á­ú¡™~sZUÊâóÝ ³m!í5V~NþL|Ø_dÅ%Ü-{Üþ ­ò ÁeÞ¸ÑGj�Ž^«ª®ît.ß>_ôß ÄU¢ÿ¦ úlž¹=,}.Ka,ø¸5Übù<ˆðŽ'úß»>pwz¥À÷¯�·DBàb@DþÖƒû\—JînFßמçsîrDS­|ûÕo¸¤Ð—NOùÎÁ’ÿü+ïñþþçl|;ópqlÛsiÕÁnq)•TJ»ÍÕ©,Žj“ø×æk4g*¬n¼û0ê쎵þÑl7¹Uúy“lkBíß]õ  Ïµ…Y¸~ØâþBKV݈üÝÀ¸Õ»;­ËõhôäepmszÃáæS¸Ì˜jqÒ¿tŸ¤W)ˆx‚/¬ÎW‚C]_@uRvèë¾:oÍ KÑ:îhVÅ«"5¼&å“«¹†÷Øý›«ém‡)[r-šäÄaÎ\O•ý,&1æõª‚¯#ÑªÇŠÇ U<�k•kVM`??yú¿ý;ÿ¿¸=á'ÏÏø¹‹3þåUkÊ«<�fîo6\æÂíÍÀoÿà çCâ§n_Eø�¡À_¹w‡ûÛ‘ò*/æÌOß¹àû×{®ÊÔõø7!p;r_yü”©T¾pqÎ[» ÿòÃǨ'÷éþ�ÎÀ™ 'ÉöàÏòñaâÙ4sg¹;üùåß|^8K‰¿ùà>úò’ï»dÐ'Ov\çÒÙÿÏçÌe.½"âUÎü‹÷€ˆð·Îy6Í=qÿ¥Û¤øªW&ÄإԃĹV¾üþ#¦ªfO”^¼¹Ýpžßze —“åÞm¾ì÷ `ÿë³'|Õ›2_œüÃ_ùek¤¾_Ç-¼h“Ý'‡zZ¸Ésö`l ÂÌ}1†ìR)V Μ­¾Ž‡f0Ö`œƒ‹¿ÁL['-v¢"AÆ ì.·îl¸}gË‹—^¼0-v*h™¨LÀ5È5gç<|ç”ûoï¸õpd{V!eˆ�*™Î ”D &z•“Ò�¼n› ©ÔȰ $†0p~²e»Û°Ýl˜òÄ£'OÉÕ@8©‘ ‰PqÐ`Ýa±ÉF¬Ðîqà0¸tƒÙó›H²H%~þÞ힨oÛô„ ðMïSÄÖ‘gól*Y"|ñ⌯?ÙSD?s÷üâU¯Ìy9K}¸?ð¡'ú?yºãƒëC?·¿öÆ]¦>W·1p1$žMs4ì™dŠÚ ö<ÚÒjKO#�äŽÇoÆÀÙé†ÃA™J�íÛCŠœœlÒŽª#¹X£ìÃ<›| `À»‚R<ñÓOˆž$“ºHôè 2B¥äH-‰2ÖOm>Ì L×”ù@-ÒcïUÕoó[û[–µÛç—UMÛü·~e‰ívËv7"A(5;sÞ·ªÍè‹ÿÚ‰ mßήR�õ²²õ9ˆHT¯˜XìŸ�'!tgÁößîWóy¼÷_ÎÞ‹Å}Ÿ"1¦ TY€³æ'å¿ì\7㆓Ó†‰)r8†�Ãá`Iûœ)+p`F¶Û§§gܺu‹ÝÉ S�¹>칺ºyµø?,·¯ÅZ7çtÎVÑU%v`@�ªÉ�2ZU~Æ»1qºMlGû}Ê •Ý8°ÛŒ„{0ÈÀùîç»—<~~ÉãçW\íg¦r…f‰Ä!°#w.FÞ;ãÁ�·O"÷/6\œD˜/Ñù€N¢vƒíBJæs«° Œñ(Ñ|Nj! ”`ë#acA%�k`(ÁÎ?6³0��ýP¹NK?žqLlF¯$)'Θ�m½óbË­ˆIéR1‰ç¬½íNgïcë¬DiÅÞ4°ÏB¢;Ô˘n¡]3ÔKâÕ¥^‚OŒ5!«¡¼ k�ÈíAÀ–YÛ'éñïG¹µõKz°~iÿ´.r”í-0m¿¯|ç›û�Õß×ùVé‹óúÜ…®Öp” ¶y¾ìªù8ë«kßÇÏG�ö××°vZ>G<&nÏH¤÷m·1xÜGÀ¡�OÖ´:t”ãÐ*ŒT'ÝÎ6€^«v—«ÛšæwõD{›ù�moý"Åô-àm£hI¶n³×FôÆ“Zl[c,„Åõóñ¿]CsÚöGaüz ²\Ïz}¥.ç#,€€:�QÕ}8Y†Ë�SZÏ¿@ÒëhÒÍ“;þÂë'þq“8[×>Ü�]êj0~Äçë’õ׿|ã÷�9�£sþa[Ê�m?êš?êØ7·×�ÞÖ‘óþ§v}é e¼ÎRì’¬€5æRKJ�ëóüáWs“5ÞOK~wh÷Æ>_7a7¯“ÕM^ N]�EמS¤O6�!ÀÁ=³ùuAÓdyŠa°ÆKÑéúA¬ÁdÓ6m˜í²Uv‡�¶ïZ©¹ZùSQrVJp¦AÕUu¹óX”© U„Úk1�¡–êkŠÄˆ$%T%ª²Û$Îv‰³“ÄÙéÀf½)m¥â¥È*×;žfÒÀfL”\¨Å+OHÖ;2È¢mŒÁžBq¡B]ΩàÉW/×µÇW½YL!{3ahN4I¤„ªÅí[õä©÷(¨öœLû5£söí–¶ëk¯Œ`7œÒïiHÖ(:Œ�¡¦Eò¦zB.ƒìAg5ºzs#ml„`ôàìŠM¦¨À8¶›Äf˜{�€1š~®’È“p˜í]P«­ò€\6À¦^ÔlW èkvê2N›bsj}Ëcµ™T´Ji r»–PeihÓ@7Ušl†í§-€mAƒžpìSS—Š�öîͶ«ƒP–$ks3¸“Õ–Í&,Ï‹¾@-ŒÉØÓ>©Ú«oª³úÚgVN¯‹û!.°Z Zm�<éX—ƃê×·°8b�4™¯&ÕGO€Ú°ófÙî´ÊŸ€ÕÕnL³Ë~³š¾úQÂm×ûð|µÝÚ!<þiÙîäÔJ©kÕ.¡Ñö0Ýè3ð*ç# ¡5(°þ]�—.Ô^ßxö‚/Þ¾è¿ïR8bûâd‘"Ú—Â6Fn{O‚?|ö‚¿8c\õBèß¹3GÇÚÆÈ/Þ¿À»×{~îìŒôĘÉÿìw¾Ç?ø?gŒû>f,葘;•¥Pmm©€bL(c²¡˜D�`úáêWh½!üŽ¸Í³7êãfi$h±™%I¥ íƒ.ÑÑÜk«�§æ$úÔs‘¸e Dº“Ûò6¼Åºæûþº‘�ÓÂjÌbÚæ-óÒÆmŸíDÕìœóŸ} ÖZF§euÖ@«K¬­dWºÓ+Ū8Z“®JK&˜‘Æžî6«íσo¢\Š2«r(•ý\ÈT…¤¶ãRb³ƒü¹®§Ì~*\‡YÈÞh¸)“î§Ê4›|]ÎFpËÕ’�Y­*ÁùCìWüúoü/ä<ñvøÒvÇÏŸœòõg/ù­31ùޝ?{Á­qàï¿ó€?|ö‚'‡‰§ÓÌß{ûMžMs÷É®káÛ//ù±ó3>ÜïIAøÕïÀÙ�økoÜåÙ4ó�ç&/ô7Þ¼‡²4ÝפÊýq䇻øÊãg(Â'Nwìb4‰ U~êö÷¶$T¹·ùñ[g|ÿÚÀŒ¹VÞ¿Þ³ �“%ðµ§/˜kåÞfä­Ý¶78½ Døò�¬GˆZÃä&�K’sádH<Þx´?€Ÿ»w›o½¸´ä%ð…[¼œ3ß~yÙmÉÚîMµòë˜ʽÍÈÿïþšøØÐ!ÿÃùïò“ï܆ë£Hm{¬ig[˜¬�'NZ³[]#¼ pßÖéV!¤MâL<ÑÞ‚ææ›‡F›\W8SºÇm{“ž°Œnf8UnÝßrÿá)Ï^¾âùËŒL•:)E'D¤qFÜycàíÏœrë !l_Á0C¸‚0AXzÉÓF´—­îK»oº8Í¥BžÍ. 0î ç9Që OŸ�pïÞ†¹(¯®Lú,!„lUR´„‚'îULjCJa �GÆ11¦@×–n+¡¬Ø¤ÐI í¹+ ìµX3ß‹taKž/cA[’Iš…ó•yµ†/õ™K°ßf­…ÙcÒRf²¿Ku½ø¶Ó­RÜH Æ2—h¾Î0°‡?<ìùk'§~ÎŒ!péÝÒŠjï[ÒžT›+olF²ÂS¯š¹H‰OžîøCŸ«ªÊãi:Š{Àpš"›yârCçCâÿãìÍ~-Û®ó¾ß˜s­Ýœ¦Î©öv¼¤H‘"%K4醲aE’-7â H^8ÉK^’Ãðk’ y2$OA`†É–,‰”�0²$Ó6R¢ØÝ¶š[uëÔ9»YkΑ‡1Æ\kŸ:—$¼/ö=µ÷^í\sŽößøüù­Öÿ£ªòñ£5O½ŠàŸ¿`W+Y¬"!Öù›ÇkÆýdÝT-”:´Ç|<}|'ÀÖC/Ðô¾p%E¸É˜Ó£#>þñ78½uÎ~H\¼ØòÎ{ï³¶±øWÂ9å \Ñ3„ålî‹W ºcØ'6—•2îI]G­Ösf·ÛS†Z÷ÈA»˜Û F«:9Gj²évu¼#Y».³è­©kß÷t}¦jÏv¿£ßï�«Û$M÷oÝÎM$’t$Í?DQ}‹t,º%)Á0Z³ä„WNK -!�öîéä;Ä÷{òˆ•ÄËáü á~ ÓŠR‡$X¯�9?;c¹Z²\ö ÃÈv»a·Û±ÛlØã0x/¥ïzNNN899åää„ÅrAÙFrÏe€ÛMó ‰9bÙlÂð%pù1™fJܾè gD¼_ëk”³QwV¾ê;Ž=ýYÏÉò”»g;>¼¿áý'Oyûác>y“§OÙî·TºåŠ»gwùäÇïòÙO}ŒO¼~�^w,8ê2»Ë¤2"u$‘ÈNódÆ«W߇>³µÌTÌî[zÓ`ÔÇÅ&7‹÷`+ˆš Ó§ŠtæcåÔ5‘;ëÏÖƒÏú&Ö)餽ì’ÛÕZ”qW…²+Ìõ 7[âËEZ5‹ú´Q‰$ÛÌvžì¯ù—-þ6r Ï)ªwi¶µm¾«?’-N)“ŽŒë=°ÎþÒw/o9ÿ$7ü}iõ]Û;Âñ‡ûÚ÷.ìü“G2?¯tvs…‡­Èy¨»ÅÄÚwnadœíj¦æ°qOÄzâ]S5êFDƒ–3�ÿ3ä};^SÎ8š�˜‡­þÝí�É ™;JS~ǃên§m÷ôn·ê¾ÆA30…Œ?ˆUëá\i`µ&ï´ÝO€_šKzí}p�ÒÆ ¿×ˆy´G(ÐÀŽíx•ƒ~µÂÌocú¾�qŒ[Ø 7ö¸6úó˜m«>òó1=Üoöû|þ· ö|‚Î�;mË =Œv=2ûüëÚ1^º�Xf“¬¸iÙ~ô7úßÔ·:û+óDÜáDŠÉ³¬íAF€JæˆÕB�¥ð•‡O8î2¿üê=þ¿/ù/¿z�g»¡ÉÊçÃÈ®VÇiχ‘ôöûðéÓc6NGð§ïžsÔe¾ìÔ#‹d¨àX�›Rùêc«Z8î;:‘¸üØÑŠã®kǺ³èù îò�Þ~ŸQ-höá~`˜Éš¯=}Np›Ÿt=O÷{ž# øÅWïñ•‡0ºœ{óhÍS*ÿãw¾Óöÿïÿ‹/ò×ÿÌǼR`>mÞNÒbñD_Í yf{:|{¹]TD&ç'{´%òÜ´ŽÉmú¦Zpž‚z€jÿF£ýÉÝqâìþ’W'<¿¼`7lØl*›m5Cò¢'/z^ýد}â˜[w•´|�v{�K;_²Åe~W6-£&ó£I¦‰€Xˆn4$"ø˜V)ŒäNÈ]ÏúVGÖ÷_9æµWoQk"?Éaï6ß(£ËÙÎć'N$9’0gÈÐõ¹ëlý•4yPbnHÀfGÊDOBÐx@PÝhö‰8Ð y2dއk¾Ó4'9vˆ5Ðbî…7IWÔ›ÛŠW#´)n†_¢2]·øé³éÞó”ZRœ2ÈÐo^£úÂ�3¾ñá‹F!4*Œ³^Pφ�gÏ, Òu\Žc“ ?}vÊãÝžG.Ÿnõ=狾%¶cáÏ_Lî:ðÛÞkäÍc«ŒŠ OžñÉ“£Ö³`_ëAÈ5ZT�#I ÌLGF$Àõ­±÷…}lm.²L’ãõŠ7^{Àý¸Ú?yγŸðôÙ`窒ÀD㌑Äóo”èk�f—&Œh-ì÷[$MUjc)Я#¼ˉN¶qؾN¶EJnÔ)©˜Äî±Ëi oˆQö5?HÕÁ33»!g¢h+‹'ª5Eê?Û;Yp˜Ž‘ªÙÆI­ih˜µñ Ô}Juº¿ÉòÙhMz‡Ñ}/¯âoæÙnØòi3@@Ä#§$¬ŽŽ9>9åh½fµ^Z•ao‰�í–a¿o´BªÐuGGG¬VkV«%)gò¸'%ãÀÏ]OÉ#)åpÉœNØcþœÕbÑgMÝ?· ­…2îa�ÊBM™DG—N+Þ”XY&a•:Öë·Ž2g§…;·÷­—VÅÏ–:|ÈÅU!¥ÊéªçÁíž7_;ãÓŸ|•Ÿ|óUÊöåê’ñê’áꊌ’1€¨fO”V³A$eŸ3ÕéHµ™«‚Q!ª/Ì(!ú&j�2¹@ ó³(’m®æœZ#é Ê�¤¨&¥ˆGÔz=Õ©Zƒb`ÈR*eoï”í&!8å]牗‰s¡£>y*“-(Ó�“vW¦Ê¶IÞ Ó¼óIè§•&›5ùZr�ËÔ N3ÍÛöšÉ•›’zÿv~é`/9€ßL\,ÓöS0_™"¿ñ{Xh¡?kó/n<§ÄñæW=ODR2|%�6 ¿)®ÓM†–„¬’ž)1`Dõš#mf÷Çów»#î’-i Lðõ0gôÕOç�ŸÃè�]ÛA6l¾éüºo:~Smó¦ý?éBÄP"�$L3¡«Zì8‹š-)2 R"+ ‘IeRžHÛ‚׌†"Ð6ÎM6¶ u5X¹G|%URã³r9Aû„vz¥/ÊX¡J‡:×¥’¨ÞS@GASj½^ó­Í†·ß»äß~Êg_?F‹7]QõP6ˆ7Åæ4Šl•¼SdT‚ê oŽ¥V�¡M˜&^ãló/[æ}ªP‰9–šS1{„4$qwJh*�J3-ya¨×†\–äÉêUv>Æä‹™²ÞÖD‚_3„¾õ^iͳƒÊ°]ô4.MO†1é=‘40Ñ�¹•b‡N˜d—¨�Ôª“¤]_1_�Î�îHÙžcê0¼J&ÿWÏ»Aõoïí^Ùk_51b}F”½VH0”ÂPFöEFaÅ*+&¿Šf*N—§Š±k.æWá÷ÿà7xû�o‘€ÿø_¼}‹í0ò±£5χ�ã®ã7Þ{Ì­EÇïœ#Bkúû‹î’“ð›ïN©•UNÜî{Þ+;ú”ø×Ïžs¶XpÜYEà—ß _ºw›UÎü–£æ_Y¯ø�VSÒ IDATÒÝsþiåJåù0rÔu;ÎúŽo<»`S+Ÿ:9fÕ%þðà ªœ-z~áÁ]~çážíM7êô˜ï9òW€'»=?x1ro±`¯•v{ÞÝlI_8?ãûW›–üøówϹG¾æ´$E-ÒçÃȯ½û�Š¡›¯Š%Á’‡G]n}Ö9ó“§Güî“}›™_vÑhè²Ëùÿö{?`tYñ7þâ'ù[ÿá϶¤@w^ÊšKhMOD‚À©Ä�%�ÆÀ×{s¤Ò,`>›�÷œÚÌ¿‹Ä@ìëM?¥9k>âABEdÙƒlé×=gäîŒÅ‘ðÚgì÷°ßUvÆݸ¥_C·V>þ™s^ûÄšã;Jê/!ïP6¬.h³Â'©˜^s‚vZ‚ž@öU¢Â´ñ¤ëk UÈiÅòxŃWOùÜð&'·žóÖ;<|´áƒg;ö»ÑiÔL ®u¹çx¹Dòš*:à #™AejÌ”ô¯Ì‚è2ÓyªµdT LnfÁǺù¸3¿Âå�é„ä M,ðó·oœ²èD“8·Ëlf½ön‡ô5ß®'d³¶s޵{NJ«nMÓ9çëÆ„[¶XŠ@°1 –$ ¥Ü5]?+Ýœ ý®ßÁµO2ýä劕æO[g­ràÚv7¾âÜríó�÷úa[ÏOûòvÒFäå­ã›ë¿5¬ëµ#Ï‚±fiH¿à.?Rª¯QV0eÚ¤8œO?ÖÝÅ„�|ÓÞÍ` á:)Ú¬˜=Poædh˜Úæ’­]�=s›tÚ„¿-~m¨IÚoÒ HFº„D ¤E6ýÆËlÇbjÁþP sÁ®—­-)àh®@VeK ��­Ë‚î…š…š ÙÑ„‚åõ»©±¹hS.@�æ§Ï™£Uæd•X/Ëô½"}%õ }²„È2#}§YÖ°‚ýVØm¡£÷•a€:UPNÆÁ¹è­ñðb™Y®:ºÎ²È挆AO2!Z½]"‹¢b�âû¾oˆ”¦‰—[¼Š SÕÆ4sš’—F2 <½Z½蔬7ƒ#Ícˆ‡kÈC°�t^%!©†ÞK}"-!/…~•šÀ×â3æŒZ‚ Ï0.2Z¢unéaTöÃÀP"``M:I‰±}QNÎ�Ûôˆ¢Æg ß¡KJ'•>‰?—̲ïè»lÔA\Œ$,LŸËm<|ü¬dT} Ñî1–Y+•mË_ý~}nªW ø¶ÕÑMÚ3m=¾,'l%�Ö5Ž¢sÈQ$­!y…ÀÔ{">ãã%M“1(X`ï¦ÄÀ¤uI®l&t$¾Ü'úxN¨%¬õLðú*ZšÜ5;R§ñÁC)qa>W[bç@Uèì_×ä­¾üÏfü|¤R´ïONÀ%Ûj\×CU–³Àÿ<)†f œŒª•ß{qÅO8¢,€7E�UeS*G]fíË¿÷Á‡|áö­–”ø`·§“%G�ýþÆzu08éºÖpøÛ/®xóhÕ¶ýÚ³ NºÌOzáÏœœð­�!õË?à§þãŸ2:†jk[<Àc�òòò>JBØ P§^.‡´‰§�grfÈLv“'"Ð#Óóƒ5 ¡ ìaÒ© ÈÈ¡\ŠÉæNjK T7öŠÙ2&ã2+â¨75ñX¦>+*ft'$ˆ^u$I‡än¢Éj¯&ÈhƧ�‰8bXœN�.‚-’ ó|½¯‹¦j«´dµZ{[3¶¥ÐB’¦ïÅ��ª¹Ñ”¢ì‡ÊvW¸Ü\m+W›Â®ûjnQkN?bÔÙ«“öed,Å耪PG(£PŠP �~ ú4äQMXŠa’•ßùî×ù—ÿê7¸—;~âô˜gW{Þ½ØðÆÑš_zåÿâÉ3.Ç‘«Røâù-.ŠWî‰ðá8òt»ç3·NÙ”‘çãÈ¿~÷w— ~é•{¼uµáÛ0ÿK¯Þçb¬Zµ5œ-{žïGÖ9ñå‡O8é:^?Z‘˜úî9«”Èy×ñÚêˆï]n†‘Z•õô9U•Ó®ãÎrÁ?}ïcU~ú씻˿óèT•{«¿tï¿ùÞcvµ¶B¿è_"À¿~úœA•“®ãÖ¢ç�« ïnv,SâÏÝ¿ÃWÀƃ‘Ÿ=;åí« ßya¡ÐgÃÀ…ó¨ –DøÝ'Ïà'G¼{µå¡' ~öì”WŽVüÍï~—ÇNAôÅOÝæú¯þì½’FbÀõSÈd_“æ¼EbÀlqÓóÖÖš×ËTá®ê6áÌÙšÛÅ!¥ÅLúv×7I�äIô¨<ˆÄs&ꔄfC« �¶ä¥rr§g}|ÄÉyÏîÍsÊã ì‡ ûqËâúcåô^Ïé½Y ÐmÑ´öÍγ P,|q�æ´‘ÁCç25{µ¡¨®¯ äuo¸€,äÕ‚Û÷Ö,kVë#r×#ò„ýþŠÝvCéªÓw$ë��…Õ²c}´b±Z1hetÊ–¡v^}ý¾*�T[€7!A¦Ä€¶õR5ÐÖŽ6Œ±v Pj ¤_Ò×väd�MÔ ©©¸ ×( Œá‰]™GÔ‘›1WüúÅ¿‹kýx9Œ|Ûé¸"øù®S}½¾^q1Ž\øï·úŽÓÞz„€UÞ½å½Aâõ/Ÿ��%ü§$ÂýÕ’OÍš UŽúÎDºÏýñÁ3öUéSb‘RKVÜYô|æÖIÛWDøù{·ù΋«=ÿòkæ­ºþœP½öÝÝ¥Lßw”Ñ€4]6 �E—9;=âî�ú~ÃåUÏr¡$¨šPõ€¹(š‚j’Iïǵ4P™Fr àI¥QVEV¤ N)ª-ûûêqû±!@4´ì é]«Pj±„’SPéÞ¦K†qôæÉ)°=f‹$AD�>—Îý,µ6aºV’X¿IÙÜf*”-ÕÐô^Õ$Ú!¥ƒÑm ‰È�Íß„/¬¡±Zÿ<§÷¨š¨µóš‹ä¶B&u}· ëzKÌ@]NžêèºÌrµ"å‰&'y01çÌ¢·ùš|ÐƘ3ŽVIÐåŽÕrÉÑzÍþèØ‘‚Ö-….Ukv?«x¯„R«%°ÝÖ‘œè²´„F—Äû 0%¼GÝÂ{ûYßB×%¥€œzQÈpë¨Gä„ã•rç¬c?lPËÌí³ÎŽt:2n/ÑaDó‹K….e�žRŠQ° :£7>¨øL˜Â©™ Àkº�êà,e ÃX-)PC+Êä †ŸIø„4ÿRr²êÛd‰·â´ÃI…B5eµÀgÆl+õ䀩N«Îk~˜¯÷‰{zÆ� ÃÒÁkÍãúÉõ©dO@´ ïCyÓbD•É·«>÷µb½'™’spsèv�Ûò7¼fºh.cf¸Ä ½ª×~Õ—¶¥m'íoÔ;ÛOqÑaçÌP Oþ Íz W¥=ìÉ"�ë;´Ùg§lŠSf&‘_KEîC�¼‡bu»CýÙÍSËå´ªg™â�jzÓxÌì±p>®ÔeÚ¼z ¦Qý¸¹ØeNiêëzzlÚÖG»D¿ôÃÇg@„¸ßÖÓNgÇš%Àôà‡ø-€,Ór™• 1Å+4ÌŽéþ…©ú[Ôúžjã¨@Eœ^×AÔ´>Ð�êòc¤ªo Ìþ2 ¬¶ˆÛ�,êÿuÓ2¼iù!¿ý¸g™ŸK~ùèk�±Ýü7�ž™�ÿ‡@êŒBà !àeZ¸‘8ˆ,³A'9@ò Åš¸C@I¡¦‰Ó@F㽯^!.©’³ �ZÞ e(ŒCi¥ÖIÔ�íÎ)Ûw°ìGëŽããŽåQ¦[ ©WÈÅxn»dÍ3{±·ÉÆ)c™ð´èé#Ã^k$W±†P*#)'r't‹L¿H†œ_9§MTMàããÕÒÙx¦È@VºÞ¸ú�FȲ‰©âhKœÔb}:ñ&sÉÐ%]—Ƚñ½JJ3´Nñ’ëJÑbK)µy�£°@[ž2ÅüKv­"@‡5®�«PÉFkÔ'Ò2Á"æ 7P0UI eQ­—�®-–¨ŽGe?ˆ5šC²&¯Ø�‰a´ëG@cmÉ ©îs;»±Ùe72³98)KCLÙ<Œ÷”< E �yóÞ)nÿn+mÆ©+±ŽÁ“Ñ(q¾Š DŠ/ÛIË͛үD4~.4¤È\Czµ@£ª­<õðØf€ÄGš(ºA†Ë̤ñë5YYãVfɖɘkÆs7�¾‹„AÈ­F—â Ö·S‰9éádI©i¦¤˜ÎÐ�ø÷ 7zã6‡Ç<9™zljåØõC­ô3½~5ÞÌ0Ž2¯,ZR@=XAÿ'Ž¼ë‰‚}UnwI„Ÿ›%æÇږ‹¡poµ ‹QKüÖûOøË¯Ýow2ÔzpW?w~jæ¬*î~þô”ÿíÑ#þ÷øÇü7ÿÉÏ�r5®ªU’IÅ"¾&ÓµŒè>™Ã‹±çÉFQK*úZmÉ9&#ªâÛ4¹ésßçWjÔ~røX®W=âs®‹ãd—gÙƒû:Ó íï<é¸è~{ð.ž¨�¾®VA[UÎlR�ïSÉ´f«×�ˆ Á»êî>â}¤³·{ÃöFÜv×ÉNV�¬ªU’Q�¹êØ@¦æUq ¾` ”�2l+ÛÍÈæE±æ«î¹Ú*›­Rè)ôN á•£­oÉF�7xR �VÕe´dwòžU­"¬’§µžÂŽPž>}�ßú�¿ (Ÿ_®øÒÉ)åî~ëýÇlЉ�o>ÁQÎÜY.xe¹ä×ßÌP+öîmÎûžüÞ#ª*Ÿ8^ó…Ûg|Å):vÞøNßó=±f‡øü—¥ðÇG¬râÛ—¼F>~´æÞ0º!k:ð³·ï·à:À»W[–9ñêzŇû=/ÆÂ¯¿÷ˆóEÏŸºsÆû¡ñ‚ÿƒ»<ÙíÜæ©(W¥Ð jþß~ø„Š% vcmˆåŸ9;¥OÒ‚�o¬WüÌÙ ïm¶TUvµòýË+ÆÙã�{¾³\pÚe¾ç´$«”øw^¹Ë?y÷QÓOg}Ç£$ìê4=ÿÎ{ïño®ìÚïœ,ø_ÿë¿€e·-ÍY›*ìH¦ ÕõGs‡˜lBš/SÝö�J0E6òÒKšþ±ŠCZZs¼YR )Rhº»õûh` Q1 ¹Ú_éHËÌ2%ò±s„RU{Ò¤#ay\‘Õº=*{`@[óc»Îf_àÂ…WmÛ˜]k—(x'�i,;¡[un×)R ”ýjÉ‘,¸§ÇH'ô ¥ê†.︺‚íÖ¸»åh�9>ZqëìG'§Þÿcàj·çj»çjL¤AØ…a)e D>¥º ³j-3+¢:Q[Uj »A’Ëù¨�µ…Aaƒ:-Bî(ÇÖ)¾ó‘H˜ ¦„ï">÷¼ª·ŒhS�¤d·I¬j_è\O(Ï´r>Cåÿ‰³S¾þáó¨6 ìgÕO÷O÷œ/zžî‡–4øâ�s¾ûâ²5 _湟oûþÁÓ©ò@™‹Ÿ8^ób,M÷îÖ ·— þ¹'wµòt?�EZpõ×Þ}Ä««Å­ašÙ€™ÏÄÙ›ýÛë:R¦ë,•õꈲSt¿cÑ%Ö«Ž“ãÈÈéEÇj%ô=H5ÊV¤GYX/ša0ÄxN¾L]·j¢¡ðgkÂGA‹×éÖ²ê4Q!m‰�js)Pñ‚SWPÑRÈ}æh½0¿C+»ýŽËÍ•5Àu]Zжj3ÿkó—…p‰jm½’Ä쩤lÍyû¾"i˜õÅÌ�Á D: ¬:¯Ãøé“l‚«E­G­â¬š' ö“8š?wt]Gß/è»ÞûÔ¹,qENô�ù—U•aŒÞ1Öžˆ Ÿa6ï­Rgò#’«åŠ[§·8Z®NNÝ�ªVí�3’,±³ölw[vû=ûq°¥$ºnÁr¹¢ïdIô9±ì„uŸ9Yuœuœžq´^±\X?¹œª=o­–ÌK`i-d9^e–‹cÎOT©:�“²Zö¬SOÙîyQ_´‚´Z’MlGm.a’DN•Lq_7%2Ñj‰�¢Åü½R(Õ€¥TO à  —™BóÕFï×’êà ÀŠ4=¦b ©µVcIðg”C‡;“@u0¸m6i,ûðÁš}.óå8}ú:�d®ÿ±ª²Ís‰¾pÉAtbef„ˆÏ§ð=9@­Íß›Š\�h[líÚ%â2-Nxèiʾ�ö¯×¼ìFV&Þúù`ÎÏ© elÛMтÿ¡é˜ÝÃt?)Ì#�I¸ì J³1Ö÷˜bÓø§Iˆ�W�8ãhTØÎy�•¤Xl® €x‘ŒhÇì6®%^~û¦íQÌ Ù¼‹øFKLM›³×ÀdÓ÷óñ—æ7ºÁñr@ã”!÷¯%žfñiÇœ?>_m-Å_·GÚ6nŸ†üu®­4·ý­^y~•ž°kôóòKnú0K´Øp»¨ù�ÔÙ¾7ýƳL¥›lófô¾ôà>)oØ_^ú# ×vú¡ ¦ }pfû¤þ»ú$žOC·&ˆÏƒRíÁ2—•³{:(#j7ÝÖNlÕžfK0 ³¸-�Oîx·…7§Dd²zHϹdŸ�DL’˜ÍJ šLà&C&¹Ñ4!+m?9HTïë¦S�GîùIëÐê×£]X5ׯƒ®~�"HŸ ¡žÍAì2¼78A‹0 È8Re$ËHʦ$#(³èëUæè(stœé×ÀΕ*Í¥!2¥OhŸ< �!/ºL×w°èÙm igϲ¨ñA3ZÒ¢ë3ýRX¬Ý2‘É:ÉP¥ÐH›=ßÐÕ’ŒowPkàÛçö½�— ¥X>¥V¤ÒN¥£V[]Ît‹L×[)øiƒ¾hñòÃÚÆ9’Öìj4ÃGn:gsÌ;µ&I‰L®™ŠqJRïãÚ¦hyS<9dÑ2!52´J£Š¨†A Aê‰�ÜYYînŸØ{´ˆ7ùreȘ0›Ö�Í™))ÀÛ¤T7R¼/F+=qùQ‚ë³Ìðæ·èÿ$§R9 º¶žª‡´y/¡5¦U:WFS_˜Ëµë ·5øÓùuGé. ¥mú}V•t `ý™Eö?Ä•;¯ˆ=ÿpX5Ö��9/ówD"Ùêœë:ßÏËs­Ÿ“bu=Öþ»¦Ð¥Íµ�z鵿/Iê—¶ÕëŠ*ô«?ƒÓÓ›׃þ�Æ�W’I[¼»ÙòÚzj üp»çÎrÑh‚Îý�†[æÔÿ�v{î,úÖGàŸ¿à|Ñsµ`¨zÀ#¾H‰_ñ¤ÀÕXXåÄç¼ràûWJÕÖ‡àÃÝž¯={Î/¾r�û}Ï£aà«¿ÿ>ßoÃ'ÏfLªÈ)D)¥–tìÐ’§¹-Àž­z#LñX·úOAC§–‰2ИQÉתTb�\’1‡çÉ�2&1þðüb‚ΓÒ°¥‡É�±´¤�Ì*Bõ`w¢Õ�qÍ Éd$Gmé´| .jÕ`.Ï’Ó©u� ”¦ìö‰xCÂÙí)¶¿ëæ¨h ¡kãTîlx¢ÅPã0.[eØ6W#/...v<ûpËv/l÷x%COuª»JrÿÄ‚sE+C1L´ÙTV!fúËä}‚–ìTó”tݱßïùÕßø_†kI|auÄ��ùo¿Ï+Ë?w~‹÷·;¾åt8åõ µò�çFéQ�M)¼±^ñƒ« I„¯>~ÊÝå‚{«%Ë”ù§ï=&¿ôÊ}-|å¡áNræ3·Nøž£‚wZxûrÃyßñ|?p¾\ð•‡0ÔÊçÎ- ´<¯­Wüå×ðeÆ?FNºŽ+ç&ïExërËÅ8pÚwœ/zÞ¿ÚñlxÁ�å‚ÏÝ:á;—|èÁÅ?{÷6o]m¸¸0Oÿb[cqÞÛîxûÝ-¼~´æbøŽ' ~æü”±j£uÎÜZôà‰��*_}ò \6%&´ó½å‚û«%ßöüŸÞŒ<'áïü—–û' ¶›â�$ÚDT?Æ;ù3=¤Åœdr¥$*^ßωÚÓê@@èë½dHå†ZÆAU¶J°4m![•ì : yÀ`£Úî!xªÅš–¬Ó¤•ªc{Æ\êhÔ�ãì­Šr!t‹'Ç ºnd»{J—6\]¶W…ýN‘š99Zpz²æüö)ǧ·¹Ü칸Úqq¹åyNt{“¯‰=Z CتN[Ò@âºn¦ïªƒÂæI)Â'2õ6˜éiñé,->Bn”z+ÄÑØTc~ùwv´ïZ½×@)£ó£Ûö–`rû§_ñõ3ª²äð�¾—ž¹òäßÚ“~±¶xíhÝšü›ŸS<˜šDZ��eN¼y´æ�..[¸èW^»Ïÿóøi[ç Ií¯ï\^ñíW,sâöbÁ㙬ûs÷nóÞvÇw_\ѥċ2%(›"óðú|õ}ï”2]^ÀBY­Ö Û‘ñj¤Ïâ‰�É'§™ÕÚ ¤‘: §”�2ˆd’›ÓÿÂN¯n²F/:‹FÚÜ—ÙÔ²õœ}Du’©Úd¨éT§DëŠá}к¤­zVë%Iàr#ìöWìö£¯·D)Õi£d²ÁæK¶g1ú–:­jÊJ4,_,•“Ó%Ë¥…a¨\m£ŠM r^P Vý"B�T·“RF4=U³*¿SýX€Ð„XÕʨ£(ìYg÷•ú®§ëúFû“ç•Ô2% €®U)-~–BF¶!ÐfgÛwNV1š,1Ð¥lö”u NÝêÚ(Û݆««+®¶6Û-Å)‹ëõËÅŠ>'«’ɲŽ—‰“uÇññŠÕjÁ²¯t�'D,ÎPGªƒ*•ZGrRúE&÷=]g‰T­#ª£û •²¹ÚŽÖ€:uD¿Ä¢jUëê=$R¦ŠõÍk ,„h1‰ªÂX¬ß8†Ñ+&K1“±Nr,&÷Xa,Úú)áj…j ?Þ§Ëûå謚’ª–PXŸ”õ“ª©1ÀmÃs–É÷Ï3= S€«Ê,�j:«UºM•÷­‡\VY¦ÃYH\€¯æ2Áü†:ÿ,³^\j{ÐZCw‡> ÓÝÓ(PŸ óÓÏ�mºxþû þÃl¯éצÑÀ—w @1ùp kiH…°¯ù*±ýϰy^ý¹ s‚ˆ£4Àä$·>KL6‰zò®=c÷±QK¦RËäÿ„pP�a¶9áv–W4J0Ìm¼fóÍÇÀý †óõ!s4žBÏÇ«ù–ók×Ù_Z ‹–hÒk~b‹3ɸ:�ç`ŽDL$Mçk¾j_’±N¹Wq—ÖcYœ&QòtÞnj¦0¿¦A™�Ú|ƒÙÏïພoÿž?âQ?þÐWýˆ�®OˆÙ5ÿÈó_¿–ø÷5á†#¿±\&ºµ�VÀRašÕË^A»j™oñ±«Ž¸O@ïÏ%r Ï Mt ʘ¨c¦KÆÍØ{3ºÔg¯˜’"Ê€5¸… t‘pXr4³rtè"‡%G+í* ¥’J2jÎ�Õ�¢–ÄXvÐ{¤€ì S¢ IDATwUG§ùq¤ ÒYÂê$’m7JC¸2—‰Æ¢!ºM9ÛÇJÒB µÄÙ5I›-9 P²�{Sl`‰� âˆäRî)‘²Æz3œw�÷0î ãΕ–$k,œ½¡—;zêHSRª¤T&gºÖI®¶-¥!lÙ, m勉™e¹•ÉÀ˜*|vÏŒkãû¯íxV:¸¹iµÚ¿gɼ¹ì–ù–s¹!SߟÆ5·¾“­qv´&TgçšÎ:wB ¸ìttÝ”\WÀs�:“Û!º3´þ•:U„aØdp5Îô Xh¨°*Ó8…±€¶ç4 Þ5½ö¯�úõºÆ9?ŸB –Â=o 4ƒ—K¯¼h͈ö¥PµkçûŒùã\§}Çiß¡jÁÊŸºuÒ¶ýæó|âxͯD¸·X4d0Dñ/¿r€¿xvÆßüUø»ÿð�ùÛÿéÏZ@*ø«–ä•RHE­GL3Òf µ$¶–³É3úãQ¹Žð๤HØ_Óy é „žšéṎ š.I1‘| f´Õdë¿Õ*{r±%ü»¨ˆ+ÅeVÈcA¼�ŒÕËTÍ�1žZí2š;£ªëæ jZV6ê×ìŸç:tn;„£„Éì ]·¤€o_ª¡k¼ ÕdêKVˆ`‰ © #Š%J±`âæ²põbäòräj[Ù°ÛÃn/m¨H–¤¨Óªkb,Éިчžø š5¦„ér úÿ×oüÏ<ûð!§)ñÅÕÿÑë¯ð­g¨*O‡�Ó¾ç²XCÉ“.ó½W\#Ÿ9=¡KÂ[—ÞÝlyóxÍ¿ûÆ+üÁòþvÇÓýÀ_{ýA ÚUàÃa"¼º^q1Œ$�üî#î/Wœö™Ëqäž~ˆ¿ôê=v¥6$¯çË«œØK ÿþϸ»X õÈo?|‚`U>ç}ß’o¬W|áö¿úÎC»–ª<÷æÇØ7š¤[}Ç­¾kMHï-ü©;çüöÃ'>urÄ·/.‚ùÝ«-E•,Â"%Þ¾ÚðöÕ†^„Ïž�ò‡Ï_´ÀäÏß¿Ã;WÛF‘r”3Ú%þ‡ï¿ÓVÖßü~†/}ú›mõ ß”˜Û‘âúQ|‹Ïý³Äd‡hAÜy�#%„,UAIѼÎG[|`ÚJò TuçÕøÎlݶª_—7M†Ä$6ÝÁ.<‰GR*– ÈugöMظ¡ËP+ïÈ#ÔMÕ+6Î0‰»Áh;&ÈæTPnzÍÑa+†Í][>ƘN`-Ú3n¡·ùbÝq÷AÏgõ¯¿zÊ~£ì·Ê~S)C¢Kkº¼¦ëV…‹b½­:ú´$턺µ âRö D½—”e›ü²à¬£šÝ6jö½ÐèÞ²svO|ø};5‘:‡6´@Ûuû(Žaî”â¹'ŸSöKA¨D—«6eâš­1û<84*¬ÝžùØÑŠ÷·û¦OzÓ±‹É‰]UÞqz¡x}ýÙ”DÛ•ÊÅ8ú±Ö¼q´j´?3àu›µ¿þî#Š*ëœÈ’xëÊŽ}¾èùÔÉ¿çBG]æó·oñ;�>`ôuýÞvgr èSââ¦Ä€+™˜MÓä�ÖŽUYXÂ~Ê^'º¼`µ:fX ìòÆÜã ]¯ôµ°XެÖÊj¥”«Ân@:ŒÐúEïÏ)zD©?ÍHEPͮ΂66ˆçNÛ6yÀ?{3ͲN>ª¸é7U*¥¬ô=,–ÂùÙgç·¸¼º¢Ô¥ìŠU¶ÕÑ©�f°ê)î$Öœ·VOÞ%ÐB)ýBY®à�7ÎøÜç>ÍÙí[ £GOùÖ7¿Ëûï?Ç’ø±iÁõR<š ”˜Iž@SŸãæ‚ULJÕén¦£ü4€UPH­½RÐЩÚy#Y.Q3à‡æR[-JT³ÍÒb¶C–Dî—~-®Ì«’½ÁóDñšÈ9³\.9>Œ+¡ï{V«5ËÅ‚.%º$t¢ôIY/Ë¥ÑÁµQuWE*•‚érFTÈœZ©ƒÑ÷€¡ø…JJ‰,Ù]Y«Z� ¬Q­J“m£*u,TIV“¼š¿J‹êA~{Ãè´‰cM†°@"ª&ã"1P53OŒÖâ~¸˜ïZ+ Åa Éã5*ÍïQ­&G5Sk¢¸mš’]_ª ÙƒðX’w °F0Ÿß„Ž€6¾mò�ŒÇÇ#ä²ñ€šo&Í|m>£ƒ¿!Þ:û·Ìþέ>^óW›a1³ nz}Äo?Ü5¼¶ÛÜšŽÁª“a D¢óšÕMóeÚó†ØV®}ï T“ÅnŠxà^¬z VKȺÜ>lä櫌B T ük)N�ÌÔÓóÛÔ““­¥®öØ[§7ðq�½ã9]‹#̆.~AOê¡Ñ&i\Ïá#?º¦>Ÿ§hÄ(fÀB�_´þší:lœZŸÈv�éÐ2»�)Œ÷ˆksX¹þØU äQN Uxp©m�tM‚œ�Ã×µïJUfA�ù…,˜Ùw³ãÝ\‡0i#™_Û�Øgv?b‘éµ=äàûiqÜt @ÖËK…í÷—Î¥/}:ñÏ…\žoy 'Áˆ\›è±øååßÚìó¸NøQûå þùÏì\\û>qÈG¦ÍȸybͲŒ³ä@E<‘ÝtŸö‘V¥Ò]ƒÁaÐy »qçù»!�ÝÈO-+ê£×_€ÒBÈ‹Ž~yY-1P2R„º¯Ô�—<W0]$€³†AýRèV‚,�%°PsÅl²l·ˆ’´Ò2¸IH½ø± edô=i¡Ô1SÇθ9s¦ë{ºE?©#‹ªVVV§µÁì¤ ”hö ’;­n¬QÅOMP  ÓPS)!‹ñÄ€Šx0Ë�¤ZãÖÔ%C Å¹œ‡ç–M íô½_�o³Í´ØÜ÷Å“Ž3å1•›ao4œËöŒ‡J•4*èªÍ³Ü%r×A×CêÈKè·°•­—‘[2$;ÃF·‰u£V’’’Xix…@(É9mPô˜;sfÔÌQk“x=hÊËdD·Š/� X3’>b-7û" ¢k+ׯZ¦uÄ nåü®AZž9 sËtÝöûü:Ä×´'3 A§{hàdê�PšYY‚eÖçˆN§ˆ‘œ¦ësƒÁNís½‰Fmc¤Í tÃìZr` �ú˜Í�ùë&u×FÙ÷yýõ)ÿdx£ï[ÌQïgû Sß�]©,sjÎûãÝžUNœxsá}©ìjåÈ•‘ˆ$`ê;p1ŒìJáž'.ÇÂ^¼à ·ÏÚ¾qÜx}ñŽý¶«•M)œ÷=�¹G~ïÉ3~áÁÝ–Dø•ósþþck²ú÷þÁñ·ÿó? cE‡êãïÃ-Ö{$Öÿ¤2]–eÓ9¹âòÒ�ö|^Ú#8aàÉôžþ“¹pý9ú\ˆ D+ïô`¸âh›V˜ÌÕd�ý í1d–'jñØ…ë¸1!¥ E­Ý‚#ö Ù›�®C»YÒ¯¤óuév_aa26™o†«Lïìçu§”Š%z›].®;‹õ†lÿ4�HÔÚcóë©c“SØØn*WW•«ËÂåUa³Uv{a»vû‰šÀž•9ÏÅ„ŠÑ\ŒcrY™�,A156ÕYÎÅsæ“Hâ7çïñ½|þúñ-¾pvÊ[/®8_öœ/zŽû̯½ûþÂý;,Sâ×ß3꫟ºu§O�ùç�Çžíî-<ÝÜî;¾úä)ÛRùç·X$ákOŸ3ªòæñš¿ôê=¾òð ÛRxëꊿôÚýŒ�w®6ìªòæÑš]­<ÞîùƳ n/z¾xûŒo¿¸âáf‡í�Wx³ã—«æùp?pÚe.ÆÂû�_{ç!¯®–T”>å†XþÒÝsvµ6ÿÙ¢çµÕª/†±UG,�:0(ƒÞ8Z³HÒÐͯ¯W|þö¿úÎûvª�W<^ÿâÉSªâÜæÂùjÁßüÞ÷Øy ô/þuþ³_ü ›�õH)ìáXm¶à£:À–j$ß6­úH\�¼6UŒK�¥•C̾6“›.¤z°SÞ?«:2=4K¦LT´j-nV¤M…¢H±`Pç� ZaðJÐT½òÔæo€_PÁz—Ìx"`­Ju�f*0lkÕ©‰èÌ_èÜž Ú£Z@·¤´ ­VÜYtÜ>¿OÝCãvW•a£Œṵ̂¶[ØnŠ»<‰>u,;Ð.1æL©#ûýŽ.)Ñ'Åú¾ÄX'û¬6žq�Mçi‰kæ^üÜó1ÀJ­öl5îÙÓX"Ü­i:>Çâ—C/ÅøÞÞ[Ýh4Ëèv¡ue�Àô8Óïnv”™=”>Y„û«ïmvì¼_ÓŸ¿‡ß}ü´Uæ]·ÞÙlyëjƒë.s5–Öøû³·Nxg³mÉ»7ŽÖd¾éÕ»RyÇ“–` ¿æ‰ÃŸ89bWJ£$ûÜ­>së„o{÷ ½Ð3‡ß[ÐIÝ6Vuå‹�SÏj¹f¿ÜÒ¥ì9y%çJ¿(¬Ö…£c8:6ÛÊ8(–0ôz‡ÊèÏùšŸÚLEóom'?Úm&À8’ZÊ­¦§Ÿö‘�b½Û:�~!,—­³5o¼ñ€ËËKž=}ÄÅÅ3Æí@‹Sb´±p \°@ë-×¥Ž.wTÝSë–eJ¬Ö=¯½~Æç¿ð)^{ýU$'þè�¾Ç{ï½Å{ï_ù2"K³9›9ák!«ÑÓH÷íû4ëû3½3))©K.ߦ5×úº�¡Þ§ÁªÆ6Y“³QäZ LÍÏÕH*:ëQVÌ—J�šÖ^U+•JŸ{ºÜÑz�xS<3§‚ÂH躎EßS×Fi[�Τë:–Ë%‹¾o ¾L!§Êªƒe/t�´âù U�ÄÀH’©Èl!s´jQ§²þz ¡ëÌÏN>Q‰ñ�ê9¥Dê³Qý”ŠŒÆéŸª8%íÔ‡"(�JQJñÂÒj”sÅ“&ñ�>ÊzhˆW ÁóãC†1üVüYb4D)!tU²ÑÂÐ’ %)‘FO\8•žÌzˆh‹îDÖẲqŒûSד-^Ö^>è‚1@tžØ‹D±ûg­B>À@â¢æàíþePþEâÀÍß92OÈô¹�ÚmÄÉâÓMÞ�Ѝù‡ð�¢ÔþC æLz»M%è“–¢iòÙç°íÛñfÀ Å}�Ùö®’‹`‘ænf i›ûªŠŽÉ’ 3ƒ[½ZºzÌ'’5æ#øÜ Æ;n5†1ßLnCTz¹O(¥ö&ðc\J\Sû\'›(u‹>êìÉ…Ïsµýõën>§?3¼2³Fò÷†Çßvš®»UªÏÏ#ÓµäÀõ¹œ}hÒì>&-Ncã1G)¾.Eè牴›‘ �8ˆÎÇõÍ�¥ùÄpó¿ÿ­_zíó�sЮë`ÿëÇÔÙo?îõÜôtô+&¼ˆÑUD’ajbئï ûÞ|ŽÆÍ×®*®- ø›®ñåóÌ„Á4“¼$PH³9ÛÏÎÝŽ]¯}n#Á!z$^e¶ß4»£8ü¥`¦Nçkz%¹ÐÐê€H/™q£ôYÌ$ãËŠÛBBîA–ÝWt¯†‚°**©ˆdrî¡f¤jc›ˆ&V¤JÉ] ÔNÉ]&÷©Ä� ú§1iÂÒþ‘4Œâ¡[2ftt#Èï)g+=GðRVsD*îtΖˆQNt‚ôâô L(þ¨ÿtd=-(kãih€ìè*WØ��}›&•b`“V¦oG²pªŠ¾Cª�FÐѲÒh5«£õìYåØ-‹ìB®ºÐ£¢ú^Å�Þ"UGX“G¦Ê‰s9�xü]Ɉömž¤ìè @\9‹ûëø¥ålh<½�ËH`8}Ò„b°[ȇOäÓŠÐö7Q]0ÓÑž(Þ@R{Öäi.\[Ÿ:é!_bÖ¾ %¢ÓT�’Åß�ž+”’K§XfñÛL¤ÈL 4j êqàfÄöS£)ã&KC_aÁ˜H¾:"3ÖšÑ YB uÓs·ëµ¤GCEÛ͘2õjÍá#h�èƒõ6�ó¯|0~´™Ö«¯·?ǃ¤Àõ×óÁ�¾ñºF–yj0|ïZ³áã.sìI�‡Ûf•ß|þ‚�­9öj‚>9i¶o$‚¾äÍcK"üñÅ%‹œùØ‘Ñ=Ý <O Xcâ?qn= Ô'ñg×kÞX,x{¿çkßxÌ×¾õ„Ïü–�µ‹QZ^j8‘ˆ•4šó”2I³9º)OA}™&¹Fçø¨™¯ÿ†’é=74ýÙÌS?±“× ÙV‘P˜«Ìö\#›|î¤ÙöÚZ­ßNØÀ%AÉä¢.¿¤U@2Ùºˆµ‘¼€KÝ~³s…Qƒ¯ªº�LöÇZOí“D8"SO�H¸\ ÞQw*"Ah'²kµró2 e€2V†2²W;åj§\n”«ìJf”Ôò!t~ž¼¨¢TÑV1 nÓNÉï3€ÿN ŒíxÑó,lƒßûƒÂïí7øx×óÙ³SV*|çò þêëxº7žb°žc­œ-zv¥Ò‹ðå‡O¸»\òÊrAøç�? ‹ðW_»Ï“ýÀW=iðñ£5¯¯×|ãÙ£Zàß<»àîr‰*¬ºÌo¼ûˆeJ|ñÎY„ßmœàGüü½Û í?T“‡wV mwõ™ÿ÷ñSƪ¼q´¢á�/.Ù×ʃõ’/Ý»Ã?{ô�%ö{~åÕû|ýÙE›•W¥ò|?qZÿàrÃ.7,sâÇG¼uµi ‹_~õï\mÕHÝÀ“ýž/?²ª…³EÏf,|͹Î?~´f§ÊûÑlõhÅÏ�ßâo}÷»<ôfÃ?ùê-þ»¿ñ%Ͷ^Ñæ‡Ø�ë¶Gi0’y.ï¥Ä€ÏŠÔÄ�4ư"�UèTZ,?Še¦öHNg�¼©¹¸ 2eÊÚE©HK,LhÄ0Ì.²Ä¥]“f€jv€'áZ¥T¹ÐŸ*�æÈ^&[Yæ2ÅŽ).",¶r(±šM=y¥v�Z½²² 0¨%Mà "ôÖÌ¹Ñ WkŸU²2$iTÐIÄ*]s¥a«™Ú±Úe¶}¢Ë�Ä ‰¶‚6Ä“:žH�Ëûa28drÜíO¾þcû©&æÎz«õž#üd~ìiû”‰ j‚¢eš ›U•�*k‘–ˆÊœHÀ©j£ Œ×ÿýèƒvÖ,Â#O"œt÷W‹–�K\þ“÷7[òb�ºÆ^‘0è“ð`µâí« ›�ù¿ôÊ=þÕ³ç|àÇ¿½Xp5Ž¼ë‰ƒw6[î­–�JÈ\Ù™_6_pDUGbòï<-Žb.•ýn¤ïìsã®ßív|ÿ{ßau²ã•7nñÚ·ùÜOœ¢Â7¾ñˆËË «Ãúmí‹�a„4dÎôU"q¹ö\š'¬Òâlñìí‰K{ÜIÌ�3›{š§}'¬ûžÕ"‘Sa¿{ÁÓÞãòòŠíîµîÑj%u)eº¨$¬ ·ÜgÊ>Õ*VQÝ¥¥²Ýîxþü‚'Ožrûî^yý5¼ºçüŸru™(c%g!wJ�ªÑ1¥ì•Û99mYžæ9Ù$cø�Eõb«„vû[ñ„€=ZÍ�#i%‡ž|­•‘yE—­Ý¾±¼¤õ4ñ'à•~ÕçšL&ó¬Ê<µ*±f*úü3Z×äÔ)Ñ !&H“áÉ€ã(vÏ-Ñd¾~IiJZ¨ºX;Ïø r ¹™íR£©y yçu»çþ¯•R•,™L¢ÖÄX•ZG¯¦pª"’û’ÙinýYTÇ”¢¿Z�¿ÔÌX}]—4ûI¡éŠ–, y(ž8²;J>®*PÉŒU,N‚ùIöŒ�²‹Y_’tj³$þ”èmb¤å›ËÇö‰ríÀØš¸™Þ úÏÅçÜ礲gÛL3ãú±Å¿p²ÆtÃ|çù×1à?äu=)àz¼}hòÕõ±`6ú|lvöw»ghõ¹­‚“ÑO¢¦JAcZñ€ºÌÔíri¨Ó„ÒZ�jP5ŸÉeµý{º' ¨û®ë˜ì«Ð¥âóW<‘+ñ,fª9TR¬ÏH´œCûÝÞSªx6ìe¶ÑAÜ!Nã×q¦ù=Ê·—Ç€æó$ìÕêó½ÅDbªÃ¸b‘$iK˜¸½Ù” qt=Á$¢î,Ó˜©ºénc¯éÀíáèübåš’ 0 ‹Ù¥ðÃ^ˆù—Fêå­o~ͯC~Ķ7ó¦}~ԵܴÿMǸé:Ü€…æ$4dJ £|Úvöœo¸ªÃã›3‘>b“Ãëœc¯o:Q‰|Ô¿‡-aPs\àüïÌA:8ïÜнi?iw6¿�ƒš �}ŠÅ6ù³ Œ˜ž:›»2ozÍŸ›­Jkr›É£Â¾Â^-A°«ÔT)"Ö`1é�@¶”:šUFJ®”®Ðu=‹… ËŽÔu�™5ˆ�—)¦]½ƒTŽúŽ®dC·7âø¸lwk�¡ £5û­RíÊ5Må×ô8ÄýtÙ¼¸ø}œ=—.QJNW4Æ9þ&D·%È´W‚²ÈÈÂ’ô=Q¦&£�7‘Ü^J-1�gt05ˆô˫֩j¡èhçJX¢£Kè›%*N²hÉ�H€ˆúv9¹buãV¡«¹¡™Í ƒ�¦üÚgÏ�X@Á«ªS:Íøg'ĸLJ�™ ×P.7¥}%ûÜi½\á•@’Ds)Ÿ* È×{Ìi¿š¹xlœÅ“Ó¿›r­ÞÏ{*Sž7žÔ†©}ÕªD›BoèÍ6gþÖÞ,Ö¶ä<ûþªµöpÆ;ßžÙ$›M²)΃HC²Ó²iy NœÀHŒÄyà‡ ‰2ø!F€<J$�àA6�ÈŒX¢E‘´DQ”i2-6›j6Én²»owßáÜ{æ³÷^kUýyø‡ªµÏén:ðnì¾gfZUýÃ÷O&f d\“KÕ^Îa‚›Ë`k�z /ýÅž­Eâ h$ÂØ/© <¬l�‡ëýHǤ,‘XS/»r�L¡ñŸVºá­_ãk<üpi¼§À™½–)�µS®Í¬™°Ðƒ5'Ì̸µXâ ͪˆ }½_K1ॊf1¢gÆ‹‡Çø™*³àGǧxzgÓ3ݘ»É ͧxh>3㕳ߘ»“âë{ûxt>Ó[øÅK—ð«wøü•_{ÿëñ9ÕiÞÜVë¤zé­œ­™CDƒ –Ò#�•I£¢$%U€•7’íý z®•fRÜòÆ�Ô¾/òKÁôsŽÛHTú”x9!fcÈ’ue¥ò(4¨‚g5È5Åœ¦ 0�EÑMŒ�¥$B € ž`À€V‹ê�\‡Íùª`‚þf} Ðq‰eT.égÅ7þ&gœ <©“FÃÝ*aÕ3Vã¬cœöŒÓeÆé X¥0r $ž]À}Ù‡fn˜ñi›3+á• U;Q>J„—^y¿ó»¿øìlŸÙÜÂg¶·±·\áÞªÃÍù/ž Ë ¾´�6Å»·6ðj6ÞY®0‰C`öKoÜE„wom`«‰xþPÊ&=¾9Ç3»ÛëÓ î-;œi ÇóûGX¤„yŒ˜ÄàƒYŒøø•]üË{°Ò(±O_½„ïã¶:VÌ£Hiøûwïâ['âdØœµøþýŸCÓL$bš©2¦êH¯âŠóm«W¾6]jX�gìÇÇ@fòZÙd 6“+ŠÌP'³QSeAö‰ØØTx‰)Œ€èe®W3ÀIœAà¦çJY•^ûA‘’Ü€rSô’’”©RÝÏx�ëí:ŸŽ RÅø € »JŠ”n䘆4;´¨53å³@ Ç€2z"o¿0i&˜M" ˆN9`–L'“–ÐD’G”Õ±£N[/ˆX@¦@¾� E�p^«z”|‚�õ9êàå¬sSôµ²¶¤<Íu0ýÞNoªJDÄ,N†TÀÍ»!b©ëzÔ8êK‡ à%úßœãÞbåÇ>¶1ù~[åŒeUÖ‡oì½Õ4¸”#zh>ÅåÉ/Š3°¡€Ç7f¸³Xjãvéwp6$´Dˆ!àYå'7fS<º1óq–’g.GÒõ_S}=J6 ÀtÉfaHóªën =ÅÚf‚Õj‰W^yó�zâCxä‘kèsÂ{÷{ܺu,Îf¶€ÝË1ÀÊç@Äà#TÑ402ÚÏ:t¹ì ß>å�Hd6 À(£m"æó³i@ „nuŒ÷8=;ÃjyŒœ;íIj@!ºLÓ8ÊÓÔ ¯2Wš MÓ c…Åj…ÃãcÜ»�u�cçÒÜHW®\Åææm,K 9¡™Ú¶s F ËX Q3Åc�r8°(Z‹2/td¶ˆd %ĉ5 ƒ%2–KyÞȾîl�™�ªç�•]Ò@³À1VYd€fzk‰!)íV«pÁæ- Â¾|Åe,�JPT lgu@‚ ¤±0yo¢4dP”ÌoÃB”,‹¤v 3!9�*²:’aÆåÁNâDˆ�8³`Íâ�Å3ƒsö¾Š¥©o70ú>¡ï!Jß—q!jÀšØ=4°–i ès ‰¸.Ó¦ì2«�ãYx¨›IÛ³ ¶£%#3"(ìmã IDATYÀ3@¥‡‡”¦S^DÙyªÿ~C÷+}™PÔö †,9ìÄbsFP©Ì#…  ô-Œª÷‡ò›¥ëça횣·éñz¬;ªõ�dJhµ©*^¹~?ÏxU8ÿ¹Æ^Íæ5ÅŽ½m^3—ÀOÓ÷ë,aTë�Èšý1@± «ÁPì ѨãUõw—¡Ò¯‘ÔNsD¾T/ɤ›þgte´¯´¡×’_/®¿%ùœGªÐh¹kœ‡!÷% ¨Z“1¹â;6‰•8Ôc•·¡ÌézÕ�»àv¬×0Ç€ ’|Ítˆ¦4¬ïƒ„â4ƒè•¦ŸØq͈èì@£O�î¤ñ�5�9«O†ý`¦Vµ'Ö¾?÷ª7Ïè&ïpü2:{ý¸Ji1ˆ±¨_¿Ê;W=¿ it¬ÎŸ1‹F€r:À‰@Y0¹¬‰èÑ“Xã“·±5°ðæŸt~%ÈY<¿Å»^®JÁŽ9Zù?a´ò\…ñÒ{#¨:Ú§~WW¦š™ruÛÝõ&¤j>…Œž}âˆG€�®ˆ‚2å u€'*òÍ[ …aä Q’ZuÌ[ФÑ9²Aƒ¥Wåb II%v¦#©x \­3õê%)£Q ¦HÒl×&ºp¯6˜$ezÔ�z6_ú¼œvÀÔ¢ÑäªÁ‘7n•o¤¤”é0j q<´µú7"��� }¼<Ä�$7¡4æ3A Œ‚Dâg‰ �@�D°Aß²@¤  VŠ#ÀÖdO�¶QG¯ã«¢â9·ˆ_ 3‘)a•�nPJ*¹E¶�W �«“ÜKó$�ÚnÀî0ÇR%[ĉ4ädåíLd©�B(ó­·¯Áû’ºVרlsÔ Áä_v2«É²v¬û›ÆÊ`íåP£jT‘¡ÌµLŠB¢dREwkSê´¯ƒ<Ž�PúZc—uµÌ²¨Ù£ÖäŒ RšˆIÓHUh‹­èÞþñ È¸‰gg\ĹÏ;Íås]JèÁ0ŒŽ0§À�3š*bw=s`]|"w §7'ÂýU‡YŒž)pÜxs±tGAK„wo•,ø„– :$:qw"™'Àgâço\Õ{Ž{-å£{ûSW.i°<ã/\¹‚xïzfüƒú#ü�ÿìS¸2m`M>ž•�BŠ] L¢£¶„Ü4hBàî|%C sÐý+kè<±1aö­ U•̶zÕô3Qq’†—ýP^gtì¶Ù¾ÖuQ9G%B®w!1ô:™<ëÍG–!I©º@AC¯h€ð‘¤]Ê¿h� dˆƒ,—f0Ys×XžQù¨•ÿÌYJðYsdV#ç€Ôý*c¹d¬–Œn`,‡Œ³8g}ÀÙô9 ã€�)¨žb‘ŠdŽ. ¿|: QûE/-åÈÜÝbIîÝ»…òÿüÏÈ9aF„'ç3|bg_¾}MøüC×p:$/—sy2Á»æ3<h͆¯�.py:ÁI?à]›süîé‘ñ™kWÀœñ­û`»¼‹Ç7çø�7ï¡Ïw—ßœãthqWË{½||ŠUÊxjk!|ïð«”ñ®�9Þ¿»�oÞßÇA×cü…Çò@™«V™±ÙD,SÆÉ0à·ß¸‹›³v& ºÄxþààóßÀONN%r8Ké:„i=XuøöƒC4D˜Åˆ�_×þÜÝÆÀŒj¦À“[xßö¦ƒ‘ Æq? Qg|åöËØš…k»›8ëL†'€í¬¢-ÚîcÛRÅN¦òY¶ŒÈú 4/ÿfbD°—\ˆYiÁ@,FŒRÇ:4Âw2iis ظ܉f,@#Xÿ%)H!�»%{ÒJÜ™ž'VŠê pÁ EÑw%ƒˆLO5Ù¦ýG,LßÒí3DW3áÄI2l+AÍÚó(q–À ÝsΦÏžrC„ä•d¹'N@3á%„&DL›F�¡„6Ê{Ú6f-–Ë‹IƒI«Ñ½eš ÿsÅZ¢lsU"­ÖóÅÞ)ࢽʟäÆ}°L-ûUÊ^i6ª_¤MŒ•zÉ P²?IÚ„„œzçç€,Ñ,sF$Âåi‹½eç÷øÜuÉê±×rÐHm}YVa#œÉ£ù?ze/Wý>nΦ8wv½76DXæŒ?ÔL¦÷nmb¯ë¼œÑÇ.ï"¼ïé9Àq.Žˆ&hýx³ sB¡Ðf�Y�§&»ú¾Çééú¦‘$¹nQƒ¾Ë¸}û»×ޱêVØØŒxäÑkXu„ï|çb,™g¡ RªÅ2–�.ÄÓïú­F0°Ø ®kªcßèH�bvÜlr˼+À3«£Jʈ‚{i³–M ˜LmKh)UàÍR\†i°C Ð éË4“:PÐËEÄ·±¹ùˆvq|²Äƒú¾úІé¼°‘Q#|"*Á¨ßA*:0’ó^+³Ã‰Ê|qß!Ã3yDÏ·]§ãR†H�T´'ß³~ íéFiàgá% (¸l·ó|Œ¨hæ€ÚÑ\EÍK™^èV�fm«£W‚‡U—±yIø¡ÉFðfÅV¢Î3²ÕžQ2Y�[‚õedNÒ `Ñ!%¸ŸëÇ!xnÖĽ¾ÚyÂ%p¦]§¥™ŠÛ“Eg’0¤ÝÖÀÊŽúf€C,f�³@ÿ–-ˆ¥\%Ÿss X™§´«�ñM¨nŒ'+­¨ƒ"@Ê–ÌwUËMð}­{É™ K°9·XÏVH`Íì2&'×ò)ðA¡rÚ1™nv^yÙ |€:Ÿä:�ÓzÕ]À~‡ë¦},‰£Èîb¯+ÁÛ•…/AElPù›Ô@›@åþð Ÿ=O"@usùN&ÖJz›S�µ×@ÎL TÒ½K亇c.¿�VÔþÓç6º² â@Òß³'æÂ\hÈd±Èø27¬zW øØô Àúp”5QÌÀu†±ÞAN¨úªªF@é8#“•,,:++obÓጤܶD©*UÑ>Œr.Â×Ä2?IÖlF¸F¿Žpý=�?ö—_`ôâêÿïxúO{¬o²w>Î¶Îø¼‹Î·ûþ4×ý×|¹ „qý·¸ÕøÙ/ ûºÿt/§v=Ç̶õ;q9~ô¶ï.Xß‹èäm_Õ1\ÿašQ¯9*.zë94>jäÀÒªŒƒ×ǹׯ‚O Æ^´  0rÁê LAÀí¬JV42C@gfÑI‚€î4m@³4ia�u­�$úAË©*óŒ@Š¢@¢úël cêÂí*Á¨ÏŽÕ*û¡òŒä½t&¬N­MŒ9g­æ´)mÂÁ亪p9E‘|Yù6˲*ÎuØ:Q&4)hÄoök‰ãš�鎖+ªÂ–ƒžQxf”õ 6Šc@Á>ø÷ oD [ EÓ–u>) RUÙæ‹áM²¬O2=9ˆ<*l�¤5êŒMÒ‰�iœ³À ‰%µÔu‘z‰\À­ ¿œ5ƒBÒQå{²°[¡‡ Xý^ÔÆ|Ÿ-*«Aza�wu ȼ‰RQ-W! ØVaÓÁ<tÁœ:dr¥� ¬R@0d)çåÞz2 ô¹³#ýÅ�4zs4`vmà¨Ö�3ÜâÉšu|©¦^ÝçÂ�(5På–?�Ô{¸.%¤ë™óHȯgL+§ÁzÉ �à=Û›htÌMƒ6”ñK©q ìw½Ô\W§Á ‡Çxtcî÷[¦ŒÓapÇÀVÓàÓ×.€7%ý°f¼z¶À,Ëk§ Ü^®ð'wwñ僜-ü¿ñCüí¿ñ3FHZÊ›ÕG$ëŸY”cãeÜê{q ÔDufeÛ¿4 ´ŽE¹N°Ýã¾7òÿ±UË,ª÷²ýnФg±Q¹×šþcií¦:R5tñÁ®óÀË"9/—�¢xNRZÉ ,|Ê¢Œ8©×Â,eŠØàI’ÿ-Ÿ42Ç&ùärfä>Kܼ“2B+ [ ˆs ÏX „³pš�Å@X¤€ž#zi2 !‡RF@ áladÙMZ/˜„Î�I•y5ÜeÎO—GøGÿäïbµ:ÃÃM‹/lmãß}ô¼¢‘ºÌŒã>a•3nΧ $Îøê�=<±±�+Ó÷–+üÑþ!"¾ðÈ Üïz©Ó`B@Œ f1`‘2NSÂíâ][sm1Ÿ6˜4A‡#Ή€\ö¬+§$º"A;ŠS˃$X£”Ù¯õ,o>­%ö€TäË|3[J–M�ò8ëQ̶R§;-uÀÚ7B#d�±4ahW¿Ì) ™=ì%ƒv'-6côèÿÉè3à�ò}‹¡€ö/i&Ò,F\𴏽Xb‘Ä!ñç¹�ßyó–:Gm ´•ÎòÒñ)2Ó°Ý4Ø[u¸³\aN«1·U-ø¤Å6�ÕÜQçŽfô}�“Ó3´1  AöôÝ€Ã;§Ø¹vŒÕj…ùfÄÆÖ.2f¸ti1pdžŒ6[L$§éüºOE�„yp ‹ŒÊlAAµ^mkÛã ×TEYíØA³3¡mgÈ0�ÚFÕ 27¢½‚ƒ”æÌ�zô1¶ˆÍʯBFˆŒåYÄë·Ž�ÓëX.&èƃ½%º¾•1†P„؈s€)h“È?†f]*hFš©S유V$øˆjKt‹¯{Vffq²Š-| Ráæ7çÎ|3RÛ•Z,øNJuI�‚êáœ%û7D•e9ÍV1œôóþ)ê!(ßåZ®@¡³+jÇ@@f©ãÔñ)ÍYÅÆ‰¦Ï1ª rš7SÎ@ˆAz/ƒ‚­ƒ” "" CFׯÐ@ß!´hš�‚÷a +‘D6Õªk±dôcÙeÉ0‘´:\f-7EEÎ)O,zlqPÃvéþ%Ù3‰ Òòϲ]2˜¥d!{\^T][h%WæÙÁå»:ùƒÈ\Žr¬›ó0 ØÖ®b0¦—hé ÕO-k ./¤˜…ád–äZ�f»Iu]ão¦ÃŽcN§Ç6c߉QŽ‘s@íY ù«E à?蘒êYUn™]ì¿•áºSÀKþpÁzÜ1 üÈ.f©¹Ú“‘HYÁdÁÑŒ+9ß2Yzl°®sÎIK'—ËîÐÓçÉIú-:¥ŸW?ºîs \ °d.E ¸u‡àÿª�⬧ÊAPÙ\ÐϦGø@µdߌeF9VƺfáW¥„¬]P“ ‘f÷v¹>i�ÊÅ#�@:mæx®Æàô*'7å'®s™èó¯µ2"óƒË‚Õ‡Žašw¸nµÐë·zë+¬ƒÛep4ú<’]•™}Á© u¬Ÿ¹>&®Ge.«;]t#̱]ý‚9¬�7¾ðIΟc‘Æ4þM„£|&S Ý›pnÌ5Åpá®»‰\ÄÚ]5‚ŒQİV%¬E0UÌ=tÙ€¹·:¸º/óøDS ð®”Ù‚¹³•^LÁƒ½ Ì™µ!œ–!iD@5L D â@l¨Žä›”�( ãÉ n2³+‹�˘{4«âe´¦�Ó#KDÔ°M)«ÁdÞDé<Ì#š¤aÕIÀw"X”œ©ΰcFÈFp¡EVïÝäèÈŒUŽðô:�gÙ쾊^týÒ´9gKÄEÒD2·ˆ�, \×R UY 3f­“‹\OÍ4©× ´‰a�kèlj«‘u v&_@@*º²fXdY"„ÚÙBËT &ó^3×Y²ž¥P|2ì N2«cήÈJƉ‚TÒÍ*½ã�.|J•~Ô1� 6ÓS˜³“°y탦{³+xat ß3¯£Ižj0æMÎiLá«$'Û#>Zé3YWÅ¢ÄlïˆÇݫߙ }k|ÁD]0Æêó[‰JýáᇪRBš1°ÞgÀ>÷Þ÷Dn°Ê'ý€«Uo��f|îÓš 0°‹s-7´Ê?8:q §ÂNÛøõŸÞÙªV ¸:�àêt‚ÄŒWOÎðäö&fê”øêí{øÙëW°­å†&$ôn¯Ç6çxh>ÅÆ|‚/H ƒÿå×þÿùßü¸4Õ¨©«/4ÓQ9’–ŠÒÓ¤ÕzºÁø ;ïƆ´Ö®”-kÊâT‘¤€A�¶e3¸ €yµnEÜÃC©*pÄ£Š�£ kÖ4Õ•³VYy„®\%“‰€Ðèè­ôH�R<âyÔR!,}W:y› 2ÈᣬÆG‹4¦2YŸ%87Z‰DšÝåLHÐwÝ2c±d,—@—€.: ÄæÀÀ„> g��âùƒcìwæ1àÏ<|?8:Cšòžô236šˆå�°2¾±·�÷mm$M¾ÿÕý}"|þ¡ë¸¿ê¼ÄÇn+ûíG':ߌ�àÚ|ŠýU‡‡ç3|ñ�»hˆðôκ”ñ“ÓÒHô±Í9¾ü¦Dëp°Õ’ðͽ}œ ;mƒiž)ps6Ň.íà«·ï9§ýäÕKøƒ{p¨Àÿ�årT"å''g` ™Ïpe6Á/¿ö”§=ýèü{¿ð3X &ƒŒâY?&F}'øÞ jŸX½é˜ �`òlåj Î)lâý*HœN‘‹ìuHõ Π¨€»7F)1B¨DXÅ 8‹þ‚fÒ@%ÈDu—åfÔ6@Ö(Ña8'�™(!#rOÓ¡3rÀ4AÊ�P€ðMWQ9»I2àHùŽFÚe‹úÔaC£ �B@L�ªfÀ›Ãƒd|$evôöh²4ýžLóÜ`£™`³™b±œbv6Á¤�’ä©ÎJ‹Ö·�f÷™>Lf˘}á~ÆZk\-‹ë,ìÆeØ"ÿ4cVzJä~Wµ–UÓ⬑Ïê(±!Ì›;Û[h¦›xåà߉ãr_÷Ê{·6ðã“3�ŸÏp<$ÜÕ²dË”FN„�Ù�—'-NSòL�'67¤¿ˆ:&�pY€ðå¯ÜÙCÇŒV#翯ûú¡ù×&ÏŠº6�àsׯàKoÞCJ }θŸJÖb º.yijØÆs‹=âP«?Ç@zD’RRMhú€œ{ Hâ¨Ê=r^!6s Bl#š¾AJ bŒÑ"¥Í¡h ßôx€‚F0{ \'@6K²Ènr.sÞÛ-x${NŒ®ëŹ"¶¶®à}O½ý0 �,©Ðeq(�ae® ˜µûJØ�+'€aˆ8;�ØÛë<(b±ˆhâ6¦ÓŒØšvŽØL½·kÖY T *W ^¶¬ŠhgNµ9~~ùü–yaÀí“Ì Ç5§þA¶m&•G@m·qÀÚ“OA@�«ºìh¤á5½•'A2óm¿ÀÊÕšêßÒ0˜¤™/ii$³›“íÙ�ÚR ðhs½£ÊòyТÙ}2Å^̪çYY#Õ]41J‚»XÊ`¯‚ ¤çeH4vÐŒ� i$Ü]ŸÐC&¤LZ¶%¸£@Xµ;‘ŽSHÑtYu“8‹e>²V¢Œ0gÉJQGÀ¸ä»~˜8#êú¦Ú1@ºGÕoñ2�Q³g2r(%Û<~Gå{Ù°äj;yiœJOwПÁ²y°Ì]Á_ˆ#Ò¹ÑÁê¸.ãc4­Ù¤é©u€'¯Ñ¸™\É!Ó#l,Ž•¸[Ñ”:²FÚ1•R;jLÈ:ªC‰“Ú³©ü¶9SãÈü™DÕÑž�Ì!F*ïÉm�D™‚öKZZÇì~Ñ’ö! ‡ 3Œ!%¤dåÊÆ@½mLnCAu°¢$ý}BfpJ -G”Á£ Ü™MN±ò$8�Œ `aF£µ’{U¶Ý]ì¸[å¸àx¥ÞÌðá™æì(´`ò Ñë1Úº•ù»Ø½z¨ò–Š(Îkoõ_kýÃÂAð�γïʾAùðoòUoηúý¢±Õ¿ãí¯QŸ~î0»ÿ;¾ýË”Íñ8eóÕ!©ög-½Ç„:šóµó\gã·X+û·^s®ÿ¥µKry›dsæYÝó‚oÈÏ¥êÚ´öÙ©Ö˜5êi„\®]Ëog\%ŒÇbŠ�ÖBP@PÐÖ°Qê]È91J´U#Qš�‚F%&DÊÚ ”]AÎ�zµ`¸4£åÒf Ĉ½4Jb)ec`ôy%PQ“†Táú[N œ*›ý¹™¸®“})hJ»|Ö4W$±98ÌaP@d@”0ïêÂ\ÖÅAq†¤HP5V[ã*–Jta¼v�J`p�R3žWr,0–»|õ|,¿!Sé³P€%BE�ÈŠî˜5ÔBÿ¶:óY N–,k”µ†¤9È{¬qj$¹Ž®˜‚Ù<Äl¿ê½+ç€GÆ ¸žE ƒÏ^›î�vçY�†².ˆtÿ·1% ÿåÜ'©§4ê’¥IfQL²ù 2—}©à‚qpþ§¤Ú±¦Ÿã½æ( èlÈ\—1‹�Á®yV¤'£s§@á 6WÕó¿­ØØxÌÿæ_7ṉ±ÑàìlxÇöhöš†€©:,RÃúÜ^¬piÒøù'ýPéC0 Ïìn�îgå„ „Øn˵^=;Ãg®Jv@�ËëO?|ÅñÐ|æ×zùä ½¼ƒ6|hc˜ÏñýÅ?¹uŒ_ÿê«øk_xÐs¥ðKþIhHÊ‘E±EUŒ‚*åY r3x$³ áÔ) s"| •L)}cïª~YE’¡Š"'Æ-ÖêÕƒÒ¯ïIJ³ƒ[4ŠÏBd|. ©â)gD’²wD’ãáRYy¾Ê Yšj¹—^:4+#³ÔÜÕ}Ï 0æ(b9¾/L¬ ˜d&¯—›Ð÷ýб²RB+FÇ„Ž�> Ôˆ34ŠÑêp²ò@bmú£”ŽhÄ"I¢D�Èo8Ñ­f”`ã×ãWðÊk/bB„¿¸µƒÏß¼†‰êðÞíMlµÒ_†Y"_:9Å£sÌVv§-¾øúLcÄç®_A_»#ÑþŸ¸²‹G7æøòmÛ�º×gSܘNpÐ÷Ø™Lðíû >xi‘ÏÞ?@ÏŒînã=Û›ø�7ïb•$[ìçn\õæÃ`ƽå«”±3iA¸u¶Àsû‡x׿æMÄíÅû]�†$‹á…Cu0c³i)9½îw=n/W¸:�`#ºß¼¿"qŽìw½;Þ½µ�³)îiVÃ2gÜ:[  ½Fzýöw‘˜q]ù�e <¶1Ããs|CË–0äÙÿ·;wð½3qRlÏ'øOÿÒg�Yj* ÎEkw””q§@q 8#dr Q”ƒ@ÉK=ˆœÍ®sȶªÅ{ ìr7s’TlJ%õ!²èj€ô²qù+úV)/˜œÔ^2$ìSË©áçÑ£$Æ~VP/%FêD¶rÞ,æc¹‡ �”²T˜Î¨²Ë*>Hˆv dlD—H™Å‘jI¹$Á2yHêPpÀô~AƒI²ê)Jèdj±ÑL±ÙÎp¶Xât6AÛFѽTW€Ž…Bq¼ìd/R#¸4UªC©ý¯n`+ê��9 �`€5S€«Â=»”a´–³�$!c€”@J˜L¦“)}ô&Úù%à;¯`ªzßö&^Ô½w–�hÈCX��H„�q< X©ÛàWvG™Ûm‹ÄŒNû¼¹Xº„j‰¤‡Áá1À‡/ïâ¥ãœjfÁG/ï¢KßSGÀ*1ÎRökö¾øÆ$™ÏÀ^¬t©~¥¡l;QËÏùQµU¾cfôÀ4t!,Ž�ÉÐ „šÊ^ɹÃ0¬Z!s @Ó6hÛ9·¢Hß«œ` ½¬J¨I’ÊÎä NŤ1·®è9kµ¢+Ïb# VË‘ÚØ`{{üàÓRÆ�»{xãÍ{aU9�*‚%À2X ³dE'-ÿç„4¬8ààAÂrqˆØLÀ$åsbd ¦…lžAUĽ¤�ŽQmQ°Qñ:]Å*²×V³€^çuÞb—û©À êDY5Åü IDATR™l™®³¦¬18¹\Ëõî2ïa4&=vLå5°æx±atnf‰Z€•@©ª¯á�Àa"™ªf›zåý¦—cFÇ*°Ym=í¡�9•±xo h ]@Œ–é)ç…%NM2)RÝ=1‹®5dôCB×g¤¬Í�£;ZÏ�9äÞ1” ®àã)8 Ž„@ ` P@à 2È8³E8Ûêë¶,Y`9g CòC¬˜D)3«™Ÿêh²ÊÀ eËmZí%ª|žm‹Œ#àQôÓuä¬ð”ÒR廢³ÃçÈhŸMFKFƒ¯µÑ^‘ôðUt)Î:·YñS!W›åQÆ ,û¤rÀœ”^ĶÍq.’´fwsD{³‰c WÙ€—RüƒrÕÈ+B")[8@Uµï}ÆÀB�€”ägXU ™3É 1 ˆO²ßû¾G?$Í, :Wð '/ U–^îX…9%BÔfé!eX/O/7ËJ™dt§Î_dÀ"ì=K`íoÛ˜5ÂbDV;ØJ“0!ÖûƒÅ™‘õ¤€JM°é•gtQ—¦¯ñär2ÐFø6‡,ÅIè‹ Í(xÛ¯¦Ã­]%¦8V‘ÇìËT]üq*ÄÊ‘\®çÞøÄ«ŽuÞÇ`ÇPõݺX1Úú{^ûšQ¦y<ìò‰ª¿¹únýs}W²-¨º~Í=ruÆ×�צðè‘IçïÜR.H¹£êYlýëGóeSÒ©¦Žê&4Õœ:œï—U×¢Õjwp£œaoí³�vÙºHÃHhd¤Ï“.'ûœÕ4¸(x㦤£¯h·¾¦Ý’Ëóe,h7:i‘uSéyQ7G†çµA˜²î²ž[Wþ`ÁNòs€—�>³zÉæÑv0ÊÐ-m&Ðt.´ì ’ Í�ñ8Ömʺ=%…/Â8"˘˜4RêÀØ#iá2èÊZ™3ûÔ¸®-Õk SÖÚÖ6§1h÷-�aª9-ùdrí¨Âµb4–üksíÙ æƒ4Öœ MO‚3yx&€í{ ¥³}�²�þd²Øuu¡ú­îwù M*e 2ç‹ZóÛE‰Î\üX–Aõä2V‰®³ Â…sFJAd J@pjÊ›9‚‚F]¸ð²…E‘ ¥÷AÂ�²DzAo™d>ÜQ‚GUÅã—C°‰“1y”PÒÈ—¡<1iªRåQ GÐ KfÏb+å¡<ºVIÖMq©Ø¾Ï¾o»z=êÎ=¥óJ;#à©§.á¹çö°? 8J ; æ¯gÄŠÞ×û ¼rºÀ“[%ûàÊ´•¸¤åàA×ãʤõë=·„§¶7=Û ¡Úã�HÃÖè8eLbÀSÛRéÇǧؙ´žµðÚég)áCêt°ZËõë¯^»†ÿþµ×¿ü?ý!þê_y?âœ*…Hç>JÞQy› Øg¥së¹@Zæb([3>{»ŽÞƒÊ—€é1¾\ãýèŒÍä±0W*>ìz�]ÁîĈl ÕB°†ÒXu€ðFÉî80²�§ÈÎ,k ‰�>ƒútè2¨cpŸ¥¡qˆ#8CŸ1 mC ÆKÓD«]�\Ä!%Â�"†Ò4/Cbt=aµ–°€e"cˆŒ>=kIía²-�”™h¢¼­ÑgÚIƒ&J4¹¯ Œe Mù—¨‘Ëÿô7ßyþë qsOOg¸Ò€‡çs4xåô w—+|`g7ç3<p„Û )£ñg5Ú¿WPk"gLµôGbÆîíãÉ­MqúøÚ�û˜Åˆ?÷È ¼y¶Àw´ìÏcs\ž´øc-½³J ·NÏps6ÃíÅ—'|éÍ{há#—wĉ €àÏ\ÚÁc›süó×ï€t=ßš{éðìþŽú;­8ÿ,Ëàút‚g.íà÷îì�!àá罂gâd�þG]ïeIˆ/Ÿâ‡G'Øl"nÎg¸u¶ÀŽN@$Y /{ýóËÓ V)쌽U_2ˆ°Ó6øÆÑ1~}oÏ¿û[î“ØžMÑõ¢ã˜Ä’ý'©ÖY£Ð­1¡8B‹Ö­õZɶx1&DÄU}j¤æ³4¢Œ"µ•��4�dQù¤tAP°ZdK*x@ Ò§Dd~¹6;ø„®{»_uo-‹eÉ=�° ÇôI¨�¡#RxCR®1e Éª/¡4!©ëYëì]Rm`%R�4ÔÎuòJ7'˜z«`ƒ–y³ˆÄœHË.¤4€‰ñžðiÑ£ KL›ó6a"z)ëDAú‹d £�Êkàqúdc¨Ædú‘ƒÕH�%võÞË&"©¾¤²%7@êHÈžB5ˆ-¤.™â´D¶Às ØØjqãfÄSOmâ,I¹Ï$�û©VÊA[‰†)¥94¶4€�Z‰ðà€ñ gà¸�v’ptœqxÔb6¿@ze´±/! dM —ô„*ÈcÂmEíÇCª7dOý”ÁRÆ�³¼‘Ái€õÔ˜M¦ØÚÜD×'´m É —R4 @- ¬·¹îh0Ü@MƒvÚˆ¡ü�)È,UZÛ!¶h½‡€•V²ÀÉo*a ²Õ8‰Èð&1TsdëèZ‘ýíë_¢kâì½Dïý–iÈÊïu/fŰBõ&))jYëÙÆd\)¸ýCÐTŽqx:ækµÎƒ:‡Ü–³R$¬ º4Õm0ȳP.ôÙƒÊ*ó 8>-߉êiÎ *QôCé�ÄÐÑdäÔáÆd6‚rƒ´\¬Ù½Á�«�Ñ'Æ Ž‡Ä‰e]e�åR’‘M É@IÁZË̳¹ÍŠÉ<'Š(ˆ~•åþdè»P1¬I¬á²¤¤ÏT€O¡ÖxÇjþË¿Yp‘€¤M¨M`´j¯êö1ªòJEd%ÿLæçr‚má¢/:å’/Í9MŸ«Ç±3Êø�êZ¾™ô|²¨|hfŠmw6qÉD±Må`¯}Wþ1¨!„Æ\™æÌ®0C£éÙûˆAK†RåŒP9š¡¿Ã�9y`­D˜Ô™ ·Ñ“d §,óã½Í”ÎÒgBz@‰|f†$M¿&ð>@¨©Ñô€íu: {!0¡OQ2h!Žë1À%nA5HÃT�ÇœÝÄ2-ԑ㬿”“�-…ãÃ¥ѹÉHãD· ºþ…Y1u|IfP¶}«Ï`ýaø�=€jÁFsĆ[éÉ&c<…J4ª )©žæÜ‹ËFo=­>±¾{Dš½SÛf ¶*°M7Úy~+.·´�±6Žñë¢ß/ò„رë¿ÑÚ»þŽ/ø½Þ•ç4ïêþë×®Çh€b5æ:õ ¸ø¹©úÌÕÖóâ�`ãÒëÖ«W¯S}"•kÙÿes5ÄúJ¦ÖW�ÛØ:r[ïeߎm]a]±~N“jëó«;`t®~[ÿÞvL€@^Æ€ mÖM‘üÞFÃõšT#.Ï}Á±Õƶß%â"TP3¤†!›S@/b[N¼ºÊuÁ(®tùNÎmýU˜A—Ú�È<£zÑ€\'=Ó#!´D’+‹Ä)Ï`Î�œM@‰O×±TTS]Íoý·ø;¤Î«O(d‰­ê¥—ùõ¡–:�°pe–z<�£�\­…þ¦N!&B$]Ó@|ÒT=ÉÈT�´óƒÞQs‚& $J.èˆ5ê.Ò·ÀöÙzií= R>ÌEHbØ&!�Ì1àn5c½:÷iät”:}fIÿ³¨ƒ ¨‡Œ?‰ñÉ�“:Bd0iˆ)Œ°R¢H-ÉCê£4@ÅÐprò7¡'öœEwW¼Â–ØQ ìQr ÛÇÐyU…Æ€d¢Â‚”ž„ÂGÌ1`‘¦°ÛlÝ’ 5›½`ÈãWçE/òcj <ýþ]<÷ÜzfÜZ­ðžétäèsFb}·µV2Èœ]ú�è>Z¦„×K¼W 3¤”† òúÈåRNˆ™q©•ßV)ã�ÅïÞÚÐÚ»À7öà³×¯x_ƒ�¶Á¼×»u3î,–xdcŽ'i„üµ»÷ñáK;øüî.þÁÝ»xeµÂ ?x€_ûÍñ7þú‡t­«ù  êl"ŸÈšáøb±Á#¸ÈèT6Ìh©¾(FÚdÅÐK”œ¬1“Öó¯‚,Še²›Q®âfâøþ¬ÇÛ¸ ¬óÃôCTã“·X¬ÙÔ`N�ê2Ð1Ð1¨gi.– à „¡°\ ^Ž´iÄv¢FN(5;í ˆ¤^w ÈC@?Ý�Ñ'FŸ«ž±è!ïDXfÆj`tIž‡ks?ÍKÙÕÇØŠhCD8 `L˜7 ÚFhpFRþ{‘MAmî_ý½ßÀïã7›ÎñÔÎ&~~÷¾zgÌŒ�^ÞÁãsü³7î‚YÊ|<¾¹�í¶ÅíÅ ÛMƒçŽÐ'Æ“›slMZ|cï>º”ñ�Ým¼ksŽuÿV23þÄõ+ø±Fþ®rÆA'%3.i„ï­³%ž?8Âû¶71 ÷W^>9r'ÂóGX¦„e’^“ Ñt‰«œñýÃc¼{k÷»]ÎøÚ�ûhH¢ýO†| QÀ¹¼ƒ+“‰—%É�Þ“°ÊRã÷‹oÜÀxbcŽxi‘÷lmâÑÍ™gDD"¼wk÷+t ž|ÿðØ�ÿ6ϼ˜…€Ç6çøÑñ)–ЧþÒ£7ñÚr‰ÿ䥗|KþÒ'ŸÂ½&NBé `z¤A!GKÈ×îd±É–1 µçm+ƒHUäÚFªf½1ú’^õÚ¿‚I²d4ˆ¡ÑL:!Ò&Èþ‹|QUØO½üDAöaZ×{ô³&)†`uÌ+�¿–=@�N¦ 4ÚT´�ô @¤(ú[&M¢"ç2KY€D’U)€6û�¤=E¢ñ8¸CÓŒPË Pq$èuyÇ@J¹3èh Ä�y…'˜†%6&¦q@ÌâhC‹” =à R]¤£b©(Ó2Až·–²ErXÔviÙÎZg07º¬ Ì=2V€€{-Ä ¬�tÈd-3µ5kðØ#O¿Š¾.w]p V€kÓ)öV+¬4èèA×£–dË”¼?ÈõÙ{«½‚ïÛÙÂé�ðÆ™8¬§Š½V)ã+·Åù7�³_ë‰�9&1øçí¶ÅGv·ñ•;ú™ñúbé¦x$Â×ï=Àã›sÜêJ³ä¶)t*ó’ô(Îi‘ƒ] u P” Rè>4‡9EÜ½Çøö·Oqë�˜ÎWHðàÁ×êÁÔaµJèV$œeZhxÛ¨nU˜å%`9 �G@¥t'Ok€Êå™tάʒ”œ§`Ò -‹S€:w†ú,¸mtç‚;Fö«Cƒ]­Ë*Û¬�Ôá‘­Ìgp‚üÉË,GdŽRê�%èÁjþg–`ŒÞÎÓÿpq«úšÙ£ò1 hY¨#jv¾VN ’ç%ÕT}MHçÝæ7«ÈR»–$ƒMn¬v#KoÀ�d3¯�1¦lð†ìå62†&»® ŽBȬt†ŠÎŒÿsõÙø—ûë­MŸ½ôz…‡È¿–½ÌûQóC誔È>'Î"s¨¾Œ)ú•VmûÂÖKVÏ'LPì]�I±ò,6§@‚ð-ª¦€Ôv³â`§€6Ã’6µÖÔ�( … =‘r#åõ²U,PëÆÆ´6±ÌlŽöL^6TÊ ]x+R°Ò™&j–VF0~�kß6Ö@B�'fõd�a3åÏî,©‚—¸«&hF ù,Ј–m‰½t7WN ® œ2[²;˜€†­–e§°C¶¬e#­¹Ä¹qÅ;#ˆÔ¥�ÉiLÿU¼¤ñ}[ûˆî×5¬õ¯×Ó=#ö?‚¥j²ÿPÄ ŒÏvýÚ �jW+åW`>aýêõk0îyž2¢ÁòÊ8÷Z§ÿÑÜÔsQhô;·9Ö&x¤€ž™›e,_ŠP Š¡xcW+Q³>Q`%Ëš–ê4'kèËî¨i¨ž[{¹½ ¨j›ªrcƒ®ƒv�Þìb¹bÌå” èê¢=J*¼Í˜PU"XMíÂ…‡ØóT$ÆÜ|Ýiåÿ˜+Ù4fŸË‚¼‰°>wQˆêǪœªlBGJjd­Yok¶Åð)·L¡ÎëÑÿÕ‰•ç¸?Œ÷”)G�,Õ›Ë1µÒó!F‹Ð£,‘Nj`È.S_ñlÝãDJ»®ä@…k5]J@sÄPÁl{€2CRïii¯æø¡j¾1¼y4‹2• ,M“Œ »à…]÷¾e\xiÔ¤"Sà�î«ñ×ô_Óú…¯µõ¬Öì­ŽúéKþéµÕ ÏllŒŽhC@»v–5Î~ýl�G7æþýŠ3Z�?‹Ñ�6އµÌÏíÅÛmi6|oÕá°ë= иgøS7¯É}’Ô ½©Í…ï,–¸»ìðau2 Ìxõt�›³)5Ì?¸³�ÝVÔ•ÿàæMüò«¯þ›¿óøwþú‡Ð¶j²˜ݬÐs¼Õ’˜j]jUëv‘̉” øUÇPu U:@uNÖÛÝyí3ƪˆEÉh .wTeV�¤VBå½np _QZÖ4[©a–¼Ÿ€• ᤔ1t„U—°Z%ICg1@»lP£@ f«‹îJC"ôCB?0º,�†]¢OXŒeb¬Ô€왲·n¬(ßM 9“;¹$ŠFü{14uïªò ìáÛÏþ ü³/þCÀ§gø“óM|þòeHãÍ!1üðøÏìla‘$ à·Þ¸‹í&âó]Ça?à[÷¥Î'¯^ÂÕéßSð�ì¯z\ŸNq:Hù ß¿{‘Ÿ¸²‹>3þP‹~æêe\›Mð[í¿ðÙ«[U=~ÆËǧhˆpu:Å,¾³„ÓaÀÓ;[¸:�à;û‡8šð…Gnà[÷÷q¦)úƒê‘­>ÿa7àÅ£<4Ÿa§mð ëñ�ý#¿øðuüøäÌÂó)Â3`¿ëÐsqL/R—޼‚ô9é¼®ÑÍïßÙÂ�Ù_ÓrCDÂ[¼9,¤|ÑwëNµ�ñ»†_úäSj`Ê=r.t¬d%@W¦ð@{  ô�L€¨4Z$ÈÕ(S•]¤¡�Ø{ïx!Q‰)@be™4 !(NAŽ[x™ôÖ…5’“?võÄ˨ù„1 Ýô¹”;3:`c–Bh@‰fDr0ýÀø"J£E»‘ÊÌZ^S"°ö)ãQCÔÁtˆ¨’þ–Rc §× Òc)É¿YKˆ¥R[8IŸ‘40†ž0 @Bi > ‰Œi0›¶Xö@I(Têy©D¼'Bq"™ž¦üp¤ŸU2¿bÉ#ξ¨˜­Âºµ<�À º*~€mC˜M´‘ñæmáű”¶}Öa£‰Î">}í²ó @JûEóÿ£ãSHcuÙëÇý€ã~A?ûàƒî»ìnã�³%î¨sðxSyòû«_¹³ð®­ Ü[®¼ŒØg¯_ÁQßã�ޱ#^[­Ê˜b³ÛYç¸èí4úlMK=ãW[/Ñ*›šMž�e—ðæíC�2šv „(} ²œ×Nº`Í„õX¹JÆ x£Ò*ú´Zù±^ ã$r$ˆãÛ@$ NŠz&ƒH�Dˆˆ¡�Ài@z õ У�±Î<@BV«ñ„@Eg4MÄd:ÁFº”¥q°ò†%�‚fôQt`K¢[í¹ µ“Ò:™¥ hªŒÆ:Ü8NïÕ{ü*@l¥Òãy-z˜É³à=ˆ‚Qž¿bw²_‹5 3y”� Ô&H§I‚¬QëÁ4$èeNe�­�‰8‚:B9Æ)€G‰²Î”‘S?âæ°y2ðÎÆø½ñ±N‰Æ6AÑï—XJ)f–ÐŽ¬OT’—ÙÁÖ”XKшì”㬄£ÔsO*ã˜%ˆKÊÒ¿™–DfRŠÝ™lÖ¹€éTî"+ëýƒz¯é<šŒvç€ÊêÑš×ó® §•Uã,.9ˆ-Qʲ@‚æ8k €É\RˆÀöQµ¿mŒdŸQl=ÖhÖ#Ñí|*4^°O•;çŒÝ·¶y…¿Yƀͩ*݆i@A^WãíoÓu…€ÉlÚzëFåÄå�žÀÏUæ€:Èô#×<“G²¬ø©É &Ä�¤ì 1•™Y3:Hq�ì�†Ë» šËé¿ï%òàÓ¥ ú™Óšf‰^Yîã|H÷>|©Ä~ÈfWؘ`¸û¿Ò‹ÃÖe�P‘DÅ”dˆµãÍþµg6'µéXz ×õHý9ö°kº«É¤rËê_ûÉŽR­÷­” 7¾ •bS^¼öïÿÿ— vп¾�iNëB¥ºý[üô6?¼Ó‰kãúiΩ'üíÆrÑܽÕy?Å<;¡Û©T˜˜]ë¢a¼Ó#™±ÍÀ¨©© ˽JJ¬\ò¢'zËÛ:á¢â¼ðiÕí7>ß¹a´¶¤ßU Î…ƒzÛ]<È*>K?¿ÝÞê· œ££m7ÿtWQ�+\€âZcržàœÚDѦÎ�Û˜Ž| Mm3@¹û-Ì×­ìò«êÿ•3bí5º«ýe4V£"z„Š+`æ0 ¬t©ôØh)Ó¢¯ëÓ‰×_)xjÀÿwŽðäÖ†_ÿÍå`x¦ÂåéÛmFf!àsׯ€d»m},/ŸâžšÍð£å/½t€_ý{ÏãoýG+ìŸõ�ZS{;Ñ~ (›õÂ.æ™]³ì¬Z¿0¾yñû¢ãÇãÌa…”ÁI3±Œ/„X2ÄÔD!�”EÍÔ×d+Ó�é¾È èWV+ÆjÙcµÒTvD0˜´Ùj�Þ(C²žVKTx2³”êS’”öÄX Yœ ]F—¸Š:’l*PÖ~È"O¬1#3�)a4ÒFõaE¦ÌK´PN Ã0 %q+ ADxáÅgñ�þ¯_3ãRˆøèÆ>vißypˆ»«¹¼ƒGfS|ýÞõnΦøÌµËxþðÌÒ¸Kb€Ú¾:éüèøïÙÚÄvqÐ÷xáð;mƒ?ûð üøäÌ‹~èÒ5T3§iÀÉiÂ{··pÕa§mð›¯ßÁî¤Å§®^B—žS‡Ã3»Û¸:�8Ø~:dl·»“ Ά6›€¯ß}€I xׯm ø÷¤dÐw·ðäæ&¾ø†8 N‡»²‹¥–2Ê^>>CÇmûÜÁº”qyÒâá�^8<Á¾f:|á‘øÆÞ>¬:0¨\„B_¯ž.ðÚÙ ¶Ûû]�çµìÉG¯ì¢!Âÿ~÷~¸0ôÒæ ÿáçe?³6ª*c‰Ì YÙ‚Kԕк:ÈÊh°<<ñMJYs\�Jf‰„T�ƒ¬<…Gti] 0mVÚ»ý'‘jr¬D‚…¨5›U¦eB¶}_ëõÕ;ËØFJµ#°éY*'Áâ,㜥¼F¨‚MPtòó¸ðGÀäb¤“[é%@õÖ– Ršr0‡¥f@(Ð@Šwp")˜Ì)<`2úž1ôŒ¾gô�( ¸&“s,zÂ*Yx#Ë gÍŽÐæ„Ò„`Ê<¡“È2WãaVsrÓAF|·Òñ¬þ®åeº¤Ö Ðb¬[£Ä±û!iYC¸ÁâtÀO~"û÷šÊé‡ç3ô9cOK"wŽÂÿ¥:¢:&n©áÒ¤Å4ù·'-žÙÝÆ7ôxp{¹D]zÒJ�m5 f1ø}7šˆÏ]»‚qgÏsØoL§Ê»lÿÑñ)À`ÚDÜÕ“ÐÄFÍ •KæpYd€F¨>“¯‘LfÑã­ÜK#22ŽŽq|v*«H“ÉM;…€ Ä©ì ðTÖ»–‚î@­SËž¢z<`öÅ Q„§Ì¦‘”sÉ,e‹„.Zæ03†¾ÃÐ/‘û%Bî0‰ Ó&aH†Œ�w IDATÌhâˆêdWó¦AÂ�ÔMŒ˜´SDf0¤ÔcÕ÷‰S07:¿ZêW–A™¹¢íÚî)v_eëD·F0´ž‰I…AC*šLuàè›QŽ*FÐÝ\í³z/Vc¶l¥ñuå_¯ËÜ´À)f,Õn‚&š¼­JrÎÈYú�vÜH7_׿Ëp’vçø¸‚½™­Q$ |¿h,_ã¢ã‡¼wŽ ¬Írµiº÷å VÖŠü¹ {$Ý$¦ Á6ÐÛBÛ²q¡Ã%Â\t}ñ±gPÅ7íÑ„Ö$+`HB—Iß9«“€­w€”aÌ�Ý10v øî–)Ó Çël�IO©ìxB¡Ó‹ÞÙM�l™Öo«Œ€T9ûþoöq”–ì-[Ôô�ò¶ nώѽ<òÛmAð(P§˜lW]JÝ/T²S]¿0Y`¿ëÛ™G¥ËÉwTM‰þQéçNè6È E1ÊQV­V×@Ũ«ï.ú»þÌ&,ô[æŒs/®þ0`ŠÏV„ôú¿�býc¨wM̼ÍyõQÕsœ;ç¢óìÜ‹;wï ‡¯Äì­2†‘8V¦°îc¡spõŒ®íµ‡G¿—ûÙj¾Õ¸âÅõíŒÎô#àúÚk„EÕ|š°ôóíNˆbÎ….*ÏíhTï�{Ù³®½xm5Gsj3Sö¿%MÔ{ì­h£ÄÕE·çÑÙ¥ÜÏV]¡æ¶&¬ëh  ;æ‚™p!8¢¾ú9lD0Ö¡T¶>ã%QŸ2[.t ëeNE‚Dª‹`PWÅM•®äùí: o£õþÄÎL1’×þ¹J»#c´z¿â ¡Š�Ç#™‘©Õ�2K$¤Ñš «µè¿Ú? vï³ç΂zV ‰’a†µ³ÁAì0ZOF5 0"1{TªæYϹ’=dX"år®¢|`À~uEµ£s·e.«DÒè+‘{ƒ¨ÀâÑ—à ¢kYhMªØ‡‚*T"i8íÙ  ôf€*4¶¯HçoDWT?�Åi ÅÁá_U¯Ú]Uq¹µclG3ÞWe ܪ"ö€ó} ¼\åŒI(ýŽû«”GŽ€Æw5§€5W´k� w—+ùÀóGøÄÕK~ýGç3lTcyr³” zãl�'670 ²D_¾}?wã*æÚèø FNƒ'·6°J3ÜÄùÊ+€ÿê¿þ=üÛíìîNËŒ�žZÑø3ÛL®½È9*†T.QÏk×\ã¼cåÑØ’ÐW_u ¿,{Þ_ÆSÜ) ¥Â´ÄR TÙîF—ëIߤŠO1`Î9å CÐ÷ƒôHQ­gœŠÑÛ}JZ¿¶È>iÜ9H5(º”%c`•°ì3úL²ÔšÍ:†$¹ÚoÎk¤•»)ÆA�0O#ÎŒœ¤4 §Aû)6ˆøÉ«?Àÿù÷ÿ.rNxo;Á_ÞÜÁÏ_»ŠËÓ ž;83c9$,RÆ¥i‹ã~ÀfŒøæý}L(â™Ýml5¿¿÷ÌŒ�]ÞÅã›sü¶6n‰ðÌîHï$¼~¶ðÐ|ãûGǸ·Xá}»[¸<™àùý#œ ®N'ø¹Wð݃#dH4ýî¤Åbh‰00ã¸poÕá ÝK}Nøöý´!àOݼ†»«^P'Âg®]ÆFŒxéø `™2^<:Á¥I‹Ã~ÀåI‹þÆ]léÿqØõxéD2>~eMƒ¯«bnL§x9œa™$áë÷à¤0�-¯u~u:Á#ó™žÆ€Ÿ»q_zó–I¶H„?Z.ð[û9á?þÅ�ck>q#Règ$ÕÔ!,†¨Õ †fæg7dE�e•‘ ~`ííw/ÁPgS1èÌ( *v˜µ…G°’ýjŠè¡ãŽ�Hƒ ˆJ‚;# z™8¡QÏÒA˜3ÚK-œÌYþfbpÌZ~²â!µ~c_Y¦�±6¾T}a|ÃX`]‚€Iú"ô¢—gI« ÍH�z „a'¡Ô–wŸ�ž e0"&Mƒùl†­­-œ­€Óå…—Z]x®‘a ï(z¹ÒýÇ@‚M®U TÐÇÍæ â€L’ßµî1¢'0’6…-åg"ˆ´-0Ÿ7hš)†¡ÁÞÝ3¼òš8ë.©|¼½\�h½Ë¬lc†[gK_¾gv·ñÆb‰ûúû*•æ�pØõî¸:�਼ÏÀ»·7Ñ É³z¶Ûצw ¬RÆ÷�DGdY‹ojVÔµÙ1zƒ‡ç3¬Ht˜6 €´‰f¥ÏXÓkwŒ6»&|ñä[×Ù˜ÝÐ!÷†ÄÌsÂ!6� #!À:[Ö®fôátbǘnKjc�t_’Ä´Ö}Ôf™1"$Æ@RV…%Pˆ E 3a¹\áþÞºÕÃêÓ&ãÒf‹Ilp¶b,»„„)KwT¬R^焜äaBƒ&L$;4ˆìDÖý¨•N�‰¹`ºˆé/õlÃï§Xìx�Hw‡£Õü§B˜k½È©³Â›Ü1Pýæ ØÿGÙ›ÇZ’�÷a¿ïœª{ïÛ»ûõ2g8\D‘j$’Z(RÔRJ”Àqq±HJŒÀH FH9NòWì Ž‘À†ÄbþO–DIÌh±"“’ER%‘Ùál½½î÷ú-w«:çËßrNÕ}M�nãö}·nÕ©Sgù¶ß·ÔbU%ëh”k žœ�ª[XQNK�Z��ª­l7 º"2Ÿ„J$cª•Œi°Æ‘éøŠ!ÒG]Vµ:Ê™‡s12ËBt?�Ñ;g•�ªˆ‹”³Dc©c†�2�¶dI5˜L7ã\y²¤‚ªÁ{N9¹Ô Tƒ~ KKFr,šk|U†ú@€Š<ç6]¢‹à+ü9™Á4ؾ&Ä��r®"l00ôÙšµù?€EP%——=Q”@£ágÑm\4BÅi³ò�\T'Ø'#Der;‘¤¾ \¢Ý1ÍÙjXäÛû–*'s•¡ “©?<­m݃ˆ•l¸P}Ï!€*B€t�’D¤\ä/æÊÐ>´_•ˆo·/Ø…�¡8aä¬óŒF çÆà„JfT¹�¨+€$+˜$ŸÅÆZ©C6¶9ù�h û1—ç`ú~ÙóÆádޤ¯žÆÒnÌÙÅ"Ä”_2y›DZóÊÙÙ(KÔ30è­è¶µ¢Ÿ¡|MQN ƒ™BµØF/'¼ÕßßòåpY=,—½ŠP6¼öq7oX\v.itôÛøšq[�»¾bnþ{ÃŒ/T�ËxüÈ�‰Ð¸ B�ÍÀf³_Âl �Ù|ÎËžo|„õ,ÅMkÁšõ»Å>»0P:Xß­EFo[¹µ‚Âõ˜QµCª]9Z›ÅðfŸAǃʧµáce¿Á8Íㆣº�†±"6¸ìøæ˜_~žýÍ—ŸÈõïç5lƒh8>"[ˆ2Z¼ÙlÏ1ªëõ¿š™oÝŠ×ôÜ·æ œ¬{úœqÞ%¿6ðC71ѼÇÌìç>\­ñÖb‰_ÙGÓDüÀþ>^ØÞÆWæsܹs�Ÿÿ…ßÂßû»?V­£wBÜåw�7Ý­­š Õüû²ÏËä’¼yÜ‹Úy¶è�ˆm6c´Ç\tR÷I,Uv=•óÂ;‚jç³}'’=#™Åã^”í@óU"‚9"eF—2Ö}ºï%bÀ›G�Ì}–ô<]Ÿ±î–]Âb�°êIÊ"³F#h¡. Ö1o›Ÿ¬cAI 6�"b”šÌ=r&¤Ô#¥)u’rÜ¿ÿþÁ?úï°^¯üë»ûØ ëÌøòÃGøöý=0}Îxéî&-þ�§oᕳ ¼¢Æ°OÞ<Ä,ŸíįÏxrk†‡«5n̦øµÛ÷±ß6øžÃ«Hœñ¯Ô;÷ob'FÍß/àÚó; ®LZœ÷=b |åDŒr7gSì7 ~çžÔ,øèáì4¿u÷bðû�×ð»•ñ¼ïÑ"`Ä3ô�ONÑgÆó»;ˆ�p{¾Äyßc#þͧoáKÇ„\¤„'¶fhCðbÅV�Xn)à¸ëðÒÝ#/^ÝÇ›ób˜|ñÊäi•23ºœÕ»ORGýòÛ÷ÐçŒkÓ €³œñwß~ÛWâO~üCxï“×�5¥ÐгL×?JAŒüæåÉT@vÙɲ�²ÉÎÈEŠQ�¿…ßQf X±Ý±g!ºô$-Õ‘oP£KÍ»@S'^±É�‰×¯ÃÞ�÷†bPÃa çëíʼn]SCÄ•R‰†9g¨ÌK–éÄ•ç‡T0—âŒcI#í4j@ë‘pÇÈ]V«´$ÏŽ uôÝGÍ\�rD!S@¦¤TR”à&FL'ÛÛÛ8Øïp¾èϰ|õÄA�µ(†«,éC‚�CTø�|g7R‰·^%,pY3µja!h´i 5¨ì0ðDg(ÍS4R”è³­ v÷&Ó]×àÍ7OñöIË3a§ip¡E€ÏïîàšÊË–~Í] p‹D˜Æ€¹„Z�ˆð•=üÑq)FüœÖôèt_-W"„Ïß^,‰ðî�m|s¾À�…È?pãŽVk¯2%Â,–ÅqÞ÷˜WÑŠ³4&¶š œ.Fæ)`ÿ²Œ,:z•î_Êî1+¢CRðdôi ê !õ„öê]ªú q1fïK¹•sþ¬kÊY¾Ò‚˜‰@1 4¡ D›œäBVï^É•ŽÀÈ8?»Àß|©_b½<Çö4`wk†.Eœœ.qz¶ÂÅj�ÅšÑÆ '.Š17I*"të5–‹šÉb3ômA˜8ðž{FêrH�ZšŒ*ñH³¨¾Ô6F“i-UšÍF2;�ÿ¾äsãFz3µ5ª6¤•HDZdåõ3L7×]ÍâÀPœ�Ä5ÏkËA^sV¼•OTpìΘÍÌøF®¼šu´(€¨©Ôq4Ê(üÄÒ¹p.5ãœ0�ÉÉjö„y4� Ù½¸5* å*”TFÑ6ìqm¼õYËÖºŒÙuD^•´•ƳÌÈOžÎG.®”/gA¢£' ò÷§)À@ ¦jVƺÁ¾>”?Ú^bȈ)U%¿ÞÞ%•ßPÞ6yÂ�Äü'½6˜ñ�|ÎÌäT2.¢û(dí”h ToBH„KOƒ:Â… ¼?˜�@æÌx·9_ˆ\]°Ôz›À@ñÒ—ýèà¿­/XÑí²Î,mPr¶/k9û;#'¨÷¾ˆá½€È@ý,ºØä>¨@ŽKr©�A$Etm̆¯ò�”)›³‡’r•EÓ±f�4±ÔÅ>Ýn'©ÁËB£œÿ×@—¿ß"hw½?é5FpƒlH… d- RðÔ•Ò6ªy&¤Ò16ç_¥žµýJå:Ë›aí»…lþƽ†Çëè‡�ó�,Ÿq}ˆÂR7çH7 h¨rþú½¦ˆª¤]¢�æËì]öý²“7ï'G�àÔŸOƒ³íáxð{=fYI�̆·=ê�þº´¶¢©œÇÎ�?µ�Õ£-Ÿ—�w=ÒîeeÔ‚õ�¥ÂdéÊBÈ\î0xã<Ö”u¥i®˜±¾kDß¡:®›”vu=–¼…Ât††hV‚Æ.°ø:®?7–HYcrZ- ¿ü%÷¬]ÿŸGçñf[ƒ¥[Sl%I\GkÓr†Ã†äJMóð¨ÖåÆv‘{ ——îUL£ŒÍˆlŒ �îCƒ¡÷9öù5„–×S°]É@.DLš$ ç›ë*Ã\ú0œ cz¶ÞtWÈùÆ›ážç”�ª—Üã@¿žÝÆlaxòiÞújœ'£J�‚™12.ËV¾Œ•}"í çÆ€�ÁùPS‡1‹rÛP-_{58àÓêZÒ'RfEvŒB=åî0Ü äÓ c(Œ³(ñF#‡|‚Køœå´6Á70ÔÖ wI±Éó\ÅÆäFe×{ ìÌâùCƒó.ã*å)M×ùØ ÕÃïDÀáµ)ž}v¯¿~Ž×—K,r–ÊÕ„× P" zfÌû4øýÕó¹4°œìð®�-ïÉEßc·i°«)‚¾t|Šìzó“®C „©Z˜žÚšáæLW;K?>¤†ÿWÎ/pc:Åžöå+'§hˆð•}}VÂAÕOðsO?�Ÿ~ùeôÌøûÿëïã§~êE|÷w?‰ÂO†œ­ð‡z(yðÉ££µŒ3|Ù1¶[ï'¹5A€+9CY¡¢…£óë%ÌW×¥¦¹ª½\‡½¬yè0¶ÌÏ«h©È�Â;Å{.È;ˆ3B„}ÐÔAÀ�”’û% @"  ”z¬)–Ñe©!°NÀº×w‚*‚™¬l¬–<Ô .9’Õ�k¢,cC¤ �ç!µa$P1ýôøþ—ÿýqqq†ÃØà'wðƒ×¯á‰Ù¿qç>æ}ÂSÛÀG¯xº°zì´×gS\i"^9»Ài×ã;¯ìc»‰ø³ÓsE^a×/±¤¨“Nš¤WT 7’Î KÄš‚/¤…>ƒÖ‹�9Äë:yj¡¤|!'Iy(× £µq_Ö»ÁÜÄ;{«ïdŸ¢¢²—F+fõP`u�’ hEî}~Ø+©hd6,ÕRP~á`šÎeñ-ÎI�Ÿ`üŒQÑXyÝJu= �A�á�6+‹¥}r� dDÊň‚G‰±È@ÝÿŠîpáõÁòÿo8Hs‘‘ísÀGª}C– ßÆÑ¨›èh`ÀêY T¾²RtWŒÉÎã�ÆVc"O ”uÎ|-d¸ÞÀ¶]”.ûÙ�ô™TJjDOö7‹‹ƒ€¶Î‚Ûw…l›,dÎ�6–6oÁ»à€@µ>“Ês¾§ƒŒ‹§“®æÆl—%}ÕxŽ¥a곉3#†À€îñ@T¤G¶žW€€íƒj-ûïº ²G¬¶PÈõ”rÜS·ÕÿËPÁæ*¨…}«±-¹˜°lÛ2CH˜—¥zVƒlˆ£JTT¨pµÉ«/¥eø°ù¢ÑOB½m Û*ß™I C5›²™¥áe·Ýèø%¯K6º“þËžñqmñFK¥{›yÅû9—>ĨIB±Îqñ1Yï“®\ò¦•ò<ײä(,{C�îÙ)˜†‹]6fÖÇRŽêÜ &_É3X ߀xֆ㲄ôÇj‚ ÜÃýB…AQaðÖ^6ÁÔ(µÍÅSxL]e £ ¦ãm0\ËJ‹ +×å�únHŠú¡Òë*Äò<\w¦€V.…P9Àåx—ñÑÇцË_ûØ ¼þú92€— |xG /RÂV•Âg™$ïæD ÷’¼~(гD˜Ñÿ¼—†V|¸ÏŒ·çK|Ûþ®_ûí»ƒ|È–2è¢ëqÜõxf{æ©P>wû>>ýÔMW'šßÕ^/^ÙÑŠÙÓ�\�´È üÞÑC¼peÏÏføË‡‡øŽŽ�ãgÿãŽßûÿþ£’·Ó÷Ç&¹„È]òw}¯çZ> Ñyõï£ÅHzŒÆ÷{Ìù@Y‡9»÷³‘Gñ(F(¡ì€žÚ#¸€[F"å-r`ÖØTIƒP @Cˆ“MO@=�Ñ"sFƒ„€Ä]bt‰±N¬‘ ¢  Hˆèsд!jÜ3£g.…ðÁ‘ÙÀ�L0Lˆ!B<ÖÌ9èïM hۈɤÁ¤�h"!G%щpòà!þÇ¿ÿwðàXŠäþ»{Ø£€I Ü]®p}2Á}^ãú´ÅïÞˆiøØáUdfüÖ½ Híi øUõö¸Zã];¶ÍbÄ7Î/ ÞþOlÏð¹;’:磇W±ß4øíûâýÿÌö ¹vÿòH<ì¨×íNÛ¢ RÐö­ù�ºïÝÝAãþr‰“®ÇV ø±§nâóGÇ8Ó¤/^9@â�tÞu8Z%´-@ÀvŒøµ·ïa¯iðâÕ}¬rÆŸ>câ÷^Åvñ›w�|�¬ÕÀHTÃKwްH “Ìì–ß½»�ëÓ ~_‰+³)^¸²�»ËÖI”Ò7K,R‘aκÿçÃ#¼¦QN‡ûÛø©OTø!cðì0*¢�í‘’¾¢Vö„²“+ñÅw+7`ó>–_­mec•¡@ÖRŒ$ëO]ÙŒô $S¶<ʹ´Ö³Þ¥f�ä¶3`ÀІb #*0ɼ˜pÏA5p²yà�EaÖb?®$ƒ\–BPùÄö>U2™Óﵕæ!E¶IXe` ðÈ+Fê€ÜgdßIq?Ò…¶ç5�2z »^jŒt”‘ЃIЋH„iÛ m£‚}’JE(´™ �´\è=«�T³–‰Q9¾)ŸwG53Q. °ÒPÜPe@ƒ ÜH ËœÀ9¡iLfSÄFÖÏé髇ç¸ÿHŒéû!b‡‚G ¼kgËSþ¢}óbŽµîŸ“u¿‘2è‘‚‡Ó ¬Ö|øÊ>î-W^w`»i° 0p‘’ÓŸ ²Ù><ñ~03Þœ ñìöžßÛqÑ1ãÁj�½&âëçKïÏŽR÷©Û7^5ÿ¬äJÓýª"¦DYÁr�\)›3 ¦Ô»!‹ÙÒ’HùYã»D¥hz°HݲBJ—FÝ&0�×ÈȈq ŒF÷ ‡NØ'䜀�ĸ¯Ø|¾ÆÑý‡hBN ;[S\»²�¶�LH]Æj±Æb¾–gÔ+ R{a§ŒÔ¯ÁLˆ¡Å´ÝV±5ƒrBà¤i(ÌK[Œoæ};�?Ø4…¢˜>gé*ˆÔë„F=º¥¶�ÐÇ¢7÷h¾dÆ‹�Æ?n¬Œú§ v ÇÃ8Ô>!óë|CŸ=à k2¦VjW¼Ž¢R IM' Q¤€†Dæ¢ÆJ×@¢.&B¦¤æ•¿(ªÜ£Ÿkúªë-+Â@}F&© �SÚ7S/™IbÝHŒzb ,áBgk ÁŒ©Bo%J øú¥¸;¯$N IDAT™1±Öáê‚Ëð”Epƒ2¸˜„lþ¹X)­e5ψ>e¸rä€ÈT¥ÒÑÉ�ˆ¼ õÌÉÙDf�”7ÛPÝ_•…£„Z½aUÄëhÜGKÑÀCPé[9ÇŒîªÈß G7=‡$ý”N&JÌ´f)“E†&©ãã¶®ú™ 0 ;«ºFmvĶ6l½èg5çÃF‹ŒdÑY�åI+ÓÇ OKeQÂ꺳¹D0°Óe;( Bíð:¦º¶çÌ¥@�Ö  ©Äu޹òÐ4�Ü�.Ùä¢\øˆ­e#ud¨û—iC#+Ú Ã׊CêŽçb:©Èî@,Qå–{W>Kƒß ÕÌ— �âñ[r%V}ä2;ƒiEýØNlkTM/ªSõ¸‘=£úÆíi f´Dyê9 FU]YÈ zÀOðŽ×†·ºhsE:T£´æl×Á¾K[vhÄÛeõŒâ!確Ÿ—Œçx`ÕzÙè&_zÜÉ‘�çã^õÜ—™ý�Í-ZQ»XmÀz_�þæ†Oê¨_Œ9î[‘‰zÍ—ôÕ­ô£Klý Uåd§d½¹zé•u©§@"�3¶ê¾Qу՘O‰�žÔàÏpXæ$5èº. ‚´ÁIÎÏ9�è qgs>ªh/JÞ:[û$†£ .“±$ª§ÀI°®çÇ.Me"ü‡�;¿R˜!ϘƒìY£¥ŸÅXYÝßæ€ÝÔ?œ%ôFzœÿè¤Û¶3P xÚƒÒ7O1U¯µÑÛ¶³ëC°µÆºµ àI@àl£YÉjûø�u\‘±Ò);é[mâšH�öí¸�êõÑ�ÞÀ?ûg¯þ¬Ú‘Ñ\s aªŠæ[óÅ ñýåmƒíF®ÙŽÍàú6�ƒw—+\Õ‡ðæ|‰ž³1 ×YC„Ïuó§]�/‹wîܸ†í&â˽¤ËÊ9£gÆ“³¾y1G øð[!àùÝmLBÀoÞ=á“7®a#~í¶m‹¯îãwÔ³7áÕó9vš¨©ÀZ|áÁ –)á;®ìc+F|åä‹”pu"5 ^º{Ög¸1›ºñ1á´ëpg¹ÄõÙ}bÜ]®qg±B>vx_?;ÇÑRŒ‰/ìaž²}”b©Vküò[wAÞ½»�G믨÷ó‡¯ìc·‰øýù¿¢ušð×âû1kô)•üÈõö0å�MÞÕ•¬ü¢‚Y¯´Æ‹Q.¨»�ˆvâRK&ßQ‰d©å¹»ÁöT „˜ 1*ËW|Àò%Û†p¾D©®-|f³¬–óó§Ó%ÎâJUŒTÆ�Ä r/û¨[¡_/šF½Ýˆ;Oî@HꥭõH wµ˜¢£B~¯¬éw Uãš‚¢O'•NL®äCÉ>¦µÌO~Ý/(:ßX¾riˆ74iÁd=ÛëJ¦àjUt�ÔÀ)i^RQ@îõNÔˆÊÈšÈÈ€pÈ�´f�Ñ#®ä}“† )b°ƒHÖ&¹Œ›­i`t ’8(�YüÔì �.`hêÑ9ÙfB‡Öi>†…ôS%ûZ·2éíusVØ�›vA`•÷Ô¹£äG—WPYPêÿn­ó­dÛÓGyØû¨£X`�Lp‰»¢ €ý®o{h ŸßÖô}б,6·²‹L ”È@rZh/›_�D¡cAíšDäñ¶îÍ©�m>|OÔöSòµ#íE©KPÏq.ÆüÚžPîcÇ�'¢ª¨z>H�àí_g¥/¨R©i†Ë¹¦ëÛn.6òc5p•üÞÕPÖJŸ—úEJÃm[ ÒB»¸ìk6™EçÓæ…0h×fÜvº«þTWyT×ÎFÏt¬ê¨ÑÄ [¬Í¿ÈÅ'ô"Ÿböy°8ª¿(OfÝãõÆÖ{5@F:R�…!a¶‡(¿�‡Ÿ/9vÉkãÒª³~+.U=ááõ—tsÜÖ;.»î¼È'þò_� aÈÌwo<ë° ¸pBZtC7³-�Ѷ1>6zŠÚpQ)ÜÆÀ€à¡³†~K¤¯Ç6U÷Ñ>3Üñ@ØÂ ëȃ„KÈyŸ(×#Ú~‘<0xøKˆ¶¥1ð0D‚3FÙ`y{á(¶ûy'†»ÿòÅ·1<ø>ZÏ—œÿ¸v.}eR„¹Èàõ˜|‹õàÛ–ªïdÜbxù`šm©jvL#ì·êþÆ*ÆÎÕqW·Õè"C‰8P rEBÁ@wu©/–g�µç¶~(�ÔC=â² ûTÖk†r@X¨ ¨?åîŃ.uÙ‹õô}.U§bÆÊÁÁ*ØàÂõÜ2|½Ê”†ônL›Ø…ŠË¸\aº…!YOΪ€T &UÌÈž¡õêuÀƒ>T4ÑÂùl]ØS’̺…‚KžAyvO2bØÃ×��9°üj(±Ú 5�²víûm‹ß¼÷}θµ5Å÷^Å<8AfÆÃÕ;mƒ…æøžád½Æë=¾mo àíù·—�ðìö>óÔM¼zv�oª7î?q]ÊødlOؚ֞áxµÆ$>{û§<·³�Ó¾÷TGŸ¼yðÛ ¬sÆ[3LbÀ"%ì¶_<~‚<ï,¼tWžãƒ{Øo÷~rkŠï¿u Ÿ½}ëĘ„€ó®÷¥‰ða•3®´-®Ï&^Ôx+üÈ7ðÒÝ#Ì{1=¹5CŸ3ŽÕØyg¹Â“»[ø{·K]�çãß�g®í£ëÅËVrà¨rþ¶¬È¥M ´MT%[®Kœ¤F�n)€BÔˆ3бóˤ…° Ü.Fªa��‘Ø£SRÌHÍ"ÙŸ‘%Ú6F …&dÔS@�3 •Mƒ€ÈMØ!‰'ebà±9é—ím�R@l”)æàŽ9”Iù`‹A¢,û áf``+,Rö §··p²î<’`¯mІà©ÀÖ9ãëgç¨_ª Â�Ö²H‚'¶fxïî6þ…¦30 vyéÎ}dÛM”û(ˆpuÒâÅ«xI#€_ÙÃ$¬Ò“q¯“ûÌšFd,“Í=X>½Ê*+o .Ê¢èìÞǶü¤I‘ÜË“UF×s(Foƒ—]u•>ÂkTBí­J ɪjéM#irB¿^¡ï°\�µÖŽ$Ú ¥ƒHH9aµî�œÐ5 “¦G¿ѶÛhÛ-lïìcg{§§¶¶W˜m-1�vX¬©ÏÈ�4R€ô�C€)9-±Zí¤E3mCð 9µ7OÌd»ÞšTEìP9™/¶là€� ¨R¥Ì(›¼wé‘d£rKqª¶ ¤j¬ †i'ŽJ—¬5öÿt-‘H4¹ÒCÜ$ák¨˜%õ�DnÎ¥’Z#Ø=¨¨–(:§93r–z)„€À�6=¹ˆ’ñ”9R½‚XF6~`ÐҶ몿f£Ej¨-)ƒ€DJuÔÈ©Hè©Þ3ÃcJí¦ Àý MÅ´=YÙ)uLʦ´½aŸ¥Þ›ŽdÅÇ=í£8 >7DÒ‡¨ÑyÁƒ�Ÿ�/†�á—”d�²«<¢í:ÓU,]�CW7'Ü8\rá� Ô¶õB{¦¨@}‘_~×Ô\�rP£ª®_ž‚GånÛ ÞFÕŸ¢� Q ûÖÀvmºpÞ–Ëþ]ÜöUዹމAžÃÖOf�0Õ�$fOdº¨EžQe]çl^ Ê_­.†ó^ÐÀaÄVT`–4ÎΖëñ#k¤?ÚOgC‡°¥?’ñÐpCÚ0Ză[Š4j,Oi1<­1éž©e’á,úwŸƒœ«ÔpE&•:9E¶„äÙAŠ�DZu2Š\5´ÑªH¹РšHˆÁØúwª¾ðÆ ãÇÛ\Þ£_}³èàÃçJzT×y/ëã_°—žÄƒ�Ç5V˜Þx<ÆgÆ6l¢žØá±Çµ)Þ€€¹©¸Ò^u¸.´;~ ebõóÖ(•†º)9/LÏ#‚zÑŽÀ·êra³r®<Š ‡³=—¾ÕMg0fFœ7ŒÒÕYÄÞ’ðNí¯E €¸º•ª±¡œv¾•Þ7³ÆŸÕx—õ1~�÷ÎãÖÎø¥sÍå«ýá4Â8™�¥�¢×ÖFè:ÕF—¨šÀì�Ç(ceLÏ×õpâÊ}j°�K;ØØ!TýV½ÙB‰­-óPÐ~*ùsíò‘s�wÓÖ¡§þÐë[$­ еÍT\襠;`ä`õ‚ë;ýÌV Ê8ë›í_OÄW y¯Ê�³ ·ŸG¶–­/N¸ØW‚¼YebejaƒGÞbFÖÛ#¤�+6#I ¦ ¤5L¸�JÏ5eSçl@‚6€™jnÉf¢ü?|q™ËKùìøÜòñÑ�`àÏ ,Sz÷“r¬_ ô9£ Á õÇë‘ÈëtÌ8S`Àç»°ÞÝRPá¬ï1ïn)¨Ð1ã GÇø5ìÀá´-‚Ä#�ÔE§]�k“;mƒyŸðùÇøÄ�kÞ·—Ï.ð•=heM¼gg[¼ÄCÀ/ã÷ÏÏq|¼ÄÏýÜgñüãÙÒîT£.ËHD8)`5”_|Õ>?kþË Gµ}®Ž¡Z›<[‚žª+œ]ëžÓõÇFM^0�ÒÚ"nÕŽÔŽúÄ(G¤‹êZ¥´AÃzËÖ­Œ/ʃL©@ÎHYhŸ¤ÚçsDÀÏÀµç6oB Aï™ ;Ö0�ñ6&mÀ´�˜´m xøèÿéßúy¼~ûmlQÀ ³-|`gÄbûÜ�#¼kg ïÝÛÆ"e/œû£·®#rãû¼O¸1›â mðpÝáJÛâ«'gØŸ4˜Ämì· >ûö=dßwxW'-~åö=03>°¿‹oÛßuãû£¾Ç£u'Fm"L'øêÉ}‹WöÑD1ä÷9ãút‚{ê&¾ðà«”q{¾Äw]ÙG7—A D8Z­±L ÏîlaÞ'œ¬;|íônΤ0ñƒÕÚó�ÿà­C-×nô[¤äŠ*3ã¬KøìÛ÷�˜ñ¬FüX‘Óï9¼ {ʠݶÁ³;[xí|ŽžËÌÖe1\G ø½ûÁq0i1‹ÿÍo`®N/ŒçÀö›Fs»1`dÓÒ}M:pFn.¿Ù²«�qW�×¶7O~ï‡õÕúÀÅáGÚ _‹bò0ýÐÖºŒ�¦Íà̰jÝ¥:¦VDõ£l˜&M^I} snì’Èë—¶ @‰~)}ÎZW3 èýüÆõÅç†ÐÃülm2»N‚*e�®“B¿ä¯b¶Ñ[ÊÂ`ÚEá¡ÄÁ7Ÿ µeK©51£È¡¼5£ƒ€ñ‚â_¬ëÞS)ƒA9@@>” ôy,úŽÉbl™…ùÚñe¦{ Hâ�ˆ ObOf41ÚýŒgPµŽ#d€8¹{Hc °ébçÌR‡¦Ã0PÍtP§ÉêÑ}9”Iô^ÖêaÙ5pþ P‡û@)¡㱑ãÒ×;9§>UzEÕB3’ï ÄžÊv½³ëQu¸6xŽ©”·qÉ³Ðø[Ú~Q¹×;z°Ç�WÿV·;¾F‰Â˜Ø~¯»LÕß…©âfŸï¤ÿչΤsµ¦´ßº.<�ÓpCÚs9w¬¨�R"J’P€ Z¥B7 ÷ose—�X^ÅÅ8|µa=y»%%‰ ‚ž£™ #†ç#àx^.ÖK�Öëí�¾ÆûÒ¨�þm^¹>ßþ ¨,¿CaÌ9.|>*{¯ÌS SÈïGð¼µ¶œû¬&SÕ=FÏD•h¨¨]îH=ù„hŸD±3OUŸÇ¨„.� I©1;�9ÙÉSc>÷ìÀ÷�œó°¨ƒ �5$ @S¹gäžÑwY@�ž=mARO:{¤zÌ£*€ð1&ö�v–ääѧÐè�2P#§¯úìó#ÿ›‡éÚ·h�l\�u=·(SË(‚¹1¤Lèƒg.«Å¶5{KÆ’Ê3E5Œ5úä?‡ Õû^ö‰gF°)ÔÆ�/_²¨X‘sõPÑ#\ÎsFcý­_ï„6È9‡‡<ÿü^}õ o¬VÈ—Ü׎œvý ØðɺõéÔmCW&í`('!à 5ôßY¬pk6ñ¹ÿÆÙ®LZ\ŸNüÜK¿[".z©wpKk¼®^�Ïj¤ÀY×áµ³9® è°ÕD|p‘È…²OÞ”¶Ž–+œt=Þ·'‘G«5þÚõø£ù«œñOþÉWðWÿƒð£ŸzVö¤�¥ÎµšÚ,µÐãçê/úósã[Ï䆨‚d Z!‘•L–&˜‚£ûÚ”$¨r Æ’´@øÒêoñn¤PB”Ž‘Ò4¡Iëd£›,i$�±"‰ñ4f” .@=}”^gyü…!YЉ܉à¬2i°B ÁBÕƒÓ!—&0šÈh#ÐFBåØéÙ ~ö¿þ/ñªF“üÄÎÞÝNpÐ4xáÊ>þèä}�Û‹%Þ¿·ƒ¼Zƒˆ°ÎSÂÃùß¶¿‡uN¸H ¿üÖ]<¹5ÃO<} òè ¯œ_€ükOÞÀ¼Ož÷{�3u®MZœ®;4!ॻG¸>�àû»Ÿ?:øô“7�˜ñ¹;â�{ž>°³…Y8Ï-þìôû“Ë”qeÚâ×î!1ã…+8˜4^8ôÙ�m|üÆ5ü–~´î1‰[1ø¬ùøK-8~8�à�‹zfì· ¾çð*þðø‘§*y×ÎîÌKîð;Ë%úÌ^4ïÎb‰7ç D"|ð`¯_,<=Ñ'o^ÃU‡?y$ušðÜÎþç;wðêRÚ¼²»…ï/ ë:5DÉjЏÅₛˆ&61�³(ù)Éñ –â ¤ü¶R Íè»îµ`¶ñ9]¯Â.¨ÔàÎðâÃÌ@ŽEÔe]üæ4SG‹É¾5Åw-ŠA öA7¢à^í D+ÏV“¶f*ž°u¾ v 50$Öý¤ò·;ü:šàžD@&‡$ €ú,ÿs�ÚH)#÷„ܬWŒõj t�äSO9#s�\×”‘‘!`@)P�K€%‹lH(KKô‹ád6�àÊþ>2P3Ãé¼Ã|•±êÍÀ¡^éæUn2’ÑÍûÎYŒó™Ü‹RGѾ“žg–2“µ `ÓsjZÊæ¤b�¤#²¼Ê$yòs@ß÷^3àIM%d†zK´TðlÞ½³íà˜quÒº¡¾x|:ˆ°H�YŒxng«\ àû®_Åc® ÂÉj�E6ÏyàÕs‰jCÀS[S¼>_âÕó9À�>q_}tæ÷~jkŠÏ�ŸyÛÛ“L¼$HºÙ\ S¡Û¹Lex‹á`ÎiEŽä •íC‘/Q¸¬«x&W믒>ÂeÍbåÒ}XP›R³iP_ViD�yt[¥ìE³Ü&7â)¡‘½…ˆ9´X¥g‹Œ»Î19íqÿÁ9NΖX¬2z–ó⤒h!dd$ˆ¾¬<1'H”T�¾èûˆvÚ`w 2V/�ó )ÍCë9¹Éõ)–6«i¿Ë€©îP�™‹Á£s‡óé³­ÑÑЗ6:Îl´ß  Ë%)óV¶qÌ­®+I¼Þ‚¥ˆ“.*D mTQjÝÿ©ÏÈ/Q;.¨ž]›)LÞÉ9£‡D´ˆZ‘uÌ̇¿€È,i•î�‚ЉÐÀ¼©9«Ý%Éø ­,SMMMÚfñÉT`%êÉDA73P×+Ð Ñ9*´ÍÐçns^¼H®#je~½]狆IÓr†²ÓMPY×$a9Í¢œŠŽïÆ]ßÿ²†BaÈö.«¡–6㌾xM6`€ª¹«À&¢Á;(ý¯M58ðÆr£� ßàú¶Ùuð ˜Ým˜2¹~É}zBç™ÈÖ³šäÔI1ÛºÑ5QO´ï%*ª®Fdø<«ü †qÑ ì˜ð–‰R`L‰ƒ�ž`‰˜ÔÍÈ^°ØSr•Ö¼dŠz-�¿xû;xXÑ7í'Ê;ŽÒ“lQP°ÍBÓ]¤«ø™¼H%Íe13ËÊaô IDATôβ¯» °]ö‚DXC×B°¬-0™ˆ¾w%Ú"Ô„˜ ²] P$­Éc7«lav¬B)ò™/üÙ×™AzÂùFë¯þÂÕ5ƒ��%+ãW¼-hLp*Âä!|êo§’ÿ7’\P¨fÙÎm|§ 5¯Ù„Ý6žëÒ=è?ðàÔq¥¡ñf¦ê¸yrW-‘ÍÕ_«ûØs ™u¹ù%ÏÅ�ùJº!.3Œ’ À,ZñœÑ £f͵Κ“îQm…c�Ù*BG&øB=èÛhØ|#Œ©ŠG°z91å ý#ŒáSñŽÒv9pÙJˆ™e#INÛz.7Çã–ËÀ0ú-^›¿ŽîÅ£cBËoþ{åE;Gˆ“/�ls •¸t2ÙôøòômQwçP 6Ã!C.ØÚª7Y-hÿŸüÊXÍèÞ!�æŠm‘{Ʊæû“pfû]ÀRP€àò·&�PÖ´²¼s‚+á ©g¤>!8� (ar2®5 4#¾­»z~Ë_&ô ,“htÒ3ÊÙoìí×ÞÊ5öâSi9rmÞ´ c”ã—»B�ï<ømÀxë~êcšw†õÇû[Ò D�K�Gúø6d²BÓȤÊÝ•£‚>¸1ÈŠöš‰Öïeí:?±kÃÐërt®9ÃãŒÅ´qÔy¤¸ŒVÈÜ|ï÷ÜÀ«¯ž!øÊžwo )¼Wå0®A¸®Þþ]f¬sÂŽžËÌøÓÓs|ð`ÏÏ�Æ0˜w3Ì3€uʘƀéD$Ü?:9Å {~þ+gx×î®´’âàÖlоJwu2ÁÕà ˜o,–xj6õȃ߻ÿÏìl{Š¢3&¡ôãp:ÁvŒø«7nàÞ½ ø™ŸýçøÂïþ5\Ù�øš$B•¶˜Ë< öÂHðX†>’]'¡žÿá‘ñ.âÑ_c~Ç�$-ˆ†�в“«óEØdоÖÉ÷¢®'.TÕY 44$ù’ à$ÂÕ¨¯)A¼êŠqž�‚²öh´ÚÞVL=«@[¼Éˆ$Ÿ:ˆ$W3HâIõ¬ Ä N.À”ü퀶!LQì[ág~þ¿Â˯°#>²¿‡‡‹¶cƒo^̱Û4Z8·Å¯ß¾‡.3>qãÚ¿úö=ôÌxÏî>|e¿«žï�º‹>a¿�˜†€Ã鯜Íq‘z|ð`“¼v1ÇÃÕOnMñãOß—Žá¬ëÑgƧŸ¼�ãu‡¯�Éó?Xw¸èz¼{w§]‡yŸðKoÝÅ»w¶ð]×öñö|‰¯�žƒ|æ©›x°Zãµ3I}”˜1!Â^ÛHúÎø�{pc:ÁNÓ`+F¼tGj|äÚ4(,úžÝ¼5_,ÆþW/æ˜FÂ,ìOZ|þè!ºÌxbkŠƒ¶uãâ­­¾÷ð ~åí{Køøá´ÅÑjíiO¾zr†eÎ˜Ä GßãwNÏðK%•I ¿ÿƒ/¢�}Ÿ4¤?€`,JTJKQÀ†ñtÄШl—ƒ(ï¤f-Èh²ƒÐÎu—±êx €3,·¬)w)M†ä”Ž„F×2GR~ Föè<‚]” dÅïàû§¤4‹Ea´o€¥º1ñ «<,ª˜E x¾Ë¸nxȲ£òîØ0BR*ÁYö}F�¨†\‹ˆ³º9‹÷_ê�ÔROè{Æz ¬VŒÕZÞë5$��Ê:ÉÆ\yt&+Û$ÇE(à@f ËCU‹DžxÒ6ØßÛÇ ¨™!´KðéyÙKÊFU¸Ù¼V]Åf%5UUê‘Y=÷¢X[:•ÍHA äp{+Ác3|”´QbÇŠˆ:‹$kã DÜãŒ÷Ä�A@V)ãëU$¸=±5ÅE—<ýÞÍÙ;mƒWõüÌŒGݰf�ÞÓ´?÷5Ràp:Ás»ÛøWDÞ½»ƒ{Ë5IRƒ}õÑ)NÖ="š@¸¿\ã+ó¹·½;k‡¯´¤yü—*ß+‘Éä«¢Îpõ©[,p-ç{)9 2³œ®so€ifü7#§Í ýFï_ÀøjªUVålÄÁ›’)Ù¬Lã.õ¹3dŠ`Šè¹Å²oðè"ƒÃ9š°Ä£“9N/:,; ±ø¥IÄÛ\èYЗd}Ò™W!`:kqpu×v�1ÃÉIÆrµc…\×\Q^,ôE7^Púâz|‰Ï�9ª·¨öæ¶P{µ–-QliJW+™}îJ(Á%rqQ—,åê&zåÕÙ1 {D€¤‚Óz1Qh| MCh¬¸s–šp¹W£¬‚“ÄꌕU¸Š ÒGÌœ¥f †^ãQA`�Köôu–&=Ãè·€&Ä‘:¸ä$©ò¼žSfHjö@÷!0`¦ª@¡Oæ}ížÝì1:>=C݃Çb­¯!“>ÅìBõYfÌ'#…7:Ðß­ø®Ø/kp¨,<ÏÖêiŽ&EÖe›+M†G·Ý·|7Ç@‡´çOH:g¡dïzª. Šc]mŠ)>'.À€ƒ?Y§a[äÀÉxRt³ò0RÍXÇ®NAåõ (BéKy>¨ªKåÀ(é�Dþ2Œ¥3-ccÄ@¢Ê Œ‘;m( Y´èq‚§R’s,²A„î…Ô’Ê-Æs”¦èœÛuärXQß”ta¶°m]—Zzëb¯ï-íB �!DR™"˜\|î­†Tåî©ô#ƒ³ð1Oê©§Záél‡§9…‰Œ(U®mŸ„2Ú@e%àêVe@à€Q'Ö5[øó^£¥æƒI.Œ•S a‚.Ô’o®nÏ©LõyÙo(Ÿc¥cÐ=SžG÷r..¹°47ÞLeŒê7FgÓèoà��gÝŽ­ôËzÁ—«^:62Õrîpv7`–bŸbña(æ[*ÒcÄ™ @ ¡Í¨¼°Q "ªñè¹*â_QÖÁü qHÅ;¼šÙ(º>ê¥"n=Þ4åˆ�d†e3˜W^Æuêù³ßSâ” W­®á�óÝF Àã[­ûÕ˜ùP±8´ª¸]?ÍO¥“Ç㯿ë9\m)ÏL,FøMž¢)lÔ”‹°Q V0Z±Ýrš1ÙêÊšh=lØ€ùÐWDSáàâ¦ÖË›;öhî ”N¤QÍDzE*(ÇVo:eb‰�ÔA}�‚Ìk,§0ÅRàÍ…n€5üLý”¡ÈzH\�]iÃÆµlý®‚yQ¤†Qƒ…VnÒùjÊ”ñZNóRèÏúà=¨úQæÑ޹¢¦ ³ôk´¸*u�1-mÝUIþªýÎCº? Ŷgiø»w×”×ÊX5~ p)_íóoE‡×ÐhÔÿü×§~èIüßÿôÀ ÀA�¤Æ?{=М質^M=îDä €ˆ0’kî¯Öhˆüû¼Oxs¾Pohy½{g{"|øê>`™ÖY<”§Ar*þè!~èÖu}zÂÑr�k“»Ú·ï¼z€Y È̸èžÖ¨ƒž¿tŒ¯`»‰ø+7nàÿ}ô¯,—xã�Süç?÷ëøÇÿÛ¿UžÊ窰¹¬å>¬ú^2Yý‰sÄÑ­2Ö¹A—¥,wbIÁ—��X �„ˆIœc¤þC€¼W¯íàù÷â¹÷<ƒgŸçs—¾øÞzk�”3˜Ì@8TS½–C6½ý3/0*º”� ‘'Ç[¹¾ôYuìgh£ëÞ¯~�Þßæ­:{óeÞźLïÓý�³‚»ÍÕ¡�À¤!´mD£Æ»&2šF�”>vë,5Ö{ÑëÊ6#_+Lä~cÙŒ°Y€Íœõ™Lup`@Ã.+€š w)ƒC(A5:"Ö~ÊŒ.et)¡ë³û@íX ¹×‘ÎVx8U‘rº Ô8lV1PϪÑѲgäYŠ®.?—½Å™‹2ŠLë*¢.>Ëÿ_Ⱦ®• T±(ör&û"6²[­6_ܦÖÙ!'K†ýs²€ª¿®J� T®­ôCyÖbÃôhÆ,´-BŒÈÁä 3Þk¹ßÖ†é¹ °Ï£¥rÝ—hÐÏ‘(¯£ B�§#Ó1°TSÉ"N¸÷åjÚ1“Ȭ”&`† 5F HP?¡êêöhòˆóTÙ@fÓØ\³\�:õŒU”[í([ÐØáËiC=îJ&ê9±sÜQ¹´ ò 6ÛX‘¯¹`‘ÎAø¾ƒK¾FLrc_ß%a�E�ZíF‘] @cm‡¬¢P$ !M©oÿMK£Y¿õ¼¡ CÞÍ�äÖ“Y¯Ž2®~¼X܆—Œ(¹{ë Ω €µAe´÷�q›BRØuu3®®¯7É0�{Šp^ÝÆãnâr„Y½ap"�Î4ÃVaqC–WŽÁ¯Þý’N�úsƒ^ƃ;øi—°×Átƒ¸ö¸©,÷bÍPšÔçROß, ¸Ï0‹(e˜-uÍÀ†6¦RõŽ Yv$œH›kUÉ—ª×©rV&Œa)q̃ʥ&ô»¯› Æ$ÖOùÍ#*Ã>�ך?ÏðÙ332˜†Z06DÊi}ˆ¸4Ï:Ö@1ôª� Ù²È 6Ç–“·Ie¬TÑ-Ü^ˆæà˜ŽµGD躀G(¿“þáf+î.mC‰Ú 88 Ëc¼Ù›R.ä :®ÀºÜ˺¤¬Ä\Ç,±í d*` %I#”4onŸ Næô“ ú]ökèÚã ©7³FXåJˆ«ÖŠÑü²½® ‡ai=ü~:6ÂuÔ{Å(>X£vŸl 0@8’sS¥ úÏ.ª¼+JŸ¹êjÆ=±qaU2 Kk¨NÕb¨>C¡eÁ”ýËõ¹ wAgÌò”‰$0=% a«)syºrÞc¹Ïã›Ö×�üðSþ÷^\lÔX¦Œ�¦|?œ–ÂÀíÈÝåÊëÀ7Ï.ðÔΦj¨ßkÔ všè Ài×c¯m°§‘ _?=^¤Œ‡ëµG.Ìácš>¨ÏâÕõ­;ðæ|‰H’Ç^¿˜ãµ‹>uóÐï}e:Á4HoZ"ü»ޅŸyùe¬™ñýÓ¯â'~ü}ø+?ù¡Š>ƒâx6†c–a«‰øÊÉ)žÙžá¼KØjüúÛ÷ˆð}7®¢¡à)ƒ¬fÁ¯½}€DÝ^,ñÄÖ']‡Ý¦Áoß{€ Æûö·)àåÓ $f<µ5ÃG¯øµVk|ÇÁÎÖb¨ Dxc.ÄÕÉ=g|ó|Ž×ÎçØo¼o_?»À] >yó¯ÏøºF¬sBU­wKÜÝšâß~Ëë ¼ÿ©øÄ‡žGÎC^'"[%OÁs2›âªk9Û>ÎÂ_M!3ã•…à—ùì2‘ö^÷ÀÚ#þ㻦5L[r¹ª²îŠ´ð0D Ì�(U2àé)�ÝØ"ÃIªëw¸2^È.&†7qV¼`E!—=*À€ ³î14ˆc~5¤Þd2v伸@Ž)}P ëÅÕgB—ëDXg`ÅAÄ(:Ö™Ñ%UöÁ.Jš/¹EHîôâ'±¤Þ…’ò-³¤„jÛ ¶c`•¦ç+4‹1%1À’ ÅàUždèÉÎ`À<•“F ϶ßÔÛD —ùVóÁß$…¯9C)Â2 xWSøðµ©<Û›óè­+À¾t,õ>"‰±ð¡õwIÓ÷Šr àù½|ñá‰÷÷å³ ¿/~î,FÜœMñúÅË$ùÎüÉ›ø�{=a»i~¯œ_ 3ðüÁ.δÍ�I£j�M¬ñ“¡ì]}/#Yñ­ ú»Ø)¢¡  ï{0'X|y^MÆ€K›öfºzä&×NI—¾LÀ€ÅûR o!´±A;‰˜´= 0Ðõ@—]/§öLàDÈ�”שÇù²G¤€H-8$4EýŒL ! °˜4MEB Ô$P̸~cŠ÷à:¾ãÅçðmßþ=XãèèNNb±º¾ER×a™ÙF)¨wªJ¦Ó™ó 9PWyìå_ékz:”G/ëÝ2¦:‡Ç¢š Mb§©F¿Š½ «óA@C„i¦-a: h1ü6!£iÈS0æLè¬)cÍ]f5Îõ¡Aa_†×Y뢈¾æê†E ¨ÎB(ïå<„Huk»Vè-ÐåŒuŸÐu‰ƒÆ:“&e0=P�ýjh*ÔÐ"×ÕXÜ GÜ a>ó2Ô,@1˜‚”§©daa­ºÝŒVƒ? ËNàûßÄ�ÇìÊM;U±Qȱìw(ï."_�.j£7ªÖ©<+r«E(•7žn©�‚§:Ì�|óD¹,C§Cp¡Ýä™ZI©`”¼ú5ï©À¿�Ê=H=ú=»‚Ò.¶¹0¼·Ÿ©nÎÇÄ€ V‡s†Ô.3F‘Tåj.3œõÞV7(� ¸�JLP¥~“÷KåY> ÖAÌ:±€QeB’ ‘(ÒsŠ‰Î¢yjµ‹|ŽÌ¦a~Â6?Fñ\¯ÔñZÄ=xÄ à©ÊŸ?[ãîOÒ:"2YÌIýiƒ; è`o£ÍÇÄ˾*0Ašæ’ÔöÁAÞö}hC•ÏfSåáŸté—ê˜ù~•�¼üU­¶²º}õYþ'gÎlôÑ k¥Ézןz£Ê0kF{cˆ‘wÿT1±:>Ö äHÞÁñØRuìqcúyÕ\yÜ�Ž�û¢äÝ `Öýª‹µlÃmŒwèkÊ âϨê ÈÎç,ǘÍ;«760´Û¡ãG¬ûis鯄šÂËc’}·¶m8ÌcÞ]±lM²�zš8MÚÐ!�<¤TµÔò¶þ¡êÏ¥ó5z(U|7·�sºáªÆÇUslû…QA.¤ÍS&霸ÚË<hà·Óù$ è.…Xe|Ø€¹¬úÿSöæ±²ç�Øï«:§»ïþîÛùDŠ")S&%K¶l)3’b�¼hœÈˆ•ÄAþàq‚ #L'ð$ÈdÁ  2ƒLLÓ™Øc ›¶eIÖnI–%Q+-‰4)¾Ç·ÞýÞîsNÕ—?¾¥êô½Ô M4û¾îsêT}õÕ·/ +œ±vãLVÓÉ7�±îj¹¶'F ÔXP¾õ€(½)*Ós„ ô¹r @ao>*‰½9æålS�•ªF„e\ïûÀ¾6›S] ѽõéÒÈêñ–yäŠ7«¢" ‚”ƒDM©@8jn¥ƒœë§iÖžrÃMƒ§=[辶ïs.T³¦çÿò×ÿ_ ÿ/�ðÔ“Û¸vm·nã…“¤Ñ¹ƒ;ú,°²†¾ÌŒ×æ 7¾§Ë =f%ƒ˜Ñ1{–AŸ3¾µwèÙpëdŽ•¸†V…Ÿë«£ÜíI‹íI‹ q<±±æå‹þìÁ^[ñŒ˜VÎ�‡WWp]{Ü]tØj¼Y_ÞÙÃùI‹G×Vñ\½Š¿wëà?ùÕ?À;Þñžzòˆ–PýLjç§[ÞÓ³vm™®ŸõZæÏ<~té’[ì"Š)h¢°Ô×ñRß�š‹/¿ÿÍiƒXD4ãâhÔV´vä Þ£Öbg3&w8çBµgâ€n`t‰Ñƒ8©Í‰H• F`F‰n(h/’HÍ(%„^|õeüÍÿéÄýÝ=4D¸Þ¶ø•KWðÈt‚ãÙT¿zÒ`~ïædf<»½…‡WWð]5–¥,Ͱϵ îĈ+³)¾ò`G)áí緰Ѷøä�{È <º¾Šg.nãÓw`‘2îwžÝÞ½E0‹·Oæ8J Ol¬á$%¼rt‚?»¿‹'7×ñȪÔÿþñ ~ö¡ËøÞÁ‘ŠOŒ>‹ac­‰8Nb¤øÔ�¸¶:C$ÂÑ�ñíýC4Dxßå 8o¼\˜MðÝ}Y×Á0àùÝ}\˜‰áêtŠ�ݹ‚4IÞl|AË =¶¾Š7o®ã¹[w5|D-÷c¯/>ØE—26šM �(ÞžLð̹ <èzüownã%Í^ØZ›áÿ•gO�¥àúir–ÒV†—ÿ)Š<\3^!ƒ•Q<ŠÑÑ\”v3:'D åª cÍT+9–š¹'|-¨³,k-t²(Tða)õ¬f�¤3ƒ2sN%½œK£ÁºÆºPØ2t²ñ_SÌ9 uƒF¥QehÑE¨c@š+‹L”ŸŠAEŒÙ&jXé¥!“¦RÀ�H³�ú¤€,«C3‹,FѤF5P‚¹v,nVl 1Þ�“À\Þ©±­ 4µ¬‡YiRÎHš ãEJTÎ[¦ê&¿��£8e1<¨e‰¤³b‘a�«1Ï"ÎÅhójuVYY"A“…Üßд~÷ƒE‡K#ÞUÜë+¸=Ÿ+ÿZ�¡ÏÙÏÛ"eÜÑ¿íeeÃÎMZ ™±«N„k«Øš4x^� p~Òâe­V”øÔÝ8N -IÌ7´ù••®Í¦øòÎf1âÛ‹Òç`cÚºÊd,ƒK9ý?!¢n¶éûè÷ö…íÞ �f· "ª±Ãê}‰ÜT­e ÞQ£Z)ßQðDö„‹¡�ÎÕœX¯DŸJÄÊ›  f šØ`Ò¶˜ÎZ´,�¡g CØÐec›jÀ��<ÐGúï‰#1Šn áqbe€}�½±NYã—¨®ê,fËÌöƒ«†nä'¡ RF( hMv7üÚc”IÖ}y5eVšTñq*ë6}|Ù�žÝ�¬:4“ÚÉ6£BviV{ü³—-Ö³d|ÝÌf°2=Œ¢Ó|I�©Í#ÍÞ„”@4Ú™šò«\U³8­L_öõdm$lòlû÷¨w†Ëd¢s’x2«|X¶ÿ^ž‰mUÁ×UJ�23Êd ®¤ IDATÄh�U*…aY�ûäP«ª°-fiz  �3ýS õ�LÑsir^(N€èos À+ ��ÇŽ¯ ñ³Ìè2Ž9[*l<õélå§ÎýÒÂËÿ��މ}.;ñ{~{ mOªGV¿�ù– •éðöÈêùNaª‡�—9~U™K«EŽ8"Uk¬Ðpé(–èô:M _ÿ»³¾¯×cNŽÊðVÒ*LíQkbéN¯CAa¸Rï‘ÜýdÖXz³4ye”MbÀë›WÇè¥û62Øk¯SEhˆH„+�^³¼e,ó#[c…'vŽ@5¼*\®©)ª±}ÎØózž¨¸‹$‡šÓ–úïÕCtÞœŒpJû¤º4ryÈÒd2)Cñ¥T…+±sSyd¹‚¡EžñYÎáv•ð`ëÒ•W }‡j*ÆÙæÊrÁHÎpÌ^já2¸iÃaÒlî³6Vç@‚fR�€98ž'H�×ÿ3g@¶ÏªœP^ªïhìÇ·@£mê†KlŒJ¢—µW@.×ã�¯à�+Aæ=®ð¤4ß) �ý µêØYq,`|ŠÇ"ˆ¢Y~-;SÊŠ4r ø\ÉÑC˜µÒ?�v®Åä“âŸQWCóÂ|IǤò¼Š9:mwÁÂÎí²³´ð$™f þåt{üâÑ_¯eV°ÃÔ¦QßÌv½‚è}ï}¿õO¾ƒÄŒç�Žð§š G= DäN+7´¢Æø×NXk£—#:N}�«z}Þ\õ à™‡ƒݶ´ÜÐN×ã/öñ΋۾–‰iðúúqýmÈ󜽧Àá0à›{‡ø1Í,`füùƒ]¼ëâyCzXi£]¼ˆ?=8ÀŸbÿ`�ý;¿�Ï}òßÇÆæd Ä‘,Q T¾ÎþÞè;Äõ0þÁÕ³êg/ãŒ]÷zxt6¤šçø—:o26bpÕ05QU'wT>Y„Ë�Ô1Ä0ªé¼ ¸áRh¯ÔÒŒ,åIbkH rþƒnìY#,úŒØe�p‹Ò"¼#J”1" }j(¢ Q2ZIÓýÆw¾�_û_þWjY‹óMƒÿøâeÜ=žcÞsùî̽L„�‹~ÀÃ+3ìô=€ÏÞ{€‡Vgx<6`H�H„Ÿ~è2v=>{OÌv×WgØhLCÄpý ¾­õÆ3nÍÈÌ8?� xõøÏïJ)¤GÖVñÂÁ!^:\žêlLW×T8€Ò]u¼M%ÌjäNz©×!6X Rm{"=:ìõÔæú¨aðƒ®eˆZ“ïH„s“÷�7 Ç…søÚÎ>á¿Ñ68åg¼6Ÿã¶Úó#Iö—wöOn®ãµ“9ö{¹ø™í-‘'Ô1°1l\˜NðáÃ=ŸÓæ´Apl³}�5[ÿ¨qæ@Xâwº§YÖXÒjECø@T~ÓDQó´K°2P*3¦d©ö¿ÓѬ£™èM¢*.óT@΋–±â½ rÖRBÖÏÌíâ�æÝæ°,h!6“U2 �(xcøV;~ÚºOL¦YG£ ïJ'tÒFå»jVIUž,ô+ƒHœˆÅQ¤oË  û� F˜LÞ« 6„¨%ëš&ºcÀ ²æŒ s`|œ›Îçúc¥#2¤Ç@]ëÔ«ÒÇ‹>ãÚ3o ®Ñ˜£aE Ò»¸`ôwõÛˆ£è¿©|Ïö[ÍÔnÔ-ŒI%‚åyÕÆÝë®?óE¯ó/ý}zcg9^î5€êë–¿_¾×~«U1ý>ˆBèü¶¬óÍ\.wG�ü®|Ò‡¨3”¿Áø)™�Ó³–¦Ì�0ë€rŠ |K YF¨þæ²ç6'{¶iÀË8î~/�ÜÁ`µÕ�‚ÞTãÄN�ñâäÓýèEÕjàa%$L<"Ü�Œa8|Ùáê Û§Ì`k¬”Ä1 A Ô*"K¨9| ³.gÍœ¬à•V¢j/Ü]mK.Lmtö|ùF°ª= zFRòñêh BÜô:Çá ù24“ž5@Z>=�ûŒÔK) é ‘!&ЕcÀ=Ýöö,«•‡Q#¯çhhÏË'µ:0<6Ü{¶Ä)¡©0�úk‚®ª¸$‚Sã—ä’ô—µns žj_e<È¡_?»3¤®sYæ}^eìн·FJ�*åšÂI¬Ä)étP¦h34ª%CO›Ãr4ÈÄ�œöúŸcû¬¿³QÔ�`»ùukÚb§"xAóÓ¼²<ð¬ßt ê)ÄqÇ }~bcãTôí{ûdá ~àæñÜKþÀ…Ù¤nB„µ&zæÁÝE‡‹Ó‰g<¿»�7¬­úó)�2a¶'-Þ®†ýEΘ„€ÇÖW/c%w8Ü]txéèïRGAKAê»$ˆðþk—A�zÌó!¹sã/�ŽñíýCüú�ø�¾óÜê:|ã›wñËÿá‡ñOÿï¹SHh\‰rzVÉg¿l÷4JXf4þݤý3î;ýwýÝp‡²çöC-¿Œ†5¾Ã×·ªÜørç&rå4 j�0�µaC®i"xàdÞq "‚¤æˆ¥K“ mH)# ™BDˆ C&,ÆÉbÀÉbÀ¢Kèú¬?T� bÎE@Üè;‚˜ñ¹/ÿÍ?ü‡Xt=¶BÄ;W×ðï=t3Žú­Î´nÂÛÎoa½ið¥{Øëz<µ¹Ž·žßÂgï=À½y‡>3ÞsyÝ o v»‡iÀ#k+`fÜ9éðüîžÚ\ÇVWðõ½}|ÿxîÆöïÏÑ»¢*t­‰˜'1|þþ.n¬¯âxÐÂG_»‡I xÿµKxíd�¯¨‘îÒt×WW¼Ñè%dŽJKV†PV™x‰]¢Ô.‘E‘éà�ÞÐq5rÝièxT+_YÊä,=Àa'€7¶RF(3ãPKŒÙËœ-ÉÓ¬ÙùI‹µ¶qúˆpq:ÁýÊ©ðõÝô\Φ]»Ö4¸0i½Z$ÂÏ=t �×é3PÃãk»ûX2 ·'-îÌØÕ’lOomà¿zíU]7pn¥ñØ«lºBü Q&ßé="Âg×[ˆ4Ø$„¨¢S‰öt¤â†6)ÇXÿ,ˈ á^Géz)#ÛI6Y²¿4–ÔDõ!4)FÄ(HKäff`±è1ôƒÒŒ å·$ã…Ež�Ðæ�!D¬Î¦hC@7ïÐå)ÈÃâŒ6’Ò„\Œ—(âh$ FBÓbõÄ›á)�BúCîìr¤dÝ;‘ó#"ØÊìÂN�é`j °‡*“šT•ýqü© O XÃݳÌLË//…#Ov'©m/ª,KÓGJ•ŽEV']�˜ÒBé: ̬¥å �†Ðœö)¸ƒ™2’²R1yžÑhuZ{Æ›e$ë¿›µRÄL-2¢NÓ€ùbÀ|ÑaÞ èúŒ!1†,:鬤S�oΪâ°GT?1ÕÇ«îP;ƒ ù^@O‡¡ƒ:W=«õ(ÐÐ-À²JØô3Ùˤ‘ôÙ`$´SŽ¢K¤Kr/\í1l3yÛ¯0'ÐhVM–°2‚õDå¬|ícÅ!‡`gú(ªk´¤®8Ì)€Ñ,müà(†?z ÛRJàž—ÓqÃ=û¹ Ê(N¸ÁÛ"γò5/ZU9‡Ü9À•ÝBÿ†í™êæÅ¡ËŠÏ>H‰ ƒ¦dç¾à7�rQÆ�³Óz+ i%B9ÌþÖ³ëÙYJf j'OUÚÑž¯@7›‚Ó#}¾ã��G <â`½4³@÷Ž™€l4ÅÉ „ JÏK AyžWÙti²¶–J"8Oôüˆ3$Fò Dá{,xÍ™®Ž‘:XÙì]UÀ:Ex³órà¹Léýð:þ#c\=hu­_0þƉ÷ˆ<•+¹Ë5S[ éµvª¸L¾ìa…15ÔÇsñŸ-ŠœQ ¹ ÂYM¹6Þåƒo-ø�ÖZV„Àj¼ê—Q‰€¬jæ Äø5†íÙ¿�?iy¬en|fÄb��-Uw’áð3Ã6Û!Íìþ�PeÔvv/C’Åp'%RôWK2ã-�#ËÈŒd“³ PTc¡Ó©Á³âñµõé3 G¡g†H œDRkÌŒ« bTìßIÖƒNFœyH’)0ˆ$vsÍQFí‹`”5S�[åÿ^ÿÎpÇ-·¬LŸJ¢½mœM¨NÆ)gE¡–öd~r­Ÿ’�Pœ²Zw è;Crñ3�ˆc †.¡ïŘ�Ù"—Ä1`Ê ÜkÍæHZ3Û¥‘N6DÍ; ˜ß½®²±u€–èfñØ”ÁÁ|`¾3ú}9ß5Óp&çQøð¦nmU€Á)§€¼Ä³ &åÂÜÍ^î8mBjŒ;åÙ#‰\øôHšP¡S�Zú¡¡•1 ZÙ9!)x$há'¬‹B¿á|¢>Àn×ãdðÞ+ñ¢–.êSÆ^? ’œ‡.3î/z|c÷�®­`#v=¾qt"ÂO_½„—�Oðꉄþ6DØjLcÀBË }éÁ^[Å­“9.Î&øøk÷@€öð |IK�üð¹M<¼¶‚?xUú20‰c¯5c€Oܾ‡>g\šM7.^žMñ¶í-üÑ-qdÞ´±Ž»þÓï}ÏQîÝO¿o¹q¥DéA Ä*|ó¥Û¸·Œë·ðô�Ëð"lÊ|]wwé,1�SÂ0 HI¢íA@Œ bЀ– ¤üL&¤�r„7¢Ä §´U"ÚEéõ`YÍ| ÄÈjLb- T”·(ø™‰Õ0'Ô�•_¸  Ü`$PÈnz&äâHccLf¡PGRê1$Qæ²ÊΜÔÇWeIF&0E hé!k6 .½J§ä/m“L� 4H¬ëÈÒ?¤K,†ú^2ú=»`€&γ”!*ü.;í“ò¬Æ(–ß‚ÔäOL@’Ìžãù»û‡¸»»�ÓóX „. ÜY¥.�á’›<¢3¨ŒÄc§ÀRvd¹ÔÿðqY�[Ë4䆥òµò eÙGÚÏãÉv*‘ßÌ^ûÿÑõUüåá±�¶=�àdH^ë¯pP9Œ¿ÀÕ•v»ÞÇzlc ÄÒ@f&†{%f‡Ñàê~Pu¥ÜLV®ø‚«¡,ÕŸfŽ“˃:Fl¯-k‘5sKö@È`J~‡,Ùl:ÃY.�%ƒÚ ÑYx“ê9q™mŒÈÔ€C+Ù$ˆèÓ€¾O8éœ,zt]B?¤Rš–‹Ì-Ž;c%ö 4S»ÍÑ"ovЙœk|·ìKù[.3Û)ük%I®Í¬åt˜ÝNQD[5ÜØ\Ÿuøy©�ÿcÜ(v“B[ë9È1+o¸—å­òD}™ëœµŽÉö]mlfï¯Q7š�Q]FlôϲãkG”¾Õ|¨Æm=Rê‰G͈k�xN€Ú¼4XM?³Êî`àâô7sŒ [£åh �•ÛSIŒÌÖ¡ÎJÃ×ψ{)¹ çA4¹¢›J³©‘­ç«Ñ8œ°@mÉ’1Þ(®þ_oß™C�·ãŒÏj“œl¿Œöêá,\Úþèz>°Ãl¯€bÈ Õma<‚9˜ èŽ!Eù/ƛ׋ö¯…�exÔÿ^‚ɼ~ù>àua[–ñœÎø~|†FÀ¨‰“y•íz«7fv¨ÑЉ:0ÞcßS2Ž·Öçj~z½¤ª!OÓýÊ´õ�Äzlm ë-àÆ:[_íª×\ýf :hi­ÖeXÅYF0“O>sìç²Oæ  ¥ù� %ÖË€|ÎÕó2ÜhâçÆ#:¸œ©Ì ”¥ŒN2/z¹'øÑÏeìÿ«Ö_¯BÖàKÖzg2X.sµù7ªaᨸô�u†Á?$¥�LÁ†rP…þ5½°} …šS  i[iúžÑw]—Ñ÷Œa(†zSÊKÃ)}”¦Â•Œm Se ÔÌXc)Æ'¶æv(ð!={Žb£*R¦Œñ¿ÔqñåŒÔ¦}ÖÄ.­ëŸ5MÏ"ó‰¢Å[xa#‡yæ Ê"([�×âõ7gÑx]’‚XLã&0¹PJA…�"�Yã§±S dÔ˜ ,çɺâ1„:ƒ®Áð²€Ñ³Ï"‘š�àg´Î;äš¾PuöNÓ—SÜ’–þàêbw”ÃÏPiž¥Wá‰7náM�oâ;ßÝÇ×NNp·ïqm"úH䆸¬$Ñ8ÕÍã\˜N1�ò͉*ûmhô3à‰Ê)À£ýï-:ÌbÀº–ÚízÜ�/܉)àüt2¢U– p’Òȉ°×õøvUnh‘3¾sp„k+3¢ŸÜ\÷ë3àóêsÆ ûGxóÖ:®­Ì�˜ñý½#ü굇ðwnJTã÷ß �ÜØÀ¯üÊÛhN —ö`ùUóo¥%.#åñoŽïyŒcÍ¥º¾º\}U#/‰´t —kN�]æçäÐìYúM sÜ)�6kC XŽ0!‚ HA¢NÅM6¾%ÙF‘sp³I¯C§kRõ;4UÆ€ŽCBÄ€†¢–‰Vj¼d QÃÊïüñGð¿ÿî¿3ãá¦ÅϬoàCׯa¿ë}õ‹œÑ匫+3óÌøÄ�ûxãú ÖÛ;]�/ÜßEC„Ÿ½~·Næn„[‰M$¬Æ€cuB?¿»�G×W–hÞ?¼yÓð×®]ÂÑ�ð™»RnèÙíM¼amßU£\ή¯ÌpÐØš´øÜÝÈzm$ÂçõßoÙÚÀ7ÖðÜÍ;è™±Ûøñ­ œ$ɘáÅ£cÌSÆÕÙ Óð‡8ÙÍxrs —g3|ugûý€Iø™‡.ãkZ „!´àÈš�áþb��ŽñðÚ 2K)¯/ÜßA »/�Ç«Ç'øK�:¾:›b¥‰Þ|ødHøúÞ¦!`0 „׺ëå—1׈¼'º„ŸzëÎ\�S#Õ?ýÄóxáÕ{޹ïxâ:~á]O;²rf5ø+âòX6±è?ËÒ³„‚!3BNè!ôb„“h:U�³F¬)WæÑù3R^ŒÄ,t«ÿ\<Øâ@æ€HÌÚÈSTsÎ) jP€Ó³ 8ŽP |¤QgƒË–joÑ~Œœ%“ÓSé!Æú%M,͹�ÿJñ"3Ћ)PÖHY•ky\BÑ䜆LR2PŒYCÊú„¡g¤^ëo‘HI#þ•¦�:É݈X“TIegwÒxX ónÀÑñ �qxxŒÃù€.ô9bàŒ¬FbqÖe¬ß‘IØb¬11¹HC1\KI%�҆ǚ:M­ÿ6¹ÌH»KSÜdº«+—Ì8é{¤ÌØ W›7VWðÒѱÃáæq©Ùwôœ5!`½‰ØízÁ-ÿê•‹øèírnêl@øËƒ#un&�p8 8<”2@o9·‰¿Ø?ô¬Ÿ7m¬ãþ¢ÃMu4 ƒ7&ûC��ܺ @x?øâa)u´=k`ͯ�/²<["Í e/qAe<q,r’Tî§ÚF”Mf35ˆJÔ§ˆ_#÷ˆ¥Ÿd$õ1ß'VP D>Ǧ;ÙT®­E;[c9ƒ«ßŠ<2œ¨e „âj‹‹³¡>cåY&Ï3¤æ«¡ˆaň ­%ß§$0Mã[›"‚FÞ êH1c§ð¢€Ø&Y�¡I𮋡UJfúA âÌ,5Á`&¤¼N< ±h‚^ 3’R(™†ÜKöYLèº}?`ÑõXtR6mHFÃÆôLTZÓË9)±xìñx®š^pÉ O#Û„A?è¨þÇä&“Ò_6ºXêò—!ØÔuÀǪølyTùàbÔ4'y ¬Ä©—Œk=KD ®ôñ¸fej’× IDAT¤¥˜qĨ²êIêØ· ƒ¡Îbf„Äj›rt÷1%SO³ö¸ü("�É·ÅÆ–R)É[²dT N$ÜŠTÞ¶7Ô™J†j;3 œdç°l‡ãžÕ€-¿‘ #R?Y@lO,Gv.Ù×,&†:täàB3ê¿Ì„FO©Td ×öt!¸€L™¡\Ò6£¾Õ©ÀœJ¤¡8c�¿Þ`G7i0½Ik‡^P„Íñ’© SR ìŒŽi2 ÓˆNÖoò T[ïÏ«èI•ñcÛžk<®îû×þQüÝÿù«€Oïïã/^Äa?`£*)t8Œû<´ZÊãæÃ÷æ \œM}~_ÝÙÃÓ[h´¶KÞ.@i. H£Ó�¦ÁCÝÿíýC\˜NpQ û¯�,@ÖÖîS•b#Þ{å"àöɳqYK }÷à·ç ¼ûÒyÒC|‘’Ï$á½W.b¯ö~ó®5þÆßxW¯®àƒ|BáVóÉ$ß,ýFõ5F–xù(óq‰¸�µ%”3²tÉÑË÷½>ŸçÑ_FÍXfË¨ÑØ…Ħâ+E-€^ßQ£N2U7‹±4Fx$2“bõÌY嬢#2,z ¥„†D(¡Ñl‡F�¯LAš¸§Œ&¿õÜïã7ÿ3"üõ�-¼{{ ßÚÝ©A{>zë.f¼ýÂ9¯�¿×õ¸]_áÖÒ^k¼|tŒ“”ñøÆÖÛßÜ;ÀíùoÙÚÄë3|éÁ.î.:´êDxA£i;–¨¨ž³H ¤Ÿºs¯ÌÐĀîǟÞÛÁfÛàׯàåã|åHÊþ¼yk�Ô¦Ï9ã$%|kÿ�¬Ì°Ó8?iñÜÍ;Xi"Þ}é<ŽSò’AOm®ã±õU¼¢‘¾VräÂt‚ý~ÀzÓàSwîƒxhe†­I‹?°‡��­¯âMkøÈk÷`ÎÞ÷^¹è�‹33n�̱£MK›ðõ½}dε-n¬K™£ƒc1xÿ̵K8I ¿þÊ+xMË¥\Ø\ÿñî·º²îMÿ×^¾·3r ¬Ï&øóïÞÄ�K[xæÑ«È)WÆLå@‘+Í¥<€5ƒÝ ‘ÅÁUKåKå¼’ÊW*QêÙbo"c®0®Œ�îÔA ú¤©û,}!Ö ‰ƒ¥‘C•ÖÐ6�¦‚K4w« åÂ{‡$µõ‡ÌÅøŸCb}N•BÈ ÊkÆ�žP; Êw91ˆ4z•ÔÔfg^#¼5 Ð"@¢¡Ñ±i`ôCÆÐg CÆ0i ȉ#˜£d,if ÇW �´šVqõÉ$™F3]�£ã9�qpxŒã.¡çˆ„‰Ð’Ðx*–èr�É$l"!¡ì9.YÝ{û>’²=˜ôåÒLî©Õ [ ³«>p¸zó„:ìÍ)°Ñ68t*Ÿ\Y™Ìî€#06ÚÆ3€�«S€_o* 8×J¹!‹þÞyaŸÔþ àþ¢C- Y�Õ&b«mqK³ñ¾+ðñÛ÷=áòlŠiøGʹݞ’ÖÆ7øÑ(¼ ùÝåQÝ ‘û ëšÑ®• «\Ò>6ä®d�‹ìd$åG5ï¥qÄxÊbòdW VuÝQta^z›¼S,ä|Ì›ûf¨¬â:*¸h$|°ž+b´öêj35GÐëé!kéeÃ(ß[ÛSû{ùþJã²’`rÕwXV€í¹s€tÜEŠóæÈ‚á_ÑãÌ`1®²�b{²–t¬0ɤŽõ§r p4ÚšU’"Íè” ¹&M°Ñ¹:Þ@œëNW¸ì; ÙZÏG®øå�3LxÝ+Sþô§Æv‰‰`µÙÿs--ª@d?VÄ»¼–NÚèg^ºÎ˜{e,¶;L È\ÊA€Æ:|…¼§þös  7#M{¤¬�Á˜ c¬çj^Jòe+�̓8‚…a} —aòz X•ò¿�}êu–w÷õªÜ ósÆn×–6•µµœ ¯§F¾Gg€R¹ÏEþL¨½N ©34 ªì)WFW�ÄÉäÌ¡xRi"ßCÇ×z™¤óÂh]>L‘ŠF¿Q½#ç‚®ÛOFQ2\ËôÆ{ät}`#Ë»>¼np‡3ˆeXŽþmò,L“´”exƒb�?Š`¶<¦‡èÔÄÎäGð6!�€F­B‰§7ŒôÓð¢¢Ie6«!jÄ�\H0"9&–:?=S̬ë%Hô»|—F7d,úŒy—±èTñM€¥Íꨖ `ïÊ1 žô"Ö¤+�ÖYMÔ â†t€r�Õ£Ô‚¡FÍP®Ž*£ôx²ñÔÈ´^‚5žÊ,Š>¡üÉ@Ë ¥‘aÁÎW#Û™P|FÕLŽHÓË5ÒA…>Iæbdž¢ô‘6’,ÙŽ_™ Ϊ"¯šVô€:Px…Iš>ãäÝ5QTé ‚ü ¥¾Lh3g¤�ai€‚v rÍÓŸG¶I£òCtq2€dg©ÐR ÀÏÿÜÜ1ð™ƒ|èâÅ‘S(†ÿEΈD^â§ÏŒ;ó9®«£ÀW¿žÝÞ`J¥¹ðIJxåèdTnè[{‡øÑó[N‹o¬­z¤Ï:HÌxõdŽGVW|¼?~í.ž9·éŽ€û]�+³Žr}m×µ9ñýEç= ÀçïíÈïê�xßÚî÷=žÛÝEJŒ_ú¥ã·çð�¼qiu#&ñ:¿•+<šQ?–ÙfíH?eô·ÿ/ s£ßëÃŒêÓÒê–åK|T>™�Ÿ–„ö(hV\#†„´q5&© ©5ܽç ",“+F …á~ys,‰òÃŒÌ œz¤4hÔñ€œ¤ë{$FÛ){BbŒRr$üãÿ÷÷ðÏ>òQÀ;f+øñÕu|èúUìw=¾º#®§6×1�‘H…tÆ û‡¸¶2ÃZŒ¸:›â¹Wo£�ï¹r‰ŸVÃÙ;/lãÊÊßÒÚþ‹œ�À¸¤Ñþ×WgøòΘ?´µ�55¾'fpý ¾¹w€ÌŒ£~@¤€i�&áBö`7ÖftO?uç>ÇØýù_Óu<³½‚k+3_×n×ãö¼Ãë3¼rt‚ÌÀs¯JÓäG×V‘ÀxñP —�¯¯â‘µU7F2MƒYŒèófÆ÷�çø“ãCüù‘dIÌÚ¿ôžw`Ò6R–ÁjÊVx¾s(È6<¾¹Žoñû_xW¶7°5›h‰Ê\ÒÅ«ófJœ4ç ʧ ³u¢Ù�Zø„?]Ï–Ì­Ü�Fü‘œ_"hº¸E�ËX)¨‘�M. 0yÂjõfÊZ&SŠòd’1ÀÚ(X3Ϭ܄9bŒ ‘2"‹—iÈèX¢Ù†!¡órº²¦tQf’ÉKpe•»ry$hÔ0qF$ÖÚ¶E�5xÄj×6$F¶¤e †�ÅЋQŒ=óRΧ¤¤LRê]”eòIµa×hYªþ†¶6–¬í Á°„5ÂjƒF5G…i”5³ÇÎêÛŒþ–¥J!ˆµ‡‚Ô �ɸ.�º"–£GµÁŸPTƒÇRŒ„£^ û.ÿÊk%Fœ$�R†8Âk4í3{¯€«+xåøÄyó�ÛÀ½yçÙgL«ˆÄìN�ͶÁIJnø¿±¶Š6¾«%Í&!àÊlê¿÷9ãÏwö�Xú €?½·ƒ·žßÂóÚè½�„ÍÕ^ŽAe8Y¡6eÕÿÊw%*Ýu"³¤•³ R„áY›¹º”©u—ÅPU‚›Œ¥ç„Ö�Vœ†Þ/ø/ç$XÖ6A"üaè@lÍJƒv¥Å¤�¢‰¤.kÙÑTœdÉšš—URl´qdÓDI2†'sÉ€0$Á˜&ˆœk²¥e1 dh£rVYRdÜ~>`ïÁ1v;lM¸o�;€Ù»Y@Q~MEÒ@&åÈÒ\0b”ÝeuöIÎu.‚4N½t.d)†~““˜S9*œ¥CµÂ*ÇGÏ"1,ê¹V2É�i�DžFðë–YmüBt Ê$ÍÓû”�žx�L‚4Qš[[í8¢j„®TÞÕ3�5îk쮢soIºôÌ„œRÖ†ÁnŒW Ib+ˆ)#ôƒ®‡0 ꈭz HÖ†9 Õ°Ë%à TéÒ0]Mu_Û÷òYœs•YÁOðH/U›WvÛ �å"ÿÊù³ó«c.ò‹¾J•ó 6ä9Á‚ÊÆAg•|Í�mµßÝ}>×åtFâv™Sµ\ÏXG1.ײ7`%v²:у–‡Ñ º%IéXÔÚ‘@)“hý‘tcL¿öìpƒW®èðü¼„ßtÓBF©,“rq äÒw€=H°Â •W8K¶”Qê ?"#˜0þE$“&èט4Ú[ûaYy1<±sœËùv¶[p´V•̦¶y¸þÆ æ6€(ÂÖ¦>³w˜#�þLÇWSÜÂ9KÙ,h¯›¤2zÍé,}�ˆ%X#’57·ì3-'¤{LµçšÆè¶FTßSa£–¡‘¹l"`™Ý*88Ê¡­è9ÑRÆQµs¶«p¯M ÿ¬—‰Ëß�u]…µ!Š0JÑF¨æèŸ|êÁ.òWÏ8c�ã©/)ñ&é˜Þ®[fŒõ¿ëÕsõÛë0ÓÑ« òx‘¾‹?`òüþ]¿–ç·üÝãV2°]jž1Pß› Á—ÄpG¬)NJ^™¹ì‘EµÎhKÇtBÎKëe¥ ËiVVwk ~*÷TÄaÄÏUŸîb¶1hé:*C�Ëû´<¾Á[)oË@ÃK×ÐéO‡QOSŒEr(û“YƒïÞ4’Í–9m5fMD–P†ª)”=¨fsÊ%�«žÅp ŸÐ}âJ‘4!£ÞËjÞå:�&ÛÙµ²…*Ê ‰Ñ÷’)0ïÅAÐ,5ôÌpmL\"Ϲjôcïl�‡‹çÙ£h¨§­Ô#£ ÐKz0vTú¦øï5ü…‘¨!"x³®ÐÅœ\˜ ÑkòfшÉj`VÍì ÔV³ ZOη)ÏÕ�µ“È1ã:‹€ÐÝ ‰(N…š)šsÀœ ®¹ê$ÐHv+u’ýGÔJ< � @F~…fØõæ€þf¹¦Q�«�M6+N#pÅ�H3‘÷ëpm§‰:ÔŸî€óyÿ1ï~ç\8?Ãýs|õè)aCë÷ï÷ãL�!sÙ3HO�ëUön˜õdŽ‹Ó ¦*ÑîtŽR ½~‚âíõcÚlø —ˆb+et{¾ÀÝù?|nÓç±3ïðÈÊÌçòÏcƒ’*i®*Ïíñ½ƒ#¼CÇî3ãOïíà=W.`½idÎ+SÌ*ÉûñõUüêÚ î¾pxˆÅ"áC¿øaüî‡?ˆŸþéǪÕ�_�'2 Nê«6ð8ý­¿Ð}_ÖBü>½ß£œbºp"ç4Ãܳæ,øOJèDù€§°{,40r¥HT¼€.ç<€ST&OgŠIú|C$N�@ &ƒ�ß +e1(¦”1hé¶¡OÈCrB$‚çØ†âø{ÿìwñÏ?ö ÀÕ¦ÁûVÖq}e‡½DÛ¾q} M ¼z<ÇËÇ'xöü¶ÚßÜ;Ä«Ç'ØžLðW.ŸÇËÇ'èYæ°Žû„YŒhÔhð¥û»xbcÝwñ#·îb½iðþ‡.ãæÉ¦Qõ?r~†ó“ÖyCb1ü_žMpgÑãáÕþäö=´!àGΟCæŒ/ksῸ�‹Ó ž»y™;]‡ë«xж¸¿è°¾º³"9—+1à³wïc`Æ“›ëâ€ÐŒˆýðÓ×.{)#†8!Ú1Ñ>=·OøöÞ!®¬Ì°Õ6xéð_ÝÙÃ4J)¤ï{=òs“ Â÷�ç`f<èzì÷ûhˆÄˆ9$|úmoa‘3v8ãk³aøà»ÞŠ kîðȸŠ_;¿�VéÓõޱº¶†/bÞøçŸþ:þí÷<ƒÀT2ŒUj3k´¦šÙŒE¨£$‹˜¦48�F…•(GkxÏ0Q§ÔèzΈªˆK¬ô3#åªö¬ÎCêô ¯GÎÈ1 –hÔ˜�ÝĤ·Oh¼#S’Há< 3£O ‹NJÒˆ(#LgB-�Ä$†ü,2OÃ%¸&q eˆ.FÒå„<ÌŒu1IŠ{Ê2fß}Ÿ�†,ÑÈʇÄ) â!s B£KiDeí/ëânHÈHbä�š-dЧ¨2›:+*8Kd]@Qå–Ó4”´(ŒÈû–æ*y¤$Å0 Y¿’¬ÌÕX"$”¸M]MŤi³ö!cÆQ7GbÆ¥Øà_[Û@ý2£þ,FLcÀžf€w\ØÆïïøµCe´€o슣/˜5ÇCÂñ Ùso;_~°ëð~ÃÚ*¾|âY@÷ ÿ-’4Zÿr·ðøÆ¾<Çí™Û».nc§ëñâÑ1¾±˜{ëŵM(õ�Ù"ŒPÉéVg‰]j ³³¯Zí1GYÓˆ£ŒC3Šö%ΕrLY –Qà­¶¤’}ª:@$iðhF—&m”�"³ ¡uã¼Ð„¦%L×ÌÖ&˜L¦h›©f't‹‹y�y7`Ñet}F×[dh@hí„Bˆ N]·ÀÐ� ï;¤!�rei@c 7f‚V‘%™ãOúˆÌޱc`gŽÕMúˆÜ00Z"¬´A²÷šˆØDé™��! Epç rð²l–©q`ê^ÕA¥~ˆ¤MœÕ߬ÁG ̃%ÀPÇ€è@|&¼_Œ³p}Àu5¸"iöD…�fV§¬é^¤ˆÀAúit9#÷ œ¤§Ñt¢²F HÐ!Ksâ„,d) •RFO"RÑtĤeŒ³EÀì„”È Ó¤)ÈD…_QÐ>ê|1£±; •Ö«8WŸ1Š�¿È©Æ Ý$ÀZWèG¹OÏˆŽ·½4»d¬Î�à;c¢éØ,Âe}ÕË�šlóÅ©gšoxQ­�r“¯G¯Ëñ,ë—ì°Ä|yö*雇žñuÇÅìú,‘ƒÅÉdNgy®8¸ª�ÌÞó€¹ôQ²²aV>±ì�f¤°r3ë5¤={{P%“°aÍ¢�#WÙ'œž’ã„Ù,¬A¯ÑP“u˜Ì)Pp×h­©H^¤º1ª}*˜Èr\ðeé¥ wØÔޝ‚£tÇÌ|v§¨òlH†gª@s‚áµ;oÉæRñ®jAi ™ÎågJhKL"ei¿–#8F¢df2#’8‘bÐ7Y/‡ò&æÊ9€bO#ª`k¸ìµL½|ÖxV Äc{¨|ê¥�Ýí·Ñ‹«�áÔ9ðè’±"[®;e¼ªo3L4y¡ö")Õã‘âM£1|�ŠGùK ëšåÇÓø's÷׎�@‘<:£†aÐëCAÊÀà šˆ58¥®HŒ¢î YGø»äÝ5Û6Ú…%2c!¨ÞCM™ô­g¿MQ[†ÕËk{È)ü®q€êßh¼U~-æ3æå}ã2¾9XÚ%œ 3>G¥+ì“´)1û‘ѵ,טS€–g§Æ{\¬Q¨¢MÅ7Pc"ÖԩУŠÔD¹šj\8õ`›;WóG�ƒ>ËÒ YÏ<³ô Æ¢g,:F×1ºž¥ù¥EhSdòÆÅF‡ŒTªy4e ø´—¦XÓ[ìøúŠhúŒ“u�ŽyDi$¤£=;œG‰ô\)fÁÚÝç@R|ðfPª‘Öää,Ö"íX‚u37OQv‹¾Ñ ã×¹¸q2’®ÉÎuðº�Þ§@r ™ççͶ>£7&íøjé�PôIéˆî‰ñ'°ÒÁ 4.B ÿµï�f ,g ˆüFz�ÁfDHÆSŸ;# 9è™Í>/f™sl ø™ø�ßz3>wp€÷Ÿ#úæRæ€êÀƒEçµûà…ýÃQôÿ…I‹I%d_˜NpAïÝïzlM¤||ugOn­»qÞj¶Ûó.O'8§™™ÓðÖó’‰ðòñ ε­Ïõù�}LbðC‘—fežm üìC—ˆð ëÑáÑ5ÉDxñ௜ÌñžË0#Â}ã~ý•WðŃÌç~áƒÆ?ù­ŸÇ?ø¦\䍨!-éË�á¨ãeØÊÁtùÆè�gúè/w8¡º·ºÀx‘)ÁËò‡g%’Mú”¸`ÏF?–9�™Ù³ld­I sÀY¢’Ì"A@ŸÁ}Bê:ä>!HûE€âØNªDKÚ�Ü›Lªù€Û’:RJHiп É{0@„~ð?üÿ'>öÅ/Þ5[Å�¬­á§._BCÀ½v™åòlOZ|òÎ}õöº—¦lµ·ˆpe6Á û‡rÆÓ[ë87™à3wà`¼/ÀŸÜ¾‡ý~ÀÀŒw^ÜÆ75¾ËûZz袖Óx0Ÿã…ýC¼ek³ðýã9n�b­‰øÉ«—ðòѱßó¶íM LC@—3ކ„›'ûx|sGý€i$üÑ­»ØhüäÕK¸=_àëZâÃJ#}G#{)agÑãÂt‚»‹—V¦ø“Û÷@ <²¶Š­¶ÁçÔIðæ­ ÜX[ÁÞ¼ãëxdm¯ϱÈ}ÊøÆî".ϦXo"¾¹'õÇ[_ÃåÙ_¼¿‹ÄõÞ«ñ™»ð`Ñ�!Ê—V¦øµï|Ç�…?úÄðÔui6\7>Ì×"Ûëxó�ËxþÅ[ØüÜö6^šÏñ`p{÷ûê‹xÏ[Þ¨I†…9暬XɵøSt ÃPÅ{*r�´Ô(rO ìŠ )‹–1 ´ß"ÿÈD Y¢=�K¢ÁâÆ­f~ágrNBl›±#R0µt“$‹-£-å†!•=÷)%ÐP=U3rP#_‡9iäjL’éC�”ž©â=0bJˆÃ úón@×e ‰�¬Fÿq0�Dî‹ÁÁÛÊ:0ÿÛhVùE õ5ÄkcD-�b‹¦i�Cr”’EPÉ`„n¾ë€EØ d4Cƒz\jS%º« @ÇAÊ�Ý… júoN*-Y ÏÝYHþ3Óâ@xu»]�C呵œahkN�I èSö>¦4D^nhÖDÜX]ñ†Á à¥ÃcÔ^+´Ñ4X­z…¬5 Þsåž»yÇ …Ó0�ÁK=¿{€>g\™MñÛû»>ÇË3„4à$Kt©o�ìn‰ð� 7 &“3e%¤Ç€f„ m"ÚVúÑ€4K$r¼|‹ËgAËa2�¢è=Rö+ãþCDÛLÚF�þÒGšÁ(´ auÖb6i$â3ÊuMCX]›aeuЦ�¢‰­:º.bÑ58>éq<ïp²H˜/}Æ¢O@`4Ae�ÌHiô'ànJYJ€9ÿ7©z€k…ü©±:ÀÏWŒ@l�À ó£óÄÜG´¡Å¬m±6k€$Î^&…¬ñ(æŒËªâ)­)Jœ+ «(açÖΚ[ú•~b¤«c›´# ï¨{MÐV–&¦,ÄîE IDATr Džv‡Ì žÁJ¹uØFªÊ?‘F[›ƒ*°4õŒ±‘¨n&Fʃ¬2 Ò$~g!ƒ3ƒ1ˆÎ`Qß ñ܉(!çRbÉ"ó‘�DYd.¿c,Éùðh^ud³Jv\¹èY5^hi6y–è²%s ®Ó’g)ÿ3cx]–+zÃ@™�‘8˜ÈÉ~ÎL]ÊYôœÒä•>©ÔÝætŠ;HŠ|LÆÊÅîP=Ï?}0®®/àjõCOɵ°\ÏÍžÍJû�cÙ‰ôÈU¡YÊF<ë�È›C‡,N”м¼Ç‰î±Ù$X|×:�?ÝðO22ĸœ+…Ö‡ÌæØ‘ç“•°RzÉ9T= Ô‰¦ð0]‡+¼pED—^âlYÏZÑw­”jNK`ÁÕnpý•ï�†ŒY"ë3tÀ` ôз›ý¨8‡K¦ß�?8F¨üPÔ.¡ %c@2TÅáIü•¡a`Å‘-D~ªœRª[Mg’郊3Ð9»=PhóS¾nv¯LPŒ�#ßq�°©bWAØ�ª^یʆA?½gpJfæ@õ�ñM¯ûZÚ¿Lª¨�ú‡ì�¯]~œÁ«v*x~Ûx¹nô·µ� ºÕïõ÷.mVcÓhTŒ8ã© .¿ê{–¯[çõ^gÝûz×-?÷Œé0–Ö¨Šƒ±|ðÍ“-” “`Ü`iTJÊ‘²GÓ¯œfsFjו1ö³Èl˜¬JÀˆBØ4ÁΔhü6F5â Tíyå@:õ‰ê Î·:û劑õoÃG+V?z�þD=£h®þmÔõÚÜzm0®ÎW=¥Q3é1®�åOp§ˆáU„²�7ü¼— j.÷êýã}/!A6®.IåÙú·Ô£g%c"Þöƒ8ä�Ñ Œž%úŽƒ*ö‡ —}#_;kæ�¢šrmä?E_ë/lÁËÑ3]»MÁ[3O%ýŽª’íIÅ1W1_w ø��†H•SÀ2,A‚¼L6çG’š…‘öP{öfsl´Â�ì6ys È¿¥~rÒþg²ÙÚ>L™c€;HË’È’¤7:“ AsfVFZ)ðóÍ•ÓS?ýß<¾¶lˆàNÈUD)e+g,KÀ#&$•»ÕA™0Ê)µqÊÕ=Yñ;“”u±ôSÍÈúùŸ}~ã·^|ruc³X'¦è×ßMb=¸S WaÌ®=Ü�w^(³ÔA¶@€”6h*šg=ºœqûd�GÖV0%Qôþàæüµk—Ð*$°¤œ€§¶ÖHšyÞ�w¸²2u§Á'îÜÇÓ[Þ³à•Ãc„@xF3.̦˜©3¢Ï+1âo߸�ÿü¥—ð•£#Ìç>ôoþ üƒ¿ÿ~üò/?k\ðeôiÊFáÇ�SÕ·µI›PÏ�÷ë=­_²g[(É¿õ€;ý\~Ê¿�˜ªC f©CÎNï+¢Ì$ÙÚ��ŒdHn|—�ú©“ÖT²t¬§âİ1Sò ¡Ê¹à˜§ug©Áœì=d ™¤>{ N8îæø[ÿàá+/üàñv‚w¯¬¡eÂJ#QÚkMÄbÒ·šæA í�¬ø´‹Øšu˜NZô]D1Ú†°¹1ÁtÚ!Ä CÆ0&,FÆrdŸ-prJ89pzœ�gÄù¨' bLHü<�GÖÑbÞçöœ†ˆGy£À;#£ Œ¾gÌO—8?‘Æ€€]è0m;,' ˆwZJºnLIeœ@Qiž€RsAŠeFMy–HxHF•®ËÁMžµ¢Ž ” IýFg kºF£@Ú•b$ed0‰ãV‚8ÃHÚój’€6 ðØ}GÓì´P¼|ˆ-!D‘ÉÇœA,�Y�‹JvÌ”óô%FC †*É+zŸ¶ܘ¯ÑåU!â’êf•„Ýp^¦ûFä± üŽ¥î’ë³µqµ€s&JšJQMLQ1*™Ût63ÒÏ6p@}na%WÞü ºTß«¾·ë£´rEÑ׫‹L‹v…í\¬½.¬+�Á›\“Exåt¥Ýë‘€E ¨ª.|# ÙÒ4‰ã‹Ô�4B‘I@~¥qåY-R@S i?ËØÈ+�yì“g1€ƒ¬-ud×±epŽ `*›çÌP#ô"O±ÊGYmŠ’¨Œek¢˜—Ü„Ap'C2YcmZÖ#Hl@KÚ1åÎú=kš¥¬vÇ Æò¬f Ĺ¡¤mv &¨=€Pñ*çß�vñj? 0`a2ù&ã¿1}œ´ÏB,Õ¤Ú@Éö¥Ø` P{�èûQe7Kï|‘øÈ昭Y×ÃÊ–!p*@MÙY)¸.7hhm~֦!mFI�+ ~äâ¦\'fï̃¿;F^õ xæÊa*»Ø¿PˆrŽmr.B‚ßÓd8¯2¢‚žéÝd$*VƬ ¾+ëIwËO»~ÝT ¨çEç]ô ?Øôw¾è„êº/D¨¢ nf¨4m!¸N”¨zê#. ¤™ìwì— Ü¶Z¬Àè:Á´q²10O Ö×2æÀ&8°Ý¬Øþí±d�ûåõÚXÑ7°:U… Ù_.¡]+ë»0¸úÐʲ"!Ð\Ú9ëKµ<µ ãøìkßÓI |/R�ì©•Z¶8ÀÐq0¼fÌ~:ySJÑ},lÿcPÖ0O*Ýæ5Ú 0»ç:0PSŠ‹~päݘ¢=?)Æ7&`9B�L2ad¸¯œY_ ±Ué¹|í9V§ÕÇe…þTëAwœ{Œ¬æüSZˆ¢�Ö`™ >ÂðÌaÌ Šˆš(a^r²7³5ÌÈ\€!õ¤Ôhb�ªxè3ƒ �½$è¶@|_UVTÖÍ#m¦ B0^‹5fPÐ'R]…)ÙבH\À€€nÙØào^û~½d#}A¡ÆQÖ¿95˜B”&Eés`xÔ€ô§º©i‹ÄU-}“‚|!‹°A¶æðcï}³§g#>yt„ó‡ZêÏ™el5blù|ŽëÓ‰Ùýå€�&bCßhô³bà�D"Ü[,±Õ¶hõ™^<›ã|ñ¤þNDXT¹�~ôá«hˆ0Oþ¨¦&º9_àå³s|ßþ®÷㋇Ǹ:é\™zíÆÌ#xÔÁñ8âÖù¯ßÚÀvÛàdñá›wñîË{¸Ôwø¯Ÿxíùçñ铌cÆø—~/½p‚Ÿÿ«ï–õë†s8ý”Ôg„Ú»BÜ…lg³ Î D.tZ'ºìƒêš¹Bé\VÅDÒip¹¶Z—¥®GµNêèGCàà0à‚¤êÙ¾«Ÿàê¤ÃïÞ¼ƒÓ1á—v±ß‹gû­¹€Oß»·ƒçŽN�™±HYÖXØnLcÄá0â¹£<³·�–†¿}Mƒ÷]¿Œ¯Ÿz�}hCC’É÷Í·OÏðºÍ �#úð/ßÂVñ®Ë{`"ü¾zìÿÀ•}ìv-žWÃÚárÄFÓ`»mq–2.÷=>s÷>¦A"c>zë˜oÞÝÆc³)~óeÉý?m¼mÇ£˜€—Î 4!`¿kðõã#žÚÙB¾txŒEΘĈ}ø*>s÷‡ãbƒÓP0ã•óކ\Óú‰�Oß=@$»®ìã['§¸¡cò=[èCÀÿ}tˆ�‰'rÛDüô¼D„Q‹[ž{W&«5C$9õÈ€ÛiÄälŽÿàêUü’Îùïþñ×±³9ÃÎlª²€í“:bÀRØ ¤žäúnv ðFá'ÆͱÀv©*‘jÊFdí*åy%� }@ Ž)/ä†ÔWÓ6T· @ sÇØ D1¬1T>BOY•2kÊ�1�³Eì6#¢Ð©œ2¤`¥7u‚äåg¶”FªœfyHóÀ5>”Õ«,ñðƒA�œ×cSÔ %,¾‰IRQF‚€{R8QòÜ»ó) Q‹ FQ¼ôE&•|íCù„!i"ZpˆEɾP¨‰8ÜѳDž‹pê1ÞĽ"[z€M‘óÔ~©8·8XˆAþɶCO’VÏh4DxbsæA€ðÓúõÇêí߆€¨<Z"<³·�ÏjAr@@ñyÎ^Œü›Ç§uÿE"Ü™/pƒŸÚÙÄs‡'Ù÷®Ë{øæÉ)^Ñ}ž9c©OÒ‡€¯,^\Þì1m"$:Eç/9™#™�3<­�xp— gWÁêl4M@×Gô}ƒ¦‰î‰žS£|„d½çN¥ ¤hŽ+â¹kü¹k�®  L¢{dO÷ÕFBߵؘ´Øžõ˜M%j@ê 0ÚHؘv˜ö4Äc" ‰Tg6N GÂô„зŒ.&)0LmÛ�B@挳S½ái©´ˆ¬Xw£TB"~˜²Èá NH o7]BÓ2ú6bÒuèÛNÒ‘¤ë[¬'P&ŒCÂ8.¤l ì†N‰¼‰1#åÅ–B,™,/iCÎ ¨Øï{×Ò Õön1”I]„„.tM@×IßBP3›`\$‰`º:ªoܘ²úȉœt´$ê£ÐhóØ5{RˆV–ŠNÉJŸó†¤F�Ÿ‘£DšÄ G±'¨¬å^ÇY®Í¹Aæä¼`Mý†yÿËg=ÅɶsLÇ´ÿÌ€‹Âsìåz¦}ÇÚËÚ1ùµêO݆çrÿºf$¯¨¯d5ÈR–P<³ªW÷£’OÁ«çTt×úkãµòt…©W¼ú�'¯o¼Ún¹ò�çYÿ.·3·¾GÑú]¥­]—"Bg&D’yµH~]„Îß]%P#Š¿- F'È�{å¡l =y„B©Ë*Û š|duy@.�È:*V׬vï�ò6ß@é¿^—a�”�€xjІ±>õ€¯òjµùù¤Ù^`+éWî˜�äèôH¦Sëë *ƒ^c€­8�H3õ~SÙU�V}}•·Yä Aí*ÿ阘|š²€Ú&/ÄLj U{”Ú b€‘¤øs”öÉP9%µBõÕ—`FŸ\ RÞX™�\>·¬ ÍÚü¬lRÿ[b5ÊIDØù h«7° ·]pÑ9ôÃ¥JvÁnµŸ(íÙsÔ]z5 jJt¨Â4ì§Z¹.GKçÊ*Z=~Ñó¬\ÿ�~¯—4¯}¾èú?é~ßéÞë×­kcöåw�þú™$·™žgÖa7²1 ©� 1}“>¯7Ǻ¦„(é© ¤Ö5ò¾éø>‘6ƒn.{Ö>•0)#k€@ÌbHY‰¢ /t…µe"½Ö7†­g#E.§h;æåmY¼¾ÊÔØ=Š]цÐçÒ=t<×ç¾ÚŠþ0+󪿛Âcé Y½¬ß6üTÆ£fÂ;¸äȸ�×÷¿(ö«GõþÚ(W¹¯k6ãë *Ð(tï�zØ+cš­€1‰ÇÏ2‰sìX° ­4²ÇÀõ ƪÏrÁcè (ÄH</Ú³zfM.Ëaé=ן†ìx¾M.*fXî){#j^äœJ`É�šc�º6©*üX8b2pǺÄ1áŒ6�[�«BÆX�…ä@Y©XÙÂmQÅ6°¹ô+H@Ûš0âäÓ[˜¨õ´6°úázVüÇߨÙ�Ó hT@�cf¯éŽX�4¤]4tp÷ª•tP zÅV-qqsX I)eL»öÇŸÀ¯þó¯aÉŒ�ã§ö÷‘!ÞóÊSðæ|‰‡¦½¿6éW†Ìj 0JÊ óîÿÔÝûxÛþ®ä„°ÈŒ)3ZÜGfßã‰%Ïíwmm¾|t‚×nμfÁó§çèBðH„½¶Eš–ÁÞëZüðõË x±Ù4xlC@„çŽNp<Œx»ÖX¦Œ—ÎçxÝæ D„ͦÁ;öw±Ó6Xˆ¥ÿÕOào¾ø">tpfàþË�á _¸ƒôßÓ>®�?ÁÖIºÌ‘äÕ6Z£ÓçtÕè/ãç|ñX›ÚV ᡦ%ƒ™B4C&¯®G—W*Âëç@‘=*Ï`4>C=¤õ�ydä!{1zᯚÁS�aŒ!Asmj~S£¶�¨Ï6Šû6§¬FÔˆa$ñ:2†’²m†DsPp’±�O}ù øï~í×q6—Ô�´þÜÆ6òbÄC»lj>íÄŒÓ1a³Íxt6Åé8âê¤×üùo»´‹Í&âw^¹� 1Ô_ê;|èÆœŽ#6›oÞݽ…º@¸3_¢%Âå¾ÃFÛà‹‡'8¼ý’¬£Oß=ÀÁrpoÿÏß?3ãd±Õ48Í mhˆp<&|óäOílIþï”ðÑ[wq}:ÁO>| _=>Á+'rï÷^»ŒT¡ßË”ðÊ|Žë“ n/èáƒ/ßÂF×à™Ýmd0þàž¤õxç¥=´�ð1 ÎRÆU�šY,3¶ÛŸº{„Ç6¦8FüÁ=É'þÖýlt-~ïæ]03šðž+ûø„¶•™q:Žt;|xŒ‡¶føûjÀ€û¾7cwsSæ\” õƒ[å]º|7&\ßßÁ�{‡øârŽ'7fx:6øÁím|ôèCJøÐ>‡Ÿ|û[=²É¢ÚlËP1`7±½ZœKjùÌc^Iø–§w@ñôÈfß:ê©ÆÅ0ãž L jb”ôÄZ“CŸW½¦9ˆÒ,¹í£z� &û…²T¯LLH)yTMN œµ² Kñ@¡9Hº!s0 H1¼¬Ñæ5'�©ëd ÈcBNìi•Œ¿f�×Å8M!"†ˆ&²ô5' ÊÇ¡…)©‡±³o‚;¿Ñjì"i$¡�Eâ„!IqWK'Š¡EäèdZ%xt"ÛŠ3ù¯¬ öçð“(TÙ‹TÉ•¢oš(Òg]ƒ¾kÄœcfŒ9`ßuÌ&„Ù„0imLhÀ–€Ø6ØØØ@lZ0€ûóÓ,çK‘ ‘¹AæFêq¨¬J¤©•€B…€IΘrFÓhjœfb¤o°µ9Ãl:AŒR' �À¤rO‰1ç”ê´Uº-ÔKµ‰MÃìGS@ŠâH¢BÕøæº îe\]f6£ëeôaÒ}Gè» )…àµ�RÊú0„e�,I݆1Y„‘ÅWˆQ/˜/»E“­½¬…Þ�æ•}B,Q `&‘_XÓ–¨ÅH�_Dœ­µ”Ç™GŒ<ˆ«0C«Qrcn1U‘;6™!¯ŸfDµKv•ñ<Ñ/ õ *£¿¯æÚ[a¬ðPŸ·5¥¶vz±IpÍáV–Àêõì×ï_ëÄŠF\l3+ XGx­˜óU6Ü:_·^Fuµ6FÜ¢ê£}ò,+¶Ä×ÞÈ%²‚ÌSÜ<å›ú›«¬�z~¨D]�ÔËYíGP9#À@&·H$2Ž=K£+BžÏ"j„Ô®�²NW@�zì³µ-@±ÛX kHÇÞå&ŽÔfTA5ÈdchB\†­0×›.¸ÆüŽ‚é>\TöçÕ ö�•-,�§$6¬ÅM¼lê•®K¶±ÉÚERp[퀴Ú6�÷ÒZ!D>>¬ôe0@Ro  *�RÖ=%A $ÞQÀä¨}G2•«Úw¨ÌÅà(Ày¶5 ¶-u(,Ѷ�¤²’Tó±Áóý\ Cõ&…v1ŠÈ—Uã­´³"5­¿êÝHÅ6"Â!W×r9É>×4c}!>ÛVžË‰%:@ 2¤k¡ieó¯vZ=Í' õ�W{èWùZ-èÿ¿¯õkiýg¾è0.˜í긎 á-°°òûƒŸmžXâ¡E*„Epuz!_ö �T"쾯1&ç-<@Ì8‹’ä}¡šW‚=‡–ÒÖµQÜÀjy_eÈÉÿY[T}_Ÿ®Î’ßk� ŽÅÑYÚ•/id¸ViU WË�ªÖ©:oeÜVRÙ¶Sâ¯áG†8¯ª¡ã¡(« mµ€„2p`e[£ð�Õ�ÇBÐ�Gpõ›}5OuëÓ3pÅа­¨ ™!ŠÚ0B½UKŽÀ¬Ì4q È èd°2w{vøçjxPùù¯\g‹·†�EaÎ2V…¹˜Âo½Œ‘îm] T­ËïoL�JC>îRG˜dNia“2,‚@=ùÍÒ÷G��¶ hÚ(Ê‹sÔë‘’®ƒ\,÷P ˆk cmøÉZÜ�t`-?iarÙ×�(³¶lRj#o5/ló£† ¯»SÍd9® o& *m² *¡ÌñƒŒ8ˆjëh�PSù˰�'B'£¬¿3~ƒ2þÂO¿¿úÏ¿ø­ƒüÔþ>€ÉZÊ 9£¥àFþ{‹%2àiz23æ)c§ºö�—ö.lëuû&!à­—vñó�=†ý¦ÁÿrçàŸþ³çðµ¯à×~ù§ðÚG·ËdTel-éñD+xT@—ETJùœ³¶é! Ü Eç:'@ôw… A! ŠÅ«3ƒ½L�S ‘ îLDñ4Tº¶HH0ŒlÀ!d˜G-tÿ�ƒÅC—ÔA˜³ô)ªR ÞsÃ×À’¦m±±X&,–ŒÅ`‘Z„å  ìb`üêoÿìóJ—šÿù£�âÎÉ9&�çüÖÉ)ÞqyÀ½å€ß~å6®O{ÉϾÀó§ç ?ùèu,RÀ]‡ê•ó9^»1Ã�Å»mƒ�ܼƒYñî+ûÈÌøÄ1ˆÿÐÕK˜5¿ùò-0€Ãå€�¶ÁfèZ|îþÚ  ×VÛàC7ï 1ãí—öpmÒãC7ná›àšzí|LH�ºEÐÂëö§˜´„¦Ñ´²”0AŠSשa²çÈjHa×ÍÉI@� mCh[ ë€®ct�¤Ì‘ZjËAŠÀކ�0 †!cÌä ä`ù�û®E×7è:Bײ“Õã ÓŽ°5m°½Ñ`sÚ`6‰˜t}ÐDB×LÛ€®%h.-ô $ŽÈ€¬iæi Û76Z\¾º�n2C΄6ܹu‡‡FÚÒئï2¤½Ø@Ó+“œ0ÍÚ> íjh¶7[ìl÷ØØhÐÄ„‘2º6aÚCŠô&OØ�ÞB Mû(E²c”{Yú®@¬…¼ÅÐŤò»*B,…+•lû;{’IϘö@×2ú6y0 L)†1c9 b cv0Ôö´ù"$­qB"ǘÑ6”´²– Æ8öÒæBï"$¡!B¤ŽUCbÍJè9iÚ—Ì`� “ç�NÇ̾ïáJI„Õ�öSI“¦aâ2pJGh…®¬Úè*Úæ—ÑúÑ œ(—\põÚKï«úʃ×knw®{[÷Ãί‰ê¯µ]÷¢æã«Vú‹zºBhËÇêFÖ„ÿ­e†êû\T1WöÖî(sHU×]§ƒÉz®òÝ¨ë” |ÏÓý¸Ì\‰*fÓ‚îOƒ cRN,Î¥Ã>õ0s½;ßARüÙØ›=š ‚’®ªd:à2Vÿ )“Êœ¬Œ§9ÔêÍÄ^ve +~¯ß 0›\qj••êæYùºÊ¼vµ/¶þ­­-—Å ò˜>”ÛElwR¥£ëËì>f³4™Ï’ÌØÍ…n§>"*?"`42ÁÓÝYú¶¨¢Q&FP>2#$BlÖÄl,kùÇ>+=& Ô”0š�¢-”Y�œ³ðM†F °Nªý%Tö†jFWã3Š!ëÁ=´öªÄwB¹åÊ=L�voó"L¯ög…úTÇ+c!Ø•.¤ f,÷ªßU³÷×)ÑÏúäÕÈñúó|§×Ÿ8àÿ ÷^|WN3Ä"\?pÜæ*qÚ#N ž«ó×iì®XRn‚åò`hW‚§(êÕ¥ŒßŸËºmDçáu€‹2K?\Ø)ÞëKr,²çwµ‚%©¾Ô ºŒ·’ÍÈà@VfM¤ùÕÿ­*LpÖî©mgÇŠÐVV?–hN:r”H0EÔ½YæÀÇÇ”C¿çÊ`éüi9,cNÊèëôGfx«çÔ¶³�Y5/µ@Â¥3:;2¿‰YRZŒâm”4äŽÜ;0Yº› Ocã…{Xh ×÷6c9”ñ�.û po íz=&% 26¨² ÏŸœÙU4ÕÚÑ{1°¦¶G¶­Iµ¡óé €Ì�M !ûA¼»\’v‰1…‚¤…hšˆ¶kÐu�öœã0b!ž”êQhu d]«a…¤°©ì€@JìûÈ"#lAY!S ”EÀÖBÉÎPÝ`˶xQbC¹2€b}ó­lŠ�*­6ÛFZÄðaϯcW‰¹©iYÌðM• ‹%rÀï<}EÐî¿ÿ=�âú•nÜ>ÃçOOqc¹Äõ®óŠ÷—Kìu¥ˆïÙ˜°Ñ�F÷ìW…ˆI?`Æõ›çs\šô^Gॳsd†{ðÀÓ ¢`½ÿúR£ iÝ�oŸ�c1&7ô/RÆ7NÎpM¼y{M„¥"yçe$—nÍ~íárÀïݺ‹÷]¿¢Qäyçíõ¶ý]1RçŒç üåë×ñDßãï¾ü2f<û¹›xÛûÿ'üÒ/þ(þ­ŸxR†˜!×s-¬kôÈè®ü,*Äyš² d§±¨Ö„yÍå‘�G£ƒÙVl95ˆ2M–X—”†¿!+àh,¼Òw8��u-аkôËö½xÆ@kû'#DBÉÁ+Ö{ŽYÒH�/3æóç‹ó…x)è;âå»GøÛÿó¯ãËÏËçìíøáÉ&ž?<Á{®ìa¯ëð[¯ÜÂ"Iý‹§w·=ïváxÑ7×§=6›_:8ÆÁ0àí—v°|ñð·æ <4íñîË{øò‘ã�Ç„·]ÚÃñr¡ „“”ðÒùoØÚÄYN˜§Œ¾r{]‹<|ß89sïÜ÷_¿‚!—õ6ä„;‹®O&xé|Ž-мÙ4xzwD䞻ᄇ�Í&⃚ûÿ`ðÌî6¾¦9ƉÏ�`ìtâýÿÑ[w‘˜ñÆ�-ìjCbÆ^×â®ìãÃ7ðº·À¦1º§Ô+çsÜ_Jñ⽮ŷŽÏ=ÚáýׯàK‡Ç™q°ð={;8d¯Y{W'þÞ­ÛxA£,v7føÑï})gRÎ /0!³%—i ¼öúe|ü‹_ÃQNÇŒ#±Ý6ø…Ç^ƒÿô›ßÀÀŒîÜÃ|ýy<ýÚÇu?ÙÂ^RÎä)Rñ³ZÏ  x<Š—¦:žÔ^B¼Åi…tÙîªïb(#¿×AdÏX4�6¦„Vx;c3Â0 ä1$ä�…ïFªÒ ÉüKáÔFøcÌêAA–g¶³æ6º }Í&C–ñ1™‘\! ^V{©ö*ý0¾ID«+�!QHêèDAŽ'c­Ð1ê 8É@P)B"'f1&¡’Þ°DeÔ¹ØM $�§. ­�P ÀÅ:d+ÃFÀåîJr„HXY_TÍ7WÇ<àÐÜB\L£á½sÙÃß?™¡�Wº¯ha^LØ^ßÔ=ßG‰d8×4¢“ðäΦt€Ô0`>p f™‚-Þ¸½‰?>,‘o¿´‡ÏÞ=ðBÇcòtCpã|Ž—ÏÎADx|cŠ;ó%>szê Ækö&Ø›Š¿kISeäÄY:©ÁAAÉÓž%¿|Ð6@Û¨|€&± ¡im›Ñ6#º†ÐFÛ0Bãke¹ X,æsž2CJ`6ÏiY+MÓ¢i1°oñ<‚0‚(¡� 6&“³IÀ´#ôÐk»FÒõmºtÁ×CæÎ!4ˆ—óS`˜g mÂÞV‹ÇÞÃlcc"pNøæ7[¡…yDæŠ J6‹á¦m¡ãд“<`š2úè7BÇ 6aw§ÅÞN‡� BÓ ˆ!aÒ%Ì&!hdð2#Çì¢m �§  ÈG©;�1ªÐ!À%{d²È3ɽ¨èWõ¿V½‰RÏe:f �md4M@«Q ½œÌqca>-1–±D?€`º›ü{ˆäÝF kXî§‘"”Xë%EHtFIÆZ£VÚ(^½Bß5×yâÃ?srd‘pÞ' ­�ˆR�àªduýÔuœŠîT |ëŠUzDÑI� ®±ÊKƒ4ËE”+¶iSôN*­¬“ÔBñª;g6\ðwíîú‘^íUÌrä:/ÈMâ@e˨ժ‹Æá�H Uûj[‚�„µ—Áê, —ýIË�HåˆbV¯=õk7A}î5OÓR½£îƒðMiÿ�íž\¾fÑ©“Ù«´c…‰¹¨’PG‡Y elµŸ¤ãU·‡êÉÅp^÷¥èäçÛ°–ÆÝ§ž¥'e °_eŽÖ×Pͥϭ^û`KÂs\p¾ ¦fíØŽÖM_†øÝÉêeÿkA( jBYúa„ß<�$¯š�,B‚…�»½LÇê�08‚oÇÑ¿eª�JÀ¼©Š‘·¬“2Æì —êj}WìÀN¦U¾¯\nÂN"õD^[²&ÌÁ<Ÿª‹ë¨�õDz~r±ƒznÿJ¨0pAèµ1ªø|Úü  F\3–³µÌÛce¤%O°��ó=€•!{_Ù#@ðT` [GE™÷ñ^¡ZìÒçQs][¾kI�`‘ð˜ÞA”¾É_^[·Ò^‰¨úç§ ÍÊ¢°Ï�݇_ÿî5Ã][K¾2ymK²0r]r6–ÆÈÄîQdûˆˆsÐ0:rƒAf �#X8­\ŠêÁ`ÞüŒÁk´,éoloH-2;£ÛÎ3¤Ð–#b&7$€¤í0€ÂCŒ+Ï(­*ôÁ¢ŽàÑ ¶ð¬8¦Ë8ÕÜ–AVñ#“Zšô˜%Ä…ÕÆ 8°è@„®Y7ø³7j!ÖñIÉ¥9Q(Þ„žv‘ðçÿì“ø»¿ò90€Ý¿�¿p횯Ã�ï’«?3ãÿEüýÿý_âô\<ýß3ÝÀµÙÿѵkø�·!�á`ðäÖ&î-\ê:üþ�û¸<éðîË{èbÄGnбýG®_F~ã%IuóÈt‚ë“�¦¯Úh¼pzŽ�ñèlŠË}‹�ߺ‹£aÄ;.íârßáƒ/ßÂÀŒÇ7føÞ½|ö®xûŸ� Ëœ±ÕDô!`³mðõ“S #žÚÞÄ´iðòù9nž/pmÒã_ÅŽp°p¸ðôîî+˜A$ùÂ�–^·9Ã�Åáÿ|é&ö»oÝßÁiÊxN�zï»~g)»goÖ66šˆ£aÄ^ßác·ïa§mqyÒ!yM‚·ìnc£kñ $6›oØÞô"§D²G[Íÿ½Û6xöîÎRÂå¾Ãn×âþrÀ�Žð»‡’Ó¼‰æû¿1Í�W£ŒqÉašœŽ3b`LÚ×vwp㾤ú¡éÎRFš/ðŸ=ü~ñ¥Áž{ñeLû ^síjµqV…¡ÉdýÏ„u£³ºžxZÉCM–÷Ú´.£ó•lëŠ>kˆ8gJ dŠY-X®^(ÿË,^ô!%Ð@ˆyDC#82š†Ô»uж­F $4YÔc¡øRØ“U攑5²5TŒ4âÁæÔ`.‘ L!r²fÆ*ã‘‘�ĘÆ x�XI="žÿò,y—I=D®&˪Ð&NHP` cJU¿kiŽü“-OEé^Ø«Bf­Ë¬Í(Šô¤wP–-僥cX_vîM sá@÷Þù9†œ±"¾»›`LÙA��&âtL^àÑÙ·KMw' =Q9{Ê @YaûöJßaÉìé¥I�‡g|NëŒÌ8SõtðBê³&¢!rào·kñt•nˆ™ñÐd‚í¶Åß»ußù™ëSì΀®%LºÁâI€��0 ’)/§yO&ÀdBèÚˆ®m<=CÓ�{�ǨìA º]`´-¡mI qTZ.ópÖ&œ5I£ÐX�$1‚€D ÁÏe×£Ö �†½–$é(/±ujUqWÖ˜sˆ8HŽÂ£Ãeò}ÚOe1q½øô:GËîZ½/=pÑ¿æ×…Ô²zÕ}[£Œbÿ_Ÿ«žô‹EuÜ*´­,ýkcm=#¸‘„PÀ˺ÛcˆWs¹§£_¤DS-‡R˜W�®ZˆŸl¢º¬V\¡íeìJ:"ë°Y:T½Ò>ÈßúÜò§&Û>:NHV8&e:ND �ýwC†m{øPîŠVzd Rÿf®zö­©6K‘ÎX�_îoçÙÓg`Ïz+øÑçñË¿ð¼ï��õhKëÄÔ ·€K&×èœ*Q¶}o!�&¸;ÝU�œ´øžyÎUçÚò!hʉˆ3¯}SEÞQè`C£Ì{™ƒÖ1Ò˜µ¨hÖ\ÍUŒAÛ—}›€uGXaD‚‡ÕKžiÍÄÎÁC€™p––£€ËRo`nœâ—þÅoâ“_ü’¯“·Ofxïî.Þ8›â ÇxÏÕËèˆðµã<zŽGgS¼m_>:Á­ùw üä#×1föH–1gÜZ,ñÝ;›8O2N¿õÊ-<4�à}×.ãxLøôÝû "üøCW02ãÕwžNÇ„k³ ^9›c£�xöî¦1à{÷vÐÅàùﺼ‡�¶Áo«·ÿ~×âÑÙ7ÔØ’ºm+9¿CÄ'îÜÇ<%¼õÒ¶š»u#3Û˜â½×.㣷î"3ãîb‰§v¶p8H[m |ëä ÇcÂ3P Ü9Ÿã+‡Ç¸Ôwxÿõ+xîè÷KÜðã_•Ü䚪ä›@QË *0g¤<à®æöçd†�®Å™îÁOÇb´±\þö2O~óØÿÖÉ™ PoßßÁ�ýúE^�Œ»=_àveè?|ûT@„§¶7qs¾p`òrס äé‰NÇ_:\­YðÉ;÷ðôþžUÞ8kÞúس‰ä‰Ÿt’‡ŸÀÈ9`XõŒÈ 47¾«gj­uSÎÓh9ÿQÚ²=”Ýâ…²ÈæÃÖ¦í»sŒ#¶uÃE´‚­�òW^¡;µUغaÙ£AS" Aò¦ÐÈIHT{Hվ؃HÒë0ùعÝD÷c– «�“ë’eˆ B9 k>n/Eª€;±�¥¾©5$2”̸٪$ÍZ™$©ÇMÙ­Å$ÕщÄÙeÔD& z-©ã(©ÜJ�”Õ¡D  ÏmCƒ€ ’Ü@èOƒÛ<˜¥ÖÀH’ÎHZÔ©ÅbµÆ€{HÖ› eVþ® OeæÊ1_€ÕËåhG|ÖwD!B.\)�©í#e!­ÝÃûY„º•žVF1/NUM"ȼúPSëÕ—mÄ‹pÁQ~Õ_×é"]|ÚÚ‰ëí­·Â¯Ö‘µë_õ„WéLEðŒÀÂÆ“ü÷rÍõ2h›,¡¼É„*E@k¯.ÎF,ê“oüú]r×"£eï·ÿ§ë¯æ?Žn£x>h¹ðµñ)>EüÀPÒÃËFIQûÎ+SiÇ|­†âPå¸.m˜ñ§^Ê++Ô÷‹öX‰µ#ä\B�x˜C|aå»1í\wo/›.ƒ¹äàÞ´füuã¾u·šÃr¼e–[­ÌÙ³t/ø'³(¦Vi>�¦Ö0zgíøzEyÌŒqÌV7âq/fõ„³¾3ü÷µI¬�<7)3p‹µY£ –‹‰ªyÈu#«¤Žëï~õ*¹6¡,mŒžA]‹¤^¤lZ�€Šñ@ŒâU™µ=¶cˆ± ¥(ž¢ÊT­G¶ è_ú5;`5„æÄâ-�ìJ 3#ššÅÓ“#é˜* àS@ÎÀeѳòÔûÿ{T�}.,ÆiòcƒMæ±-n»îm`|®¤‹€¡ @"³ä~–VIöu(7rú&t°õ )®Î¬¡65ÞöôU<ýÆKøãçîâ…Åpr‚7M§h«¥i‘öŠDn\ñlŽGf¯çOÏquÒ»¡~Ö6n„Äph ÀÁ0`»i±ÛJ[ß89�¼¸ð˜÷+` ï½~Y=FÅãáMÚÖÝÅ'cÂ㚪èåó9¾txìé‰Â4FtU”û¯*l0 IDATH±å£aÄÁ0à5³)öÕÛùã·ïâO_»‚�F@†o��£ �mLñß¼öµøoÝÂ?¾u ‰ß|é?òs¿†Ÿý7žÁßü¹÷âòÖÄ£žÌ+^Ö-«rj‹Py\”Íf¼(ðiЬ†Ì—¢ìðœ–ÅÈjô°¦1\äš |/<�|Ø~.ë;]KºßF"”0гðkm313B,…™1 tR±·ÚC–C~`Â}÷>î-<¹½‰gv·ñÙ{‡X¤ŒûËÓ�ˆD@¦1àåó9nÏ—xÃÎîΗøüý#<:›à'¹†Ïß?ò”?ñðU�ÉùÏ¢ï£F œ�adätìÃ0"�É÷ÐÆl‚Ùl‚¾ïÐ÷­l¯  @Óˆw~мˆ™3"-±¤ui"bCnÌœ4óц]Ì8_Ì—c& ‰ ñ-V‹ƒ@©D³äJÏ)a5Bƒ1DD H$PÒH±ãN€zÌkªINI�Š4Ò/� –T<�¤>B׈—<É.“„FÖ˜DЋÛ~M�Ú})‰á*%PÒ,F-¡ï"¦SÆÖfÀönÀÖn‹v“ú„9b èûŒ0%4ˆh©AK-ú†qv>âlž5]W�7Ë1!å¤:“F‚è m ´ÐBKAãˆÀ]�1¦Q åêeD$©{¦�¼ÛF”�F 0£ER•ODbäQR q̈Ì@Pš‚€‘’…¡«W!I”‚�¼§-a6 è)¬!žÙ”å¯ñ‰PN¢©(>*­º ©c r� ʶˆàdQ2¤N¯ ¡åä)FÍÌPéFÎÕ4ÚLÓ‰ /£^Òí®ëÚJ�Ö<ö�"+V~Ò+·\•3 9ÈïQôòbgÉ¡�ÃU[Y !µ<§s]kuÊG.#sá€%`}_TúõÛïiOV)O”_…Lj¾NØj•�<Ú¼~ _a¬è¼úÝE•̪‡[ëäöËՔײÇêa3=CjUQ5º si€”Á�gÚZ/vUrµbå_ÒH;MCkr‘ˆé!…Aëq{^a¦¼2;õ³­ÆãÙœyö[µûF¶h¬õ¨ÀÂß×SmÕ³X¢VÁ�h)N‹åÊžR¶‹ÇV¢EÖyý‡ R£X @¤^ÿÖ‚{+j´v¡QS‘É ù‹Á€¸Š;�*­®ë[¹#ì˜=ÚWR ùX1YŸ2Ð>tº¸VhØÚæ©'u}ÿz[\<íê9S‚f{³ÿ…•ºÑ®jÖRÖP¹¬\Œíy`^ÖPf™¹6oË ãÃÈÄSÀ8QÞ2i�@YÓEø@Õý•m}0 -'+7â 43ÀA#X²-|¼ ma]Ç2¼6”ò%³9íW´Éû§cª)íŒLeª„åWæEèü’X�þ:>öf3sê#}I ”ÅCðôF•‡yp…”%̛ɼ8HtAÆìçþâ3øOþÚ‡ÿÛÝ»xëã�PÃÌ+‘ÏŸœá 5Üâ©[¯:û-1ãtLØn´­”)úÌÝûxGUŒøþbÀ$FLt-?¾1s/a@ »oÜÞøÊÑ ^¿µ�^=ú?}ç>®Lz¼~K¢ Ff4UÍ‚ë“Þ‹"ß8_`·k<ªás÷ÑÆ€7íl!xi¹Ä7ŽÏð�Øi¼yw} XfIð¾k—H­„yÎø÷¯^Å»¶¶ð‹/¾ˆoÌç`~å_üþ×ýg?û�§5Œê1�\3åÌŒ‡h8R"otžšL<Ž óH«*z%Ýs¡ÓÈfñòíT8Ìš��8•“88°fuì{ QЬT)@AâH(K-�”3b”ô9ëÚMY#_Ê8 H ŒãCJ„¯¼x ÿð_þ¾ôü‹>¯{±Á�ola«m°ß¶¸3_âÉÍM�#"üî­»¸>éñc_Å­ó~ÿÎ}?öðU>s÷À2ÉÚÜï;Ü_Øj|åè;mÄdsW'R£€ø¡k—1�ÿ×Ë·ÀÌx} xãî6>1¿¯C ©‹öûGC‹K}‡ÏÞ?ÂbLxÛ¥l·-~ÿÎ}œ� ×§=~ðê>>©Ñ7 |ߥÜ_ m ¸? 8\ â�?&Üž/ð¹{‡xýæ ß½»�oŸžyŠ ÷_¿‚ÓqD>–}ÓRCcÛâtÐň߸ƒÍ®Áwõ"Ï?þN-ÊüI-@x|c†¯kä@¾rt¢¥¸âGnÝEÏìn#1ã‹ê5|m:Á;/íâ'gøoo¼‚»êÉ|y{ ïyÓ‘RVZ«ùÄ+£È~p²f2Aø=Ad„.6¸º³�›‡ùàáÙ·Îçxå|Žžnâ•aÀŸ�aG|æ¹çðŽ§žB¯à#Ãø�‚TïëÞqYG­@ÌbBtÙÄ PˆQx ”/תC©5¥<›P€yº²)~YjÄ”1)Ø4@“$Õ sDŒ#Ñ„àŽŒì!5Ѐ(–ÂÄÙ�9 mô]‡qLEÉËÒ'Iž!+(’Õ`š2aÉ’‰T^‹ D"d ^lØ¢„͘2 ëS¢‚ ²(¡9_¬Y~´7šÔ^`€€4MƒÉ¤ABÆ�r’¨†¬t(+m¤@ˆ!p¡r'9q\{™¾¡2+eñn‡yëyº<ª›0ýÁdGåõfs1Ù4qÂݹoì&+�_3›âÅó¹óCK d¯yJxñL ÷m ™ñŠ‚OlÎp{¾ðH�½¾CƒÓŒ!g¼¢‘öú¸‰;]‹1KÝÙ×=�Nð¬¦b–(††Èk <{÷ó”ðÆ�-üínùxüø›w°¿Ýa2iÐw}5b 9"çfFŒ²»R…NèdM§Ș´­Ô¢g™Œ¶ h[Éï.5 ÄXLœrVqIÀfq@‘:À ÄТm}'Þð‹�1)HÀ@¶ÂÜ£ çŒ4ŽXÎ瘇Œ-‰˜ádyêÊ„6‹>4Éó-—#æó„³³ŒåbN B÷»6bÒ5h[¡)!MËhh`" J�‚Ä#¿ï#&­¯]F%©çзÀt؉ØÛ�ØÜ› nwÀŒ@ˆ¶�hÑÇ“¶Åæ4àô,áü4TKROdÆ4¨¬/ú )ššLÚ€ICZ_š_[�“®«Ç¢»0�"+0 5`¢€=K# Г8kÝMåÖD  @C 1º¦Á´Øœôؘôh�Ç5êYu×”2†DR‘‹Æ�ˆ4�¡MCè@ ”¼PzmN ˆ1ˆQ’Ö*„¢Xä$O-$÷7%΢„¶©£`-“é¾M)a¹‘R¾Ä\¼¶×ì?ë €×(QBWgLpG§•Y.Ñ&cº=!UÕ ºnʰ&Ë!ò>¹ Åm)+”¸|W.U­ úl²Hu|õ¾ëïªQ›P;öp`ç0FøŠ‚BÙ»ÚêŠ�Ë¿ëßLPŽ “;ê¨sŽt{)à?‘$ò¡RžUó*wZR½Täv³èù`_7Õ�edI`æ6=º<íŠþÍ5`eÏ^"ül¬Œ—ÙÛô›M›‰!R]¬ö¿Bºª"åÖžP5öÙmV#Ç#…Ï‹íAêuA¢J­M• Ëú-v-â,�e�°N"‡f‰Kš*.ƒ@,¢@œ/4î ‘癄¶øzÒaÌd�æcã/tΤ @I¿<ê;%‰ij�“Ê8–—oÚzC¯éb¼Z߈kŸœÖ°_�ê=æÍ©W­6bDÆ ÜEÐ]Ý®ö¸D h?Ü›]¾{ެ•§ùm¿êíxmÌ.’LÿU^Ú½Zß.:¾Jôxí»¿ÙLxá‚6JÛÞš}ÎÜaß5ï•§1ÈÐ ¦dR$[œUu0%Ò˜��°†ê991¦ ÛÔ…ˆø9Ƙ` dÕMTFn.ÆrK×ðà:Ö%[Ñ?#5AËÊ,mÐ$¨Úo«jG5†M­UnnÏ@@•Gm••­¯8¦Ëó“?§#gfÆé@‹â™Ùò’•T:å­[%Òì*$Ìx*Æ/‹©æÉçm}ß”°¿Z0à�¬(,¬¹ÓݯùÖˆ-Î 0@.˜I^o ­³š²1�.<;~ë]´H§Ñ'O´¢œ²=MaºEPRAÐÖ�ß3¬ SBä� WMÃHY-°µJõLðè e#¿Ng’%�¹-™# IØkXÇ-eÉW†¼bDq�•å™D@&-¬Ï£ýdŠ{¢Žu@È 0°ÌAiIN$ŸŸÎG XAö±¯#M"@ï£ò¯Î›.xg5¶Q9 M³ƒÎ[pÁ›Šð´rLE°QÖŸKÖf»RÏ[iä�HUì ö1d�¦}þ½ó ø«¿øqŸ.ñ±ãcÜ\m[D@ëG”Ç©A@€¸½X¢Á¿/sÆýåÒ¿€·îï®\k‘GÈyJ¸:éIr©üö=¼Ï½ýk D^ï¼¼¯bp:Œ¸¦Q§cÂçîâû/ï¡S‰è¹£c<³·ã5 žØœ¹Q#3ã‰�žØ˜a`Æs‡ÇxýÖ&žØ�¾}èæì÷¾wo€¤'²ºo˜Nñ¾ë»ðOnݯ޾��÷ŽæøËç·ñw~ýYü•û]ø™?õTÁ«Ü¨¯F"°I-€X¢<}‡�¯k<%‹0šõ2!çEλ�§±yëºð\ö+30‚1:íԵġО\+zÕ^U¯è²¦ÅƒšaL„”Ô£0”(ŸœÔ»/@œD %ÆÁé¿ú;Çžý£cØOoïâ-ÓÞ¶¿ƒÍ(©vî.–xzg ß³·�?:8Âár@á Û›Øl#Ú°Õ68F/¼e‹”q4ŽøäKxj{?ñÈ5¼pzŽçŽN@~òÑë8X,1h߆œq:ŽxdÚãxLØéZÍÏßàu—ö0pÆïݼ‹H„¹~óœñ‘›’BèdHxx:Å$œ!¡¡€oœœâRß‚™ñдÇ_¾…à—÷°Õ6øÐ+·ÁÞ°½‰·_Úҵ­Û ‰8Øm;¼LsLbÄsGÇ8OOno¢#)>ç¿ùÍC•k°].—«lÇín·�vºÝÝN "´òR@$ „ "R (üŠ”$ Š€üQèv϶{°ÝínOUí*Wµ]v½ª7þÞûÍ¿{ÏÙ{ñÇZ{Ÿsï•] §ê¾û»÷ža�k^ßÕ2‹‘Ó”8ì{^Ù?ä7Žùê‘9&mÃOäÃ ÑÆRG)^ Áãì–²ß+Y¥¬S{=qé"·ìñj·$a޼ÝE O‰{‹%ÿêÎþ›¾çærÉÉbÁ—_y…�¾ïYZÏþ©²©¾.üv$t¨ž‘ems‰@¨ûÕ%219*Ö,ÍQ4šPï�4“K:ŽaƒY9qŽ%™&™c ÏÐç`ÙÑh†4bÊ],r¶=/ª9á ÇîÕÌ !I&ydt¯Ê2—Ôð"™•�‰Qæ.%ÕŠx�Eì—gyȨs8{ …¥È«ga|»óìƒE]í_…æ¶ûŠÖh?̓ £gJ$_3!Cd:‰¤œé³ �9ÔaÏŠU~�™Ic�¦ÌìX2¶ó‹ÌªžEe2½2y¯Ïc®äšÂ[ôˆ‘L'°{Ò“²r.F>2jðÀ¡�¯¡#w´�«³Õ¬�÷mnðÒÞAmËýe·R øöÈ pÎ3âJ��:¿Í·ö�*$ÑzŒt’9²�ì.:vVh}-NRæ+÷ÍIðÌÖ{K+8Eø^¿d×ïóþk3Þw}Ît™M-ª}2qX˜PŒ¦­Dƒá"§$fhñ¶O§�ÙTˆ­Ò4K¢q˜ É$ÐNZ·½9ƒ´4’VÑãj¢Xà@"Ó8�‰Ó&s¼H4KshîM  !CHhÌfEhD ²&õ� —A=ó§/Ï(hˆåÒ1Ð/…~iņ—'=i™ B'yAå‰9¢ô´¡g>QÖgæ0OX>fM´5?m#Q…¨�,=aÚxQáµÀúVËÖù);—g¬�Û YŸXJA2G‹„Ž3!Z}†É4ÒÏ&ÓÈ|š9:^rt¬zË2 ™N’G®Š�k¬Èx(u”i“™7™&¤ gae™¾É.Ϙ–Zœ‰�·'!ƒ× (:ˆâ&EC²½È>I[¡É¢�D˜fá4K=7{„ÕŠðŒ±Ìša”yؘ5lmLi$�—½9<¸¡ï¡ïÍ‘SFƒê,)ª™œ@¢¹/±ºE]—Y♹d–;T‘Ë€ˆÉÝ!D‚D£uY)Eæ³×H{8“ÀÆ0%Fñ˜�!€°ï¡ÑD'½éFâm èRÅnR"ˆœªQ° íV…o„1 -Úáˆ6 h©!çü‚/í4¶0ÇMe¸ÉøïBËQ|«†ó¢§®^7HnüÙ0 MíKù\[iã1¼9"Êgêùc+N²á·r¢…ó]®šë•U*©}óëupˆåÚJkÆà(êãÐòq# Üqv}ÿ¬CfÈVð9«:þ0ÞŶ= �Îhäj±a3 ˆ>2Ø*†QÒ•9-óZÇh,3:Ÿ_³:CP³µ�—™²ÄúbS,íœÅ—QD‘¬&ƒääu²ÊzD¾\ _Ñ›ƒ¿˜$u_q@V›Ššl—3¤ 4ÕôZìJ–µ)v ³qDpø³B Lg+ˆJ’\V+ ßæZ‘«lZ-Ýw TÂ3’ŽÇ›-ËÈFìËbÅó5—bî Ð¢2ý¾F“f­&ÐNSêoZ¿ð^�"�Ç ¯Fßñ×uâKï]ò#ȃsãQC°ByF›ú�ú¿îþÎïóp›W¿{Ô{y…3Ÿþ]´¤�¹G5Hþ þd{Ž3/ NŸ¡ –O“dd™6G%V˜˜ÂaÀ\ *•À—E.‘£A�¤ŒJ&‰Á�”töé^ª’�qÄúµ²`ê÷Á£›†õä¤F†óʵ¦d�ÇQ¡úÞŒ ')xfS¦¾çá Þÿ ÁŠR•ab¸†²„‹—²î<Î-J­Ï¹F†á3º÷Ÿ±!Øî“4’rôWFç2=0â³Ô@êR©ÏbÕY³:Ç¥Ÿc¿0•€B¨Šiñ4gJÆBª¼É*»‡ªÌÆîìûóQª*üu­:š¥!7à&¥£è)¡ý‚Ò÷¡¬ �ïÇŠ-Ép�0RPîUØæ(kJˆñÀ@GƒUD‡"dæÂœj°º­ƒCà�:Ïà(ÕŠå«j0A"*‘¬�>Ë!Š¡àæ•ŒU/´La2Pöª;ú0Fž½Ð™áJ}O"DÇê˵¿!»ð­Žêö1x´âØÀQwMÚ �/{ªŒ»�«§ƒ”ñ Hh]å§Â 8x˜i‹â)×(ÑÖFR¤·±B…H«ôQ}>=­04Á¡j|ÛLˆ ½·+°9oø‹þYþþÿüu’*ÿdw—¿|åJ-À pëä´øƒº67C>ÀNÛGçÏcäI7®ß:YpÉ œüÑÞWç³ QÔ«G¼û1‹‘Ÿôý.+�æ1˜Á¤ÇþÞ8>åÍã>vÑ2®Î†v�A€Av‰Ç׬wN|ñÞ>}í3Ç×~°ì8I‰y´¾üèÅsmvØõ<ãíØïz¾ñ`ŸŸÛâ/]¹Â§··ùïoÞäsAý­÷ù7þë_ä¿úß¿Ä_ûó’Ÿÿágle©YFZ$;1 Ÿo®’9�zÇÃÎ%ËÍWaÉ ðÌ‚â¨JŒj5¦æ<¢ó#Ù¬Òß’¥ �E y×X(‚`­ùâû3„`õEð5[RXý»âĆéœsX�A*´üø´ç3¿÷%~åK_f±tìøhCà/_½Š/9Xvu=›MÃ,Zó­‰Aj\šN˜†À•ù”ÏߺÇR3Ÿºz‘Y|æÍÛ,sæÃç¶xïæ:_Ý5¸™Ã¾§Ë™Yhƒpi6ã¥û§Ìó;[l4‘o<Øçþ²ã©õ5~üò_»¿ÏîbÉA×óÂÎV- †ù½¿ìxjc ÁjüÓ·x×ÚŒçw¶øÞñ />8@Døùë—Ù[vÕÑÅ¢/L'Ü]ÄÈîìrÁ úN%ð¹Ûæ€øÉ«Y¦Ìç"èâtÂÓ›ë¼zxäû&ó�£ÎMZ²Â¹iËoÞºKžßÙd£iùÒ½û¨*�¯Íøäå ü’`¾¿ìxßö&÷F°&/=0¬rƒ4jyõàUåêlÊs—ÎñͽCniâݹS¯ùä‡>Äl¾A_ymÖ„ÚÍÀ; i<£f$ÿlA™K;;41Ò¥Ä+ËS¢Ù)¹2›Dxë䔿zñ2ÿÅí›<è{ŽNNøÃo½Â‡Ÿy†&Æ‘¤:Ȉ+Ð#Öˆ§b÷®\ ´ßþŽêl5êʘG¢ÓvÑÀ»ûœ½ÞNÉÐÊ«ƒDP—ë„Ú.Ò4�®�ôm$èC`*‘––‚MÕŒ}ä C‘5¢èÕ`€ŽûÄÑRèûHßNú2+A ž­V•×=½Üe"‡ìƒ•‚âÔ1n…Ø44Ò�5�2tIYv‰®Wƒ Kƒc  ½�Ç`(�3UL™�•r&ÒB€ÙD Ú^X&!v=Uè³Á ÕÈ}Áª©*–{X+c>Áø£ÉL‹±+õ ÔåËøM AGVØY›\�Ef-”¤p÷ÄhÜ'gëlyÖÜVÛpܧjØ?7i™ÇXª°ç�@åxѳvfÑ"¨‹Ñ{Òre6å•dÐõµY­ð�+N„ò££³Zs@DøÔ•‹|öÖ=Ýø¿èS…»¾6㽿[ïó3/l3™G&­Ð6™6&Ú3/ð:�XT»9¶:›íÉšÐ`Á±í‰í‰‰ÑjRä M“�Î`æ‚›Šê—:E–=Ò™¬T"ÚÛ˜ˆ0e�°�L›•Ð÷¤¼àxqŠÄ†66Hãu9B65–15i"óI`Þf­0i­Aí“ÁX¥–~Ù ]D»†Ð´HÓ�B:�è"ÀR�¾£X5U|³7õ”) ¶'Ê…õÀR"‘…(‰DƒE¡7Ö†˜1C¯ùÓ6'̧G¬­¯±¶=cýâ:›×αva‹0™ÚÚ–Å“´éí” ­�Y“ˆ&¢ÄÔK‰,‰•Ô˜~¥˜1~Úh-ÖÛˆQ™ÄžY<¡mL¯‚¢×e‡J{ˆØƒe í”zú¾§È!VÇ%`Fr¯û¦&'�z‰dI&Ib& ˉÐ, [*i™é—=AA�Fa¢‘©6Ì€™æ12o£9¢SOJËn‰t=!+­Úp"B»È´§‰†DL=9Z–e, ,–«�=» IDAT¢J¯VнW+êi1Í-! mÛÄœ ©$¢Xt=¹³1+ù9\Œ“�6Úº´L™‚-Þ±”Sº¦£KF{»ËlPQ¢‘¬C 7Eð$}è�Ó:ÄÌ+ÁKÅÆ±¢»â™Í�C²½‹&%xÚøŒÄãÃåQ㘹ZF6‡*T¸�E UÌ“ /úyQ»Çö®áÏUÓ·Ÿ7X*ÿÙŸtÔ‚á¦H&×[†®9i¤Vz?8èÕåqëûj;‹] BL»�HFí´*ŸW\æðvÖñ,}RW›j=ç/1Xû¢ÖUmµ B\�®Ç0M£MR�2,ÂÚòb\×a!1ŽÄ æãgø VÏ+-(‹¨îѲÑʯ5giµõ‘�¡õ¥…R•Yó¾½]„ü£�ä xô¯úп«gëêg9{Þ;kÙê¿c‚7,F]q°zN]´gúqÆ�"ºÚ¶‡>Õ9p¢‘€$füJÁ_êL%L V‰Ý6®¸po^»¬qR¾!ö:‹’ÅÒ�³Xi1St V¨DgVŒgßìC×VÇ¡ #:ðÁ2óñ—ÕU,õ$ñû ï¥v†Ô~æ%o¦y­8JÈA66¸ïi!ŠunF†¡\�ÿ�â¹_Qó`R7ðª²Ë{é[Ò@—G×V˜ŽÚU ÇE,œåžeoVg@½GQÄJ¤aabC*]¥u2œ1˜�÷Á �†9 …™Ž×ªªíƒ*p(Õ¸.E4 %¥Ý0ÜÒâMö´u¡®•BcÊ^m�QÖE1Z ô/DG¢aä`Ðá~ÕC\Ú|æUi›ÏãPìgèûÀx ãP³]ž³c^›àQ=ãÈ¿`L3«AÐã5|¦uM›ƒD"Á39Ð’Âë‘;e°ŒÄR¹3…© A#YroéÃà¾Tˆ*æjW3ê‡0xþ¥Œ ‚ËÁ£½<,ªp9ð Ÿp/-K²ò5¨¾‚Ñ_�žE££÷Ðd…ÌÄ¥ÞB52•ܧÈ�-Ðøßh†6CL^ÔÓõoÿ…òþ—¯£ ¿xÿ>¿pî<çGµ.xD~9Šq½Wå4%6Ë Hª|ëà¨òº²§ýxn{³þ�Tës’ZÄþû·7m­_¿¿Ç»6Öj1ã�¶-h˜µ¥°ñ÷ŽN¸:Ÿòn‡ú­Û÷x|}^£ÿ÷–ý óÅÙ”�]Øa*Âaß3�‘O^¾À«Gˆïñ¬†WŽxyÿ€?óØÕºš¯{b6ã¯?ö8?{rÌÿxë¯�š�å•÷ø+ïŸðþw]âßü3ã§>ü/ˆ(•>ÓÛü�¾úê{HýdkÔá 5…µð·²g‹ã¡ð²\è­rXñ!U88�,BJ‰”ÔÍ!‹lpŠÖ=ù­Ðµ’aRè�•[Á×QƘ*‡'§|îÿ�ßüý/s²¢[?>_ç‡çküÔ¥ó÷™<�³Lf4ûÕ·îðÌöÏoorûtÁWîï±Ù4|êêE¼f„`FØ$Âõµ7O¬5 ßx°ÏÅÙ„­IËZùÕ›wU>}ý2}ÊüºGè?6Ÿry6åå=3¬µ^g`³m¸<›ru>ãwïÞç¸ïù‘ ;¬7 Ÿsãû3[¼kcT ¸ãù�†M‡ÞÚl"ß9<æ¨O¼{s�V„oq÷tÁ“k|äü6´wÈ�Å’ÝeÇÏ?v…Ž'žTy°èè1ÃáqŸèsæWÞºÍÕÙÌj,–|ãÁ>üôµKÜ_vJ$аÝF¢È^×ó‡»{<µ¹Î=�..ØÞdB�~r}�÷omðËodÈqêÙïz.oÌù·^{­îÌçŸ~×.^±,¼˜gA`•Iñ¼ªìÙ§ºÌÔ=@*peg‡÷îñµÅ)ÏMlÿ[ä£ñ“;' þÆÕkü§o½ÉQJóõW_åCï}¯ÍË!•_ií*r“íuz,â™ð 2MÍV-¾_Ï< Uº)N�A†¨)9×Ôõà<«Ö'ñhâ.BÓÝÏYÈ"ôAéP& 1ºÜ–]ÖP%†h™¬˜Ñ´ë•®‡Ã¥rtš=SÀ!Käà¨?&'ú4­ìNkÀÇ0C5ëC³CSXCæ”eBɈêS¦ë­ŽH*5œ>Þ<Á]u¸NÕ#ˆƒªÉûä 4i¬ˆrh1™^Øõ¦BP3# ö¹õìã³zNÉ,°`!7Hhh‘‡]¶S_Ð¥¦V™ïñ:/oí“U9#ÏLÞºLy%Kêþ²ã>fÈ/Ù9%{àé�5^?:®ÙbÛ“–œ3w’9»¾îËñâs"\˜N8êS­Yð®õ9ç§¾ê�A†Û>\§ªüÒ›VS§ðú’Õpi:áÜ|Ê—ß0:¹9‹üØs›L&�ITš�iB¦ ʤÖ¦‘ù\˜ÍMŠ9²$3�Gæ³ØJDC0È�”Íhß 2M0ך" ,�8(¼KúàQüBëÛ4"D,£­ïá4&"K“m£˜!5(Ò ¢­g“™4�Ù¤a6i™6Ñ¢³Qz¯¡Òu ai£Ô«Õi”¾ú.Ð�Ò"�úÔfkF£B£„&Ó„žy“ÙšNÖZ¡aAäD Ê«i m„Y Ì¢¸c ЉÐ˜Ï…õõÄæNdçòÛW¶Ù¸|ŽéÖœÐ4 †\È$T”{ˆ�Û«”&Gš ù$“¢Eš/Hö Ï\@`ÚØ+âK˜S¥•Ì$t–œ†Ä5å‘~\‚qjí¤Ô‘–�ëJ Ñ y¶¡J!ãìAO¡Ô�ðM× ÌšL¯ÐG¥k”>fú��œ¹·z A˜´-™©(¯;ж˜#ÃÉú” vHÓ;/ ×!4Qh"vo\é2,5еÂ2A¯™^”eN,ûL—Õë’ˆ!2™˜‘¯‹Bßy`…g¬§ £Œ|gN#ÁêES�6ÚÚ%Z¦Æ2)Ë”9í•E/„$,½~Bòì-°8…v xè|¯ÔÝPQ4˜T¨UgqY×¹WhíÈ™QÔ£Uª[þ¨ºT!‡R3:AÊÞq;@½?ßlËɵ/Ï_µg¬Ú{[Þè†g?¬ºA.ßXWd$/�2Ñ\É* XÊ•G»Ð8¸òì!ãÿrÝæCû˘Ï#î3’ÉÆcc†á-¹Ê]Õ¦QÛ7ðÓŠ²0zz±sXp¬‡–W(Hï© ò\ýÂ×kÁíZ3„ónŽc¸c›¯öµ–-08}lˆ25~ªÜËaf­kC;‡Y-6Ä:ˆÊEqTï�”¿3ˆôm �ìû4 �·, cš²Ñjƒ‚ õ™ö<·U¯ÝšLV8Æ]0ø¡EÊtš+4Ñ޲㥽>~é¼§€*¯sy>Y>°½ÉöÄ [–YkaâÓ”xyï�g·7¸<›’TùÜ­{|`{³B%5Á 3ÊñôÆ׿SÄÇàÜdR³>ëç¦-/ìlñcí;Y¸Ñ/ù‡»÷ø®º¿ù½;üµÿîŸrqk�?÷'ŸçÏ}ây.ïl‚(špx§�ælÙñ±mmÛ,ë¾ð-õ}QĤì´w¥08b×£ŠcÕñwØ÷Ü>]pãä”Ëók1°ÌÊiÊü�7npäFÆ+ç/ðÁ÷¼·:}UÕ1ñ“㦚qw€ ÕJ'‹Ã¼*¯•ßÞeòÙõóç¹qïoô»9ñødÂ]wjÌbäý[|õþÿñõÇøÛ7Þà4göŽŽøÆÿ1Ï?ýôJœ”6ÔÑ/Ê—ŒÖ¹gu )RŒÔ6ÖŒˆ"Gˆ…,TrìKc¹@Õ pÜØ\•aP8èéB&öJXf”Þðþ“a´ý¨8BH¦Àaòa×[ñ¸£ã%G'K+þ¬Eé «œãüGŠ'd$·Çu•Cœ÷%5^_…oC*1ɇëS¢/5WJf“hå¡–I!>Ä#Ù/¯b1ò�™| ××"æšèµ£Dkvzmw¹Æó¡X£=³då{G'ˆMä ëùö¡e |`{“ïŸpà™ OnÌé²ÖL„Yù̃5<ç'žÝ`½1i#JÔR&ޥ߶ a UD£ef†P¡²ˆ ž) uïYÁmiZBÓ& Ò'�͉4¾²í¡Å,I-â}Ä‹4gÂIJf)°¡ ê‘ôÆC…&4´Mäi˜´Åœqm,£U k"å@Wêôd¥?Yrš‰KBlÈ 4Áò´c¹ìYô=Ëœèb@šM 4‘ɤe>›°¾6es=3• §ÚÒd¡Ó`m£0wç@Ô@P!5‘~[[s6·7¸pí"WŸzŒõ«ÛL·×Ó€H6ë²Æ‘¾gò9sãÖfY‰ë{-ˆE’J‰�Ö3"%{>ƒöˆ”Za‚ÐxÖ€­ÀФYô!—W¥D¬&+D�úžœz‡+L“¹=’f¬Ó�u ÉÎO¢À4d²$ƒ@S¥ ¡1˜)ÉLb¦‰Kbˆ„ÐXÚI@£A’ 1ÒöC”ŒV ñ ¥®‹)}néÒÄêž ôd:”EßqÚu,ºäE��þH€6XÁÑV­õr™YæžïOÕ³ ¼¬oÕÚ®[HÄÆ21Úœh’{ç'½9ÏBú�ž²Ðd¡ðŽô¥ïÈ”K×´°�àÉ‘³ôŸñ(שéòý÷¹âm~ ÝÛ3ª-Ç� ÅSå�¢Z �>¤ÞËî»Úžâ Îç Ý´=Q´¦Õ¶5òöøí:|朱®1¾ãÙ±xÔû8°ð�<¶§ mÜ¡SÅ©b§Y9µ&�^=C°ê ÏI¦\gY€ZÀ¢fqÈ.!çL1'é9"»Š.5kT*öÑÁÊóÄa^ s‘7¤èbXðr¨ç 3 ¨É:þÞí6<Žb@íOpY¥ì{ n3DÆÖ®4Û†eµâ¦ýï÷b°³X�”�˜ì¥½(:v bUý,Có¥¾�z\¨ÿŠ"Y¥ñáJ-]1B['t´(jD¦‹hõ9åå«£,¢q“G†°jÃ)†§QÔw5è<´ùÇËRFÿ>|¼”·½âûmùÕ; Oýg'²g¯x¸5zæ[}›3‹G·çmú»j=0#mÎHñÂYj€9 Ë+¥ì¸áC;‹áÄ *Ž_¼ï•aé€ Và<Ú¶(KÅÐRŠáŽ:6BŽ=jãÍOQhËN†ufU(ŸÍ¶©p-ÙdzDûß<9¥ËÊ»ÜðúÑ1ß9<®�B%RºØý£?qù“8I‰EÊ5Ë`w±äëöùÄ¥ó¬7 ËœùýÝ=þĹíÚÖ Ó ç§T {ýù�MžSø±�m>·û€ÿóþ.¯-ÍÀswÿˆÿá—¾ÄÿôË¿Ç'ž{Šñ/ðÃïŠs•ŸT}­ÔBÅ tRF}uÇ+˜ FŽ�BÚ«ÕÚêYZ¾v²Z¬UR%%�ˆ£ÐÁX3K*ý]á�¾ÖÅ„Éè²Â{½­Y-*î•ï~�ß}ñ%¾ñÚkµ€liÙ�onñ#ÍD¸61Òö¤¡Se{ÒòÚáWçS.L'œ›´üò›·™„ÀÏ\¿L—3Ÿyó6 |ôÂç'-/ïY_ûžÝeÇåé„;§ žÚXãË÷Ыò§®\`¿}g—ã>ñìÖïÛÚàwîìrÔõÜ KžÙÚàÄ#u7šÈÝÅ’½eÇ{6Öˆ!pãä”ßß}ÀóÛ¼k}�¯ìîñÖÉ)øùÇ®òæÉ©4('}"if£�{6H +³)Ol¬±H‰/Ý{@+Ÿ¾~™›'§ü�Gò>µ±Æe‡åÊnàxeÿ�+Ó‰E ·-¿xã&müÐùmD•/{±á÷l¬ñÜ…>ó¦Eûï/;Âú¼:s¢¿sûÓxßæm ¼²À"e›Ïø±Ëçùõ·îЫrÒ÷|ìÂEî/—ü··o× ™ùtÆÇŸÿÐÀ{µÐ±ä™^Å€k }U¼. ø°"l?èÊ U¶7ÖY›N9^,øÇø×«FÐeJÜ],PàÞÑ)óÚcü'o¾A§Êýƒ^úö·yÿOTÃ?¾#ŠÜPSÇ‘jð<¶PW•1o«žq „ᾨíѲ7Æ{ÂøŽ?£Ô쩼̢ØR¶z�7!åD— é¬6RáµêÚg‘/Jôfß[ḣ“ŽãÓn¨Uâð:<‡qõ\‘àYmE‡³&–ÂvµsU.,ÄFk6céË Ói]µ�z &±óÌ¡²*3«–þer(Ški«Ó&EÔ…!².8_´ùBÀr•›jΪËÜ+s’­nŠ!¢Y-4!bŽEqŠJ ¨Ó笘hÊÊ­=/þ=›³ã¼s³mHY+LÏ2%v—«„¶8Ö›È"[Ô/üÐNÛu DØhî.–õÚß¿÷`Øe"Ür‡ÃVÛpi6­ÇŸ÷ëoÝ©«Ýå’~@óÒ«g0 �óÓ §S~ñæ›”Ùþ³/lzôu¦ÑLО�Ý+Ž#߈E0¶ D»Ã= Še0L‡ªs@b‹4­U¥mJ”²oO¯y“±…ª=0Õ+Ú)bâ†(QbÈL"¬I Çv€Þó}3i[æ“)ÓÉ”édbÆíìNMt6ݤWz–ÎSɰÈ=,“Cz˜^²Ðu‰~Ù³H=]JæÀhBÛ m$Lí$2›µl¬M9]d:m™æ†‰C¿Ä(4æ�9¢CiæÉ©acgÎæNÏöåsœ¿~™Éù9¬G�i9RVðý¼[%êÖöÞàÐs«…Ž Ð!b¦‰1è%Ñ„j��\¦·ŒßÆá,�Š.Sh HÖÓ“óÕäûÔé°f47#§§Q A]v‚ëp£—ÆD �^=™+¸Ú:¼T0�1¢dbÈ´±£ 14HÉûŠjr� \ˆBîƒÃªÇôwy;XÆI…‚¬Ð§ }?!ûšîrb‘{N;¼Æ�²£ñf¸ÍDé 4úУ^ƒÃ´§…NÇ¢š‰Ñ³9 \BŒ´M$s¬4IiR¶o�¢Z!jç‡Yų;(”!8qX7É7š�µ~8­A)E¼}²(JýJ@Ù™ãQç¢ë88­–´zS_Q«ºáÃGyê¸pö9Õ¬ø�Sà8jDš�Sq\zëÊŸƒL>hýC`ípmñ˜–kV>«ëÈgû+ÈgÏYÍp(rÄÛ¿¯K¾í¿³c0èkm¿Iª¸5îÈ༑‡Ú†Ûßd4ÖutXo–Ý¢€¡¶«­M’¯/ Q•!h´ÈUìY²êŠ*ŸÃ°¶ë{ ’EˆZ‚KF‡Û{êÞ©´º¢“À�10–uD0kµ ¹ 4\jŸÄ@ÌÅrSœ¾\]Î þ´,Cv¨½bÍÞ5Ç@”3sï¡Ò¡BúYÑTvP`ØMãÑoèB8Ô°ÒÎ,ž¬–::ff+ÃWvMI+D}ß—Õ+Ãyeñ¯´y$ø�ûùПg·ãÛg7Ë;¹æíŽžk¿ß5ÿ¬}x§ç¾-™ô×¾¬´X2r®€§f0³l-Å Þ2¶© ƒ,)ꩤãÕÂvƒÈ”h£Ái0D1⸋áô=ðkK_¤*ST.¦‘ùzª’ªÿˆ‘W�V ®ˆÄ½J¡ÐPÑAµ)玷J}fÝä£ÂÀ.ÈDþÌoõ¹ÃÕö8a¬n´_3¨†¶�ùH}FßÚÐa=ºO#¦_˜ÃÈ�_ Ûмô{õΫL®Ži‰ÜÍë˜I?úØq0îWq6ål©öAFÂëH)úS<Äâ{äLëKûj;‡1¶ßµZ¸+¼Ô8'ŸYum#äà ’½Pïà+m­ë¯:0V"¥a1€'E±¨˜˜†u\™žã‹ÚõÙM°/óäp ¥¨*ePÆkv¼æÀ*ÎV õ$k+Þãcš‡õTî_×þCb€õjUÓNùèú:?º½Å…™„Hƒ†úÖþ!<·ÅGÎïðÚÁ/í°Ù6|êÊEî,–,Š%«E^_››¬|áÎ.×Öæ<»µÁaŸøíÛ÷Xk"?}õG}_a3>°³É,Z¡b!1k"|pÄõùŒµ&ru>åWÞ2ìüO]¹À4~Ù ?¿³É»7Öù•7o£j°gžÝÚ`#x�>[Áàg7×ùÂÝû^4>¹}�ù›Pîž.8N™Ë³ ªpãxÁWv÷xv{ƒ�¦á�ãS^><¤Ëbøæþ!Y-æ‹4,N„ |öæ]®z–Ì$¾pg>~éö�ÒÄhY':ò'™ IDATÐÖ”Ó�­¦¾^*tš+$Å=:Æ|t̰xìâ¾uãMNT¹}|J#ÂE÷7véùíMnžœò^{Œÿì­$Uvxñ;ßá¹'ž0È��•=å°w5\Í–ßfÆq‹Ømƒ�°¬%s $§ü©Âˆ¸E]pÛSBsŒ\ãZl¹TªaGIJ‡–ÉŠÿ†dxäÖÆ��(EvŒœ}2þ±XdK©Á3¥�=ÒöîàT4=lPß,Bº‰‚Äâ¤q¨—"Hš¼ëň T815¸s”b²ƒ|¥:„?H),<:¤%@³A�šŒà—l!ËE¦Ò„Ž^ “¿òè~£Bý¤Õ©€˜|iSXä>¿6¨×/2ª Æ@K ÷¸! ÊÍû÷éRâ\ˆüèl­ömo„û?�±:¨Áøè7|¬Åˆ’ò:ƒó*‡Õ±hÿ«ó)C“Ç×f$¥ÖEér®™`¼ùW�Ömµ ˬÜt'ÂSk¬ÇXk´1ð¾í ~co�ûîÐøÐã3ÞwyÊD21%$õ�ÝAÑ6P2†Š,%b ô�À{/séó£’ë"”‘&"m´Z­×æ)�dhšŒöbŽ�^Ý1€AÂĽÒö ]@¦ Í\é—™niz'90m•ùD¼x²E½WG:Vp8瞃L\ªZ¶B ¦¯ZÐ#žß÷‰¾ëé%‘Äœ³ÉŒÉú™6ÐÄ!lÖ׺eK—–)0í,C3„D…�YËÚ,2‰-mÓP2›ÚM˜l*Ó�9²9�i€àFö‚Õùò—h2zl ´�L¾ £pf_ïš ${eË<¨Ùˆ!B�H¹3©F,£ 5ø£àƪÂL7J u(íq1$š� 6Š¢ói]%“1ˆÐhÑ´¶µ˜�¥ ½ÅÒ“B2‡bš4Ñ`ËTÏ_^ŸÁ|jQW¢ |í£í\ÃyÅ…YFíìµ£ö2DÇËèìÂjÔH7„ñTŒœ >¥Wâ:B½Uí®Ô>V~6ºë;Í8Ó’wpÔ–‘³x,Äp¯’˜ÿ}¨õìóÔàþd¼žœ^TÙÑt¡€:–1PÕJH²GSbµF÷œ£Jµ‘¬Ø–Ì ou¨ò[�n5ÛbP‡BÙSGT™³aoŒv^¡´U>©ŽwûH+ä«\ˆjYH¸ÁáØm—ŒÕ,R´‹mÔ`©vÒ†RT°L†–¢Ñr¨”ÿ]"mJÁƒJ­GsY§FÀÐ9M³Õzž)¹ƒýoDXd<¢ã¶äaRF÷© ß½F•yŸdå^«íÜhƒ?ttÞÃäíîóN޳¤öQÇО‡[cßÊC�}ŠŽ®—•>ÈC}õïõáoÕ‹æ�½@¨ xb|MŽO[¢ý1/´L �lÑR︊ú¸pnÖ‚¿¬CvAuؽÎòÕUjËB�;!©›ÛÇV†sË�PýË…˜!Z}p TfZiÛêuÅ÷f¤cò¡F43&æÃ¾5pP)ŸÈ´gÏvf<ÛÂSÔ­HÅÀüv†Â”uÜžò,YeUPV_”SΨŽzõõ7À­:Æ÷3ßâ®Bà™ßuô�>ô>~• xáÅW˜´ÍùÈ ^ÚPîÇjc‰Ž(ÌiL–ri‡¯Q ^ 3È×¹ÐÁ9PÇðÌX<äà�"k¬ìØáÙbÊra˜âm©i{8¦¸â…R3)›`[3"¼/M„¨Ñú_"±´¨`�=*HKÄ�]z¥:Î8êú.kl4Þ q�r®0=»6zÚ4ƒ1´ ö°†ÐUÂQ¾—zž-P7€hÁ 1©àëÂYnNT¦Ü÷ŠÄ2ÙÃsðµ•=ÚB¯2‰]bÙvA.hÖjNƒ`PþƒíGøKë3üÃ;wªcÀÖãзIÕ)P„ç n˜ëä”­¶eÝ�ó–÷Ëz~á17ô—ãËsÜ[ÇâDØ],yiï f¨*GgôG/ì°Ñ6$U)×çìw=¯îò‘ ;4nú­Û÷øäå l{¦Âú(ãàù�­šrþÆÑ ïZŸóÂÎ üê›·yzs½:nž,hDjfÂõùŒµiEx°ìXo~îúe.�œòWÎ_díúuþ¯Ý]~ùÁƒ ½²tÊg~ï%>ó{/±6›ðÑgžäcÏ>Åßý8kÓI¥ËuMUz\–•2í{}ìt‡c¥Q#® ¾ù"C˜Ðnë·Ò�¤ƒƒsHñÌýã¾öÚó•×^ãõ·ÞZáù~|mƒ÷Ng|òÒy®µ-¿øæmÞPå—Îsq:á;‡Çôª÷‰N•�é„­¶áÉõµZüöcϱÖD¾t÷>wËzíïß{À�Åá©‹ç€%‚Õî/;Žûžç¶7ɪÜ<>åw�ŽyßÖW/ìð­ý#¾stÌzÓðSW/rãø¤:Æ+D½Þ4,53 ‘¯Ýßã½[,<ãð×nÞaŸ¾v‰û‹%_¼k†óÇÖæ\]›U#_^?:áÒ|Ê2g®ÏçüÚÍ;ˆˆí¾pgÞ»¹ÎsÛ›çûÎÉ‚Ç/Ì+äÏ$^98²û¬Ù:|qÿ�£®çÛ›<¶>ç·nÝã$%ŽRÏŸ¹~…×½æ€b˜ü1óHÀýÅ’—÷¸6Ÿ,Éé’oî""|úÚ%nŸ°‡ò÷¿ó�:§xúv66-3À6+%,»c òÓ3Ác¼ÔrdÓ–kVLÿÂ/®_8Ïkoݤ˙¯/NøÓ9ïÛÚ`÷Î.ÅÔùÆñ ')³Ì™¿qí1þË·nЩ²wtT�m«":´)¸1Þ”®œ^Á`"š&XÐ(D×5²ÃYdYd ™~OÀŒ›jw ’@‚Éë#f¼A Åan¿„ÁÊ©f+²*iP­ÎÈ—FÄù¥’,—Vk %ññÌöèx†¨7«ç U> ¢í+‘}%;­È¸ž«êëÊ#‘Ëó>(¥â ª§ú¡¾fÄyþpÔŒ ¶ª9ÔŸS"¬½¶Î,¹Àñ[tˆ:* ¬Êc­©:€\†G,í>TÙ`äÜR¥f8}�Á,(ôØw‰Û¶÷zmƒ(¶ß6Û–Û§dÐùIË�“¡ÎK{ƒSàŽg4"¬·Mu*ð#Ïñ%§7àã>Éâ0Öcä°ï9Iöì½xޝîîU'Âcksîœ.*í»wºdÏmA„ƒ®çîé’t÷n½ÿ_üøyÖ'Á³Ü)�–fp¯³ú”�¥±ú:Ó­ØË” (µ¹\——Æ …dÒ@Û8ôNt8UËd¯h›Ñ΂Êèí3ÚerÌäV‘¤Ä$A“„f™-„åIÇò$C/H& ÌeÒ*“ƒÂ2—šI wJg‡©ñض¤^,¹¯k±ô¿ï{Rß[ý‚)Ķ¥� “µaÖ Q�ÒN`c­…^éSâÌ–°ì3”&f6×`s=2™4–Ñà…ŽYËèzbº=CÖt"ÖY|Ïg_·3€I HƒH9 êÁýÉ¥ìnñ´—ùNf•0çbé˜`éÃâB‚+Ÿ¹ô*¯è{A0¥¨n†U¾gS8r¬N^ÇRt¹fÔ`}"�ÌxdŽ¿¦ÐµbÛÐñÝÁµB=7*C6~û5£•h$ä@ÎÁÆ,ÛMÿ•Ÿ~Ž¿ý~‡ïÞ:à�Ž�ùƒÃC~hccÅx~ët±/ôÊÁÏl®W�b»m™ÆÊ„97i9ç†øƒ®g³mj­€o<Øçé�õêDØï w·8ÎMZ~Ä��*­/x¦ÁkGµlùü`ÙUìØž5 ðs�]!а·ìP�§½¦À�“SþèÁ>?uõm0£Ç7÷8ïÆh^8·ÍVÛ��Ó>ñ1Ï:¸¿ìxyï€�œßá]ësºžßº}�ç;`‘3mÓðÔlÆ¿wý:ÿúåË|~Ÿ_°ÇWŽ�H>±Ç§K>ÿõoñù¯‹ï½~™½ç >ôôðuœX£ÌC²Û 2Wo¡¨ïµa·kv>¤®^&¼�9íÅÊÖù·oóò÷¾ËËßý7îÝ}HØ¿mîÿ…sçhO{ÂÕ¶E_›qÒ'Z^z°ÏÓ›ë<¹>§ �_yó6k1Zqá¾ç7oš1êÓ×.1w\ÿÒ†›' ›Ï˜{´ÿçoߣá'¯^¤•À¯Ü¼CVåã—Îsi:©øü–ïZ›³ÑD¸<›ðíƒ#–À³[l¶-_¹¿ÇýeÇ ^�â‹÷pçtÁfÓñ©«+îv)¼ÌÊåÙUe¿ëyùæ]žÞXãâlÊ�ã^Þ?´,”ë—ùîñI…ÉAhÄ ‚¥œ‰AøÆƒ}Þ·¹ÎÝÅ’õùå7o3 �½tž¬Êï¹AðÃç·¹6›Ux�ENÜ=]°3m9=É<¹±Ægoß#ŠðìÖ&Ê€þÜö&ïÞXãÿ¹q õýø��-Žºb|´Z[³)ýÕWç»t…§®?f†„"àQá&T¡¹Tx¼×¤ÒóG|NÕ�ÒJMo–A†�Y®žÛáÍ{»üáâ”Oçü–×m¸8›°L™ûn4½2Ÿre6ã?ºö÷æ›,ræàä„_�çŸ|’i[è›PS®† FÙ Õ‘áQáå%`FL— te¯ÙaꊑÆy¬ˆGÙû~¨QÑ1˜áÆwiôìP4Gã‹êõÜ =Θ,ÇXn*¿¾ô©ÀX¦]�PÛV"Î’Ë eZ$+±`ÀKö´0DÖ×q3#|V«ÓQ s)gúÞ‚Ѭ\øçH b$ßÉ •ºA‚¯­A®R5&©Ú“ƒËò ÈÉàQ(玜+BÍxü\RÁ&B¶9^* Édˆ ‚HQ6cȾp”×nÝBUyÿdÊ“­9ÑOR®†ùr”Œ¡­¶á 7è ÖùçŽ�±ŒV>§À,F–9W'Âùé„­¦©™s6–¢â|pD7ºßyfÀ‹hË`ŠÑày´’çÑœA-û!y±óÜ9Ïöôq£y;�´ó–Ýñš=š@_£:âUeð”œMvÔh«„D#�ÐôÉDIh›Ð‰ÒH°ùÍÙ#qmwJ¹Ë8P�œ.{N–‰Óe²÷^9íղςÐNì _U£� Ú“ze‘s¦õªtÉ`Ýr²~ ™&XˆUŒ–öVì8‰C¡–Z†Ù÷p¡ªã_¾Ë\VùÐŒŠå¿Õ“Êg}Ä»Vú=~ ¡ŽïYô¢A·Uþ]±ËŒOx´1ÿQÇþƒ‘N6Öëýd庱Þ8¶)0þ»š^ÞÞYq¶¥z÷QgÛƒRkrޝ£©ãw]å7£¹)¾Ùz²¥�/Zxéêx<2XóÌw�êëÛ]Wúûv½^9_Šê4§ P€ãwà슖"¬Ò²-UAÃÈÞ5’g »Zé™ HƒÌqF<©òHUû*¬£!˜\Z‚…VE²�“iº˜ÀOR¦�B]Æ*ØÃøÚH£¬ÿ¼š10j¨j1(�vV5L̦ÑkÔÁüVÒ%V<€ƒ¡¥l_4Œ8W5Žˆ c¸·¼û¤†ÒÈ3�¯]ÎÑ:èeÔë¢( ËjïY=Ψ·ûýìÕ?x¿Ý=~ð÷ïôXûwö„2Ve½Ý �?�÷gÖ54¾­­,–ÊVŒÓÀÍ^2¤d¿•¬F’+4ß³©�#¦W5kw Øoc=¥Dkž�­�>�Lø:6ÐTI1Ê(î%.FxV£äÊßC„v«á~cºX ‘”8-õsK„º&©[§Þ£(�*XTBU—ü2*\Éʆ¨Ê¨Fá„P¨˜ª#v8Œ�ôB½!Õ+Ã9gGºÚ£;£ç¯Ž_‰r;›=±:g«‚Gû•ót˜×ïsÔ>èøó™g¯0˜A`‘bð‘-)�z¦–6ž5Bû^¨˜ÅeÍùXÔL™ü°³dì¡Î½_Ç@ç )­í/m*ÎÔÓ ”ta‹4Ó@ÙSæÙVdȈð=#ÌÑWî«pc%žþZpš}°C¨¸‚‘°å]2ÌÎ!}½Ùq/ “_ɢĬŽI:Л ³-î‡a’Åç´`LgÍõXxJª)mÈXÂÚWFµ.ŸÄB³*V|Ù(#¶Z�¸�¸:”a?ç’,¶ßMA „<8bhþýù#üÕ¿÷9þñ�»<=™VÃ>ÀV;ü f4<3$W8 £>ñÆñIýà;GǼ°½Yyê»7Ö™�œW½FÁ2g¾{tÂ{7×™ú¹¿}û>·]Û2oâŠàønwN(pw±äÂtÂ{6ÌÁðÅ»÷yjc­:4Þ89å ëù¸;.N'<µ±Žˆpš3Mäç»À«G¬ÅÀuÏrøêî7Oü¬g,Sb©ÃÙlþäå ¬ÅÀ~׳H‰¹`Ïùö¡Õ;øä• üÙóçùÈ|�¯Þß'·�Ïò‡‡Õ8“ræå7nòò7ù?>û%¶Öæ<ÿäã›r’—¶§D1ƒ÷ǧüðù®Î§|åþß;²Hï�^ØáöéÂ'bÅ9OúÌksBîœ.ùöáÏmo±o�œòòþ![mÃO8ÜÐ7÷YY›v&-‡�9%¾¹È{7Ö9è{¶&V x"?wý Ç)ñÙ[æ€øSW.°Ó¶|Í i�ª¯±–ý®ãÂlÊîìVlÿYløÝ;÷P†â¿úÖmNRfwÙñþ­�Z,t£‰|çð˜N•§Öçd„o<8àÁ²ã…�-®Ì¦|éî}úžm/šüU¯°È™¬™>+“è5³¿ìyñþm®Ï§„8쯀Ÿ}ì ß=:®ð!ïÞ\g""–�qØ÷|íÁ>׿Sv—=WçS~íæ�:¿MçrÓßzýõ ²½±Éóïy¶:ŒÏg²&ç=¹~ª Xä¼µž’¯[Æ\ òw5�^Ì“W®ðæ½]۩çrl|L’*ÄÊ�“·Ý°ù7¯=ÆþÖ Nræèô”¯ç;|ðÉ'˜O'n,(²NiOÉÖ¤¤ ‘ÌCp>;8áEÍ9¤ŠCÌÀ`4‘Ai=KÅxY(üåyâ-ÈÆÙŒŽ©w¾�«ñx, �סž–�r¬�"ž=æ2):dß–ŒÏ’ÍŠP±qÁéA‰Ñ¢Ò,Ûb�íÌɯdM5³·OÉœõ ™f¤—*t¯ÈM%Øfä7gXÇX´¢œªBÎÁ‹¹dÌâp�ÔȽYÇ|X€Ã\OÝúb ŠU<£Ãî”EQ ¦Wøw¯Þ»ÇI·d#>½¶Aa„“”k+žÙÚà[£âÂÑb%w`œU¶¾Êú~bmÎ÷ŽOj/žX·hÿâ;ê{£:Iµ:.M'ì÷}u"¼wÓø`iK,°8NSâ7nÞåÝ›ëü�·nÔ{þ»?}•­y9џ²Ë$IdzÃÀ'ÕzTÊà0§Šoƒèë@¨Yâß"ÈD`ê‡j¢£`Ž�.£}†˜Q78[ö¹Xúdo²O‰°Bt©°Ì°l�¥’O2zªôÇ=ýI�ö‰œzD[þ_ÞÞ,V–ä¼óûÅ’™µœýœ»öÂf³6—f“IQ µŒ$�% 0` `öƒ Ûóä†1¢a{à‡yŒa˰ý2À¼Ù3Á’,R7‹l±©&Õd7›ÍÞnßíœ{öZ23Â_lYçÜVk q]Ô­SUY™‘_|ßÿÿ-ŠÐ4éèº%]×áúç ë:æ ˆ�N戧hSdÝTMÅhjmFk#ÌÈ¢pT�F�-¦1©®Ó,—žÑ9Ì€¢j}M³¾¦©FšjlP�A5–¶©hë[ƒò p‰‹¶$ÙÖ{|×'b€@fõ]�o=Êk,£ÀMSiƵ¦òa4�€¦R45ŒG‘8#Éõ˜>HÐVˆOÙà[‡×9#@$‰�ÕT}Ôe4mÛ²\8ÚNjni­¨*°•ÂT:D!䕬c¥î‚qÝkzãè;Eï4Î…TaÚsk[k°•BÕFæ—êB‘æß…Td† c”÷BJ:/ z¯BÔ…$VNÒ ˆçééñÖáOmÎÙ¡å!Ö5ÐHMck¼2ÌfKÎç-ç 8›;f­â¼“û†Ñ˜Jc+ˆtêT…c×IE�H­è=¦ë®“úZyŒ,)ð §Áièº CjR£�ñ9…ZØ'uÒ/³íŸä¹ÊÞ¡õ^iqÌŠí.[©*¾�©•וS—¶¿ÊmC­à>ÚIï1�íçþ,%®“çÊ ÝÅ\ìF>Ÿ~ï#®ñ�k¯¿8æñÈ!x¡µcºÄP†¯ùôE»‚¾žœ=é^.¹ñ±ùŒŒyXÄ€\ʇÏVÆ"v'_Lt²ô$¸à“Òyûò‡jxŽìˆæ a?ó>D‹êpßHz�‡:{öE�#ÖI‰µ\ÔêAýR +�àZ§­2á0±ý¾íµ÷Ë$` ½ÔEIaýFb eWé3¦ZD ¬Žp¸åÊÈÚ^ná…¹ú°ÅVÜ€~ D1󒝿—ã âÃË,* ¾¸Zœ^@!WDø8ReKÔêsU¡¼¬Ñ÷ô˜¿êÇ_õuüÊßåùÕÊ1ê’cKa¿"´‚1åCh¨Ò;/°”9€]æw^gðÍûˆF0.IRl1ÔH ©Ê ðª°[!¸Êî)(ò¸Åõæ¿/æ5ñ}43óñ¥q?[e�S:_þ2¥®Æ6.ÆV¾ËÑòªÃf¨Ò Ç# >¦,Š›ETÈ\Ty‹¾ÆV& èÂóÕç!*½ÔWw?è[žæOŒû*úÛXŽOœK¹kÁ£¯¸—Íà‹m*½xãßq³]½ „Ü eŠs×�/ßã½ìãôJ©±Š ^©xæ¾K^¾)}N’±ùÒé~¤/Šižš3ô )Ç&·Ü ÿ IDAT*…^iÐ1O»u,Z šå1–ù¶Œ¬ˆ¾«Ä²—1í£×)™`S^‰rëðT¶ÙI�Nå»�J'Ž�€¡Z¹PèN6ÅÅ [KðîwÅ8ÅþúüG¬I›8j) ŠØvh�eG-Œ‹püÊ-sØÃTH£û½K‹âp”:*”hñ‰€I/ ‡ !õto<’ÚñïüÊ3ü·ÿèÛÜ;œñõÓþí®e»®$¼RIú�´×F UÐŽÚç}J)4±&ñ��O†º‡Ë«U*L|k6çî|Á Û›€€"«ŠÝ—®î¢”bÙKŒÅÍP7àpÙòÖÙŒç·C=çxqÿ�_º¾GœnŒ¶ Bãã›ëxï™÷=?99çéÍ5žZŸ2ï{~ÿö}~fg3Õ%8k;ŒÊ¿ýÈÆ”¯OqÞ³¿l¹2qm<¢sޝÝ=àÑɈ'B¤À‹ûûÌ�ãW®_ ÑŠ­º Ê{n„ôC›•å©fÄ¿¿³Ç;®ã[''¼xzÊA—ó?ŸÏøæ+¯ñÍW^“Y£×v¶ùÐÕ+<~í*W··ØÝÚdwcƒQS€,‚ýQ6¸ & W®É¡Hú`ò,-ÇÇÜ?:äÎÁ>ïÝ¿ÏíƒûìKîÊÆû¶e-¿´¾Á‡1\Õ|nw›EïøÝ÷¤øí/]o˜Z“ÒGµÎ1)u½x¶ÿè üÂÕ]Ö¬á+wö™÷=ŸßÝæÚ¸áëw÷9n;NÚ–k£)‡KƒF¼kïÌæ,œãùíMFZñêÉ)wçK>¿·Ín]ñÒƒcÞ=Ÿq}Üð¹ÝmÞ:;Çy!¥bþòíºÂ§mÏ«G§<½1¥Ö†³¶å[÷ÐͯݸÊOOÏùé©xè?³¹ÆH¬ãÛ ‚_›p´ìØmj~çÖ]*­ùÙ+Û¥øúÝ@Òy\ijþï�çûxÙ²7ªÙkjNºŽ±1¼ôà‹x÷kàÅýCœ—\ä�NFüñÝ:ï9éz¾tm›oÝ“s­y÷|Fç|ê×'g³×Ô¼z|Æi×16š_½q•ï=8–{ãÁ*ÍÞ¨âï¿û.¯Î$ Q]Õ¼ðÌ'ÐÚI{•dºJrNÄ¥':C”zõ…½>éá}´ÈïµW [ëklN§��ñ'ós~sº�VŠŸžŠgôÔvë:fž›Nø»7áïݾÅIß3[,xé'oðñ'>Äæt’tç*$PV€5&µS¢M{ºÔSma‚�&x’wUéb Š~€xÕšX´²¨Ç&ÀiL³ÙCÈû휒”%^aœë%/¾Ë8ŽRs+u>|4—t¡}¤c„ðPQŸ çSJúdan�ߌ†&ÁÖ|“}_‘Gqލ Ÿ•¦cy«ÃÓ)cÐÆ€ ÄRðø‰© …ÝF‡Ô•5x”Ô]# xò÷HD‹+lØáý‰Ä…D (¬ñ’ÃÛjMêåš©G8ZÑöŽS3çõ;‡Ü==C¿9Ý  äm£Í€(I �úS+uWÒU)Å3ëÓTŒà°m)QªTkÍØŽ–mªYð¹Ým¾½ŸÓ í�ç.}ÿÎÙ,éãZ)ŽÛŽž ”â£k¼qzN�çŽïSÑñïÕü­ç'TFvÊPK×Uô}OUkFÓŠfb©Æ32P+0”lr…Ìs$XPƆBÔ’ƒ_ª{A9¢‡£*�Ö h§ñ΀ïCŠZ“Yò Q”×B´–Î[ÔY+)ht ”ðЉç¹Ô8°ô^£:‡_8–N‰çµs’æ%Ôñôà: «bŠ—�¢Ì*š�†ÑfC³ai6,£©EWN¢,ôL‡­C1àVj8i,MEš�ã5K=5˜‘B5Õxh<ÚÊS…bÀ²Öƒ÷d×I[)¤kBñM•Ý(÷±«T‡Ñ=•qŒ*Š�RÉ[¿²žÊBUCU«9JXû±hðÀÙ- X ‘-ºG¢3âÒsœŽzJ(à¬;0�ØÆz¬uXëÐ&ÛKÑ1LR�zt—uv­r•¸1¶¡ÄÏ/âò+øÍeí)þ/߯~ò~§)xQ°28%áRþnˆIHÒÊõõý‡=|°dŠ3¾ÿÍ}h›/«qùqù³ËÆbµ€ôðé¡yáŽø€;�õª4çJò$D–j—½›Kˆ@à%±Me†ˆÍ”Mü\£Áí)`ˆµB=F¤r ^ã�J‘Ÿ±-rB?¨{#3‡ˆ¶£ ÏìhºB ¬üí}¡´¯hwIù_ý}Oç,?ŽÆ@\W:LxBºˆ0ØÎÇ8½bÂeE3èíAŽëb„39PF$ceÕL’•†¾ï$/¿ØùöÝ_õãý¯ñ·dõˆrpË,ŽMoUñ©O?�F |Z|Á3—ÁêÔ À~WxÔz!bñÄü¹ „€|Ö÷$ö«w’·»ïW&ªÈOº¡¢`Êý‹Â(åŠKS£X^'Óq�O.]-÷« C_°8‡¢ÄË›@|õ*‚ŒE?JR î¹qˆ b€¤’ ù ÃÆ ùÅñqƒ1ˆÞ¤}•†c•û™Aó$KŠA6¢C�Õð÷q|cHÞêÊSÁH\]“r Åêfè‹Î I˜K6æ‡<.cÒ…€raEd…'ï ‘¿xȪSåº(¯ãӸėEÆ”mŽõ5¢p—óäÙr1-Q¼°J24…Þ­ ‡†TA>Á«B4¥�x°ëMÓG¤>y'¹€)€'ÀC¶×#`éS>dñRÔÁÖs�ð- “bÌ4=&ç'K#nt˜ÃFz§")FðœNZÀÊ]Š}Vù³¨XÄëÆ¹Á±ÖAR ¥ïÉd‰E€½×éQQ 3¯ÈÙP„­ô¨ŒM‹ã•³‡&;Ùû‚‹?Þˆ÷™ùFkàïü­�ówÿÑwøŸnßæ>ù$ïÌæ©0ÀµQ=(8=ù=hnÖ9¥ÐwùØæFzeR|Ü�¸¼ù½£1:¥áyõø”«£†­pþŸž�ãÉ‘ •Rì�êt®‘Öüú�+(¥¸;_ÐhÍãÓ|®Ë–/ìm£”’2mKï•1ŒŒáçö¶Y¯,ó¾§÷’š$ áõ“3>¿·�nÏæ|{ÿ�/ìmsu$Þï[µ ÷IŸ ‘óP¬ùñɘ›“1ÇmÇßÝçSÛ<:ã‘â®WF5¿²³Å¯lmq{6ç½¶å³s~t>ã›g§)u Ⱥ~oÿ€÷öøÖ+?*ï2ã¦agc�íõ ÖÆcñP­j¬µXkUâM0_.ñÞ±l[ÎçsÎsÎæsNgç�žrÀŸ‡=dçé××6xÆÖl55ýÊwæ þäþƒL­xj}Š÷žeïø³“cžÛ\ÇjÅýù’ß¿u—«ã_ØÛæÁ²å�ÔžYŸbµfd¤øcc5o‡â×WÚŽ½¦â÷ß»ËNÓð�^ç¬ëùƒÛ®ÿÜ•v›šWŽNqÞ3ïz–Öpsܰ?_pu4â•£œ÷|bk��ºæ�C>þ¶7yl:ænßç¬ëPJ€µŸÈªÃýù­àÆxDc4/?8æhÙòñ­u®�F¼xpÈþb™ ¿v|œzš�´¼ ׳¾ç;‡|tc�Ó®ÃjÅWoß§1:äöŸ§?¢R^9>½»…wŽ—B¤Á Û›<2óÏß½ HÒ�ªJ$_¥M¨� $ÂZ]ñæù9tÖó{‡‡rß•âù§?NÓŒ$yÅfÜ�JõÈa¸·Å7{ÌP¿.÷*ñ¬tÙ}JùXßZxêÐϸ´„À/OdÇ“àWQ0>`Ãý�x,>NK¥ÿ/ÿþa©f¢]”ì2.!V±–¸�âcMÚâÐŒi”ä@´ ?IÁeÝôÅÿñ\þÒ¾­âÞïçqY†ù<ÛâI¿*mèÐ ¿Ò®‡=2.Vë/ÿáûœl•¸ôû ý�bId=ÚÈå3ëZgÌmÐ1—?Êv}L£}�¡º c»ŠëçÇås9æ…Ð+ÇÇ1�t_1¾(hÃ^ÈçøI”MÞ+TŸ4ôرÐî!$Ä€Á„èOqŸÚÙd'œÿí³7'#6‘÷�OÇéÚg]ÏF]ñsWvIteܤH„ï‰çu,|¬aP;áÚxÄ—®í±^Iþe«Ÿ/s{¶àoܸ‚B¢+~xtÂN]±cj¦ÖðÈdÄÔæ}Oë<¿tý F+Þ>›ñÖÙ9?³·Íõñˆ]cØl=ûCW8Æñ£ÙŒÛ³ß›ŸóÎCR÷Ì Þ½·àÝ{÷/ýþ_ôa€c¹×w\©*~yºÎ#ÚrcmÌ ëÌ»žŸœòÄÚ”ŸžžÓ¿|}�±±|íÞ>§mÇ—®í1 ƒïÌxïùÔÎ&‡ªÅ�R¶-‹¾çé�5&Fó“ÓsÞ<›ñ™í ¶›šŸòúÉׯ#>¿»Å;çsf½ãx)ç°Z±]WTZ¼·¿x̳›ë´Á«ú÷Þ»Çõñˆ_½y•;³òñÿbh[kàÓº?_pm4â+·ïSkÅ/\Ý¥øãœ}nw›+#‰ðÞs°l¹9³YUì/–lV•À‡¦c6ššoÝ?`Ù;>³»ÅÕQÃWnßÅ>ŸÛÝJ©‹:ç9m;*$bG)Å«Çg·Kž^Ÿ02†[³÷æ ¦Öòk7¯òÒƒ£905o FIñäs×óòá1�M'œwkùê�ûTJñ…½mŽB� €Oïl²S×ü`vÎo¿™S‡<ý¡§ØÜØýiÅ6 Œ^~\°àнõµø�¢ÐïãUy7wwøÑÛo3_.y¯]òýÃc´RŒŒæ¼²$¥Ó'gÌB1Õøoy”¿ç6oÌç8çøþ›oò‘öO\¿64ì‹.Ũš¾Ïs$ÊV¥ êèˆ¼Ž©†²ãÃÐx[FuI[#�s*%/4@é˜*Ç'·÷±&@¬aãSôjt�îÃ3ëfa7q*Õ'É:fB_!ң盹°µRôZä½5>ÕÝÄç‚Ò±6ƒÐËy)fç|4úk5¸àÍ[è›)òP©œÆ*¦³ŒzS¡K pMJ‘¤�ïÊj«©*Mcc£YIgb¬op­qhNgK¾ùú{ôÎó˜­øâHöÇG'£THuEâã  ”R,‹¨¬g6ÖR4‰pw¾H¶È�Ù| ýžµ?¤ÁÍñˆ;E1ág7Ö8n;Þ )ÍÜÊú›u=jvŒCÍ‚×BM”™†?;™y}Óò·n“ºrn.z•uU ¯ºRر ‘@ ª’Ô2Tà­ ÅJ‘ùh$=�Ö„"ÃVj Ø@𥹠}(õ:™ÆŠŒËlJN1ÉŒÇÄŸÕÀúÎÑ·=®êñ PÿCåAw(o0cY¯FTËbÙ2_:æsËb¡X¶Šv Æ ¨XiE¥ kêqÅh³¦Ùa7-vCS�Z· :tÆÈ‘¼Ú¼U{´#¤œTèʃêpôBô=ªïpn†g�Ÿ‰³‡šW¨ªp¶õÐ*ÔRÃÒ {ƒò&h¦±�F{�Ò=ÚöP÷Ôø�ªR $£=F÷P+Aº>+æI¤¤ÐH®—Y®'3) Ëôâ©»ej-Àu"ƒ�öI]�,câo¥NWˆ’pß·xßmyŒÏ `òp¯ýy%öGô �Ñòªð>”vK}A¼uCV‚°W¹œrH첄‘È©h‘§åøFÞÁ�j�6L_ƒ²šZ9”UÔÎ0q&8IÚÔ¾ ‡z„0 Ý;zݲć¡wÉKP]îhc:×b$¬+ís*—ÇW懮—4O]ÜÛ=DrOl‰$wE­ÐUô|øöRC¯ë�µ|ñöÓˆY”¶âCú1D.rcýÊñ—^.~W˜êñUúqñªK[iG0²³sÙemö³äa¸p½2ÿÂj%^%ýnÀ\Bj\hóåC*×TAV^rPtXUÅÄ/µÏÕ.yWZþ&é½8‰äyçÂ"ûÓ°‚a´B<$­…„m„çñÐ)†Ü%�ö!E�Š¢TÖZ¬ë£ç¯ )æQ—î]râ(ô$;�H…ô ƒææB¨•ãW%dñ>â`"Ê’µ¾"�.a¤xX¶‹4Q�u±�Z È�Õþ¾?.4ú’ïÿ‚¾>|þ%?>Ƚð¼_¿d"EM÷î¥K1*r¥1" )½�äIu},šÓÞ¸f;§R­�D xŸŒ#!Äc@€R•b.�«T -Hmê~4&|Ô=Vº§š~ ñC`/DäœÐ>!ß&�-ç*üà\— wÜŸ]Ôaâò)Tè�Ø[Ó²(p &eÆõð}Žì( Í´äˆQAùð+çô¹½q>iÞl‹µ¨òúÎ}pÉSº»Áx%}¨,䎬lb+ý^�Àg.Ýç“ôÂKV�|�VŸÆ(|6´N@¿÷¤yŒ Óï¢sCÁ#e\Röds«ýMcEÒ™S¿.l%z¹ÿê+&f÷UVˆ]y~sº.AÿsŽæ8!Èä¼ i ð¯ù¤Âq… âƒq©ƒA£^Œ’ˆ…"f#qî”ó£G‹"8Rò‹œnÁ¯(>�e°Vã<ŽkÂ…3Å+‡ ZY|2>£›½âÖ>P€£l‹µRò³wn +”ê¡QNBÌãj’’V) ùžXËño½Àßùíoð?ß¹Ã××%µÀ²ebÅ»`ZÙTWd¬?4•È‚wÎgì5u:öölÁ¢ïSªL °]+øÒµ=@£TJésw¾àöl‘Sõ=¯�œrmT§(”g6רª¤¸fï=Ÿ ‚�ÛŽ·Îg|bs�‘1œµ_¹sŸ/or€‘5Yð¹½mñìöžÛó7F ;MÍÒ9¾q÷€§6Öxt"m{ùÁ»£†½p®Ç&ãà‰']ÇÍqÃÞÍ«ÔJñ½ƒ#vGuJ›ôÕÛ÷Yzǯݸš®}Üvt½£Ñšk£Ïo+nŒöK>´QsíªDW|çàHrIWŠ»mËÙ²å¼wüùržrÀÿeV©à ŸlFlYK«7êšÇµeÛZžÝXãh¾ä‘É�â¼ïùÝ[w¸9ñé�-æ}Ï×�QÀ�\‹©;zðžÃeˇקlÖׯ#¾qÑüú�«xà÷Þ»‹~ñúë´ž÷=Ç]ÏNƒD£hÍn]ñÆé9Å Û›lÖxç>§]Ï÷¶Ùmj¾vwŸË–³®ç {Û¼ÒÌ8ï9ïz¬Ö\5ÔFóÎùŒ÷fs>º¹ÎFeyëlÆ;!ÝÐ_»ºËë§çœvJ)&ÖÐù˜Û_¼ixtʳÓ´æ~çÝ;lÖãÆîÍ—|/ý?{e‡­ªâûGxÄQáhÙòødÄ�OÏ©µâïܧц�m­Ó(Í·BaÑÏîl²U×ü?!"âpÙñÙÝ5î-Ä+Ø(‰ŒQ(vG5kÆòíûX:Ç'¶6ج+þßûB”€Ôbøö¾x5wÞ³è�ÈKÀjÍá²ÅiÅýöÛ©Höõ½ë:YEÂ� À#©ÜdšùdFÚ!òËá%ÑKbï:åpª ”«IýM°© ¾¯�U)E–—ÔOÎ�­ÀVT•¢B]÷ÛÚÞ³\ö,—=”ï;h�AKÝ2C"\oÁÇ4¯±å?ˆ¶¢ÜWYþB¸£Dž;/¤�ð §B�Dmã\ˆN‹wS…¾R›¸¡mád;¯` ²D/ZÐy�„{ñtÅùJ\AÔ†‚(OíN „¦ö).Á r‹/yÉç-ñ�pÙ÷}d;óB|C:óP»"‘ù§Câ$·EQöC;³l-q•e IDAToú�Ò…ý¼rñKZ^î«Ãk¿�@ 9òý/&J}³<$‚ÇAåvälY–¥{šôÒkY›0~˜²0ô}ŠV\í{Ú~Êi¦¼è2ñ¢qBÛU88îj"’B_‹ ‘ˆu�"ÁàŽ­Éû£Jk"­„”J­tTÑ:âMþ¡s¥ÊTBQ↿Ӌºð#_ܸŸ#÷Yæ _\câY®„ö$ø%®ÓÈ/ æaΧï¤- œòzyoœ§W†!Eȯ™È¨4‰Òø—¤À@ù×s1UW× ½òøÖ…ó—ž›ÑÈpDN -GŽ�ŠÀ��®Ï©#|’#Ò&«Ä»3ÒEYÚ’½I=ÿî/?Ã?ü§?àÕw�øé|Îïò¯lo³Àoç=GmÇv]¥¾ÿàð„�o­§)µní µÓ�P\ØÞ‘Ͼ{pÈs¸xo>§Ñ&�ï»MM­3‰°f-=xóßšÍÙ¬* $¡ÇtÎñé!:程vL+Ë/_¿ÂÈhκìA ðúé-?³»…QŠÛ³9ßÝ?d÷ÆFÁëzwT³UÛ4¿¾tm«–-ï�Ïxns�­­uöK¾qï€OmoðøtBç=÷—K6ŠhŠ�m­£�Jw ™Œxl:fÞK:œÇ&cžÞX£÷ž÷Y¯l*¢¼[Wà¿¶³EäÎÁ²åʨæåÃc*£é�×wNÎe¾Œ,sçP�£r][Њ…ê»ãšÊú±\7ÔZóòÁ·fs~ao‡5kùÓƒ#Þ=Ÿa”¤’:²ÎºZ>³±ÆØhI‰4[ðé�-£yýäŒW�Oyl:æ…íMîÌì/–TJñÂŽ¬�ͺB!ëûÇ'R\xÙ÷ŒŒæwnÝeoÔðk7¯¦ñUJñ7¯â¸Aq?i;>4�Pé9�¯MøÓƒ#­ùÂÞ6kùÊí{xà—®í1­,¿ûÞ]½ã¬ïùðÚ$yïN�vÎñÄÚ„�®-[>³³Å•‘Ô;8é:¶êŠ_¸ºË÷„8ëz<06š‘Ö¶/–¼v|ÊÓkÔZ³¿XòÒ!Ñ~ã‘k¼v|Ê[í èB*+Ÿ@½Ó®ã´ëyjcÊñ²cÍ~çÖ]vêŠÏïnqÒõ)=È Û›l5Ug}ÏW›Šwg ÆÖòíýX¥yt:¦sR”T…�ï,üWo¿Íq0×§ë<õøS";]š£T��½PîIÁq$¨Ž”2MŽL‰Ñ“6í‚È:SÔMâöþèÞ~üî-–]ÇKóŸ�Sáè�ºbÖ»”®åJS³VW¼€ÑãeË|å*ÿW]ó¿Hš¡[÷÷9›Íyþ#O0išØàÈ‘û8Ø»¼€àNû"Çvt\ÉQ¬Ig’œ8¢“šœ~»çú¢.Oª“tC…q÷ù>È}ÛJÔcƒîë ÅÙó)æTŽSìn¸Çåû–o“÷AwÑ í}°“€/£&²—¶ò¼ëzç u•Sè¥Yù]?�ÿZ€§œVM¥ša@ð&çœ'1Õb«"¸òaH¤ŸÎÎa>Fdc •Ö4•¥©¬D …Q=Þµà¤cn_Ï?ùÖ�ùÞOï`PüëkL”b«ªRú €kã†{óe"«f½¨¶Îgà³®u›Ž9mû\wñê�ÄÀÂ9^ òGæX®»±SWxTúívSóäÚ„ïÁy¸·X¢É…�_ ß­[ËdõÑ¿' séd®È‚0êÃȽ o¼ú@ª:I¦‚n­¢#]Êã$¾ÑZŠøzçÑ:à;…ˬ�¿Bú…†JœE•ò(I×jè¬ï*æšÏ6£B¯LÄ„20'µ�è)$ŠK{Ä _+”"“ðÁã^åH�8ÖÞ;úÞéUUÚïA�Úå¯:¼ï$úYk¤J°Á„ZŒÊx´ñø^R¤õ:ÔSh=ÝDÓöžE/ëO…uè´¬ñÙº‰&˜AÆ ÒºQ)ï«Ò*D°„¯ÁžíCÚ dqzY2ÎËéó*^±B}ºžbø(=«ØGù7å>‘ló~P�ô‹�8U,%æBÄn2†£Â>–ô‚ûPþ¦Ø‡WÚt¡ãƒ"†°r²T¿ØúüY4üV/XڪöæÌ ±+ LµCTÆTÒØ?l¼³·z¾Öå÷g•¬yÿtI]4¬ï¹h‹—Çû ñ|�.¬½|>I:P(µ ‹É…y‰ó�(NŠ{QêR^p´HÀ H‚æ�‚\·4Í·$VS$€ö¤ì*Îå±±ÖA¼ç«m$8-&,èW>÷;Ö‰w,4¼Ç|ù·>ñå,èÃ3ý©.>ãÂ^¹!oßâ©VÞç�¾J宾z­ø¾lOøMyʤ±ŸÉEÇÜ:¾šà Ÿštùãý¾,6ʇLÔ‡}öpïûúX½ÞêxçÏ.FJ<¬½jðrÉ›Á™/œKÉ=Ž)UªSR„¨eʵÂ|÷t½ŠÎRÀ©äýïÂk缄³õ.|^D £ŸIZ¢@*„M0¦¹IénB[}zæïsÑ×h¨FO8•Œ±Üù̽÷% <_C¢F‹mÑ� ÇÅs¤×t¾p½ÐþòÙƒ)ÛûXˆ.œ']£H¿Tž3¶…ùIè>}�OtŠ&™_óæ¿ó¬ˆzXµËÙ¢Š9”¾¼ìóÚ”û’ÉŠFàs�àýàzåkŽH~rÅñ¾¸×A ñå+)<~¸��/ w‘œ(7Ç"å“\ÛeÌ} sÈsÐs=^3ÍÑô÷êÓ?|L|lO.0�7´¨ÌF=,„ɦ”I^ì}{MÞíƒö÷.M�˜»7Ï1? BþEð<û�ù0‡bM‚4çs0Ï›X—ć¼Ð.�ŒÎ¹ÌLRæõeD Ÿ•qȲÃà” ÷`•ã¢dà¾ä¦Î‘"Q–xŸ£�DÎ9Ú¾§ë{ºÎѶ=m×ÓµQf"Tá©”Ãjò¶†ÂÇaÏ”:[c4×·Güïßx€ýÅ’/¬o0 À}aËh�«°Ž9YGV€ôã¶ãö|žê8?8:IÑ ÀÆØšD$ìÔ5•¥sŽ»ó%•ed$õÎWîìóÈd„ DÁk'gì5 6+Ë͉¤':\¶l7RÀµóžoï²QU¬U¥ßÞ?ä¨í¸Úýd#²VYž\ŸRkÉk¯�\εּtpÈ+G§<µ1%Ö4xíäŒM'X­hŒ¦1’6hÖ÷,�ç¹Íu¶ëŠŸòÆéÏl¬1µ–Ÿž�óýÃc6ëšõÊÒïÍ\i6*!!®ŒŸŽ9ë¤hò“ëS�ŒÙ_¶üÑ�ûL¬á±é˜…ó|ïàˆ‰±|zs�›u�Ö+Ë67ÙTšÏllð‘õ)7«ŠýÓ�7 ŸßÙbÓX¾»ÈÁ²å¹�5ðÆÙŒóN@v�‚˜F+ŸŽyíø ­ŸÙÙâæ¸ánßçǧg|zg“½¦áO÷�Ø_.Ùnj¶ªŠyi�Œ™‡zWšš'×§¼rtÂKG|vw‹g7Öø³GüôL<èŸÞXãþ¢åölN­�LÆ8/×Ç#–Îóúé9ÛZã©�5Þ=ŸóÒƒ#RÔ÷¼íøáñ)‡Ë–OíéóÖù ܘŒ¸u>g·®™V–ݦæë!•ÔÏ_ÝA+Íwq±äù-Igôƒ£ƒÜëHp?6sÔvé\ŸÝÝâ¬ë© µ¦Ç§ti³¾çVXóWG ‹ÞqÔJJ¶g7Ö“j<½±Æ?¸ý^ŠFû{ÿÞ#üâg·0!(TY¤`p­ Ñx�4Œ ªÖRW@;¼U™�&È ;••gÈç¯Â{•<·UÐñÊìÊ¢oÆÚ%Q'=p�l_D;W8CLOÛ‡ˆe,¦²˜¦B7ª `¼ *…² ŒC/¯�¢©£‘¦±P[Oe¤Ý94häPæ¯x�«$[MH#¤³ñ^ŽiÜd Þ‡ -í :¦�sŠÇL–Ýr=�÷‚bÓM¢é\ï}q=Óøb“wR¤0G\„ï\×!'c¥ÏLîEpFáˆÅ’Ãñ.“ˆQ.ee$ÏÛœ"È¥gŽŒr9•P_Œ±WH¥8¹RÐLQ'9¡�–ptÝúÈáØAËÿè£ÛüîwßæÖÁ9÷{ñN~a: ‡ªD ¼}6c=xy¼}>C¡’÷¥%ÕA¬K ‰8n;<žµJ¢ Þ:;çÞb™€ù³¾çö|‘H«5WF ch�È£G'c£¹3_ðæÙŒ›ãZ)NÚŽoÜ;àÃk“�æBqÞõlÔ6E<:s}ܰpŽwÎçÜ�ØijŽÛŽ?¸}�ݦfj-/QÍN]§~mÖ–5k9X¶\�xzc üÉþ!F 0i”âkw÷¹¿hy<¤Y:Y¶µ�…÷[uÅz]q¥©yóô”âc›ë’çî>?99ã[ÔZóêÑ)?=;çæxÄÈp¸lùÐt¢wx%éŒnNFüøäŒ??:á“Û\5üðø”�ÐXÍÕ¦á¬ëyãôœ�pm£VkžX›Ð:ÏONÏyns�§7×9\¶|íî>F+>¹µÁñ²ååÃc—-O¯¯¡”âíIðøtÌíù’«ãF¼´­å[÷°f ŸßÛÆhÅ7îðÎùœOíl2±†??:aé×F£@òHŽí'Ö¦¼yvŽRðäÚ”'צüá�}^?=çg÷¶yd2æ÷ö9Z¶¬W7Æ#öK–-ë•Ū˜c\qs2æÇ!já³»Û<½1åû‡'¼u6Ãjͧw6¹5›so¾ óžg7Öè¼ç½ó9k•e­ªxãôŒÇ&®�æ}Ïwö©µæ¯íq¾à§g3„ÄVi¹ŸÀnÝpܶh%€éõq#Þ¸JñìÆkø³ÇÜ›/ùÜžÔøÁ¡kµôë`±dÖK}Œûó&P�ŒÇüéÁ·f >»»Ås[¼¸ÈY'Å¿pe‡wÎfœ@ñJÓ •Ôs0ZqÔv¼yzÎfUñáõ)KçùêÙ ÿGð¢WJó‰�|‚ñhšS!cƒ@쵫Ϩ³G-Êø´«¬n3IŽûÁž‘t’âÐéxÊ[wïÐ{ÏšÖ\·"�î‡ñšXÃf]%R@©H¬ˆW¶>2óŵu^š�3rööþØY_cè칈rñTÄVÙ £Ïý]ßrÛ1Ì©†:Zr.ÉŽ$�stNÎÑ…st®§÷ño<è£ÓK&°ã~� Ê!¯ÉRò.8 „gÔJ@ÀÇÂv)¯tjsº‘J€À¨ÿ&’Ä÷ÎH d£¶ø.éõÙñ'’ %)ÇWô›âÁð�û¶¨(²'F�#ö,n�’þH [£i*MSF�eTª¨ÕÚÑèŽÚ’@¶—ÞÜçí'üÜxʧ›qšßñ:•ÿŒÄTet¨5cP�G�˜ZCòýƒ¤zns=‰¤;)ÒȽ7›³èZ)*£™w=­“÷ßÚüö£›ëx¼o<Þøº Á€/z ‘Ï´U(«BÔ@ÿQjIZªà-¯Ã½Ò:Œ‘Œ•Ö ­äèOÎ8{1ôS))l-œIL³æ¥?ažyzÐNêrXi¯�¡½!SFLK'…‚¥?Úx´1[ÑÔ5£‘¡©5•ÕX«B´� û¬òboªð·"G±Çš-¥© ý]KœŽ49‡èê½rBöÄ¡Ì+3ýE8�RÃå+îê/ƒm«2ž�ç^ÎÒpé£8MŒuþ;ßÃãÊã)�“õ£Ž òÖ’½²?Æ—q•a[.kßå.úYâ›…ìŒÎQ±�åø—¯<6{—1Ÿ4�u»„+ÅýzåIOU\í’›|é}z¿!ÀC̪‘>è³Ù/ ƒâªÆ$a.+ «§ÖÃK­Þ¿KΡ?ù¹J \x:�b b€^A«q­Ç-)°ô´´=…¬]ì\ò ê ¡ÂÁ·h0 ²d@4ƶ¯Ïž»%À †ä½Ÿ<¹ñw6^’9ܼ<¶xŸÈ†àMóɦvù¤T$Ò¢l“/ˆ H^c‰ (È�$œˆB*{ŠG�_é>ýó”ø�J¯>�óá Â¥@{º¥€]Ù¬âF�ï]yÎá&¢Tnßà2*3Ð>üçÓ.ÿÑņæ1QQ°g ¹T¢ Ë9tãøû´¾â˜E�ÚvÍ07ñÃ{k9Äñ �HÍÿ âìÂúö-º±9²iG/)¬› ÿ|Ùx/\ ó¼+òõÅôQQÁÔ:Û&+œDÅ´TæB[üГGöüL&¢ #âfŸ¢: R -i &à%Þ×p蒵F ,ý€0ˆDÃ*!å�'}&úÉ�ûS®;I[„2(%9U�©ØÑçˆI–B)TуH@®gnnò�¿ú*¯ÌfüÊÖóEòþë›"ÍÏV]12ç=§!L$^<8âúx”fÑÛç³ɰVÙæ4Z'RàÕãS£YÞþß}pÄyß§Üþó®§߃ ~r}ŠÕšûÁ‹úúxD­5~xÌ;çRXV)Åþ²ååÇ<¹>•¼ËZ1²†íºNÆÈ“ëvêš÷fs^;9ãÉõ)›UÅ›ç3^Ü?äú¨adÄõ­óWš†µÐ–�ºæ‘ñ§$õÑãÓ �OÇ÷æK>º¹ŽUŠwÏç-[>².Q cc°ZñØtÌ;çs¬R¼‹ßÞ¹Ïk'g|vw‹õÊòÒƒ#Þ=Ÿ³^W!%KÏíÙ‚ë“#m°J±V[>¼6åÖlÁ�ŽNøÜîÏl¬ñƒÃ~t|ÊXžÚXã`±äͳ^)›Œ±J1wŽuk[Ë›g3žZ_ãÑɘӶã[÷0²†ÏínsÔ¶|ÿð„ýÅ’v¶ð ^©`ž\Ÿr´l™V£¹Ò4¼ôàˆ5kùôΦ÷ðÎùœOïlqm<âûŽY:Ç�ñˆµÊrÒvµO¬M¸3_ ì55O¯Oùú½üô윿vu—g7Öøæ½,[¦ÖðìæoŸÏ9i»”bÊy˜…sß›/xç|Æ3ë<±6áÇ'§¼u6£6š¿~m�û‹%wæ ®ç…íMŒV¼s>G)ÅšµÜš-ØmjÖ« �¤ôب,ŸÛÛæ4ÔÍ8\¶|fw‹Iˆ:Ø®-ÎÁÌyæ}Ïf]óÊÑ ›UÅΨa·¶¼ôà˜;óŸÙÙâÃÓ ¯‹§üNSó±Íu^küƒ[·Òš~æCϲ³¹[èÅ&_Á�åØ@‰*wŽHˆ;ÉU²Ø(¢~1ØÉ:€5–eÛrtvÆ�¾ãæ¨á…5:FưÝÔ ë{³yÚctѼëùW·w¸Õ·Ü €ìÁÉ)NÏÙÝÜÄ’Ѓä¶F‚@<–¥>Àî}ˆ� nŸ�}ÓÛø¼gJÿ‚> ²„wžLDrØG'H—#CÓ¾[žJ~ÓgB<Þ8Ï�0�ÅôHàžB*Õ�Pi¿ÌûˆD ¢ÕE—¡¾9Œ�-½ý»Þ%b ÷^"Xƒž#QÂY'Šºy&"1 @)‚é³N›æ¤ô…£2œ5•£Ú2j,Öj¬†Z{Ʀ§¶’û�û§ü/_ù ½ƒçê†_žHjº+M�È8�4?}±&zï)Ó^ÅÇkf!2 ÑBGb ÷>û&€á‘¸9¡µJ‘Ûuÿ;ŽÊ IDATÅÕñ(­´A>”ë¡užíºbl GmGç=[uůîò[o½ÉY¸öÿðŸ=Æ'ŸmÀö8×Òw-Îxœ!D !jƒ¯5.€×º2â}]Y0:éÂ*¥Šd€¸½ûŽàdähHà›28µ*'° )RyÞMä€R!ÊUcŒI¤€ª,ª¶!ÝŒrÀ<Ô�x„ë^Šäjƒ5ÓhL­±•¢ª5¦ 5”GÓ€o<�épµƒÆCª1xßãÚ9¸^"]­FÛ8f�¨MðpWâ_ €í-8íÐÞa\/ùà!àSöŸèLCe¤_�TO{/ ³éÁÀs-ôMÈ�#錢1å}HCQX†¾°"–.°¡=˜eX‡ /$ãr«Î‡ S2>fñ‘HúPt`Q)ª4éY>㪽S…ãu�SúD |òË—ÝKfVEñopWïꥋõÒ)¾,v–DMÆó ÿ‡8‘3€™—YV‘@D–3õm0‘|Ñ?èÍÞeû¢T~zùx ý/ƒþ‹W,Z~™„{Ÿ¢·†/Îx91Û¢Eêt>?[`éñKO¿pt‹žvéh[¢‚÷•5�œU‹9Í£±”�² º¥ˆçפ@’\>}2.¢7qbejž|Ü%€¿+‹ƒ®,´ÕE{áµ žþ ?/=Å£àÈáí>•’TX!€È>–þ¥í_zž¯¦Q¢�—Í¿¼1®Ì `xºÄÔŠ§Zö \™µÅôQ\²)¤ JÚ”…ù�ȯñ8ŸŽÏïËv^Ü�SÛV—I<6ö½è«Œ =mŽIŠûçgïB˜?iS‰r®<ÇpôòzÎ#{ñQv%w5ÞÃK”‘ˆ”×Èò3!µNêd±©†§Z9oR` y=±²'J&2!å‹€ÜW!£'dIº¤„ı‰›s9– Ä/Ò“ eEÞ”ÓFeO8FHL• ŸXü‚p×¥¡LU‘ûÔ¥hŸ®ãã|‰©ŒT$·…ÐÚ`Lˆ° �A›H�@*Ü"G–O7·§¼q瘼u …xÛ–ãÊ@€)…ÏѲåhÙ&0|á=·góäaâ©l‹½e'¤b9í: ïEïøÊ�û<¹>MócÖ;¦Ö$’áÆd$9“¨' ª¥uR xoÔ¤¶}ç@@Õèý?2A±QUôÞ³^YžÞ¯÷׎OiŒáê¨ÁÏöm›¢þ?ÚÞ,Ö–ëÌïû­µjÚÓ™Ï�ò’"%Š’Zj©5t·Ýè¶� #OA‚Nüšy3â †cK $pà—I�'à$?èv[jÍ¢š¤HJ¤(Ηä�Î|öÙcU­•‡5Ö>çR²�싺û콫V­ZÃ7ÿïh¹äxYsÃ9™b§,Ø, ÍæH)xf4d˜güüø4âÉ+=þ‹ãS®õmT|c LjÛý^�;n z\ªJ—5ïœNøìæ—ª’·OÏøËÃc6‹‚í²`Ò´¼~rŠ’+®~C¡$ëeŽ’‚{“ŸZqgÔçhQó�‡û 2ûœËVó“ƒ#ö–K>5²QàNgލßã¬mŒÑåªâÕãS )øòö&}¥øó‡û|8�óåí úJñò¡…dºÒ«èg �5`Ýõy4_P)ÅÃ7ûß}tÈ›§g|e{ƒ›ƒ>?=8æÞtN_Y(¤‡‹%‹%›EÎZž¡,µá‰AŸ£Å’wƾ°¹Î�QŸ÷Φ¼vÚ—5=%i´áÞ|Îõ~�­"çþlÁ{gS %ùÃ+»Ü�X¸ “ºá·¶ÖÑÆÖÎ(•àdY“+E!¥…݆ÿòîÝ€ã~ãòMn^¹nKÄW¹‡g^]þ)EËõÒ—0Ë ßÃó°H Sž±6r÷áC–ZS!ØtxüRØÞ)ðä°ÏiÝà#Üï m”7’ÖZóŪÏÍ^Å«Sël™.–|´@U” û=¼ä |†§wht›ds9c»ÏÐmŒXü08ô½“Ú?oÌF°ôÙ9¬5&ðµÖèÀûY.(Æ]%µ3ƒÆD™ ?ÆÎgyíŠrMŒÒ÷pÁ­‰Ï¤5.£!ŽBغ tƒbÚDvNR“Ô�dð/¿:~é2Œ—on�vžZ+`Œ&m˜Œ�) “K®Q Ñ(lqîBiJ¥É|t4çþöû,ÍÍ,çß®YØ;ra ƒ~ÍIàÆ `zÀFû§N„ãeÝq",µf©m-‚›+×~f}Ä~âôòô×_?kup \îULš&¬÷ç7ÖÐÆ„{o•%¥¡ýõ<çdz ß9±u ¾òÜ€ÿþoßrÐ+&îÃ2³Ñì½ÑËe¥²‘ö¹5ÒW1ʶVF)„r0B®®€È3\¨uX']½U&P@^æ¹Hët‹•kýg#‚,nutgìV ‘eòÈÅ=lŽ7${èšL"óYˆRÙñÈ�Þš 0™F]èId_!« YJ->[@yˆ¥Po!q ® ³ƒÀ Œ´Fa¥5Rk„Ñ1žÒDý^H÷\yfÛÊŒŽ�FÏýóëtpŽ‘ {ß'ik^ØlI.3 ƒ¦ yfÈ3I‘+r¥È3ëÐʤJê€Û¹’nr”%¥Ë0°:™ìðïfNÊ­¡Ñ²kiÂéÁÉD;Þ”°A0Û]dš²÷ïʩۈú¶%21”§Nª•tº'èè¿¡o"½U”bVm Ÿ¯!†ë{€ß7�Ö=­J á]:&:gû¿WÆÿ|´7ioÂŽó:ò¹mÀôÉœ·÷œÆ‹~íŠd¾Ò³.šãÎ)]#QÈ<ñ׊^y÷—]” ‘ÌC÷zceV:½k8égwˆÃyé¼¹/$pC¡©mgÕöíDá\ÛEøœ.z›E ­î7œ¦SÛczŽ@}ó8Ç€ðK1õޤË�ÎßqVGdõåE߯^vÑR_!,îÕñ<¢bÉ]`:»ÚG„TÞïÚõËä_ç•Nüjÿ/“îoÿ¿@ uŽ ®¹ðžéwç·xäñÝurÎ1๦Ϩ5¦–:8깦vŽ�åR;§€ˆ™V(bn§@²áÓTcoPÓN¹0Þ€goØÎ�nv’rcº‘üÑ€ë“(†ñ…‘ݵsÕý!ÙÀ$}0Ɇ×Ýþu½™Iö@0ü§Etîg|Áa‚Ø!J">›éŽÎ �–ô:köq†õà ÐÎ!`¼²ÙÈj{Ál»Ê»ˆ„ÛßïXQ"LÆg|´ùE}5~yGr"Ο°ãXríLh��œêBY¥FÝžŽÓ9wñkÃÒ ˜Ow;¯Œ‰é~ŒÐÑž8–žÉÊ$bÂH�¶‚SÀ‡öxgaH6>b_GAFz‡€ti»ÒFxI§Æ¹(.鲤p¿ûa"´N*¤èFÜ{ˆ ½Âüs„ ï½�éxžÖøZ –DÈ/‹óì!ò1ÖBiœS n[ë” 4ÃÑ“&©i`⸦{ÑöES7:¬ ˜¿ÝËéØ{ÍG¨Ì:2C–áðR­"aDt†x,ìHg _¼³Ëÿö�_±lZ>\,x¶ßçfYr¶ ÊT0ôJ1ȳ°%2!‚S`¾ìœûþdÊYÓ°–Û̃…ÖœÕ ë.!“‚ÛhÖj„°™¹”|4�ó`6g§,B°7_ðÖøŒ›.Â^¸gÙu¿ÜôdÇuÍÞ|ÉnU²–ç,–|ûÁ>7ú=ri ‰o�'TJ†¾Ùhý‚LØÃW{7=æZó“ý#YÆ¥ª¤5†ìÑh õ㺡PþÈeÁ�~e�Îã YÆÓk2)ø÷÷x4[ðÔh@.%o�'|<�ñİO&™”o zÌ—JòôÚ�«½’׎NyóôŒÏo®³Yä¼q2æíñ„kýŠžRLš†û³9WûWz�gÜö9^Ö|0™ñÅ­užöyãdÌˇ'¬åO ûì/–üòtLmŒ…B¶žÂVQ0Ê2.Üô¸â2;¾ûð€�‹ØŸ·š޹?[ðùÍ5„¼=ž`€'†}Zl} ),ÌÏ›§gô2Åsëkl9ß~xÀÝɔ߽´ÅvYð“ƒcÆuÃvY²S2èZ¿Çɲ¦Tе"ç©aŸíòÞÙ”¯ïnòôÚ�—Žùx6g�e<³6äþ|a�ëYÆV™£ .—\ªlæÆ»gS>µ>àF¿Ï“)¿<=c-Ï,ÍdÆGÓ9'MË—·7¨µ¶°4B°VdœÖ ýL1Ê3”¼°Ä0Ïøòö&Z^?=ãpQóÛÛ› 2Å;gvL®¹bÛ-†Óºa»,ø`2e-ÏXÏ 6Ëœ—Ox´Xò{—¶¹9èÛÌ™¦e³Èyn}Ä»gSj­)¤dÑj2)„VÎ;ã3îÏ<³>äæ Ç›'g× …”üþ¥m¤’üçwï†bÃ[ëÛ<ûÄgoéhAžÿú´êˆ…þ³'4Ƶã•ÛN›&¶® rQ—wž!JeÔMÃñÙGmË—Ê›yÎWw¶B6Ø,¤YÛ†–Ž–¶Fƒ%„‹¤Ö üµ�-þr2¡v|÷áÑ1“Ù‚­5küm0.ÏB¼µŽ–Ç`ŸÝž‡{™2`;ûH}§`»°FU7H–Ä –6(ˆç•H¤J³“AVd&üâE,ïHe ÏmOD‡ÿÖAÐmŒþ÷Á9�6øÌÂàÈö{ÓÍ¢ë*¥îYIê'Yo„ _¥ëðuâu^>2´mk }¬Ý’+i {‡€i¦Aš¡[†\ e(3ÇSþ§ï¼Ï¬Ö\É2þ�¡­_²U,t\c¹ƒIk[¤†}ˆN„5«çs•R\íW�ó¥ø¡=W\»pƺ¹Ë4¨”rõY–áÜ[ƒ‡Ë:ôí´n8kl][¨æ´n(•äÙõeÁóñG,\þÉõ,wn—h­pð9™BV9ª—#«Â92D™�7bK�Α¥máYV–Ì2Dæ¹3\ç!×Mc)† ÑÍÂĨWoœóZ§Ý÷`¯ð²U %Ñ(m¶OÎÈËÐ:N'Ãpse�¨ ‹÷_8‡H.-O&¬S@6èL!�ý 5(P¥´xgt—J8\}éêˆà pΟÁà ÛFh-ÒØ¬á37vŸ8̶ؚ!\&B€$JêDˆÒ;"œc@øötT€ÜGgC&@Üp¤—E"•ª„Þ8}ÀkÆïˆ0E ƒð 'ÐA2ó™Äþ:ŽÎ8MkªGØ(ü� a£ï�­ëðDÑ: „Àe Hç ðz ±…w´�÷ê "ÝH›-ì�I!Ïü\¹u휻Õ-mÛÄ¥ŸI›ý‘Ž�wTäÍ:; Jj2e‘Q9E¦(òŒ\edN“nnLë2ŒA Gæ´ü! aOkÏÛ¥5!Œ€›ÝI8."üœG:õh÷l�‡qÎ,åc®‹2p�}K}3ò5/C\dkó,"ý½sîŠÝËï¶Ç½¬hãùh|æø›@�Û£Cã"…s4-Ú4¥sxʰƒèÆUû=nÖÔÕ €tì®3ç†4¬édkÒÓ‡õMÔÕ’ÛÄßVÞ»ö7*‚•E!:KÂÚJÛˆòW°EÄ/&†}‡¬ãl4!08�;_þ¾ñI;OÕ-›ÛqD%¼-drD18z¸#¬�¬Ü!«&’e�Êi¤AÅ)2I DÖ.Û iEhÓg*¤²˜úæßþ[éÃyU4öFܱ[Aç~¿èÓ[Ê5e.<3HösÜiÉõ‘OlZiÊRù(üúJnZº¾ ô†Ý¾¬ŽB3ñIc” („>D2ó‰;n¥­Õï/ºïEó±Jì.øÝÞÎMol3]#�ÓL2D­¡6öh¬S@/ŒÍXhê¥a¹´™i�Ÿ-•®DÉJ ×>W»èŸI r݈¤n”vj”O•°Øv'"ªsߨ¸tÛI‹‹pÿûË#»}H7š1à ußÍ`ˆp$$¸¬Þ C[áHÖFˆT[•ãÂ}J•Üv餇¹5ã³¼C 8´�)ˆ=¯ô¤ûø<ñ Ë*´ïÆ �”Ñ¥Œåb‡…9wÎ9f”0Ÿ ™*^aö^ÜøéØEïñ¼àØñðþ7cÙÉá÷Vàû�º¹LNq cÿëwlL«t§¸6ÓÄô>BÄÂÀ¾Æ@Lï>#~\E—q§]±Ž'Ïå#T’ñöŒ=:õ¹uš:Éü ú9ŠÇÃ{ØÓ}—âD·Ë?ðN2B6’!8ÚÆP'�Ñ0$"SÖž–™8¡^!ûÚ?«-,¬=ÓÆ)cçœñ;[g”jB:“mšÖö¯n uã2µjM¡E&ùÞëZä�锿¹½Íf‘“¹ñš4 e‚ŸúÓƒc®;C=ÀþbÁ ³FR°F~ox_¶:`€cxõxÌ®3ļv|J&-¼ à2LÈLd7úÏù£é<â…¼rtÊÁbàˆK>˜L¹å éöôÐFY0qÆ‘'‡Öòœ·Nϸ?›s{Ч”’»“/ó”ƒÒŽê†KeAåª[ý;eÁYÓðñlÁ�рݪäÑ|Áwì³]l¶ïK‡ÇT™b«°ŒBIú™bÃAžÜô¸3²t>ÚßñpŸ¹ÖÜô�Bpo¶ Ñ†ÛÃ>­1lƒ\±Uä¼y2f˜ç|aÓBëüéý=>˜LùÂæ:ý,ãç'§Ü›ÎÙ,lQæ™Ö,[c¡,tK©$;eÁƒ>¯:Ä7v¶¸9èñÒá1ï9lú›ƒ�æK̬;è#…å©;UɼÕÜŸÍùÒöO�†¼5>ãŃcvÊ"`e¿u:a\·<·>¢ÅðÁÙ”2SÜìÛˆûí²`­ÈéeŠ=:d½Èùòö&³¶áÕãS-–|}w )àÍñ„Æv\í%ãºæv¿ÏÛg6Šœ+UÅnUòÝGÜ›ÍùýKÛÜìWü`ÿˆ³Ú:®nûÜ�̘µ-[¥-ä,… 6†'}^?óñlÎom­óÌhÄOŽÙ›/å_ÜÚཱི)“¦¥5ðôhÈ´mx¸XÒÏ¥Rܛ͹R•\îU|4�ñËÓ3¶Ë‚¯ïnq6çãéœÃEÍWw6YÃÙ…Ù,sNë†ZÛ ‡Q–ñÊÑ ëEƃ>•ñÖxÂɲæ‹[ë\®JîNlÁåk½ŠÝ²äpQ3ךõ=®üÎËÉå±·À ŸVÎw´Ïc5„lŒùBÚ,£T42;´ÇêGiL¦maæžDösÔ GÊä…Óº‚!g¸ÆÈeØwëL°˜A-кòâ‰:†Ç:=È,”“È�óÂ/vŽŒÚ.ê>‹:½KOµ°­A7ݸ ¨Æ™¬h!œŒ3¦a�áŽ`û>¸Œ�ô³}·4UwxŠìLìjCé³ ‹z&tŒrŽÛ>ØB²· uø—�w¯[Фm_‹2Ö¥ôë„ÄÁà7ž;`+—µ›9§€Îacp¾Êž#•{®Ø¿06Þ8ïki–u¨¥éj$(£‘¢AŠÖ",å.Íg(iJX_˜·í+%�¸z=J:ø!û|�'ãtaËGjchœSÀcxÏqл#LôWO#„žß¶Ñ˜nÎ}·ªS¦/?÷)’½&¾Ÿƒáñÿûë|ÿVû”¼›Õ/W„¦4Ì8ÊWéóÇ»GÝ»CùÜ>çÞC¯£1`UúJl�"Üß¿wž_tõéóOšÐuqqðtúLñYÎ÷ Vç#‘“ÏiæF°Ðm2ÙÌI?üª‰ã�JAn ì)á=•ÛLêîa¼÷î;“¬³”vx»´í_ê0‘AfJå¨ ãåHÿwÚwèwÁ‘ÊdÚ„ æ`3ttºõ�Ç8yÎÚðöõÍ¿ÿ¹o%Ooiqðîøw'ù‚�ü ¿‰Ç|nû˜¦Dò×êÝÃÔ ãº1âg’…”öÇÓ¿êkåŠ Œšç²û$Ý';G5’k~ÓñþuŸW?®þî–¾Xù½CKR1l•zºÏ-.,Õ µ±E‡—†f¡i–-u­i<”PãœI�oˆKk¬ïƒq~ų¶ ‰¾gå³q Ñ‘œ¡ýÕ#ÈPaãyeRlÕtã…à‹ó}Ä+Cш¿ó‘䉣 ½§N ™p‘3ÀiÄ´ßï¸þiâ8oòN€òìÂM·ï�nÝ¡Ã{«[güNñl½2Qd‚îóEù �8@Òg®í,ÍÎgs®ýÎ LuåžþJÿwò]z`ÎÓ“à41QéÑ�®¦Fnæ(2>Ø)ývû42Õ”9�Ã�Öu $Ì·ÃŒãXØH Œø¶¸‘ 3 ©›[¼²æˆµ?.¾`hˆNñ÷tŠIЇܦ¸Í&i/­+LßGY$xÉq¬4¼±_'Síœ�Ž4§uŽË¦ÑÔMÛ)žè Ñé&0©c Œ³U„ý°†‘ª­qßG]Z¨ ëˆ11‡™è˜±MÒt!…½¨[çh4ËF³¬[–µfQ·áïg¯mò�×>äðlNí”—ßZåEÛ2uÆ}°ë(u ¬¹3ÌÚèDî¸ixéð8êýšd*¬½«½Ša–±ÔšÓºa”g 󌳦áG{‡<1쇕ø³£.÷ÊPó R’KUA梧7Ë‚[ƒ>K­yãdÌ(σ±÷û�¨µa×9fm‹@„BÈëyÆ­aŸ\J>žZ¬ø'}*¥xaÿˆ»>º_ Þ<�ðþdj±ýÃþ±ÏÒb(¤äÖ ÏNYðþÙ”�ç >5°Uüüø”W�N¹Ü«dŠYÓrw2ãR¯²Ð:BÐË·û=&mËÇÓ9ÏmŒ¸=ìóñtÆ÷ö¹\–\ëWŒë†Ÿ�Rº¢ÍÁþbÁ(ϹÜ+× W{=®T™’¼txÂNYòÙ�ó¶å{�x8[ð…Íur)yýdÌBkžö‘BP¸¢Ö7=[Ä8ËxzmÈå^É¿¼¿Ç»gS~gw‹KUÉOö�x4_°S¬åÓ¦eÏ}Τ¤ptãΰÏÛã Mg|ãÒ6O üdÿˆwϦl—Ϭ ùðlÆÞbI/˸ޯ0ØlŽ›ýK­¹?_ðìhÈÃ>�æK^<ãTëhEc»•«#´_”éº�áfžÞ:>˜Â«D¿—‰ ’àâsjÿ^võ2c”�ÁÊ \]„[Š}´ãRÛMÂ{�Bîļ}ÝfÃ&† ï€éókÔ¾[ô [OÆ_çÊÒP$Ž�*W Êœ~•Ó«r>ØóO¾ÿ6u«Ù�Š?YÛ¤‚ÊÃò¹näR²UæÁPt²€ŽS@A킘”\éUœ%Å„oû`Ò´'üm™6-J.õ* YænõÕ�Mu¸w?ËÐêŒë†û®fÁ0ËhµFŠ|ïÈ3Áÿõ�>ÏÎfn÷žLŒúEæ ƒr(¬CÀB討!ÄîSkØVÎ) óÜ9rÈ¿«-3ûew�&ÿõñ†1DR’ÐË“é¬teþx¦�(7ш)üùЉaÜ:laÖ¤=Ÿ‚÷b°ÁB`‹Ýæ {™=ú9ªŸÙÌ)b?C!]ᬳÂAý�î¾—X§€�5-o>Úˬœh-ëÖ1@.-ÌSaá„p5 Œ+`Œ˜Pt×Ò�ߌ-¦Ñ˜ZÓÖ-Ͳ¡­}­0F:ä76‰@íêõâíHa¾ ŒÄßëBþÞ>HH!�Œ{voÕÂe8ƒ›vF½Œïé› ðš1 ÙGêvLNW‰g÷ö¤—C<¤›?aìß­›âú—2³N™Ù§ÓÆBϹ,¥2[üZeH¥:üÓ1OØß4Ip8<ü¡—Ó"…ƒÊ<ä�;UY:¨\áu_€Ý"l7,Üš’"@ y=ËGZkì2iLZ÷Æí+-IôýT? ¢E¢wv?-A»»p/Û&¼¬!Î}ï�µi£«‚‹�}yÜYêú�;ueóØGˆúvä[©î�â‚þû,ÿ´­®O Ém#áî+z»q©„±¿ÝŽ›Î”=Þðïïݵ!œ¿¯pzº}Â$;Âó�Õ±Õ[9ËÒ *¿6B[¾(½H鑳¿xù$Y«�?x;Þ~¤«èp ¶çÄ™èŒ/>ÃÒ®«èK.²O†# Ûù¹Å�YÇÖeªŽ4qxø¬‰` qšš’  þÁß{þ[A Šœru.ÏφxÌ÷+ß%lý‚óÜæ÷2ïê¹^~NZéÜ×MZ:9Bø òBD�E†�ÛèlÓY„¿ÙKtþ†¸sÏ+.<ÿ¢3ÿÕîé?¯´;ò˜ßWÚJO‰œ½³1ºwÝËV×Šß M÷0¾èðÒÐ,5Mí ·±®@ãa.‚3`B¨“à�v~“ÅxkÔ‹JK(nòæ�áüh4<é´ò�ß”i~Zt-¼“ž“8Âõ)qò†Ž‚Têùó×ú¨ænï�“KWt•ʶÈ3‰¨À§Qþ©ƒÂ§Ç'YÆaå'0B©àîÂ(”ÖìêêN3ÎEÚ{åÜ$Q÷NY°��(ï~Á&„�Õß¼p}ÚÜ=ºÊèãiü¶Ûǰötw¬8#»ï—HF,ö�ôÞa6âõL;M…ôãë õ1‚&qðy‡@GP�ï=“•!ýÛG¥ýs£+Œ»§ßk+Â=Ñáà‹[™8qÂxêÇ íi\drqÜÒ¹íA£6a�7 �5Pˆî¾O²šäüÆÁþ¤Ð­OYôÌÛõÁG?zE.Ôi î½n†‘ øÌÆxA„‹�ažÖhŒ©Ñº¦n½# µ‡s,–îk–µÍ"xòÒ:ÿïËïÑxm6å«£;yN&e0ô?š/Ž?À'cr%©”ý½5Véî¹Ï¥3�ƒ5LdR„âÂo�'Lš6À /k>œÎL�Öx:Ȳ°þŸpÑýû‹%ûË%—«Ò^,ùÁ£žvEx5ðátÎVY„:7ú}¶Ë‚Úöç ®õ{l•ÇuÍö¹ê`ymøáÞ¥”l;§A­ yÎZ‘‡Â¶O{6fÌ(˸5è£üéý=¦MÃÍA!oœž±h57Ö™²î21.W%ÏæTRòÙ�5ÖòŒï<ÜçÞlÎókJòóãS>˜ÌxrÐGIAcà`¹äj¿Dˆö¿Ö«x:åîdÆ—·6¸Ö¯xíx̫ǧ¬åWûMf|8�1Ì3e/ÓVs¥W"…àîdÆó›ë<9ìso:çG{‡ìV%Ï® Ù›/ùÅñ)“¶å™µ!­±P<…RÜô9kl‘h?_¯Ÿ²Qä|nc)ß{tÀ½éœoìl’KÉÏ-<Î�~�B*ŽêšYÓrkØçþtÎFY°]ÜôøÞ£C>šÍøƒË;ì–ß{tÀѲf»Ì¹Ò«x´°5!6‹‚žÃÒŸµ-·†=>˜ÌxàÆóSkC^>:µˆ¢àKÛ¼;™²7_²h[žßXcÚhîÍæô3Å0Ïx8[p©*Ù,r&Mˇ'ìöJ~ow‹»Ó9Lf.–|ãÒ6óVóñtÀÕ^É\–­f© ;½’_�¹R•\ê•ô¤âgG'ì/–üµk—Ø(r^?3k[¶«28”46ò}¾ kór¯âåÃcö–5ŸÝXãÉဟ�pZ7\*K¾°µÎÛã)K—]õÙ�ÿ÷áÿìà Ðùçžú<£þçx–WDSþ¸Šå<þ_ ù 7 Ž`O�ç ‰BÕá[±­H£ãï)ñ£Á€�=¤Ñš¹ÑÜÉ-½Ø[,YhM%%½L1mZg€ýÜæ�QÔÒ‚^Ç{R7¨Fó7Ö7Øo[5ö·é|Σ£#[@½,�r¥;üÛ‹Êé+åéAZ~Ý»çRapŽa£XL'� I, œÀB&m _ç§;™ç¦7¦Îû/R˜I‘ÈPޝ$ï^¾Žòª—5yÚ?›ö…6�¼”ë©•WïH·Ÿ}TlÔßÜgã#ís™`Tvc�À_(i£…s_O ³™…s äBÛw©É¤¦_(UF¯ÌyûÑ)ÿûE£ kRò¬mR9£¢G Ø¿S§ ó;UIÝj¼Ô¼^äŒ2Õ©30]É[º-R%Û`?œËTp{Mˆ4K ÛNúGX�.v»²­=£&axç§0�á'�P_ 2K!C&v->KÚLœOHž¯¸´UO“RFId–1UOH—þ–Î�Ùû(ÇA§HyÓjš&FhúÇÔ)`ŒE}f@£µƒ>ÓáC¬=bgÂCþ8aÀµeÇP…gˆXɆ̥ô …AaŒÄ×:¿ˆ£oѶ-m» njMcµ3þ;‡ÀÜ9æîXÖ-Ë¥fÑ6‡=N¦K~uï¼9›ñtV°[ÆâÂSW Ø¿v«’J)´1,�uôÜçWŽOCA_€wÆ %ƒÓ W’5g$ègŠ+½c ïN¦Œ²Œ5ç4øáÞ!¥”^èÑ|�€àT¨”âz¯¢PŠÃÅÒ9$z”JòÊÑ)GË%—{%J>šÌxídl‹òº—†G”IÁ“£;"èÞtÎS£ëEίNÏøéÁ1O ûR2i[^;:a·ª:‡G¥[U‰Á0®>µ6äZ¿âÁlÎ�öŽØ-­Á{Ö¶üxï aœöKÖ²Œ�ª¤Ñš�ªbÇAýâø”�"ã¹õøóûŒ›†gÖ†()øÙá ‡‹%wÖ†H!‚Ùâæ ÏÞ|Ɇƒ ¹Ü«øÎ£>šÌøÆî[eÁ Ç|<�³SY(¤G‹%‡‹%×û…TTιòÔpÀ½ùœ�&s¾¶³ÅS£¯�òÚñ);eÁS£ïN¦|<�Ñh Wd€{Ó9ëeÎ0Ïy0_p}ÐãZ¯â¤¶Y!×}~gg“ýù’×OÆœÔ _ÜZ§5†·NÏxrØgÚj¤´¡7Š‚7NÏØ- nú¬å9ßw�Aõò™”¼rt´mƒèÃÉŒy«¹Þ«˜´šRYÚskÐã…ÃcÌæ|mw‹gÖF|ï�Ãå’í²àÓë#ÞOX´Âf§,0XèªKýŠƒù’£å’ý·‡}Þ<=ãÝñ„­²à÷.móæÉGËšYÛòÛ[¶f�‡ôØr0W…ãÜ9 vª’§FfMËû“)'uÃ^Ý¥1†³¸Ò+É¥äha³vª’·ÆF™Íb¸ZU¼6›ò�ïÝ ký©›Ï²³qéBÅ9F˜§rqJ—=ß�QÌá4Ûˆ¥w"Q†RyÂÓñ¸< Ứdvù•…90ÆpxzÊ^Û0ÌÏõû2h͵N1ÛOê¦Åí ªƒLQ(ÅÒlj­ù£� ž(K^�Ï<ãÑÙGã1ƒ²$S \„7^¥cdM4‚­>ƒ�t÷¼ÕÒÇ�<”œN²|æ›W“ÃóAo€ÁËžú±OøbˆÆ¾íèXˆó’¹Ð•cýßé»çµÞáÞ¸Z ]¹A^ÞÝü ¯Ó)[°3®Gíå® §øv¥tÂ6+)Ë„«' D�¤ÊeâÐBHj2ÑÒ/3†½œ½»Ç?é=´�+YÆŸŒ6)}¤qò¼³Nük5ú¿Ñ¦³æ­N�žRÔáÙm�œÓäÚQž!B¨Ö:dxÕʯᛃµÖÔÚ¶v£_q¥W'‚‚R©Î~x4_ðn[óÏí5—züÓÿö+Eîtj…Tä……šQØ"½JY\ü [{aÔ5æC!3…È|¦@æ²”5^K/ù'êFu"¢ãK{}‘Ø% €4S¥t%À͸kMØ vEc±6ÐZ§€qŒÌ~ï)�–„b«>B¸¡!ˆBZÇ€Ãð'“hiŸðv¯c8C½Q`d ’ ‘ëaÓ¶à2 �£;Äþù:Š®–CÌpÎW¼Ö:lÛ�nµÑ¨5,[t­Ñþ½6˜hh�4Âú&œ�laù¾Ñ1öŠ@|Â(:»�tF4åx°/Ö“i1ºÅ´. Ý× Ñ¾ð²×?…sVH„vkDÛgòË„DuÚ„å!üºrt8.“5ô÷î –~~(¸P¨5EÐMK½¬­“EÒeDœx\TÛ¶4Mcí­³m´Î1ÒhÐ1Æ:DY é3­íC¦ •Ï&@´v뺲y.) IY)ÊRR–Š¢°‚ÂAÙD ãüS®^‚²™ÊÚé@uÓR·m°¥-Ú)é°opóîUÓðw0?þ•!t^i{ %ñ|dÕ˜·jX74›žbò–öæâ>âÙnÔS;ï�{„Õ>v¯ wñü‹œ¶™8bwâoéã™ÈXÓ–ð|9}ïØj:Fþó²Nt $t´sMlï¼}Â÷3‘iÜ Äqö²b¤é>›0¥Ûöz�pÁ<……“÷ƒmÙýíäO+¼íÂJ*b±ë(G‡ytY¦Q~2›dÈp6‚Ž –ʉ^~ô‡‰Á¦)ú*ºI´wFxãtÊSÙÐÈh�á̹¦Œ0ɦuƒä"¶»ˆ’%¶²V×ÚÊÖü5ïɉÔÛ¹ËÅ›ò|>yóþ�¬´#…ì·m¸xM÷ìÝ×ê³?î³ûÎø¹|Ñ�ÏÒ݆¿iw|t†OLÇ!‰òH£…Î! hµìô5ÉæéÂù¤Ñ³.®ØmŸ :m¹.v MÒLWZÁpQ‡�›� Oì‡Q8AEhb±­¸ZÂù«{Æ@Š/úl<óJ)!‘:ð΋îý�1&>Á�“mYcã•#Š#�Έ ¿Äw|jZj N™o,Oܼ¤³µÝXÛùŽJeôWß“~„±O4~nD˜£8|öúT°‘¶„´û0B瘪¿·HÆ$Fúwí¾—Øõ+…_¦3ömER [XtŸ¯sîE‚ÇjO»tÕ_.ˆ©f~!§Î.üœ¡ñÞìàSéö¿+=Ù9éãÛ4nNÜøu˜kò®±÷Ð~Ÿúó tLN+™*á;SÆ;u1ܺ8�ͤcæéG|2¿¥t} Â’{Ó`¤—˜âŒ0θoÛÁ�­L¾]{ÞIÆÍ‹M[Oö~-J¶ÑžK�\…ÝÒNé <¯½×ŸüÞøé[xxrÆ[³?šMxÎáÞ N‚‡Î0ï�égMË£ù‚§�±] ÁíAnè¹�‘;·¡Õ&õOë†WOøýËÛa–ÆuâÒNøøÜÆÃÌ9 Ô XcË‹‡Ç|ykƒAžÑÃ_óéõ·ÜÑ媠IãþÅnÞO¸Ùïñi÷Œ~�+ýŠç×m_ïÏæœ,kžY³°JO ,”P.%㦡R’ëÆÀfOcxnc €—޹?_ðÇ×/“ ›ýP9%m` _ÛÝb#Ϲ?›s¼¬ùòöxóôŒ_�žñW.ms¹*Ù[,¹;�1Ê36‹‚RJnô+vË‚…ƒ`úÚÎBæ ÞOxvmÈW¶79\,yùð˜Qžñ—w¨µfÙj†ÎÁ3ךO¯ 9ZÖŒòŒW-\Ó¿qí³Vóg÷ÑÏ3þðò?Þ?¢5†§GF2c­È(æ’LHÌ\핬gÛeÁ÷©¤ä¯_»„þüÁÓ¦ås›kÜôyéà4®Oë……~ºÒ+yïlÊ鲿w/m“I[à÷hYóÙõŸ]ñ³£ÌæœÖ5te—ic ÌR0oZN–5O�†h “¶åOï=âÎhÀ·Öy0_ðòá1øãë—m´¹3òåB0om¡ìim Ï/žp³_q«ßCÿòá>Rþàò6Kmøþ#�¿[–\ëU¼~l!{„��§3®TËV³]•|çá>ÆÀ×w·Ð~zp„6†gÖ†üÖåu~´g�uÓ¦e·,©‘¨”â�“1ó¶åv¿G&︬›KUÉ×v·øñþ!“¦E Á_»Äë³ÿðîÇ�^Ù½Á¥ík�BžåÝ+•CV#4ÃßNv”ÂS(œˆ„'òG¯8âô/B /y¾'Ï,xåõäµk|ôèóå’_Ìç|®ˆ´æp±äpaŸíÆ çœAÖ ûüÆïŒ'Á‰�˜fëü}ïlBø»»Wø‹Ùß>=`2Ÿó‹÷ßggm�kÛ[ΑcÂóØà[‰i,ÝÇØç Æ¾d|µÁ"…—“¼³ÚÂØ'÷¡�¡Ô;ãMWöÆYýܸ^ùñ5&̵×4„£ù†Hû!•©V„fƒëk°HaÐ^ùw²H”l-¼�rP>’®Õ‘ÿZyXD•ÄK«!Bß`ƒ¼°ï»6bOFG»¾°©ƒâ¾]Y‡/­=¤±}¶pë¥ ÿìåxã¾�ë]•ñï�6ñ.ðBI2!:Ù«™ì~ˆuJ%Ù( ºßv*ë¤ô¯’âÙ3<Ü�ÏDøÚîV ó¦Mdz[‡Ç÷c 㦱…Ó�¯loòúɘ§ÖüÇï½®ùGûy†Un[1 �`hiåx©C‘à “eì*’Á%¿¤ Íâåé 7¹=âõçp;ÂI‡¼“Èó^F‹Ôÿ$Ë( º> '¸Jíõ˜@Ý>óË+êO$ÛÊ*ÚG„e ­p%ŸD§¸/¹3ø'ÆÛçDªqÇùÀ¡àÏðûÈ~cß­®ÔZ£•' ©ñOðçqu ’-§ÌÑW/HÆö°Y±?hO×m Úx³•°4ÏãÞwdö ¤â‹úG&Ä~{f =_ñs˜f§ŒÊ ÅZ'á¾�@+¼M+f€‡iÖnŒÜü{¥"Ò<χ >r_ãö‚=_(û‡¥ãÚuÛíIã‹Ó·.hÎ>»Ñ:þiíó¡itKK‹R„–X%DŒÔ>jÑÕˆ0.³Ý�cf‹hã3ÌZƒh M&ÝshƒÖм……u-©ëŒùL1›5,]ÝÇÅB“- u#h´¢Ö’ÌH0šZJ–¶�±ßIF˜°mÒíh¹›¤…¸(»¢ˆ¹ø‡°Ô“»:yÂ~+¸PhH[Nœ®üuÏ•Î|â+ÈQ¢û펈{uå±:ýŠ?Ø}na-ÈT�Óºw³$Õ�…1Ñ©�:|žÿšgîÚnüÉ&æ¢ììÇpñ8¸¾‰„v¥(>W+ I*ƒÇ!YEá[¿(“а>Ü.NžÛ�çíÞÒñð•z Z´žQÅ±Ò¦'®V®óAÚxúÉb÷¹’áAL;.�Ctž6ŽËÊn{ÌK¬ÐP''™dó¸—úæñ™oE‹f/’á]½A÷£yìO«O°'®OÔã«ûA¬2ÄÔCv®�+ç]Ø?ýÉøõ½ºàsú�HŽóçÿf·¾àÙÎÝã¢÷Çœÿر0+¿Ÿ?Ïöä|sh¢5P·15±6áh¤P]Û£i\áaí¢r�ˆEt�wø(#â’õÞ7{mŒ�ž Ñø&ÁÝêDÞ§¸„êÜqÇß;Ä©³]œÀæNˆ¾Ä+‡HîéÚXÙ þ¼pãÓñp|*¦Q§÷JSº¶„$€Êm…YI7O‰þ¹œÑÝ D¡G!Ú°.:‘üç2üC:o¦Ë"èx‚]j”ôø–^xös¦£Ç3í_t øóWßý¹]š$3á~öþ^ØK�túÔ}%óÒ}Ú _>Z=|6ñûðî£þ�®¸¯HÚ�žå0!þÏ%:Û=î§t$t/F‰Êdܺc‹´'QŠAØrΑîHתíFâ¯Oå Ç@=|�=(¡$�¼“Mâ Û¡Jú'èÒÞxí±/µ‡Ò¢¡Õ(DÜk¡°Jª/ÆŠ û}“4·} ™9¡ °ÏlH"2J¡ B‘cbV@ÈÐDØ"�Ö_±t²8Î-­nm–ŽN Ž4¶ˆ»k¯m�¶Gë­ÚAI‘qsgƒï½þ¿˜NùúhÄÁlÁF‘£G%%…TÖØ‚5~x¬þ㺦t™¯�YjŠ�ë†qÓÇ@!-^r.½±ÉCJ)ùh:c© ›EŽ‚w'SÞO¸åœC­5»½Ò®ja£ýײŒqÓrZ×\vØýg ¾ÿè€'FW”Ñ´½ì²üõ×ú¹,´¶àƒgmË+G'l—WªŠyÛòíû¡fÁÝÉ „PH[•Ͷ(•â�ñ„�¢àéÑ€LHþŃGœÔ Ÿ PBðÊÑ æsî¸ÂÇ­Ó2n zŒë†ažqµWq¥Wò‹“1GuÃók¬å9/ìñÖé·}™âábÁG“™5²…‹È»3°7_°¿Xò•í nûüüø”Ž¹Ú«xbØç£éœ·Æ“�i`0<˜/XË3¶Ë’£ºv…tK ðâá —ª’/n­s°\òòá ãºás›kh¯Ÿ2n[î û¡†�®÷*Þ™LÙ* žöYÏs¾ópŸ³py›ažñ£½CNê†[ûûû»n÷{Ì´f˜eäRrg8äµãSîÍæüÎÎ&O�|s®*ž yãdÌYÓØz ý‹Öð`6gÛ9�öç ®õ*î û¼9žðÆÉ7=¾º³É¯N'Ü›Í9­[~Ûaûߟ-õ½ru IDATB°]–,�¡uë¸T¶@ð•¾mKIÉ«G§,üÑÕ]4†÷Ï,ÌÏ�~E_e<œÏ©µa”g<˜Î…Ã.é𘓦á—¶Ø, ^?sÖ´âi}Ä/OÏ0X¬s)¬mã¬n¸1èq‚á?}ÿ}fÎ@¹>Úâ雟¼h•»™„ѨIy‰ûìùJʘñ¼.òþ¥ü1ò› ô$ŠU8×x'ψ,Äò�ªÈypxÈXkîä׫’ç×GÜŸEÈ KUÉÑJ¤tŽÔ:p¯÷í^ó¯Í¢`C þ`´ÆÛõ’3çL˜.ì�œ0ì(W;C)A–I2•Ù¨u©\G‰Ê*Ë'Úf…9ù5d|ùl5œÄž—x¡U^×MwçÜ«c»Å˘žÿ»(|ÿ†èð±Y vÎ:òª‰íDù'§Æù‘ÒŽEžçyN¦¬ƒ (ÃÂ*ªAöròžôçNò2‘_{ž‡úú *SäyFž)Š\‘gÒÖ�ÚÖ^Í Ì Ì ¥4ö=ÓTÊÐ+`^·üŸ?»ÏÖ8ÿ;UŸ¿9\‹ñpX‡‘�ÈÉw`aÃ&‰“`�e âï­1L’l Dïo8h:?G;eÁz‘qæÚÂÖH˜%ðCÞÈŸK‰Ä:åcXË3®õ«PG!øôÆ(3Xh ÷O��øÅÔ>ïßøÊ.ÿð?zÖW�qÁé0Jc2ã"ÒeT÷}ä”_S>ºÒ‡%;Ø ‹�žDV{¨�ñò�—�ÚÚí~_Q©+ïF*©�6qÆí=¢Ãgá"Ý}–€ãÎifgRÓI(ƒPn ª�#3‰t�Kdá ý†j®nŸ�8R#µöûHˆx/Oõ¼�ÉÚÕ¦¡e ÷ZÄ{Ha $»"ÆÂ÷!%v ¦5N?·Ù¢ÖÖ Ü D+Â;Z ´Dj‘d<Ç÷Ô’ú�@…_DÚ‘˜4ü\|4Œ-p,œ.�é<,Z„‚Õ±0ˆÖ9:4&» —m Q5 Ì+B½úuᔩ�1í/‰ñ5dз&n{ø`²èøt‰½üÞjtÓ¢›%%¹ÌPH”PÖájˆ´>UôÜÜ£Üzóû-l1 ]i¥42×d=EÞW=EÙËmA!És[@IçXõÙ>jZÛÚjMãtS�£Ó¶Ÿ1õ/ê;)¼LÐ7㠿ȼç"áþ‚îìùµ�^ ¾v_©�!ÜáÅÝŸw‘¡ý×¾i²K�йôxŒãâ¢o»ÆòU~¯Km"÷•ï»ç­<³ÿ²ó{·ïöçh?Iëàöª}Ę1ž99ÄJÿDrn¼¯Ð`rN¦ô[VÄï¢Í- ª4©�,í–Ë8t™ŠRÅ D[<\&¶ŠôP ròlA6Šv¿UÄ’Ôfâå©xØÎÑédlWŒ¯M˜\m ]/£¥ãmÄû×—úæö™o¥™xþ%¡O&gu²Ò×o´k’ÓÒµ†á7r tÖgÊPüBL'gå�Ùˆ&üßqwÓ Žô|ñ˜¿Ï=ðÊ9¿Ž=nTw�äóêx­Þ÷qÙsz±º°ÎßM¤×ù—Äh\!£¥Àv¥éö¢w ƒH /säÿnW<¸õPFNŸu�ˆGí¢N[m #·)<›¥§�s*øš.þ7ë„�´Æ°9ìs:[ðÞC )ôó锿uõ ¹°˜ÇKc‹ëfR0ך_žŒCæÀ“›‰aÝaóûÏýL±^ä´ÆðöxÂvU’;Ãö(•bèêì/–ô³,8Öòœ½ )D(üº[Y§À Ç,µfË9ÞO¸?ŸsÓeTJ’+ÅV‘Ó`ë<=R)Åû“)gMË­A�BJÞ89ãÅ£žr†úZkîNfl—ýL‘IÉ0S\ô8«—5Ï® ¹Ò+ùp2ãÇGÜôX/röæ ^9>eÓ嵆;eÁ™3~ßX8”׎Ç\íW<1è3i[þâá�Ë’Bð‹ã1ã¦áI—5e§,xçlÊ¥²ä™õ›yÁŸÝßãþlÎoooP)Åö9X,yr8@I[Ðw\7Üö1ƵzJñäpÀ¯Nϸ7›óõÝ-®÷{üpÿ�wÆnz\íU¼3žðp¾`�)v+[§à¤®¹Ö¯˜Ô-û‹%ŸYr½ßãí³ /s½ßãù�5>šÎx{èqÖ´ô”b�e 3ÅK‡'Ü ùÜúˆ£ºæ¥ÃcŽ–µÍ’~q|ÊÌ9 *¥8^ÖLÚ–ëUÅÝÙœ­¢`”g\®J~°wÈÞbÉ^Ùáj¯âÇûGœÖ Wz7=~5¶Å†· [_#S’³¦åjUñþÙ”£eÍg6G<=ò“ƒ#îMgÜèW|qkƒŸ�2iZZcøüæ:SçDèe3ühY³‘+†yΣù‚×OÆ\ëU<¿a1ðï¹Ì‘¿ry‡“ºao±¤5†›ƒMk8r8ákYÆ[ã »UÁÕ^E¥2Þ<=cR7üÕ+;,¤àï¼÷^0fzCž}âsHaÀD»oM�þž¯þî¿�Ôù¼ÓÛQ¹„o%dŸáÃ#Ƴ9{ã3ŠÈʆÖ8h<:Š£Á�‹¤£”‡ñ>?ðÂ\¤¸†Ïب×Z·¢¬š Îò®“U§¦2Š,#Ï2”²Ž’`T+2�1hÝZÙ@t‹†úÌä^+K(¥È2ë È�S W EK&Z eœSª ªú…°G)¹w2ãÿxñ>'³†\þx0âKU,v/€Q–çÀåªë˜¶º3âKC 6Ë'uDÝ :µ-z*£Ö±Á´m;NcLp <90kÛÐö�~�R©_d„…J‹{§ÀFa³Z@ŠÿñÁÊ\òÿü×_d{MÙ¥Ò0�Wº@Ln‚Œ# †·/ï‰A$”;2ûnR§@Gæ�²eø,|vŒ3v`u"!\0tªËÝÔ#ý{çeH#w†ac£§½3ÀÃæ8•ÆG‹gäô‘™å ­T¼§4©Ýsøµl�BIåmÓP\ñ`ëxótN$ú†_cî–ö™…LÆÙï[¿�Õ?Dƒ¡±û › ²B`¤ÄHeÁ1áôƒ <»!j4¦‰ŽQkdc­°°0­´N�V@™[GÝ<…ÍyúÿÞÏaP€L˜/¼ÁeE]Â�·ÿÒùé ç"d× ïü1Ø5àµõ¾±”,ò›•w“|&®=?�ö»„_%ÅéíG?»‰ö´Ý@(Bê3—}}�\Yšé‹(û5šh±ÁnTJ®º°3Êb!4Ê­M™dfP•"ëed¥$¯”…Ê"Z˜t‘ÓÊÉ@RXc¤Nj±cÍß™T(!�ðýЬ^„QO�Á!.�¨Ù¿ºØpíæ£W•¬Âz髯8ÍÉ}ý}VÎ_5¸ÇÃÍòçè\w±%‚Lª±wŸ;¹±ÓÍýñš”çèŒë‡7Zóø197Æîz!:­'çFC~§­ä¹;�…¢Û¿p8भsƒ”Ê—^æ\¤î«û³p´Îòš»ºNt�ìÈ/"•W§@ZS 85¼›ŒY$m±v ^A/ñò\äƒ8S˜xYÐË^+6ILÊš;ä«kÃMñ{¨oþ�ç¾å¿ Óbü{w|Ï�¾Yùñüª>7iç¿ñ7÷ݽøŒóמ_bõƒ¸àÇŽò’Æ€¤H‰Âå“_â‚÷ÇmÿÕ÷‹>]üÍãÛýu÷J_~Ü/: b7¦ *~ödJ”œe ´Ó´˜º 4“Mc _ËÆ°lZ›1 q�B2Fù{|ù§@tøi\1ÜûsœŸn¨•kÂ÷]èü¦KþütYÑ#þí9‰Yi‹Îç¸ÁíÂÆÁ¸1 9Ï·ãƒ%Rï`lS$÷ètç³7rGc€mÕá[^pn¸Æ$W:}:D–U†Âùñ0®¡HhÝûEûSTŽÀ½ðÞ‰êH…‰@¼`çÔ?uJ\õʸ]ôŠQ”á›ðÞ%§vßÄôÔÁÃçgµ/ÀEÌÔÿ¦M7~ŠÀxâ»�LgD(n÷}TêRA 2+:cy™g¸1ƒÜ2\ÕÁŽ˜|±nAŠAìÿ¶E¹¬%wªIŒýÆa;þÍ9FœÒ�ˆÍç•LÂp=|C÷‘m>;éH™Œ£U½S@;€6>KÁ c�ÿ�-¼ô†ý–Î1à³lE¨—àûÆ#RöNc³Ú$“Àµ×¶> Â9#ZëHyæê./¼ý!ÓEÍqÓpÖ¶|m4â¬iC;X†­²ˆõ!°Q�RN놅Öô�QôdYóâáIˆö×XÃÝvY„ÕycÐg”e4Æ0o5—ª’ž«ðâ¡Åö÷EºÄÕ^Eá"òJ)èg1Sa·*¹Ùï±Ðš7OÎØ®ÊPLøÏî`³°Ÿ?˜Ì0vÜï¾@ï0ÏØ_,fŠ;£U¦øîÃ}ZóäÐf¼rtʇÓO9%!guõ^…Æ0ÈmÍ€ËeÁ[ãI€&Ú* ^>8æµãSn { ²Œ³ï�M¸\• ²Œ\Hj­¹9èÓhÃYÓ𩵷ú=>žÍøþÞ!OûÜöùp:ç� as½ßÃOç óŒ+½Š¥¶‚oö{ÔÆðÚÉ)·}Wt·å»�8^ÖüÖÖ:™”üåÁ1gMË�¡ÍjðQ®OûÜŸÛ¢¼WªŠKUÉ·îs¸¨ù½KÛ¬å9?xtÀþbɵA��²à£éœ³¦áR¯¤�’žÎxv}È—·7xõØf@ÌZÍïìlrR×ì/–dBP•9çý÷ùÿ8{³XY’óÎï™Y{�sî¾õry{%›‹(Ž$KEŽf<–/°1°øÁ¯^† Œ¡‘DÀ~˜¿À0lÀ€á3c`ãe$J$ŽÙì�½òöíî»�½Ní~ˆ5³ê4)gwÞ:U™û÷}ÿo;õ€b¿;äÅ;Ÿ§PeF�<½Î÷Y³…–[§llR/÷|ƒv:mí&]-ÚBâMbi"çUüûM ×MÛ¦P¤À²3pïÑ#fÖÐ’k¾ÿíÒ�«¢v¤lX}/´‰J�RJŒßoÀ¿³LAàÆÔRøÚpÄõn‡7æó¸§žMyx2¡, .�Gô:…R(¥b,jéAÓx:�³à}f\8lOèmNwñ–½ˆô{à¼#ÍŒ�äà�¾¢•Ä/y°f¸A¾ÇÃgF ¬?ãêò$¸U*µQ¸ÿqýáÛäc÷ EtÖF�ÍcÐû™žcŠ\º‰¡{Sž…FêÜÀrKÊ"•uÊ3ÌLðJ•X)1!‰±LžD®­Ö{Fà<´ÅÔÖů¯ Rƒòà?VEEZ:Ù݉�@."HxÇ„…µšåž3Ö$OcA mœo˜@ƒ¼œïäfW7?ÿŒû.m–‹  1O9i „OÒ^F}ÄQpSÀºYèÊ÷Æqø=)ìÍÖ{;å ž ÈÝ®ˆBûëXKY””eåæž*\©&Ý+8à?­pSÀÆ1÷Á|„ßí1ÌÎë¥#]È«ÂúðS©œ Ö;Jåä5aq¹µK¢,,~ïUTEA!Ö:㣰Wç½™@ßö!¢>)„ GBÖGŸpÄ}%‚ñ?ÿ™mñú·)~‘zØPiwgF7³)˜— ©O‚Ç_–EjG Ï{0ûžó¡ž[ÀúíõñIÙ•ÚѳfY)òCTx6ö÷¼¦ÛËhÖ)ßÛ7ûìÜClÔ2£Mî—þæÛ(ýœ×ɯ¡`t!‰ŠBº<9›^2ò¸mbc²¼…&­ýÄï…}nÓÃ$¿ž“õQÆ‚ÅÏöï‰O¯ic…áC}ý÷>ýõfï‹F,¦v_ÿÂGXHá´­ÇÛ�'ŒùÔoN-›Í’†Ø‘ û1¼œÐi±‡â¨Yùš ¢1ÙZ�?/6ãÅ[žkÜ·ýÚùÊ‘ÍôÉ×·üdc%ù#›±[«˜Ú•­)ÿ�&¬m<ºe`mÝéÝ­ %ëÚ²®a­ ËÚÄ$ŸÆHŒQ`· ü²MÅ€É^—N?Ù8óÈ>ãÚö�Öâ –ý[7ýLØÊʈ�UÊYx–èÚ„­|Á¦áHÃ’�ö->&¹ýg–ô~cÜ NÙÔ "*;þâßþö¦!„þßœÿ¡œÆoá«ÈÝÎ2á Nž$lƾŽT1ý�[ùÇ}"$ÿžÆ="hsIñ/ýüûAòNh22©}ÿ˜Àíkt[Ÿ´º;-Zë/ײ ±�06‰…hh«ó9”Æ2ò½±„&a k%Yº»ò¿›J�æÙˆ7ë�àößHÞ#’u`öULÜC+¬hB¬“ÂTŤӯxâšÀõèIä•ÁZ'€þÍõ¼šk>ì˜x8޽¶BÂÖ)I ë:„j¸÷!²òMƒ¢B $1Î{oÍïcM¯µS$¥©ß^}ŸèLij‚€ÖýÙyèØ_ù–íê&…àéË{üÍ[w±À›ó9Ÿêõx®ß‹J�s:¥À��Ù)KJÔOÖ5"PßUŠ[ýBÀJJ)¹ä•ï�MÑ–˜Øøƒ©³("ä)‚~Q0òï¡q*)Ù_,cx•žR¼3™z sÔ/kÍ;gS®v�AÁÅNÅ^U!°ÌkÍÀ>X®xõø”›ý.ã²d²®ù棺J¹pF8«Ìn¡Ø)KŒµ\ívxÒÉïø„³OûÔÖò§{KöÁkǧœ¬ê˜#AIAO)®õz®V\èV<;ÒU’ïî1ךOïŽè)ÅwŽxÿlÆóã!…”,´a¹re#ƒ²àÉA�Ÿ�Í8ô9 nô»üàð˜�òÄ Ïån‡wϦ|8[0. ö¼2äpµöa•$‡ËuÌÅð`¾àÇG§<;òÂxè’7Ÿ²2..¾¶–w'3ÖÖpgè¬Z»Êy ”â�Ó3žôxnìò6üõ£–+~ýò ðÊ‘ ?ôÌØ�çÇóKcxjÐãpµf·rsêf¿Ç÷Ž8^×|íÚ%.T%õè€ûóOö»<9èóŽ�¹?*KE�NIóİϽéœÓuÍ�Ñ€çÆ#¾wpÌ;“)Ï�†|voÌ›'ö—+ÖÆðÒuÍãÅ’B .u:,¬¥p±Ûa^×üøè„;Ã/îŽøh¶àý³g뚯^»Ä¬®ùp¶ ¶6æÝpŠ22è�ɔ냗;…”üèè„ÓÕšß¾q%ïxÄÍ~—'ú=Þ�¸�A£Ò€…”,ŒæZ¿Ëkǧœ®×Ü ÷;üã»w9öVĽNŸ>õy UE:ãèšM€Ùßñ÷&=�¼3á3(ÏÑT dŒyæ@ Q“ó¢á}¡ÁµSDŠ× 3B8º×©X¬VœLg|¤×üR§‡‚�|ß+áB±LkÍÚX:Jr½×i$b}jØOáWpJƒœ–¯�‰Vß…�ô üöxŒ‚V.Ák­ �O&ÜÛ?¤( .Œ‡(åEƒmX@G/1�hAЇ�…÷�–È?ÿ˶iȪØ+‘ñZ‘?¤%@†!’aL2Þ çUÏ�£9Ö"¬£R8¥€n Š€²pá~ ¥(•·¾ÂÕ×ÑÆh¯(c‹0àÖ$¥?Ö"D°f ï€BX”Ð(j ¡é–Ð-½J0¨$£^ÁÙrÍ?ûÓ7øÑÝ#ž-;üÃÑ.}áDA)àSDÄcT6=zÞ ÜS[ÛP @R*\ëuá„®v;ôŠ¢‘§À’®d£S>cœR ô<øp-�a.É‚cÇ}8#)…° >L�õJ©¼|Àr¯4 3Vãr h‹Ð  Èv2_-°ká<ýk0µ÷¬Ex/T“Blf ~Ã37ðó~_O!žlJ²Oß«žÿ&ßw¢RŠ”üØ�¡È<’°ïæT¢TŸ|4NҞשþ¸=Ým�aÜ‚Èõcó"@ê•Fþ¥¾œ²()‹*yáX|{h�¡Â`¼‡JiÜõîB\nŽŠD%¡ÄÏUƒ�)�b@ƒR"î×ÊïAƤÄÜRç­å÷s%„�íéOÄR6ØˆÐæ† œ>Ò�µ'�f6Aí GoÕsFûüûDªHFCÛ÷æûX³.[ßéÛ•H¾ÜÜeÛ™x ø ï`lÍ:5ëFã™ØV’’€sÊuÏAôô\³ÝÖnë…ð[Àuw´ GDª`V¶Íª¶ñ†l…¾“Y÷¥1Kó†�þKsÉ{ ¨‚€{$/°f»ÛQDrÜÒmÛÍ\b(¥†±GêŸP§Ml(}iã‚´îÍ?70ÄìoõG¿÷é¯ lî³)“MÄöã­#öI¾À·-Âlk_ÞJ¨yK»©›Uïܾü[Ýã6$¢l<Ÿêל�íÚö[>Û¿µÏmEŸ·�µËÜvß¶÷ÿm®C‚¯Ø|wÛv#e „ËlXiH-ãÏà1°öV±!¤†±cU:hl>i€n6û={}ô¶]ÏŸ5­3,ìÐÜœq´çŽ£ˆÓ,‚ÜžÑ˹ë9cˆ5\||ù‹>$K%SdLN|Ÿ e†k©ýÍ"[€@Ë·Ù§»÷[o ²�¤´]ó6ݰÚs7õŸ»_m‚ÐYßmu�‹Cmû^‘•Þ×´’Ìû)'žmËõ ”7úÓ ªÍ#¬“֯ ~ŸqýãÊ”2k/²A¬}è….уÜ"Å ¶QƒkÛäÛ ñ[sþûþ”>ޤwÖÿyžécõŘ”A˜lÄék2oI´võ×Y cRÜå� áEÆÆ¤1Ú$œ­5Ú=B»s…C⻽/*Pø•6Ì)™{÷&o„Ì;À�ò¦a¹¿Öù5\ü-\^#<ÀeºÈ\„0I¹—„µx ¯èûfø-öÑò0îS�éð‹àÂÈ…®yëãǼ:�ñ•�1C¥°ÀÁrÅn•¬�¯÷ºQ)`­³”ï)ÅRÞ;›:Ïá®}ãÑ!7úÎ:PÖ)ÿünUòÄÀY½èC�½RàÏ<ö!fÜ÷{³Ö?0ò÷‹‚…1ô ÅÓþ4ai W}ø¢×O&ütræÁu˜¬×œÖ57ú=¤TJr±Sq½ßåá|ÉÉzÍÓÃ;eÉ'¾pÌ3ã!•”.Wüäè”+½ƒB!…óÖ¸Þï"}BÜgFnz<^¬xåø”§†}®÷º.—|{ÿ,\ëu0ÖòÎÙ‹àfßY{K§éoŸžq£ßå¹ñ�Y­ù7÷YhÍ ;# )ù›ý#Wk2HæFc­³d?Y×\êV\ë9kÿïíqR×üê¥=.v*þòáLgÜôÙ«JÞ?›q°rc=(œ�8­5·‡}.–ì/–|éâ.·G¾pÌk'žôxjØçõ“ û¤›Oú,µáÃù‚�Ò)$æZ3, nºâ™Ç IDAT zœ®k~txÌ‹;#>»7æãÙ‚W½â—/ìrV×¼w6ce,·}„u`{åó[¼=™r£×ãB×)¾õø�I]ów¯]ÂÃk'&ëš;ûUÉÝ©‹õµ×åLkºR¡±<ÑïñÊñ)³uÍ.ìòÄ Ç_{Ä�‘óbxÅçÍ0À“ý3­9\®Ù딜¬Öœ®köÊ‚'ú=^?9ãíÉ”ÛÃçâ.¯O8^¯À.ìp¼rÖþ—¼X[D~=¾yrÆ�ါÝGË•{Uóo߸Êt]s¾@Ë¥a—ßÿà=`Øíôxáöç©Êæ+§} 9ûŒWréáouØ5 g"î3io‘¿Ž{¶Íö1Ïkš[�#¥§�Æcî>|ÄÚî®W|¡7ˆ{Øõ~� U�ƒ‹³ž[„‡k³=(*)ÙëT ð6X€¯�å–*øêx‡5ðá:)îóÞƒÇct;^áj¨kÍ:æ¶IùlŒ }”YWç æ,6n´f“2#k�q1¤P�i$�'€ç£É>±I¸ |‘´i3Î>)Ü›R]Âô‰Õc’=)…pÀ}!)Ë‚ª,¼ç€Dú:£1Zc­F`P²@È2åÀÍÃJ¹+é…¤,„‹¢!µó`M)5½R0èHI·’üùë÷ù_þü-Ž¦Î»æ·zC¾ÚR A§ögT�°ÊŸŸÖÚ%KÇy Ô&y³´Ã ]ïuâ¼ ï�×:ÒïÚÚ¨¸Úí°Ô†µçƒž¹æp§ˆ!„ªBò¯þ‡ÏrãrÞS@ˆ4OÂ(K!|¢SSŠ(@ù¹'œ" †®IqH’wÖ‘K�àL>‰ÂÔÊð`€ßÆ$Z²¬… [Ò§Þ;@�õæü!awôòL†."ôþ}aO2I'x9¤u™BQ¸B®ýFxã�x¯L Žà"äeí WäJ�¸�€F Æ­SëH|åò;H¥¯ÞåãSÚÚ´xZ�²î”(¯P®�´€Ìêµ¥^'OÔµ•ÉXÅd²³1Ÿ�5)б¤´�q‚1¾ÿ“焵.¿Õ6&í�!Ÿ‚Bá=" é1`³üIfÌFŸ+`SFoΉl^ˆ‘u&AP8|ÃÝ#¢G>_bT øÊå䪠;ò^Q¸}Ò:Co�óª°IVX¬ÞiÄËŠ1Œ3öJ ¿> éCB»×0ëâ+8o¯J¹yJ¢¤[ R•½UQ8O-áèÎJ[–:a-³ˆrªŸ¹q7qþßmy�û›PF^9‘íWͱ Gޱ¥w'&º#&åòÍ–𑸑M¾ÔæõÈúAz~*žñ½­çã¿‚¼<¤F0ÜÄËõ±}a/�d13òõ^UQÏn[í s7ä\ÉsÁl[Û°è�6lë_dö/¤µ@OÖÕý7/~½ñ M½õu"ü™�ºØü{£‚T)¤p6Í÷n™n›-Íïoò›÷‹4[m@P‚rÀ Ú]׈æ"°­öæ«|£vé<=·eÛ>·;¶/Ö_ü}žêÅjn«o‚E–<²¾56Ìvn�žA3ŒrŠ�S hË*x ƒ¶Êy X˜¹àD`Ÿìo›RbR2€ÎÒˆõÎü9ësAÄ\1Ð. ?³aq[LÛÝ»I ›wÙÆ’G$îÉš¿ÄÇEÝ´Ø K:ÜšÓÓ†2 ¡h0y‰�ñŒë$ίpúÍeDÈ6çh᮲g“àïxPD�<¹K‘-›6μoÃ÷lm6ë+|»<Èì±þ­µûÖƒÏÂ'Y ¥oS„4 44’ìACAâhzS)°i�‡ÝqJdÊ¥XO?Kš{sÖ?�mŽ#ç¿Msߟ!‚”^1àA~%SÜà\9 üýáˆu—"äbóãßœ—ìÖ>f~°„7î4¦Y_Âúv{C®ârý!Î9³q%¬÷ðn›ccòaWO™î§)XåɯmxÖ÷ÉK@Ç|y8Ÿ:*ˆÉ€]~CÕäûÁA{OЦõT¡- pM¯«HuãÒÉöw®]â�ûLfÌŒá�ùœ°·‡"ñû‹%µu ˆÁ%ø|°XÆdÄRÀÌv|òa!·‡} !8«kVư[Ut¤äá|Á«'nù¼+íÝ'½è™0*\˜‹E®t;Ñ‚ò�Ó)W».Ð\kþìþcFeò48\­uß­J®÷º(!øp6wqæû= ðoîc¬ÓðÆéËhí�ô•âR·ÃRkFeÁ�ñ�QQðêñ)kk¹3Ð/ýð€wϦ<;R‹ÿîtÎÍ^—®RTJQJɃ‡ËGë5¿ta—›½¯žLøÁÁ1/ÜépáB K—«Á"x¼XrcУ+ÓºæÖ Ëíဓuͫǧ<5èóÌxȣŊï±ÔšgGCZóúÉ„µµQ9R[KGJ.ö:¼7™rkÐçÎp@)%ùpŸi­ùõË(¤ä;��8Z­ùÔxHGJ-–Ì´óÀXË…n‡J žôùñÑ)'ëš/_¹È­AŸ¿x°ÏÓ9ÏŒÜèË÷šAáòF¬ŒKüä Ï´ÖÌ�æf¯Ç�aŸïñÓÓ3^Üñ™Ý1oO¦|4›c…å³»c–ZóálAWJ®t;̽‚ñbU¡±¼r|êAþ!G«¯O8Y¯ùêµKœ¬×|0�3׆vFt¤äît†µp©ÓáÁbÉÅNŨ*(Å÷Ž™Õ†ßºz‘¾RQñÌhÀÃ>oŸž¡­å’ý;…dR×\îtx{2eª5wÆnt�gÇýù‚gÇC>··ÃOXC!%/ìŒx¼X1©k*)©¤d¦5BnŒúü“{÷ØVÄU—çŸþ\T lçÏS �mmšžÏîml¯#l)LPvO¼/ã¹�,o‘£CÛ™|�‚²(¨ Åãc¦ÖpUìy/¥ÉºæxµFÁ¨(J�wFdì¸,0ØkkJHànO)Ö~J•|m¼ƒîe ‚GÇÞ{ðˆÙbIé…!Ñ}mlÌy<ÐbœZѤ+®¿˜šóqÌS*<ïé¿WÑä“%X ËÁ»ÏFún0 œÈ”6�¿/&~*?VÁc ôÞ�² *KÊÒ… <¥Õmj>޼,¢ŒB½õLzPþÞ#½ÂA Ÿ_Ji)¥qù¤¡ß‘ »Š'3þç?}‹ï½{€±–kEÁ2ÚãéÒÑ( ¥$ ¾�' §\Ž™ø›¢ù|ž'@de <- y¤|j8à`¹ŠÏεi”Bò•R0.Kæ:)~ùâ.÷½â\Âì<ÁÑjÍÁjÍK{c¾þá=f¾ø»Oó¿r)‚§¼MÓ% ë+„€¬MQ=TOàÀŒ"‹isiˆù‚xTð$0Úd[[êO�ôsÒÉèy¨«”ß@Dð4YäBH ì&a’3ƒb WÑ„ô+.OEèS{ÒÅI!•T`� QfÂü !¢Ôä(U¸ð=q}䘊ÑNʳ.u­WH¹Üi œñ+ˆB:Å@!ܽJ€ò šÐ@áOYHŸ/Ç)_ƒÒ7W ¨ 005Úhæµ`©“l骑)⪎ =Ñ  Úž…hÊŠáØð*ˆì„h߸ù0¤½,>“�9»Ì6åþægØ_6ñ€¦² {]Bd2n !é^±QÍøî<\³?’:úœö‡w´û1H‡í±‰¼H~­i€›÷iØÉEëØî4ö¡!9ii†Yn]k¼Ý´¬žÉøÒQ�ö7œæt ¼‘»0�H }}ST‚ L· Gˆ–V4÷C“¶©¬ãS¥@ä—·Ì¿sÇÐ?³½a­ûl $›w®]êÿÑó_OÈ¡ëúí¯Îvton^Ï!ÑþÝ6î"ÜØÞ¼¸Wp~Gli_Ø&Ì´z¢ ž‰-Z2Òåð‚¸@ógS!ç<¹e³Ù¸þ‹Ÿ<)òw}²bàç½ÆSß(|´Û6‡öß§ž ±Ú$7N�sûÓ ¡¥‹Y=`UVµK¤Y‹1 cJŒ‹à`q“�ÚD€’" )‚å¬ÍÝ÷Â"&=Oö»iL•æFԞŇm|xF8Y»§¾Ke#R}uŠÏúÞµ!®eX¸Ù"n,éT‘t�/¯Ig%–ƪIŠ6½bÉž1Ù$ –\[ê/Ä6‡d¶y’–FŸ¶ˆ²ˆÄ4ôU $‚k—�ß–¡8ç»�Ê¢¶2¥M`Ü<±�çCBÁFÙÛ8–sŽmZöÈ4d«©­�21ÙÊóû#P´Œ „2mÖ6Kæâ–µs³O£ž<¼b@„ß3ê™Ú˜öò<}óÁ¦9fl§Ù÷©‹›}ç^ØŸ·ìL�£µþCî-9MLì®û¾‚”' XßÀ"ì1>y˜åÄO=ò„Á)ŸJ°:�#±F`¬ÄZ™¬±2pÄ1'™BÀ-O÷›vù‰–}ßZ¼eV>£[Ò~L é ÿ>}ë*ßyëVµæñzÍP[^ã–¦q¹‚·À (¢R`Vk*%£Rà§§g”BÐõÀݽٜÚXÆþz¿(èŠ~¡°ÖRHÉS—WàîtîÖn!oM¦üìlÆM¯D¨�åÃÙÜYèûú\ëu¹X•̵a¡ 7ú]v«’ûó¯�ðÔ`@GIŽVk~xx­~ 7TË宋‰¿2.ìƒS­yãdÂÍ^—«½.§«5ñpŸJ:ï ¼y2ÁàBH€Kv:(ãÒ½ûj¯Ëóã!Á_=:`i Ï{σïó`æÀa!³Z³2†§}fµf¯ªØ©J®õº¼z|ʬÖüòÅ]vÊ’¿x¸Ï{gS^ØÑ/\Rå�æ ÆUÉnU¢„ •òô`ÀTkZóìxÈíÑ€·OÏøÑá /=ìó³³oO¦hcyzØg® ÷f .v*.t*–Ú0* nõ»¬µåµ“ ÏïŒøÌΈ�ç ~xx‚ÅõÓZóæé3­yvä¼–.QìýÎ\ïu¸Ð©Øë¸AÚX~ëÚ%Jïñx±â™ñ�ÝNÅ»§Sjk¹Üuý=* fZs{0àõÓ3¦Zó¹½17=¾ñð€�fs>³;æÎhÀ�ŽN˜ÖšRJnûœ¬kö—+ö|²á™ÖôTÁSƒïžMyíxÂç/ìðéÝ1?=�ðÑlÁLkÇ~¹Š �ŸôYÃÑjM¿Pt‹‚×O&<9p^!S¯„™Ãß»v™Éºö çI²WUÜ=›apI¶�–+ú…B[¸Ü-ùîÁÚZ>¿·Ã•^‡žpV×<³;â÷?ø€G>f~UvxîéÏ6<¶n‚?ïê/ÄBŠÆ}M) ÑÐ@ªÚÜ…´+£þ°Ö+’mq`±'o2ý½7°rÊ|é?ßíðéÑ0ZR àö°Ï~À†ùŽ…d¥ìTe#ñ¥nÓs@I' †£6†'UÉ×Fc*%yåÂÀXë’|pÌñÔå£(ŠÂs[ÁšØƒs0ՔĿÝâ{4‚ýéS4eÍ$è�4ÐëF¯Ïf|ñ™ÿë?z)=ãÆ/αÌúácåçA]üÄ Àf¡œbÀ:`Ü_s�ðŽÍ¿ã-�ýFDñÓ›Ê �3«Žâ�õ@Ï— p°\(„,@D/�ÀàdJÏGsvá-+„³®@ë×J‰�E*[>é²·Æö(jð@¶ûôºxLÄËa_óÿ%]€_ÏŽSE �Æàbë»PB>p¼k_QDE�SöÛ“B´Iß΀Džþòù „W6éÃÖ+Ãr¥Y¯ ëµe­k#|HJÖÒ&o{ƒ—¿mæ•MÙÂ+|[ãäH¿±‡–'yÝYÏ)q¤p‰yETô#R"æH[­p@[HÌ+3 .Œ¿p=*‘D£\‡kà¼(¼rCœKÒ ï•�Ã;Âi‚ÁŽ�mO5��²�PÂ…Z-œ\…çÃÙÞŽuŠÞ¸÷ûê"*¢W�=,ø5ZøwËØm”ôú2 %ÚÜb2÷<Éž!Í1m½1ßÈR{üئùDR´˜º ¥@T …E³]A™æ‘l�gðÔ0�ùv“ yfÄ=�=Jb¤6Oë1œ–¦ ,ì.þ~à›d�<–‚G�õ¡}RÕP÷�„-–¥µ÷‚±Xƒ‚ wÃvJ‹"Orl­ôဂb %;kìq¡žÚF¯w&E‚S ¤ÒàŸ};™!óNºUÁ� c¾÷ö=¾?Ÿñd§ÃíŽ qÐõÖîÓZs¾ŒÖøµµ|wÿˆ›™µ%%�BÅBªŠqY²6†�fsv«2*þäÁãøàƒéŒ½ªŠJ…QQ8kéË‚[>ÐËG'\"d!?<<á`µæfßõƃ;Áó`P<;P)ÅÏÎfèôé*Å��Oyõø”gGC¤.W¼}:åf¿GGIJ)éHÉõA�•6,µáÙÑ€k½.Íæüèð„§G.w:Ü�ÎùñÑ)â`§*ÑÖrw6�@ÎÊX®÷\΂ÉjÍ;“)wFn,×üÕã*¥xjà¼~||ж6æb¨­¥W(®t;OzüÍþÍ|vo‡Ïí�ùñÑ)“uM)%ŸÞ1ñ ô”dí×å¥n‡Ç‹oNÎxigÌ“^)óñ|á”×/óátÁñº¦6–çv\ø¨I]óähÀ?ΔeYñìS/Q•ÝæÂní½9�´Ùï÷6þÚ“»�¤U~¢•MÚæMÒa¯"($xíAáiK¦Þ.�Ü}´Ï¦Æp•W+*.u*–&%q½ìc¶O²ð=¥Š�¶ç@zÃX0·6–k²àïŽÆ<ÙéðîjÉÚ_[®kŽÎ¦<>>aU×E‰*ª(ÓÈRÙ @Ëi_ ¡ñ3È/TÌ>¥õ¸Wà§BQáo÷.é{0v°ž‡Í%$KÚÈU!p"¦$B8é’—¥í;>„PU9ÏŽ²pI‰(j}Ó„S T%RnQ ø±p9Šd µáÞ#éV�RFÅÀzµâ[?}Àÿõ�øðÐâ7‹’8æùN·1–…t‚{8Ú!ƒÂØ–b3ÜÐ�^·1oVèæ�öüOé áú ãaCQå¬ýM\guÝHF¼66*žnåÅxiwÌʘ8gÃ:éŠÑüŸ�]8Àn%ù—ð®í‰¯Gdô^D�Ð`-¢ï4äXá� ¬�•O’@ÇÈ`Ĺâ�»Ýº–ñÀqš‚·Þâ?¥ï^)€Ï«E@ÎCfr¿u|\`ÌD8},ˆà-½ZB�#)A*ß2¬¹òO b@ �%(\L÷„Cˆø_XW€°Xa°Â ±Ô¸PBÊJ°X¯¤�Ê�‰R%ür ¤o—%%ДÊ+8š^Â[»ëÚ¢W†ÕJ³\äŠXYé=Y[¡=³½#Éà6�²pûˆñ¼quÙyØd“T&)¿‚ˆaz|L6R>?ùý¨žÌYxÚð·õñ|r€N¡Ùbš=¯ùðóÍEâñѼ~4"ICW*þÇâBƒ¶Y(Š¢ðr•Þƒà-Ãâqó aÜ#A*gÕOè æ³q4ǘ J;#<5VÂ+³ÀJé«K¦íä¸|Å(™yî[ƒ15º^²®kfº`^§ð¢IÖôÙj~ ‹ �aÈ¢ü˜p\AcãÈv�Må�+lã¾ìë–²²û2;G¦£u|«…mo€šo{Y;ÉêÔäÃlä ²[å¤j'Ìd»b µk³Jí¶û2†þÍÚÞ%ãÚi5">-š]˜}iøM<§]+ϱfûIŽ5 ”meû=¸‘ë*ž6Ýã+™øÖ<|¹ÇHt2ø3aÿ {&Õ?~B å¸aà¥ü>ÓÀ4²ú5„õ&¦/¥îÙ€žâ!lèsítkž(lZ{o_ãë&¶Ç½1U­ òG†ÈÝØÝufGðÓ�ÏmGó÷è}b¼ó¦µÁlî}írs«xѨO>Ãityë�P�ͺÇÑ<§=á9œΞʗ¬ˆ„@4* Zuˆ± Éæ‚ ÷¦�N2ÆP XV´g>�ÍgBS©Ô¦#Ö‡¢R%B¼�&¥Ÿ¢h ySÕî´l‹…7ð ^sê˱Ö2_,9<9frv†±–²¨(T‘‰A™<Ò¯G¥Õç `Ó¾î@tÎÌ“/zÄÏÀ«åª(¼Ñ�³©ù‹ŠB9¯ƒB¢”ËaP‚R�6k¾ûæ‡üóï¼Çû�\ßîJÅï ÆüfoÀ �cè� èµ@ÿAQDzë;§ùâ¼Q"ya†yRHÉÚ+*%٭ʆ7Að4 Ç´ÖX\®‹žRQA!…à³{㘌 ¯TL> .|ßB$ÐU’™vòã_¿w/¶ëüÏŸçw~ù"y~½`è�Ï…*Üé«,V‹ÏÏg`-’—€+ñ ·ñ–Íi®Ä®ÌÎæNÕ”¥Ò I°*ÅÓÇOüXX²¸Œ| ‚Hz|Üâ²$ ÅZ¢†Ö µW Ø�ÃH017A�ãC]Ûcòa ƒÁd9¼7iI>®{ÃÏ6{'7ú;\Z ŒD��RÈ�‘ôÏÏ)yÜúžQH…• +Tì;lŠ‘�½6Ô+ÃjiX.5+¯$X×Péeu“K AÉøþ¬¯µØbÒaÛôÂÕÚ ëd�»!÷[ë a¬ë,1‘´— ¢Œ÷Ò`œæ×rƃ۬ßCh)&t+åã¿Ym±>*¸gSDž‡ú¹j¥o´'£·€¤öJ�0ËRQTE”Í�¬ë\$‹3 ëOßÏ9—ƒÁÍÝd é”5Á+,$X¯½l‚”ÈB¹á�Êå°~ˆJ2«�÷ˆNyßj]Së­kjm˜êª¡ Ñ÷a"$"�…ëÙ.Ñ€š2£â��¤yä ìü¾_D1°iÑ/÷çÈù&%dP²'à<*ø·Õ»±ÄS_¸ÏÐ^OûÓË›-oÕ+ì›r?´1˜¼]¢]Fëû¦Á_~²ql”‘Ç j`Bélâ?9æ’~ßv=kMÖÜ>0�™4Úö7þÞ ÉùÓä1�yäGŒ2+Âï+)7©žöìñȧV|>»c[g‡û°é3+?R^Ǩµ:-(mšc  þà¿zöëñ>›‘éfOǾ³ù—°XCËüRVéÍRš¬@¾@òÁM…ˆ×šUÚÞQ]¾Ù©Cál±*µÎ'tcÿ:¯ùµVÙbËo¿ð±e�o™áq³ýÿuäÓ¶]ÏlÑo¼=¬bb@­×Ñx¦.x x†Æ.c­-u’t´VèÚ1 ÆÞsðÌDN³øà6X"¤úÙF߇ÅÚš§‘@‰æ¦Ò¾/ @žu]°’°�Eã_\ÌÙs¾¼æ¦a±Vc�n€šÍ…o“°H~-ŒsÅÛÜÝÀòŒ)±Žu5WYŸ%F®Ýw"¾c ÑΘ»f7fL_v_('XË;F)sOÍ€�ó@ ÛhSîIg¿»ø8<Ö¿'?µß �žõ¿mŒ-Î ]ÉëÐè›ðÛ9í ÷@õ,€TãÆ<>,rå@¦$ðŒ¤ŒJ�Ž©L–¢Á£#Xèæ4ÛExîÆE>x|Ì£g=þòlÆtå2=)9«kºJE¥ÀŽ¹Ô­P~L—+´µ |ÂàA¡¸ÐéPHwµ”2*Þ>=£”’aá¤×ŽO9^­¹ì¯ÏµŒ‚gB)%·G:RrâÁ–+Ýâàµã oO¦<5è¡„àt]óÆé·ú= ß']¥¸Ô­\Lmkyf4äB§b¹â­ÉO úì”%�K¾õø�qåâDàÝÉ4†öØí”.´‘€ó%Oz<=ìs´Zñ�œþ �ðíLJ¬­Kv L슫ݧëšý.×ú]ÆeÉŽRð™�ƒBñWøp6÷ɆïN¦-W<5èSúøóBÀÓÃ>çK‚—vÇÜôøæãC^?=ã³»#®v»¼~ìÂã Ë‚KÝŠ•1Áo\¹À\~rä_¸¸K%ïL¦àé�ëÃ�NIO)®ö:üàà˜RJ~íò.w:|ãá>Í|~o‡ë½.?9ž0ך�²äB§âd]s²Zssà¼1jàbUñô°ÏNøéäŒ_òÖþ?8<áxµ¦«ŸÛó`±ät]SHÁ^U¹p"Æå·8«kÞšœñìxÈ3Ã>wgsÞ?›±6†¯^½ÄÁjÅdz ­yiwL!¥Ë‡ìT%Ï\êV”BR*ÉŽBð—.ÐQï�M™iÍK»;\¨J>ž-Øöøýî2ñ`s§ê:¥@¬¡7÷hlRÂ&¥sÿMûæ'óÐçÝèHóÇð»ð샌¼‹–›‘· <›o±Hãx˜�L/\ö§«‡Èr HÊ ( J%}LjïIP9ï§(©JE§*èõºô{Š¢GQô�^Ya­sß>‰±òñ­ %bHûÕzÅ÷ߺÇç-Þ{p‚6–®üfoÈ¿;s±((… çêÚ¹š|7¬�i|ϯ_l)Œ.w;Ì2“•1 ÏmmT Œ}RãPÖ­~k“§B!�‚=|·•]¥ÐÖF…ÄÕ^—®’±.ãªäFßå©ùü…þû?ä±÷&ú÷~õ*ÿô?{žFn=kQžW…ÂÁê\EáÈÊóI)àW)¢WrôNv³¬!ÛŸ';¶•™ñ>+bÜ{'±'ž0=#!`ðäÁÙLŽÀhîméªe“U}]#ê ðkŸLX „ð¡{�ô�9´p¡—°XaœÇ@™]¸>kI ¿�¼lŒù)‚1›%$…�¶ƒD¢¼b ‹ƒˆ!b8E¾Ï ª@x¥€�ŠßÏFF�…^êµaµÔ,çÚ‡ÒÞˆO¢­ ö€qÈ5�öpAPÞ8�>{yo[­3~;u…©}.­M¼ÃzƒÁ�öÁè`håÞ™<¬óðE©�rÙ5åMq§ð˜òˆè1à’‘ÄøI.Ç@èl#œ§@˜«°Ê•åe£6%1RDp>(Ò ¿gbÎá!ªAˆ!à¿n}¤[k­ÁººÚ8#¥ÃÚd!‘¥ ÍÍÃÌÚL1 ±™ÈhK­5F×]£�eVÅ€›¤Nìù¤Ì º"=Ú&2gPƒñ4)¨›jÛ|w­gÛG¾g�êÓ£S•¯HÊö¼­Íøá–ýmÛw‘UcS! ²kÙû3å@*`;¨Ÿ^Òú-+?Ô@Êp±ìhLÙ®y뽢чíw5©@Àh¶éZÂ\>ù°ñßÄËErÎ�§‘ûÌøœLþÏÏ\1½Âêš·-l½ ,rEäÆDˆiŸÙZWÿ)òßÚg{÷9¯}­¶¶îíŽßZÖygÖO�žˆt£µ¤[›B¶Òœ·Þ Ô«´ÂtbÃÔh³ÂÚ5ؘ%Æ@m‹±Ú3÷™Û$¾-?¸ÜìËÄûM&-b'6)¼ÁÏï¶ë϶M-¾)­Ù{âî`iÖÁ¦º…{\=½%EœmkÑDzÒ&d£%ubžcÒ+!#˜’©†b’!Ö›t‡wIÇ@™¨ —3׫¸�úñÉ6« ÐÆ�ÿ²#XÅ¥ÆÑúù`Zϧ.‰Ÿ9qô¿…$W ër&1�cŒJAt?ŽŒe¬è‚×Ü;›-´Ù¯ù=a.Øhy=¬�–æÍÐ1"®¥°ÖÜ™;}ÊÈôFæ7Ÿ#žy¶á¾HŒ‚p•\´¥”qe¸ØöŽILv7ÕŒŒ,|#ø@¶§z0_ú~‹Ä?ì! YÆäǶ ¿g‹¦×„›sÁEׇù´>Ž¿ÿ\[Õ¦8©kk+¨­D£gMö›P¡°¢Àÿ›•h+1V hdú´îyƒB[…¦p‰ÕýwãŸKû–³ ¥F�d�+ YS*M·2ô:ÐëHI¿«èw$½JЩ,� ªŽ *%e)(ã…%$J(—h.Ò}÷rçèW­Õn¿õ‰ŸCån]á'w0]®™—Œøk;;ül2�À=À•^'Z™>( Zóñ|ÁnUQHÁÚþäþcîŒq�ŸÕšJ z>dÐ^§âRÇ…Ü8\®¸èCXkùæãCv«Š¾¿÷ÇG.æ~¨Ë@)z…bT1&þ�Ñ%ožL@®÷ºRòÝý#-—1gÁÁrÅãÅ’[>Ò (Ø­J.V§õšµµ¼0±S•¼yzæBÜŒ‡t”äÃéœ�p¥[ÑSŠJJZs±S¹�ÀíaŸ'=,–¼yzƳc—„÷ábÉ·÷�\x¢^—µ1¼z2aX¨Ø.jV.TÄtî@éÑ€³Zó�G”RðâÎ |óñ!÷g ^ð9 ö—k¤ðžZs©Ûe\º°L¯øL¿ri�½ªäOï?æîÔ) ÆeÉ«'NVk®v; Šm]²ÌÛÃ>Çë5…”<9èñ©Ñ€oïñÞdÊß¹¸ÇSƒ/óálNå9ËæKzJr©[±6.䯓Ç«oœLøÂ…]žxg2ã�“ ÆÂ/ìr¶à£ù‚ÓuÍs£!…€�K”Üè¹�MO º Š‚®R|óñ!BÀW¯]B[ã,ö+>¿;fT¼qzà#éV·ú=^?=£«$Ï�‡\ívùöãCÌ—¼¸;âÎhÀ÷OXC%%wFîÏ—Lëš�NÉÊ …”ÜôxíxÂ;“3¾ti�gÇC^>:a¹B"øµËø`:ã¬Ö¬´áæ ÇÊö—+z… Cñh¹Dõ*þèÞ=æ8ìuú<ûôKTE7£Ä¸5Ý G~�Gž#íÓ;^-k*¶“ÞÏÜ| lØo|}I¤ÛцdéõFµñtbo4äƒGû¬¬åq]óBå”%w†J%™f–ÖÑpƒR (4p\)IWIÖYÌ™¾� ÿ‹ÆX.KÅWúC¾ÐïsæëŽu½f2;cÿxŸÓ鄺®QRQ>¯Ïó“hrøTHU dEQT(U¢d‰’RVQ (€hïBc؋ګSïÑGƒ#vÔ׳D.žµç…[3E¡(+—`Xù„ËÖ#j…ö«Ê)ºeA¯£è’n)肎r|{­-F¯0zv…5¥²tTÊP MIÍ££#~øö|ã'ïóñÁ©óº‚ÏvzüÇ£]neä¬h¬Ž O�ð­§Rˆ.Jˆ�¹Rˆ ¿‚J5s\ïuÖýƒB1Ï”§ëºáP¿?76¿¸3bêsθ:[V&å%XjÃÁrÅ�á€qzÌw&n]ìòÇ¿ÿË *�ŸŠÑúxá©Âú ë±Æež5Xi1"ñÁ6È>ð+6î §hÉïQhòu0®8Ø ê òz£6ç °�×�ò2ðÐ! —iƒ¼ˆ ÊòGY�–È+DX‹8zA™Ò!AÉÛÝ…$R^Éüf�3d•i›�V¯Ä‹u¥¼2't«q¼{àé5n¨�Ô Ãj^S¯ VûP¿¶Ä˜Â˘*z¼+Ñ&„ÅtÆÚHj#¨µ@‡ïÚåÖ2¶ð§»_[Im$µQÔVRãøæEm+£XÉÚHŒuŠ #FI©å½:âLÒM›8}¬{m‘Ö"µAjã”AµAÔ6å–¨ƒÀ†pAA‘` w‰Ð"†j"„è‘.)´³%ÂyYÉ‚R”²DQD¼Äjጅ4è/—J·§‹’NIغDÔB`J0 kDLØy}\誠Ó+”)ˆ!¥¢‡„k‹ÕÞ{9(c¬%D2�Qâ1¬µ¢®Ò®ºöûŒ—Q½”¶‚�—Ã)¨ÂË-¹=µôò¤Äº13"& ¦msÉ• ¤–í ÉÊx� He¥È¡Ï¶"®Ï<\r “!�ÈðÑ„…×fûQ¶7аwnÛÛèn µ;ø?·-9~°%ÔVT²F6VÖ¨ 4°¾=MÔ´&w›z[ۙθêq±$=È•žcN ¿%£[¾6¾1k[Ø�S›ò -mÒ~§BÄNJ8v³àÜó ‘Ž�Í¡ ¿–7¦b`†Î'Z /œPl\“xÒè˜wOŒ…ǨÕïyyY#�ÑQ)ÞFŃâ(] ENÐYIÍ ÄË8á„ù–Â4lBáÍqÜj-ŸõWáw®k´§É…¤fΩ:9ƒ°¬·Ix¼¥|è3Ž2ÔËú>Ï÷wgèb ŽÁÂ0ÕÙ)k‚](+(l[ÌDèK6Gtc=C;Epï1)PnµÚf¬ôH‹ò^îßs�œIóÄ7nñ6ó§!yO¤!òrwR³•*"{Eò ïÂ:7bg�)R¼æR¸ð R"%Xa}®3KP ™Z µ@×x�,fÖj?Þ:Ñ`ƒ•šà¡eÃc Ö ¤àw¿úEþÙÿó7,Vk^™NùŸîß翽yp! .ø$®o�žapÖä€\R·”Ròn\E j()xÊÇ˸XrâÃׄ²_=žðµk—âJºÙ뺜~Ìåâ.àB<Ü÷ |eÁÑjÅ7ò›W.:ë~k™Õšy]ƒôÒîé·Ç£ÕŠ[>ÙðJ¾µÈ3ã!×{˜ÿÆ£z…â7._ ##ï ±¶–§=…KùúɄݪä—.ìb�?¹ÿ%¿}í2û‹%�KÖÆRI§ùÔhÀõ~—ýÅ’n¡ø{×.SJÁk˜ÿ·.í!„à­Ó3~zzFG)W7ë¼[¤pJ,|noL¿(øxîÀô—vÆô Å›§g¼}zÆ3£/îŒØ_,ùh¾àÌ'ÃBDpZ?;›ñÒÞ˜Z”üë�q«ßãËW.0©kþæÁ!R~çÆU„p.q²fi OxË•^‡Ó+¿éà ýÙýÇhkùŠŸÿ÷þ#VÚ0¯köª]/L_êVÜŸ/芗vFŒªŠo>:`a ¿rq—QYðíý#—+nû¼´;æ§§.¤È¼Ö¬M·¡Šû‹˵³ä‚Ãå’W¦§ìV%¿uõoœLØ_,ÙÇ�rs­£w�1–÷Îf<;p²^ÓW’?þè—:¾|å"‹ZóýÃc~ëê%:JòÖé8Y®(E‡�*Xꣲà;ûGô”Kˆ\Á7`�/ìíp¡SñòÑ óBòO?ø �ƒÞˆgŸú,JªLaœ,ð7iN 9)×woøÛ…* ”R]q}im�眠 0ÞEÍD~Ð#A¤PzÁS�l¾ðâù/í¬ÉCÌyYÎú\8ðÝÔ5galQH,¥ô;ŠnUà2œ ¬Ñ­Ñµf) µ¬)Ä T� „Þ�§sÞºÀ›p2K£Ò‚/vûüJ·OÑêóÈÏãÖþ"ö‡EÑîÛ ¿µ–}¯0*…ˆ9#Àå§8^×1d�P É2óM¸ï‡#$Ä”®–SŸ7 +%×z]~æC’ÜŸ5ŸýÉñ©k«]æ`!/îŽøÉ‘Û»Þ×+þÕá!à¼8þ�ÿâ3\éKGÈýZ#*îE’±½1RBQ¢­ ¥.þ¼ß7DŒÛî gË=op k!¼ûf€�¬—}_‡ïM94ÅWß¾ÎDë3—ñ£F Ö�÷JJ¿MZÚáÃûxNL °Î0 ÏS p1äë`�íå€"ïGë­µB(¬±þõQjuûs”Ý\Ç/û½X%È"—>Cð´w[Œ“7¤vášÜ&ˆËeP …rï°!œQâéƒROXƒ´Öï±2V*NA&ã�~"±F¹ÓÓc$Æxkué¾…ôÍò»»51ê6ìoÝž Røy畚٠R¸µÜñ¹RdPÊXJÏvƒô÷�² 81ôoX³2Ž…ÃÀ'À¯±‘9ÉÏÆ� M¶F¬—-Ö…C3R`´SªDeŒ—y´ÞöJƒµ”¥S¬ éE»0z´@ÔÖȨ8³Ê`•¥�ÂÇïíÒ¯ŽfZ uí“VËà"8ÀÓ¸%Ê •¥(,Te …ŸGÓ¥f±XS˜Q×Ô¢`í�qkuXšR!TóÚë Í„—™…µQÿ–NÀCÂuKÆó"à‰ì¿öè€ô "-Í� á<àòøFqSáb’S…Ÿ“î·Lž�éÝ9-Çnb%­À=³‰øf—›<Ø'yè%?Ͻ ßð¨ÊË'˜�âDvGàAEãÞóŸ¤ÄY RçQo°[xO!±ÙEÇÓ¾6ÞÓ¬Và5¥���ÇK’�i¿Œjeãz£­djâ”ÿ{okËuè}k­ªÚã™Ï=w"ï%ï%ERͲ,Y²eÙ–Ý@F:�¤úÁú%N:éi´;@ÒA‚ä-/1ÐFA?$H€b»e ±¬�šØ¢,‰”DR¤.y§3Ï{¨ªµò°Æª½Ï¹W¶ÜÈC×A�½wÕš‡ýóûˆÍÉw×D\µ-|\øV¦uéä]ü4ÍŸ¨òŸüƒ³CxiI.×^è¹øv/M’Ï4�’Ä�o‰ÁÌ’ë/y3 o.ßf=ÂoÜp@'å¤ÜV§¢¥ŸÝ2nÒR¼åÜKÌ|9#óÃö ôóÊ|˜tóóÌQ-€Ô&„uêÏ"m‘IQ ¨„}V(ÁÔjgAà$Òº6”uNYA"g‚rrʶHN�ؙ֔¦À‚Y0fÁ,ºûÕRí]ìJm–ÙL3¨’¬g3û®]ÅœTÉ12[¾ð ¡½iç4(jé÷Ô ø5IÍ¿f5w,Ì œ—¾[˜&£6µ¼H;w–{ž¶Oÿyé|9öð™ÓÆ3ÏâvÌ0ú}i_b{ÒvÍwÍ fî¶À/äwMËš޵¶ªïkƒÑàÖ½÷Uœ6&i{nøöx¡MŠ2ˆÖz‹ëÑ/µtO¶PVÂï×(´óªÔ%PôÍŸ(øÔÞg©ó-ëŸ'îÆ¼À¶4Fsÿx× ��¢ã›$søóȧ'¼M"ÖDpµ�[ŸÌE¦èŠ^'§×)è÷ z½‚^¯C¯›Ó)lPǯóÃý#Þ·ºÄõAŸWŽyí蘎”<6ì³9žpgdÝ]ìvÈÃlÙ YÞ<>åÝK \öyûtÌË»Rñ�µeö§S~|tÂQU;aŒàg'#2!xdh_êué+ÉRÑqî›r>va |s{�{£ Ï®,ÑË$¯Si,(V°óØpÈ;n�\êvxÔ¹Qº}:æcVybqÈK;û”ËEÎ W·ý]PHA�Õx»Üïñæñ)?=<á…µeÞ³´Àw÷¸s:Fcø¥ «¼u2⨬˜Ôš§—¨�Û'#ë"ÏxûdÄ#ý}%­µÍÁýLñ+ר�Ú€ËeÅV—É•ä�Ó€ À�ñêtÌÿtû6žm¹0Xá]ןE©4È®ƒ3sÏèä|ò¿"xu)fÏÆyùOçñ|Ü`þ¹>«¶k‰´øœ%ñç�°U$éVØ=:ât2á­jÊ#EÁ¢sk¡„àñ…»‰&öXë†öÿqUQ; s~™ýå]Áø+—2h—ÿ¼Wm ]Ï>µ°ÈSÝ.Ó´$ÐF3šŽÙ?ÞçþÞ}¶vMFTu�‚<Ï Q<Ëðnðêó¦N\r6•BîdÒ Š Íç²I!PJ‘+C w12)� �³r 6.@ß‹ h'œð±yÆ•`R+¦eÅd:¥®kvŽNøñ�¾úãwøúOÞáöî1“Òî„e©øxÈß,r-˽ÀpuZóÓ¶ðÚ÷óðÔÕ"oh÷ò¬aarZ×�µ¡M,o¥(ˆË½.§UP Á­�o×¾sûãÝù²öÄØKEÎj‘sà„ + WB²±Ð㟽ýv€ÿüヒÿèWšxŸp´yPÞ �|·šò"³)ÁbÅ»¥ ¼‚t¿:ü1¸8ñZôÐØém:Å·tò�öwÑLK3�h?'ùí„Æ«wã” nWl«„Sôx°s¥)UX#6¸¯ÄûµH)Ž Jè'__£�&LG–¯!ò_Üw¤…6éo[JzMe§Éoƒ0ûgÊYaE+ËôO\æÔºûÕSÔ„˜Ú3éZgNƒÝ)õW—~Ó3!º®2Þ�h¸ °(µÜÖ†µá�×ζÁÎ%"À;Lç4ã u‘ ]k ùi‹¿£®Àk; ^a…FËÐó zÞ2[ ƒtJ6†ªÒ”•¦,�›Ríaµskª=lÔáÌö±c¼ë�€Ï»°ÁË€£ƒ²5 °–$.¨0‚T摌�‰>íúï­_¼Å±Pd*#S ån¤bª;”ºé"éÅX΂]ˆà˜ØÎ‘µHÆèxô…Ú85hÁD+; /~~ýþð–us4æS>dŠ—$uz×ÅiÉÍméãï‰�'�áã×g »iüjÒü Ðä•6‹ˆ[‹xŽõóY ÄïižŸOÈ�^qÏÉ |FK¢½^¡S´ÆªÝïV.¼+¡óxL0¿u!ˆ:R¸bâ³ùíLðc÷¿¡ßŸôaÞz�8;²!¼hŽÅlÝ1¯ïE«—�i÷, ‡"vè¬ÌÌ”c4Á’Ïó¿Sÿ@®@3gÌ ó&#á:¤=šéKÒ¦9—>Íó ›ó;-égæË/ò2?gÁí6ÎËkÎxwÖósÚ!ÜúxPºv�RÑ ÄÎ"]V£%“ • Sš<«ÉÝ¡“Õ ¥AKƒ’Æš³%µÚÃ%.!�³fl˜Ñ¤YÉ»¤sö¿[Ú^'Ã>sR_!k/e“¦eÍX$ß­µ€ub÷šÛožO6é稵ÇRSéw{ÏÎ2žLØ’�¨`ÎÞw 'ºcŠBDh~ú>Çç"iˆÛa&-=i‹Ú *Ò~.p°fÅJZ¡@–Y?ã™ôA!W’ÂûiÎlZë‡ØO§Õü2@-¬PHk�vœ?=FC-4˜­mÀ0k1`ãˆØÈi¶Lë ÑÛaD³J¿6žººÁg?ð ü�Wø£û÷YËs~ge€£²â¨ª¸âõ“Zóâö.Ÿº¸ÆcµS4¬Fž]^¬o磲 ÁKcxqk—_Z_!wB„»§c–óäìÆ°¬FuÍJ‘ó+k”ZóÝÝž\7<_ÝÞc¹(x~eÑw'¸¸>è³Rä,ä·OG,ä9]·ýúÎÎ>­ƒ¥À›Ç§üìø”›.Èòй*Z+ Fµ&ðéË(¤ä�ã¶F>|a AÛÿ#ë+lt;LŒõíù“]eé a{<á…•% °5™òí�}ž[^à‰…'eÅ+ûG,ç9W\@ç�nVíö¤ä…åÆzH._ÝÜåRÏj¶ŸT5_º·E&%Ÿ½²ÀÎxÊiUQjCWÁ¥^‡QUq¹ßãõ£†YÆ'/®3P’/ÞÛFï^Z'—’/ßßæ°¬èHë~§«¬²a¦Ø›–JñÔâ�•"çû‡l�§|d}…a¦øÖö[“)O, x÷ò"¯3ªkö&Ö/»ÕôÏæGUÅîdÊ×–PB²7™ò¹;›\ôø­+yëø4h�ÿÖÕ‹L\Pq ß9scaÀδd˜)¾xo‹¥<ç—7ÖÐÚðâ¶Õ¸ýøÆ™¼îÜ —ë�‚…<ã´ªY) ^qLþÇ}‹œ/ÜÙ¤6†¯¯²ÖÉùüÝ-J­yl(xne‰ïïYÍßq]³7-YÊsyFWJ¾¿wÀI­yne‰Ž’•ÿzo—qÿ~€!K ëÜxô™ÆÙ¾=Ì ¸=4žG\Äsál¡<Ïh—ÕúœÉÙ:ëÏà °ØÕ¥Áºo^s+±‡tðÊøÃÅš£!…à…›7ùÊ÷À¤,ù³ãCþþâ*Ë€}ÍÍe?SŒª:h^¯w;”Zsà´º%ÐS’£g8,#Óh0Šÿ:×´ªYFðÙÞ�¿=\äÃ+“1_;9n£ÀúÓß>ØaûÀ‚WR1è Xìö ûz�žsÿg³©vî�"ÞAs!@]{˜‰�®Í(0X­K/È2G@¡’5ÆxíL¨«š²’”Ó’©(w()iéË,4ÔöOÇüäÖ]Þ¼³É϶ö87í5r!xWÞá¹n�+ªmм¼§�kö3k9àá­‚Ž” ‹¯Ýï¯#7÷™s­,€Õn‡í$@ð¸n®o9 Ò’¶ëÉ…?qkàJ¿ËO –;£q°ì³g×UµÑí°9ž0©5ï]]âýì-¦®ŸÿÁG/ò�þöM«EÜ œ†‚gú=d»À ¤BJåÕ¯#¬ÀijR;rÆ»ªJ:ž(b7HÆbÚD·VŠLY„l.U;xœ%’àßÁ#·®Ü€®Ehiy‘ICí',‘Ùp/ÚèLì»§HñÖ¦³ÝÌè@ÎŽW O«:ËZmž›î&,CVHœ˜Æó0í6qEd5êà¤Ê¨�¦Ò5¢lz.ð®]KmÐuŽlë•ÌŽ•�Éa/Æ{žüF·Lí¤Û�„:ßZ ÐÀÀAàO"ŠÀdãÌm•-f�]þC€È‡¼„»%)Áó L|ò jàÏò‡ï›Åqö˜ð–<Ü9ošL ͸ŽsðÞ³øcîKú´Ñ— Ch�_‚¯Ïâ<èŠÇÑœA4†l†Çe¬öeh‰CðÉa8("PÃ\a@䆜³0< k1^ãëëuíøÏäµ11i)ŸµÕù¤¿xE”êÏךŠq5„ìÍ/g>øwt%>ó¬ý¼ý.9Ü‚ÑLÌÓ2n™SVšÊc :ü6N�WÚ`<Æúv4NÿA‚ó��¹€X% ™°flÊ�U> S‚2Æ;YBéú€h³ôüsÑø=Ã46^Á6+8Xx`„Æ•]""¯É\˜€}'å _ÖìØG£ß2�ñ§˜¿Ÿ£ö|Æ~…þ…ßíºÚÙÚÀ6iS@:‰ð¤•גּfzè’Îײ�Œ Ïùèú*C©­?æË½.—{]ÆZó�­]ž_Yd¥(¨�á»{‡Üôx·Z<:è±ïŸV5O/yji�Zk^Þ;à‘^�g–øÜÝM–ó<´UkÃÞ´´®~¤ä‘~�\JÖ:·OGô³,0æ_ÚÙ稪øäEë6éå½Þ>YMúLÑSо’,äy`d}`u‰¥<çLJÇ–/¬.‘ ÁŽxóè„g–¬áîhÂÞtÊ‚³~èeŠG=úJqXVlŽ'|pݺ=:œ–üÅæO, øè…Uî�ƼzpÄB–ñ©Këø ¨•6TÀñ´äéÅ!eÅ…n‡·v¹ÒïòÛW/q\U|ùþ6B~óʹ|ggŸÊXË…ÅÜZQ•k�oŸÒUŠ÷,/°Þéð¥{[LjÍ'7Ö䟿»Å¸®¹®û<·²|qkp�ƒ­uÊR‘óêþ!»Ó’÷­.³Rä|wwŸÝiÉ£ƒ^[æ‡GÖíQ­ùàÚ2‡e‰‚\ FUÅqUóÔâ�ÕþÓÛ÷¹ÔëðÙ«yóØÆ?Ã`\ëÄçwÍæX³^äÜOèeŠ/ßßf¥Èy~u‰q]ó­í=„üêÅ5*mø‹MËð=,Kžê/ðGÛ[ü›½½°~W—6¸vù]&êxNÏ;ãâ ßÄKÎ:Îç³ØÒ,®ch×á¯ô,�J2'g)ͳÊ8FœuÓ ¸À( ‰À XЬ�NÑá…'nò­WÄn]óÅÓ#~wm�ÃQdÞ³Ìj„»ö¥Œ]°ýžÜv9Óþý‹¼¦µ&žÏ:¼°ÜEIÁ¶®ùÁxÄwG§�ñ PëšÃ“COÃ3)$ýn�A¯O·èÒÉ èWNÙÀ�}Ä íÙg1뀻/Ö"-p˜ì¸ AQät‹ÂZ ¸3,sŒ~‰vn@JX†™Ö†²ÖLÊ „`ZמLØ<8á�í}nïò³­CNš.tÀÎóµ¼àùN�y1cоr)V =%qÒï`<,íHÙ° ¹à‚ÑÇq1 ã}ÍìÚñ–>ÀµwK5È}¥B@ac ·Üè//è8:È·u©È¹Öï—B`-жÆÞ»²Èÿpç6÷�ÕÁ»ò/~ï¹àbÅUF“žƒ@=‚Ö¼ÝÎŽ*Ó"‹ƺ¦µËÖ†E Øà¬R[â-qäÝŸF«PÛ6ãÞmM@ž.`El³ˆhXC)*?"….Úëõ”I*æìi/ëžE6 òÐ&Ùó�GØ´žÆ1&¸ôñõG4xµ¶%T@í=Ø`9†gb¹@¤ñï�å$†ùóxš 4àçÑ VLÒö0ö®ßÚØ@³%P•Äh+jÈ„D;…$+,HeÐÄ`%NHápr0?õLz3OG\Xˆ@Wx­XÏ ÷Ìx#ì\oÕà>jLPNòÃ$Nné´œ+ŸZ˜Ð–d”£KdWNÃ1��y¸öª´½#šœ†žà‘–þ6.žŽµ^¶–Z;ZÕ8«©ºôŠ–:E Zcãx>�§µAûF8ÅÞ`À¢E BìïÔ£CX-‚Å/NéÝ[¡€Ò3k ²ÖÉ En ×ÏX(mÌ£rlÛ§�¡Ò5JXmdëvÎÆ|óô L ÿ*’ÀûÓ̓£c„gþ’Â77/g0M=ÏÐ÷ßÓšª„u’”'f¾Ì\ó«KÓ·ð*ãA€l ‘ÃUp0‡oâ]?ü•âpMÅÌF�©RêL &-ŠßÌÿ>§Móø3óçmvñYeøÄ~NϾüÂsÛ`…|çÍx»î¤ ÷_4ææ¼6¸4¨Ë�Aƒ÷æ�GRorÖ"Å,S#Ð^Èà§!Œiºß¢ß|Zex#”m¼ùjôWÝ,Ï$gªi̹Î4.Á€=oœÉ®ëS Ü,B°F‹c çNA�çÖý‚eþ+¤4(áüˆf’N®èäQh€±~¢M]aý2GM"é,‘Œ©0º¦ñÒE*�8b›×Šcu¢(�Ì_; ,ÓXÞXðš„ÒôëCïåh<æåŸÞ¦6†vëÿãc�ñÜ`À…^Þ=à¹å… ÑÿÖñ)ë�"hð¯vrT2Ø«�"Þ8>å‘~7~i÷€a¦ó}ªu°"XïüÊÆ½Lq\UdRò¾Õ%Àº.ÒÀ{\Þ7�OùáÁ¿q¹ �’ Øètè*e݈ øô¥uºR²9ž°9žðÞåE.v;¼s:â»»|t}… ÝcmØOØpVÏ//¢¤ Xº3™òÄâ�'‡lŽ'üåÞ/¬.óø°Ï¨®ù·»\ìvø°"dº X­Ô§Øè()xigŸ ~íÒ4ð§ïÜ£�’Ï8¡Â½Ý1ÇU͸®É³ŒK�ÓZs©×á�Ó1}%ùµKëô•â›Û{•%ŸØ°>ð¿¶µËîdJOI®ö{ìOJGÔ*­æ×ú=.÷»üäð˜½iÉÇ.¬ÙøûGÜ:9噥Þµ8äÎhÌödêb.ôé(ÉÀ 5FUÍ­É„÷­-Si{²þñ;÷¸>ìó™+Ü:9åûû‡t•â3—/0ªkFU B 1W7úl�§¬9_ÛÚe£ÛáCk+RðÕÍ„üÆå (!ø“ÛVÛ~¬kúY—\) d�g¼y|JWIôØèvøó{ÛœÖ5^[a¥“ó¹;÷ц‹á[Ö’À (ë:«Ÿ)^;<æ´Ò<±0`�)Þ>±3™rµßã·¯^äûûG–Up£´=™ü{wR2®kô8.+V:ÿå›oòÝ“¨9|aå*W/>îä„HÎÃögO‘Ö9Éüë,Á@zlÌM>L™¡,áOÌ&Ù={îØöû#V@ðï”�Å%5§DÀúÒ27®\á�;wøÞdLoo—_îB[6s¶«JÄ ²×ú=n�F†mÙŠ«ð7%h_ƪڰŒàã�>Ÿè�Rph4?�Nøîè´áz¬ÀþxtÂñèd¦<«åŸSd¹µÊU9y–‘« ¥¬K:ë¦C9Æ”@H›Îb=&\{�‚^¿C'Ëìæh£ªšZ�زd2�2žLM§ŒËŠqYqx:áàtÌáéäÜø kJq-+x¦ÓåR–<8‚*ÁãÖ¥Sj½Ñ bB¸ éëA¦s߯c·&M‹…4ÎÀbž5¬H.öºÜOâ •UCˆpTVAØäóz—C6xù8´µ�²±÷ŽÊŠ9!¤¿~rxÌ3Ë‹üË�m^9µñ V9ÿ×ï¿�…~‘�×ÌX´èX‡+¹Àöwmb2M`Ò‹@9ã¸Wr‚�@AyDI:+ê×0:Òœ�G)EP¤íœù4sÀ‘ÃËýs-l XWŸð4*̺1òc8uX&¯o˜q öTñÉs.…ĘÚñË- àyžfð_m>�Á.€T²|�ðÂí¹PF`ü·„F6+lXL˜8Ï•† L ¦2V‘ÏXË~%5¹Ö 5Iuão0Ö=¥ÖAÉ\ ç_ßáж.Çìwƒ ŠEÞUK#¨k³1v¨lŒähA¦$#|h<ë{Þ÷ ¢Ž.<ýÝFÄq·CâÞ¤[+l¡-V)¢tŒúp&ÌШë§ñ-­½³v(®Â²ª©ªÏÓRÎ Ë2ê<ãÛÅþr‚¶ ¨�£“­°$o´²{'µÐÉÖ™_ß&��8¿6-±á–—@8!°B’èe�atŽ©KŒ©¨«Šª†ie,¯„da[mÒ1óÛÈïƒdLý¶ô¸�‡^HbE4ñ‡tל}‰·ðãJá·öy<Žç IDãÃ&Ì>œ-s®¢ulÞ\Æò| ò„N}¨«9Rgâo?Oiiçð<ÚÏšcúsVÜ.GÄ53¯O)OÁ˜f;E 4|¦³ê›»Ú¼ÒÝù+±9þ͹œ/ iZAœ…�§ù4’™v”n8¼Ë câ9Ò03´#èŸ{‚pÖ´•Œ£//¶¸9QÍýÙôÇçíÆÇ�äwÂ_y8§I€MÚ8“|Î4 2ŒÀ·ßi/¥8J”™–ínïZkÍãѵ’'pp>i¥Óò!à˜pðK7A‚,ƒ\A®4�…¶^dM�4Ê YŒ@xw?²¶ßÑÄ8¶ŸRÕ©�q–°šIZ£k�ÂTHaÍ«…S«2›9 kî`¢Öq¿úù� … sôw~ù}�&¼~w›±Öüo·ïðû×åF·‹® z W=ž©?Ñš£iɺœT5_ÛÚá7.o„´“)�:×8`™ú]çÿ¤®¹ìÞUÆð��}^XY´Á…�olíq¥× Úþ«EÎiâ/úñaŸëÃ>xëä” �ï^¶mûâ½-–óœ¸`Æ;“iÐÀ…n‡÷./²Ú)8,+2!B»¿¿ˆÀ3øáÁ?=:á3—/ÐU–1žKàWGJ>´¶ÂR‘³5™²3™òÜÊ"BÞ>ñòÞZ[æJ¿ÇÞtÊ�ј~¦X)rðÈ Ï0SLkÍötÊGÖVAËŠoïìóäpÀûW—Ø�Lùîî> yƧ.®c€“º¦t�ªŒá‰á€Í±±N.Ep7ôîåEnûAhãµí—;‹yÆå^—·OFN±J¡$ožpëtÄã >²¾ÂO�Ù�L©´æ“×C¼„LJ&•“§†Œ�%¨ÿäö}®z|æòî�&a¾~ãò¥Ñ9&ketˆ]°7-)¤ä»»û¬t:lt;t¤ä‹w·@>±±†¾|°nœ® úÜqÚé¹’Ü:±”e¬u †™âk[»—Ï®,±˜g|k{�©Ö\ë÷¸±¼ÀõÖ[¼=±ù‚+g}åŠ#.ì¾ çd³ç\OK‰ˆš}æÙݵÑJï™]¡üóÐQ‡;'?\�K¤5ƳNãð¼ø<”aœ¸ÀŸaMñ±g„¶¨b‚K IDAT0÷‰«�°sxÈþñ1ß�òL§Ç³ƒ>»“2hˆÏüS¡4¾;ÎrÉ3‡…{6þ¹zÐeŒ¡® à٬ó ”ÔBp kî–%¯ŽGܪÊú@ˆ70žÎjåŸuYAªsȯ'á]@hMYWLË¿šÀ¤‚ *cCe¼«Óå²ÊH£g¤‹¤lõË]:µƒAw[sãÏJ�ÌøIËzÀ3ê{J…˜4à¶yÎÞtzf^/P®[?RÀ#ý>·’àÂkîüðכǧ�¶{X¤„�“r{4XüGÖWøÞÞ!Wz]¾t|È÷m ó\ þÕ?|ž'.‚6²p4†×^OA"GÐ#« pðˆ´ŒtKÐ6`r;�¢D¤ñ…±q=#ÓfµÈD¬šˆƒáÛåý£7‚|ÚrÂãñIš‘ìiA�p´¦ÑXO$ÞeŠÁ�h¤mÒ̾~å†JØþ7žððô�Às©£’m‚[;¼\È8ž©Oûè\ÄÕ!… $ë•S’fùq"©×—ëÇI$߉~ä+c…•ÆÔã×B ¤©ÀÒiƵ£ö}{¬+w EúÌñ‰„c8›Ô7» W(¼•@´¬p”�±ô†k�e¬ËÄZ@k>AÓr@H/ÔtpÛ $¤Là˜·`‚`Qí}Ý ƒE†ÁºpÒÆPU6v¯6^™Æ»55x»î0/ÎÛºA8ëeç ¨´„}�œ›žn©ƒ@ÅímD<‹}ædB?·Þ+CpnŒ-¬Ëf»çd8W…ðcf@™@˜ »(¬pƒÒ†^O µÄä l`aMMU×ÑÅ©–Ä(Û‚:,eo�.ˆ=O Ç—nez�hæim’#µQK;���ÆWåÛÕFˆZ4÷WÒM—Çò|šL_ÑHÿs3âãý›4ñ'ÿö¼Âgq‡°SÐó šv›ˆ´ú<>L‚pž‡—¦í{o'@䔆OÖƒœT±Ô˜æï¶F{s–˜®Ö4Äsª�'Æ™™Lj• wöyܽUç�‡Ö=Î�}e3¹t˜µp@D&ïÒÃ%íìÌå&69Ó|"¼' F´:ñ$cƒÃfb8g( [›1²5�óÚ;ï23Ÿá\÷mKc+œ™ß瘷-ÏËó ëa6ô¼4ív=Ì•–7ïûÙõ9#M‡t‘`y˜¼r‰7´Ȥ¡vß•ˆpÞüЛw¶Ýb«…³ze!SÀ‘âs3ãKÌk9D�»¸Ó‘ð£1¿Þô°ó¥Ä½2ŸÉ-…‹‰¿}gZ ñæ÷!ƒðˆ&q�yDÖ˜€hšPwÓb hU„ºEÒÎùyÞû¸ocÛƒ0°Ú1É~ ýufÊ&A:Ϩ˵0­"¼ Å€H´ðE*vòmñã‘î騦v loa¬ýÁ@:¾$Ÿ�ž0+p°ÑÍ×<ˆ2ÏB 2å›GY˜‡d=-¶mžxƽñ‡,‰aœŒ×ÖLÌ~�Ÿ[köÚ®BØýžÎÐ\"¾OïðÌÁù€l¸ñ�ÞÅ–í6®ÞÄÖ š'㈆VÛ’q–μXa �NZWh>È¢W²™Ïdçv”Ô6^µs¿ÒiµQ[BÅZrØ:¤Ô©¢Ì¯ ƒP–�®| eá´ªêšZhBTÖJ˪ú€r�ÓŒÀ‡´hKÖø •`�àè$a,Šð÷>õAþðÏ^äöÎ?˜ŒùÏß|“ÿþÑk<=è³î´è_?: šè`}µï$‚�A¦øÔ†u74©5¹’¼ß1æoŸŽÕV,Óî­“¿²±æe¥È)dd%ýê%ë†ç´ªÙŸN¹âêÝžLyiwŸO9-ùÚ~|pL¾,d6�@xW"Ï,-ðÌÒ'UÅ_îòÌÒ�ûà+›;\ì|pmÅ­ ë~Æ_7†}–òœ\J~z|ÂZQðIǘÿÂÝ-™ /ï³3™òø°OG†¹,æ9ûÓ’žRÖ·¦øþÞ!ÇuÍG×WDwCZ[áR¯ÃÖxÊIY—‹EÎ .8ŸÔ{Ó’_ÙXC ë?ÿLJǼ°²Ä³Ë‹¼}2â�㪊K½*cç¾£çÿCkËhcdþù½mž\ðë—7ØOøæöøì#—(µf¿¬À¥®5³Z¼²ÈB‘󡵺™ä w6QRòë—ÖAþôö}jc¸Üë0̲ ¹]Á½Ñ„•NÁ£ƒ—{]¾¶µKYk~åâ:…’|ùÞ6£ºææpÀ³Ë‹|s{�Ú«šB)úy†‚çêgwZòÌÒ�LJî�&|ggŸÇ†ýÀ„»}:F0æ·®^dg< ÄÍqURiØèv©�Õ üÜÝM.u»|xm™Ãªæ/÷‘ÂZ1W5?s.ƒ*cè*I!m¼‘:“ü§o¼Á�[CR*»ò4 Õ;M�ž±Ì\ís"ÄsÒ6¡¤Ž>ÔNãJ>«ÔøÚݳÖkóÛ® ^2bé�sLÒ‘%Ñ,=/ž½y“oüð‡”UÅÿy¸Ç‚�ø%~å¯ôºÜI4¾¯ôºÜOB¿§­†øw&8몌^B°”<=,ìÈHI-àDkvêŠ;Uɽ²d«*9ÑÖ÷a®ª¶Œ�_ÄÕ‚e¥XV×ó‚KYÎ’äA�Dl+^m·?™L#§ifnRaI¡$ÓDXÜÏTÃÅÐ$Áù}^/ðj<^hp¥×åÞ8Z@t”D ¬´¡!+XÈ3Jm‚@b!ÏXÊ3Þ9»¼f&–Å7·÷¸Úïñj5á_mm…çÿóß{šO¾{ÕZQŠèÊÅ:Æ!wBù ©"’ãÕž#’é\?ø^(ý¿:4Kà¨V0ÇÍHãH§tÊ´ÈQ~yø¤-3Ùk™¤ð"EXÎÛ�ÂÄÀkðÌ—„挮‘=O‚H§šX†w�Ôß}º¢J$O{5˜ó–y¬|ý-]š@¿ù KÜ,áÓI¬3ùd R{¨;'¯îÇ! �&¾« ”SÕèªÆTJƒ¨mloÕ/ÁYX˜ÐG�ÆÆÌKJ:+Àd§u.œ¦x䃺>À³!ÖlJyå¥?·2«h=Ýñe‡¯Jo-€ÿôËO (cÛà7Æ;à4ž¾� EX:º6NÈ*¨kápeg à,o�ûó´³§©L˜c{ûí©k«Ðƒ[Ïu 6-Ã[»öÖ2*Ùš±—QêMAÄùv± špŸZhƒÌÑ~�JIôÄá¯(¬ ƒ0¥ ]g¥,È�2ÇPS×’º®)§6Èr%Á ,ÑY·pB»ÂYî,Ú[4.î¸ç, j0B6¬Áš—[³b¾cHÕÚS3LÛ€Z4Ëx(­v�ë88â…b¦®‡;›Ï»RžKØn?—¤Á´>çãƒç—Ù—À/j÷­<Í2góŸY¦ ‰‡˜<.ëÂÑh_³¼¶F{,;¶éŒ¯îŸÑº¥è›®a[öüù»z†OâÇÂóTfÇ×+÷·G@$Œýy#– ÏLq¦j¢ÁP‰ˆu ¾°äܳ«Ï1qŸó:å7›/×’Àœ$~7ñ ›³hšÃÖž{Ë ¤“6ñ£8�®þôìo¤¹å6.3'Áy›þ¬wâ!Ò´Ó¶Óý‰u«‘I�‘†ÚñÈji…ÍÊÇȲÕ5Pf·Ãã†ôu¿„DÔ»aYÙÉojÝAD<™yg—°#1³1}â 4F>5WK—µñ’Œév kÓ/Ns†t.¯H5ÚõC´ ŽMÛÀø=�¡ï 0šw@x†rØë®­óèR2ͲÀï,Á@ПnLBzÑúM£ímésûàóZóéêO�sðwO¢ÉH_M¡@Ò¯3/\Cê3S65!|¶çÝ"ñ`tzð$f»D»5hEW²Òjt ‡˜™Øgí�ä³Îï‘P ó ÷Nh³?F’®ÛaI|?†¹lŠ®¾$a’ý™ %-ðÓí]&„x5F$„0Žñ/Q¢„uÕà…ÞTÚÓJØ``J”ÐHcµ5ÂXJJ2$™PäR‘;ë•n83V[H È [oí4�ªZR•¶±ZªÊ�Wyvæ )­‡7}F‚È ÀÍ­ð–Æ~…[ª"ð÷íƒüáŸ}“̓cöªŠÿýÞ}þÁ#Wx¼kµú¯z „}­S°Ö)0À�ޏ1ÐQ¶gßÞÙçڠ˵A?¤_Êc�ÉGú½ÀèßOX)ržrq^Þ; #e°LØOxíð8¤_.rndR0ÖšBJ~ÓiÅ¿}2⸪BÞóÚá1¿qy#0z´�²ÖV! «¹9È2ŽÊŠãª ®Šî�&|wwŸ¯¯ðH¿ËaYñÊÁ1�ö{<ï¬V; NqXV¼mÙj¨jÃ7v÷¸¹0àãkŒêš¯lîpµßãýÎ5Òq]1©bŒ�Gû= )Y.2~z|ÂzÇúÀÀçïn‘KÁ'7ÖBð¥{ÛœTÝ+®-RXFÙ~Y²Xd<µ8äR¯ËË{Œ«š_½¸N&%_wî†Þ¿¶ÌÕ^—×�N8ª*¶œËœ…L±Ñí°Ö)ØOØ™–|l}%·Nl@àw//ðñ�5Þ<:á�ãSú™âÓ—.pXVTÆBÎqmµ÷o ûœÖšÒþüÞ6W=žYZä`:åÛ;{H!øõË0ÆÆp0ÆPƒÂZ‰Ü×,ä?:}Éöëß8wCO-ylÐçk§ÖeÐie!«EÎá´d£[ðíí=Jcxvi‘A‘ñÒÎ¥6<Òïò¾ÕU¾º¹c-8&ž[^@N¦aÑñ;£1GeÅu·¶§S^Ù?ä]K ¼]—üã[? Ìç<ïpó‘÷Ðí H°㢂Œ™ÃÒ+(Üž‰¦ÏÎ?_üçYDXó}ÐY ­p´š¡)LÔööX;G;¦‘Àž9>û/S9ï}ü/¿þÇZóíñwVèJÉ•~70hÊfÀÙTH�ŽXîÑ_QCþoú2@í˜É` 3®½�ÆÇª1Œ�a¤5c Sc8Õš±®™8Ö5•‰VS7ƹ›�A!…� ¥¤+%=w.v„` ]!\ Ñs‘�s/OØÖI“ÃÜ3ú3!B)fƒ ·›2/V;»‰K¡åÖïö:IËjÇ£x÷ò¯î…¥®¤‡RwCÞ»3ztÐc˹P{ÓTü¯wï†|ÿÙo_ç?þÄUê:±0&Ðé^UÊ»G‰îd„Éd„Õ®—8„ÈíÐZ#¬&„ż¦Vˆ!‡Å‘,ÙºzñUaŸ¼Î¥É\4”:<Òi2{:3ÒV Ý_XŠx'˜z@zí»”çÒ§ZÛÆö_œgKpЍ%Ñ¢¿lpÞ°tŒ[÷597ŽÙª,ÃÙöÕáéÏlÎ�ÿíåã¸öðﻞ(âYd\6ú‡qïk¬û Ò`ÊS¹94Ò RH2µ2dR"…F8í>!�±‰çŒÀ·)¡‹]¿„ô¾úÝ0HëêÈÏAšTÙ<Óוæ�Ñï¦%àÙg±›¼E¯ˆÊRB ´”H-��®°mÁÒ5ÆØ3F»¾Áƒ½åU];×@ÉšÑ4÷R„‡OÿÂ�Q¾Æ $ìÑh7¯•sG%œ�ò´…³JÒÅgp®Ç]â]2Ùei-A´¶{5sÏ2»îŒ÷¦ìÚò2°Tþ.ß9 8¡�Ð¥k:º¦6–†¨k…Ö™Å\ŒAJ!yRj¦•”3B’heÇÝH+8©Ý2­Ý^óûi[À7*Òûs„ˆž·ÐÔŸÐpörgMÃ�PÀmÚI[ŠfNKÛ•#mÀB㟠ì�¹×Ùƒ‘ÀñD’08 ëœâ„wÃu^]ƜۖsóÍÔ×,h&ÅpÝùå¥8iú2-S$z€fmðî࢛çÔû†MÙ¬¢U_Zf’Ð ‡ÒAœ¯Œ3[\#–f#½i¥³Ï��qõŸá¯*óÈt¤0’C.Í£[ï™"ý�<—­eç$$‚i~¦?MóR–63/ý™ dpu5ÎŽ„§< S1‚‘�¤Q^ÚùŸç:o;¶þç)§]ÞÃlûó6W;½9ã¹תw^Ñ~½„L]cj‚ßuc@ MæË:heP~i‡S‰`借ٔHf7˜ù 00" à f´CVÓŠ0†€˜·Ç.: ðŸiU ’áŠÈ4zÚÈnf6{íÄ­‘ÀÚfÆ“’¬µÁ�5V¹Q²IæÄ„CpýáÛ¾õÛw¤]g£®ä]Û÷ší–8CX0ÿÒZÏh­s’uáQVã?S Ý ÅöµÛÝü=£ pF3›C“¬ %2„GÒ]³ N»EG�Y8ä„Õ� Â_’³2Öl‘8”Ê$$�@„ÀÁµ«Ò3Ç1&iŸWNiÃ?¬mÀp§ñDzyø¤„œoo<…âüDÁ€¥Žlû\}.�pûÒ2÷e *|¡–Vv.„½°JîöåË»|d}…¥ÂÂ�Gû=Ê„YôذÏõA�I­ùÑá1O- ƒåÁ—înñè°ÏÓN¨pXV � z¬9…’ÜMX.2~Ùi÷¿´³�"Ä0xiÿ�ûã —®t®]íô”�µ0ÌŸº¸F&oŸRÃ\^¯íÿñ�Õàºf{<áZß UºJñÄ€‹Ý‡eŨ®ùèÚ 5p{4æû»6fÁ»—¸s:â‡ûG\èLøè…U´CÇ Gp�V5Ï-/0qB‘—÷¸Üíð;W/±7-ùÊýYƯ]²V wGj­ÕšE)í<ÃržñÖñ)«�‚_º°JW*¾pw |úò$6ó´ÖôW–xtÐã§ŽkŒÕÒ^êlt;<âb–¿¸FO)^ÜÚ娬x~u‰§—z¼¼wÀQU±3žðä€Úät•b�)ö§%GeÅ +‹TÚpûtÄG'¼gy‘÷­-óºð(!øí«ÙOœõ‚ 4†Ó²b­S0®5ƒÌÆ^¸Pä\éu©´æÅ­]ë.êÊûÓ’7Ž­ÐÀôº\ps\ê %?9ï¨eõàó÷”j¼ë(ëú%µ6ØmÅð¿ %©jØú])æÛIú<=Ü€Wö›qö�0J ÁZ§±/ž^6ÒLK6º^.ÇüÑýûáùøÑKüŸ}ŒªÒÖ ÐX.Æ)Gæžp^z'0u…ã`ŠÆæA<Ø¥âðaiÞ„ÛŸEé( PÎ1á O”ûµåÛã™ÿ¾~¿‘}�S“äó <®Á�…3À¯¹ð¾),iƒ9áž§xd u„cA;\/®„DSï&&�'PMì¼·ðV AÎZÂ!~¾=Þü> È®^ßÐàÉë|SÚáw kc9¯¥Á”Ú *í,ø…Ã-N(”@+C¥™ &ÿ6F˜´ $â[y1ˆe㢦¼BzËNãçY�ˆÖZ›Ð5 ™fV0 ,0.�·°Ãbñðˆ/{ %°ø<ÇΕ <=#©�ë¢Ú8?øÆ¸á²A‚+wû@ ëÀµÓ»âñÂï)]v„„§�|:eû#£5sp�çè(­Ý²‘ã…J"•qt‡@eÒÑ.®2ï¾Öáúh0ÊX¥0F œé²µvç³—OoLá×™_CÎ…Z£t…2Š®±ó¥�‘…<––.-¡­R‹ÂÆ“ÓBa© êD¹Ôà„aëˆtÅ»eäy &Ìk˜Š�±µO7LíË  #ßT´Dýæ¹—h}º6ˆX¾/'IÀl‰QYò�UÍK“à‹ó„­ž]ÅÃ$šƒsýu¯¿nIcÉ� Ö5žIQjW�·Ó8ÔÜïÈ÷iΡ ¹bRü½qÙý"„tí™ßîùø½‰ïRþJò.t¢Ñ®³/õOïæØ,Q’éq‡fá©?.7$ÚŸ­º…Ï‘v0aò ÷Û&Lê5Éüq�×´.¯U BÙ¾¸Dƒ5Higë‹ß@!Õ4"".€çP¥û¹!E ¤y—¯¬5Hg~¨]8§Žyßýÿ÷°¥Çô铹¥·�§—øk¬ñD ¦*bÐ¥¦. u©©«šª´fŒºÖ. ¨ úŠ Þ„ºü*‹ÈŒ@`Žè™³¾¬Öf�·iæ3s›#aÒ´îA•qí¥.NÂ"k‰äMÚ&ï–¥}†„ÏÄEPklÂo‘޳KµÍlo}š„À;ß ¨'.¡ Ѓßç ãþ`pïÕþnšW™0�³ùÒu?czØãи�Ý‚ÄÜéšIn/Ȳ&¤:ñ1Ûâ?c°áYrörˆx`ÝÉøymæòÙužÌ¿I~LNç4“�_—ÂûÆ·u#œEŽ#Rü¾^£EHŒP˜„4Ég¢”nmD˜[“´1ìa$6ÎQŽI‰ Û–†%¸c¤{î}{ú5Ú:­üÚH)?ã\ä(á´Œ¼Æ‘ ˹ ü›g6.@ó–äʦSŽÙŸ)ZiœÛ éb dP¸ÏLj{‹EM¡ � º…¢×Uô»ƒ^F·PtsI‘ re])eã®ø²•„"t;6`qî‚–))B¨u¼e¦JYm-©�Xi¨jîºÆÆ0"Ì]ØZ[í#/`‘Ð+¼±ÎßÙædR1Òš�F¼·ß�y )¹6è#°ŒþLXº‚7ŽO˜Ö†…ö– k.²1ÖeеA�‹Ý»ÎÝÐå~�¥"ç´ªyq{%Dp�´7-égŠU÷{­cýÊà�ã6º®û!øüÝMNk͵A�LJ~¸ÄÖxÂM' (¤¤Ÿ).õºlŽ'ô³Œ§—X*r¾µ³Ï½ÑˆçW–èeŠ»»ÏëǧÜX� Á~Yr<á‘~—ŽRô2EGInÜ�ÙšLøàÚ ×–¹þ½½.÷º\é÷xçdÄëG' —{]¤ìN¦\îuÉ„`{Ròô€kÃ>‡eÅ×7w¸ÜïòìÊ·OÇü`ÿ�“ªæéÅ!5Æ–…áñဩÖt¤"“’µnÁkGÇ\éw¹9Ðͱ¹ÃæhÌ'.®ÓÏ2¾±½ÇqUqµßc1ÏØšL8­jž\ro¾±Ne ·NFhcxl8@`ƒÖŽëšÕNÁ­“7øÃíMþŸ½½°ÂÖ¸yí=d*K΢æÕ ´’˜&É=‡ØˆÇ] -Ͽγ˜W{J 7ÌåÃïv»ÎÃPEënVe Á÷³6Þ­Ÿ gó Û£Öš£Ó¶ë-×2k1sµ×å aô�ªº¡q®� ŒäLˆ†•j!eC‹ýß_¿ØK`©`ÀëØù«Oá¼Ùè*ÕHßÎ[žµë½Øí4â NÆ·¥2†Ó–bì¬VŠœ©Žðz§`�gѺÀ1¤R·A[c+`ðÁ苌¯OF ÷AçÃü·¿{Ã2=Ž"!Dðt²ÃßHp4‡P™„A-\[á̲MmÀ3Œ�T©…ÍÎöSÔÆùò7‘§m„ ì>µˆnm4#“'Ä�1�£) ·Ó¦ö¿]½–«kß›ä{°rðõ%uÛöû>h,?fÁÏ�§‘=éï`Ú2_}TUÑè�ˆ wøÌÛ)õ lß] ã†+ ^ˆÐ°¨�¸~›ZÄçaMàz›J;kƒ®Œ¥Ûµps¯l›µD×]ÙØ;¥#„µŽUÒi­Ë„Žp€ P± w)Re ÇÅ�©‰tCÛk ã�r]j­�U2ÖûéJψpÈù6ˆ¨ÐdÆH´±µTZPj(Kô2L*ô4L+@wRjÆ¥ýœ”Ú¾¯ emcxÙJ¥%µ‘ÔZÙïZRiéâXÅ�ºÝWDÐRš¡Ù’½Š77vBZwHRY�’ÊÝn.„]#Â$ù²ýù,%B%··:P™YKäh Áï³0]�q±ÑÀZ‘¸´Jºuë™íÆØtB�eŠ,ËP*C)ãPàñ ‚uH ¡=?/òã"oʺ€’MV›Ç’²�,fq”ÀðÙÛ|Òfú�G8ØØæÃÐü:¯î´ž?šŸ¶]þøQÒ×´o3gEø–Œöœ¶Îž—] IDAT^Æ¥›sêÎ<:¿k”}Sßó>æ×kpë­Á÷=«8Ÿ6ŧçfr5xÐþ·ç;êVÒVgàéiËÛóßödÑ,Ó$ßÎ/;îw®Ï}ooõOïæÄ-åR,f+²–ˆÂ`¦Lòæø�”Ô‘lTÑ*ˆ¨íß„„QÀ7·±aÃ#„‰¹˜ˆn æ.¿Â\e­$‘hJ~'@)áÉÍ«6@˜ iÏ{ÿ ë¼<ó�ăÒ?¼` ˜ ‹€ð¦4PY�€.5õTS—šjª©ÊŠº²¦yºÖÔÞ% Î]…µùÉqყB²�ýaØ~µ7)!ß¼+.ÁÆ‘ô€´ž`� ø¸dýú÷cæµ³bÒ¹ŠíM築ä7ÞÏmZzPµÓ4]*Årg�YÀ?Û rô츦5¤@ü� …ØÿôÐK¿†¯iέÏÁEœµˆd˜Æ0†&y'ÌdÚ}n4Æè†æ}:ïÍôÙ‰s š˜ƒ$Чm —›K0�ñîÇ^„@Ri�V0`Ûï‘P©,Ò.¼z�ˆ`Ñ–RHV( ÂĈ€œ7!4ñœqN@d>ûï³1DòÌ2¬í­ƒÏT@˜t κ÷1ê,2%PJ„àÀ60°ýÌsaÝù(‰òqügf¿[×@µ�‰âJ2Ǽ·ÚÿÖ “AÇ  ec¨äRÓÉ%ÝLÐïå z9Ã~‡a¿C¯“Ñ)¬K¡Ì l\ÖÝ�¤SHŠÜ ²„X«µ¶>Qݼ¡€3ß®�™ xÁ@¸1wf͸µ6²”v »Š?±Î÷~¶Ãɤb·®xñø˜÷ lžŒYïvúÖÎ>˹Õü«=ÔÉ$ÇlY.r.¹æY |us)`1·Œ½Û§#¶§S.9!B.%«EÁb‘s\Ut„àú°OGI^Ù?â ¬¸Ò· ðŸóêáQ`ÔO´æ°,¹ää…”<Òï±Þé°7™²;-ybaÀj§àí“_ÙÚåÑA�a–qX–|oNÎbn™9§UÍ¥^‡\Jö§SÞµ8äê ÇÞ´äÛÛû\éw¹ÚïqXU¼¸µG­ WœµÀÇ'()¹ê~/ä yÆ0Ïxíð˜�n‡÷,/"…äÿ½»ÅædÊ +KJòÍí=ky0è‘KÉQY¡� ½;�²Ô)XÉs®{|ggŸûã »°ÊZ§àë[»Ü:qÁ¹º}:b{2e­S°Ü)Ȥ ¬57†}¶'Sö§VcÿÆÂ€ïíò½½C.v;¼{i�×�NxûdDe 7L´æÖɈAž±Þ)¬k çZʯ‹ëƒ>ï[]âÞhÂö�8©kÞ·ºÄ¨Ö¼qt‚Zw‰çúÃôô>=Ê0˜æ£«‰xæš¿ œŽGŒ§nW%‹J±¡² è(ëzÁ³v¥€�^‹Üb,ÿ{¡Àßü¥[cìIp'Æ_Jòjæe»¦™¢L|Þ-æY`ìÃl°áÊ8 {!Xȳ†k£Çý` àÛV'L®ÓºB¯8ï…� û–eH{¹×å‘A�?>>ä_ïì„2ÿ“�_æ¿þ�ÇÜ^Žôµð�NÝú÷îF‚ærBRxf¶Ö‚T( \€PáæµKï˜Ú–^wyæzP³®udÐ[ä-j”kÇìvö>°tLtމ®�Ë�:ÖѤuûïsn/@H©@À#°!³§„…�»%’7a’´Bã…Aûã}«3W8àiOOÛ1a^• *o‰àoCPhм±h]/·.<Í„TÊ]+V¹KyáŒçå8âØÃ‰Ààv‚©2sB�LÚùËÜw÷éhÏàÚË.>�µz–ÆÒTB Tf J©7I ¤"“V(�©Ü)0¹-dŒ¥©�îë„×ø?wIv§gv^ÿ:WC�™OŠÏ…û'yRfû<&zht’¡ÿ>Oû|:‹!Ÿ–›ŽÂúå• ý™ÑúŸÖ>¿g4á¬k†gÕlOûûl{gåjK*Ä9Ñm—iþAی̦:ù öNÇng�xsk…á…Bíþ6r7xh¦Õ­óqòXVãäšó²ô•ðo¬ËyÃBá$¸¹ípI"ïË&œ_ !üaFØ6Òg0±Í>'¡k_{®�ßl­=~íô¾Ï aâTW¾ÂB¤ƒn\È—F¾_‚9ƒÙúÝ^¬â"Åîæ=Ÿ_öYoýÈ‹ÖÓö︚sûì>DªçßÔ¶ö¾ú€›f)4Ê™Êd“ Ä*ÕF¸¨6HmÝ—xøÁ2À5=E8ÚÏϾân̤ðeµ5Á£'ÏØwÑôóëÕèƒ4p~Í ¼™©·ÑžÄ®­ LÒ_�™òB�”ijÎÎÙp§3“×§·È×Ì5ÀYMæÙ~¥í‚à*@$ëǯ¡™~%Â,$UQëЇ¤ù&ìì3ç$츖�À›…z_ì¾ìˆì6Û›·­¯y�ái„R!C‚Ø%"ÛÏ~�À0ÐH$ãÀDÓ'mcÊØIyÆ3ô�÷ÅibBc`,Ofz!D#à|Òàt\š±bbOCš°ß¼P‡I³ÇŠHä‰/ BW³5/6ÑìXà\­$ίªi75.„qAƒ¥s$InA&½pÁY(§Ób¬‰¸0ÒZ(èv3z�Œ®(Et³¬A<ºáª®|‰så4ýµ ‚ï{µ6VÛª2†ÊHJGøLKMY¹»4”•�ã]Â-±}õǼ÷k*$¬.tùÇ¿ûAþùÿý¶FìU¿ÿÖ[ü7—¯4 ŠwË3ÑšI­Yrþî·'S~tpÄÇ�OüRk^?:a£× yßµ8`¥S �a¢5O:w@'UÍO�yÏÒ{´�¯Þßá©Å!7㿓Ɇ «w-ylØGÃÝјõN‡®­`ŒáK÷¶¸Ü놸?;±7-yĹ7Z(2ôè+ŤÖ,9¿zq�~žñý}pöyç2è[;ûÜ�ùõËè)ÅöxÊÄèàöb1Ëxvy‘  ¸ÔšO\XEÁ«G¼u|ʯ]¾ÀòÿÇÞ›ÆX’]gbß¹o/÷¬ÊÚ{cw“b“l.") Å�iÆ3°axÆÀðØÀxÆÆÀ†-4öü’Æ¿üg€�Ç A%J)’â6lnÝìfw³»ªkˬÜ_æÛ"îñ�sν7â½Ì*jóŸŽBÔË÷"âÆ]Ï=ëwš ÜMðêñ Z™ÃR#GN@¯‘cµÙ¦²Ä‡51ñÑ´Àw�ñìrO/õqo4Á·w°Ñnâ£k—%ö¦3…’ãÉAñòÑÚm\ê¶Ñr_¼sMçð©­Mxf|óÎ6˜Û- YØÚY†£Y�«½62’�ߨÙøìÖ&šŽð‡ww0öϯ­àj·�ïí`¬ ޝvÛXnäh),ÏÍÓN‹\_A/Ïñƒ}�oz÷òï[]�LãÒã#«¸7š¡[`bÄ P°ä!øêö.žôÑÎ3ìM¦xaÿ~õÊEìŒ'8˜Î=éd™x+Ó�Žpµ×Á¨,ÑË2|ñî2"üÊÖà_ÑäÂ\_ÁV§`”g®w�Û(ñ¿¼y3(�ËpõòSXYÚ´î<–0„†[‘}ä àÊwVH}z-FÝÍß;÷jï·Í–uãX�«ßMõjeG! ¨`{Bì«Ç._ÇäÍWq:á‹'ÇXv®iä@Ë9”Ä(Taë¸?ŠÐ.dMÃQE‰üöñ—Ô!ƒ òÉŽi­ÿK]Û‹Ž:ÜP+s(}Œ`Ì+þ�tó £"¦kîå1—€A~¤ÇµdÃVv+säU¸¡Ç=¼v|¾ß:UÊËá_îîà+‡‡á·_ÿôuüg¿,ÆM®jQ�ŠºÌA”á�ßCbÏÀd ïÊ€(ÿ|tØ ëÊ–=QTž3À0šx‹¾›ãïŽnšP˜"&b`9)~*›`82ÀŒ “䤋…ºÀÀˆ oªËIœÈ[JŸŒNQz»Î²vÅ{8…”ñÉ; °=}§'¤Ñ•ö³‰°*+†ù²ç3:1AacP5ÖX½L‹ž¸«séÁ¥†)W¬%ìË`Ì0�9ïA#f ¢J‡Ôª—Ì‹s+Ç£*`רkZ7Š›edÊ8ïVoÛ4R‹å"¢É 3" Ž  î7�@ý»Í�Ð[z!Ä�ð|=âFjÆ¥tW öÌÙí@¥¬úüä/Ìcñp »•¢56È*õ³Þ)SRY@ò kï¦<‹ìµwbX0é‹õ®·yl¡¨YH Úî}¨ì…Ȧj,�áa^qe³÷dÑ[æmB•ü3i÷9nAÿÔ)(§ï ½ÃáÞÅjVøÀËéÔ8 b8¤Y‚OJâ/õ{r©ÁR•ä°Dg^ŒÁ@hæïÓÌÍ0d”Á‘‡C.ùT (WØ …ŠL>  ƪd¯¹0¢qà�(Ø|û,� PmÓ¢À´$L=I˜t©!Ó3`2õO½ G¯=¢Jq&ƒe˜¦.sÈs§‰ ��¥.¾ð÷>Šöo¾�[Äãû wnã72‡58l4ØÐh€“)ަ3,©ò}­Õ Š~@”CŸÜ…éýÑᢠ^=>Áýñ$rÒù­“ÆðÉ­ dŠ>õŒ'ûb ¸?žà¥ÃcüÊÅ t² ‡ÓþíÞ!~q}UÊ'ÂÅv›­@á½$.sÿÕã!žì÷ðî•%œ%þøþ<=èái­ûþt†^Ù¬÷¬ p·ÕDÓ9Ü<a£ÕÄç/]@ÁŒ/ÝÛÁz«‰÷­ŠáÏìI¤Á•62�î�%ÇÀf«‰WŽ†ØŸNq<+4oŽk½®v:Ø�L1,J|jk99¼tpŒ×ONñ‘�UÜèuðêñ ^9â =Ç7V1*=J$^¹£²Ä{W–0*KŒÊ?>”È‹ç×–qw4ÆŸÜß9 ŽfX"^ÝV[MÍöç•£!.u;Xo·ÐËr|ñÎ6Í>wùF¥ÇÞÝ|dcK�ÁûºË)vüJ³�»§#%žZê ¼1<ÅÝÑïбýæƒ}<˜L‘;‡_½|o OÁª�,K�’½<‡g�¨zõh�õ»`f¬·[øí{÷ð'^¿­f7®=‹v«‹”è2U…Îó<�Âñ0–tÁñèÐ@?/™ÊµÍÊ¢÷Î]êümu?Žb“”$wÇ:†6±q&IÑpxâÊcxùÍW1+fø¿Žñ/¯b݉!ËŽzrá¥F^¹þ¶Mà¯þ¨{÷§F Ž3ÅtΠŒk?iYuD}¬ëGÝ€À@H0¼Ùj†dÁ€@žq¬×§¥Ç¾¯&¹6£À Ï1.Ë�èy£ÝÄ“ƒ>þç;·ñíáPÚJÀ?úÕ'ð÷>¼…Â{8ÜÿŒ¦¤P¥¿¼2Df �µ�W¨ç°òŽàˆá�ùz«ú‹\Pj„¥è¡[¤2 †¹Éh*—Á1('a°Jý¬Ëç�éO¹(h�i¤7•E`cx©Ñ­¨C�7 ï HÊO¢Fæ„—®3õYÖ~'Hý¢"Q…S}gä{«|=@¢4ò%B‚”AÉßrúø=‘…Œ 2¢Bß’!ÛiÑiÔ‹¬$ì£òôÞƒÌ0à¥ýš¡é2q‚¡ô 8&/Š\bÉh²›S8KuH�Ê`á—©EyŒŒÂS|iÉTz4P©†FOÁhP�ÿñ¤ÑÕÕ¨iƒ}ã@2¾@à}28&q&‚¦ä°è–>4žŸ‰�ž‚š.�ÆR�;ºÖÅxäv`ÇÈIÖ·³ÉO8‘˜L®†D»¤sØÖœ­¿š�€¢}h²Lã!&.¹§£ŽE^ǬÙÚMÂhBO�ì´@Yð¾2E‚(£äÉ¥ÊZ©fÀH��²1Á"Ö�wˆ #5NÈ¡ãSUð2Q£¦À�|sÕ¸Py¦ö=…$Hº yÞŒé�>�ä¾´Žõ¾ˆ}i¥ôGª‰M³¹aL¨þM0>CXoâµ’|Û]G™(ï wVI®·õ ׃!˜�¬N�Y·ªË3Áè�‹"!–µiÍ«[TñÂIŸ[ÝÂý@ˆ�w‘2»¦P¯óæç`ˆ4WòdÎÃ9G¥(ñõÌ�ÜgQ�ŒƒÇžäh6Ú ÉÐn:´­¡Õ É Ðpz-G«‘ P.ÑÑ0‘$.&ýÍEï}› ÉL žBOfƳ“i�ñ¬ÀdVÊ÷Y‰ñ´ÄtVbª¡ÑSÅN•èñšâD‡`ûª¦'X¥Ì!odh42í î·[øøs×ñâ­]ì�P2ãËGGø…nO+ö? J˜Ív 3ïqût„åf}U¨éÞÖ›Í7t{4F3Ë0hÈõ¥fWÿ`:C¯‘ˆ ö1*=6Û-dDxñð÷Fc\뉷¿áÓnª�¢�ex¬ßÅr³�{£ Žf3<9è¡›gøÁþ¾¿ˆ'=4œÃÞtŠ—7¿“eÈILfW»ŒJ�‰÷xz©�Ë�6~6<Åwwp¥ÛÁ…v {“¾³{€Ü9l´š`wGc¬µšXm5Qx�Ë�6ZM8rxùhˆkÝžYêãdVà�ï=á±¾äjøæƒ} ‹2@!ͼ)—;mÜOp©ÝÂãý–9¾|ÿf%>°¶‚nžá«;»¸s:Ƶ^Ý<Ã[§c®v;È¡ßÈ‘áñ~ožŒð`2Á‡ÖWñX¿‹¯nïâå£!ž\êãj·ƒ—�Npo4F3s¸Øn¡`àîé›í–æC(p­ÛÁãý.nžŒð­Ý<³4À{V—ðæÉ)^9b\”xne dz·NGȉp­×ÁÄ{L=c¥ÙQ �õ{xjÐCî¾¾³‡½ÉŸÔ(†áhVàÙå>:y†×5áóå^&3m°ÑnãÏìc:ÃÇ·6°Õnãk;{Ø›Lq­×ÅSƒ~ppÏ@+˰Ôl€ÙãxVâz·�Û£1N‹W{ÜèwñÂÞ!Þ<áñ~ÚXÅ {‡ f\ôð…[7ñ•££@—kxâÆ/ ÑˆÑ0鎰è¨;aëP>#åÒ=¯µ•V–iŽ×ˆÏ=ú‘òÉé�çqSUÞ2Ö·^�Ô<^¯Ve�@ÜŸí"‡~·‡ƒãC”ìñâtŒ‹�V,1&?>Å{Oabêï¬CÚ¼}üåõ¼‹Ž³lU:Mç�;ªŒWÓ¹Jùõ±6ƒƒæ ƒêy&¾šúx\zIvIVœÂ ½gu÷“dÃ+ CV0£™9\_êá7nÝÂ�N%ú s„ÿîï<ƒ¿û�KÑs:È¿Ê÷颓üWQmf‘Ù¥×Ä©…žÏ¦le…:ñð¥Fw—Æw‰·wz�|Mrz„ß�5#ÍG°õÙxÃÃ�°B”@‘(`+P@\Í/P(¸�cÔ¦l� p}#Ô‡@�}ŒŠxû”3UTðü³Œ:’ðZR[ñO!ƒôï¹È“Û’{B´(\†|(EêrAØß Ï]¯–åX¡œs< äp±ýäà) ‘ðn@„ö¬xÖ'�Ÿìž2(ø-O[ìJ�®`…ÃJïó6.¦  ,ümð˜&oh!Ò\C(P]AéMÑO(J`V²FγB rZÞ… Ò¿KOú¼$Í-ÙÁ{’|IÞ‚ð·Oú€£á"*�(ØÑ­#d8ã-²’�¯·ý�ÄãJ‰Ä¶9 [wq69¥rF½‡ˆhbª�¨E ˜�PjoÆ¿rH�‰ôíŽ2�f!È\ç$¯€È¦ k 91åk@a¡º s̲®ïȆ<‘‘âß÷!¹Vý[dE˵yªŠ®B˱1 z— ç4((JÞOÕòBM‡Zè’7¥_ã³v�æî�´c‚ÇxŸêç£8†œ©´¯T3¡vÖt­ÖŽ´½6ÞDóýPY#õC/ÖkyËús©–æ,Þs¾?âü™�`˜»_×HlFÄjHËsF«*ã³°� êR?“uNé½é·{¿3ý-$¶nªT$UZÎ�ú2Gº§¥ ‰± ¾`ª ždÅ˵kñDú·^OªUë9]í3­7¸25*E ìPxZ >P‘ÀÔ £Ú]‹>ÿü‡wwÐÈÖ›‚sÿãCÉC`�AK�ÍÌaµÕÄÞdŠ•fO/õÑÍ3|g÷âÄÓK}4œÃwv÷qët„Ç52¡ð»Ó)®tÚÈ¡›gXn6q¥×Á­“†E�çG+pû IDATV—±Öjâ…½¼°„']¬4›¸7žàåÃ!ÖZM TI0+¤ÞŽfžôñÄ ‹·NÇøöÂüöé?Ü?ÂŒ9(×_;>Á ‘ár·ƒ‚—a¹ÙÀr#Ç+ÇC<Öë♥¾ôçý]Í <¿¶‚Œ$gÁát†w,‰2þÞh p£×ÁöxŠ‹�6–9.¶2hê=>va[í¾|ÿî�'¸Öë`³ÝÂ+Ç'8-$Yt'Ë�0œ•xlÐÅöxŠ“¢À;þé«Û»øéÑ ž]à©A?:8Âöx‚±BHͼÇ[§’³`¥ÑÀ”­Ìa£ÝÂÎdŠï<ØÇ3ËüÂÊ÷Güôhˆál†�]ØÀál†»£1JOöz˜1cg2AN:-¼>< u&"|oï'…ǧ/_@á=~r4ÄqQà‰~OÚu$s|½Ý¸ôb4ʳF†òæ¸5�*Å'l]¸�«—Ÿ!aᎰxO ÷¤¹—*Ï,æõª{ËùÂàü^d?\ˆœ'Uù’PÍí¿ó÷ÕËC­Œ¸÷TDêF" *#d]™¹ƒîÃÌxm:Á»Z´´ÝfXi40Iú¿árª*–ß6 üÕ3 ¤G³f¤Ék „Á YùÝZŽƒ· ÷“å8Š÷˜QÀö,3ôò ƒF#�T H’úÔˆ°�DXY3:Y† ƒ.þÛ›7qGiF3wøÂ¿ûN|ò�›ei…ïs‚íã}5׆)GMN* ¯ŽT”äp¢ ð/5Ï�/èI&ù½�çg³EáQª�8(ÍIä;rpš�Šà¯ŠnucÃÃ÷HŒª”ö@�CfHHŒi^”¬ oŠøþš[€‚Ì<»ƒÌ*Jü9…ºAÄ0&¥Œm¤`ø@ �A®eËÇ% ì9À*+²&QrO݈@f‘‰0@c€Ö%´ÏÚÇvÆJ%‰„eK,c�ÒO”È…*ÿ ØûØý…×Þsä"ÛóTtW&ý[¡Y=ʰï™a:_IW^F’ ‡)¥VÊ F€œ’O§F�T!`#ƒ„%°E JnÛd½ ‹È¢²ºTŽPž äA ¨aÓ©N͘òž™"¦UfÖ�?åNxNšª\W£ƒ.=G&»¤Êý ‰Ö¶§º�´¾–Ë…`y¢Âï.ùn%…±Oy“ïºÔ¤m¿´˜�Z¤Ü>ëX¤$_øšð@Ä`ñ�ùòç<»¸XõE6•õGÑeÕy�úª|Öê˜(®ÎÓ¹Ä*ÒÂïDiäIJüÏï[ tö<}Ïâ:<ʘÅgÂ_áLÿ-*@Í0�ŽKªÄOᄒɬzµ¿ I§‡{t°“ß+'L¤Ds¤—UBb›©zºj]ä¾óŒ1-Éß6؈2%ZIA‹~Hþ¢—R’vÞQŸg}?oâ<ʤªÒ_cƒmš�¶$m¡yX˜g…îÆ’2%Œ¢%ËeYžiòL¨£‚Q 9 oxØÆèzaP-_A�a0ßÍgiÆ+“s~L)ñtNû(@i!m[\ˆs#�̲ú¤{cJ–Î=JvEÃÔ³µçÒõW¥Þ »bQ�*ÏÔ×dRkÝCÉõÂn€Õë\Ù„“M‚…aB EUS¶/:8©c 7ÆœA tõCA¬MZï¹Æ�™ü~v™?¯!ÖQ?IØ,c’M”òu¼g´ÒXƒÊ†¬Q8¦L }’l( 6iÝ™$GTõºHn›ë_VÅMªô¿Ç{Àq®ÛuQžû@¿£aÀðvD^=î}Í(…ó)%*À¢ÈB„€D dfPP�øÜYt€(û[1àÄ8ÐÌÅ Æ ÷Yt‚,÷‚Ñ™!ñÓv­jDE4n…(A±T!D¦yŒ'¥ÆbÍJŒ¦…D ’x¸d‡Y1 ”Œ²a�Qõ~qŽ�9I.ÖÈ35 HÄ@–;5nP˜{Žš�Ÿxï㸽{Œ7·âå{''Ø+ üÚÆ:Ú™3£á®t;pDx}xaµÙxépˆ�É$$.¼(úÖ4amÃ9<Öï¢—çØŸÎ0.K\ê´ÑË3¼y2Âw÷ðD¿'Šõé /q±Ý’d£Dh8ÂF«…ŒRâz¿‹«Ý¦3¼xpŒ«=ñàߟLñõ�=´³,¼ûÖéý<ß×ZMl¶ZpDxãD O z˜²Çß{€™g<>oÿ¯ïìá¤,ñ˜&Ò�y�œ—»œ”%Ö¹´ÙjâûG˜yÆs+K4r|ãÁÞ89Å»—h8‡;š øJ§ƒn.˜øŽ€Çû]Ü>ã¤(ñÁõU\évð­Ý}|ï0xû¿6<ÁëÃS8"\î¶QxÆÝñëÍ&–›9NË+Í®÷º~°¤Êö%ülxŠ¡dÆ»–(Øã§Ç'—%žôP˜xñ€½Ðjáµá nô»¸Öí á_ÝÙÃñ¬ÀÇ.®#'‡oíîco:Ã3ƒ>:Y†W‡'`�õ:–¥äTp×{müðà'E�ç×–q¥ÛÁŸlïâ­“ž[YÂÕn?:8ÂÔ3ú�[�6¦ÌØOq¥ÛÁát`³Ý“ƒ¾·w€Wއx×òϯ­àûû‡ØO0ñï]]ÆÎx‚ýé ™#¬·š(™qZ–èå9˜Å˜ôø ‹ý.öÆS¼z<Äf»‰¯ŒOñ¿Ý»”ËY–ãÆµg±¾zñLzÿ0N-òÉ”îPñúÙÂÏٛЙb¤ î �Vϳëö{Ò}ù¼g«EÄ/q‚ª{‰E6›-ô;}ìï£dÆ&²–/$‘uE²_ X~ûøÿïhÖ’ ×Ç&Uâ7jF‚^žW „‰’»(ŒAâ}o29K¤jÉ ÅCj@IÀ�»•ùå#T"gDú�ƒâFG`gÉ„#­lN+�¶¹^rbȰzeIRçÔ�œ–4ØŒ… I…=œ:*&T 1Z ŠÐ©Js%Gù²v£À„y¬¯Ná›”–°‹s"·:; !Z Šrº`2rŒb“¢0õ¬Ö¤]Ùr­ã'_ö6Z¢uYxIAaE¢ÿŽ{¹V“!Ž×L”Eã¬}6g˜}TRTª�„ñDr†H"E¨'1 ¤ëÒž§u�(C§F�Ôó=}w(#åÇñ?•~HÊBú=Þ?ŠŸ‹=Ë«<Ûϧd®=—¨æ�1SýFä3Ïå“ÓTa«N¶y]ŒßUzI±g Dzd{S½Æ£µ{Q?T 3tþsÑ�¤ã÷ÕBÐÝY›lToŒã_©×üù0£�æø‹ M&Iá{¥Za®µ†YQÛ=G"ÉÑÇ;-ñ:çFB {J¯�Ç̧³Ù8 Eqj’òe“#Á%)ϪõL¯-šgÕ�j÷<ú‚þ«?Ò>³ö³R]¶¤Z£‘(‘”$G²!±0�NOÖ�¶ðT:xÞoæ�,eiü*s½Î7'+µ™EiÍøێT½ŽúSÊ:8˜�CôoF Zs‹ž#CP/›*sDž5‰Ê̦J̓"5�vå0# §dŠ ³0H6e“”OD±-É‹)Ô-!ôsmK¿Úšö�PXÁ<œëÑ9…EÚ‰ò?©LTfÛ}g­íëÄ »Xñ™­Ôs1lèVLJ,½EÐDõȆE÷,RÚp`ÍD’�Ó &(0ïóªp:¾,x’N˜¡¨c�sÂ\<¢Q yß‚O!ó ƒ§t?¶‡ç>RX¥P†Ö…ºf9”•8‚»g0q¶âÔ7ÇZ>ãh¹¬Æ(Û}„RËQa’Eè3ƒ‚$(¦$1«r\òäääÕ"÷Š€áP‚ØÃ!SüT3(º]9æ„Ùâàig€)çm^˜ÐD¼2 ÁB•œŒÉÌc2è É´TC*o.F&'›g•2Z*Ž,ƒA¥D ‰! ËÇ-­£÷@(  ‘gøoþý�bmÐÆÿó�—_:<ÄÝÙ ÿÓ�øîö>²¹†%…"PÅKô™å>2ˆ°·=žàB»rüéöÞ¹ÜǺ*æožŒP0ãkòýb»‰Ò«â�k­&>{i€`;/©Â¾»wˆÝñŸ»|0œ8šðÌÈH ¿¸¾‚�v {“)<€o¬,úŸŸà7ÐÏs¼1<ÅK‡Çèå.uÚèæ9.w;è72xˆGòÇ·6Ðp;“)Þžâ¹Õ%\ïuqçt„ïîâé¥>žYê£dƽѧE4"¼ky€Qé1eÆ­á)ôðÌòã²ÄïÞ¾��vZ_Ÿ,ñ£ƒ£ -rheZŽpR¸ÑïŠâ¾ÝÂ÷öÐÉs|þ’ôÁïncRz|bkƒ<Ç7zçp:Ãz«‰K�6ö¦3l¶š¸yrŠ3>¶¹†Ì¾ý`Û“)>¬ù¾³»�»£ JÞ»º„Û£±ô­#LK�©/DÒÞt†ïá×WÐÉs¼~|‚W�O°Þjâ—6×p{4Æ…áxÇR�Ì¡—e˜x�€—�ñŽA“Ò£×Èñûwî£�eø[—/`o:Ã×wöŸÚ’§ª„+XÞ}±Ý¨(q±Ó·w÷–dÂÍÌákÛ»`ï[]Ƶ^¿{g…÷ØŸÌðd¿‡£é 7–úø§÷ïâõñ8Ìã~wׯ>Uƒ:�/�ë¾zT7£êîaGJƒÿ|‚¢ æÉ£äQõžª¿«zؽ‹ÞWÝ'^+ãaáðA 4Zª{"1Ðëðø•'ð³Û¯cÆŒ/ �pqi2¡E†÷Þ B'¯æ!¨'´}ûøë?,²£ž'À £A "褨æ(“±nd®¢ø_Óh1;Œ«I©5QqF„væ*‘OÖ’ ›|`óö­S¡W»mü¤œá_ܺÖòã›}üÆ¿÷n\Xƒ­s„̼ná…'À¨–’Û× ¡Šb”Ñ“)�Eá`fPå�™Y \³è`!ü"3'eg™2ïà²È'¡~“ê–y‘–:²”ôdì�I9á�­S,â×+Ÿ¤u]fúEÊ#*PbL¨ëN™¬¤D‘�„ 7Å:b-2U¢Xd{¯9þfDÉêiü7Q ?Q« £”Ì|¬Q²$c@ ±BNeÕ­�A:1Bä”/f_†{Go}£ŠaÊ¢LÆ­ÚéUÑ^–^œKJFYUâµï ³ß+Š‘æ2c«›òÁŠƒÏDʧr¦]æ_ŒWއTÓK3Œèk•Ms®Q=(*÷¡ v \P‡•£I2‹AeôøöÄà$kaþ8–Ã6•  yÁ;œt³&ßõàš²ŸàL$Bæ àL ÖÆ¡ŒœÚÕ%yáemÄ�ÎÓt.zã“ê ÂÜ s,Y‹\�#’3ÒÑCfÓ�Ê./á\ ç4›hU È n}œŠäàJFÁKŸ{v˜ÍlßU×q˜,ºH•]/g±(H½úÁ•õkwÄG©Òü oàäçšnczV{Ϫ«éÌÎkŸ~jýq–Ó Û˜R}äT·hô0NÄ]² _4g¸IK¬TO¾äÕ›ëGm#N'`úRmƒCåì…f›�6 }ƒmî•®NˆŽ5°Þñá[ºaU®ÆÉ$?qýÉÚlá…׬³©ÖîúóçŠ1É&Pՙš¬ÍÜ䨿—j§Ï�Qƒ3Ë^tkTRZf:µÊšåßÈ¢I’}Ò%8#¸œÀ9�Kª„t’†ˆA=KœWÀc”ò¾Œ—‰b !™±WGqÕ[Æ“ëýlm<³ŸcWRõk ðd?&D¦º,íA®O̘ߺ6&©ËúÑ.°2©fñŒ2³&Z�ó�ŒQ$eÎûÁªìÓji—…V�‘#*á¿jê>DPâš4œ“/lVâ‰Ì÷˹ ]˜¬_k¶N:ª‹ô6^é=æ‰Áé(…a€Ö¡xXÐQYN¾'† Ì�n^Ò3V4-/̇ºõ´Þ#�¾RåŒwD¢˜5“ùNæ‘dôW[êgå§sj~*(™7ö[RÇÊør˜÷6Q‰�PgÇl¦ b(ÎASf«RJKæ{�žÔ°Ì^¯I±àCH­xÎ8 % ×è 7”)™) ‘xÁÇ5%IŠÕ8à€œX`†TiŸ;ƒ" qzºðÎ`°ñP£³œ¦¬ò^èZ: ‚™¹,0I4±š( æŒÇ˜ŒÓc6So?õ䪜Bäš¡32u¬¥¦aÝâ“ÅHnŠ‘ 4r!¥ "ÌüƒÏ7.®à·ÿßo£(=^<=ů¿ú*~óÆ ,5$ñ"A�½3™âþhŒw¯,Ng~xpŒOlµ‚iðF¯ Q8ÀiQâÍ“S<«�4M`ûþõU\êÄÄÇ6Õ¨ðô ‡q· ÏŒ�ñ—ºm\ëu0ö_»÷O,õp]á…~ppG„_Ѥ¿íÌa£Õ@¦‚íõ^k­&zy†—�1h4ð­›%°ý›—/ #ÂÎh‚{ã ÞQ”h56Û-Üèu°Þjâ�*£>qqŽ?:8ÂíÓ1>yqÚ?=â'GCžìwA äDh©b,#‡ç5§Àöx‚·NFxfy€÷æY0@\évðþµeìOgxëtŒ^žáYM¢¼Òh`š‰áìÕã<5èãF¯‹¦#üîíû¸Öë࣫’ÿ>{ùÚÎ ·®ë“¢ÀÕ^áZ·�ï9|üâºy†?º·ƒIéñË›kXk5ñåûp<+p0-°Òl¢áD™µÖlàÍ“SÞ¹<@/Ïð“ÃcÜOñ�µl¶›ø·»ºè}«ËxmxÏøÝN�<¹sx0™âÎéï\YBÛ9ÎføÚö.yŽÏ]¾€Ÿ Oqo$JÀ'—úhø5 d�z¬×Á¾J~r8Ä‹ÅÿâÞ½ T&"\܏ދ›Wƒü-´­² ý‡Ñe®þ=·…PÜ{’ÿ+ÛꙌë‚:¦ü]úŽ…üçâÙ;­Ò}±Rdõ�‡Q ­¾+mk½¶7÷»KxüÊ“jðø?÷ð™Á2>Д(@ ³ZBÚ·�}GÝøT7øÚOkF êY»yVõöoä8.¢sÑŒE-Á°rª­{�Ó² D1¤Gj€5" 9Žg�ö¯öwñG‡‡á¾<±�ÿúo¿ݦä@ 2"|°Ì_ÏÙà|Ì}äŒgAT‚H2E€ñ”‰A �ÙÌrB–?•.BÈã¤^à¹�ï�è.Z^Î Çp©a€PÅWáÊØYV§2N^Äy¯¼u€-²çµÑœ¼„(æ,°Jån;ë~K�v¨5áŒ`‚ Cð¸ 8ëAð•¶ŒgÐú¦‚eàù)þfý`† Ú¾§���y3 xƒª2�T¯ü4ëhs| ûİa%ýD�Я79ªôSˆJñ'Œ^•éÁ;_¼ò•SUÙÝú8&ö å”îWA ¦�aΤÁ€†T=Úû ìä`VåµÝ’ŒªÝ ƒ|Õ09zQlxíƒdBÇŽ³ùÃV7‘Í3i‚Î\É ³È’3@ža•u‚N†4ë8{²e@€#‡’HN1¨d¸Lþ’4¸æñlsP�I\Hr3 ¸< óœU(”o.ˆ�2Å=…èŠ÷™³pCoÓÆ+ñ/Q–%Êb†¢°löEÀ×fvƦþ4Æ“q­·)*Ñ‚uAë%JoXØ�qÎY“eº&þ¶&`4>né½fn‘Ã%ž>Ñ8ÀÆê=Öï–TÈ‘ùAD¿Š üŽÜPR}¹3h�Q?£WŽT•~P¥®nž»óŽE]:_6‡Ž ŒHòàœñ°¶Qyȵ Ê6¶HØ… S&«¶îLQÍöeÒYç(’ò#,OÊ Ô6¶ÍÍâg�f…b,Q°0¬.x¨ˆ@ fÀÂ<[Û¬ãì£åHƽ2Ý�)%ñŽÒ{%ò@™˜Tû‚8åï¸o„uàâÜHûÖëšQ•�Å6¯aêÚç¾;Ÿ²á]ŽY q+ròk �‹g q¨«'…3Bég`ö½æ!�("aöŒ¡Sõz’]�‰Ôkä-ÅHÃè-K�²,´[Íø#L¯äå%x°â�J¹A6�`OfÀ´¦%aæ Îà‘Ä çaâ{ ‡4YµÁ®²ÑÇ%h—gäUË_V@ T‚-+?ú½OáÂRÿì_Ç£)îÏfø/_ÿèÊ\w’Øñ95´3’¢„ùÌ¥M€ûšˆØ’ ÿHÎþÒæ`ì=îŽ&xjÐCƒ­ÌáC«Xn6BòHóö¿;šàæÉ)>¼±ŠA#ÇÎdŠoíàCë+Øê´Ñ$ÂF»‰<áa>¼± G„Ó¢ÄÍÓžìw±Õic*Šå®¯b«ÓÂŒo�Ž1Èg¸ªù®vÛXQ˜¤�ñÏ,õñä ðåûpµÛÁ{V—pwÆgԃߒgæŽ0óW{dD¸Òiáå£!ÚY†ÏjÄ×TÙþ©­ ´³ ßÞ=À½Ñ[]�Yêæ9yŽõVâøÀú �/ìbg<Ň7V±ÔÈñãƒc¼><Ácý.ž[YÂÎdŠÀqQ³Ôë©A9ަ3üt4ÁÖWÀ ìN§øÖ½}l´[øèÆ*î�'¸y:á�K}€Ä³+w çpw4ÁýŽgz�tÿÖš üÚÕ-hÿÀ/m®a½ÕÄO�OÀ̘ùÓÒãJ·�㢦½C8Gxïê2V[ üñý˜”TÑïlcâ=:y†ÇW—±o @GØŸÎÐp[�ÚY†Ÿã¸(ñ¾•%¬µ›øÞÞ!v'S¬µšøåÍ5Ü›Lð¿ß¹ƒo‡až´šܸü,º�‚«v„Yõ0Ín ô6ò”‹"åBZ|Úñ…­OZ%Ÿg•ŸA\ݹãîD�\»ÅÑ ñýö·épRÞ¢,Kºín\z oÞ}ž=¾x|ˆFŸñlC Ç& ôK/Ï*áoõ‡:Ö†cVSü›·¿�gÓd¼:YV�õ•ÕgÓ(“÷lFÕ#ºy†ãY®ŸÔŒEs(o#1ì’œ~Gáɤ ŒNFx|e€ßºso$ÑEçƒ7ð÷?þ íc¼´IŽžl¥DåzÉâ‘ìD¸©F øê÷„¡—5‘ÂBïÏ¢ Œ áIœ2…re4 �^cÏ( /‘�—1ÆLøE€,Éêç”q†¡º²¦½2+!*VÇ0è÷”99ËðHJLL qàíõ…Á¡|2A½³�`Œ`û[»6Uüëx¹Áªgm£‘8TX;Ô¢\UC^ûÇ]‰¾/À ÕÄ9ó*¯HûÖNu°þšà BENEøH(¼�g1 ^?aæ9àï3T�‹(s§nÊvo†¦ÈK¦ò£òÂAþÒœ…©˜7„©cC Ëy�({©ú„×þ•4 2Åqõ\¥IÖõ‘ÿEŒØ°ëÞš¢(EÁœ;†W¸S§F�Œtx“WT†%U>«¢ÑÛÚÕ×–^�$‘΋ÌRªñÎy¨ME[í9Âv‰gQœ÷žÁ™òü‡œ¢µ�sÂ3ÃK4…Á„hh�ÊvŒ,ÓÓò»Á#ƒGÃ�–8+IUJá 3B‰ %g(‘«a@ª]–ræŽÛ•Ò¥æj††%~£fb”¤õltÖtª´f IDATGd‘l ³e.KßÈ`zU´W"† …Éüªàa¶Iv©@×ÇY�έÈ×påW&^B Òã ]ì__Cá38RÚT½{î¹EßÍ6Ï»Fg•h�‰FŽºèYõ¬Ö£ºeü<ür}«I�wÎ<λV¿5ilÅ»òÞ”(¦…Ïï…õHˆ¼Z–‘éê÷ŠeÆ&vÝê�¾WL9”(Cå3)1Ìï¸I.*2lì”Þ¦�m;k`4ìáúVÛ§'/ ³*lÔ²Ù$ãä¶E“dÁ¤©5–“o ï;÷B•¨Ì?´hÒ¦×ΟԔüÆ9ŒÆ£¼Ë6ØÚ3$Þ"¢‘ƒ`م𳨠gÅÿ“þ—Ó,lÉR1 3”e ¢ÔÒÍN=„ÃÂÛøÕ¬QâÃ{VÄG²tš„©Êģt•V‹NÍ 0•§=OR‚–ÔÇxL[Ff�m¯£x¿%%$åtMÖZE ._uNs¸/¶.™?JªJðz�Y�ló]L0Rƒ/ø½ª–”I†­«ùû=Ï´Þ‘ÖUU¬Läü:¯‡\‹Q€ôË‚vT:_ßbL@XrgìÕê‰gD*yÆäeçDÉ\õ 1ú\¥£‹Ç¶:>±^²Ž²0®Õhñ&·)e÷ÇÍј1—>¯Ïf¬>õš@<] öW`ÊÀ<àK5˜XU5²@Y‚ù÷ù1ã€ÔÁ!×È€` ËAöYf0@±;$[ê@™Á±B¢ÉÇ=¤„÷ÚZ}&18(aÁi‚4É�RÌ,ß‚­!‡,Á„à©e˜ÂÖÝæ¹?-8f¡ô™Ð…”²Že˜,h¹dîø²FåkÛ¹µµðÃ#\ÒdÀÀ5Ã@ƒ½Fô•Øh5ñ‰-�ºu2B7ÏBÔÂ÷öð`2 pDoŽFxõø—;m4œÃ ‘ãZ¯‹^#ä”ÝåS[`fÜ<áÞéï__Á"¼6<Å‹Gx~mW»m…ÓñhèDcĈã¢ÀÝÓ1žôðôRÆüÙƒ}<»,IyÇe‰WކÈ�à 5–¬)îµ#ƒÉïZîã±~ý<Ã7vö°¦íôÌø½;ÛðÌøì¥ h)ŒÆ¤,1õ…÷Øê´pR¸Þíà§GC8GøÌÖrçðG÷¶1óŒOªâ›ö±=ž “gxjÐÃÁT¦y's8šȈðŽ¥>�¯ŸàîhŒ®¯¢ßÈñãý#Ü<oÿWކ¢|Ó=©ãÚ’Ãaâ=^Ø?ijK}L=cTøÒ½\évðé­M¼u:ÂÍÓà3—6‘;‡ÂGcá�ÑXrIÌfXk5ñ•í]t�ÃG7×@ü© ~ys ½FŽ/ÞÙìÍfXï´°ÚlŠa ÙÀ—ñ¿Þ¾�£D¹¶|×¶ž‚sYÜ£�Ò<Œ-›;æ=³dµÍݨ왑ïâÅ÷×�º”/$\A²¯ë¾Ê<¯}5Þßö «ÝÙÞj�ò»íµ�.yeŒDÛëôqãÒc¸yWŒ¿3<Â~·�ÏôÃÀÛF�¿þÃÿ²†ãXÔáœÊú?–¬«çM┄ʤ ‰&°tN)Ì’tK4¦0<©Ž P]•êöÃAÖe©�EÈ„NWwõð¡Ò¦+GÁÀÙTL VÉó„�!ÜÍcr’Ì•`0¨ÁŽ›×ª¶ô¤²ÛÒ 5ðD>*Ü�ôy z¦èð$£FK¬6“i ކ0»/|Øó�W³!–»Ç ‹*’æ9¬ºWªÿ¨—YΖÃY\[²ÊkJøÈ»I3(Ü3ï•Ï¡ùD±ž!Ò(}“é ‚Þ �Ô€ös­¶¦Œ;“¡M®sõçÈàžÑgwL­ û'jxµÐJ_üùs Pí¬T…†/§«Ö¯:÷‚�´øˆ£2áÃÚ ª¢PZõ]gLÔÊç™/¯•3–Z­çëc½&õg6CêåT¦ûõ:¯~\û›°øç•_Â�TÍnÂ9ÆP†L-ØÞ `Q ú˜ «,%´w6+1›Í0›ÍP”|飇1۔三©M©RÅTq+?Ôïªö›yÒÌ·sqï¤ÓÏt´P+�N6,ö^�¼èLi_YJ‹ˆvøÏú�’ö¸dH80ÿ y“к@<“v.œ�Á <®¿êݺñ1Ìæ®WK—á[Ðßá“«ÓÓÞÊö¬R/£~„È€3¼ Ï3,XÝçŒö^®*ÈcÏYãai=ÊÎ`3#hdÑ{J¼±ä4(˜zL<®Õ/ùZ7fØflQìÅ£ƒ.Ä^²Ô $5�62ò'VR‹Çõ«ù3S‘TŽ”í óÔú#F{G9àîj¢© ;�2�V¼X„gGj 'eSâùïYÂfÙãT¡×)#(8ª*…/³’ ‡�œ$*pp™`Y(¹ÄÌ[«1^ 癃_©Œ¸E†˜Až!J”Y!F�ñ˜„Y)á¸^×Z$wÒÖ�…§‘ßÙ=ÀÞtŠÏlmÂá•£!^>b¥ÙÀ…v Ý<Çr³�ÕfC „�n®¡“9Ü:áîhŒçV—ÐÉ2¼xpŒ×†'xv©�w,õ±3™â�æHxF×êµ^Þ3Æe‰Ÿ�œâùµe'3üÞÝ\ëvð‹ë«ØŸNñ“£!žèK”C3Ë0õJv'S<»2@o( š¿õ`ý<Ãç/_ÄÔ{üñ½Àgnèv0.KÏ ,5Xj6@£16ZM¼6>÷Kì3¶;t_í¶{¸~éqܺÿʲÄ×O‡8ò%~µ;@»†;_‡³yûøË?êÑõdÀçÁ9Õ#;ÚµÈ�ImìшPïº&Ÿ·_J6%R´›Ì[¿Œe†Lùú92«T‡ÒŽNêŠÑr‚ÁF~#(ïH� iÝìy¢QÀ©C…†�ó-‘¯¬©áLeiáÓE)­r©ñ&y{‰Tö%£,Oê}ïMô$uøIûG”«^ÇÔ'†{+™íÝAÞ/u¬£a@eа¡Äî í·d&' �ÕyE#Ìx 1àNsªL2Ì–;Û$-õùPë`JÞ<·¶¼ÈɤåÁë~íÌ0BjÐ6,k´®�³ÆA DQ�u ÏÈKÊÄðâJsn¨š LßGŒzMö)‚�ÓƒS4ˆ@­�D@NÈ›$‰| ”^hšË�ûMjÀe ;E�äJÀ±$�i�Ü 'SÔaË‘äPÖÉC$ÑÎÉ” Íê”ædYç’ès“wÀ�Šcó1 ÎI f€s°°ú,ÙìF0ˆ±ó�:/p0TE“CüŸ*É‹ l“ÃSžhþ¾yµhMÉ^¿ T”äu¥üy÷¦Fƒóž‰m‹ô2%™”Þ‘è!ªF‰Ô+?ÝÌŒÞ.¢Ëéçú^i˜í*Ã4º‘E.7¦kKúXÜÙ•vÔ®$¼uzÿ"6|¾,ÈP-æË4šüç2 ,®L-6|TN»§JM±ð5…²ÁzpØjYs Átsœ¯®mcg4²ú@õ¾ú?{²Ëíõ{Ïñ¹ ŸõûYÏŸu<¬®õßî`nqœ»Z ¡r•’ÍT²æÞ"]z’Ï(JƬðj(0›(ŠEQ¢TFĘ6QRLR”T�âd u®’K銯ž¡ÕÉ&PQOz'(@)(÷cæúèííu#$F@ù¶*�2Ça)Q$÷óGÝc=*ÐQ×�)Ž�9ôÁ)Å ¦h¬v WƸ:#’ 1P„$X5QŸ£+©~Æ�E7ئ¯Ÿ·ç7¦8w«Ã+FÈ×îK˜eÓÐë*ݪo¬ËŠFc¨tmÓˆó0Ý�ã5f–u£¿9'Þ=+w(³º©KUt^hµlkXhœ1&¥b€r¥/”´|‚âôë\ÆÛ2Ã}ÔþôÊ„1#â�Š� $• s(öa´rCVÃZgeóI…i ülHüK*h»ä ÷‰À%B‡$yK»°†ÑS‚Q’GÉ%('Å·ÔHíã’‹œÀÈœƒÏ¹ VYæÊÁ$¡Ê‚Í_x‡YI(B•ôeŒ, á=W 6ÞbL�•„YŒgŒé ˜•5 ¹ßÃVLŽmL3»K½Î †ÍÓ^'ô�¥ïe(�‡³Ó„tF†¤]yÞÀñw¿û­—ðo¾ñCxÏxe4Â?|ó ü“«W7ONq¡Ý y^88 †@9iTÏr³��]\G?ϰ7�¡á(^ž`g<ÅG4Rà­Ó¾¿„‹�Dh:ÂåN K�Fȧ`žæ;“)vF¼se°=žà›öñÁõ\ê´Q0ãþxІsذœK=4Õõþh‚'=<Þïb\–øâ�m<µ$Þÿ…÷øþÞ!Ö[ÍÕÐË3”Ü€#ñJ}¼ßE7ϰÜhà{{¸ÐiãcÖÁ~ÿÎ}€�Ï_¹ðâá1î�'¸1+ÐÉ2¬·›–¶ºmÜ<9EË ¶'søÖî>öÆS||kS¾?ØÇýñ�,Ã�^{:?šŽ0)=äðÌRK�Þ:a{<Á×WÐv?><ÆÃS\ïvðÞµeÜ:áþx‚çð®•%0$�kC=÷_?9Á»W–0.Kd$9 ®v;øµ+q0�á{Û» ¿ve {LwÃÃé �÷º`f\lK‚à^žã#›kȉ‚âã70häø�Û÷á™1,J\évx'Ïpëd„®t;Øh·ð§Û»ž__Áz³�¯ÞßÅØ{l´šøèæ¾»wˆK�6Þâÿë?Åi¢`\î¯ãúå§ÑÈ›�æF�¾@YõãçåçêÇùühê5w²@$õžJqg¾'ý+dçøå € í·¨Üô=�Ã1VʳUÞ¶a;¶oQ¥íý¶Å—sR¿”÷½¨û\§ÕÁc—žÀÍ{obVLñ£ñ{E�ÿhe­ò¦·�õGÝëÞæ^Nö;êÑõÈŽ9 |Jê½ÜÏs “dÄõHÑÝZä@ÉC«Íö5o\ïvpk4u5˜6@àð¶züã›oV ƒÞs}ÿÉÇŸÅ ÓÄtf®®ß°?ë­F碾Ðx8IRùóTwÄ�÷!$¯0þ"4Y˜)ªê@¢Ó„ò™K�QŒÎ’‡Iœ ,ï™='ô@’“:"¸Ìi®"¯ð”±®ä$bO„ºg8�6H®xšS(¼Šö§yÖ›|æUÎ2ž¶ÂkS"_*íÐ{F*­#�)�](¯É •ºÅGB�­] Û+p2|^(6ô%eR�5¤,R¦/ùžD$"pèËØµšWJåÏæ€e}ê*cÂl‰‰M¹.¼°7Ðt/2ÙêÏu 2^`58øèÀåYÊv* ¡²7ă`†ƒTÎòf`‹h0ÉCÚ ‡lk„“1YYQw`1@”ÉBŸOœŒ-±(µmû4�éð‘§`k‚B¯ŠÿžML_=ÙÇ�’ÈàƒAäˆ#TáY j ­¯ GÅ—¤ë$³i¥ïtñ:ëbÑNd$‡,Ì—@[ȉþ§¸¦J.Jisáà9»&(cÌ4Q5•Å@%À¥È‹ž†(Ïľ�)|‘s.í8ƒRy†ÍX£Qy†<ÏäŽhžÊD¶£ÐÑ×kº+™ü¯3G'wEaͺªà$ªÉŽm^—Þ#8y…G¹Ü@"Rn,*vmÞr¸õ7‘'«-öÊuû•(ògq^EfŸó^û‘ß­?s–qÀhAÊ›™�#ü­üjZ—.(=¬ï#—™ôGµ�…Ÿ”¼ò¬#®¶´ýó&å9+ušÓ§¥cWmÄ™¯¯_«õAýÉê¸<¤<ªç¢Cü^2*1-ŒcB-¼H˨Ìb)3å=êÍ  ­¾Û&ÅMÒ¨©. °í¤“ë/|Ôû㌾yèñ¨ÏýeÕû/R>g,ªŸ.D†bÊéƒâÎ}œÃ³rJ¢L�ÉÔc2)1™–˜ÎJL‹E¡PÑ�7˜ÕB�±–—«Ì…mÚÆ°Ì·'ª™´)©W…=§ÞÉ.‹ ™' ÅÄÀçÉ ŽEï @6a—!2°6Ý�–%}—¶+蜙½ªem�*; HÒ'óýÀiï-¸žÖ&þ=>οµÂ›&Ô«®ôXäÑŸ*inu�îÓܳ‹ÛÌæ•Æ�¦u­”RQÌ׊åx=zÌT*X£W5Ó¥>Ï %¯F,X&>s-‹,AìË0æúY”ªD/Ÿõ" QÜó,‰!ÏLiLÊ4F ÓEö¢ü—D»ºèÁ0LJ[ÜÖ&cRÆÉ!z’…­ Ô1ö„1Ñ‹H8û8ÿ{¥$?×òK·4£Oa-�‡3aÆÖµáÈÙžçÕ0�‹r>ïòÒ/E %aêf>¬P5°1ÊN"¼†Ñ†ú’ *¥Gé>¨(�é ˜–PCƒ”'QXb@¨8£A1‚sÖ-" ,Xž9äYÎÌä%ñ%± „…J˜a@ÇôÝŸyÿ;qýâþ�ßÿOF8)Kü÷o¾‰¿½¶†_iu+yžôÐv"¬ ‹[�6¶:ñƒƒ#<½ÔÇJCà…^<8Ær39 6[­ m¼Úíàr§GÀφ§Xo5ñ.½÷Ïvö0eÉ…�§3Ü<9Å3Ë}dDXn4ðìR­fð"þôÖ&ˆ€—�†˜yŒ/ãÕãôó í9tó½,ôä—6×Ð˳`€°÷Ü�ñÝݼou×zœnŸŽÑt®tÚ —:4�’v'S¼guÏ.‰èò•í]\î´ñ‹ë«8œÎðýý#t² ŸQ(¤»Á•%žôÐÏsl´øþþÖ[M|îÒ42‡/ÞÙFÉ,ßáO·w±?�a£ÝÄ�^½,C'˰Ùnbg<Ár³�çV–°Ül<þ�l®¢ŸçÁÛÿé¥>žYêãµá)Ï‘©¥Œ,&ÊzHZÜǼ‰Ðö16Kï,BkÝ8¿?q ‚€.ýœŒ�÷u›¼Çpl¸ð á]öÄÏ*<´×ê½û|`z�±<èxgÇÇJ±9²hÓ¢zo$£@F8Ƽ”ËÈ,J«€º‰˜Öb¸˜4¸˜ˆ‘ ®#BˆˆAB“>1íOð4ƒ�Îü˜5uOq¦zxÉ.´ï¦7vB:�s¨ª®i°NÎò³Ûë…ðD¢ü‰6 )¾CEûRÚ™n6 X覦i¡Î™K±‹itÇÕád©È�GóWP!a†sm­}÷™yP–@aÆpÙý9JìN_%žm)hæ^íE5¢gÆcX‹^f�~§OæÖMšÁ‘�÷¦:˜L‹f%æØ`7}l­2û�Ö¦@ö¬“ë23šÎ4æ ™‰î©™÷RÕ ÆÌ&\ #`0-nž©a ôdÏÕäÌj¦élPx )’Ò£ìÍÎé�%Î1ƒžòœi‰ˆD— @˜ME"ÖGÊKjpg!ðÎIQ/Rà �¼‚¢†?W,™ƒ<Ä#(ÓuBd4 ÔÁa=B0À(Þ–z-`-:¬O!hŸMÑFÓšF M¤â§~¯‚”ª€DtÈÚ:B8ЧŽ²qÀ;¯JIû†HŒä“|!ü„†BK]Hj¸XYÝÞÄúo¼„ô‡Ž×Þ¾ øg{{øFÿÿÙ¨�mWᨮñôò€ä~þó{ûøÂµ&aèÛxû[k$Ì�‹ nŒ°Ü«pP×øÊ�=üÚÎÆ•¤'úÑÉ)*¢”~èÆx†·Ž¦5n,-âñ¥ELbÄ×÷qc¼€§t,|û–« /háãÀŒÃ¢(å3Ëc¬÷{Xé÷ñúÑ Ö’¾¾tgç!¤Bß?:Å[gçxbyžK½ ›ƒ>Ö=7 zDøõ�M,Tß;:ÁþtŠ_Ý\‡ð/÷ñ“Ós<·ºŒ'Æ Ø�Lq8­±TI ©…ÊãÙ•%¬õ{¸;™âöù>º±†žsxóô ß>8ÂãE<·º„wµ óîd‚‡®l�™Ñ÷• 7ïž_àýkËØŸÔzŸŠ&îêö§S­ãàð›W �Qå IDAT·"Ü>¿@ÍŒó& "Âæ /µ ¼rp„ïñÂæFU…?¾u53>weïñ»ïÜ3cs0ÀÆ`=µ¬WÎaw2ÅP‹P¯úøÖþ!¦5>±%{ûg÷öp8­ñÈâ>¼¾ŠWŽp#v'S|`m¾nàˆ°XyÜ™L±w1Ás+Ëè9½ÉßÚ?ÄÎp€—®mcwZãÿ9ÝÃ?yû'­ÔT«Ë›xôÚ3³Q3ÒeF�’/z°«ìû~aÚeûVÛKòýzjË/ŠQç<¥�@äU6¹IûÀ¬EùØÐrѯ)[2ù ‚a)ˆëû™ ÷sjÅÛ™×$dz>sÌcÏã¸u÷mŸá,Fü�{wñ·V×q… ­é/®¿öëü>)ƒúÎ%Å= Ñuq&J£ Qkzoä]«ñJ¿‡ÃÂûc ð#�ŒŽ$BÐŒƒ>ë&½¯çœÖkiðèÒ"þá½»øz‘rlua€¿óâ3¸±½Œ&h>psœ`°�Ä]ÈÇ�³Ç>!¥Ë ¶)z¨íÁ\òmÆÏDf#•—,5‹KƒPþÀ<]Yk D*Ò‰Lãˆ@Ñi´(çþIÓ9¦{�âµxáMI‰Ò›V ^Ò‰$Õ‚á•rCMàQ^ÍÒY&\c<\ÁZêM§¼*;‘ÙDÁ) FŠ™ÏòšQ™—�aRüâ¥AâƒQà.?%‰ m<†<²ȋל~@é±,X*®O¼·K,=¤E�#Ÿ—‹Šd}F–XxÑVäÈ‹œê½ä…wQ"šSvd>ÏÆ5JÕžûQ½ª¸Áer^¹”ìÙ�DZK0 n)²D&’:Ù0PÊuE`ËÍ–Ú8µ7†­�KýÉÉpXv€¬K8ÐöÔ–¨“<§#M{„¬P612;‚E8Ö³âdÿ‚7;ã±*µ©ˆˆQ`‘/.2XÑ+1vIϼ7YÒ%yˆ“S°.œ'«/Â(†ƒ3¶Z $W9T#„‘)á+ï Uåà#û(xÃŒ‘ààá½G¯§c$­‰ÆêÌE9Å©ž%‹¯*�~¯B¿ßƒ¯¼êK"B bQ”ýÌšÊZäšH²nÌP<¥ø$D*dU…±Ç$éSÏ€ ã4 �è‚Ú…öÕ1ÜüÀ£pøƒÁW óg(ß›yë<2ÊxªpηÇa?³7B>sU %mjßïðª˜ÓPÑ^·ÛÔB��—Ìtt–_í®A[Ç›ïK„¬Í«óÆ„³Yñ~ûÙû¾Óö°Í`·®.�ŸÌóúârÊŽ¸ø{¾ÎºJ ;¯»ü¯b“OMùg¢v—]³À 0΃œ9Ý”ïL§ÄØ n-Èì<î;Ðû\íCV’º»:›ôžßÍçý¾û«^ %·íW¥«;Æ9c0J›4˜Æ,!ß³|F4«58"BÓ0êš1�\\48?op1 ˜Lõ”Ñ4Rw ±vGu2–áGeH2±ža²[Sã™™¥û¥›1£m0ãLÖÛkb+•CõÊ‘zU+Ñ>" a‹NŒÞ†0©¾w;b­ßÛJ਩[X‰š $ÞUê]ÍzϪŠ%*æž6Œ‘‚ Í3^�Eëüsœçs@ç²ÖvwžàA"­Ó«Hñòp´Žµ¿P6ä¢b³c”¶�w¦{sÆ3ó÷ý¾+Ææ�ŸäìS¬�1ðÝAAÝMæ(¨ÂMfZcr‰²Ç…ysy ‡~o–(U .žæf/pÉR„ rßÃj ˆÊ„%\”¡ÑÒ ‘æ�0á(%,\ÞØ‚< Sæ‹·O&å;œÌ(@¶obý7å’F6FNÖLr`:¸èÉ'Ä–B ˜#P3&S†sMZ[ñb‹ŠRa%RÃ`ÎCz,“ÐШƒ¥\‹É(Yj “«×ÐH*„¨Þ%Î`^×QåH.EYÄ€srÒM@Dˆˆ±sHõåųFÆê$Gœ¤KbM­d1§5ýª�ï·?�?þæ«øý¯¿‚#nN§øô#üÝ�M|nu5�ëÚ �Ï_Ý‚#àöÅ+½*y迼„ÀŒç×µA]ãõã<6^XðÏ­,aä=êáÉá³WăþÖùö'5ž[]¼uzŽoíâÅí ¬õ{‘q\×­Tϯ¯b莛ûñZd\¹{€�o®ag4ÄYðúñ)®4!¥Ú&�êÏ.�ñäXRä|íÞ>/à…­uDfü7ï`µßÃ'Õqçb‚³º<ï®/Œ@D¸:à‡'gXª<^ºº�ÊþðÝ;`/]ÙQöößHš¦¾*wÆý §MÀBåðÁµe¬öûxõðûÓ/n®£ï¾¾wˆ›gç©fÁkG'8®ìO§±Ò—”H=’¢Ç·/&øÈÆ*"€ã&à«÷öñÐâ¿qeož�ã�“3 ¼ÔW˜Ê*äî^Lðìò!b¡òøÒí]\ ðÒÕmœ…€/ßÙᥫ[èá;ûGhX"Öú=,x‡#KÞã•ÃcTÎáññ¢Ô,¸uuŒøøÖ:6ú=üîÍ;`f +�Ç—–p»Hõñ�“üw7oâÍIÎ#^ù¾úÖW¶Ç”ØüßóõWãßîOûºÂËý.ʸºõ‚¹Õá± ºÙ&y7') Lh,…ÐY¡%œÎCæXq3ƒà”ÏꤣiõŸ ÿ%É2ÁÉy�ë;�àîÞ»Ø=¼‡àìá…Ñ"^-ΤœùÅõ󽺹þ‰(¥5³kÚáu,Å“xÊ”A=GI‘/mÛûWsv•6ÛÃî\äó¿3àÖyÆûÓ6]0tÞsø�ßüI+娳×7ð¯}ì), *Ô¡È®ò¬ucóœ{fHàhÂ-¥”Cd˪Ž~1h¤gúÑÚ�4íeˆešMüv±p ä OQVVøI¤�Eº·¦™ÎƒŒ3ªLh8_~k;†$ ]ñyé"” H>ŒEÔT¹[¬-€˜žu°ØefJÈ g›–e»K'ª§XzÛ†HœêwUs]à€"b`=³¢±¦T{@Ö…šLÕûf’“ŸÉÙœ�Ê»·RNEN%|�#»(©~<à¼r3 ‘ÉùÁ> n¢X.‚‡ì‘B@ÝDI£(Ë®:vç€ÊçâÏÑ98vR›À»¤‚:`ey&K…ïzU…~¿B¿×‡¯\2òÄXI�áÐI-Ô„ˆº˜ƒ ìÎTn(X4{†»Ò9Md?R”Eš†Õ%Ï~g’!Fmã£2\qËN˜y-;Ðu·¶…ám½@[ï‘ ÝkÖã?¯¤8ÇsÒ‡¥ñÌô¢OÌù"ëVÊw¢53.0·é{{ ÅÛoÍýSÙ`î`æþÞrV°ºŒƒi�ïa¡’±Jj‡…ʃuŽX]ÆAÝ`¥Wá/w÷±3â·¯ï`"þàÝ»p~ëÚ6ˆ~vŽIˆ¸ˆ}ï°Ñïá´i°9èã�³slXé÷°Ú«ðÇïÞƒñ©­ ô½Ã¿{§MÀ¢÷¸±´ˆ×�NÀ…ÖiÓ`ì=®/Œ°3ì§À/no r„ïãí³s<³<Æ/­.ᕃ#Ô5ˆO-�Aoá¾s8«ìÖ5>¸¶Œã&à¤øÝ½Û¸1^Ào^_Å›§gxãàà·®ïà<Ôšf&0cwZãÚÂ'uÀrUáÏîîáê› #üÃ;·ñå[G-<³±z×wž@å{siÈŒ{.oõ ¼óìuy¤À|Þ¯KK["�ž»öß-Ê›(ÍN”´Cרüo.ÍS³€ñÒéÜwxY*ǘiiù÷Ì•„.—þ&ŠšÜjÄ àKž…:4ÓHk–76ׯ¢×áö½wÀñgç§x£žào¯¬·5Ï¿¸~®×¼“0½ûÞ©ÑZ`º×5XJ¢¥^…Ó¦I[é‰0¬ä”MlÐD§Ñ§â€4-h–ŽlÆÂsq/FVå³thl|v4X–>MÖ°J%T¶<÷Šß “Amï�Š#[ŠËœ†K HŽ[PÙæÆÉ(�ðL&RY|Ncà4ÿˆ´ &ô™¨gÄ;äÈ@Šñªɲ)eò“s(¯#QRði,¥Pà\JcÊà¤â"3h9Br²4Ä�‚~^úr•LAc*¬ÍR¿ fp V Ö*cĈ&о‰Œ¦µß²ÞªJkÊ�Ù!²G… ÌuÍhj‰<�êìTêEÌA ª<ýú½z½ Þ‹h† f  š0­P݈¬BQSI_ —¡NñVJCUêGlfV49ωðkgÁdj˜\¯»>/Ê3ã2J:ÔŒÍ(Ài,Æ_åÖØæmp¹ÒÝÒ3^r:/¦Ø–˜[ usÛ(p™·~ñÆb\vÍSÄÏlêô’¾©ó³ûõœçÚúË¡jsÒ3ƒiß¿4R`Þûgä‡bÔîË`ð†jLîÏ®ùŇ[ûÒ!(r¤[G 3«w™¢L……ö{31n}”‹âò´¤a+çùÖª›È¼ß×<à/©É{µ}Ð>çµùi¾§Àæ|7çÝÙG·$ÙJ°#„!iÔ¨47±aÄ& Ôõ˜L “‹€ ûL‚¦šˆ!çâg ÿ+S–tÖBFÄ­ïÒ½ríKkB²ª–}Ì_¢Äœ¡`>Áàd=œYý…�û¤ÓBjŒ¬Õ�B UDÁàæ0\(¡rå8ÈmÈÆ0sGh8{� -¤ V!_eøçõLÌnq*¹ ³­õ1Æ®ø¾µÎ—€ë¼5î*©ï³ïy•ž�í±=· %ã� _—hdItKÙÅ~ÍÂ!µ–üŠók?ß2Šv ²WQ Cæ-WJ™úÞÒCjö�mÏt,ã%3’„.Uð§ J¿—̆±Ã: õN£ä}ŽŽ€å,‚@ŸvÁ.gc¦RÖ/{E±žâ[_ã$^ÿQ ˜9€X¼PK›äÑFFjÊs‘_â@ìáôÚ‡( VÞ\`i¨jÈçKæ‘ósš‘ÊLZDó3‘xXObÀ¤ ˜NjL§µN‘ú”~ê¦AÝ4ɨî+DÀU¢dð2S 1ºÞ`GFÃ!ï?¢“ò`ç�‘³C(Š‹S«q á6a�žÅX±¹º†ÿo¾„?úÆ+øÊw¾fÆø�~üþ­Õu|¬€°Oi€{œ‡ˆ‡G€ÛçüÅî>>u/^^‡Óý–4eÐ/¯¯`è3NêO/�ñ4€³&àë»xÿÚ2®�†˜Äˆ¯îîáÆâbŠ&XîUé,f<µ4Æõ”ÿîÁ1¶G|bk53þàæ¬ úɈpë|‚ýÉqu ŽWÕ˜±Ò¯po2ŸòøìÕ- ½Ç7÷$þ‡5âåý#¼yz†å� ¬öz"P)>šÆˆÅÊãCk+Xí÷ðÖé9öLÙN„—÷ñæÙ9>´¶‚GGxëô·Î'`^¡r„õ~CïqŽë€�n¬!DñÂÿê½}<¹´ˆ_ÛÞÀÝÉߨ;ÄÐ{|þê.BÀyð“×qÝàéå%Ü›L°2èã/w°>èã3W6ÑDÆ?¿½ à ×v@„”2è±ñ¶{ôœ0Î#/‚×}ôœÃÎp€/Þ¾ðâÎFÎáŸß¾‡³&à¹Õ%<³<Æ×îí#êž6‘±à½ÔNöñƒãSÕ5žßXAßy|O#"/à×¶Wñíƒ#,÷{øÓÓü“»wS>p Çxøê3�–3Òù©®Ÿ‰!…ÑÍD—ª÷ðœß¬¼Ñìß3íU’¥’¾˜Ò°Vç¿?ó‰‰i²Z2‰Ï4…}b¤æÌç’ù’–œ×90iX?€2ç«ÑoJ#ƒBV¢æDÊ”h4ce¼Ža7ï¼�i=Á»Mƒÿ~ï.þöÊ:6fÒOþâúy_=çî[ðy:Lj`W·¸p·PñqÝ®˜“Q GíÔD›ƒ>v'ÓÕæåY‡"Â#‹#¼ÑLñ¿Ü|§ÅxŸ¸²Žßþð“XõQk„"±*Ì�¿W0O†{ÌŠ¾ ¸(Êû4Î<Yå N…:[Þ–&3¨!")·Ô0P(,M‘ygÃ@æMž³Â®‚¤†1Ù†¬Xª €õ]æ¿HÚ‡“šLIœeGFKLÄ›~1G—Ò‰…(glìÊjÀA”ù¤QwÎEM�T¤Ê$ÖúÖO‰›2¢”šJ„´‰Œ"�ŒÊ òÏ ‹ŸP¦õ™d‹R&…*kUÖ5c€ý,úK‘¥Llrx u(:69‘ó\T±*³µO‰Lhb¯ê¢Ø @�À;Ûÿ(Jx@×–Mž@°Ò•¤àåœ|À/æ‚O¶Ñ·¼ö)-•ц²Ó“ðäe*!-›ö³€ùƞ…Èèå:šüß’Ó²rNCJj# t�ƒ§ý šÚSù³"_E¡nF7Ã+ºýúwÊc$‚(ô©qŽ“ÜÃL’ Je5ÒZ…W³,Óï‹C–¥µH#y¢ã©Y� &¡HÙ0Õ BB‡�#á+'iªBˆ„&8Ý3‹¶’‚øPâ -:ìPy©OàH¥’…5fª¡O7€T.ó �óp žÚ©…bKÆ&€�à³Îñ6œ×UZRr6C2àÎxˆ_Æ]uSã,P1†v'óÒìt¿›÷*&ÃàIˆŸiÔ>û™›ïì2ïýHz™û�‹Šõ좼î3í(ŠÎËLiÕNÒžÚ{Ãå^).é(õß}å|§Õys-°ÇœVsÿ>­g 3ö3}Ýüé—^\~¸XÐb$ï©©¿d÷Ê>åï´›é:{?øõ³{òì<€z¯vÖöAÆ¿v—½ïæ:çœä/Ê¿¤aEö×MŒˆF &H2m€kV¢ëMM˜N&1 L&ò™N#¦ Ð§Þ jÐÂ3)‡]Áº¦YvXÒ±B²if.-y¤ÌÕL'n«he"ŒóŒÉp¡YéàÈ«§R(oÔ®"L1Ÿ™‘!˜Ô Ñ(#@v2·ëô�lóÔP@ŽZäØˆ¡d¡(¿ÛìÍiÚÆ¨'¥qæÁ�!Ñ<æ™sßũş™á+šsùÍ_åj+VÊg]£@ù{28Ÿ È @ËžIHD@æÔ%°”'J³ð™Ú`¾•ù2<'…”잃 ��™£Ò;¼ý<?�”ß§‘>ãl¢Ì‰É!»¥)z šl.¦_±Ur–’2Q uÊ”ÚTr®Fƒ¨Ð‰d\ÈFAc bDi–ÈÿYrâ(ïˆÊDÜf㥾8I[Òm`‚ƒƒƒ±Y,á&0uL¬¹ýcPüÅ*�Z¸{ w"0,Q+< 0G\„€IÝ`2m0�†äÉey{­ÈZÓ4hš8‹Ú`x-Å ¸"EhXX=8‚Ö€™WêJ8ï †� LNE 1ØFË!ËÙ8 )ŠÈeZÅSÏ`Öãó¿ò<Þ÷ÈCø¿þôÏppr‚iŒø�½{øgGøw×6ðôâ"ž\ZœÅˆÛÉ0°5ìãù�Uôá{u}røßy `g4ĵA?ᙞs˜2ã1þ§[7q»ˆñ¾ÂÕíDZµ~]…á’a~Ы-@<ðe(¹ÅŠd¼Öåogr³¦{FÌ‹û©·þNØ¥xŸýZzöêÚŸ™‹Z?ìA5¢â‘é£)ôß[^ÐÑ‘†ë§1$¦ â²XγûRV¬ÊߤЂ’”ÿFƒ<þг¸y÷'8:ÙGÍŒÿý`.às‹ã”#û×ÏÿºŸQ ¼‰2©Œ6è.�ÝS¼Úïá H)4¬<êÂpp¯(< 7}ŒGüƒÛïâÕ³³ôý Wá3¿tïD  MÌÞã–®GþÎ5)²%ñߥHné#\,Ð5Ö< %µKLF7ã�3E½*=U!(Š0§µ$j":À±F„šrÃÖ�r®wÓ‰{²t’f ÓüóŒBa“ïYd·”#ÞŽ­FRVêp«²Ïº.-Ì¥¼Ÿ) �“§³©/·eTÆrp,9Ûct)·9¬?Ç᪎*0….#åƒ1£@T¨¡Ø8¨#‹ñð‡'@Ld¤0x»ÊhQëÛŒ¥÷J���T –!<¾}Q¶ÑwØn‰b”ŠzfQSB6RÓªaqÚ @ˆN½§Í0àtŸtTáî}I? „Ú<·,éHp@Ðýa0Ø©¾Ì¼îíÐxΰfŽe%ÉÔÉ�=€ ii}ŠXG4MÔ¬²bÁiœ(©‡Œ!8MñU¡"/†LÇèXpTpÇ@EY¦7VÀä^)«0<Î�±X»Nаb-[Ê÷yc£„tuóW)¨õhzgúmV/’¿í®SîÛjJ´ßwùZæ�ö»º™,²á£=öù�"“žK®Â0 JcÄç0Îí¿õäjÒ´¤ NÀŠLŒZÌx·KÊ&}bòp *ž£â™Ò% ÈdÞä[÷Ú'rNëË® úS>7ïúiÞßéµ#> aXvn IDAT5Û�ýkÀÜAX­ëÒwª2_ å¨ ”"¸‰jKrh¡Žh¦õ„0™:L5Ovj•W†Õ9Ï‘*¯Š7áó  ¹+.<—§gP_ÂZKlæt>ʺ"v&]²8gå3«G€�‹˜•í Ë.õ#³æú,Ï��Ë”­©ð�®7ØÑccþ]뎜“pã˜"òGU\¦Õ"h.UŽƒ3sS¬N8Ú„¦<ŸÅºi{.¿°Vlk¨}P†ÚáçÙ‡;#“¶9ÍŽÝCkœl�N1ÃfÐ81»åJEu>ƒmÄ=ï;.æ— +R"zÒ)·­Í3“-~fx-tçPU~æñäUƶÆÜº—É𘪊úïcw2ÅããED‘ôøxã^…ó±à=~óÚ6zÎáÛG ¥*úæÞ!Þ>;ǧ¯lb©ªp8­qT×É#uµßÃV—1îUØŸÖ8©›eðã“3¼rp„OnoàÉ¥E¼s~�7NÎÀ/VÂú �qU¡aÆqÝàù�UL5\ûK·wñÌÊŸØZÇîdНÜÝÃr¯Â¯ïl‚™q÷üR˜Ú{Âc‹#Üõ«ý ¯�`}ÐÇ'·ÖEÙ~ó@ÀKW·A@ÊÏÿÈÂHŠ»y9¯ U%ˆ^O.-bg8À·öqRüÆ•m á‹·wqÜHz£g–ÇøöþÎCÀÁ´Æ£‹ W†Þã¡…!n�_à¸nð±M1^¼}vŽ·NÏñÔò_¸¶�׎NðöÙö{~cgw'S03<ê±ßÔxryŒ£º�Ó½½:âý«Ëxc:ÁðƒàEmX_½‚‡®>…ªêgÞö§½Òq/…;³ô¨ýœáäò‹Ìswù±V43²pU¼ÝèSUù·‘>N?­³y×ea­Væ :3‚^"­¤�j;=›àó ½ôJïb$/ÞBŠáâ[)Î’iú¼~»Qy™©BA{ Ž*þðÝwZèá±­5|öýO`<ê£ m¾]xëÂÛ×ø!dÀyªÚW–Ãß9‡@–¦Tùc{Ž%"2DNg7E� .RûhÿvÏ;Q�²“§Îqâ ²—¢ò±N�²‚pFÑqây‰²>18õÌOÏÊZxÖ¨RžRû7ÅœñM¾¨E’¤£ÖVÆMe.‹ôŒ,†©‡•ÕÅ&÷ÉÚÈIÄ-³÷vv)m Èôîâ,`û`ð(ùÆ6š7¡’™t‰k ÙFèžA•ðoX@˜Õ‰²T“ö"³µš¼©øˆE³iÄ»²[Ê_‰l\(ædëÑJ�Åðã™àÙìA®C>âèF -îZ¦=¡‚®„•'•´Ùäx°ÕŽ)hˆ ;¯’´·�f.øM¶éȨ{�¦ü̲�@ f�Y—Â>¨¬À€¤AEW�)ƒˆ­§HÕhæV™S ‘¥>ŠHÙ "E¤!Èš‹¬@2¨…RgJ{¨ŒSÈq’U–Ö»„ zP ­wHjU´ý�9‘É6`�æú£‡X�?›ˆDi£)&€|*Dí@šN*q0';§Ž`Þ1‚ÓHãäˆS:²$Ië\r„Q¢ÄÅaKÆÃ`xïSJ13’z'uÕBåauI2k€êMR¾iÒ…�êmÄ¥[qjMB5ºDW](«‘ Ï %ÃÚÏù³„ÑŸÆIzžq «ˆo÷ß½¦žMé8 朞QðZ³ci+ÌÝéÌN¯ä 9gi v {˜Š¶³™ ÁwßPà€V§­t³<óüñsÃòʼn3R~Ö`£Å³š:3Oª„-*—¢hTŽa~*¡<´û¥¡ZÚ0P2ø¥Ð#ß‘ļŒ–ÂAkìmâÚ™`š. þµ1èÝŽôEóÚ=øAýë¾2¡™w]6Τ‡D�˜ÄI]b ›n€ØB#D#ÔÍ4`:%L¦“šÑ ä*)=€ ¦Ì«X‘•·�4óJµ9ðfw’’­½ j &LðH6 ”÷�D’UZ¼m¬¨MLïë´ $FHLGJ)�OqZ`-¦„t‘¼‹ì£„/çk×§ÉÇŠz95P#�ƒ)üÉB"�²‚1d‰ èÏ2z5³ªYá�W”ŠVå Èç4¡UÎ--tùüËÆ0Ï#Ž­;Üù¯Û&ÁÅm¬jc™gÉ7ÝÆ[iw‰k¾×Æ‹³Öae"Ó!h3—ÁmAdËwzïá½¥–ïx5N[æK©�„ß‹U+õ&&Ô9”„*­P"�€y¢Ú\cq,mLz^Ôxàˆà¼ÌSÈè„Eõ0ò³2]®ÖZå½—Ÿ`óü0ô$Es­µtÞ…˜˜ñ‰ É ø(92-u‘0¿Q=HY"v¬p1Ûºë¥)Ù±òàÞ†‘Ï€1´¦ ˆ`LY ’>VÒEK±¹ã|–wWYº)8úÅXàÅ“N›åÎ,ŠÆ9PF/­sPC„äÍaá²/b@‘ÔB¤J À³^“bíb„ Ì òøôóÏã}�>†ßûÚ×póÞ.f|éøßzýgu¿}e KÞ«¢'ÃøÔÖ¼#LbÄIݤzûÓß>8 ›kXª*œ‡€ï㹤6ï[^Â$Š z#>´¾‚ñ:ýÞá1žXã¹Õe4Ìø£wïâÑÅ> †€óqVx›>»2oÿ”§‡¿ñÐ03¾xû–z½T4ùÏîîaoZãÚÂP ÷*Œ{*"œ5ë}ñößôð�ÃcL‚Ò%¹{€[çøÈú ®-Œðêá1ê§�РqUáÊh€ÍÁ‡ÓuƒOíl,¯Ÿâ¹Õ%|dc?>9Ã÷ŽN°5èãã[ëI±¶XUÎêϯ¯`"jf|ùÎ._Zij+K¸§ˆž#|áÚšñöé9À$Œ|Ëý¦1b©WáGǧذЫ°ÞïáoJÑäÏ\Ùüžþý‘�Uì xçL”øÀþtŠ�A[ƒ>¶G|cïÓð±Í5,÷*ü‹;»8O/�ñ±�U|m÷Žç`üW7ßÁŸ—‹ +xøÚSX\X¹Tx›'øü¬W—÷M(ñÒë½ß]F»¥~Ó³¹ŸyJR̵è…¡®ñû£@g,íöÐÔwÝwÙÇ·¼Ú†�ü¾„P™lÿ[O<dzŽÖÍí2‚ÌB˜¾Ã„ÇÍõëX¯ã­›¯áüâ§1âìÝÅ‹ c¼0\Høù×_íj:F€ûºŠÿ‘—š,v•ßíÝ+ý^»1! �†ë #|{z�ÿ¶S\xi4À‹O?Š;b\£@[inü…)õᣄ÷Wž³%##ñóŽXh²ã¤pH›·µ}ôŒ?å\òìw„œzD=í™Å{8UsÔ¨�ì‰/Ž QSæl±ÖÆ¢07›²ÍdûI|Ʋ‡.'ÞÈiä„ðh]èñŸÅMýÕ÷l>%¿½7}8íi›¤ÅÖP„¬›ã$ûغ’·5YÁ4¿Œìq�êØ ‹A¤qs�0.ÕŠ©êz$�‰9Ž%qV¼Ç-üÄê¼ �L¥ˆ¬ø7��îe! X®‘øÄ…d¯pì!z‡ŠÕã;J� pb5 POŠÝzÉ{XjP‰RXÒj¦å`9Cà-rH rY7‘2r… “Ͳ¡Á6¨ !E¡[5È ç<ïf¤È4ˆ:°"ðâ:Ž`š„GÆÂùì&q-ý“{·mËO’ŠyYÙŸŒúO„á+׬¢!.Jµ´寬‡@Ã"•cˆðªC`–¨O äu’.ë+Äá+‚<�¢ØIc¯ï0�™4EºìŒ—kHÆ´ï‘�âH —ÃËщ‘‹(?=7¤zѱ0e]Ž£\8Ý£+ŸÊ™Š 1J!mf†¯*øJR ’òCÞ‰ÌÜcȼCŠ*8Ý=’ßÉCÒI6�Æ5p1 „ˆäC6^JŸ9|G™çhñY0”A¼ð[œ�N—I^�wÍ×mÌ¿æ·+‘YçÅ­÷\Þž�£Ü¦Å¡¼ØeÞôíw¸º8Ád¯O|ìœwÿÚ}9V±³ÖÅtæôÓ~Þ¡ŒBmº|v~ly!ËÓ6 ïkÑ”ÎX¨£ÉLGºUq²s:{ižv Ó; è2ÌKå {+ò„:yì˜9yL€¨¹ 3€«ÂÇM4tfåóPáóm 7ÍY�ç;€Ò°ì@t¯¤ÏÑ5˜#nÌ>3sxZéü]Þ»¬íÏrqçç%mÊWùYK�ˈZë2‚™˜¡ Ô¬„ç‚ÁAV¡ ˆÁ#(Ác@¯ɳç=Bth‚X˜­¨¥¼F ZJ4bLÈBef((g2÷Œ¤§³Â=#Rf�4ý†÷^Š�9 UKlz à()9H “Åþ ƒ/¹ó$U€¬ø„iJÏ'š …C3³OT®·0C>ÁI(¬¯¾©Ð Q˜´h^Ò{ÔÜ‚ÄâÅkŠEXþESDZÙÄÈ”‹Ìú¿qG $ÁE¡(!uJ§G·FÛeƒÀ<äÛ…ÜöNóÌ—]ü2«€±ïn¹˜ §çÐÂŽ‚æ DŽ (–ˆûråI¦õ+Pš  /Äü~›ÝùÎ{}fDºë‚Özdƒ2¿VF7§:ÈCŸ�éùìAzVŠˆ1 ÃuúxñZÏžøvà…€¶Òe”WΤëªm™µØ—*Ð`" =f˜a¯Œ~1Á[æ¯?Ñ!@¬&š¤ÂŠí³)ijÞ·È‚ÚûÇpÞÁGŸ×ž,ÚDæoý$ù�ä«”Ô�bÊûìÈ�\ÔÂj1¯;‹a Wyx/˜wÞU çAìD¸ðÓé4 ®N%à�F O³ �/7Ñ#ÊÀ1æ†Èê%$©°ÄØ ÆV|> X_^Å¿ù™Ïâåþ_ùö·1©§8V…Ü?>Üÿ½½�¿¹¾ž¼û_Þ?¸çñÄXÒ }÷ð?99Ão]ßTްÖïÁ“„À½Oé„Þ9;Çyˆ)UÑw�ñã“3¼tm="‡ˆwÏ'xxa¨Âþƒ«ËXìU¸Guƒ�m¬Þ>»ÀëG'ø•�U<½<Æþ´Æ·öñØxX]+¼�a§‘ñK«Ë8k.š€×ŽOðôò>½³™ oúøøæÀ›§ç ×Ë "\ àˆ°Úïãí³ \ ñÐÂCïðÅÛ÷0ð×H„?z÷.Κ€On­c}ÐG}~�:FLƒ¤¨ZôñÐÂ�,.à{G'8k>¯kôÕ{û¸s1Áóë+¸1^ÀË{‡ØŸÖ¸¥ï\ðï°ÙïãpZcZã#«ˆîœOð•;{øåµ<¿¾‚ŸâÕÃc¬özøÔÎö&S\ÄO„†E©we4HóWïíãÚhˆë ëh"ãËwöRº¡ýi�ÿ©å1FÞ£ç.BDß9ܾ˜`}ÔÇïÜ»‡/ݾÙÂ|ƒþ×®<޵•mÁp%þcdÑ^9*m>Ý™mo¿ü´^%=iÑX\ÎÊfœRRÛîw³M)€•ôi6"îÁhϼqµÓøpùe‹_N:9d¢=¯ö%íK¡)ã\ûžgÞ×W[ˆ3e(c#Œ†cýž:íÊéÚwI1œ"4E‹s¨¼(Ô|eÊcF BCˆ!¨òMBV«9 „‡Ð4¡D]£´nÆPë8Œ93 x1Hd„“ŽÅ×W„^z=IÑùXžo‹²pQSÅf'ß©ða…mÍhÁ�5²ÅÎ(ÀàFXCc&Íø—Ú¦ô5ù¹ä¿ñhà²k1{�vÜe �ÙÍ r{F˜²á—VøÌy0BÕêÑ4 ‚z 3ލ9¨^aZæ¶§¡àÊ˜Š‘’St� ¹æ%Ü#á}�ÞÀõ­|íÕïàõ·Þ3ã(ü·náÿÞÛÿ³³ƒ__YÁZ¿JëÌÌxvEŠÓF^?>IÞý�%¯ý£ã¼OÓ ½{>Á”³aàÉ¥E,x� ’nb\ùd`xåàžÏ®HabóØéÚ6Îi�ãå±Ò«ðáõl xëô'šŸ¾¾{€[|zgWFÜ:¿ÀÛgXí÷qc¼€¾wxtq„õ~gMÀiøÌ΄›ç¼~t‚÷¯-ãùõ•Tÿ`{8À¯n®á<œ4 *={�O/�q\×è9‡oîàÚÂ/]ÛÆIÝànÝMé†"K<·2†÷ëêUÛw·Î/p}aˆ�a«ý¾t{Ž€Ï_Ùá÷nÝÁ4D<¿±Šë£!þüdOê,4 f¬jQèk‹C|ÿèç!àã›kX¬*|cï{“)ž]Y“K‹øÚ®$.BÀ¯ïlâ¨n@$†•£ºÁIÝàÉ¥E8"ìOk|}÷Ϭ,a{8À­éÿóÝ;ø“ƒƒ–RÑû W¶ÅÖÆu”ÅhIô¸D/—Ó—÷^îsqAûîÓ¦ü#aà9Â]ë^§ãK¤D«³ VÒ£y‚Î_¦À"ã Ûôiv,Hò„ñ@Y`›g€0åþü|WØízwµæ3d´�äׯ<‰Õ•m¼õö÷p~q‚3Žø_÷wñì`ˆß/Ï÷ÎýÅõS]¥QÜeWWY0òç…Òß«"²„ã®QÀ¢–´P±õ6Т7“±1`ê ÿõÝwñF'åØc[køÕ§Áòh@Òùå!Y”¥žM BÆ¥6ïTð]`…dŠˆšÔAœ‰L Ëb¿Â½Õ'bãrÚü´ §üäl}š�>Q¾i*Gï=ØΫŒAj” ˜Œ<‹Ñ+­'5 ”ÎÅ Nõ›²´b¼Y[ñ‘x¼BÞ'íKÙ¤BÚWÞÑŒ1–Ƈ9)V%J‚ßD”ü´T‰›ñI!åè6°¥MO¬rÒsX%eã ŠTDŠ´ò~’�Yyc°(¢�ð˜Â;+?Lœ®³?µÚSI>‰ê çDFui}T© Æ�À= ã0ßç¥ÑΉåã¯î²ìÕóŸU™ë*� „&Š#Z V/ByxÊQ)uÇxÔÙâÁ),E­?¤h�d° § �hˆ$úÀú6Òm[™Ó½ UmšÃéN J;õoT™in“áœô9£ROFK_ «’ä˜B™ÀGÎL6°‰¡CxbÁ-.­{ëd8†ƒê 42¥FaPC!;À“Ä¢¦Q²z&±™Ñ/ 20(d#¿9/ÿ/õÔ$MT¢Sh¢7‡aQªh”q¥z£pÊ$‘=ˆúpÎk­F<¥4@í=-¹ÔÛ[xðˆj­·Ödþ� �Ÿ¼â}rªñ’ò4¨áLŒ6ªMJ°®2+;-FŸAŒau#,Í@Z‹.ë?Òè¹%J"�#óMék8Ëg´ø3Êm’’Ò«Û*݈�o�ÂX¸]{eîÿÎnÛîýùãç™v] tiÀIHRE·�ë”ÇPsOæ¥O „Øû°GD@‚ƒ'—ÂÆÌ›]”Mb<¨=£rµ‹è;Fã³²{ZL)$OTó×�JÔ“Ç€…)¦µµ}&Ds'i­„LÒ4„T¤ªç�ž—è†^ω·+B 4 ô#äÞ!¤¼|ÐÂ^ †÷í½ vpl?¿Óf¤^<âÉÃ…bQö,F Ý $ÞÑUÔüã)´j�g4šž$å&e¨·/‰·sˆhÌì��£�¯’õ)û‡\Aɘó~oQrc+dÇ 7Pɘ±îD‡�ÎGZhÃ~Ñœ��ч¹€}— ¥Çgö:Ës$JÿÀ<›©µöÎ4ÐÁYxéÚ*"|ûà?9=Ç ›kxxq”òóv†4Þc±òXë÷qŽë¿²±"`wZãõ£}<»¼„—®mã­Ós|kÿK½ ŸÞÙÔôDµ9£�˜qu8ÀQÝ`Ñ;|ÿè�Žðèxçðû7ï`¡ò¡kO,-b!ÕE!Œ*�wÏ'xlq U…�aÿâîÀoìlbà~ÿÖ]41âùõ\_áOÞ½‡aåqÄÿèæ;ø“ÃÃVšï<¶6ÂöÆCð¾BŽ‚Ò.¾y¦ˆš³FŠ2^3�¢„ב$—’&ž:Ý IDAT”¬ç<£Qç]¤T¡Ã4—FÇî€KQ#s7má 5�λI'b?­eû5‰aÆÁ§Å?gZ‡¾,g/í…§µ U6}Sæ#�)°PWÚ,x×O}ýLÞWK?¡8Š]^wõ€Í^¹Ùƒ°´¼�_zîEܾýÞ¹õ:bŒxur�×&øÜx¿Üþ"½ÐÏá"ˆ²þ¢0TD©N €–Q@+EP·fÁX éÙ[Ð?‰›Ã–F¿³{¯UXÖÆ øØ�àúú ’-µŒˆM ¯4^ø4;qb °ñ£Ün'žï”ø‚N¾D˜„IñàUÞŸ�÷ÖwÄ"µŒ§ƒð‰Ž�ÈLpQ"5=<"y0I½!1NP–9˜RÚ1htI «Sµð'Ù#YôbèÈç�•'Œ†ò9œy\s+5ñ¯ê(fø#9Q†G’NIoÊ7_iQB³=o0&’Òµ‚G4Ù„EÆt1ã “/È6ÀžMºy.9vé:ó¥�|5I Xg/wkæåU,¢—Õ P¾ _¸tÂ"Ý/…&ͯ2¼óIŽdv)…¨ÔÉ*p3]CubS%¶ac‰ÚÈ2˜yP§Y‘¤•%¶Ý61ã?  †'“îd¿Ô3E±läŸm VHn+¥™¨dZW9…Iþ‘›VÍbulž&§!�11 Úº0å…SÖË{\êÏŠ)‹®�ÁÎ<ÙEfàHÅrU> ,õãMÐs‚½“ã©þˆFt8"ø õ =Dém–I½ NÒ `xö’ªGå›&ušèØ¡a‡&:ÑÉ ‚)"  Ž ‡m ѶB—í'9ÀUˆ¹vE©äÏ.AL ²æ14!¦§ÌQŠ �ƒóæL¤r˜Eùp„… .¶íS=Œ�šIà­!BB*xb°Ff\’¹8—q�ÀeX/QO©FŸÌØš%yãU�qI·p68ÚY¡’gäVÛÄ5–éÕÒY(øÂâ û�ô]DåÓŽL·|Zçlˆ�ó÷%—|?Åxê&3¬�ùç?ʹt¯,ÏSîGõ±déæR‹rFíWeXÊ8FZ*Ž7ÞšÊaóœþʹϟ¿AL©'(ç@…žÅàƒ)�¿¢ ΀Š(�ö;¹èÔ~e …ÌT<Ï(Ai‚ 4 ›°y�™ÞVv+·ÔrÀÊÁ¥Ž)3 �%*!cÕ\«Éå‹ÜÞ”ym3€péõ í2 B 0lcÊqÌkýž6ï5ßÙ^lLYhÊÀ©£´Z`X´Ñ$\]ƒü D@hDi>m€&ö]¸ žr¸ xÂÒkDÙÝ0z>"ø Q‹â=0ê†qîLó¬F6’2·ÐpG6£‘&&Mˡ̳ÎÔ±±ŒBš*'Åz< ÉéÐwÀ°ç0HÚ#çB Ô50©Ói@tL1H(¤˜�0¨‚œA98€½iâ”sÜŒR<,êïÙX�8D5¬¨RŽØËlÄQ‡ˆ¦‘¢9–÷äÐDBš†Q×S«ÃÒX×´ÀE †�Œx’€õRŠ— šÉ˜)ˆ‹SÐ�cîZÌçÁ»�fޙᶷ9�~28×VJ^6¯˜Úä£Q ~б–Šé4*Ψ²˜8’ç%ºÀ3r1khŽYdFܵº‚ Ω!A•ó–ºÆN•y¦e¯ % ¤^ýšfÊÞFà˜rÿ“ —œZjÿ’ӱɨ‡‘Ï2ž�6`X"\Ь鳴.›œ×Ÿ�#  {/ïVE¼½LH¯* ce‹Œia¿<>sv—¿Mɤœ¡E>é±É!êò@d+¶†¶€´@ ‚óŒé¶ß]8ÑÂdq"¤y0\ŒðAÀTˆQ¹Á7Âh:B¿Çè÷,$["°š G=ßCßé§êcÐëIÞM[I` èù®ØÜf$\–Å àœs¨ap£iÇ"+ÎuZ & iÑzÂL™H€º fÕ…i› äÈacy¿õ±Oãí{·ñÕW¿…½£ÀkççøÏò<1âïnmáÙ•1N›€ÅÊãsW·?8>ÅBåñ˜Öxyïïœ_à·®ï€x’Ó0òK•Çóë+ØVE÷4F|T�?>=ÃÇgxq{ãa…·NÏñ݃cT$^þD„Õ~kƒjfœ7ßXp4­ñý£¼oe ÝXÅþ´Æ—ïìâIÍ×Ïê:)ÊàÆÒ"ΛÂOÎððÂ7Æ’ßünÞÁJ¿‡�iÊ ¯¼s�×Gô¼GŒ–—UÒf\[¢G„�ѹ{OÀg®l�P¤ÚÞÀz¿‡oîâ¸npÜ4ØÁ«ƒÖ}\ ðÎÙ9>±µŽžsøÎþÞ:;ÇG6VñËk+xõð?8>Åæ �¶Öqûü"yÿ^„€³&¤(�ƒI�oìàÆxÛXÃëÇ'ø¡î×g¯lá¨n°7™Ê>©²gcÐǽ‹ ÎáÎÅ+‹CüÓÝ{øZ'e�s[ëW±³õ0*×—SV¤ú’SQ¦�›á�fk¤©Ä„>Q?¥¥{ö0yÆëˆÊ¶"7º,5Úܤݡòg&v9Ï�=Ý«Å3ê?m/5£ÛÖÚÜ5İì¶y�y¯´Hñ‚¥K("ͬÊ!')Ï4²I ‘ÁLS”±5Ue#—"�ð¶&°‰Àlª5ÀÛÃJ£]«Æ“w„‡z[[×ñ£7þ%ï!ø½“#ü)�à__YÅŽ«ZFä_\÷¿šû¿”ˆJ£€¤è¯ˆÐ”F?å§ÊÖ¡ólirMƒŠ-ŽpÀÿt/Ÿž¶Ú-�FøÐ�‡ñèÖŒF=I,Õ¡ñd¥vê’¼jÆ%�—ž KÃÁ時ÌÏ•¼4ZǾlõÒ'=r‰áDö66¥&·�8(IQ`�í <"<"<;V>‹$BÀø‘ÈSÄ:€<˜œÐå«•Æ`õNöÊØŠ|¥ëY°„ œ7|eü§E<Æâ§ª{)¦šjˆb4Àw" £Fl†vò±ïÌç�Œ©6Y6­9'~Ý Ê•¦½I5çbNC‘Ð!2ž7œb÷ÒK¨ýb_+˜,xË` ”Þ˜ËAE(ª«K‚Õ«Ò±[aUVT<\¹ ÷”hų ãùE ŠIiJêAí8Âií'bó>—5N"“FŽÊ09E‹±Âlgˆµo}�iÓYñ¶)ËY�y²Ñ'Óݶ¾CôF�Š[KZÕ´·N53Zå %XQq�¹2r€[íäÌ‹²ÑR™øá¬(o‚ ØÉ™‹bã«ÊyDvð‘RŒ¾‡d°4T]{b4 4ªÊ¡¢œ ÊtÉ - .¬ÈÁ7Ò¿+"›EW^é9’½’(a(Õv˜ªn&èߢâäyÿöެDzì:ûÖÞçN1GdDäÄX¬*ÇbqÐ@Š-5©�-Ã@ÿÿ?5àg† Àa7lôƒ?tl©-µŠ’(ª[¤DŠUE²Æ¬œ‡ÈŒ9î={/?¬aïsî�È*±-ÀfŸÄ͈¸÷Ü}ö¸Ö·fùKö-W‰Ot݈$ù‘ŒŠŠˆ�É_ �së{Ù [E–“s‘8¢Ug°ÄE‘¤FZÃ4 ¨ÉmDY�$*ƒ¨XlÆ3æ£ÄøB÷>mÖÈGÏkª<«ÞÃ…P”G5Ýêí.Æ�‹VÂNq×ßÉþ=„6Õ] ¥B»«9O©ea©¬ŒÆv:¬¼“”ÁˆÀ)ûͼbšêÇŠµxT%«7µwÚR ×xÉðµc²pR-ôä…&KGÝ6]Ÿ?û@û#u‘3äàrаNd {g÷f$@Ójטq!e�>°ðl/d…™dFîà ÷Êèã+Ô©Ÿ,�Æ—ŠJ;2æ•U¢’öK À@Bv/¨Äë̼�¬?u8ofó‡à*í5AÖ�<@I ÖV¸©ØÃRó%· )‡¥„‚äÄÀ�üL 0@H1®1 Êœgfp"À„?zEÀ(^+¶×ígv¹¯@)†LZ™†XîÏYŠ‚­Î’:>3Ñõæ)Ò [�–;´iÔ˜ËÅ&ØÒԤѬÅ3Ö?Öß K“|þÓ_Å£½ÛxëÝãäô'œñ¯?ÂvÓàŸ¯n`ýCcÿ_ì«.‰:)„úņû‰çO‰µÖO7´Ú48VZuy<Â]$ü×÷îàݳ³Î÷—Ç#|ö¹gð®Ð|Wdê>0¹Æx§ñ.;W«·h�+ºÀþʇ–F±~ßð¢£vÃÿT?“Í잇ÝaBÚ>,· ¤ N –Èpƒ=m¡ë,ÀÝrîèÚ™Ó,¡(Z>ë˜HA½{Zð©ù_0P•£€á6ô~·<О•ªÉ·~ø\ûlÂZ1_IS“* ÝÆÒY„"wpÃ�O´F¡]ÃÞEötóÆ6¤s¡ÜÈ÷PÝi+Úg®B©duÁ¿f�\裂-�Ô9`.5*œÝ‘'g� εç&wüÈ¥N�õ«°ßS"Ÿ˜¡@û¬ýñ49€ð3ˆ£xÈ+�—¾嫹ó‰Ò´¸öÕÂÝ<fg?V?®ÏçÖÖæ¥ÚÔ½\özÙ݇’7�;ëéë«óeÑÌPSt|$Ì �ëšå�‘XSŽIƒæHÈゲe& Õ/Hz°– MšX"m<’ÁʼÃeþ“F4˜Cæ,eœimËnj5ë3'g½4NP3"RŠªûiGq¦“z(&c‘Ëhö}Ò‰Œš¹HŒ�5fˆžÃ2/ØÂA›<“€Î) �$ÝÉËèVÎ,饳Õm‡¢&ÿgN褘Ü j ÕÑ÷1Á ?TŒ@Ç‘­s™Bœx !x�l�ˆþ¢âWF3«»ºß‘¹ôÚžlLÏ)ŠSŒÊçT>ëu²òQéžS6BDè?õ¹«& ‹ð¬}Ò™ý|ÖíàZâÞ³çZ[Ð�<�Ã#Ô{ÕMòÜ{ý>u»ß¥?ó ÷šMÕÚ¡ZüMóTª)ׂE-§[©UíC.ž ‹¶Å¹}ð/é†âj ç\ ¦ûñ:oãןÛÏ~/ûŸý¼£èŸ�þÝ‹¶•æë—UÆI¬)„ En¬˜‘�Y Ãjšà…‚ @Å6>ƒ% Q&ä6 GFÒ4BM„( hÄk€²©,ª¤aL”«£Îȉ”hÇÄ@P¼N€&š(,‡ƒ€á@R 5 c4$ŒÆ’&cÖÍ4Œ³)a:fm+yôX”p ¢„³…0%פ¼Ä�õ'!Fñ¸ Qr±Û‘LüGr–"@Ér§«1"@¿ .(SR…�Ö* 2«@_Ô”åh:›Ç9ç³Ë0æ?ãÞßç\TµrÞm oÚ™À":¶°­¾·$ê `X¦°KáÁõïÒÑštZèìÅ_<_æÑ´¾D6rÞOQteТUqŸR*"-ÖbÎî¡ßíQe"re€x$ 2 ¤ä5*ʘÊ8Èùo©êžÌJG®¤n¡ñªð'R¶SIÙ÷½æw7ðd`J�Îä¹(†¥7.ô6™!…¬ØÂâͻÀ,+0Ê>ÿ+O1X°ED :çú8‹|ˆÑ¢ Š‘À œ g?ZGe.ƒÖ<‰"%žYÒš¥d^�Òÿ”ÚÖj"H ¨”b)lh½Y³#)�BÀ, 0 C%û†¬½GLÀÀºÌ¯x[™H!ûÅÑq „Õã�jÐÀpa×á521^yþy¼üì3øéûïãûo¾‰'‡‡€wNOñ_ݸ�Ï�'8Eüæ°Á˜‚§å¹srŠwŽNð•KØ ±7�á{÷ðÚÖ>¶4êxìqK"β¤&zny _Ûá¨Mø“»ðâê²Ö4`Ü;;C3%¼ …�Ÿ_YÂÖhˆ!îžœa{4Âo_ÙAãÏî=ÄÕÉŸÝX û³œñ­kRÓ ’‡aï°g–'D¸¾4Æ[GDøÖµ]Àwî=ÂÞtŠ_ÛÝÂæpˆì=Á½Ó3쌇ذ<ˆØpy<“é Ç)áë;[�pëø?=<Âk›RáÇOðÖ�¤FúâÖ:f-NRFæÖùõ'×VpœNSÂ[‡Gxem1g-¾}ï¡×,8h[üû‡Ýñ™õ54!`¬‘ ãðîÑ1>±²„�Ñ—Æ#üÑ�û„€ß¹¶‹Ã”ð'w~y{»ãnŸàÚÒpðÿÇ{�°×ónâ»Û×±³u14�Ïê°kãý¼ú&,ÚņoË;øëªC¿/zVñ0=O8¨0ÿâ'ýzwN;•b¿ó YBεzÉ)�VD "U•k·ÐÄày…Sk®*Ñ‚0‚ ÅY3MIÔVŒÉ–VDzRálRšŠ! 6 ¸€eüÂ~G�Úe¯ì^ºŽÝK×ðÁí·ñöûo mgxжøŸö`·àŸ¯®c­ÃéþÓuÑEH˜/6œ«û"‘{ÿ󆀹tCœñ±å þ~zŠyï6öèÇx8ħŸý^¼²‹‚;Úèì‡:}X‘›«ã« 0Pñ«t›ãN÷äÌÕѨÈAIKTaPRç¡*"Æz!�/g0«Ó„è½5/÷‹¬P1�Øø3#g©�G^ÿ±xUËþ+rm}YÒ1'X�¤pf«Q.ÒäɆ]m?HÄxÎêž3‹£žD¨t¡˜WœwÄ@Wr³Û\«<ϪàâÄ㲪éâôê%¯^Ùdd°Œtv¼NÎ6O~^}Ÿ8 u$=]ÇZFæÙ]Ée�Ë9*Ya*Lkýò¾è-…¤xLÞ(ÃPŒNZ«�Ä’’îû\”ÿ¤†�èw9àc$ÕßdË<@åüb¤ ú�…æ5A²„ªßbú‘=•õü0kº"Ò4ÄmB›%­�+û)êÃܪ®º€rVr�öð肌 ‰O¬º ‹ÖÅ‹ÔÒ"Ëž/ëLªk‘s!º(K[ fpjj@ÅžŠ %KÌ9OñH ˆ¨£ Žš1G©½�¬øFúhÆ*yŠ8Ö³]¢D�ι®»7º8Õ?“œ �ýÖ¹G…åŽaë"âºÜEÎÈ�1'M‚ÒÄš©ÎI{¦£ƒX›ÿêõ!dö"lÛÅïuÏ„nÍÏÝbE}Áÿ �®©7^—Ré…ß±>/ª[fŸ÷¿÷¡"J èþ40ºð+šI�{_ѫѧ—O:‚‡n.ëla"öW‘ð{}èÄh‘·ká“5CîÂactåGML¥‹¤c®ÀHÿëT-Û9“SP3ñîÏ�rÕ}©ÚcÒsý©òÂÍ~Þ@.ú¬îÇß{Üùxñ˜�øZËßÄ�ðM��'ñFÏÉŠÑ e{AjéÞS”EÁ@’ää,{9)Jþî¶bkÊ7B˜eÉû–J@ˤ–j«3À’«±òP!(ÓrOÔ*ð‹M`4�0Œƒ6„á b4Œb F#`4’¹¤€á ÁlŒ¦„Ó3ÂtJ8›Í0k“{RD h‚¤7‰Mãó)€”Á ZWÀ#1B¬#9�ÔHY”�zvs6P*¹4ª�MèYÓ¥–œ„æñ“AœEHPO]"aCöL#övÜËná¹³ë,ÏÈ‹§ªFoßy› ,‰ª½¸p/"Æeïu¯ ·D�wÄá‘Ò§Âtª¯ÚôMUϧªá.�4Æê?µïA‹ÁÅÝ0 ³Z€D äÙ¹pf1˜a M2DO]Ò5 /LÏ×Üλy½ÛsU€°h„âÕÏõÐt|6¦:g­(‚Mjñ´G¦`Wá´…äG5¥» ž&ÄÈVÏ*PU‚÷È`Ô9e¥ŸÅ›(c4A™uã’KÄ5E®hk�ã ï«~ïO]ûA.‰j¬0“M,¤ØŸ£óhŠË`†‚Ù#�‚Ö¥ÎA«a[¶—¨Û¯”’ÐÄ™¬_Ó㓜u®4�‡D €0À¬•è"�„H£b…ÈRU™êO'ƒÅ»NŒQé“Oš)3”N‰Fé…ñ¹_À«/½ˆŸ¾ÿ¾û£áÑþÀOOðÃ;'ø7â[«kø§;—ðÜh¤Ê¤²=7†|m÷6 î©ý—/‰·ÿ�àƒãüÖU)¬ûÁñ)Þxr€­¡¤Ô™4Ï.Mpu2ÆiJ8Kÿd÷23n�œâíƒ#|ùÒ®LƸsr†¿~¸‡O®­àåµI[”s'ÅÅç6Öpš3ŽÛ„Ç'xvy‚o-/á¨mñÇ7ïâÊdŒ×¶ÖÑæŒ×Ÿ€xne À¥Ñ£HXŽ îžžá¥Õe\_š`µ‰øŽ*êm÷Àïß¼‹–߸¼�å¦ÁO§‡8KgY’¨]�pÔ¶øøÊÞ>8 |ãò6B üÅýGØ›Îð•íM¼<^Áwìá¾ÎÛg7Ö0KR`{m0ÀÁ¬ÅQ›ðéõU CÀÇ'¸qt‚W·Ö±1hðÓýC¼uxŒk“1¾ti·NNqÔ&4$ý†€íñÌYñïñíã/漆Gƒ®]~Û—®ƒPR}Ô࿨è]ø/Ô]6²˜˜º' ycOCq…p±Ø·©âÿ‹ã]½�ºJ.†Õo³×÷¢äxêzÏÓŸd‘¡¦¨!qãÕ'Uµó•ï5�D?�� 1C=Àî¥,d‘6Y÷)F(¦&éP·ª—qÃXQþÙßð6ml&£‰áܼí¡ÑÏ¢èBãƒ=°ÈÅ �Rec©ä},Jr»L ‹:4t2XŸ“�Y|#8ûq`{©?73ÜñKÒ)}4,§s+xºœmh$¢ÉC‰ ¸KŸm¯Ì&ò`sF“¨ð —eÍ…¯‡;žÆÒxÀ^³ã^O +WƲtP†ímþí~u¾à€[ZtT¶ Ð…Ü8ÿ1%tÍ*Lj°�[‹üÌmÊz+Þë jëÄæ…oë"¿¥¤F�”ÑfB«5èRÖt1ÌHœUôg­!eÈv>`{Ž;ò ý¤2iº×¥Ÿæ!žu”fô¹ÂÒYy䵿ÈäÏvzî›jRŽŽÂßx�ža›Æ;ªûlV@¡ðt²Œ ïg“¯`?Õù„xæƒJ„‡DN‹R6�ȼø3H2pÕ¥T¥¦€Ñ%3ˆŽ!ÅŒH *gè’H’1U‘%T IDAT²Z�žøO#HR'ÉéŸØ¢9Ô-QN¹F@³¦ë“TF›Ì�ÈöH91%Qœô+9U}®�»#‘;Du°ÈE—¡ shŠoMUösGd5JŠ[©Á‚ªdDŒ2îhº2Övƒê DO¤¸8ÃkZ›Î ³wlÔ†a]ŸËš²è"„¢Û5~R3FmwNAÝÁªež�ÿt¿_h‰<ð°o£ãª3ð¯ZhÔ¢>»‘¡;~VLK>ˆº¬´¹K™©úY�÷ÃàX£UŒš ¬Q}·Ë×§|jL£îŸq½Òfÿ™¶÷ü‰TÆoÏ÷ÛvíüÛ:7s³b�«‚…ãØbÕƒ* ¨ÓPGIÌÆÃÍ™§×áÞNê¢ýð�k3¤À¤×Œÿ|úâ.¾Î?HO¿ºeþ³‹ú´èóþ{Ô{ïimÖ×Eãâê·z=ûÏ«ïÕ­÷Yý’øA�à–Á-À­“”J¸­m/ûIê oÖR˜QÀ­¶€ˆðpÆ”$J i¥ÿ�±Éˆ³ŒÐ2(±òÈæáL,Þõ6ZQ.I>M5 è�0h€ñ0b2Š ãaPƒ@�"žÒ"Ä42rHi€ÙŒ0>ãÀé)p6ÚY’ÐÀ ÊýAÐ Š'BÛf¤V¬Ì’g2*³v£@cêJK×ÄhÕÛxFb²o�>ƒ9jñÚ0™ ÀžѼIÙ™ SuxV@†ÏÍíŸB˜»éWä¬ÃÛPBÓì\cKf°óï;ºb‹/}Μ4^ÿMNØ%£…Ñq°>—ìcä]îpLyÒtþŠÀ¨o6Á#Ì8`SR·Ôž›ax¸®©rrz-Â`ÖpxBÊÙk-ˆrZ=øõ yÿHŸëÞ ê5T \2ÄJ ‚y‹† )´¢)¡Õ#/¥¤ŸY•?B8Z–Rf ¤@4Kª%ñ ª<.Œ‡±�K�ÖÌbÓqÀR-)cŒ¯ ðfuçý½Ú-4̾XÛ7ƒGçu·˜æÙ •q@Ï›D'"4Mƒf Š37 x¼fÔ€gI÷€¹í‰Ò½mmïFñ|Q#T Á½edý%b ‘Eh¤€zæp³CP¼ð ¹…U0Üä!Õ­�&4!øÄ¥”�­¬F“`f’TXQ”‡_ü䋸Ò+/ãÇ+ïþèG¸yÿ>àN;Ãÿ²÷ÿëÞC|ye¿»µ…_ÛÚ@ÊŒ?¾÷/®-ãùe©;ðæþ!ÀÎxX6 ’šGm‹«“¶¯î`~°÷»ã>·)Þþz÷Û„ß½¶‹&·’Gßhßöh€Ïl¬âÚÒwO¤ø¯¥&úáã}Ü<>Áo^ÝEC„wŽð“ýC¬\›DD Æ€µáÇmBËŒ_ÚÞÄ(Ü<:Á�ã|nc «ƒïãG�÷ñÌò_Ø\—ÁÓY%V‰1a–E�üÙÁ>±ºŒ�¯.!3ð{ÜÁµ¥ ¾riÇmÂß?9ø–Ž+³DE"<8›âÅÕe,Å€«“1þüþ#LBÀ?».¿÷Ád_ÛÙÂÖhˆ?¹ó')áhÖbg4ÄÚp€aåÿ­ãœfÆk[ëX ðg÷‚¼´±Šoïïãxë-Üè¥û€õ•M\ݹŽKë;@”¼´)%j:IäÝ9sŽ$áTƒv¡®ÅéŶø? G.JJ¤@ úòÏ"獵…LŸÏ ü|ý^øðްDPwá ¯+n©ó œîIäSðs=hQF$‰k•O�Ž!#˜á"Ú¤`DdŽ0OUêÑåŽò§hyÐE-�Öžpõ]R“k4šàs/ ŸüøgðæÛ�woþ 9gÜigø—{±~wuÏÅÁœqëýê ¾È(п–›ˆ£¶DL‰JÚ™ŒðV;ÅóàÞ==�ûÞöÚ*^ºvW¶6]M)+ÿç"ã*Ö±}â»Ù¶ V Êžq¼ÐÙV”Z%ÕwÙÌ+®M�|ÕÔàÊT£…z•Y/«weïÂp©ÜU†ÔKŒJé.Ø °š„¤i82A#±siÎ&žŠHi«á/0¸ò’—ùõc&I¥jJ~[—âæ„j‚%šÁ¢ $=RåçÈÚn.ŠaÑÕ©ƒX¥„«�ÆSZuO¿Éµ2L§•¼R Q®ZJSbŠa@ë`)x2e¶¯…FˆHz*íg®÷känQd1Y˜âóŠ—âùTïÇ œTõ¶éGºÈúÆ…9r—<8½vrĽ¬S¯™i÷?ùX)}Á5¡3‡¾1zzóª32‹ò·6BthÃוæuH¼ï�jNaé‚”i³z–7‰ èe ñÖKB‘áýé®�ýM7v„‹ð“(kÌœÁl‘ ÂÜæ26†Dú‰àǶ~\?ËúR­‰z¢/Ro<êîg`Vß@€s¼û¼Q‘HkàjaÂ~k9E)¼ÖÃRçî�MÄp0Ã@C²rî^Ö�.ˆ1ˆ°ÍÊd逋€[¯)W³cýÊ$º=.ó*‘(bÈL­¶Ë€ŠSe•"A ¿¦„�Çs-4ãFÓD bðiM3 )°÷´ *©dõ¸išFŠ3Lj@_úäKxíå—ðÎÍÛøËýo¼ÿž§FúëÃCüõá!VcÄomlàÕÁÃ�Ž‹ñµ�-$ö¦S¼sx‚Ϭ¯âúÒΦøËû�ðêÖ:ž]š 3ãñÙ M¸6¾xiNÎ0ËŒ»§§øøÊ^\]ÆIJøÃÛ÷ñìò/¯­¾óø�à†�†ÄÓ?BÒ=»²„AŒØ�ðýG�±Ò4ø¦Þûû·î¢eà7¯lc#Þ=<ÆÃ³)Ú«ƒ—FC\_šà¹å nŸœ üÆ•mŒBÀ÷=Æí“3|ýò%¬6 ~øxïãhy ¯n®áîÉ™B¸RÜóSë«`fÜ>9ÃÍ“S|ak ËMƒ7žà­Ãc<¿²„Ïo®ãîÉ)�MÑTJ³­ÑӜф€Ÿîâ“ë˘10 ÿ×Í»Ø�ð;Wwñx6ßÝ}øÆåm´�p ¸ÿ?¼w{ÎNÛÄ—/]Å•ík'è_ êa{ýü{å VT×å]‹øÌyÆ�λ4�±z6�p6X0tG`Y$ÔôŸÁåýÓßE—s¶^…gôæX¡æ{æ g‘s5ƒ/}.^{¡c8¡D˜Å†�I.e.Éð�ŠßQÙ¶3ÊH‘Ű@Ù}Y,c2õR Áé¶�¿x™U|È<8-‚E\ÊŒ†KxõS¿„—Ÿÿ Þ|ç‡xÿÖ;H9á0güïOö0 ÂW—Vð¥ñ¤¤nù¿j£@}UO?: ¾Ì(Ðag2Æ!2þòèß¾yÓÞ÷®nmáÅ«W±±²,˜*uïq|ê?wšRËöj¶(hÚH @U@ûyds Üy¡z^�Ýz–:gÇ”D óTö–”µ3†µ ý *‡Ùè,= íyÏ ®Ê;›•ÛÓúßäï‹7®â5 ŬóV¢g‹Töƒá™Ë\ГÏ;Aê!—¨�â, Ê'-eÎJÄ4]ª½igÛ¼hÕb<.ËaõªäyF£ü)Õ3Ù7�\­­*ò,9óÉpªb{º’9ú2y°-‹ 2WÓ*‘ùæ<�Ög¨ ¨'¿á/_ãlѸªÔ×=Ä`¤œD†®ÓÓšQ@�AQÐf–}«•×qíË=>4¥—æ´9Ò—ó][S â¡Í–Ë=hxMË«†�`2±-Af˜œ­…"Q—m¬kŽÿMFÓ÷¤+Ú‹Ú%uÂñÁ]=›ÑÎ\ÿ(²Ku*À0Oÿ.ùɆc{V¿#Šj¹Ç M™¤XxÔ½•!ú“˜‹!CÆ¥Î6@•¡@ô+M 4Ñö¼Ð—Ùùo‚D$§v–€YØ Jc˜�Ì(`þ¤>rBÉè�; PY�îg°Ï�A%sjå~‘o,µ�¹07�Ó,‚DYDE„() Uð+TÒÈ8Ur•îË„(mÀ¢f¸ÐT£±†‡æÙÙxÍeÉò{@uv\æ³8* ìGiž:ýñ£Ú9ó}ìƒbV'\§õ® ¨ŸÍç}ý¼�ø/Ô}£Ë[:ð’+›@ÍW+hýSlW º2X×EžÓõ~WÎíøÂyëÞ¶HKýÏõçÓ#*GZatú¾t¾q³¼¦Báªg÷S·ëŒ¸zÇ„yª>ëàá‡þœÞ¤”uªA|ÆeO)Ul®:mÏ)'ž²0�Ñ<åý‹�ØâûjÆ÷a:Òe”óï¨Áô.îýì¿ß}Žï•…[‘ý¾ÎäÚZ{”)u'1 2k‘#x‘P’û�€¬D™Ë @•`EaX J̵ –2–�í¶ oePÈêe–1Ë�ˆ�$ E¶Èƒ¬ûJ÷lb¨¢,Hqï 0Œ$†�ay°4i°4‘(�á�<½OY_êµ ¤)E´CÂX_§gÓ³í,{(ˆµY\"2÷Â6EY£@°B¦ìS¢Êò¤¬µ¢ä-§À3³ðמåò{ÖT?D2² 1Y2߬žfFñ½¢ºGõ~*O5ˆoÌܺѽcáè·û¸j¤µà*†È¬×—*ɽÐaM˺ôd S"¿ÑF`Ö〆ÊÈ# ŒH¡©Œ¡<ÌæºžóLã@5ãrVª¼þ•²£o°qds­´æH¼ˆdýÔÈP ÊÓBù »}OÙC ’lNª= ™RnÝ ‘Œôè‘eT¯.5\8v¬fÅoù�,k͹—fuk7DP�ªlÏ&·}×—ÁÃÜKÛêU㆙j|=Pfƶžõ Tͪ҃Ær^ªð¦)ü(eò¶Ä¿ðüã1þóÕ5l‡ˆ_ßÝF àp–pÿì ‰E‘¿1à³k¸ªùù›ðëW¶AÞ=<Æ{GÇøúî6VW/<W&#DÈ7’Î$³xÅCÀ£é ·�OñÊú >µN¸{rŠï=|Œ/hÑäÄŒ;§Sl�Ê^z~eY…Â�£¼²±Šµ¾ÁÞ¾�Ë“¾¸µŽã6á;÷!áw¯_A”g¶?ÎrÆsËKDxfi‚ן !Âo]ÝÁ0üáíû˜2ã›W¶1‰¥)ƒî�‡øÄ`€Ë“1nžœaµipG ¯nJÔÂ=Æ�Ó)~u{Ã~°÷7ޤ6À—¶Öñöá‘§k™±Ò4xfe ï´Sü‹nàûGG •€+K«øØ•g°»yÂg,j«€à>-+Wûº… ÑGFoúß­”ó?Ï5§hÔK¶¾§îâÏÿÌ”«šVçKÎääï¢ì+„ §uÄ0 ™R³84„ )1ˆŽ] ì©A�ëbPeL‘¼ âŒƒæ@6¥„R$Š  /S’Ö>ÈÎñë5«¼¯N2Ô3Yþ`X£¶†j øÌKŸÅ[ïÿo½ÿ3LgS̘ñ§GøÓ£\ ð;+k¸LñBå÷/Ê5ŒÓª±xn.¾ˆ$IÅÎdŒ#0¾{|ˆ?»ó‡½Ú°2ã¹Ý]|l{Ãf†ÖÍ=gÊ §ºêžáŠ!ò]ØÅIîÍ a·A��ø9«ÓCÖ<ë儘bÖxdWî4#”€1h�4ýf‡ ;s.zëwCÎ"k8ŽR-–,‹)¯s9mÖ·ìÃÇ (�çŠ~©s€÷Qô@UPáRq&¯ä‚‡,µÂÜÌþ˜ ÿ…«×L`y?©&ž3¸j�_1Á™‹÷~S‹"¢“rÑV®&€ëʨ´EŠ�±È^Ž“H�’�7`ŠT7„°`P—ýPÕ±âZ7%»¯Œ¦K‹NßgÌÚì¿P\˜9¨a€ÜãÞ ³ÑPùN›€6›¹ÐòßÙ|\ÄÇL݃ÌîÑ_Óö^ ›E˜TÞÐh�bÜ•ñe[÷\ä19wÅðcû¥¬]µÖ:VVC—Yl¿ì@ê™-mº%ÈÛòuP…µ! ë÷Ã22Qqäó캗Ò{‘­ÈÕmn4×s”, mšÏÊ`ò Aö É1°2š&¢q�ƒe°ó%ë-F%‰(I™Ðæ 2Phà1Cl…¯ul0ÅxIûÈ:Ù™dû%Ãi°DÊÃ×·Dì›>D�5žvW±¡ÞeNfè0¥•)�M $u’έGg(u4ÝHG–¤ú*qt –Nˆ{FgÎú²×ëÞÛ•rŸ>,âý«ÈšuJ´¢4×çò"ÝK­#¤Îûþ›1˜Ìoç¥6pá�öV§©®»åÂð9ãäžÑ½ºm1”*¼º ap´#›û›þ5�wû½ xå#3ÜUŽ®skT¿÷Ü~—í»ýŸç^ª×£Úàjmé÷𹙱ɵc”Îqé¨üÆp“v}�OÌ¢ŸÊ<ÕaÊ•s•w× éÇšJȻڼ+ûˆæ-9õ7j©ñ¢kÁÁ˜o³ÿ-xó+l÷-ìB­¦_|/¾ú qñÕµ»]´ÉÊ1 S¢E*F¥^[AÀ‰åeÅ ÆÌTELʨÔ+^ߪôã2+Å3…�“´5m#ÄŒØ�•¤D=+ Õ¾±zV@=(­ñHéhŒ‡„ÉH"–'ËË  0�’0×ÀÂ0¼�°ëœ ©% ›€AÓ`4 ̆³iFJb0ñhm##Gx M«Ñ¨ ¬©B(˜g�)ôÊ•ˆ`ÖJ1œ  ~2’z 3�„x©±Á]5 �‚UÒ)6!D×-(X*‚ZoÝý×ý›«Œ ×[Í>í)T·vÞv­ÏAÕŽ½{N#å{äD{þÉ4Ï›Œ~ö¥çI%=kþ“;ãE4@Tò» xÉžÏ�ÔuÜY¯DgÖ=÷¢�ñHȵ<Ô²µ{-8ÎåžF)E¹®ÉƒÔ8¤� XDÏÆ¿ôÄ‹ÀÖžÞÏúJ±d1 dñvÑüûBêÍnôßÖ‹4lŸKëHƒ§`'Çþ e°T¼\Œ^:¯*8 xˆ©÷O¿1R1 á=­‰ò¾,¹‘È #ÌP:[�Èl4šJMè�=E‘¤Ü Ë"`ÿ©àçW„äõ*2£Ue[NÉŸk…î„Õ—âèIçŸê—¶-bƒ¯¼t- À:d–³y1�6Bˆ1D�[P�ÔGªÐØ^ßÀoå—ñ�/ÿ2Þ¸ñ~ð“7ðέ|Ï¿{zŠÿîôà¥ýÇøúÚ¾¾¾Žß¹º‹iÎøóû�ðòÚ >¾"醾÷ð!–›ˆ¯îl(^®&„¼¸ºŒ•&âÒxˆw�±ÜDüÆåmùîƒ=<šÎðÛWwˆÜcÿù•%,7«ƒ6†LbÄ“é àŸ^¾„Þ:<Â�ÃüòÎ&&1âÇ�÷ñÖá1^N+øäÚ œM½H'Å€O­¯bOg¸urŠ/nm`î��áûw㹕%|nc O¦3üìà ^R#à  td·NNñÙ�U<œŽ±#þÝ�û¸4â·®îàÉt†oßoÿß¾¶‹QøgOÐæŒÓ”ÑæŒ�ÑO¦3\™Œðú“l øÜæn¥ÿýíÛøÞÁnN§ �æp0Äåí«¸²}ë«ÈY#U²E2àQ/FS¸ŠC9†~nÞìÅó@²œ«ža¯L8*;½àS§‡E³ÿJØWŒÆ 1où°¸ñœËøÓSžÅ=ÚdC.ý5µ_W "÷› .÷5ô…K*5}HQZh«½­ QŒÈ•Ñ b†g��’&U/Gó.UP…ÊPÓ6”b<œë(:&ü9Í´‚1d•ý×Ä^yá³xñ¹WðÞ­wñöû?ÅáñàöLÒ�€×&KøÕ¥e¬ tŠêþ"]µQ@rZ—}3ާ)a6ÇCìsÆ_Ÿã;çB¸ºµ‰gvvqiuÕ•N PCξxW-5ê[X•o¡ºÇ•þrŸ(ÜŠg(U-˜#•¥¾¨Ø¨ð^�´øEþ·õÇ [Rp#Yã‘Ô 3¡¢H-J+SøEžf{–�A=aÍÑ‚ÍIËæËð¦�yý›Á޵£ 0'§âQ&Ò[äÅ�F²gÛ÷ òy¤€ãMÃ6iZIÁ+Ší}¢ ^gîË) Qü±ú³®Ý×`Ãru] ®±€*sm×µ'SzÀ¼²Ix›â,2Y[7¯í1[§œ5b_÷™`-Ù�!éTV–‚Ä‚•ÕÀ‰ðKÙÉq¥õþ²(„gÙú(�€\ñ8Ññ¸�×U`Fãå V=“Tp¯]SÚÚ �}«µ¯¬FŒ)_ƒé'ˆU?Qæ©kxP9Üv›õÃ0j€ì<ž%¿[²ûi›0;]àj/×”À ˜û”¼wÙ÷{ÙÃ&3d•y¢ò˜Ìp©<3›á�$ÀØd©„à;™PR5‘0`á—1jÔ�Ƹá��œ ³,i„‹ž�²ètL¹Ÿ²ì—lçËŸVÿ´Q™Àæ :CœkjP­¡bˆ*"ÝÖJŒ“Ý­&ŸH6‹ÊKåïlio3ãJ¤�ѧ>º9H#ÙÛ¨q€+kq Ùž[–P£B×(°�V8’º¿ÌÍŒjÜ|ŽŠ1¥y2§˜vc�w®º»×J —óVߊB¯ …v{Y?xÁgÞÖ‚Aêû¶†��ÍI‡™*QŒíó`4ÇÚEÁ®–±¢n‡ªõ‹‚ÎRfMÜû~ß(PõéÜK³ œ7e�/”}Ê(TÑM”Œ¢5aã[ÊðPÀ’ÿ, Ì‹y¸Â¾4çÚ—9 �¼ç*®�w€›MP‘{??ÒuÞÚUâ¼Ïì÷óžÝ¿¯ÿÞ¢û.zïiýBï³óÚ½¨/ Z«Î‘¥(›Â˜ÐÉ}n £Ì ^õ¤9a­®@ˆ@h ^ø]IPÆhnÇ9H¸°=ÚG”X­Öð*öl`$1rNà–‘CFJÂ[÷®È bÄFRMF“QÄÒ8`i"¯¦a š2®¬'­™ Ÿdµ4‹÷=a"Ú& í,£mK!=K’›Î�+þ›&¢Ä®!¹xøÀ…P}f›2fmÂ` Âô¬ÅY”ôK³Tj$[y=¿YSÅ "!5R/�p«dŸY½y*ÞÙqs¿Ú4e‡Ø%^ÔõÁ¶{³ß/Çú£�k|ØQÔñü_øíŽR¶ûèî¹q`@}£^— ÕuÚtojæÌ‘ÔÐTæ^)‚]Õ.HÀ˜­'«D´A²Fh;r¤*zL•烵íç‹ UºvHêÉCÐÝ‹‹ g]��R¬Œ™²ˆ“²å𴽑+S­(£2PËçîicsÎÅ«I@¥Eâ¼D¯ñ™D õF`8ÈõáרBç‹¡ U‹a™Ó,´‘Ù=Ò˜Yì陼†‚xC‘ïIñî—(†æßgVá";`!Ý/V|3%ñô‚]Þ¥½–d³žã¤†š,u]’•¦`OoÝtZ/Óô=Q²‰!ÒŒH¢°%[3-(()LÙ'E�Í#3@ikƒ’ŠÎÓÄADŒ©Eä B"l€BÈh2€ñ¥W>�Ï¿ü)<Ú?À÷ßü1~ô³7±·ÿØÇþ““üääÿóÝ»xv4¯¯¯ãYîz¯~e{€¹¼s|ŠV—ñÒÚ �MñÝ{øôú*ž_YÂ,güýã}ìŽGØõšŒ”àïMgY6îí IDATxym×&c4$E}Ÿ]^Â×w/�Áƒ<…Гi‹c]sø˜ÖExfi‚w�1‰ߺ~ ¾sïög3|Së!|÷þ#Ü?›b­iðÌò�îåIŒØŸIñãO­¯b}Ðàõ'¸wz†_ÙÙÂ$üíÞ>Þ?:Æ‹«ËøÔú*>8>Åq›!†‹åAƒÝñÃ@8iÞ==Æk[ë`f¦„ß»µçãzýè?>;Åw=Àßa6§Ð–«‰ .mlcçÒl­oyñê¤ ŒÄ¹C/œiñä"ÜÛy®he9¶~Þ™Ù!ÊG¿ôÔØÞ®¬Zbô ŸÑƒ‰Ý´5ÿÐë£âዯEQE�³xÒÂiŽxÇœØWa¡N—‚yý‘¥D4ü—@hbÀ jqEWÎD§(–F ÔŠ“†8_h²yòA�¤Ê/E`SfB([ÈjR•yà,¬4á–¡ OxgVÏDŠxîú'ðÜõOàáÞ}¼wómܾÿ�§;û›“cüÍÉ1À/--ã——–±F'í¼ÒûáÂYbD"lŒ†�pÆø·‡øñ£“ŽÑÀ."ÂöÚ:®nmáòÆ&MôóhðŠ[ì�Ö«sq÷$¦aCܽ×VÜî!¦²§ì¹UÒqpså@¹³N3dxª�˜Ònq¶tΖš²âõÌÆ‡©SÉ•Í(©JäwUªVŸÌ@°¢e@ u.�ïjv�¢ø'Á™A••æ�kŸg•£‚FbZŽ—ëý‘~fsW¯ˆÁQRXUlý£*ä%eæÕÚWô¦p‡%¥"¬4N€ßWh6-µ"ºxÛ›Â�ÉŒ�ÁÛ-ü‚ª>hÝ-Nâ4c÷PÉ(ØGÚçKd€ÜLŸY×x–äeE…Ù÷¢FS©Ñ´äðV¯éƒ¦)«žŒC’Utð³ãrdç~k»8êØ{E_!ï-†üç½_ÚYÔÃÎÕÛ}•QW0~§á…ìRgßtgÈœ�êþVsONº>·îm÷»½N-"Íßco/z/j£\ ìùõMÊky¦óüšq µêF Øèç—NVªóÓ¯7Vaü � ® €ÂûPmî§^<÷ËS®õ,z¿ÿÞÓß_ôÛùmŸ×f÷Zœ?·,ªÍâü³{ë#��Óm³ÊfD£n¯š³Š¯§*DRYLóבF ĆJj ÔLN­Ù‚5�IÀe�ŸSº$œ11Ðä’£cHFn3ZkL„„‡ÀhI!4,�Ië ŒG„¦š†L�ŽÅ¼× X€N$°ÃHH)HñäYBÛJÜ”€aÌQ£š&¢ibQ¼‘Ä *úž-G�’^LµBbL˜Îa&Þ!©•ùM\æ,WF4V0¸ö@·\‚e¥Í»ÇO*Ûï5!í¸‚Ö÷�‡jj&Ø'3…�wö; 2^_Fà-RÅÞíßgô¥o¥¯=ü�À žùߪÐu†^ zEÙÓeòò þ2€i‚”�­äÞÌn4ðæ•>fcúõüÙ| ·ƒyAH9»öË£ÚñààJÑ®í˜ÛúI>‡…�0ÈCz-÷)³™€²þ-´�‚ùݨÙÀèŒ3dög¸W¿õŸ ŒÁiÀÅ!‹«µì±}ØWl4¤lÍåg‡ÍUüSN]KÝ×ÈØ-$pN`RNeγ„ø'lôÂóJ˜°(Ê¥-fÉíj˜/3�ä,ãRÊh[Ö}µÈo¬ö�îÝj ¡'$k.Y1.Ȥ DÅ»×�¤-RWÊœ«�ߎD.çй¾‚�i‹­Ñóð1¶FCüg×/#åŒß¿%cüÍk»‡€>9ÀѬÅij1‰C\[ã`6ÃÆP" "üÚî%¬ |û®þúî6–›ˆ?½ûû³ÍÆ*ž]^Â{û8þ·'�ð_Þº�£ < '£%¬¯nasýÖVÖ5½š ŠjØ“ôìïuB±Y Ù}å£Åþ†”vœÛ³ùËùC}ø«¿Ù¡¾yQ_æúXøSvŸÒÁÅ÷Ì–}gÑÅ]{á3Ñ4ý¹Î#ÜpéŸ]Õñ•0TŒ»†`ô #@0Êp0ˆ@T÷Ñ‹&оgBny8Oí”JÞlqÑIy“%‹èŒÐ™g%¼Ã•Bñ?#s’‚)� ·öÆFÀæÆ.¶6¯à3íÜz7n¿ƒƒÃb¨ü«ã#üÕñàÅÑ_]^ŵ؀˜.ðŽÿÿÓ5„­ám ì·3üíÉ1~¸ÿ�ÛváýDvuë.ol¢‰’§Ý”²@w?ט¥`ÕyÜ(�€:oúVîûîù%ÿ'ßwŒ¢Ï2œVT|òʽs餅k5OI )miQ”*ÔèBñr/ §¢D·g�ö³ìç@p?¤ÖP¾m²¨þ–:¢ˆ¶T,^œ8@#k€n4€<$PõGEEé S�®¶õÛ©V4SõBÁç5Éôµ�É6ç´¾ì‘ÙH{ôƒ¼Û˜ÒÉÖ­o°9¶b°f8Íú¾uWèÚ™ì%^×ÙS1[,.)R¢ì³¬ŠÚ¤‘.çAÒÆhм¶‚Â9«¯6AœPT!®+©ÊYéË,I¢6©W5ÈÛ§œ<ÊÕ̚ǻ�Ù~÷ù‚ÙÚ„ˆXñŸ-³:N‘VdŸK´‚ùêÎ,g¥Ž$7Ïspá‹.3¹lQøQ‘]Ô ApÙK��ôË=ðeo‰n—]®1ÙCÒÍÔøD¼àû)iK°÷¤ÌOö-/ïçN°šÚpêý()€R†ãuÓ[¸, ¡‰HjÄÙ,�ƒîÅ€èE„u9 ÍRt¸Í’±ÁŠªÛ–Ï1 Ç®äñ¿Ëø,ÅdֵȾFRïƒÌ! ”H2i2TYä%Ñ*[hjBÓÙÄ ŽW!RÃI»Ï÷eWÎ5y‡+¹§¦CE¾,Q,µ¬âz�ꋈr¢ÌÅÛ¾(ÜûWÅdóú>í ŒÊ»Q´‹5:U½cd³ÒøÜS97usrÙ½åïîÅ:ôùë"ƒA·o®:­vû^ð´Î õ¿V�ïjK_.6 ”Î8%ê0‘îßÝ�1•çwÇQ5Ûû\ôM &HiÌyWÓW§ú_ݦQ™šérõ'÷¾[!›eÛ½6ø±¨ètR˜A™V.íVkð4‹ÈüÕëïGºžö êÝsÞï¥�‹ú±¨ÿ‹7ÛâûÎÝóûºË/äÆa#Þ3§{Z45Hjª”kn(â•%-„½(ØÆ7¢¨d•É\½ F`ÐeeÊbMNœ\seŒ á‘LÙ_‘„!0rnJˆ1£“1°4&ŒÇ„ñå##F£Û\1V›¶¤¹½¨xø�C7ÂÀÛHhÛ€¶…›{ôè|6±q£@lb%�šR…è3e˜€½”´ˆŽE2€H”¯¸lð1"˜—ˆ¤ Ê®€LlJK¸²Vðsgÿ ¨“w²Q¼Â€* @Þ ü¾zÎYV©ûyùY^í�8o8û0gÿ¢{*eª³Žú=Qêš‚�ªM¸ˆ÷´EQ[õ¦f$`•èÛ ²!™È='Mdd]ï9NËPƒ ùü‰' U@¹¦Õü˜ÀUÏÜ«¥¢X m—�ˆ4£DXnÉ@ºß£xÓdàV„›ÅÊ-Û‡jT 8EN `JJ3zôÕÙI½sYß/¼«ìuý:3$À¹;/bÀp\§ë^¯¿­¥)�Jd•¦rc}†¸‰\ŒeÏYX:Q.FT#òuKû“$|7³ w MÓˆÇ D8IY½æ<=‘>‡àB­ŒÝD!H�³DÊ.èÉzÂù� Y°0|[·Ú¢…ï’Ò(m‡ªº%\¸xWŽbtPC cBÿÍc2‹q­‰Ï\¹†k—¯âë_þ*î<¸‡·Þï|ðŽGÀIÎø£ý}üÑþ>pï.¶¼¶¼ŒWFcÜl%MϵÉ_¹´‰ÌŒÿûö},7ѽÿoŸâîé)^Y[AŒÛã!>±ºŒ«ã1¡ ’Û¾ÿè NS¯ìl�üÝÞ>Þ;:Æ$\[šè9cJ0ŠQsûpëø÷ΦøÊÖ†1àíÃ#üýã÷ö¿urŠ›'§8Íϯ,!j›Q ¼}|„W7Öˆ0M¿ó.ž_]Ưí^ƒÓ3üûÇû^³�b  Â,g¼Ö⬠¸�pï.Þ8>ž+úY_16X[ÞÄúê&Ö–71Ž*EK-8-—Ï\1’ M0ÎX×Ò©�úBÚáÑHG^ô÷Œ«ÂÏ5ÿ�Ѳ „ó¼ö£\]£Ëy7U÷ ­›×8ù#‡Ü‘%¬ðl€ꃆ0 BX0—ò¸@–!"†¡ðƒ3€‡À´mÑÎfmçŒ 1 ˜+BŸn&3Ì,c`¸�ïkÑÌŠÅØà^¿Ê0Ü#­¢éÃÁ/<÷)|üÙOáàè1nÞy·ï¾‡ã“Coùgggø™ÖH€WÆc|~²„ëÍf)c‘÷üÿ®QX4@ x’nÌfø»“#¼±÷g‡ƒvÖ7±³±‰í�M ›¦»–lžÃ]ÜSó1æîÏEg£VZبO¨cY¯øàŠwxùrá£*Ìã\•£Õ!é˜ æd”=$‘¦Z/C±�Ñ6¶ô&®�“ÆÍÙÃFbÊik]ö1ƒ‹ÒU1Èd)©íÀ ¬ª\iY•¤ ‘MJ} ¢#‘¹X�äì,ÒŒ³ÃÇVfPçÅÞ+”³Éð‘‘-x¥Äñ•sú¤r™Ž(ë<è;T , x*Y°ìÃZ^;Q°œó¥’“]•Ðá�Õ(Ð&K³)!œ–Ï:’¦‹QŜᾜË’EÎHlNs¦„5Å¿Œ)¥¬PJ# ’Œ½Mæl"X¡m3f³¬éc¤È)“(P-Q7nÊœ’d²â—2?š6Éû›‘T)iQÙç0D‹]‘9L¶Í Û›BÙÿIÔEbFNZT:/Øg� ÅübП�ô*ùVGİ�( ¥ÚŠg�¿Àެ䘊XØÿ,Fu¡‚S.{Ü�0%%ê0r6#»œ]1º›Â\Ó0*á ‘�I^’ÞI VgsÎTƒ@’î¥Ì’>Èæ]j ÉÚS0[�³PîTæ`0r…œÎQ‰ª®e‰²^Ù$5Cˆí!›âØ„’þpg‰ô,o�²B‘�!kÅsøQ¡øE›£`u:+K~_'³‹REñÀ·1v±Çü_¥ª÷ª;{ýì*è«~ø[Uë®ÃéâjY¿²»OàŠ¼Ú"æ…P“€s39�é .ºì •ßêó×ýj(ê|¯ú{¡ÁÄô/S‘Ñ“F…�ÉV¨uÙõ#¸;/¾Ó¹³ó³k(CïÊJ²7»ýîö¡é6Þ¹K~VV°¿”^7ÌÖ¦-¶uŒa€Þ”J/ó.½+£2–÷,{Tý{µA,ß‚±öÀ‚±.üôâÖ î÷¤Ÿvu¸Êùý9ÇÚäïÍ5Ñß–‹žaëØ›+.÷×`µ¼êù—�HîÍ.Æ�¬Ši³ªŠ²ˆ äÅtÍ0 Í”µ·¨�E'iŽ9])›ò:a !–Ä¢È:?̬í$ � ´I€'ƒc0 ,M“IÀd0†C‰�:øØô°…ëþ·G5 øÉÕÁ©…F Ø0æd‘ b#©2€ \:—´—¬9E!Œ¦Ä Aj6Hý‚²wJñe™¤˜ T0Ðca ™3ڜЦ¬ìb¤)̹N'ÄeÛÌíÏŠ˜uùJ'ä¸Cp{ĬZÉêâÞ™àÞ{z�m&cç ÐÆ„¨‹>»Ç¸œ�¸©×ç>UŸQwNlJÞúc#ÿ޽,è¾& *ä4+ÜRÜa{Í<<Ý›¥†µa…™Ê~àâ¥a¤½fŒòl¦Nj¤p��+>n^6�P¼:(¼LÅØ'¹LK$Š ­sàÅ¿«T¹C 8¤³%Ú »ojÀÐUzENð÷¹Þ¦þw-æjÊ:ÖéƒL‰éÆ-4$ƒbÔ¹‰žf poÊ÷’³�Ò>˜]˜äzLQÀ7 ˆŠ/›Q�Ž$@ž5x˜AÎÒ­Ap³Î%šÀÏ"ySÕ)ûÞêhD+>OžÕHžH¤¬T~ºgÕKMíœDpRCª4öø_Mµkî]b\ßÙÅ•í]|õµ_£'{x÷æ{øàÎMܺwm*žªf3üÁãÇø¸ LBÀ+ã žŸŒñÉÉ[K#¬†ˆiÊØ›ÍðÚÖ:Z^C›3þüÞC¼´¶‚O¯¯"3ã{cc8À×´fAbÆqJÞ÷�¯,aeqi$ùùׇü³ë—Åqë€o^ÝA$©Yðd:ÃsËKÆ€åØ`©‰XpûäëMƒ/l®ãÒhˆï=ØÃ‰ F!à?<|Œ['§øÔú*^\]ÆÏ$ÕOÊrþV‡<¿¼„&¼q|ŒwÏÎðVžáÍÓSü·?½�“§äC!by²ŠÕå ¬­laei]×Ï šW—Ó'[K£aÕ™ñãW8N1 “ Uçá¾ê]§ãð…Nó÷,"ÎyÿC]Õ÷t<ç÷mÁwz×4q¾OK—_ÏñDB9oO¾ñ'“•2¼âª ÉÄZ‹ªxñP¼!­Ç õ�š Æsç3^Ö´Ãf€A3@ÛÚAÀÙt†é¬E<›á S Õ/jÊI*Ê•¹EÁJEÎ1¼W)Qlü¾ÛŒ“&�|+|+˜sM XYÙÄË/nâåO|{ûp÷Þ ¤¸?8ß*ŠdKYir/[#ætÄe/‰ì’<Å’½ú†7ÚVû¡Æ ä/ãIÝS^°oÕÙþ4#žî"ˆU�áÆ<[‡ZNe­ÅTòwú`çVOŒv´`éòý�­Ú˜¤î´5,ëo3 ÁªÊï@˜U'`‘0Z[ÀŒ‘aÆ3 h½1åÓÅú®ë©ó`óÍÕÚÙ$šS�Ë}.\”ypTh¤õm.…†ˆ<Ô¨�IöHnüƒÊ”ŒbI£*Æ'ÝÓ:Sð§¹WAÙ0\m„ �ÚDþýÚ JJœþT— �DqŠ)ß)wvaŸ›a‹Þ‚˰ªR�Ž«Ûñ¦¼KX<¢ ºˆ_gÎSÕDeñG5éES3üQ1ºs¯2:%¦E8xúÎxÚõ´‡_°Ú /:ççyïý²]�¤Ì}Ö"k28�2Pñ>‰Z\[„Ú%_tæâŒ˜‚†;gºo0�£r‘2²žWé¢VîAžëuŸ¿J.OVã†�R(�*ûUŠËIAÔƒ*~ªù«”šŠ’ZÇb‚dÖsn¡´žM£baÖ-Rž#…ÞÍÈ@ž–)hq6™#™g© Tf®4Rת+( ù>JåE9#&332’å ìÑ.V(L^Ñ=±€ÔÙwú‹ÌvENÌsÜè-b'kRíaVï;VÅÆjy‹):î�íîâc»»àüeÌfSܸs ïݺ�÷ïÜÄýÇ�:tæ$g|ÿøß×´v=;á•ñ[Ã>6a·ip–3Ž4_x «›ëXŠϦ؟Îð¥­u€$ÝÐïã [ëxaeϦøÙÁ.�†¸6‹’lÐ`ÄÛï`ÖâµÍuœ¥„H„ïÜ{ˆç–—ðÍ+;Ø›Nñ�{�°ÜD|CkìÏf8ÍŒ³”ÑáÚÒ Œ«“1Þ?9EŠ„õ•1~Ôžánïãݳ3¼wv†½sRyô¯¬,­cuy«ËX¯VÊ– s.€¦¶f¤øÒ”BŒÐ�¤º›àôX‹¿õ•×¢(;¬¤ú»Ýóºøº_]„Ìêg,zÎb¥ýÏ{õÎ]¥t˜ÿü¼ï]Ðz%T�†œnvت}Zñ_±¾cU”s#ß.gŒu dÅræ<•¡ Ò2[Z/ÝÇrlÍc×v^é © 'гE s‚°~èÙ âŒÔ1¤§/Õú”ÎÁÑ3uy úŒTN2¶�*T0‰�ïBê0k…”‡óH—[%¯?ûZÚ1ï}°f̨cÍW*dª^\<ˆmɓʲ¶þ)gdUÆ ‰³W(Ž}�5ÝZqøŠ·rµ|Ø*'2Rß{†èö™$:€Φ Ó6cš,��¤ ÊÐtŸÄ¥˜2Sš‘Äqª)­‚FDèûÞÕ:ýCçÈ6O¥®01¨J«eµl”¨\‰ÈÜýé;�»¼Ùúì2Z•´¼:ñ+�Ÿ¥K�iFêÜh2Y‰òéb[Ù/†»Mn‘~[ ¤ÊÎÒ Wš‡ZA¨²Šï?þºM1ÑA„dr�„!Cjnµm.|Ûè´V�’}äÏF%ÿ@)5ü(¿eÿás"E58VŽ–¶V]eáÏB'WX�%s÷ õW‘ý÷àçÝÊ{ü?Խ˲$Ir%vÔÜãfVW¡ñ` ÌÈ@æ±àgós¸¥p;ÜŒd„èШ~Tå�0S.ôU5�¸YÕ EèU‘q#ÂÝÜÜLÇôe+m A÷Qºee¹·Áuqf>ª­”ø²;£èŒMÊ,¹ÒexÞ&±ÛØæ:S¯nLÖ¹­t']Òïfû˜oãuùèzŽ«” 7rÿöƒ$�ºâ«X¼ß[G ÛÜ  ɣƹdG”ÉŠkKg4uÑ>Äë!BËqWë}àUù$5�g_µ»ÝmÓƒ} <åXa„ží8å�Kˆu†¶0Ýe•â§.u¾¡ )å¸ÌqL—…YXMŠÛwÙX=W_[×ú9Ý}õøèŒ¯|ÿbœ?>>"�ëßR£?óxý ­'?zbͯ¿<£ J¥&ß%Ù IDATId*2�á%Á�Šh ÀÇy;a˜dþ  �Žp¾!7Ù�a�0!•!ú` �.�} `8ψ¨x‹Sb#c•Ò„ô£ETªXÊîÇøÜ©àÆÞ>Þ>øæ›ß|sâís8Ž'Ó¯üàŠ“ ”1D[é†�rÜlk8|²vÝ ü65.ÉY‘ß.Ô1…ðÄ»itƒÀƒ£Œ´‹Žº¥å„Œ«Ì½æA�µðþ0œ§áX c- ÿFKáèFsËÁO¶¦,Qú+±hSâúKÑ3mLa°SSzF é'&çe‹oÊ£+UCsÁ¦2¨lB^óܤS‚EëÏVHñ¤�„môg6[ñ¢R ¥1Ú\ FOÔ ²¿*r£–ßr,änÀï¯XXnN— �Ê�ÍNEâÄ�ÞèN9¢‚ÿkÂ,†~Œ¤]Er/f؇dœ€Ÿ)3ÊÀÜ�- m€BF±r¿„>Fýزh<Ï SÑ(� _XTì!- âʘsÕ¿˜tf¬9. Päêd�Q3k%‚Ú¬Œán9Æ,9,y”©Ûaå4 …‘\55½-X$š³ô‘¸C€†¤(ã™QþX d²æÌÆ‘s™™!P9³>ΖFž-ªª'N{+´P¥•ÜsÓGb îwcÚ7aä‚Ηc¾øßþþïñ_ÿîï0ïüá‡ðÿôküÃ?ÿ3þñŸƒßü˯ñã—ŠÞÕñ?Þ¿à¼yú¿~yø_o7üíí†_ÝnøÕ8ð­ ü_÷/øn |‚áo'~óxà‡Ä7cà¿þå_à›cà¿ÿñüpà¿ýÕ_àóøï¿û~óãüç_~‡¿~»áŒ{þóýŽãýÀr௿ù„sþ�ßýßωßÝþ0'þ÷_ÿ#þ0'þçýŽßÜïøõÿü‡7þè8Žß~óøÅ7ß៿Ã7Ÿ¿Å7Ÿ¿ÝäÖ+�Ÿ ZêþM$çZıËâ:EÌ”´Öp—“gE;Öé’½xÿëÎ�Ÿ�…uÐOµóþïuÜ3²ÿ‡µððØdüßJÖçqâ—ß~‡ï~ñþâ›ïø÷·Åõ)ï…íÅí–üãU2AïùÒQî¤ ‰mîÆø6›`Â6ÇW=ñ·î#9Ç‹Õ '–¨ í÷±©â–¡)ËŠnž_õGí¸¯ÓªÒc�½ðŒ7‡é4Ÿ‘y¥ÛÛFGÊdÑ„¼aa£CÀgdú{Üg1˜â±¾ÜÃ1p_H§@:ˆ‘•BœuŽB«Â)�õúq%u•zŒqíËܾö±Ü\;¾_V{qU€W{:Ä�*rQVØÕÆ…>š>ŠÐú¼J!÷g�±®èS·æ�grà†Å] Ô,s”�?–?Öh2úúKI‘\K ÛïÿÃ,öÂ1•zá(Eczì+ñ.ϱ5ùi­í|R™º¥}rƒÖ8¢ÇŽŸ¬ÑNŒëB”�*ºh³—"–ŽLí%5);Õ-ªOxÈÉNX+”¢õ†e&Ít­�bn£Ükzˆ¬ndÚ;ª§I3�Îrù¢> ÕÑ ûÛt²mRH[íŽ�.ëœKk¼‡‚ë@hN9õ«ÿû·eKyÑáNÿþâ4ÙzT¯Ž¶p5Ú®+LŸÒ6û.�1¸J§…ýš7K±{íwLõÚ³š7›ÓÇÏYºÉPóP²ôù‘_Œ펶µc/G¯2ͶI´Ïß]žV-Ë c/~³š Ë{U‡÷t»ŒªÕ[ëc0DŸ�ú~ |EY?yü±ýÙGC0/IçÏ9¾vÝŸÓfí»m~ž.¡Ð’TM(ÇM/*©1¾¾­ �øæ›7|ú|Ãq£S€†|6 øh`›c"§‰UߊÖªg ‘QA·KìL#šœùðÞÆJ¿óÞây¾eDî�`*½ÜkF­¿e¼§gðc�Õ÷tÃXÀq.n¸l8çÂc­Ø`jiê�´ã˜ÆúÂEm�¡2ù;驵•Â~ày¦ð¡1º¾¯(oë4ÎZõ®ŽRÖý›�£¯×tPôv9˜OŸø‰ Gç•s`qOˆÜLi ÒLe È@ÍÕ®òLFÎ>2NÃVÖ Áœóž§ˆöŠdÝ…{lR¼�£öת\g¤•Ê‹™øQ'Õ¥´–Ú¯òiÇ1p;cØtèÇ6�UcyŸ9:2ªÞ±Ó©Y›ïRærrè_¹ C |ƒe!þD†(ƒhÝw;Y#“|j‡ÀŠçâI›½ŠL4`:Ü*}ûHš@ð~Ö´.Êõ`÷ÇŒEˆ�ù6j†jeÇÚ³kÄvÇ0+çÏeü QnÑqÏÁ,…#ΛspIõáhÌq$;/"ûmrü8ÇdÑ©ê)ÿœ¿©nùÃ@tGÎ ÉâÃóu·»¦Ï//¤ŽZ¾b�*ÉZ÷�!�9±Öw–!;-¢öVDíÁ�ù˜¸ßø2N|±£”Ðû;î÷æ|d ÑÂ’·– ɨ>– i5¬mœÆ‘6¤pÄ£dt/ùö¿Á(W�GCSlÿíí3þöWÿû¿ü:‹}âø¿ûÃoñýïþ¿ûÃ÷øã¿Çü#�ûÏšÝß·M�÷ï¼Á±™áóÛgüâó7øæÓ7øÅ§xÿî›oñùÓçÂCîÑwÛ¡ÏÄó…Œ×Öi¥ûVÆ5ëü}�jÀÒÛ«ëÔ~h}L)~/šºÞ Òr4�”¡Ëº³¢5Õ$¦œœˆ ^»akF�‡¡4ñÚ&zZ/úsè?í`Ú‡8Ÿ[:ªŽ%E„a2Â"êXcà©è(YÔ0hÎ.8V×gi1É ß«§mÄxŸ®q¶o†²¤ŽÝðmöZ;Ζ8+ú¨b,Ñ¿MCòn‰…E{�¹36îó%,tÖ\ éˆðþ?ÎÁnÄ9,rÃ'h’JÓ†htŠö GÀ]¥„ÜrcãÉu`ÞŠ�T)ë´F3‚§ŒìúIÏ}Œ#ðØA9­’—䟰‹Ï.é{†w�*RÐQûpæGá ‡>£éµy?@Z„<Âuª�(Ù)ÁÓ±­a,y+²™Yy†_É÷|Q˜Iíô¥ðv¹YÐ0|¯ö<»pŠ—qîm9lÊùã8—aù³†#¤— {°t�W€’ÆV2åµ³s*r{ÑÆ”rúÒMCe§¡Í¥Ú—!_c¼ÖB@SÏóÕ‹é3ökã|;…Z9X™-À±ˆM½‰TL˜mì¼hrŒrÎ7Œ$ð` ‰$9¬¤¬„�òÚš"H¦BãžR¼&QýikÕЧA¿ÈkŸqI"³Ô“ÕŸ+Ѽ²S¿>^IbÓŽßÖñ H½¸�¡ha×6¶. MHß%¢I÷F§ýú”çö²+8p0[D¥‚«\Yþ{yœî¤ï6²'äóõg~9Þ¥ãG;Î\h¤b탯‹Úw¦¾k À�|Ñ“>g©XHhZµñÇ]@µÛ£â�ë]÷󑈧¾¿_;yûÉ_Ïê‹ãååžÕ?ۋﺥ�§…áO}~Ùúíì¹ë?SQ¤þ¦Ž sïßì0 ¥<’¦ ¬õ6 v3î˜ÔÕ™\�±Å!vsB0úÙ*RvHñ@å„_Q#ñ|LÜWlš4†Ñ1pçÏoxût²äï—C¢SAmCè¹=�_;ߘ£�…9àbœÄRIXçgiÀ�»ŒÐ_En&@90��9Öd ÜD¤.§c€œfˆÝ#Zn f^À8O‡á8npW‘äŒï×ß�p—%msÞV 2à(ÕY‚³ÜŒ>¿HFÓ9©ø.JÆ«�IF/JNd?žX÷Õ|^~7=•€žÝ~­QÔ+¢±»¡h_QŽ…À8•D:¹TJfn ”—œÝÈ=ÆèÑ Ì`íÜåL ^écùÈ0Õ³Â2ê ’ژαF¤Y‚‘;†›Zy¤3˰m ?R¦O”�4`ÚöLW[ßs µª/Úä2�Þ@�ÆÙ÷çI'K�Ißd:t’^‘>Úd@à|i5ïŒ<˰gŠ|öÜûyhѦÔòö¬Ü'Ålå"IFµ%ð¬¨xlJ‡ûÊ’=‚œv8kNöñà8õ¥¨ö~èq™rÒU»”² %ÏóltØ�M¥+½ýM®�þpN”bQÊ(WH+ÀMõVD³MFžmsI@tgq!Y)Lj�M?½ÝbŸ—ã€ûÂ|þŸoßbØ‹WçÕ°À yñ”2šÊø>§#6¸k÷k<¢ø$ÿ€'}ááœoÒ+m;„Œ’þÁ{‰q6„Éûíøì§ ï~ù㣅P‡½ý:“îÎŽôŽ¿j§"¯¢˜>êoψû e$‰ vÚÆýzÏk×,‹×ç^$t Þ¸O:åœTàHCÎtÊ0¯Òî+�æ<à›­Ëhq¸<6¾?ðŽwühÀû—ÞßßñxÜ1çbTiÉÊ´t2Œr¹µù{�当£$â«ùGèY•;Ûúµ(ïêp*/d C;§�kÒ¸ÎqÃ_ýå¯ð×õ«ÀRmŸ™÷û;þðãðÇÿ€?üñ÷øòåG¼ß¿àýþŽûý÷ùŽÇý޹f–sZka®��çqÂÌp'nç‰ó8qž7œãÀÛÛ'|ºÅëóÛ[üýö)xSò¸ Ø’ò´� ;ÿo#Zˇˆ �BEÓ—YÐßð]®\'³ '¶y!QòóÈOWžŒ9“1µ²fZÇ.t·ˆ[s-Æ5€™Ã&ͳ ÂÈžX+ÓΎ'¦‡2 :ÍæÜ Ö,Ý9 �6ë ‹Ê^UrØsÉÕU-ñCžR#ŠÚlÒ¹þñ*M’G<ù¹½ý, ”«µú*xG‘²2 Ë€.:ôl×·›ö¬H¶�ûB豃ÂZØy­‘ø–]V V†1õÒxi¤㘵µX‘ÆÙ0f¦®&XqÈ 0gídŸîÜS`úÀ\åÐòÕH~µ^+:±æ .P&Vd*Ä€Äìó™Xb Ǒٜ c!‡•cíVù°&Ã\[[%"~’»Õ}¬ù â{¡3Å ƒ% sm‡D5±¦f9¨À§D)Øõ#é ‚h`pŒžÈç·lS-Ù%#ê8Ê™"¼´D�Hfà$ƾ¦ṵ̀^ƒŽÜ÷ƒ;sMPÙAã 5.°4ÄŠÆ{°›–ÁÆ~KÐô9‹ªáY®å,Õz¹³4VÍ|pÃt¦öÓ3Ø8ÙɰƒhíûXzI-W6F–�@9N ×(‹*Ö¿m�Ód‹èÜÛØC¶�†ý2#“2^2¹¯qkÏ.=ðkÇ@—ûºÇÓ½6݉—‡xèÏ=ºý#e©úDpup=Ä|×v¯˜Jxã©=÷§¦­ú ÎuwV> ¥¼@í4yaè®§²ËD1ƒíÕŒpz(ôƳ²N¤ A©ê)T�5p801P Ãy;pÜÎ`7o•qR<ðz. s8"#ºoûìÏ×¾—¢[HEЦ•ã�=_3|ï“�úÎÕ!FôŽ(MtœÀí60çÀš'Aÿf–f7žzqî÷…÷÷…û{Ôœ+€—q7÷µ<=ÜFçDÔÞëÐw0À›@†ÿtXÐZmXUtºÑ�d€yÿȶâ‹.ô7ƒ }M¹=ˉ�ŽYÇÔ ÔtÙúd˜ÙR‹©¬PQ(råâÔY"H'Z–Á:z‰“â©v·M¹öèÓtÖB΢š�ˆŒ\™Ê¼HÄŠ` Üsb ÞöûT ¡&_h5±øÖ½üŒÚPŠ+°hËÈiò€{ܶyÜúžý¹ö«¾ï›þŠÃކ¸mΜôàHYâ‹‹>sä^ ùœá1:r|¨ª-OQ²=Edï; `t¿;èÜ·|–¹€6 f±:©XF€ÐyQNØÃà†aÇX¸ÁwþvÀoÎqÐIøà>~øòŽøÁ[9È Ü \‡kÂ8-jxå"ú:/¯§6>|ÚÕfÖ’.ÝZÑjµ L>:ÂÈaãh²p盚�‘×ok¡ÔMŽÛÛþòí~ùË¿Áœs{97æÔ-2SÑÊx±ÖÄZ‡Œs’sŸªoŽÔ…½+²$맸Ò_ºŸ/rMü\ÑÁû=®.½³K½<Ã× ÞîŸ}sßæU� XïÌ>èÁ6dLm˜êß÷µ{»¾�çTÔÇ/Ê­ÄßÎqL9¸w…Z„¿Õ³[¶êu+Œ�æƒ ~*·á¬î8Ýèk‹¬AËÆ½ÆÑj.@C¶‚0„>ôsnWH¹i9v�; ÷ц£*=£u•»·½¥H�ÃÒ9Xhq_«Z7\å·)ÒIâË3•˜aµòÍ`Äz*ö`”³À¨(yÉŸ¬7? ‡jϱ zdg0²²'�Ùº&íº/ñä\x̉Ç4Ü×Ù Œþ^tÜ™Õ0W†+A†ThU [—#"Îå>£÷ ‚ív£› —�Ø_Fg€Ö¤@Y�©ã´Ó:FÆiV¾g¶Ê*ü7,éXcšÙÿy$mhî×"]+G˜—Ú+§ÀÐ*/ZUûÙÏ�nq¼ÊĻ̱ºÃ�×/E¶Ô´ßõ]D¹ÛjëW±×7•ÍRœXX4Š?æª�½5_fQy`(£¸ÖV1w ƒhÍä|õyïÏSká>"¤«†¥dû�É %—_Úš¶¡-ù%�¾�À½)ØPê§òÁ2j·°3ô¹J2Û É§M©ê6{ \psÒH/qå%k%�;ºJÝ*Ì&œˆ�Òg¤5Ñ£ö,�ÝVRey»,+éï^›Mw`ÓÛçWkèn/¸âÚ«=!ß­ø§fãª�c,Öþõ–®q~sÿIÇÆ:øµ&U_WâLÝCr¥ø¿ø%aôS[O ;¿¿ŽM]Y:ýU«g"Þц•­‰lÐXO 2JlmªæÈ«aÐ}¨Ds¬EAx»d¡€ìvŸzÔ4š½XȤÜàÚýEߟ»üªÅ'|ôý¿åÚççù¹G=ÛÏkc'uÿ¯]]J1èÀ³|�$ªÓ)àá˜l™.šš‡åO„5S~È€íïåsÊ8ÏùVÕ¥*S@»+Âà<T¤ïÓ�ˆ qÜ´q£¹ÆˆÍOq êöKŽ«w¼6m×KÑ¿í·D®5ÞàBx82ð¦IÊà’âKã¯Y³ëƒ:8Þi5%_Ðe=Nù ·yDº°£RœV€`ÕF[µÐï÷‰÷÷Î�°œq,õ2hL6.'2B¢ñ0²‹åyβž;5®|î”^t#…™ë§6Äqî åÒç¡Ý«¡ª¯I¡(Å)�^‹yhÈGW†(ĶC!ëšAyÔFT%á 1N~³0:cäKé¹J_ FØ�¥ âχQ$K*4…ŸuØ÷±èN€µ/ï%ƒ€·!» 5ÍEì2ȆA<sêÏœU–¤+AýÖÜ× /�Í%ã5s㼤€ ¸£¢�rÞ.cü¢RBGÒÁ1ªïÊN�3Â8©*¥ãñ¼€Ùžmy¥BC™ £ =æñ{,òŒQñÑwE©XÒ™R¤U+6Ò÷±EV R÷˜I ¢-Ò?FÒ·�X°I_ëZ[ÏË”a mþ+G‰nš<ÂWD÷‡"qÉÔå8�X;£Ïcsë‰E€›VÇ¢?6@kÆ¿#Æ*Xдɱ-,xx; o·�·›áí4ÜNÃÉÒNk˜0à~§7ÊÎlÝñîæS×yL„d‹ôðGê¹Ï·ŸÎïû®íÇZ¸« ʺˆtúxiþN›8ÆLÚKÈ7Ç sEÍE”vŠïøá|¹ßÓ ðåþÀº—Á!}$ïˆ*j�öœT²ËˆDƒfŒøoò¹éd!ŽN››“—×m€9udƒ�(yÉs+ô•Ãýq·£�[¯[ëÙtN]ÿ5̘nO£¶^-j¾ÖGÉ­Ý@ù¼Ð+ca‡îTØ»õµÓ+'ˆú¢?Œw3ò`Œr-Öá–Cj nHÀ‰G@õ!œç¡ ’[ðöyÀÏ‘:÷1~üñŽÝñÚ@7\ÙEÙ^V ¼>ÆOò¥,±@ÉÚø$ºŽOÐ[§; œÕx†Ò?OãÜð‚æÃ×ÌM4{9 cViF,jø[4c™Aä„G�0Gx–âÁÒ¨ À0prì±ÝWüÔJAtz†Êp�Kšôÿ>{´ÿ¥NËåöžº­¦æBÐÐužØ]ϳµÕU¿äHƒµÞ~»J6cÉ´µqÅœ×Kp§l¬sJwÆ?ÉÇFÚó…L}³XìË@¾‡¦DÃ}�) •“lŒ‰ÜWö¯Óz ˪ò3p˜Ï4î§úØëÂçs•øÎñ ý'µãÍyÇÌSb™œâ99!aÚ»(Jdžñq$ Ísgˆ\óF€s)­ÑS›ã}îÙÆ¸,fy³ÁÚIâ¥�è%pcà Èîm8)eù``ÁLÇ@È�çQ%Yt�ó<1ÆÀûý�÷û#ƒ>BþX`ä}�ÇŒ,«Ç¸¯�¹¹ï�Ê ÅÆÃÓeWô´>2f)GT»HŽ�#t�ƒÇš&ãâ8�¹æa�ÿtjgißY¿òŸ7%”‹@A!õ¢daJ”Â1‹ÉüÅ–Ö„o?ß«×ö:MUU¶:PTÂ×çõ'ŽWÿç¶óª#nû~yÿsŽ—#ÿᙑâg ! å>˜,1²Œ/ + ç]†³mº»º ÝlÞ) ø]öÔÛ½U¼ÛHŠ£â¾‘M0;v¬¶Á±„©@J,@}X80"Ë’ ¼Ÿ¬I@‰z09>é1Ö=ê•[”Ê8 [t²dÒD8Ìqšã6~Ä\„àØxÔžÕ}vì†Ø  FRÉ™ƒØw#£xÍÃx„¹IYLÃg£ñøK9%ç�ªTThÎÒ~ˆ2rf†ƒ™-Rû9ï¾ËkÑPrºæ&ƒ%/¼‘¿5YÒ&Ii¯%Ÿt\`™žÄúϾÓ$ïõ ëÈé»Fûî•Âx¡`_éÜ?„ÚåCJ;ð÷§‹ž×q5Îé$lò»ô‘í“”­—°R&Èr3Û½ÛZO�&–~q41®¾©Íå5ÎÛ%~í÷‹A�HMÊüèÖ¾­c�í齿ž�Õò×lþâÚ§¶ˆ•~2"1ïëù^OoOäð42�÷”Ù×ȱØóñô×îßç'ix gÀæO8ö:_îìKÓsn-:9ö*à ox”P„YÊìÒ†¢ÓèW´UzMãõÂ#BÜW‹Åu+×1oµ-$®¿È¸]S1^ô&�ñøñ”öü)¨F‡hFÁ5‘ GÏãâšY–‘¨�I¸>Q` #®�3®e´‹ó†…úˆR13J…=Q.hε•My8£ÁqÄz˜ki·¥øÀ42jM¡€=$MÕsf�ްƒ°*z°“!Ëc‡¦ÌÜl8ç3rÌ|Ê`ŠD eÒWõH¹ÐdPïYÃÙ[i.çž/îAcl5²Øù©•=ÈÒNé¸3LÓz4dPŒË¬}È8v™‘.º3á_@ø¯I«¢Ô$BêŒ (2ÁÉø›…ʼ¿†¡Š#�ß5g’…�°¹›dÕ̺ÙÙl…NWl×fJÁI|Þ¯ë!›6ݺ¼õ‚T9LM�æ=¥—=8q;¾Â\à  ,3 :Ž�ê™æ,M¦óYN+åG¿Ê’ïAo™Å‘™\ ÛÓ¸„g«»%:°ÈL•|ÆWmÈñ"~5(xƒ6;ö.ŠuXMIã}­¥UÞ¸ö‹¹�lœ ºxêÉ+ýéÂ$¢˜çs‚ÄšíGÓº ÷†ãž„þmB#i91�¢v Þ.â¡Ê‰GƒC™ü’i �î�Ñç˜dM@øŒSšc ~ †‘?Û“>¡5^I4Ç tìøTÒƒåj¤üÒXïSûû²íý1¼pþÜ÷×ãù•ã…ÐùɆü+¿ôÛG÷ùÚñç\óÓ‡¦öú]Nîò4þGÈ"â|>�†q<;h’n¬ñ�o7q)Kf€ÑíôEÐAÚÓfÔ °Ï{’ä ãþé°±õOôј€€�‘›™ÊLW”×[ýÉW£õ»Å5ͨ&#Z>ûÆàÒ„.f‰«žÈ%¯OÍG¿m Ø&°©÷a‡¼„apÖP(4Ø}aÎ;îÇ—÷…÷»ãýÝñx¦�†š7§èã}šy(Œ|(°<ËçÜ'Œe›Í£‘Íõp ø“gaþšC¨èÓÛ¯Cö½ÕK ïA‡Àq gÔ4ãHAܽÓË€­¬åk\à<#{ŽQ×墿0*t¾šQ"ºçðÕ¼ó:.&ÊÀ�4À(ë¶­•²×ˆob¶ÑT+¬dþÕë_Þí®+20 ªrl[驌0›ÁF�‡g"Zli³§>‡éÞi<2.ŸÓ–ª锆åâcW³¶( 2ë›6Ëð¿9¹= ´ù]`|Fm ÖG= 0¤°$Ed�eoæÛâGh96b«éEk¥/¤˜Ó1 ²Chs/ùœìKù%ÃB�°°UfRg"�å À[‡ ¾�,Ùá¤%ÀÛiÄõƒ¼nŽœ=m¦\Ñ@-ÞjWrš 4· |ñ!"ªî0œrøp@‘QŽ�G¤ž¯Z„Ë(hGHBÁ�/ˆ}Wαp†% ÿʾ$Vˆ¬cf¦Æ"ìüоiuV%–ä>[Lßp¹ÀX>áö �Ñi¨¶XÄ{&¥µ )ßäQš%˽Ê^“æ¥eIM<Ú°žÓ©Ô T;á8É´G�YþŠÆÏ¸Èÿ}¤Ûõ£äwwì‘òìaS<ý®·õ|Øööï‚Ïr�®ïÂ¥ù…Œ\–¿?ŸcÐâ @b¬ú�ÿ¤ª/™Ù—E—2DeB £”oR¾pŠŽÃp»Ýðéí 2žßïî…ÄHVÞö`»ã£Ôc_îaÜûòn8ÇÀ1¾à¶Þߘ>€qâ<ÞàIg4ê3ZSÔ’†Épêo1Š G.ÄØ&æ)=‘Î&ÊìÄ&.Šõ²�!ÊÓðÛ+²ÚÈÁ—ë=ê×vØ÷´„Ò‡FçYÌo# .Ô ƒ×ZcæW¦i÷B«¿ÿd‹®#_�#×­Šß>â‰MòzÕ¯[¿«ÿU.RÍ7ù#AùüxOo÷èß­¯t9ïY]K¹˜ ¥ù¶µE »0w<žít£×‡}¸ðt»g4!ƒ7±Jd°ø&½ÛL’Î×*©=¬r^KÜ, aQõÝ-�²¡~åð¶ÇR—‰¿Œƒn¦M˜QØÔ"€)"sÉ &CÍ�1Î Rècâ(º´†}¹¾F¬ÚÀéŽÈÔ« d¯d¨öNQ¿ XÜL—^i¼ã0 ;èPöQ´±Ìñ6|ºUÚ‰™ðv°qⱋà=díãñˆý˜-:×ÀÃÃ9pl`�¶¶Vt(ýÓ>s9–õŒWÇ@Ú‰Z¹H³;„o:>r]mÂ.œÛ”GÌ,CŒ¹Ê‹d Y2OwõÞ‰çøBß’õ lcVê2Ç�sÀB&¯Þ/Ñíªö`ÁÇ‹òʼn÷×|¤þ�W4uÞ!œ Ø9ïÓ¡¢—@šÆ˜7í1ÍŠ“})S@36æ�±¢ƒb;³¶µ¶£æ]ÿ„yÄsü3ŒãL¨HoƒM‚˜)¿úŒ]RÞ«~îG®ÐlDµ¾+0dyÏ•™ èâ~qÀ%}¨’šŽ�¤×ÀÜ4$¥,šÑ0æÁ¯¹çeÈ[”§íOóSŽ­÷^Áp¿ŒÍµ­Ò¸—ï7º\ÐZLüT‚Ê®’[?ª�×ê¸õsàå«þ!ÇVï“6„=³dï³ú"ÃÒåsv˜ ”FvÕÃk'‘s½-zAI�&Å$å6hÓ—È RÆ�(™ àƒJÿjðOÝÎRCÙçÔ5”O“Ô£ I¯�R·>¼šÚ�œ/Ÿ¯Ìûêš�¾þZÿ>êË«ßEÄ%˜÷^J±´WfUòï IÓŒÞ=…‘ïÔ$}¨¸«+£`C DHƒ”¿ºêµðq2Šlf¢A9¸h³àô°˜1s`ËNhs`ÖÎÎð‹j3ë\Œ6@Îqp)3Ï(?Ê+œ$cŒ_¥Cð�1X«ŒB%LšÊ€†ž«ÑÕFó…@ìˆh‘“ã›G.܆ãŒ÷˜œåk>A¬5?‘€I}É>!ç=ÓF“Ô'¯ïª›�½ØS)v’1 ävŠ—ÐÝ¡O vþu.ϦìhŸÑ"Œ�VÎGY£ž8"ÃäÁ¥#…c¤6ÎóÀí<·Z ¾¢þ1P)°FÀo×§¤±D‹¾v ÕŸ¼k‹D�õ2H¢Íe¥pÜø]ÆwÊq“18˜ò ðÁôló‘Fƒr\Ìéce[+ ÐŽå#SKEà4‘A™hYrLSÐtœžÿÕ‹¼´ƒ–pêhó<•¿8�ŠØ‘ã%Í‹ô· ¶ªÞªt%åföÑ<£´‡�„ueÈgÄ ÓÒ�õBm„yNêæ­mK£ÔðM}‰rhX_5ŽVÝD¤ú2³¡Ë)FÞ«²_ºöä¡ý:8V)$ç$SÌÇ=®EEôì•eBU�R€N¹sä":²v,oá †Wd¼¬Ø€Ù±°Ö ¯7m_ðõˆRl+tۀ㤣ùL~°ìCl– ÜyE‡qЪŒÝˆ¿ÓØj€Ï¸§¨XY3Ê„s�ò‡.>”¶ªsÃyXûØSƒU–„‘và6Öñ¯ÊÇ)AD W†(¬EÀ‡ú¢dD²Ó¶˜H¢ªß\ô.Êëè¤0_Ý�²ýªØÉð=j×·wɇî,Ô�úâf“aهן¯‹Œ��vÍÖ†Æm¬�÷º­ú­E´éÒ† ÿªñËËAý6êL»è‹ÖFÒ+Tʇ³7¨“ó³Ã†·ºÑ%CjÈ^ûëÜÎ�Ûmà8ÀËŸ¸GÆÎc��má ǘ˜�¨¿¼¨$g)ùOYTŠì+ͪ zÉ�|N@Ú"ÇÔ¯4”Ä“J^�˜p_@÷¹ÑôE×_%_Ð IBFÉ5r%ÂÈhCÉ&2=¯ñët´™¦ÞÎçÞ[ÝùSs ·ñhÐñõ}¶ß¬µeÛ�žóp飯xkS´Íô×˃³ûÑX¸°~Ÿ­øÇ½pJJbàmøÖðõN(Æ š­ŒLÛyÚšNuÏ¥AÊrݯ­¢Ï{$û3GÖɆù&¯2Š9t|¯Í^Ò‘zÄ7‹k #^Pv_âøF7¢ÅöÄBdå¨ìIò�õùñ(Ëå4¿ã9ý�«WÒwâG5Ök,GXÉ6ß½Û—Œ˜a„3¾ã \C$>²äGf|‚A �i΃ò’Y„ÀbvÇÁ ‹•½Y‹‡ùxî‰Å륄p î?P™Ó “˜òŠñ†Æ†AÔ»~0²ÌÓH<;:>kúC´c%¶‚^ÝakQ ÇËó5³lnÊFÊ䨍6¢§µæ<pŒ2̃}Êñ›ÚFô¿˜Ü sÀ‡e\a'ͳŒNLÅ€Ùœ£'i@Í’Ža W¢·ô ß­=i�#‡¬ RMr¼·‚nrO 6J_w^L'�ñú‹\p'¶`«•òœºŒ£A/ôRs‰TtNö¢ë¥.ãJ=UŸùt\éœXS13&\‚›¢³š+µÝm4VxÛ NIk@•KÊ �c·`?$�"°pf‰Þ”5^¨-ã t äçS!çU;uwðÄRv�hÊ5AoƒøÏ8ÿÞû™²Ãh•HôX4 =ö”]PŽ�Ú?PöhMñŒæº)ºÖ� 3IúÍÒÜú[×í8;ÎKØ“J‚ïÖïý4c5Ò§É»ýJ-Õ0 ž«§ ù²b½iMv^ô4 5cŒñ#(—óœvŸ ®8ûuri=€ÂØž:ZUœvBc´¾:ÞÍ4xj1Éê—!�{¦]³F/þ— pTHÍhW;쳕„ûà°j#�Ÿí‚v¾]>ãÅwö•s¯ ïçÎ5?·Í×Ïì`"KÜpî•9`˱&Â`‘2HF²2n­« x�›C›kÊ1�©¤€õªåÈ{Žö>‹Îã�Ó#úzs ô¯;�VÎ�t iI ¤ä*Ú"¨C�ê*Ó±�4Û¢fN©û˜€¥åpAÓ�´Ü4==—ø¦p€¨ñ©ZõGD¡Îµp»œw`±`‡OÌyÇ|,̇cÎ#è## ÔŠ¿ Ú)«XÓ‘eCŠkäù~æ!†×ÜàuOé:…kdäèÎ�&ªÊHaý{KCEÍ’›š±îªð“B? ý+Áí|͵$g›&•›æ•ÏÔ˜ÏæeЖü y« o—ÐÝH£baB6–~êºnôo\¹F¿g6†øö¬Ø°A?�³Ÿ–ˆEy½~ot_ÜûÓ{ÊP«–z@&æ�…Ñfé³WY5lÓ¤®EÎ켨 Þ;)‰Æ$VDo§¤¾7§@ßK$š„ÆÂ­ |âç‘4Η5^”ƒ‘íÉߢÿ(§DnÕZ>ç>žõ€‘wCÇj­¢ùˆçR£:«)H¶kߟÿî†w‰M,/×:>MÛé”’!Db}_¼¨ØIa6�[á¾ø#6}¦\OC—·§½?ãÉÒw»ð÷ö¯Ú+w^ª=ŽÉÒZ�ó$6�c€ãeM~ô`õQ¸Hý›ôÄ`fŒgt7®™êA_sÑ3'Ʊwß“qW}¸êyÊ4�lfwÉvC¾ð‘ŽÞjÿ-�ñt ôýrð¼˜Dí<›É² xRØšY�ÎöÌ5ÉÆ{ó16‹mòp{&µq*úhØûÓ��ž•Ü6fÛYWáÕýèfƒÄŸèØOOô‚\£T t (Ú\‡Y6Èè�GÑ�ï®´[N.c…Kφx¤ IZSn^s $#yÊcØaá 8Ù‡WA£…9 èÈì‚ΗǷ_hHz´àAÉÖ9þI�à—6Bž6å·õ�ã£)kï•btÔXÛRRÀÝP^\*|¸á˜·5p{x{øtøæÜïŽû}ÄûáUÉiE–†1^”õJ“]vº›ý› …Lô•´?2ò<$ÝX»Süñ1¿\ÏÕ"¬¿ëžÏÆá‘‚]€¿ÿʾ¢{»bŒ,1‚Z —¢ÎùÀÁ�;ËPa„‘‘‰¥¡x)ì´©6 �KÞ`͵ñ�‹”‚ÍÉ¥( ¢Š˜2ZÑ�Fæ0Py˜ ºraU,#=vb󴊆¯s¥›q£)ïÚèq””õÖAÿ`І»e¸ÑF‘Ñ eAWJ%㺗~Œr’ÔL%£Æiì-Ž�‘µý\ÙŒ†5Ï9F%Éäã8r!kŒœàn6´�EJéMW:�lFt›•1"grΩ*Þaµú|Ö”G~íp Ø¯ ž(£ãÉç[üŠ×uÑ'žã@E�P~Æ`¨ç�=Ä/šê‹œq�' %Ã�eªVÌClàm8��·óÀ1€“Xо#fš³-"6Öp`iñ†Ú8jyâíW3 P™Ÿ4Î#¢ð‡ÇZU³Ÿ«rz‚iŽ-æâ"%ßÃY2Žã80e  ž+çKQ›éˆæóBŽT»+‡Ž'[\ ·,Á4ÐAcøšXÞL[—’~°ü¼ã«çÆ2ZŒtð=òšê�õ« ãjí�°·ýú[Û?í?\@|Œ×êû뵂r”]ù6ÏJE/áÍ9áüì2ºÝó^ß8×€žy¾¨=ç1ÄE�QŽf4LWkN"Snæu‹r„ì;ŽóÄ8¹HucY€ºÏ>:,GÛTŸ6‘‘«ùÊíHSê©,O9~Ò-W£ð6Û¸C�æï¥‡äø½�tÒ3à9âßv |—½¯(N›¦ôî7¡5ǸÐ(4F2Ö)mAŒ"Ó�_%gp¹çG<ñê Š_ËÍšãY¾¨¯Ù»…�6²õ_¾‚;ËPÀC鈵¯ý¨¥�ŸÐhKŸÛø¼2B¨} úyKn÷N ˜‰ê “èlñîÕ]U4²¬ŒR„ní=iˆwC\É,GÏ@Ãï2ý4ܰÆ] +í´ÙUØé>RŸ+¢†KdŠ'öy†1�åe”…`3>ûÔ3Åv‹Bf.ô,«¶ xeQ‡"ë^Õ/m`O:¼Ë Ù”tŸP¦Lém‡{l ?¸�¢ª#,(»8äk(‰µ¤†d'¡l7®ÉÃ1ý]{Êë1äh |Zu >Ø0=<³bý'º)^ŽLBHÚHkx={£!Kzì—Tûýž|ã\–ì®ó.ŽŽa¤�Ò5¢¿DÜ:1¶6¥·Å£Ì†S/bãe²è8m#þ¤Œ€í)¯ Œ‡ŠaêºL©ŠWµ_ T’²D ùîaÙnwÞꮤµË¦/äò´v¾øv;8¸-o·Ö›¶ ÍOþ•ßì'~o÷o:~vg¿Ò`ïGÍ_FZ¹…3`‚åƒ *!dt ˆ9 ณ(dìoà5Kî0=Æhì×ûæ Èù ½;"@Üà ð0F@SïhΠ6Lj�Ùþ–sÀä à=ëïëøñ{ñ:€x:P‚Fr×PF'H�Ús&AO5–DËE/l‚¨Ï¨Þ÷”aKG@*ùÐà·�›‡Sà1|~ß< ÷‡ãqàq'pä¢"@:Ý ˆGÞxã­kÏ®‹ÌÚ­�ðÎ“Žæõ}E»s¼>ž�Ž«Cà⸿yÉç^¼{ôBFãˆn¬©PðÉ`öÁHðãº+IÙ+6žsâqŸxÌIc:8,rèâåµIX¦{3"ßÁ(¦î&½‘wmŒ0f¯i ¢ž¨>ÜnÊ]|â4¤/*P§ ¼ƒ¦N¢³ÆÄi¸!ßæ„†Ìòì—Áìhó \An£’0GKyM¥oÀa÷š8Ã3Où¤a¾žÇ-ê�p3dFË|ôlãä…è!M xjñ ‹¦fäpÉ!”ç p‹C9¶Ty˜>¾‘êÚcîU†#�0ç@Ò€ÛÕBxyÕVE1p—ýÙCã“#œj6ÔjEÆ”$ñLå Pè0�:µ§8‡áv œ#RÅ•šÐQ§.,3¬I£:hÙ"˜¶Ö÷’�Ã(ó-Æ;˰¼áˆs|†a“eP‚l ]�…”{&{ÅK?¥¢¤ŠÆqDâÛqÃqœâ D4b¹P!ížÞG’æÈºÎr©~j,˜ ƒN�9£ì™P† Ÿ årØÿ4¹yU¨©®’[´\Šz“1‰e’R IDAT&úÙª…ÃUi¿Ò ¶]£6u~Q•žñHü¹8î%�øy×a�Yõj3rØWÞiLI x{É&H"Z“2>?Ï)€“m¦ · Áz|+ìbÁmêNZ|zÙäìR&‘»cúÀò#Z± Zp¡éî°­.k|É«ØÐ<6ÚôŒ|Íç;êêŠWÆæ��@¢õ±Ó×\VL]¯>/}LÙÓï Ø‘2:åv;*ëp§ókÏuß g:à",‡"E’ØŽÌžùßû×/èê²oŸ:7êY.]–®r9WOÇ|ôËç�¹NÚÞ¦h3Xt¬òâ6×v›þÚñJÚ躽…�CÅé…w)ûÍ.KþÖoâÅ£á‘ìAÃôÖ/Cƒ6m¼ôТÜÀ0ÖPËåí#iËû ,¾~t–Z8Ãå°W€ZHÚ….d‹L�0ÎÆ†¼k¶q,q�)!‰��º\˜Lÿ™Ç÷�7c(ª>ôyž0‹Z½f�}„ cIjM¯àSÀÛ16C,ʱŒp<ŽÇ=²æ\BNpËñ~à}¼û„Ã1±ðþ§À}:KòLXçHšXúƒÎᕾNR�þrh\�ú�“ÃÈ›R�¯9œ#G´h [j?³0b™çz¬ëLëïW½É>¯9sÿˆðO ”Ú÷ÅŽpw˘áQEâ ã+f¤:qŸ[ë ̧¶"Ò[ã&ó˜7š|Rí M'£$ûY�™{ùŽìc 0£s“‚$zÓ äã˜íG=péu™ðeIC•-b·>ÀOW‰k—ïÒØëz¾ÒŸÊ¸—.îrS:ue»Mªå:Ë´ÕJwš‚¹ÂI0Žcœ8Žã8óº² ÇÁõÇÌæ|o?ª”ïV.8ûlZì—ÎÍúÚäÊÌ#å‡Çï=;:nÊïóÔ:7p×\ k.bÿYGz�è±ñ¸uÚQpžÓŽaŽiÆ,‘Ÿä¦2™W~÷¤ëóÚ¼˜ÃBÉ®@5aÒ+é˜æ´9h½'5n /ð÷d—RB?=;ô )_(Ã;Mì�¶håðÔ‘Î'xòx:·Úº)~c&Yký,éRB&Bòbÿ¥÷Œçòa”)`FÞçÂÄF+~yÞÀ ᢢ�~ šú,o_:%8OBAR�Dží‰"ÈUO_»Ÿèæ]<])²IÄŸs<Ë‹´û}ŽüâšœSf `¬;¦€Š Ú*¹’-&x£bcèe/Vk½]£ßâÒè[lÎMiÅw6øÛ°*ID§ƒËê~�DußÑîWÙsžN“ºáÇ»°Ùh·¾®±Ú¢›ë@R޵>—‰Æ/S«È�\ÜÒÁcû�[<ôíÓ�O~Ã7ËðXŸŸ4(q·!{Ci¬Û£<˜DŽÊ kÎ?)œ}hò©ãq_Hm©¹fŒÙäl_ \¿?QºûåÚìAÉe–ŠÙFWj<'‚^žýîŠPçÖÇ1,[šÒa2 3ú)ÂN¢Ô¬áS}÷+k¡"•Yþc…B^RgœsnÕ'9*¢G-[Ö5Ãß ¡]{Ìä†`ƒýèF-$5Np‡¢¥Å¿eL]ZØ­U}XF*$ù§¬,@ÓhùQH “~K>³j–ö¹ÕÏ6Y1¹l$ð À£EåH0ˆ¡È�føRÆ€…c$GQÊ=®¨ŒèebÒ;G¬ç4ò— #ý“êWÏÚÓÓÑa ïdȈ~{ј‡ÑXE=ÄWÞd]�°|Xð_ÄÄÝ’ÅÿFäd2 s-+ŽÑ�gÙ²Œ×8eV”˜�ñÐFu¹è2¤Çà©ì�J8,IÃö){ÖˆAYIïZ,T².,ðÍ0e]¤äÓsre˜ˆzé–,•ÌTqD4ÿÌ@Ô‰4×ó†N[9§h@r���*ü~2zzÐÇ0]û 0R/­ ðšqÍÄß%�,ÿq\ ön¤²ü=è»9ýÈŒº&iáªÚ!c—ÎÙu^\ÛõìëöÔNý]O™¦ïlø£vž¾¹ŒE:_;^˜â›~¹ê¹=’ɶï¶‚Æ(/¬9ƒ_=ݲñvx¶Éw‚1é�ëý–5�Ÿ2ª³õG‹Eé$ÇÁtÀ&�ÿÒì£6])ƒCs±¹ Ç$;bSoôâÑì:ÆÕQ¾œÚü5Ÿ¡Ó|’ç¤Ï‡i8› ·¦“릆ü23qÒ¨ïÉã}©“ŽØv­·våÔ½FÒ§þ¼”b+Ž¿“ÿM÷h¼—ãÕÞ_¥ú¸™iÜÔ5éÿÞÛ~åe¬žžíããzV6‘£(—×u>ök>¾Ý¾ÖÜx%·:'ì2Drΰ…3Êq¥öWo"gG _䯞ËÙŸ*ûÒy¹h~‘™c­ÝF¬]WÏëu ñO¹ÿ ³ê}PO.7L­AY»NŽøÁ5e8fòÃrÖ_×:——hŒ%¡åg¢ Ã2¸Eôî‚c¬Y'4¼ ÷Âüù´ÖhPpO·±î<Òç‡}åüd‰ �±PÔ�.CQ8 Æe/„ºSb]ôÃ`Ò­wX €ÀÈ £9�9cï9˜Êÿj¼cG'_3ƒÃ,U5ý³ü�Í´FÐWJW‡vRÖŽŠæO|ó=F–}]R'æä¦Éms[wÔ~ §¡ÒIZ_Ü¿dÁ¸öP¼yá9zécéÊ.N-1ÆÕ9PÊ­Ú¬ËJV™DùGÚÞ¶k/ô':èi¹¢w—3¦ÚQç»ëLmEw-avò§³µßL:„(¸2 ò6“V-žîø¢¨1…Œ'#Õ˯øÙÓfy1¢Òp”'÷ˆÎb¶˜:mŒd)šdæ&áúè+J’`ËIÜÛy ¾Ö*Oû"ȳõúð�~ø7)ý™÷¹¶ñSçüÄÑAËUÞ.ĘË)ðà+, ÍÚÐÆ[ EsT}~}JÅ›M"�=ª_ÝSãéä6ÀG”‚g¹£Í!�–%lÎ�¸Ç…ÎŪF¡±•5rHËõeŽ=¹õ¡ph4é©4Žccfi*·ËüemrÛ^™"”ƒâù’L_gSPt…¥Ú£­5†Ãn~öFÃbxQœ‹o÷m”’xLg\�JÏ„)qq½QŸ5V¶]@Çw-ÒfIzToïû�»4) ªTÁíì¶€é×w…¯�qô^uÛyºŽÏc}0[_jAUúis.P�hk#3„cËð®ÌaÛD¡¼f¼¤ü›òó¥È‚-·$r \åÜØ?Eö *ã°UÊsÍEÇ(&ðQ)¿¾=³mÓh9­FÚÏTD>›Rå8¸¹sÊù®ìóÙ�©¸ÊiÌXžN��JÃÉé`Iž}ŸXQÊŽ`6:Àˆ—a‡r ëû’‡ÉI|º¤ÍX‡ F})•5†©iÈá*ÓÀ¨?�õ³ŒKЦËuŒŠlYCŠ*[õ6#·2ù»y¤¢OàqØ¥EUtf.uÉ£%+}Tµ�” ³€1cÇ¡ÅpáG|¯ëBÔ3Ë¥ío‘›tÕÎÇÑGðé˜�I™¾˜‰ö¹ø˜"Ú‰p’¶1 zÊh]Ǩ(ÍyQNêpŽ3å’™ÁŽˆ‚6ƒäbñ‡ÛH=IΤ®¦®AÔžËR†cÀ¹Q emõ™‹ÊP/ƒ{¦haÁ�Ì IªŒïùèŒ$ygä9 Ø_Ñ]ÒèP)J(Êøè�LÞu^ñ*—LWE´àŸ>R7!áãS{å$yÝOûðÓ~\´â˶ԧ�úÚ#ÓÛ¥€>èãóŸlš‚ÉÛxï÷(=èOÃë\0õŸ„FtÄþ:í¶îÂo޲Ç\—ñ©£µ9ò¢+w†<œ Ç(êàˆ�3—Ü ¥¤!ç€è;Οõ,×4ƒÊPu#p¾{ÍÛsìãT—�enÎ3(BZó$lÔy¡Ï JФi×+ÓKŽè\WÓþv] WÙ‡gz/¶sT¦Þ‹qjç±Ç9ÎÍ$÷DÃ�{¿'‰åç³óåÐ@MBô§Ó¾v\¸ååﯚ¹Êº×X²ÿº¿ç#ü(ç®é ³­¬@:äz"Ëö>5½eVK¥ü-[Jª¿�,g£nö1mË–(WCˆŒ8™Á%'9�ôÈ@‘³î’V�Žt ¬¦‡Ú²Â8ú.0ÇèLpj%2I×7 ¶´'—6³Ýù£Èã��‹3D9¿û¨€píÅ2˜<ˆsÒ)7ËvrM#Ã"„ŠÂ:ÆrØX¹Þ� —³ƒÙŽñŠýè�¹ðX s†Üæò8 %±Q¾XZÊÀò¢À,'šEæš' pÇÞ�Ñò§€å¨6™ÆrHfÂ�>Vl:¯,{ft�O`É =2³#ÿ3I©À`‹kß9˜�GÒã`÷�fú#°Û �¯ÅRNÒWÞ׈bW0ãÅ£�õ_Q‘ïf�†_&¦ñcÊ„K{‰›Œë)­+ÜM ÊC†P“sÇÓN³„”?Áó¶,ãd¢?r$ɨ¯ž1ÞeHŠ›DŒ�îêÙKñG‘/(g\ªl|º ôê“‘ŸFs ¸ðÿQÂs¨œçÙ»ç‰ã¼á‘9°@ý;'Ö,>ÊüÑ:†NÕŽïŽ�…2Æí£2� áÅÊìüI9åYŠõ�2@pî•BÇç0œG8ΓŽ�ë“s޶2ˬº³D©µ’BƒÏ<0Æó½´ù<Ï[ªŸii ¿"39J u§ˆˆµèÒ1gr¶5ˆ)xÐSGI'ä-J½µ~KŽ’žd_Ö;Ö®øÅËùØßSš' eHÙ*�˜¸È«ÿ…QÅðêkQ¸úVèèFëu4fM¤!.l¢ßw,1piÜ/7q<Ð^¥AÊëÓg„÷sËL°ü…m+ ì+�œa¤Œ„éžR?¥I®Ç×tùÓñÚõ×íÇæâÿ“{qíÓÝ.ß_޾ ë:)‰,äÌ@e Üx8ìáâ*^“ê†ÂÁS 4%YÀš�Þa¹˜Hk”ó‡�2cÜl8÷›KRÔ˜7ÚÐý)¦k®>®ËØÏSA*«A¿§ö}Z8öÚ7™˜©É~ê3`kïF „à�0äRh‡P2®”¼x ÎØ càóÀ:àŒÄ1øiÈ�º”Àc¨¼Pðôt`°æ¼Ä„_^«�A§Ö2Àø6ï çòó3¿…¡£§2o¨~»†ïm�ž;¹[¼8OMJ'³¸ ‡½ãH"è 8ù�²Ž$RA£"�ÖŠRAóax`b,-bƒS‰‚ÜHQJΑFË,#BúpOɱIQlœÑ0ËèT:ÁU >gš4È0�ÀhÆZËs˜ê=£ö]mþ†æ€hs—ôÊNö¸ÎËÔÌT�«T û�ÀNF*rë)̨(U¿¨ùcô]b¦2kLÏ TD›9 ¢žQ;ª˜ —À&°)Ç‘è*2*65íEƒ9þ›.�c”ž“"f2ÖÁ÷¬É Sä|£WÌŽËfÄù\ä»Ñ–×`çY`<Û1(z¬œ¦é‡á/bqéH~ˆËÂÃó€†Òå\ЇœžÜ¤z²ß�JMR‡9÷ñóŒÝˆ« ÍùJÛèUßSÅü7¬@zGÃDµ°ÑzÇ� ÝRÏvÑ+=Ðd„¨ïÃ.pé Ñw=â×Ó?hª;^ÝۯϨﻹòü‹¾Š©úýrcE}ÛÆâU_Ÿ�¹â+-œýÅUö4W�«ò9Á窫ZÎFÉjSd¨”Cü±h@âÂ|àÈ4~—þÇ(¹káø\ hß-8e GoˆŠ®¿Ì”‰ž°‹á}@kº®¸V§h¢Íh[ik¡86h�”ØCc•§IwëïèÄjç8ï©El]ß�ú;/}t\�ž.C»ë·¦zKÙméÊ7^Wz¦ß絫a—7ž4þ´š¿ô\�Иä8WËHnÙI"ûÝi7¯¹`+ƒì#ÕûÜŸåk|=ìƒ×«ß°¿[ÿ,9ÚôÖÆR–�ÆJ†/]ñ”a´;òù|DÓõ†Õà/õÌ‘{±Q¤E4lûK_z¤j´q¸ãÐçV!áÚ73îs@~f/v8\³e;1šGüWˆŽÒì4�Žv¾Êž-FƋ劤„ÕËâkÃ^¢4ñAi²Â =Ú¨„;:�&î€ç&µ[<£‰œõÅW”^™«•_C»˜{ì/„µÉ!ŽB}‡žA³ÐH‹!Ú¤�&ÓÖ„!ŒükÆ2`¨$¥1ºX3¤y ž3KY[ôÛÌ[ñT¡ä|T®jM`Me hccbö¿FíÌ" Ë@¤à9å´À³ˆã UUûE­§MEÓåFðò�*�•&ÿvÓý/i€úl‘L,§ˆr˜ó¹[ ÓBDŠ×ŒmÈ �FNc0UFê[Êþ'J籠?Ò«¾º¨Ý¿è]Ùã2ö "�àeÑ¥ ÛJ–ÀÂî4Ž#œt e œ7f D�²oÖ0L›[¶@–£Ü˜ká6Ï(<'´¿EΕyïX3ø²èDŽ�ØG`p¼´¿áa ”“c@4[†óˆŒ›CeÊ`XCk$P®qß�µÅcÕºP%’Že �ØKÊæ01l$E‚¥~µ‡AÏ£dÑx²CçŽÔQ×£¯¤ ,åc92ƒ�"öÃ6G‹Ù=ßœãçE˜)#žônÙկþ‰z #ÚZ3³5:­W–E{⺛íß–c@½7kïÒÀ<_£’ç´æ·¨m¾òaÚyÞ¾Ó,.I:UHg{q"Ú¬'Ð�â`9‹ k ‚ÎÜ=2¿„PuŸJé’öþïs¼ ÆíÐ=¯¯Ÿ{ô~>QéýùÏ–ó ÏžŠ®š¿vpw�¸{e0">»b AØ�£'àÓÉ!Èsª u–kI«ïõ¾•Bs Ýí~äN[쇮Ûþ¶×Cïõ,Ö (Žú�3§þi6ÜU°�c'z�Ž­K,Î>-9F’V ™äéýÞÀ ð0ãD,®? ؤc4 MÜÜ÷ûÂýtT±Ož�mÞ#ª—eÓ†3U)ÁkÑhéé2|uáÕ†Æ�–¡3°– £6ujF{ÃÌ4Í}.í—i‰÷çZÄ”Éä+mØàOi&òx_Q¶`LƒÓ9ËÇþG+#‘ =Æ8öø ¬9] O™R&®^‡ ¹¶ ÃäôÀM2„Öæ«Ì²¦£9’rU´=ã}*‹Á€Ø§1q±ç˜õ—‚Á+÷5�S@AùŸÓÀÞÄoòø†Ë^IròR›E]±Àõ½yÍ¡4zò¤ª-ÈÈÝå‘ó[#5þ–äPáµ’ Ñ!óÌ(Òç3eKQ ß_Xý¦`JVnÁŠ:ˆWä@ê,ñŒYÁoç‰óö†óvˬ•І#ÿsÄšòP0R+Û3Kú‹¨ù•Æñ õYß1ª~*HFv4Ü+Zü c@%Zib0IÛ3uPíGÀ²Ñ-ëÇýHâ+‚âbSyñ80ÆÑžé@ØV®Ãçð­í£Œªd}_O-L•sOyTTÛ4x· ¶#qs q ¤Œl¸7 ¿Þûý>Ø)»9V.Ï·~ î¿}k€œUµO…ì'åàµ,%­ JòŽd¿>|`ÏýÞ›c ù·—W‡¯úÔ D›¤Šx�}öúΊqs€bôΞŸc@®=TŠbC,Z—¤§’}•�á‡ÆÖ~û’ ¢ž@Àóò°×_õx¢Ž‹ÿÉ[´þ½°Ùf;ׯß_®1/ ºJY;ç$œ�<,œ°‡Ã™)`Óá —RÔDö$£¶ú}¥}¦»½k…FÀ Ë\1ð®AÑÞû«;û ^8 #ñÄsÛ»ɨ-uɽ¾·Š†�òØh4�¶d¢B·D)µh�G^û¨q'“kp ’JD#û mä×h\¡2T…ç ØÍ°>ÁjÓð˜†ûÝðåÝð~įij€Eò;ÇíŠ=KÑ£ñ•m¿u¿¢q´ïšk|œ�óÁÕ%Ãíòý³C íÁ[”@“qr,÷4ÆfÄN3 ‹¹ñÁ—Z!-§H5kuAµçAA¸µdô?²œÛrD©“¬h�HeÛéU”ßǨÖOItMÉz‚`4²Yka.¦÷¢Ê§¹·1ÖÆÊšœº+rC®ž«×è'ýîIdL7l�ÖÛóÆ«j«Ë Sy¨|¤�¼x\›ç:çr`f5´ ç ypRn¹ÓY¢ì «>9rÌ�÷�n|Zìo¼oÈSNÞÎdÅ/%¸Ò,ÛÆE#¨È›8Úæ}2ª“¨½V£i-kïk.cÁ¸®Ïœ KQZeçÈ)0pGéVÔÿÇðvn§å†À!ºc ²”¬E„œ¡p=’˜gÙªa þ_>;_€ö{hò` `…“'ñº'(ß#ê*s •5hc°dØE¹ç†Kó|P…X8ÑŠÖ-í"™b»¹ŒúØØ¾üø± Î�ë³2 Òss9Ö\ Òãž RXK´‡‹¼)c4Úxîr¶Œ0‹Ñà¥XwlÌÒ €r8už–l°þ_ÍØ4Ç«ó fÿ/qï-Ùuž‰}ÿ>§ªnê{;g ‘(0‚%Š•–FÒÙ¯ö,ûÁ^3kyôà7?Ž5Ëo³¼lk$YžR¢H‰f €©ÑètîÛᆪ:gÿ~øÃþϩ۠43ò ºêV�°÷¿ÿýçP ×°áQÙ}�#ð¦þ½þÎ2[3Hz9W®�aåNض¥ï [kVX8Šf'q*iƃI %ŽO×`ˆ¬×2–r“VÐäzÙ,?ÐJAë0\7R�ãþ,»%¬•3Øùá+7Å@¹¦ÍBãsÒhst|¦™+²cC@âî·sÛóÐõ |ËîËe²}ʦq1Di©ó:²ß„@°ÓB1Z[ö½ ¥²wõ*“}Ý }ú¼ÔÄVù�!¾ÑÚ­äÛÏñ; RºÙÃ2WgÏ¢ÞÞŠú‘�‰ m§ÐgB§B9Kæ»ôuÄÏœA¹¬¡?×åÕ2‚^Æ¢^2.™zD èÍ;Ô ¢Þ¡”á™®…Fi¬C)¸ór€qY@“9ù:İ-D� XY�xt=²„(Dcæî¼ý�™/orÄßßm[�ÓÆÍî¹Õ÷?ë»›}æ2$3j´\2´··â@“%òªú™å³Á´À­CøA½sí *kX¤EùœGögá¶s»¿÷³칂Å017¿÷ðÍÀfŒ³{ÂÆ•dÇIèÆÍje×0¸ï“xS 7Ö=è 4N }ÏÆ�ÁÇñÙÂ[Ô\ê @…¦¦S`<6ÇŒñ„1m²8,»„!DŠXj¬kÊ'ÀaêκMœæ-�­÷¢\]„…¾¦snÏ�2kP‰÷%$÷î(í#DÛ\ ÐáH)¿ Á.¯€®`_2]ÿ ‰µ•3Ñ´½¶j‘³ÔtoÕá)†>�*·Ú7¾æ"ظá]òÎXm=üü°WnÙ¸´â"³ÕmáÎ?¥!T.ëÀZì¶í3@Rqä¢ìIQHizˆ®Q�¯#:ê%`IcÈ"ÉÉkvŲ;Pã5 Ï”ûJå2Òý^X}Î2*OkW9¬$Áü K?âì/Bò½Ä.tf�#�b�Œ�},ݵô�Óc³†‰²”�™š0DÅPîÛ@ñAR]+[¹S«8©Î�–Òýa÷XÛØÀæt›ãMŒ,ÌÍcçò²:4u–”~hÖŠ€A�4•U"Z¬ŸEºXÍLd¶Ñ]{²z±V¶‰�¦�¢m˜ \W’•SUäYŽã�°¦©1ÐɘæŒi+´Ð$úÙ`_JíªV²‘4R6eÓEJHP£4e0•~Æ6*%á^»Ô֜ʜ<릤ÍΕO ì3%¤†õÌR]Ýõ1jè œÄ€9x‡Þ²ï®ŸIoÅ0d½mtÔ3R¾ÞÏîk� Œp?Ãí’‚;ó¬ðwqü;£êŒ·Ì§ÂÏÎèŒR {¾²ÛêˆÆ¡(KÍ>kvnÂ[Kù¦âè? ŽN×ød<‚Ϭ}ýÙP¡q££ÊZ±4„g ‘uØ…€ Bg¼fÉŽà’–s ¢²'`ÆÁ&Ð|uàçÙólïxB{v´ Û3ƒ‘©sCC.[Z—/âaáY@¤£ 3.çÏf;vwÌlF f~ß*û Ê7[ß¹{GŸ¶Ÿ;»þ�Ùõ]R 8NXqIp¸ÈÌêÀb»¾ì(—/Xäö-Ia†VÅõ5µßžWÆ\š•Ié>óÝ%ëÓ ¡9¤-|<¡dÌ‚,[Ñè·®iæ [±ðqfÞ´Ž}‰H�aʽ¿€ïe/Œ&°ËR“d �±8 Ô 1t³'ª�ŽÊ™ú£#§Ž,¹®d§tùŠºYO\5……‰m�YÓVçÿd:ªñÙÛ嫤úªÕ ®¥�R²sŠ!¼®k1x“•ìÑ{hŸgä‘*eÍh›M›1�JCðÂ#U)C)½–À®;UĽËÙHà\ù�êÉ%}©8I-C¦ã3Ó ë ¡q2iÀž8L–<ØÏ®ÉYû�ÈßmÅ^ µÊÅIPxYqF˜:¼·óO‘ñl��©E§@ßÑVpŠ»ï½c&ƒ�QdÑ΀l A&‡ñ‚2 ïg¡=-l¬”ÉJ+¡¦ &6ŽÜ…ŠÉÒ¶ÇëÎd Fú’ETœÐýàBœ2=&"y%# 9.[K�òg£ænB‚}ç×û{7vÊ�®�U°ï¸|a°ÂàÜÇY:ñV w*\®·Èá=­[KVvC°-Né~ËßÊRn!DnI°ÿ•µðw¥sV#™[Y'´¤�!Ug¼é°0n-Ɔ€i.|�Ètg�!SYÜ›LÅýqs[$¾¿ôCê~g_›ÌñWîì îÔïÁ½Ð”.�éààÄ©?/—Ì».ruÇÁ ©™Fö û•‡ÁÒ àjµÏ£?�Þ¸zûÈÊíÕµ‚fH˜Œ€ùcc”17&ÓŒi“ÝH–[1æYj  F 7}Ëõˆa¡O³{£C[{ àº�� Üè\§s¼©¡¦�ŽÙ�…¸Úr›ƒÂd÷€Ô©5*ÕÒ’)Pc“�QhH(ŠRUi”Ä)×®ì1YŒ.D%ÄÁWŒVft"b1ŒC�>Ù.‘4rYÁe+KjçI„L–è” ¹¾×ÈYŒCžVÎ/ ÜÙÿ-õ²•³M€yÝ–&² Dç€.Ü[ƒ;ψхÙi(|­Dèï ,åƒi—í%ÿ>I™U¶/¸Ú!sz“È2Ë^6<ƒ³ã¢¹À¨“eX8´eXÿÙÒKÞI‰¨”o‘{mŒÇxñø«xçÒy\¹¾ŠëëkO'³©Œ[D„Ñ`€m ص¼Œ};¶ãþ;nÃmûö„¾%õUÞ‹¿Ð4+Fé éØÉk\Š”=™0Ø8KCã:¹¯Îp8çh¥¿— Ê� ¨-3ÖrB,/‰d¡b˜¯Ò9;(ó…ÄDHIa‰¬ Ž&´†s&ó¨i"¾‹b䤀Fû^@EÎý^™WïGÁiå °¨ßlmØÔ¡ß‚3…äFzƒÎg7¨èš³_ÁÓx�6uî'eÎr�¾mq�OÇÎ+Ïú‡ð —£ýÖ¶¯nþü¾(v³#*b[9»ãg.f\K�ߢ3›MÖè>52çyV³ƒæÎ:woŠ«éÉ麨'Ö8¸¤Óë3tŠ’U€e�ÛEdÊr/Ñ�Ì™¥އ1Žø„®&PÊ Ø r„{˜ºs—ÛÔ¼}¸E™$ç¬=WèÌÔÇyçy:Çœ1™n`:£m¦hÚ)šfЦ™ø+«’ß4SÙµjÀjÛU=úD„ªªĄ́ªu=À`0‡A=ÔÏCÔÕ€õ-(‹Þ1`d:!Îì|¾+H÷àaÊ:ÌI•¨n…Êu¯È"N“â=âóz{Èe †”jȕٶ-2kY7Í”ôì.½›ÛŽÌo½•ˆ•F‰Š\²äõ@;Ö×ÜÛNq/õÉiüPþ 2 •ëý÷-iŒ1.çQÿ †éÏB çJ�ÿ2^“—�Y�ºäxʺ_em“îw‚æ#-KH)—¾KºÞVNˆµ¤�9@kþQþëñ1ªÞèª#Á+â2d.Vºè&Œ6ÐŒŽUŒfÊ?ƒLk™|&—òôoÆz®ñ’8·þg‹àq))’”Èé!“üÞ4ÓiƒÉ´U§€•4ãe¥6åJè µ†ð(ö ƒŒ)N*ÿÖ×±‡Ù^óÏ 2`†d+$€Z…e#\£e§S²&â¬÷Y"H P-åéÑÅ\ðE¥{ßl°‚Ëm«{Ý�¥ï¥kŠ6¹&“ ‘BøÝ?TnCÒÈ_—Ïe,m&)MiÕ s•õ3CP"ëO2<’Äq“+•¶{o9¬†yQ�‹|—™A¹U;²ÄF—B"ÅHI d’^rR^Z�$¤r%à§b»³q{˜,ˆÖ�6×86™VerV#lHèÏ.„ö�`ͦpD²�‹"媞áïã*Pd”RS&ÆU)‡j}CÄ^U‚O ìeŠ\®pZ(úŒ­%ȹül2š6£ª¤Ü�Ýñ¼äKvk–tÌ�–ì)S¦A²º²}Ï6v¸¡Ú2þ�M30ÍFt ßTwO‰Qéð\�ež3¨í:*¥emft3xÔ)èjgeÃBφvi§�ÓÑóƒ>ýûÌ`¯²âi¯Èˆq~²Ú€dm=•§ÌÆù•9v•â0ƒS’ · gGùE˜‡Ž±7ý¨Ô‘t Áñ ¯ãéÖ…pŽÕM#�@eÅ?_AËæ@AìbÝ ¬!�ýuêDÈBm-ÉtÏÛò)€‰JF@¸Ô„Hwl!Í<䦚Oÿš­Îá›|þû7»çâaw’o8V ·,–>q>ºcŸ†fVã¸ÝܳÙÜr¹>¯ƒ«ÅôíkåÜ�Êõ�|æ)ãεv?Ù°‰§é]×\˜©â’sS*Kf'Ø„ ð®¦úÌN3¤Îž²ñŒúBX|†~¯ÑRáü(A¼ú.{b 1¨J¨‘0FC`8d ‡Ã!0œdL‰¯TPϬ5™¥–cxT‡åHR�Ñ—6ÖP˜”Ðu#­Â;wׯ"…º®ÅBøcXŸ)ô�.Nˆ�x+̶bW“…ïÄú ¬YÇœR§Q•1 ÎÙ³²á, Œãê›Ð›[–È�œQù8Ùš"û˜\zsšÓƒl?•Ÿ`‚®‚e¾ ][G_æ2–šéù%0ÖÆ½gΰaõÆe›€N°�S9 ©�ÛFIÔ†l©€¦Ck éÛ@EÝ©[É9$Û1P¬e)%=ÀRÝ­NoÇp×ÙEh%Q\qâòàŽpï4Ê�ÅJ1˜(Ûå‘!Q^ñ…,º/¹1ÞTUbĨ«ucQn3žyù%Î×Dn²"çŽ'÷½ç,oÛ…â� Ž÷Å0Çà¤8�ˆ¥Æ¯EÐÚÆ`dÏXsÛµÏ9m‹Ÿ>ÿ5ˆƒBz€ô�¶m¾ÙÑ4“‚¬6+fù¾wÜrËÏáÞ{>ZÀà>™l`mý*n¬­bmí*67o`<ÙÀx¼ŽÉt“ÉæÌýþ±Žªª17ZÄÜÜF£E,Ì/aiq£Ñ WgžÙ� ,݃]~±fßɹæEÚz_eÎØo`s<Ææd“f‚i3Å´�b:�¢i‚øÇ>Ä9>ÄÜp„…Ñ–æ°8·€ºªþ^×ÞÓ¥}n(vƒì»ÞÈe0JA>Ög$2ú —u¢üdFR€–‘P±Ñ,“U6"öìb·,jÕœó¢“åiJ 2Qtõi“^ì§ÅÑ—T‰Ðc�”R¶í‰ªÅ)¸¬@µÄ«q&Pp܇KŒFeHy3²,Á]�\')'•U]F òñÊíDvM®uaàó/P1e[Y޶Íb„愬Æg©™^‹Ü•+ÔÜbšZ”2=ïÌØYJŒD½Hñ+àaQÏNٻɺD`´Ž·‰¤d+ ‘F¬HR�Îåja0är1\B‡~ È’…ix­ŽÀܨÌV®gÊJ¨èëá(Ο"kwpÒaPè[ÖŒMÑ¡Å)ÃLî¤õB`køhëg{¼è_äûÐ28DÒÈc òq<4œtÕ"Ž[ƒºl­¹ðT ƒ³Ö‘6{QÇöCå¦YqD�zgUa88ã¢SÀ`=³”‘qL¬Yn�uÍÀJZ¤Ð&—Ñì {Ýœ²Ò« {é Jšjd� Çõ¬´­Ê-ÚÜ€‹Ž—ÒA‰Uÿ¶„È/¬™)̨8kÉ©BÓÌö`�‰Eœ<¡”@-£ªÙƒ'Ü‘¨0›q èÉË µ`–æÆ@Öž¢¯ˆ¼#xo=ç*Ë ·þsŠ_“7f´W<"Ò`Ñ_R²ï¥‹‹À�”±ÐgÃ)C!ŽÎ�è°>']ù`«èê*žDšØ·ç”ž†Œ]ÇCt"”ïJé°®“­Ÿé+™K€XJÒœÙhs 0,Ï´ [92b¶¹ü½µ1ìÁ&òÊ}9Ç3 æH˜=|ÙŠeh^‹†§±Õ\@çY‰4â¾Ê>áTËCL­¥ø³mæ  ˜ÏO²Mì ÙeÌAR3péøKhooÂvÏ2Zîüþî"o÷^ŸïâOeå!qœ&¦ô É}èöžcøcJ‘ BÈP'¤j+NjYr„Z€ZîÖ®¢ðò2)B�½Xdy ºR’ý-¯ÎÆê 9ÌË \„2ûP­x˜Ø£ß©»Ûh–CÎvå„�ïf1–½ (gûA7�nDÇcÞqIФZªÌ*h8  ”ÐâÞÅaãúµeR†%ýg²­G¼E°²0‘âBv‚’P'ƨæ*Â\MׄIM˜4$¥‚3É¢›Ñ»°ic¯. [Ìœ)Q„®`\`¤"q‘; ¥ðÔ'’Â¥o¨af�BêE³Ì,`õÉ<ºÐb4*D¹0|oð–�õÙ°c™×.,Ë�ð�F3IÉÆ¥ºÁ­UFÓefpáѲ¸¢[Í~/Ø4;žtϥ̡L”QYC$£'\PÖ.NhZÛfäèJI þ³c¨q¦D ŽˆLHžá>_Ë( wšÛÉaXÔ³+LI“.‹X¥9Á‚ãœ&>Ε»Fq‚m÷h7%r•`”Ü{–ÀÈŽ–ð0\öu.<®Œƒ|^à²G|úÅY'5.�:Y³_¨“@£« ¯œ:…¯~ï8yîœÂïr€•ºÆBJXH ;ªs‰p-gläŒR…o®ßÀt‹{µ9ãÜ•Uœ»²Šo>÷"Vçñ©÷ß�/|üŒâÐŒ˜‹£Êªd¨"ÔµdÔµ”+bf´ !W ›L��ïÛ–I�m-¦­4ô�f ÉTö ¦�›Ñdu<� [�ò/,¢Ëû|’ýU­Ñ3ºŸS’º¿š[/JiÊàVh@ ež5�–˜’–ÿáRº FW¬œP`µÚ´Õ"Ãà´Ð^ ØÞнØmf´á_ã¦g\8D_ˆä×þ˜‰f/{$¹!KÇ«{Üì¾]§‡-hçÛž u(/©ªlüßå˜â~á(/®W(nožè>èæFtO+ ~á?PÞÄa~1"¾Ì��¡î ”þu»…ÉóÈd’-,‹T3¿°‚ëç/ÎüþŸû¸pé––öB¢D+y× +ÙD42åÉè ©��Â<…ŠØ ”5(üðÚÕ·qùÒéôùíßw;Âx¼†“§_ÂúúU¬¯_ÃÚúÕ- ÿ¥Ž¶m°¶~këW;ß#,-®`qq;V–vaaaY~p™ ˜¯•ù>DysùÙ‰z{Cå<.Æ?ç ~-û½š¶ÁÛÏ`<ÙÄædãéø?,þSqŽ�±9cõÆ5ÿ~a4�íK+ر´‚Åùù°¼ô(t´P^ÌœUžgƤä×–(ôB��ôR\#òñ˜úÐ1(f‰:õÅMDÎÙ8ˆÉ E-É2ZòÂwwPÑ9¥pwHx €ÌæácÔ1!r'‘dùÌ Z¤ŒµÂª¬uêÿXÎó²j>«ð|埖ukê_¹¯R³N½['n²-«MÄRfª7°eX–>­Ûn¤ßL49ˆ ñ–†#ö|�Läx…Þ*þpv¾%вB³ü0~ö¶Ñh]PFËŒ„F0�RàdMV‹}ƒU¾)½›ä„2*“_J#×ÖK1uœ½,RWoˆ‘ì¢â•ùfÖØlN’éf�w8ÁËMcg(-dÍX¶Ëé 'L1ÔuÓ`Ãs/ûkAx�÷™4bkb�Œ­ñ°²É³W!=™4q�æî>²ç³e{Ø3ž9nê˜Ó}®Ef Ó…Ëš¾Wº|ÇŸ¦2�9|ûš¬NFìÞËd@Ü‚<’5Ö$¦B§´ž>™ÂË-ˆ%¥>ŠSù¯N°°W£s€(d0P¹^2ÒÈaèBǬ&9‰Ô'ö†ÃŒª™Ü‚sëeV­§ç,ßgÉ0çN­åËÈš’82'ÓŒzRšL'0Ã~®ÍèNšyc%À€†D9¦4 Þ±˜õrf��ÏÙzkØÞÑlãÿ¹ç™!¾DΚd€2¾Å¦SÀù|ŸÙiE¾pÛ�î“ÎA²*-'�1àIÊMU�¬+d0”kCL%Æ>?o6LAt§0t³¯ ×îQê¤8öw™â�Ø]æEb”,ÐÌb©² <ÍÖ,µ©{ÏÌàî‹áŠftÓó”Îíî´Ðkmæ(4ç‚'ŠQH7 ·ðl2gFЧ\’ˆâèVs¸é¯å-¾ûY7Œ,·_;¶òÞü}dž°ñ*7XÂJ5¤Í†­Ÿ¼Ñ°ÅÊè”ö1IN=ffDï c(³ò -F÷ Ä½_#¥=Ï~IZ·Û¹ ŽjæSA¡\gLJ°-Së‹LKdgNz/wpDÜL †¿àÅ K÷H…’YæíÞ•ãwÊàŸÔ»ŒcDYÓ†zª FæÑ ‹w˜ ”1Mc}Uƒ*hWz­½­÷�Áæ)O²XV7nä´ñYâQ¬%߀ŒLGa&Þ ³# ¦šüežX«…—|ýÇ“4 *È~Y# úÍBI´r‰dô1ÅbÀÉðód>BžH�ñ &޶Ìh‘ÐС¥¬ÉÿiìÛ±,pã™Ç°LJ ¨aXgÔuV¸e$nPÁþ†4à£J5ªª‚DŽÆ“)6Ç-&Ó“F#¹H Šœ  5‰0WAjð7P%…%Ò,·–KÈYÖ"Y¢­(3ˆ³Ó«eÌœ•§Š|)%œ9sÆa5-byû k×ñÆñ½+쬱ßââ"¶oߎ¦i±k÷.9r ó  $%�¥_Ñ Æ®Ý{°±±Žµë×{÷í¥„+—/¡™N±¸´ ëëk †¨ª ›››ØÜÜÀd<Áù °¶vëxë­¸páÚ@£`:ãÊêy\Y=�Ó†Ã9ìXÙ‹+û°mÛÇWµm9’CiŸÑ�`zV IDATÆúB�-‹ƒèá)˜6œ¿rî]á9±°°€�� =z‡Æââ¦Í£ÑvîØŽº®%[bam3En[o ?‡Ê‡À`0Àh4‡k×®‚ˆ�Û“¦Åt2Æõë×qéÒ%œ8qgNŸž)½·>ÞÀúxo_:‹ùÑ<öíØƒ=Ûw‹óX÷»£¨9ĉT/°+‰?†ÛÐqK¹:J ª$ú“¤Ö!R͘XTòŒpÎÁøBEέåmÐÆ–d†ô<�žUd§Dä%k*5‘i­Ô�Þ{ p—¯Á¨í`¹›™¤G™š$†N¹8SáMŽ_! Zdu+ë -ìtXaiuáýùfÜÕëµÚ�Dò&öÒ;”Élà$snYt^ËÂH@ª¤ì†•€Š,âV^êš›ÉÈM‹Üd‘Z¨AU†\!åÚv€iS�Û$×-´¹é¹in‘´¯ƒ9æ$òXšaÚD9K42¡R£–ñ'1Þkæ–Óv”5YÕµºîDÉ<3I3ù–¦¨(C¬Îv7•ë›õZ�ÛE5Ò¹œ£/ ¥¡Á©M­Ä‹˜5²Ó,Óß"žp–¯ >Aª€,L%°‹4‚Û²2s0kM��Ö�&vÄF%K¦†ˆp–§Ù ”µžWRÌèo\�Œ|Š¢X”ÀàLWš™Ùz0–vbæXLðÚ¦ÀLÙ-s49ÍW\”6Ç\¡&øtM­‚CÅAàfJgùäûÂ…TÅã.-5ž¦�µᜮŽË怋QŽ &ƒ^dÛÊqa–±ÈJ‚‘Ìa`r] "1²ävuä¥w9¸÷7¿ë¨Ì�fÊ¿ÑðBÿ#M2£AW ò�êsìög†AtaÒ÷å•}¨ë!šf‚µµ5üÕ—¿‚啕ιãñçÏŸÃ-·Ü ¸qý:þúKÿŸÿÂoan~ðôSßÁ-·Áá[n¬®®b0à�þðpþü9¬Ý¸‚ñ´Å`0*øL’–Þ0%5Øø Ž‘«ÂJo{ò1Éãž±ãÒÅ·ˆñøúã?ƶ¥eìÚ½ó øî“O`mí~ás�c÷î=øæ×¿†wÞ~w½ç|ø¡�àõ×^Å÷Ÿy·Ý~;ÞsÏ}X[_ÃæÆæææñ�ï<‰ÿí_ÿ `ï¾ÛQœJÿSÂáÇÑ4 ö8€û÷ãàÁC˜›ŸÃ‘£·ayÛ2~ü£"猇~wÞu7þò/þ “ñ‡o¹ïàAœ>ù^xþ9ìØ±£á<„áh„ú&ã1޽ ôcøò—¾ˆÍ� €�_ýíßÁ¿ÿ=¼úÊ1 ‡üÚ¯ÿ:®\¾ŒS'ßÂÇ?þq0X¢SÂÉS§pü�×ñÓ^è8z&“Mœ»pç.œÄp0‡½»cßÎèë!b¤'¨‹›Ñ)Àèë\F0³NqïY¸{ <úè£Ø¹s—±k׌770K)¦O>úξó6^}å`Ïž½HUÂåK—°¸´„µµ5¬ßÇÊ?üN¼y—.J¶ÌÃ�| ãÉ?~ö‡€……l[ZÂê•ËåùUÂ`~öÀæ-›¸ïÞ{‘RÂö;qcm §O�ijÏ>‹“o½å×lŒ7pâìIœ:wïÇáÝ0¨+˜ûÄ&ïÛÔŒå ‹ îéÏFÇ5éÞJp‘«ìž¶WÜ gö,Óì3Çõ+‹Av5º‚Õ`j²H e"×µÚ[°²*F^Ù RçB1^²×-0í^¦NÐù EÊFf  YËA4t™1™óEùµ•0Œ‰¢6oR`©Ä ¦+3”=wÏ¢UMžc—\%²·:••ëŠ4³“5*¹ì³ê7VÊ‚Ìi 4m%�sUUP…ÔThH‚#Ú6…u“ò(9OÁY"Œ­ô-q–õÉæØ�g'´`Ê’‰J&oŠL*+nu·©ð*wÔLŽêè0Æf“Ö>Ï"7[Y`’â�–ºµŠ.Ës¿ƒ<ïúŒ®SÁ£ìv-v¼E‘™ �`ESÖòuêÜ‘50ýHàeÁe"+ve“cŠ:‘u/(�VÙG‚[M[ÑÒ_)ðt“ü¬þ³¾Y¾…5–î4‹w&jš䤣Kúm΃«¬@¯‡ãº”À11I�¹Œ²Î*s$¢bR´ûFÒ¦ö@ è¾1Þ妯uÎ\Æìr-‘8“ÚñŠHZ¶zR#}VçN›‘UvÏP–´Út¸%¯ y=€Üd´Ó\Õ.ÓY¦{Á…Y^F$†J ÊB3,¶Ò^lƒš0¨KÓá:‰¾—l~LWà6£miÈ~w§É»â„ó8I·輅 h&-¦ ´Ä± hJ�j0UÈL˜6ŒiË|ÜæRI¡ Zv³áË®�2i ®â@nNð&즇)¿ëØ<�æ:Z•Ö Ú&Ÿ3+ jáe( .ƒf ó@zÜURMêp1§ —½i¶º€cRͶÕRf¶ÞJ;Í1€9#µ Ԓàd'(~å²³e‘9t�mf¥áWWˆèì¥Èímæ]0³xN2ÄSh+h­Öcò@�ü‘ñ³}Ïæ"àûïa|6¦ø}¼!¿ËwþõÎímB?%œû®Çì&îŸ{üÿtDZ?s¶¢àIGø´ß:R':›Wײ+ÛwH�çÜ6�EE¨ÞЋ`EŽÁ¨{7ŸƒýäFâx—±Å_LB°‰š@©¼%>¦Ëšâ;ºøÉ…iw,Ë@¦Ì¬­2ĸœ7:7Ó± C#Re¼âž‘m­Ñ45À5� H »ªbT©u#V©e—üÞÖ„ØžÇJÜ;s„ VF7V&7†Ø…TÅ¿¿‚‰û€ƒT'ËN……"wÌ`Î9´&) ŠÆ*­Ñ—(I&TÚ ÊØ@Ö¨ ®«Fmdh©Á§–[©äå)®=!6:ëì£/Ã�§"røÝ�Bfõõîœã±µs·üæÌZω'‰�Y"ôIqƒ5m1‡|qR<6×ô0C§¢HØ+´-é[ÑÚþïÌ¢±ò‘íÎ}n‹£+W9@?Åý#pfÆbKëûÚÆneÀÊ�;´£c ¹¨Ì?Í|Î@ç[žA[Ü߹γ:Á+7[£ŽÂ*×mßq/œÀææ&žzê;xÿûïGÓLqäèmòf¬^¹âŽ�Å¥%|öñ_ÆÜü<6Öבª„G>öqÀ‰7�ã­'ð©O?xèá�௿ô%ÀÕճسïW�âËðÌÔ¸›Á†·€³|ßãÖÖ.ccC2î»ï>œzë-~ç÷~_hC. ®O�<‰£·Ý�mÛ–qðÐaüíW¾Œ;vâ7çwѶ_üw fƯüÚç±¼²‚o~ãëþœ}ûïœÏòò2üqì?p�}æpò­øÎ߯d<Æ=÷Ü‹T%œ8q—/]Âx<ÆSO>�{î½£á›ã1þ毾ˆ…ÅEüî?ùœxó8žùîS€½ûöáèí·ã'?z0™LpâÍã8rô(޽üöì݃¿ü󋺮ñ¡£¹9|÷;O€™qϽ÷á}÷?€ÿûÏþ°´mþàþÏþàûøÄÇ?ŽÑÜV¯¬âûßÿ>žþ9ŸËdº‰Ó.3g�cçÊ^Ø{æç·m¹ÿ°# }enU>ùÉOá½ï}/666�RÂÎ�;pîì&†Ã!ƒžøÖ7GŽžýðýgžlß±¿ô+¿†¿ù«/bUûê¬Ý¸Ñ¹÷¾ÿ Ú¶ÅÜÜvîÚ�·ÏœÆµ«Rné“�~ß{úiw@½ývœ;{gßy9gܸquUcïž=ø¥ÇÇÂÂ"®_¿Žo?ñm¼úÊ+¤!ò©ógðÎ¥s8²ïîÜ Ò,A@¹Ä˜£Q•ʳL¶í�‘°- ›c€;ôLde½ŽÃw¬7ꥰþ_J<@å,Î +÷nëãåjHË9æ©Ê¨”÷e�n-t‰»³³M,½BÚÀ;äiªIb€M…òO̤1æÞTºûšÕÿ,*[§�¹Ä'*ß&ø�…6e‘óSâb8tF#7!² ˆ¬:“d êºB]›ã¬À€Ç ÌÑ£LrMK˜¶�(Þ†À(�ZG1-À-87bËMùÌI³(*͆”yšlQU"ÃFˆ|º]>Z‚†d>fˆrÑÉÝhœ*TI މ*ÏXñÒªo´Yú°I/›Wh¸ØHÄp^Á‚LˆÄ•úêÈé‘ê–�Äš)¬zD!£j[¤¦�gŠ”´ïW´©öµ”Hó„TU¨*ë¹¥¶gP’£$θªV'À€0èÖ$qÔF£G·&TY^iÂìxAͳ4Ò§6 ;ÒPýêºEÝH "s UIÖ@› ©ÉHMª LIJ–gy¶ô'×Û^](ì­”À’‘íû‡ „P;ŠÉtñ>°Õ†&ÆÌC—•Þ³5î<<©­"ÕnC ‚”X"BF%A+°"=ä,ÌúÊ!TL(ú…¿²ôõk[{~Ð+Èœƒ%�Í3;ü<”ýÉÚìÚíñ²¶uG)`Û÷Aí#ßfVW—œÔŒ“ž¾�3Ø<žYïÏ©gc/ØB±à†G@¿e`l�´{ÿ™ƒ‚gÌ\`ÜÝ}]i ½È#ÒÂŒ°åé³c¹™2<«¨Ü\Éû‡ï6™°¯·TÑåæ³:‚ Ü—·þS×4âÄÏž©2ªì‰Ð5:ƒüarUù×£~λ‰2nÌË׫Ëã°Ê+þ�zžíÞlúŸ&[²{f±uF %xðçEÀÆÏ�õ#"X-;#*¾£˜´%CFž0òh†Õ £ªsI%ƒF?Ká‰YU¦Ã[ëÔŠ$÷—ì…²ÚÆ÷KBd¡S@™ŽGv•ÌÕœœs87`šÅ[¶¯ÉáéŒß¨V¤‘~‚ç$ëeæéŽ«àèÙ_zƒ9ɾ(µ&ŰÛdƤ5&– ƒ`@¢cÌA+Ôܘ� þÙ™;,º¼Náh×;œÉß˽í|Y•²¤Åù`4_ .ëR…]˜"¿.ÌS_ä`–”\@\ …}Ç'ŠÕ<ìœW˜\gIˆfîÿŽ©¯þÛìm1J&ŒD_Ø9~�sP’I�Z¿’ùI…ÿ–’+Ö¥©áJÄO¶1Âá.©¯a2HÀh�0?`X‰C`}sò¥¯âd¯Vøžá¿»k7>·sÖ¦ ¶ƒï]¼‚ûwnǼJ/®^Ã�Û–°8¨Û‡ì çïñ©}»'n¬cÏhˆC -ü“+WQáç´ÜÐZÛbœ3æRÂçvìÀg·oÇË7ÖðW.ãÉ«WÑêê=õÒ üäøÛøç¿ù0Þwd·ôD©4e¶–4ÚR÷°zŒ-ÚÌ’^�*¾ZW"§m+½;)¤‹ì‘S¾Öзi´mvSQ'Ë€gïØz¤$c * ëZi¶8Šúw\pÛ"7 rÓÂz†Q2õO„®²w�{VÖÁè›:B�‘ÎÊ=äw±+î§w¡ÁºóÛÔ£昄óŸ­�Ý{o-/:_ûü‚ñÞþe '€nytä”õv¶ÄgÈì `²{¹›]£ÿv²xÖ8b² =¯4nt·7ö­A8 ð¿©Lbèw«%˜YfìÚy .^8xò‰'ð¹Ç©3Ϲ¹9¼ïý÷žûÉ�q÷{îÁŽ�;O÷)ìٻן››Ãòò²Ãçá‡)Ž�+g°oÿ]0‡I7óÏBØŠL`|�t·jün‡e ÌÍÍáÞûÞ‹;îº ++Ûñæñ7púÔI|âS�b~aÇ^zÇ^~ ‡o¹Ÿ|ôÓxýµWqéâEŒ7ÇxèáGÐ4SlÛ¶ u=Àt:ÅÉ“'ñʱczï%¬¬ìsXÙ·­ŒV¶¯à�×^Ãx¼‰ûüF£žyú)\8~ðCxì3¿ˆoóë8îæð¿ùÛxù¥ëë¸|ùRJسw¯”?ººŠ¿ûÊßàλîÆöíÛqæÌi|ïéïb8áw~ï÷qìå—pêäIL& †CìÙ»×áqîÜY\ÿΓ  †hÛû•/Þwÿh¦S\¿v �<ò0~ÿÿgΜÁ7¿ñu¼ðüó:¿ŒK«gqiõví8€CûïÄ`8÷Z“þá{Oà2H!i_ï¸ãvL§S<ôð#8súN¼yðÈÇ>�œ[|ïéÅx<ö=yãúuüû¿ü L&lß¾ãÉÇ^~ pï}ïŶåew" G#<ø�â�·ÏøZ¾rìåNé¥ç~ü#?wyy/\ÀÒûàC}?øÞ3H‰ðا?�/|á7ñì³?Äÿûµ¯�Yz&¼ñö[8wùî>|¶/.‰Q:±7·”½®¼UdP§l~FÖšð&zßÓXôŸ ëB§·/‘Ø¥æ³&�â²ÖØ×¦dõà�Ä9$‚ÍþìR-鈬ɽ ZåV‰nŠ0¯¬2K™šŽŒ¥•?ü=�`RYÜ])™NúYx€0P1¨i&¸[¡ÀÄF%] “Õ-ª”]Žù°Æ``Ž�p(UÇ€ÉÒf ’H\ e [Ã�bÄM‹«ÒÊÚ³@+å‹\k/ˆ'¥�t›%áÿ‹c %—C#—Œ½BÕÒuVÀutTΠåG[– Éü•2%ÖØ´8¸èA¡*Á ]wŠ|sV®éÊYE' ˜N ‘þ9[â€8.$ÈÄÊÙûÕ Uã[pÑQ‡hÎ�ò7ÈôSuúAvs{]Á—›:³3½�ýœâf°b+/£¶¯¸`Ëfß—Mfâ²9jeå1  ÒœÜÖ†ÊUqS ý/kç“{ó/îE‹à× „�¨¨—¬„R˜YCõ,ŽXs¨sªåŒ©®sUµ¨*1�KV»–'…ér-r¶R¶&»¨^¨å]S%ýàl¯�GR/£”Õ@]Ú0-1ç@¡[¾ TEdÚBîc8Ár‚¬¯¸¶”�ê US"ö2WË–i3Ü1Ài@HM ´rnͥ鶹Á:�K¬NX). :¹¸Å`v,Ãy.™Ô…H�˜e‘Ìá(]/N�ª?+û÷æ<ªHúr"p§WÔ ™uBUW¥¡´ã€ŒÉñSÕrÛs`D½Ac¬·ƒs#ׂÞð j›T‰¦Q¼7ä2¤˜Á.?Å´lV&œ�¹¨C�Ò3eØ�’0Ég¶¯œrØ'àjMöÕQ¤ä­Ç­„£óS¡û…�Õ2ADrRàðxç0�8—-Çó_â¸Ù¢Ê!D¥P»ÆˆQÇ Ò$ Ûë="Ø|y qîþ2�r^ÿ~[i¦!4NaMI ˆ»+éÒ‰ÎÏf>wžÑc>Šß'ht*•ï;ø Xý}!Îv®oÐ-Hard.—úšºdÂañ{x‹Ô$´YOd–T/jõ„P�õ�1HíîAEZRˆEˆ÷ëãJ³§ÎÚxI៕±»åÝœÅ)`Æ'w#†:kïôIqÑx®püR†à5ß ¨æé.èÕ*b ¬%r…U05äµH•¬Æ^ó+}$ó†[tG^ÚVåÜ"sF“Ó,÷3G‡Œ—Ü`ÅÌ[£M™(DLÑ#qÂ×ÌpGA0(ŒÁiÂÍcHf|ɹÜ':ÍŠÐ|Ò²¥dݼü�­±ã.k”Ïì±åØt�¶Ìà°½Ä/™ã}¸(3Ɖ4*¬õùXL…Eû›ª�Rèe‘T¨e B™Cæ�Œª®$õ³®µ4ýuÇmÃ�˜ Fn ‘PÆô‰KÔ ¹¶VʤiÔ°"  £ s5á韾ˆ?ýÆ“�:Çš[Àc+ËøìžÝ¨ˆpmÚàÙË«xlÿß¿æ1 ¼ýc{w�¬7-.N&¸U�þ›m‹oœ½ˆÇöïÆ\%­‚Ïm޽ܱmCáüêtŠ=£!öŒ†h™ñ£Ë«xÏò6Ü·m ¼m _?w?Ø\ÇW¯I4æÚæÿâÿz�þÜ-ø—¿÷ ‡ G5Fƒ ©²¬�™¥c£ $NVvgÚ´òj³Ô¾ä_FQd$*­HR̪8W�ÔÑD`®”fè9žÎ™€œ1Ök 5Ã`FÛ6Ò¨[ñ®ÍìQŒ"aI­Øi»j•Ò%â š>Ûö¸B|Ù·1bI(vÖüêr­ŽÛx—±gYvOÖÌ$vŸ¸ÐÛ’¥Õ‚íkï²Ô›áFQxåÀÏuì=Uåp^™0õÞ" ÏÅiÎOŠÒÓ(‹èy[ ß�õÔ•6âéÅ1 ÔÕS݃Q<¬/Q÷!^JÆ/ºrC�D�?Û]ˆf®‰‡]±¼r)ÕȹÁ‹?}›››˜ŸŸGÓ4ø»¯þ ~éW~ͯ™ŸŸï¬û'>ù)ÔƒÆãMœ;{·9‚ýâÒÅ‹xò‰oáƒzÈû¬®¾ ã×Ñ!PJ+é\8 lÁˆ-çÐ="œ€‹OyäÌ�†xàÁb4áKÿþÿÁ�7pèÐaܵû,¯¬Hï�pêäI$JøÀ‡>Œ}ûà[ßø:.œ?‡Ï>þËX^YÁ3O?…7Þ8îOܳ÷vçOÎ&¬­­áô™·ñ«Ÿÿ üõÿàñ_þUìØ¹?QÃr3�b}m ·Ür+®Ïm8) IDAT®^Å‘£·áÛßürÎøÐ‡B=àk_ý ˜ôc¸ýŽ;ñçú¢m[œ}ç<ðà°ªQíD„_xmÛbÛ¶eTu…7ßxÏ|÷;¸óî÷`÷îÝøéóÏãÌéS "|á·O?õœ|넯ëêxì÷:î,U…O?úiüÑõ_ã[ßü&þîo¿Šñx €qéÊÛ¸²z{÷Á�ýwtðÝ|©¨·qÃÚ2õ®šOÓ4˜››G]—rw¯½r ë�hÿ3§O¡ª*<ö™_ÄóÏýçΞ¼ïþqñâ¼üâO—.]ĵk†×¯]×ÿê‹€C‡ã굫~íÝï¹D„W޽ †Ø½{.^¸àc±RD€àá•Ë—pÇí·ãÃÿü_àßøžQçÅ�Íuüä�—p×áÛpëÞAf³k…·%.¼«CiŠÕÍw¿”-2P‘�,@&8^Œ'k%@ /1£J¡¯vw _˜|Ï€z R’³ m²æ˜dш!`¥k”P€‚9 ¬”ñuBÖöL"Ã,=ö¸•šß‘[CI@‰±R~&u�4Ò�]ÅãÄ2L÷NP±¯9Ùb/MÄ$N“J›}J†@ÒZÕV~ÅŒŒ)ØYl•ÕDŸM>Y´®†ƒZŒ�!5š&P#‘6Ãå�ÀˆM‚�38W¢›i/¡ºJ‰ªb…@¤BU‹‘Ræu1t /N]")7h†Oup$’L‹NÀ‹­!h%€ªÍ*·evˆE7­ÈÏZ-]UI¸¡»4L¶RŸ$º¢n÷—–”T�Ñôf“ùŠAÐ]mò=¹RV•,“D� ~�¢·i6ÆÌ$`ö'ò½.A&¯š]‹­ì•®õ,J©£÷x ¢Ò矄ŽÕäN)»“Ã5ºËÃ3aòÌ–²H8Tx“m]Ê»~Ãf$»­Ó‰B·âgëkHݹ™ÎOIžBT*N€ËʲÊðm«%®’ïcÙk\ÊlUR>ŠI‰Ÿ¶BU5Ú¨·’ÚóIû#%빡˜[d&¤,xÏÉÞEv§$ø“<9C÷Uê$eb+Ã#¥¡Y•Cb*ålûlá}æèËP©U‰³V¨*P– uVyÍ Ye Õ$ô&A*67@ÕH¶@vü6ZbëdòMJð›ó&égã=ÞPʈAè…9,sÜ‚1í9%jßÈ縫?×q h‰­ŠA;?2šV%¡¹u�P*-5”ô¹2V±ÿÈÜsªFŒþœ¡åÆÜ#@œé©j‘tNÆŸ9‡F+zúAõ/¿°ï�ËôlCG#°Á½·Ø@˜xäêAh@×ëkÞ“î5ºÉ¸‡ò ]ÒšcÔ[ …žWÔØ öÏd£# #Î!RÝð7Qøº?ˆ#§¢…¸ù–Ã5ýƒnöüáÞ7¹¾«R†kºØòY¤Ì¶#)e!BçMp™YÙ€½ûrャ©]bó(üoë—MµÕ¼íSdFNJüCÍ (JÆ›ðþ`î‘#þ¸v ó‘ÙŸïSÙt�¸ýù9~÷aé49ÜFŒ Œ¯/èüΞKTÅ$’f.¹PY^jÈÖÿ('¤œÀ-Ð6RnÜ0&Z{ÒŠñº±F3ES˜Ýëöî°…f-DÎ$ÀÓšföCaÚ ò·GJ£§J}@²Ã¼i“Á«ª„ÁëßÎôúb” Ͼ =ÇS[íi`o‚iø,Þo‰lš�¾OµDIÛvk–w#Æã¸ÂÜê\Œ¾Ž—Û‰þíãB8g+Æ�}Œµ�Ù/Ó`5&Ëz‰pžs/kÀ/ �„2 Pƨ‚úLjž ÆÀgi¡Û�:b¸BÀå1^ý€{t‡4%[#Â%ò¿å‰LX“è«*I]ƪR§À@"ÈGI—hòJœI›j™¢i Iw‘µÌÍ”œD,%ƒjÂÜ Âü°ÂâÜKóCü÷u|ù™úº$¿²s'þ›ƒpÛÜ<æk1ä�ª„Û—AÎnlb�»GC^ºzïllbÿ¼D~žO°:™bßÜ€K;GC,htOܲ8�Q•pasŒ³›ìŸ¡N„Kã ¾q·/-8Ìo4-–‡µ÷08º¸€�¯,ãèh„S›c\ÑHÌç¯áÛ?=‰/|ì,-Ìc8"¥„¦m1ilŽ'ØœL%Ÿ¡’u¥�½�IÓb<�bÚ2š, Š[¶”U‰þ)j„×âɉƒš1T+ÍXHþª«„ª& ´<ÔÜÜósCŒFCÌ�5¢5éÞ[i±œMc!êP¤ ¤Škn¥áp“[WÖ„^HŽ¥®Á“5mM¥¬ZÜ�ÓDÆT¢ä môšÆÖ×"”wéÐǰ7mOwß övdÊ®V>u?wd·b@ò{„ýOá¿r�r�É(Î�G zw2Ù¦szŸfÚX F±{à-©r¾Çö ¯É�z}H¢3FœÒ¥9¯G_R™_‘ãoÝ16t×¥{%¬¯­bcã*š¦ÁwÞ‰£·Ý†”îºû=€Éx aÏž½¨ëÇ^zï¼ó<"ÂéS'ñÌwŸÂ½÷½W›Ç“É·Þz/<ÿ<Ξ=‹œ[ìÜu ææ¶•¹®AÎ;î‡y ¹¬ðnGt O'xý5)¿óÀàÀÁƒ¸õÈQœ|ëº+++رs'¾öÕ¯¢Ôøì㿌TUøú×þ§OŸÂÃý8–––ðýg¾‹¦ipä¶ÛöÀ¿þ“ÿ—µñð�w?‚áhÑeÊÍÍëxç�W1??�Ûn¿�<òQ\½ºŠÅÅE,.-áùŸüwÞu7Ž=ŠiÓà;O| k7Öðùßü-0g¼ðÜOpãúu¼÷}ïÃîÝ{ðÚ«¯"çŒå•í¸rå2¤òž}{ñÝï<‰Éx‚?ðA,¯¬à…ç~‚ çÏãþÄ}ïý9üH�Ôóóó8pð67¥á2¼}ú6Ö7pèð-XXXÀ±—_Â¥‹që‘£øÄ'ÅO_x“ÉDÀg~ñsX¿q�>ú(:„W^9&`ÜX[ÅêÕóX\XÁp0êI/ý=Tö¼Éý&û„f"BÛ6¸ Í‡ï»ï>ìÝ»¯{WWWqï{wÝ}7^}å¦Ó)V¶oǧþ3xýµW½_ÂÒÒVWW±±¾ŽªªðÖ‰7qáüylß¾‡o¹§NžÄõk×°´m~å×>�×^9æòÖ{î½7®_÷æÔëëk¸vý¦Ó)ˆ“É/ŠSàÖ#Gqõêª_{èða03&Zºh2ãÈ‘[ñéÇÃo¼�ׯƒ\ºvÓ¶ÁÞí»\þ±}›~`t¤ÐåΦ.J9:º G9­ÝŠq—œ.=—¤¬_W·Šk­O5ÚÇñtÅÓOáð—eWÃ�r0B*£EvFãže?ֵʒµÈ¢®X¿#‰ÒM•£Ã˜|`òŠ:‚ô㪖“ŠÌOP=¹+:b¤©*eÿf¸ì7#“¡œgiüԧȬV׎}' #³4Üâz”ËXaÑr`ó-2œkÿÅbfMÇaÃ/û;¾|øE´Qºˆ@/º½@Ê�ç¨y´˜ZttÙ›^+žk°_¶ *3¾‘ô P1ºÈn¡ÔŒ— Ò~pu¥ýàô7£/uJTâ<¬’”v?%{i³ˆÒ¡ž¾÷ÊRsøÜ}mÁ7 †jü¦*yóóTR-ºnªÈËëˆ*¢sÐßRE¨j3žk Ü a8H+}%ŒFµ¾W�jÌ�jŒ†’�]×µÓ¥º®QWöRZU£|ù;i¿¬¹ôi(%}Å1[¹ƒ¶®T·¯+ÑÝë ƒºF=¨0Ã!0X9' È ivÌs2nË«mUÉ(0Y·J•fÔÞ¿ÀìVÅ®Ti�EñbG��4ØÕô4w dˆÄ˜ ±õE/ÂAÙ‹ÔE€-‘eÖ<åØgµo}÷"R,Åê;8„À¾0¸Õa´¼wŸÎà”hËgîÎ%\X`Å­Ô±ÆĨe÷m9€­~¢wÿ=\O=m}ÍM¾ –&Ÿ£p“üÜr]øÀp¦ZÒU¢A/°”€?ÔÃ¥2¼¨¼õÒË‚Ò&�áî×[)~¶®Pü &ŽÓÉ£¢2®Àn²Ž*4»À ½�Õj£D=á¡» ø¶¢å]XôÄk9›¬«9ùs„Á”w‘8Â…ž)€ò}äj)p„,¯ÜrChx㘩v”o-¢�Úš‚j�*tÄáÒo4³ïýyû:QöuŒh’w�MÐrî—´œ’ÆÉRS�Èqµ4¯Jù3ÉŒ@ä‚I{Ó'ÊQs<+ßYC$hn›Ö£–³Ó»¢¶ZfL$K'.ð2A£€^`ìó!RAèy† Î>0!£kŒï:D:QÃÆ{éšå",:™b«¹“}zBÉö€)[E-+¬BÇDÝ=Ö�Z) Ñý­ã2¡½ÀÊM¬®øØ9••‰©Až nn$‚?±ü>HÖ"ìÌ jÌk¤û Ö¦ÀIêIV -.Òl“¥V£ ¸‘¯Ê6AQ”ËQ�07¨°0ª°0WcX'ü/þïðÜoúÜ�ÎÍá¾õV||iv�†˜«*LÚŒ§.^ÆÁ…yT ï×o¬a�–j)4L {çG¤„†Ûì›�™qìÚ ,Ôµ— úþ¥Ul´-vk¶ÀêD $+Ú¬x¾®pÛÒ*'°~£”ðÂê5\›L±{NÔd¢ iPá„Fª®®�ñO¾„_øÀ�ؽ²ˆœÅà?™¶OŒíÙÁñÖdBÃBÇÆ“›Ó�5­RÞVБÝÁ늾®õpŒ†æ†5†ÃJ& VgÀ §�9 æFÌÍ 0ˆ+E1µælà-Îô-‘9š*Ô)Iv‚–js‹&8Ô"›6:!µQCxŸa²?BŸK�£Å¬3/”·æXîÕ~7cÕ haÞ‘('¤ø+|f«#òF®ÑÚÎ3ã5‘ŽÙõ7}Ä Æ–Ÿ£1¥ŒÌ" #ÿ+†ŽätS�U§|N p-™âh°HÒ  �fïå.κô¼?ë2Öò"ˆÓôòåSÈYšZîܱ{÷íóûüøGÏ"猕íÛ›››ÒÄw~€Ôq7§ÀóÏý‹‹K¸ýŽ;1qùòe<ûC1R�FKؾã�ðmsŽ¸Æ»ldC†×ßjM;ò)pþü¸páMìÙ³·ÜzøOÿO?õ$^yùe,//ãþ?€Ó'Oâô©“¨«·ßq'˜.œÇž={±¼¼ ÇŽ½„÷Üs/îºû\¿~ _ÿÚßbai ÿû¿ù7€¹¹m¸ýÎ�øsÀææ œ}çUL§S|âãŸÀk¯¾‚|ø!ÜÿÀðÝ'ŸÄùóç0Ôxÿâ�·ÏàÂùóZ/66Ö1O°sç.\¼p?þÑñÁ?„£·ÝŽã¯¿†7�Çúú~ý ¿…óçÎI ›ÉwÞuqò­îÔ?ùÖ PJعs'Ö×ÖñòK/âÆ�øÌg?fÆ;o¿�ñxŒ÷Ýÿ>Œ7^ 0¿°€ét‚+W® ·-RJxñ…ç±¶¶†ý`ûöíøÄ'?‰¥Å%¼þúë`f4Í—®¼ ÎK‹;¶À½YTì�£ø™»ç´mëŽ�={öâ‘�} çξ@J7MƒË—¤„Þd<ÆO_x9gÜõž{�ˆpüøØX_ÇÇ>ñ)Ürë­ž!±k÷Üqç�xó¸dL§S\¾tëÈ9#¥„3§Oc}};vîÄ®]»pùòeL§Slß±Ÿzô1‡¬l_Áõë×�¶]¿vÍ�N 666ðø/ý2ˆÇßxpmí&Mƒ½;v:+Ný€ÉOèíuFÑ÷g>XŸ&s\t‚<œæ¨³ùg…6rá<=É*è^®3è;Nµm­�®ú—L(³y¼€Î¹ˆâòŒDî^´ú8‹ãáÝ¡`Ü0Ȩ:—O‹œ(ý�Š1¸“eJäåS¥†A3ö©áÈJõX)Šÿ�´÷ ¶+¹óÃ~ÝçÜôrð€‡œ&ÀäÌ!9œÀ!¹ä’µ^oÉ¥Ú’jm—U^IvɶjYk}pùƒB•eWy­’T¶¼µÚ—œ¥™Ó’“#0äÁ ?¼œï½çtûÃ?t÷¹ öEÜwOèÓáßÿŒT�è¡�N ÝzÖdŠÁÆp~–9Šàôàá¹’Ðs‚«ÌXUN嬈ÔÔG¬ô&%¦ Îj Gb`‘(Jˆœf mHz')³2rÖpŽS‚”)PztÕ(@¿%ê¡tâPIÒ‰ƒ’¯NÓyfY†Üfa¿Ø`x·VŒ!=Övƒ“PH[D^—TÀ˜øù, Ê_1ž)Þ·.ÉXÆ2Ÿ*ï+ã°ŒDdù;8CÙ°/t:¼’Ê KQ89ïÆ´T÷VÄ%{á¼Ðâ Œªü•F#|�]ÿ§�à¼ã}¨³æ8Â$l Ÿl�0‚LX_ż¡‡�Ò3^ŠäPYI¹¤p/2¥N…Ô MsÒþ›aˆdKâù31 ‚ðKf€Ü˜ 7²ü!~�”¦Ô©Ñ‹ÕЍâe k·Ù'åå!ÒL>õ$ü�ŠÕDôbôx0&Zˆ�2ÏI¡^«ed¨YÔE©^7ôwàQuƒFàY'å»S³œd_+s‘±aÂÊ·{ÑJ¡fzžêÓ±2¿fQWE~ Í&)ô[üÝlæh6kh4I¦k5s´Z­–A³™£¯UC«•£ÕÊÑlñs|4Í&�§ÔrêG–Å´�ôz™É`Ù�‘±ÁňA‰:ÃK„—Àé¥8RÅÚœ¯S”Jö'_Úú•TÆãí¦ÖõÍ�A—Ÿ­¸ñž—g‚UÉWª4IîoP¤ ‡‹�´:Š>.|½O-×›~|ïeeBRyF8–OÃ5`¹G/™[¾ºº¿Ð;¥áB$ÄŠjG6šé¹žþަ€ÍÂm´\F#bÚHË\eq�ÜC¿cÏàÈú+kç�ÎWÞjÿ|e˜Ñ ’!¥sá+‹l¤­DÉ—tV¯ ÜF²xГ ¨Mäßp’÷’í,ŠÐõDPÖÛðÎxm¼qˆ�F 0U†ÅkŸ‚CŽØ0 {5[@È�+E²Ö{…bxãèð¥AY”Ð-ˆÓƒÃ8…§Ði2áÕ‰^\úšÀ{²œ|:TP=/ŠÆK¼Þa\%9#Oˆ²ž¨PÒg#c�Äê…Ö£~È¿„HæL ߈Q@™p�YEžBƒÌì–¥~ex3*ûÒG0U"*Ô¹P8(àû¸ë|E0“À—ä×aÄø‹)UJúPP7QÖ$3Ï*áeÞø�KŽJ›Ògµ¬Ç„dzÈéy¼a÷1¼!Aû"FÙ{bFßDö5i—·NΔH˜Køp1&Ö0ÃC�:3µ u. œgžŠèÚpX†õniQ8«ž0@ìy%L$¢H‹V=C_#‡µÿÝ¿þ¿pmnuc0™×pl`ÿÓÞ½0­®«÷f †j9úÙ�¢~ ϱÔ-0ÛncK“Œ76ÚøÙÌ ö+¹þhuS‘Qa¼QÇÖfs�.&[M ×jh—?¹9‹í}MÔ92àµÙy æ9¸fAn ™Õ¾ŒÔkØ?Ø�OcÂX¼³¾†®÷è%þòÅxꞃl¡Ó-ÑéhwKt ‡®Š(¼¡h'G†‚v·@»Sp(z/‰§õ5§YÉ÷kШ4–Óeê[“´P9y„ˆ‘ ÑÈÑlÖ95€ePÂKí §;Ý‚˜C‚«\…nï ø²@áøŸ�Vò¨’\¦±%˜EðÌ”´J.¤‚êa¼ÐrˆÒ•ÚR/v› ¸‰ã‰ðTÑ;/VND“*¢±¹QÀÄÊ{l/îz§Ã ü¯ÕþEF�M_¸¯¨—�†#z>SbHÖw }²ÉuêsÀõ‰Ñ·r¯�®%ÑhqœŽ?:"&ýN„"Þ-]Qþ…6šÍ\½z€Çôô4~ÿþýý:÷;¦vbxdkk«X^ZƶÉíhµú0}ã:¾ù�çpðÐaÔj5xïñö›o`l|CCTŒ¼¯Õ‡ç8�Žs%¶O}Œ'Q!Æ�\1Éjð5QØÄ°WYÛèü‡ÞÀÚê<Ž9‚Çÿ$<ˆ�� ¬­­âà¡C¸|ùÍ&víÞƒÛî¸ßýÖ7qâ½wñä3ŸÁÁC‡ñâó?Æå�>Âððö<ˆ+—.ayi ?¼ˆ7ߠ¿“ÛoÃèØTè€Úë+¸~ý4Œ1¸ÿþû`­Å¾ýû±¶¶†F£�²,±oÿ¼öÊ+(Šwßw¦vîÂ�ð}\¾t Çî¾;z¯üŒ"úúúqøö;0==M‘X_[ƒ÷�fƒƒƒ8sêΞ9ƒ»ï½GŽÅÉ÷ßÇÊò2ZÍžýܯáúµ«XZZ‚÷ããX^^ÆâÂêõ:®_»†³gNaphû÷ÀõkWqõÊdÖâK¿ù[˜ŸŸÓ"¼G�Ý…,ËpæÔ)lÙ2�_ûÂñÁ©°¼¼ XY]ÀÚú††&Ы`< LØwéõ ÄœC†JåóéO?�™›ÓÄäöí¸|éæfgÐêëÃg>û9\ºôº�¼÷xø‘ǰ²²‚¹9Šìèv»˜ŸŸÃÚê*šÍ&æççpáü9cp÷½÷aqq óópÎá±Ç?�¾¾>�èïïG__æçPÁg1 X¦w‹ ðÞcdtƒe`ŒÁ¶ÉɤØñÂÂÞ?›ðgÊ}Æé“"À*OÁxéE¶ ѱÊ1± A¦—=Ä-Áz¦†é–¯ŒÎGx@xÞèG«a\dX ü–à‰X‰Œ<%äè%Ñã&¤ 2l°I�AåyžúPê9ÐëæG¼Q¤Nt�/ª¦Ea]tméX¥=ÕQ)¼›UÀýÎsÃÆŽ¨YÔë–<ïÙ0Ш‘ÜµTÅ�EF�Xà߯8Xë�eì¨Ç j52DÔëš� Í&)÷[bØä¥«eø¨Ñ¡Ïæl`ÈÐhdh6, 6 Ô€œ# ¬5Z$;Ö¯Î2Ë?hBƒ.*8¶Š.DpUÆ…Úc:�ýÉ—¶}E¡®“Xš#Hã#‘xDxP"݃|PüÇVíØ( UÚ+;× þ�((a©M;žþ©ˆ›•Ãê ª·ùÞqG ÆÞ7ô ‡I[ÒÑ*~Œ;v á¤Ò‰Ÿ{GÚéø¬©Ü¹I[Þ€½ÇSCOûMFØS•00�aªM�2îƒLMOôBø®N½sÿBžò¸�ð°×Á)x*ÂŒKˆªÊ0#¬aÏ¥a`lÓþ£€QogaNôˆu3x:©ÂA:½/—Ô¤¢ JåÊ€TßÌ}s \yà �²p( �n—rr‡nº€WÄãE¼a´ÙdB!ôr²ÄâG”;õôŽ®G§…QO•N‚Ù�I(­Dd¥KÌ@…ç©ßò­Ê4ï¡É³Bõ‰`ö~ÜŽX\Tà”seú¸ Uoð9ñ`A0|Ø(`ÃúÄ �Ρœg¯ñ~ˆD°ðÂ<ï4Ù…l|óÌ,eQJµ¥€ƒqø!)�2!rÖRx¢© ¤阪 ÅÂúE�3¿r§À–còÒ° �³×FÆãˬÜ:‚}báJ¸² ï ä™ac@†&{™7ëô»ÁihÔ(`"ã€Ô$€�ó5À䬤å±ÓH�×+¨×‚Q UÏ�Y�òoÿKkë€>kñÙ±1üƒ�;Q7Í,S£À•µu4m¦Šù×fç±á¼žët°îÆêäýßÊ2lgïþõ²„5;Ù(ðÑÚ:fÚ]lm6` 0½ÑÁû‹ËØ;Ð'  ƒñF]!`ï@jd€˜ïгýyŽé�6~2=‡½}°Æ ô×VÖñÄè^]]EÇ“0øW/ǧï:€�¾&:¥GG#�@ߎҡuK‡ná°Ñ)Ðé„MTH�PR mÔrÔò,D„äõœ¼JýAáóìÉcYxf¸¯¢Z�Ú´Ì•€+Éà�¢fòÌ“÷ghÔjh6hµêhÖkhÔk”ž('· µ™x>‰"¹ %›" IDATBÏ+T“Q§ë¥³)²‰¾…¨r10I*Áu=Â÷o†Óâ7þ\>éÏ V#ùî¹âaMü\Ч‚øãA$ãR>õ"úhAŒãõéåêŠo�_T#è;m¿ÚVôL“£LL$|ÄÆ”Ä8a3,/ßÄÆÆ2º�xðAìܵ ^8�µµ5 QañkW¯áü¹³Øµ{ ¯¿#££Åú:á¥Ûï¸CCÃ8sêœ?wGŽÃß<÷u¬¯¯£ÓYÃÔΣÈó†ÒóÞBÄñ\‰ñ*ÔºÕ|Èǹ§?xΕèv»ø�ßø üà{ßÁÐÐ>ùÄ“˜››Å«/ÿ Ó7nà±Ç?ÀàÝ·ß@yä×××Q«Õ` ¥ˆy÷í·02:Š»î¹ÿÛ¿ú_0778pøQ4›ýa¯À`cc7®ŸF__vì˜Âïý§€ çÎáõW_A³Ù§>ý$®]½ŠsgÏ`yy ÷?ð õΞ9 Ø15…+—/crrYž£Ùlâ…ÿýýxüSO Ï2¼÷î;˜™¹‰cwÝ�íÛ§pæô)ÀÐð0Œ1pe‰•åe옚›o¼†¢(pðà!LíÚ…7^{‹ 8z×ÝxèáGðÞ»ïPª¢¡!Ü÷ÀCøèâE´Û*ÌÎÌ Ýn£ÙláÂùs¸võ*¦¦vâà¡Ã8ùþ <õÔSÕbÌíÎ:––g1<8Ž,«¡*‡tïǰïˆò‡][”…xàÀÎ]»qì®{pþÜY8ç�gŠn�¥Å”e‰f³‰N¾�¹ÙYìÞ³»÷îÅù³g°²¼Œ‰-[ðù/~ 'OœPïùÝ{öbnf�E®ÍÍÎ`v†¢�&–—–°0?c î{àA\½rYÇóÀCc}mMa߃n·£©Œ¨Q Ë2åW:�úûûq÷=÷âõ×^Ì//bx`ý­>¥_–ùB(~’éLy.óh N‡q £€ÀošÈ“ÚÚh¹‚µ*3;ÏT½h ÈØ')q�|tUã ±èμ�S%© òiU� ÂÿĨ 2 $‰w"|—🚾D·û; ï¢9Õ8 Þ¬QêÉZ¦Š0ñQ"ÅYüÎà¼R¥Sªac­õ"yTòË;Çõ•ººE¡I4±&ËHÍô�)ù¢kôÛ'^ÍÆˆÂÙé‘g~HÓAxÜS>|_p�—gåp·à>l#€(~]ä!–Bœº ê­ÏsdáÕ’óþQ.Çf°YžÚâõÓžì‰,|»eïäœÓÁd¬wžáF÷�DÞTÓi¹’=á“ÈêMtT)b <ž‰Ù»@ÇiO…¹Š a+Ç{Ž‹Q'tT¾cN)ÙÉþ‹ é¹^zÖ² Æ�Ð礞EÚx:E:n–ãØ( ‡�9׈q!ZÑZ5Ô©’?ô’VWç%¢aÕ¾Y¢‚k‘#rgfv²°½aɘÖœ£«aøðeb‚Tù·éÜì’L^:Ÿ¬0 úO(ÿ/)c"mCŒ‚ãò<Ek5Ãéu je¿µ)‘ñ ÑWЈˆ,²œŽ\S9SÒaKd™§BÍuƒFâV'%}£aÉ£¿eÑhehµ,š¢ðoÍ&ÐjͦÙäšMKn‡Œ äXc@* 6:®¡ŒD sbT1Hö¬Ð÷XþÊŒ ðñ—¾ò¥­_QqCzP*2�2 +J#EŒ G=8‰ÀÀƒ£x×V#ôo±²U1{5,ÉØô#\‚-®�ÃäõÿVS6KO£�í}«£WV·jýs;�Ÿƒ©üß³xÉo“\“n™È0àuøÆ+ºá'‚yܾ‡O…x�b1ÚȳžŸõi�”RUƳ¬òÖs‚ŒôdÜBx.laLdÁŒpY<�={�¡�Œ>îC¼Ç˜È„†ƒâ1æjSÜ,°«à™�î3iÓpøeÒ_5=BZL*Kl�PàÕ,8Ct¥ðdè:]‡nס[”šÿ^:&¡¸±ÅºgKÄDø#Ô– Ä>^é<|4}©§Œ ?&‘jÈÒ(õ´!•ŒU!(UüEŠ,—÷”Ë2”÷Å^³)ÖàíÄ0B Ô0< œ Ï鞊à\…2Χ—zm Œ¹WW 1MƘ�?ž Džü ł×&†�€MÂ{£Ñ…y{Dzq 6 C@äõbbÌ\á™M4wѺ!úŽ…¹D€4ì©e­æŽ…±är´60kb ³,hðæ�/ xW�A ™GFò4 ÇB²AÀÂ!³y$dcáM0y`Ð=y%QîROa�œ>¨Y·è«ç0Æã¿ÿwÿKkë´ãYŽÿjj _ž˜@»,ñ“›sAQàÒÚFê5Ô–¶6ÊsXkÐ)Fê5ŒÕëèz�wç1Ö¨£�½ùt}Cõš¦ZéèËsôsÍ‚�ZŽ=ü®KkëÈs5 ¼1»€Õ¢À8§ºÙîàâÚvq1ãV–¡¿–kÍ‚ÌìèÃîVw4šxku«\xék?=�'ï½ ­FÝ¡ë<º…'CA×aƒ£Ú��¢D·,™# ÉK™³Q Áš(·¨qÄ€D€ä{j bæmÌЭ;A°ÆÞWÞÁÈa¼2o$ ä¨×jh4êèk6Ð×j¢Y¯£Q¯)ãì­Ai$·hbBj1KÞ‹Ñ3B$L¢�/áÙÓÇTùŸ@ˆB/m„O"á Â…6ú;ÜÓc0¨îc*†»¨;ѳ¡PÚk5… ㅈΤŠãÊýÓgy=!ô,[õ›æ.Á™žBõP~*f2ýæW”Ü!R#´MÞ—ªŽÒ·ŠW­^K&”…aîí1Mt%æçHéÙh6ñØcG½^G__rŽÁ®Ý{ÐívñÎÛoallccã0Æà_ÿk”e‰ÉÉí€ëׯa}} »vïÁ… pö yY nÁÀàÖ™"ãMúêsUø­�R`~þ2®^ypôØ1Üù±#¸~í*ú°}Çk±¶ºŠ}`ia‘Óý<€�9ŠÓ|€Ÿýô%ŒŽŽâáG?ŽÏŸÃéS°qdÿúÏþw@³5ˆšFˆÖÈ{`£M†�þþ~ÜvÛmxìñDZ¸¸ˆë×®bÇÔ˜ó„:Œ“'Žã�·ßÂC�<Š»î¹'Þ{O=ÙŸxêi\8 óóXYYơ÷¡ÓîàÚÕ+êHpöÌi´Z}ؽg/nޜƹ3gPt»øÍßù[¸qý®_»†öÆŽ=†V«¥©s¼sXYYFéJJyã=Þ{çmM/”ç5œ?wív<øöìÛ‡‹. ú±±q\½z‹ زe >ýÔSxõ•W¸ÎRs‹7048ŽZŠÔ'û?Ù-½|‘À{l¸÷Þ{Ñh4°°0�“ïŸ@½^Ç‘cwa}}—/]BQxòéÏ ¯¯×9ÝÐö;0<<Œ+—/Ê¢Àå�>ÂÆÆúúúá\ºx‘S2ÆÈè(¦oÜ@Y–غmîà!\8NûU¯×4‚®\¾ŒõõuÔëu4šM¬¯­©Qàà¡Ã±cããXçH€¢úû°gï>?þ`vqS[¶¡ž×�e™FÄs“¤©“ߢ”X¶ ^®%×U"þ”çWùÅ`€V%5 ‰~S^ QZ ï5ß¶ÊâGDñj*ooâ…�ÖšÀ€ú\Q 23§Ÿ5Œë”N žcca ½ZõæU|w‚�úp©Q@ßgbÞ0ÈGYƹÃsr,Ès6 Ô êyP\«A@ðX$wS=7þ'd)Ï.òaðJ·”ªÔyt»äQ”dð [K†•‡È8@’U yô‰£’¡Q«J~„­ þ&c¾:cg&z‡ó%¬x<È0Ðaã@·(Ù0 ‹X•xYs‰ZRþŠæ6Jb%Îìüa@0b³6Ë#^&-ˆ¬¥©ˆ”g 2ã4µ$E Ä#F=‚5E‘µA¾ô¥£ñz)�|"½œn £µ£JD„?©´¦²‘ z'`@üjïKΩ€¼¹Š'–ïƒC¯�¯<lø þÅ>Yãx[ôà€þRy.ãH\IËRáß*{ß°e'tŒÚãÔäYI{L†¯ W@¤ã0†"Îkµœ~‚a ãèïœSÌfbtó€)  ,@.„±žHäY@"Œâ‘ÀEðS…måñ¬½ë-†�”¥ ÏzÖûè¼±²,C'FËûÅ Ï} !‡£@d@Ès «y-Vº“AÀÚÖ”d4¨uVà×jT Ñ0h4-šÍ Í&úÔ0`ÈHÐ ¿ÅXÐl­†E«‘£ÕÈÐlZ4êñŒµØ(�…þ‘6è}c O =¯òä »êña¾�ì+_Úò•xÏ&Ø[�m ¡,äTå�ø^S¹fžDY¬ÅJS (_bŲ÷šïþV¯ ¿«½‡[( Ð-Œ›*–£ûÒ?Å“´çæÞç63.ÈŠöl°žÎÿ‚ë�ùí�)S¹Û$ÏQ §‰óЍÛé‚‚êfþ*oõô>I%¤7ËTÈyõŽ�ÞjÌ>´�Ž¿Ò­ a¬ü 8.&†1Œ÷4Ti<¢yò;Ya†7õ*Èât ÒV÷€š´æCÒépˆ8µ3°-—4Yr°—‚Nœ�¿�Pl‚»À5|éá»e·D·S¢èèt t;Š‚™k�xv[e‚!E2i»gD{>0 UâÏ`/¬øÀ¥Å“¨Šk©ÐŒÍr6 0Ó+Š�MöS¢DŠ¯ÇøkÓ¥ áÇ&ÆEÂ`DžVò Z"8E#‰ž�Ï)QUï-šL1T¸H03†óæä‘� 㑦T ð„nEc‚΃c¼F×ÕkMˆ7è8Â<¤9²Ã&ù"O!É9ßjÖÐjÔHÉ\·hÔ©®@�½Ï)!ä!Í3¥è”µÞÖ9õ•¹ìs {lÔ©Ž@«YC­fŽ?ý÷_ÅÜ2yŽe9þpËV|zl­šl5�[K0gÈP³Óm¬t ÕkȬÁôz¯Í.`ÿ`¿ÎÔ\§‹í­¦ÂæÎþ†k5¬%øZža¹(ðÂ�YõöwlTØÖl žÀ52‹-­rcÐõ£õvõµÐõ§—V0R«iÍ‚ï_¿‰ÜýíK‡»úúñòê Úž„Æo¿zŸ¹ÿNltK¬mt±Ñ-Ñî–œ (KPñtG° ðŸ«pÈ5#rsk¨0 }¹r+Œ+ &b̬eE½a8 …#÷&╌¦’2€êTPñ-2N4›T°Xkp**Ãq²õ<×tCdÜà0R5PÒšÉþUþ ç|ðVJH"¢)FI/cªéßRÅ{ aÉÆŒîÿe>?ï¾X±¿ÙÕt· ¾’ñˆ@¥É wÅœGÂGÃ� ,ÆÛÑ‘*UÒ~ÄFèðw¦«QÅwÅh`zâ:¦xøÊ×Å}x;îWjô‰g5í»�A³Ñ�+¬P_Z\Ä3ŸyƒƒƒÈk5,,Ìãßûßv;Êýþá…óسwŸÒÀÝ»÷`|b œ+1?7‡½ûöc×î=¸qý:2kñ Ï²¬†­Û&ýNÇÍ?;´H8=ý½ Sñ—>zKK7Ðl6ñk_ø"öíß�;î<‚Ý{öào¾þ×8{úžzæYlß¾ßûη0?7‡©©�غu®\¹Œ¹Ùìܽ[‹ßeYŽ;�Á÷¾óm¼ýElßqFF$�Pèo› Þ{ì?p ós¨å5<òØÇQoÔñãþW._Â'>õ†GFðÆk¯Â9‡‘ÑQŒOlÁÊò2fgf´0n«¯ÃÃØšÚ‰Ÿ¾ô._¾„Çÿî¾ç>¼üÓŸ Ýnc`p�ò \¹| ËËËÈk5”%)ü——–066ŽË—>©>À�ƒ‡°{÷\¸p³33Tt÷׿ŒË—.auu¥ j·74•NY–˜¾qC üÎÍÎâÒ¥�?ú6660?;‹ßùÝßÃ[o¾‰ÕÕU8Wbqé&F†&�çµÍ×k“³UØ,Ê®:Œ¿ýwþ'Žç´$%î¹÷>ÌÎÎbyi‰àvisss°Æ`hh—.Q‰�ÁA<ôèc˜¹yóóspÎáÉgžE§ÝÖAý(ËKÜÖêÊŠFÇÆÐÞØÐâÍBžçXã9ÅØØ8æuËËK•@�1ÏØétpðàALOOãæô4JWÂ9�­£ãÑ~ mZÈC^áó�IÒ�q%ðGA>Œ½ÝEQ&âQÍgïJ­›£Ž3’F&vâ1¬ÐŽ Vú@Ò7ŠÁ5¤E:fË�‹ å®D60Éó&Â{"Ùµ>ð}é|M Z7@=ӣⶆ~dž-0œçÌëù0Ç–©+Ø%ŠCÆnÙM6IÁ¥xŽû¦îñtyÞ—ä4Q”¬Œ²Á˜ÄÑÔÎ6؅¾ÞGYæ�pˆXqä2÷¹�xå“ã…Õ´H ?jd pŽx4JT•’ Šæì8¢×d½U!Íó`¬*¶©î͹®5x®l˜ã,3Z¬TÓô&Sá5Æ™U§ªªÙ¶²ÓèÞXÙ_Ø"%ð1¢ñ«ŽUåDCçC[IDÀ/Á2VÙÅÔ(�ªÍ2.^«iXB͇ÍDŒÀˆƒ†7ë€Qý�̳S<¡Em³ÔÀTËÀuë 9EF-‹’1"r:¯ Ãò(§ìѺ—÷±’KEÏW4z•O²óBÛÉo‚ßøš°›2oz ¨¥‚¿«�¾ãÝ�€§eèœdžq®ç(£žü�z†z#c¥=®[-LþbÈ Q ¶>Âï©¿w&Â8ã9�“è$³+*òêôVÞ/☡U HtÜôw0 È•ê hïRy�rudÚAS…-( 8§!òH�Ž2bºO„¢@Žrˆ'Cø9lavõI�cÔ?ÚG•ÙØÌÌÙ3üÍ0’O¿«·(1ûyج:á›÷à—7 lrÞ#*½Ù»©�&Ê÷gÂq{U¸3Ò·ŠîZïIré—áÏJ�“óå�‰o‹wZ2ŒÊæÔs YÁ@icá¡ê^1Q×LDn™Á5j0iž_¥À<üíÕ ÷?ÚéJè–1 â£a¸QÄ@D?§"–`1Ýc<Õ={„ˆÇ@ ø®ƒë8m2tÛl(K 36Œ�³HémÈ+Öxñ¡‡LØáCøŒØ8e {¬þaÞ«$¨ú1ñÿ¼.–ÃA³,‡±9`-¼á2É&"=1!4Í&Ý*�óÉŸBXƒBÜ&LI¬ q.òÎò=ÆJ'Q‚Ÿ!úÊ]–â^!ß?=' îŒóàC”!ËÉ`<üi|$Ôñ˜ôˆ�©¢ :FòŒI�á>i'Î��È(Àyõ2‰Ï²žðθNÎfDXÎfTÖNæ9ÜŸ¦“tAâ5^ãüÿ™áÆCb ci¡±ÜR¾ÿzÍ¢Õ`ÀVÊÐÈsNEÃy"mðŽ�:5.ˆ”Ù, 19yFŒ‹¤#"£@Ά�:þå_g¯N |”ÿh×N<1:ç=>\]ÇH-×È€—gæP·VSm”$�Hnÿ�ZŽ]ý”"h©[ ‘e˜l6`ŒÁñ…%,u lm6P��¥"üÎ Õj¬åpždíèG=#Äb§‹m­&rcpm½�Wgæq@ Þãâê:Æšu­C°­ÕÀH½ ãÆuìh6p´ÕÂKËËh{ª9ðÖÙËxè¶½XoK­�Ò”Π()š@…¢ˆù–zu1°a ³4—™ñ”úÉBC€Å(�‰R^ö¿à|QŠˆã|ÄT²Q c£@.i„¸øU£NÆ�:第gh6ÈÐé,‡ó$,ÝÚŒò=…}.{]FJëbš¿`P/vÖâT � ˆ÷j•#®æ­þe>¿Ša@f¹‡€ §*4€_VÁaá‚/޼5<ùIõÜ‹[‚Ò_<R/xi§7•Ž´­´R¤IÞÞŸò=§Fms;Oúo³®¡Ý¦<ìÄî={PJ•}ûö#Ës¬­­¡^¯«Qà�·ÞÄââ¶ï˜B­VÉãïá­7ÞÀ�;(º]4›-üÍs_‡÷ÝÎví¹/™£êê#é£0»›d_�wâéSÏ£(Ú¸ãŽ;0µc–——q×=÷¢,Kœ:ù>ò<ÇÁC‡0?7�Á¡! �Œ`ll?ûÉK˜œœÄ>ŒZ½Žï}û[¸rù2ž~ö³Ä¿øçÿL•Èû>Šz½O•WòÃ@Y–¸ûî»á�Ãúƺ¾ÿÜÙ3èïïÇÄ–-øèâEì˜Ú‰­Û&Ñé´ñ“žG–exê3ŸÅüÜ,N}p37§ñé§žA½QÇ9ޏ˜˜Ø‚µµ5ôõõamu£cãxù§/¡Ùja÷î=˜Ø²Çß}óssxä±Çqèða¼÷î;€‘‘Qì?p?¼ÀiwZ˜¾qëk«ÈóZ­>|pò}Ìܼ‰½ûöãè]wãýDZ¶¶†��A|þ ¿ŽóçÏ¡ÓéÀƒSSX^ZÄâÂðÛ¿ó»8qâ8Ø80ƒÑá­È²œ×)]¿MU½Ã_nΓ÷ÿý÷ß�¥¥E´Ûh¶Zȳ'ß?Žå¥%Üù±#ÃåK¡½±�}ûà‘GÃÉ÷O º099‰›7§ÑÞØ\»z³33hµú04<Œë×®aii‰Œ�<ª…Šà¾ûÀÍéi�(ºVWWP–$ÿ¬¯­©Q`|bëkkª ܾcGRc c ™‹¥¥%<ý™gñýï}Þ{,­®`jbêyU˜°ŒM‘A¡œð‘Ÿc\æ[Ea/)CS¥¢*ÄxE¼¤ÄŒø~�86N…bTÃbX­ží"¦ &I…¿Ø2‘¾8+ƒ*ö“ÿ W DêLD¶*môÛ€sì[*Ò«i-"E’*î Ô  &Î'yŽZ-‡Ô”ÒœÒFxX‡²,Ã@HÁÑéªWán�Gm@—ë/IÝ8ïIÞ*Ø J‡Pû¬pp¥ïQ†­Çt‘eKÙŠªÌgZ‘Y1šf Ï2>9 �@QÝ‚ Œ¢$Jaƒ ‰ób�.�ôD`^‹<¯ƒc�z³Â•"=s�ú4ï 57¨H3Eízra�g©5%…SÉqÇ�'8ós"©”²L•ÏŽ�Z¨vË׎dr«<�á6R "åéxÿ Ý‹¼8åùT$‹ts·Rj›ï›åñHø©*>Žßñ|A×òe0&õŽø™[é py Ý] §\¨U�yŽZ^C–ç,#sz^êyÎÁšª"ƒÆãSÞJ¿L¤÷$¼l XÞÈ8]©D‹¼Z8¾°ŒÉf‡9¿0=ƒ­¦`¢Y×ßc�:¶6pÞãÌò*Fê5 ±wÿKÓsð€zû_[oÃaþÝÊ3ìàH‚µ¢DÝZììo¡n-N..£ôÔ~f Î-¯âÔÒŠ¦BÍsìªÕñ<{nÎ-¯am½ƒÝ[ÆÐåH)Ê+H0ã”=µ< �̲òŸ#A¼ƒq!å\ aP ¨&€5YÀ91qÑ=îTqâ8ŠR”é€Ý$= Qœ’÷ %+��7¡þA7$WnÊ@ÇC×7t IDATl’ˆRD�•ž ìGáâ9ëõP÷:Žð|0ºš„7 Š Ý—ò´°(Ñ…Ã(/ãg£sx�ôf“OE1&æfâ{ø}=©’è]¡»�? d%`ñ” üM˜ÛÀ'ÄÊÿLß+Ñmº 3Õ5HÓpT]š ô CB4í<¿LÏ«<~t½j„ ʲ�…ù«X[[ÃøÄî½ï>¼â8¶n݆œ�‹ßýÖ7Ñh402JK’“~lœðÒÖ­ÛpàÀAkqꃓÃää$^}åeòŠ.»Ø²åÍÁh½Lâo!Š~ù-$x»5×½º2‹?|ÖZl›œÄÓÏ|‡o» çÎ�ŇçÏáñO>�;�Å‹ÏÿÇß}»÷ìÅ‘£ÇðÁÉ÷qéâ‡ð8|ûí(Š.Ο;‹±ñq4›MLߘƿû·ÿÐl a÷Þû7}¿�<„G{ G�Ý…~üC|ðþ <ýìçp×Ý÷àûßù6®_»†ÁÁ!Ü{ßý8wú4––(EÍö©)8ç0só&úúûqszgOŸÆíwމݻ÷àäÉ÷ñá…óp¥Ã¿ü›¸~í*ffnbue=ò(º�®\¾ c ‡†påòG¨7ša˜çxóõ×`ŒÅÃ�>†¢,ðá…óØØØÐ(†Ë Ð×ß�z½Žé×á½GQ8uò}”E�]»÷ Ë2œ=}ËË˸ÿ�qàÐ!¼öÊËøÒ—¾Œ·ßz›SXZžÃèð¶~/ýôò P]5 Üsï=X[]EY–øÜç¿€¢(0s“¢&¶l�Í2ÌÜ$z{cçÎ�l›œD·èâÜÙ3holàÁ‡á(ŠKðÞcç®Ýص{�¦È“ue’6⣋Q†GFÐ×jaqqeYbhh÷=ð .}ô‘>;5µ3I!´ÂÅ™å#ùþ¸ÙXÇØøNŸ:ż�Ãäè]Te|P¤&RçŽ 0YÀ›ò¢Ü$UŠ(@D ØÓÃ#Ô Ÿò[)ébä¥ÄÓžÑXìiŸ¼Ó†y.Ã2–Ap–‰yÏÍäØçÙ̘ �hmB‘Ù#£´ŠØQ'ÏB½¯�²0–�ld@ˆ"3–Ÿh|•'#ïˆ#|I¡Lô/6º�YE+Ðj,qZD–PãA¡uQ›¿pÎ|zŸ—v¢þlÆàÆý­ž»õË6yø>©î߸] •>4ŸA—Êl61 øhŽa�,€¼OSÕõÜ$sˆ-Yëêøñ�“9н*||Wõ]³é{‚bÅ@óø2ÒµÓc*ï’ûcZ(ç7†‰Çk )˜<ç–ôާÙë<òásð %€‡3€5¼<¦€P ©9-úd ®3&Lî‘ÕÀžÉͺE§fÑ®�úÎÌ” t ÞgÇÞð†ŒÞ{ºîÁƒ‘©¡õI•R²j^{Ù»®Fï0ádøÃ˜ÊÜÆžãa{·¡v{rÑëÚ‹ò�æØšç2ÙøaÝ{™›p™ÂR%<52±`ô}F™hË�T†_ú¡{�Ñْ‘¼Sjµà­£Ì˜—¾P>Bïi]Âì†wxoƒpVÙ“D| EbDãnŽQàæÆFãñ“àû[z}"]fµ't`ÓšÑǘˆÍµ!ßhžg”2ÆRžT�6浜ºŒÈ”1°Æsd¥ƒ©qª Ü†�DÊéÔ¸c#|žçÜ Sîa��3DüëY†ÒÀgÉœH±ª‹7fð—/¼ªç?><„/lß(=åç?Èù—V×ÑÊ,&Ø»ÿf»�‹+kxp‚”wÍ,ÃH-Ì€§&·Â`¾ÓE»t˜lѳW×7pjqOLNð»€Ùv'©apltµœ¼ýËRû±Q–xqw� £Ÿ¯?cw� cFnfY"üìÇîþœ§¢ÉSý-|rt¿×ÞÀÿÍŠŸ¼} &·`rl Þ†<®ªäC”!#@n,‰ÈÞÃ0çæJI³ #»ÎÀ1Cnl)K¡(ççðu>(0=É5¼¯CŠCö0Ì<2K‚@Ài>3è÷9J“£SËЮehwJ´Û%Ú‡�6+”ÎQ8½ dH !¡a´÷òXt¯Òo1|èö(mB—…t÷ð7^¼;Ãéx'ÞÒ(³9›ã¡'«Ø!¡·`nÍæ2îÒG¥‰€M)hõ;éwhQ‰LlĈ£ (¬Þ3+RuШÎHï?½O÷«D~Éã~èÿ€—룾ñó†–×+ÞOgqlb.œ§b¨/¼ð<þÞýç¨×Ó<ñŸýµ/Àƒ••et;]ìÙ»pùÒ%¼ùÆkøü~ÍV xë�×Ñjµ000€‡~'ŽÌÎ~ˆ¡áIz«¯W?ž”Ø:™C~hfæ`Ïž=xèÁ‡pï}÷£( üè߇÷‡o»ƒƒhµú�eúûðÑÅ199‰Zžcj×.|㹯¡( |ñË¿‰f³‰o<÷5Üœ ŠÞñ‰}Tˆ3ÂU:Øjµ066Š;?veYbqaEQ Ûé`muã[0}ã:ñƒï~C##8v÷=Ä÷¾ý-xïñÌg?‡¾V¾öÕ¿Òe?pè0Ns±á¼–ãÄñ÷Ðjµ04<Œ,ËðÝo}Î9=v¶nÛ†~Ÿ¼Ð§vîÄSÏ| ßøú×�Â=Ësõž7ÆàÕ—_F§ÓÆÀÀ ††‡põÊe\½r�F�òSxõ•—5¿þíwÞ‰+—/k‘Þׯ#¯Õ`ŒÁ'OâŸ|å+øþñ?ÆÜÜ,6Ú«¸tõ4öwaòn±µ£“® ŠÖŸ¼øVVW0:6†Z­¦‘ccãxðáGðýï~EQÀƒO>ñ$~úÒ‹ª ¿~í¬µ…1 XZZÄÈè(¼§—ÅÅEô `jjÖÖV5z```�<�9rdee¯¿úJÒe)$=88„��ut»]@½Ñ@__ŸF�ÄŸ••<ýôÓø¾ñ7pÎáêÌMÙw0x.’ÀFb ª”âõ‹ñ¶ažÎÂk®r݈ǃ*[ÀxÜø¼Hin…®ˆS•"ûûÄKS›€(`„ï ýQ"g"N €q¡¡\Û™ä" }ÈDíÏŽH„û€R=â@â˜3°†£Ö„–%ÅØÀvÄ œš3?Λ*Š\n“9lUð—CBàÄ�GÆ Ïù%Ö”‚ÐÉ�eBWrJ 9(8-ŒJŽ Þf¤ìw€Ô&¢P¤¬*}œß]ÒÂU̓ܳ$„§×h`¢_h©Å(á™·bŽ +ÎZxgÃ{EašÇä5ˆßàèàXɪGP¦±Ê˜Œ–RKf¹JƒÒAù²(¶P�X’ª–ŽH�8 g•ÈPÉûáA¼X´.”i£äbÍ,G).C¤¹Q:-V JA««!ð&rúª ×¡¹5>l‰°s婈Vª>ÂF4TxÈ”?éÁÇ¿øD€'¥Óá¼¢„ÓÓ®þƒ’Õ1�X>ÜÆ¿cýveR*ý¿åÕʈ¢{Lô÷¦OF7ˆÌ…K^ú§ÿ÷Fëõ …¯‘DéŠGc‘ ïL0Tº§ð”̰`~³ ¬EÔ£‚ßLt‡ aøè‚¯mb‰Û6Á€ÁÉBpä¼üÔ›ša#&Ôª,EX‹Ê˜6ƒÝ0.RÀ0e2Ô&�Ï ]ReŒ‰ä½ÚèºQbGàŒ°Dc²šA½‘Á7=ºÍEÇ¡]8tK_ø( 1ÉÞ¸ÌÀçžÓvXG‚† F-~#û$Ù#–ûÈÄÆÇ7„¹ L¥�îxª [g9Ýïg) ¥ÕŽ#eg²Ç#Ü”‚U€*Ÿà/iƒ#Š?«š(ÃÊÒ‘ 8’"ò“²ÖPʵî³÷¯æä4Bö$¼Öi¿½Å»1£kmk‚—J(Rl"´ìµÿ€3´^Τ2ÞhÒƒ8T5Ì&)@e½tÝ~EèÓë‚ãeuSA‰Y¬Ü[ †Ð"Ú碜Õ²^ÑÂVYù-^ryF)} $,Ú«W›D€ði8dÖkNQÉ+*E‰C8¢ï¢CØêCðøÎ PÏhïøŒ•»¼†d¬pøÓÿó92Røüà0þþÔ”Žï¥éYÜ7>¢‚‡j9â϶fÛš x××7°­Ùк?»9‡ƒCØÂ‚g6ÚÈfgº]œî´qÞ”øÙ¥KXuç0�exõúö68ØjᎾ>X§–V0ßîàá-äÝè<дÁ[Çxbruk±Ô-à¼Ç>60\YßÀù¥U<¾mÍ,Æs8µ´Œ¡ZŽáz ¸m>X_Ç›++ðþü…×ñ~ó³€É¹Fƒà¯-Ž¡æL"Ù,l .µ0â5ç<|É |¼²=<Ìsα€cÙs�öª†-›€'a$Ï­!Ó¸@ )"y†dèdTxº‘—hç%6²™-ô9ÉM›qäDáÉH:È})ÔLá”DÜŒ·€eœZa\í=þhÔâíÈ#NnÕY _&áÄÂ]FÞ#xCž‹éhÒdÏ�Àm¤í+»¿Dæ(aFøÛ‹r*îù&�¥]ÌÝHÅ‘ñ‘â­à€`.�´Ÿ¬WJ?ãï”ùœõ߃pŽRo…§o5‡000Ž••YÌܼ‰óçÏi]�ÇßÃøø8&·ï|pò$ €ûÆLl™À¾ý`­¥¼ù##ø­ßù[¨7xï�·qìè1}ÕÜÌEìÛÿHÔÝ„yàÓ¡ï1}¢Ûcf.ÀçÌÍ{÷îÅØø8VWW±¾¶†G?þ86Ö7°±±�o<÷5Üù±#xä±�ãÜÙ3xýÕW0<<‚Ïñ×±´´ˆ¥ÅE2º{�õµ5<ðàÃøGÿð�µ_ãû’9bö÷ëë¸zõ ¦oÜÀ#eQàì™ÓøðÂy¾ýüöÿ ^}ùg¸qã:nܸŽßøíßÅ+ê­µho´qãÚ5ìܹ ë뀱øÞw¾�²t¨Õ˜™�ÃåK—Ñ- ¬¬¬ Õj¡Õl¢V¯ãâÅ‹è%š­Ö×Ö`m†çøLlÙ‚�ÁX›á¥ç ï=>vä(††G𳟼عk+{üxî¯ÿ#Ö××Q–%fffBê“,ÿ÷]t»]LíÜ…ááa¼â8ÏÍžyösøþw¿�?ýÿ)þø¿þûèt:˜_¼�Á�QŒ�lCü ð[q ¡‹ÉFi6›xä±Ç±0?§†€ýâÀÁƒx èt;˜¹9�<¯¡( Xkñµÿø—h·Ûؾcò<Çäöøoþácnnî–N ÕÏÁC‡pôèQ䵊nÆìÝ·8­<ñäSxáÇ?ÒôBI‘J�v�vû–ï˜�™Á}÷ß�×^}�¢‹› ³Ø>6�tß ¸1ŸÁEDÉ$â�ÄhË{Kóüƒ \šXqâ#…¯Dî°ÊMP& Ó=�Ò;*¤áQQø*Z5 ïz~‡ôl˜DääG㱜•æ-6„�àe ñjÞsd@*ø�–å<�%ãƒ�@á�Ã)BT¬DîÄg4¨ ãºèw) � Ö•#‰÷,Ž* x>�3YÓ‡Ž@8|J¥"F TEµ�xø¥C· ‘eéyí )± ʬ {ÁHĵ.¾nE+i„Øû]”ÜÞ“sEÊ‘T0¸ðF‚æ)‚ÀÀh‘ÎH�Uº*iœBš=ø”â“s¨¨ÔƒâhO�QIR¹d™A Àºà5Ã_f=2ã‘Ái:\iCR€æ,Ã:…?š/Ï<¼×(dMbAF)ca$2<·*A9¢#S‚ÂÉÄ#P-£0J°­]¬e�6cpÔðOKDzÖœ†]§{7lÈMð¦°dÊè†dé  ˆÞÎxöh¯2FC=«†çd•˜hEÊné³-Í"aC¼…$”ÔC1œ†¨wÀX×2È8„— \[¯¸jT±0ÊH?“i !EK{Ø2ïYQ�n¤T©e¼ .â5�aÞ¤®‰æ’äRUtUA^ÿ‹˜Î¤ÉÀø‚�Hòª×x£Åj‰X³`a ¥tH0ðV,¡ÅT°ƒ…ÈÔCÜG†™;‹À�²Œ™™%¼Ç¿zîE,¬P±Â>kñkãÈ£‰ÿä6òæï:òz‘>ËE�3K«¸wl)�¯®m`¢ÙPtxhhcõ:<ˆ¹Ù=ЇoÎÏã¾q ¬­mÆò÷|&j5|jx_Ó:3íÆë5Ü92xcv;û𨯑×Ö7°ØéjÃÖFå`XÓ¦µxjûVd4hX‹ÿvçNüíÓ§±á–Ö6ðãwOáéûî’EÕÔ-56˜.š˜³`&i„HéßEéGc‘ÑÞÂ"ãHFqb{>"­l¼\I…åŒv„÷™#”Ô %{®QŒ1 8¬Ô ¼œÙ,G=³(r‹N–¡�—ÈmÁ±‡ ÅÖYaÐu¶ôè :dt'ÆTz“„“¢CŠS˹Ø0``™ä ‰öž£ÿë¥Üñ'&‡•}¾éÇ$ÞºmƒÍvÿ­ú�ÞÓûÀS(oa$úAðNð”Œ&ð Vû$Ä=â3^€×KøÈœõf Ì¿ mMGº™á;üç5r ðBÀøÄ^¬¬Ìb||/>ÿ<¾ å¶Ò¶î€ �NÎ�Ã�CqôØ]èt:øúWÿ GŽÃ\gàÆ�ë˜Ü¾###XXXÀââ5EyÞˆF$³|ë5ÝÌè$2A·³Ž¥%*T{üøqüÉŸþS<÷µ¯bueO>ýìÙ»?ûÉKXZ\Äôô ìÙ»ƒƒCh6›Ø¹{7Ο=‹Å¥E|êÓO¢¯¯§N}€kcwß‹‹~hµ†Ñß?šö!æÅy=1;7‡—žÿ1ʲÄý<ˆÃ·ß¡Þä®,qíêUŒŽ�aûŽغm/>ÿ#¬®®â‘Ç>Ž¡áa¼þê+˜¹yO>ýü½¿û‡˜Ÿ›»å¼ü¼Ïž={pÛm·cÿ�ý0žyös¸ysZS-..¢tNainnÿáÏÿ=ò<Ç;‚™éi¼ýæ€G?þ8ºÝ.^{åe@__¦vîÄ'߇s«++äÍ¿¼Œisô_ü—ø—ÿüŸ._;ƒþ¾!4ê­[¯oÄmÑ”¦°°²¼„õõuºn .œ;‡S'ßG_?&'·cúÆu¼þEÙ=ùÌgpñÂ�ó-[¶¢Õ×À`vv¿Êçì™38Ë5öíÛ‡§Ÿy¦§o?úÁ÷õo‰¨‘ÏÄ–-šöèVŸ7®ã©§ŸÁk¯Rÿo.ÌcÇøD´Œ¦¢cbïáKÞŠa¿« æs )…˜/§þ�³²U'q—g/9"¶pN�N�‚Qœ¦jTçÄa÷€¨ú­`H¹(r…CÊ}»°Õ¤ß€â/’™”ñ�§±œèzqâ!#€1Î eÂËѨÍð”N/ĹÉ%ÊB`ŽÍXlò cå9£ô¤0†j°Ü'Æ7á �òx¥À2¯4$å«5$÷YJFä"ÑyadÁ6až„†öòmŸî7½�óH óÒË¡26áHΊv²êN*”^ùaÁ@ö+t}z"�‡óŠB(×zP†AàŠ®¾7•:!¢´7ñ$E“å¹�šžŒ¼‰àM‰Ö[”>ƒ39|îáY¶7®JË|óæ”�ðl °0Ö…(%™Œ€*¢ïÍ~ýâÏf;¿ü³ÕæVW+çã Žøéž±0.úÍMšì=Um#Zo^Áô¢7 ¾B@�®Î9b,c+ ¼·LL42hº5 º_ N>�¦Ì²BCE´˜(2È#ßÜÔ#�ÄæÈÀ@-v·œ8c¢¨^õék#llç.\c %á^t8£íÀÇ·úÐÀ 2!ÑÀL46é{±4Æ;˜wN%ïTYŠ_l>ЫTÞJî 7ăfmjF¼ *…q$ŸM0½�:D\Ÿ6®¸ ž�"†£<�qˆ¥å¤ôP¢L@ç¢\¸–t!â}í|0ÊEC‹=€äôE±=0àžS¸™é‹ž?@BÀc†°2ÿÉ"I#ºO‚‡³ù s#csÑ46 Kém¬ £y<»pÒV¼zöçöÃý&3!r€S 5ê�ŽE‡D€ o@åp ­i p>#Ò¸²„ñ@É‹eay9h‘¥°>â�dT‰OBÌ„b?@p'Š….¿Ñ51a‘µ�°/(%ë p¯m²U!Þ ¶¢O×µ2#a©fkÀùÓvEmØ[YçÆ(hò¼#I�1›llò`e6+?%zÉJx·Ü¬@Ö7™Ÿîi·†gÂ3RÅ•e7áZÊ.žŸ›)|µ�øuí 0^é@HdI´F¦!Æ.Z#¯°)9e)�»'¦ §ÖxJž=åÄ( êWš'§�T$Ø2‘WâO}´¶dFÇi~BB�%<.Ý\Àw_§º-cñw·oÇm¤|ÿpe £õš¦7ÚX/�¦òiY‹=ýAñ’ƒûÆGW×ÖÑÈ2Lp¤ÀZYâû‹‹ø77n`ž‹*þ²Ÿ™n53ƒ¯ÍÎâÙÑQüg[¶àÕ™y|zrMÒ.`K³ŽzŠåÝ64€Ò ]]ßÀ¾�~ìîk¡ôß½:�ûÆG´Ðñr·À*€ÃCø;Û¶á½Fy¦Ÿ÷$ž¸ûZ�:ã_��ÈÞ^ÖxärË¿ááKbÔÅ#JC�¹p™Í(ß­À úìÝW:E‰²()o¬¸yy¹WðSøz°¿gcÄÖÉp…™æÈ»Õõ IDAT�ƒÉ<Õ:4¯qžä5‹z=ÃZ»ÀÚF��ŽC»[–™·(½AQ…óè– FU…± ”Kª+Ïü�󎽵¢Š}mBTSÊW(Œž‰‘ŒnãˆEÑ;MÊûÄD:sŒwƒ0™â£ÿGžmѼ÷~ˆ BÂ{@È Ï)ñØ’>%´©w 2á­Fô~ž‡PÏÂèyér�¿SA¶—ÓÐK ô7ñF¢A£‘ËËœc°eÛ\üð ܸq/¾ð<~ï÷Û&)õϵ«WqöÌ)<þÉ'PõS§NbÇÎ) ÖP«Õpìî{°{Ï^¬­­amuO<ù4¬µxð¡‡ðÝï|Þ;ÌÍ^ÄÖm‡уþ¤Ô^Uš¥†áêyþÌÌ|ï=ÆÇÇñÐÃ�Àƒ}ìÕ ¼÷î;˜Ú¹[¶`pp_ýË¿@?~ã·Ýnõï=vLMadt'Ž¿‹þþ~¼òòÏôãûÒ~E0Ù¬µh68pèVWVÑÏ)‚¶ïØ�C‡oGYøÑ¾c ¾ü[¿ƒÕ•¼óÖ›€öFC»†Ñ¨7ôëkkøÿú¹xñ".^¼Èóï¼óîºë.ŒŽŽaphHÓäl›œÄ'ŸxßüÆsðÞ£ÛíâÀ�ƒ(º]ÜäÜýgN�B–ç¨7¨Õj8{æ4Μ>…þþ~|ìè1œ=}ZÛûħ>�F³�×_{ ?yéE8WâÒ•S8¸ïî°z>Ðb�Ϙ÷Žà|iiI‹(Ö€Õ6%Q¥D—J)•Ø�þÚØ¶tPÒEá•?¦èŸÝ-å$i`6}¨ïoˆWἸ¤ºòWÍú>†çÔØ¸³BzCŸWo¨·D(!‰VUÝÏ5•¬í&½A£ðWk›IÚµÑ|ÙôZ.ëéBV‚õÎÄ1 »CLÍ„hYÓ‘Ö»‡ËzeS¹Êî©s# i­‘ñÞVú%ôš®©�¬`eÃåB³ÙÍÊÖäçÉG(/,FÇ”ë³ÂBê°÷Ñ*�£Œò‚Œq›¡—¦Å9�Šfá°›…¦c¡c-¥uÌMãœ.z"„KƒÕîû€äc�‘Û–F¦?®5·l’ȃ $t�”—DEQy&m#¹(¹·ï»§!É\‰^`™ È%<;¥M}±-) …™J DþYiº¸Ã='äò‘(ࣄܜÆ]²å¨¸)4-ÑF™d ${$>’ß;tý†å$�Wê„Oøn´ EJ BI":ÁÑ&ËÛ&˜ÊÝ4Ça£Ãñt#,$ûu£»ÞY$Â̦Ü3r©dÝÙ¨dÆ¢În[Qö\1<%Ñ\âP*Ü_ɳ–©/W´×ᵆÂz çü0.:ÅeM«G£Â¤¹9BY´uë²’|Ãt¬•µü«¿}, ÑW††y`4F¨nj6èMŒíõ9'@e-§V[\ÜרþŸ>;ÕÃásÛZ' ç:þËãÇùÍòrm̵VìÞ<µ;&¸q÷C½ ôœ™[æðÙy^:p†·ŽM³´êp“KkùñÌ Ï-.òg]DO–qv­E¦ÛûdÐÁ¥eN¬¬qϤ+NÚ6–©•5¶÷÷Iq`Åm㣠¹«a\!N„…NÉ•yƒ½½½¼³ºŠ±–ï<õkþÑ}'FCÛPK Ô”È\Qº Þ)ÐÚÆ‚sŠPƒ¢Èh�Ön,¨Êí7B¡,Kʪ¤”ñS:¦�´(¡dˆ´î>¶ ã뉺††¢+ç0R.jÓ‘‘"Ó9�"£Ù“ÓÛ14×:äy‹lµãŠò•`TAE&E-´JÁãVŸãÚç]^R§ª*Œ­/ ZÞä)8]m*YêÆÖE¨«ôcQ‰¨G]ÎóÂîsë7ž`ÓÌ3USôÖ]¿Ý�Ÿ$Wù ¬küž†êÊάq�Ú�â�+x:î!­¼ë¢ &…çÇÔ×z—6’£œa2üuQõñcåÓõ‡†&èëfeežÃ‡³ïí·áÒ={áŠ+¯ ,K6��ñÅ/}€7ó›6�±÷ ‡'ÿäã�qîì¾ö»¿Àm·ßÁ#?ÿ9Óç3¹ùò®o´7P“uÒ¿éïçÏ`vv–«®ºŠÿèÜy×Ý\wÃ�¼úÊËì{ëM&&&ùô}÷súô):�eUQ––—–¸ìò½Tâ }òñǸlÏ®¿ñfþôOþ8ºííëãÜÙ³,--²÷Š+é”VV–ùη¿Å¥{öðÀƒ_fpp0ÜW뜋/ºœ"/P¸" )ÎwYu¨ª’Vk•vg•••VVƒ\X–%Ï>û,Ï>û,“““<ø¥/“gúiue…W^zc �F­5ÿä!ªªâÒËöPû÷9‡õÎ]»ùÈ]åÛ󰺺ÊððyQ„¶¾òÒ‹,-/ñ�þø�Ù÷öÛÌÌL³´2Ïüâ4Ãc|Øcvnžáa— 7??Ç¡ïQ�Nk ?øÞwؾc�N‡“'¦¸òêkصk7?ýñ�d ãd5‹&—_re4–+\¡L…VR0Ë`~e‘ÓÓ=sc ?ýéOùÜç>Çèè¦PGàÜÙ3á}žçnï(;�.–Äq±Ñ¡”btt”ÙÙYæ–—*Fñ؈ìgª S: ­ÆjŒ‘u ã.û»"ϺÈÉ’Òï1^Ÿ×*â«ENžÁYŠ!¹¬\d:JÚa@IpŠ—»¶¼Ø” 1tƒ’oR�®¾üóüú Ùr²y¨k#ŽUƒ A„F2ìªJ9½s7‘øk4¨Ý^âA>)8¤}yWëã‘,R+�t$‚Z"Rå„YˆÌÖï™è4ÑÜâG%Hæî^òOô¦_Z�Π"rL×ѵU×&&e4Þ[×älÐݼò/šeü><ÀÆkI¾K¾´ªÞvë�w–0vQ¨ßº6Žáݤ»�ê—^³nTÜ áS·áŒdP½ãBwÍk‚„%ÔÔPYò�gb™Â%Y^:ên“­ãj­éëƒ¬å§ –²×¬=í¥Oú¨`Õ´ÉØvQ”0ÙÚªÞ¨ÍÆFAÏÖ&­~� £?'´é§ÛnФõ]NhNù…#óè7tï% ®v‚µI%ÃÛçn%—J=ïD'´s>KŠ&%…Ñ4D8ò ̓ѲgŠÂj*¥0Z¡Œ¡´.ÂÄ Ð°•«E�‘i,Ÿ¯òS-ýH˜N€—QNP o&Œ=¾Sž„[’×ÍÔ�P©8G¸&fm¼_×DzA­û}j ðé£þÇ/,kÃ\F£»‘÷Þ½<‘É3©¸j�GÂãÀ;ÎdþÄÿ dÛDPï¡î†�ëÙ®ÿ*9"ù†½n\Bäªh]©c FÀ¦ýªßÇ55:§Ü8ûP3?Kâý´>ºC ó§Â^á…qi¢3‚À¢üåÙ.ÛÀEÐ9Ø'ßOo¾ÿVXƒ‹:ò¢ÒÊeuC\Aiöº"$`¼ì?z–C§dD¦ŸÝ<�VŠ–qÆ|-�Ó«-ήµ¸nt( Ó\»ÍE}=a&o¡PJRÅa§ê÷­¬ð/Že:ÉêkòÇŸ¹‘o~âqf9AÛÑUpTz~òê¡süçóïœp…Ïw:ü'G�òlÛÆ.�3Úˆ¢í}½ J-„Ž1 ypì_XbKO38/^Ÿ]`­ª¸]à†2 ]þñæÍüs�óxóÈív›Þf#*¯Á` /Ÿ‘£T€P&:Ôb*¿081¬kA ûQè”ʲt0DBn}+¹—s øBf^^¼Wè\QO„L—œ²˜Rx»&WŽOg™¢²šÜd àˆ´VdyF«£T6£]ZÖZ†Nié(-i¼Ç9(DaÀjôÀ'»µdEÆë¼,u�#°’uœ¾OdCw®&â ù¶¹3Ø€ÿ¤GÌlˆ{dT¤6Ú˜C Â+šp U�ý>�ëÝèŸv¶õO´iߣréÆ]'ûaýMÌz4VÝ!ã{Ûùiºn­�Là j‰"XLl¾”£‡]û;ï¼Ã|ãét:?z”Ý—]F__íV‹ï÷oùÜ_dH ¶+ËËäyÎ6‰|¾ó£w3;3CYv8zä×]C¨A0=}d½üX;’ïUò&‘åƒHgJffœ±½( úûû8yâÓÓçdÇŽ�,ÌͱëÒËxãõ×h·ZÜÿÀèïàçÿ”ù¹9>ö‰OrÑÅóôSOrbê8�FÁÄêÇr§·o„ž¾á¤]QƉ0[õ}¯( Ž=ÂÖm±¶¶Æ¶‹.æ'?ú!Yžqÿ_ ÙhòÿûÖZö^q%w|ä.Ô ^ZXD+E™ðéóŒÔ@PJñù/<ÈÔÔñ!Ôl6éëïÏ:þ¿|äg4{z-´ÛüâçpãÍ·`Œ ÓçÏóïÿñóßþùÀ©3‡ØT“m‚,à—ðΡÂí/¾d;G ŸßÏ)°¸¸ÈŽ�»˜��ÅC§ìÐßÓÔc 2àkÂy9'ŠÀ‰¬¸EVÍ´’šH"çXoô"ԾʽN�)ŠBö áÍgÄ5~ŽŒDq²³w”G{Ãz^¥Až#m!ê).�Ãé6óxŽ1+3dâjï0—ìYk�1¼ch+P¥Å(�ñAy¡-Ý/½Áo^VV.ú^…æËÏN²ÂGÝHjlÀ4q – ÊVRÃGœ Ö¨ ãfí�*¡Ÿ[T @@ñ�üÞæŒóÖâj•†²ƒs ´*ZRC®Uºß:‚…] yXAtJ…õ©V’ëýh‰¬”éLðû½ãCƒ©““]x«ßsPÎpnñ�¨Z ôšNi(Kô— {gš¼pt’gT’£ÍXó �îÑYFO#§QÉZa+‹éX4ʸä*mP™A[‹ÉlȆv�"ÖÁiyù_yyáe8Cºù„BßÊå™$6ÊÉ_*s°¯8 zç0Q’½_ƒƒ¤Á J cu–³ðåu�Z@™…4Òz µ~~…Ϫaˆ?ÝÛ?VÉ×ɦ‹ßk|?"©êäNVøiÈ–÷·S­„›ÅþHÖl¦â,WŠÅ·ß:ð›¬0Ž.…e¹@º‚ׯ-Ÿ�ƒö´e$¨OúŠÿŠN¡#ò½ô|4×®þ„{W«BœËÚs+üV‚?´rÚ€Ö•+©'èçÆ·Ã�‹�9YáÖ~D¢D½þXÿíû Óïw§×ã·»Û…ÏRµ·))~ø&¼ÿ…!õ¼èCb¥ˆ”lÃN7°’Í¥¤aÁc×Û6êÏŒ¼7çøµì36ž!ºTâ\ÛßH tÆ;"7I8¯×Ú|ç-Îl5<«pØäoWdWh“È�0µÁ=Ó/~ËÙM›áŸ—jé9¾Ÿ5*"ö·v­­ÿîo$ý²Ê+ŒVngcvÄFÝêRî>¸SéƒßçÊ^Ëî¯!âS%@ȈYÒm�Œ‘CÌ*ÿl¿‘ÕØ}}±yâõ‹©»{)�2‘/ý÷ISý=}áêØÏ8FÞ1uÁñêú±FžµE“´… ~t£’÷õÓ�¸Á Ã’šS*Ù˜Ãz¶>'Íc'¹wâ3‘Ððãì‹l‡çkí"gQ>ÃÀí°*:dSÊ´%Ï ( 4¦„Òbô=¢X€Í4…d189W Ñ26V¢\òJSY'LštŽÃðˆ0Iw�çhô›w2q@’úp�%nšŽNÓa �šÑ»îØ�y7áo£”9¥¼àê^_äÖ§ŒªðdÅ�†ú&â¼ÆÞî°`¼ôc.4å¾²AÞ šïc�X¡†E8üâè^4þ7¢â©‚Ø™,M%íˆýJÿzXŸ1°ÑžC¸V¡4®Ó°‰fI1*>GÏѬå%´,ò1%ÇÑu0Ò M¸yÔîþ¡Î‰ÇŸ©ñA?’õáæ÷žT9�Ž�à@0.Ê=Ê�–ý}WòÆf/÷÷²½éà$f[2­˜Èœ}²§Áx3ßs¥¸fÄ9 Ž­¬2RÁ‰ppq™éV›ÛÇG9°¶Æ|ä‹ù®•â÷ÿèKw8¶e ¥_K•¥!àúåzíŽ1~ðŸ=À“ožàŸýåS¬¶K*kùïNœàŸlÝÊ×G†X蔜Z]cïГ=MZÆð‹SçøÈøhp”Ö²VU€ëËÕ#ƒ´+·:%Ã�‚›ÇF0ÖrëÀ/.-a­å[O<ËŸ~îãѸ/ô¡ý|Šç1Ú«r¬À ($šMhÙ¥† n2*pwËÒA'x­Fi9çmYþ¯s ˆá@x¯VÚmŽŸ›eêÜ,Sçç˜^\¦Õ)Ykwhu:ô4 zšŒô³só8;·NpùŽ­4ŠV) ­É­¢°Îdµ‹ÞË%íJcTƒN•±²VbL‡<+É´ÁXg ðIî¾P–Jœ&™dŸ¸z~ 'ëÕ¯Ñp(‘qÄÙ™¬Õ�ŽV{…••9VVæY]] ,ÛTUS•”e›Ïü¼ƒ•)ò‚\ŒÕ««+ òëgžf||‚þþ&&'yè‡ǽŸúLm\|ÜM˜1/GÊáe UÍàÀ&6qñ¶½,,MsöìææÏP–%/¼ð/¾ø"ßüæÑÓÓÄZË믾ƒƒ4�P\¸`€[o»ƒçž}†s‹gƒá�×_ã½wö0ÛUÔ÷ð¡ƒ\wÃ�ìØ¹“£GްÖZavþ c£[krT”ޏðzµ°uÛE¼÷Þ»P–tÚmž~ê éë璘·�—¥ÆÀæ-[¸òªkxâ1‡ýßÓÓË}Ÿ€•.X&gx µbDè¥Èµ¥‘+ÚrÉÄ0ß¼ï#üå�ÅZ»Ík¯½ÆÍ7ßÌÒââ:È'ïèéíeMj#@”»ùæÚÚZ­ŽGUuÈuOPi�xá°à RŒTk:âW&ß4dî¯ÖûÜä�ÚËÿŠ<ÏÈòLúmɤ ­Lbdºè’J²R}¤®3ç9ZKÌ2‘^>óÑÝEæ!þäJ%py™w`GË C†ŸÈlYæŒË Ž�ÜH†hF‡Œ ÆV+íbºU4NǪzpR 3±q„š<Ò£}v¸Y•«ÿå^9®ø®¼îPè²Ö À5A?¯$2ÔG�kU%†ÉL“Žãeg!X%:Ž£(Kh·+Zkkk%k�ŠVihW¾±Ï@œ^?“,å¥gßIÔMÄ ŸüƒÅɼCë2�T†¥ÂËÑ^V°ÊÐ( ò¼ ‘etŠ‚V«Ck­2|&¯Vs4"Á)xÇ’›ÿ¾È3šENO3£Qd”¥¥ìL®0îÆÖ©½…¥\ ŒJ» ßÔ_ïŒúPd–"sz±ûìàŒüì!^5qò•ÂÁÞ¨ÜÑ¡3Wë@'¥�ª”Ì [Éþ‘%:°›dŒ�œé^^"·Æzó°ËÌОÎýÞã!mÜc:ºõÆ„$k5|ƒR]ËëxÞqƒ Q_ŽÙá*UG5fËäÑ1Åv½�9��s©Ñåd),l*ŒÐc%vŒÜ9•Š"s²¼ÔÚ¨ÄËýl^¦sYP:~§ÄR`-(jFdæÉºÉ•¨ö¬µ8“´•¢Ö.ÛÅÁ‚vB@šÎ¬Ë Ê”s äJèÈÄqöƒ¥J¢cÀ·Á1‚ ÌâX'`ýÿ‡)�†ï�ý‚D e#õƒ|¶’%PÙ`ç bîö” _$;‘GHm`îM|Õ3ºo€I>úç+�9†'tQƒá‰'ºñºöÈÀ(DH†4?p�D øWr¯0¨BÌÉ£ý÷[ƒ¹ IþÖH6åYég’¾t70ê¶ñs–\w´‡|²‘‹ÕIŠà *ñ©cÀ“�ÿRË"Ó´2÷;á:ç°õÞ¥ýJ7‰:w«½ó¬Ä;$ϰµz#Ÿ£ IDAT¼ 9Ö§ Õ=å6ò”Ä âÖdýNÝ‘„a)'$ gZ¢y\BD8.º+Œ€5bøu™ÖC‹I}¶†ª=G%cà£/m` Ƹì«áÜ„Ç×2’aW~Y'ë÷µC§99ã0‘uÚüÙäŽ0&[z�ƒÀ¾¤¿×E¯YË£§ÏqÏæqâDRVPä¸l°Ÿ]}œl·ù N�Fžñoþô~®ÛµÙAà§M±‡Ç:ôû©ÜuåE<ú_}…¯ÿùO91í¢!ÿ§S§˜( nêëg¾Ý ž¦ÖÜ39Æ@ž³V9›k†LÆÉÕ5fÚ®$Ï3æÛ~un†{7�Ó—;åék›ÆxQ".ß84Ê’çZÒ¦#Y#YËÒÚ�¿º?Ð#t»Èb¶ˆOñ޼ø�‹8ŠEï¸ê2¶ŒeÌ€Ã}øÜ4/½{”×çÝ©3N1ùG³(¸îÒ‹¹óÚ½|â–«%ÊUQäšf#s(t¥1¨RÑîˆqDi¡ý N;Æd*¬Ša€>Z=d+ÕöKéH]0Šô¬¨}ïyh»µÌôÌ fgN0;w’N§õ¡ú�}½ClÚt£›¶±it>‹,}¶·‰‡­¥™Z}�÷î8wæ ­ÖââD×î’ì½òsrfýèíflüÒš †NiV–g9sz?ÓÓGXYþðEeûúG™Ø¼‡-[÷208K4üG9¯KHÃï¬q(½Ó#¶qhd+Íf?­Ö2ûö½Í¹³g™˜œäÖÛnàÅçŸã’íÛÙ²uÏ=û4�¢ÁÝÿ„k__?ccã!;`ÛEñ¹¾ÈðÈ·ß~û÷íœ�w ¬7–v�j:§ast7=}p…vÇ6mâÌ©Óì½òJfgfÐZÓé´Y[[euu•k¯¿¥s³³<÷ì3\ÃMLnžä½wßå�×^eë¶m|ⓟàñÇ �ßµN0­vmä.~Oß´iŒžž^ÆÆÇ9~ìóós\Ã�4{zxéÅç9uò$7Ýr+—b_=ùSÇ�‘ç9¿óûßàè‘#:ܼ!),ƒ Æñ1RLØï­©ø=48ÆðàK˳;þ6Ë+óXkùþ÷¿ÇGûï¿?@]¾÷ ®¿áF¾û·ß{wYvV¶ýàû´ÛmFFFèíëÆðññ n½ýþÉCìû-þäÿ)ÿâ?ý3NŸ;Êø¦-ÉúrtÚ-v¥Ÿ�1¬­­òËG~†RŠk¯»ž™™™ËtËm·3::Ê/~þ3Ú­ËËKΧÕZãG?ø>7ÜxS¼?„èu­\ôg‘IÔrfɵÇ4z³ÈC}|â¦Ëyø¹·8xð 7Üp#ààÙn¾õ¶à èi6i­Å:r¤ZkkÐQUUÑȽá\l†5«ÞGrë’$ºÜö•"¥2íÝÃÎ(Œ­Z dK–¬g©5’)P•SÚQi�²$5¬|¤y ÅjÏC¹, �ÀYq\8Y¤(œÜ-ëJŒå$BÿyxE®ÝùÑ1�“å]et*2jf½7hÌöØ.L•ȸµI‰|É@)x÷j¤ÒÎxhŒËºw†Ñèp2DêT�€)$äkÁ¹¨nd€“Á´ CiA2‚MRWB‚¥lEUZ:�Šv»¤Ý©\m�™1~ž¡Ä íÕÚš¾ÝµG8g“)×�—_}@Žiý@YÌõ˯-‡×¯°U…-„¾ü3¶+×â” B?ºØ6-uÛ\Ñà"ƒ"W4rM£@"c19ØB ÝVJcµ%×`2…1ÒÇ;¢Vt7'cyF£‘Ñl:ÇCžg˜ªt8áJÖ¡Ìi`De.´£9ï0Vð5¯¼¬í &£®-bwÌbòÓamŒ<·Ö!ÐkW‹0ŒrÅŸƒ�IöEG¥²+Y—EjJ‘î#*4#ê’©ì×½'§|̆õ”,šš­ügqö sÈMäÇø�‡“à$eðÅÄýB¨¬E)÷;©ŸkC¡]X-óœª$ý§;ó_Ê©­¦Ž÷ÜL´2¨)«\¬E£ÉUF‚,­slePäPÐhXŠÂ’åZ—Á9 é¨à°XY“²ÐQ¾x#•ûMi�GÒÑV²ñV²ÁÑ-v§øà›­—Ÿ?ð¸À%ëÅí”~›Ûmtæo;8/Ù6�¼‚¾Äj¿?$MòvoË ǵ’ØDïL÷k0Ñ3äfu‘.Ù—äoNí„ubW½�à úÚ: c/›F™5€QƒÜó§Ð¾4ÚTîä¹~ª ©ø3~°R%®Kp­÷FÌ�Á˜•0¤îKlýÊuÜ­ùÐΚüYWvÃݺ×Yøœ(õŽKû'MpL¯f¼ínW-ñQ6ê˜|µÑo~üqÐ*õ„qV¡mi{äÚFÈG;%�‹/FH¬ Í÷is¡R:ÞI¿m¸@Åâ¿KORÞ ›\ì�ÞÉZQ©Ð©¨�Ê Ï ˆ�óoýoÖÄ9ð›¤o[H/MúfÒqIÆ2is0v†ß?€Åuÿ$0êaLI¿kçÊØ+#ó­Mtî¨ô%c"6"2ƒÕ4ÍÌ EU>'¸[åÓ�µcj]mlå"P$ ×§�j•‰ îÐ#?‘­?Zë»R%r5�>J²¯PuÓjL~ÿ!ïÊ H ¢PÖj×ËsÒÌ€ ä©õŠm4«è0À)Þ W7 G¢·ñ:W‰Áß„Œÿ¬úçÀŠ­�V_?>a�zš•g{%œ‡æÆ"…h1xÞÓ�F烺×A Y‰ÚIƾâéƒA²UD€×‚ûïÓÿ�`>šÇµFø—UXãð8µrg¦R>qZ "°Ú ã· c%Òß�=1š,dÈh-áëì+ɤÖ+¿q?Uþê/…S?½i”ÍEÁÙµ‹eÉ¥R|ØØt?vcõÉ­“(\� \"ŇgÛN¯®qåð ð_;ÆBâø›þU.r…õ§€õã b"S-­Þ¯IY¯�<ç{ö¿û¯~Êѳ àϧ¦ø‹Ë.ã¶ñQ¬µ¼:3Ç®�~Fbè­¹E”RÜ´ÉA�ôg‹*Bf 7 >³e‚F¦9µÚb È¸}xˆ«ûúxkec-?{é7|ù£7:›·LŸßŸAj¥Õá[�>Ïß÷16<ȶ±*S…uØ®*^ÜwˆG^y‹÷NœyßëGuFŸÖÌT«ÖУ-g¶Õéðâþü¸ÿ0ÿËåc7]Í×>u'c££.ÊS WEi£qËV �¨�Z²¼l£qPW$0¦¢Ñ¤;2¬æ¨ó¼AøFe*Ξ=ÌÉ“û˜�=¹aЧ5}Js¾*Ô£Y†µ–sUÅšÀ4¥ÇÊê+'˜:±�¢h²u˶n½œžÞ!‘T¸wà\î5AÇßâ¯gϼÇÌôñ÷�¯{ mf|bO}?°pö컜8þ:‹‹g×]“¡Òš­i$®ò5¬$Î¥•åYŽz�£‡^`dôbv]z;ã—†¹ �ØšãÕ-ÝÈC¼qŒš,éΙ˜¼”©ão�ç9¿|ägüÎï#d˜ôöö24<Îÿø½Ÿ ÕZãø±c\zÙ¶nÛÆÜÜ�<üSn¹í6v_zÖZ®»îúpÝôù#ìØuÛ‡ßÚ¾ Ìœ?À™3gؾc']|1¿~æizzzøòW¿ŽÎ2~øýïÒjµøôgïcbr3�ýâ¦ÏŸçü¹³\²};}}}(¥Ÿ˜äø±£,¯¬pbÊáÔ÷õ�ÒÛë`„ê£Ù%6ÈûÞÞ^¶mݾ·ßâË_ûzÈ\°ÖrÇ�w±ûÒËxãµW±Ö²0?ÏÜÜ#££œ˜:Î%;vðôSOÒ鴹ᦛéO |bÄŸ<-G±FréÜ×d}èåʽwrêôNž>Àââ"�üügt:m.—z'Ožàô©Sôôô°ilœÅ…ž~êIn½ív–––Ø÷ö[lß¹‹­[·qúÔI¬uÅ‹x�‹¡-Ï3ò"X§óU”TÆEšwJK§t8þU‰ËP("sysåy° {±•ïÑÁ=¾~SO3§ÙSàãØ]4p ¶Â"XÞâ(r©û$p�®]9YV‘µAµ5t¤À«1 ħ Y¤Úg85x2 ‘1ŠëÐ+)hj+ël(´ÊÈ´h3o”rFXë! |F¢´'Ë\M$�ròÒ³^e�3&Ã�gý/Æ8ƒt¥±btv{|%ß:�’N§rQê>3[ ÂZtA›è§©úQÛTýåÆAtg£ÂðX�tq†n#òpb„Å¢­AÙʪ•3¢š\jb(¿Ù¾Ç ÆZôJW@XÊÛ W /‰Î–„›Y…m4•r°î¾nµ'� IOÝg%Y)EžÑlä49�FAže”¥¢*½>åæ³2U|/,âI ·Þ)d•+‚íКŹ2ÁݤÔ2QüÄ„ÂÚɯ]÷0-8æ’Ñc‰_ ¬òŽ0 *óÆåîÝ?—:­ÐõÛº#Ð�èÃV =¼t’s“kC¶ˆR(*¯È $�(LÚg“8�8S•ã-Td8¨«Ý�­­®Y3ÕÀÉZ™“˜IZ”*¡Ší”¶h›¡É…fp™e EQ(ŠÂÕrl4�¦¥(*‰ä…õL{£ aQJ�·œC 1`…‚¾-ƒ¶A`Þ…�îyûà½7>çÿíãï£-t�Ñ}“€ÄäÏ�µwàú“l]×w´ì ¯•'%ˆäbõÏëbE6Œ1ŽPB�|{“°ùÊW݆-¯`Öåîq=ñ –•ü÷]" K|hõNC’äîÛx]8½Ë(’ÎezjèÆ†#ôÛ£_°*¹E÷´BͲµþ×hWN¿À&'¸–†9õo‚WÁ&ùJÉXƒŠô)u ¨n#ÌõKÀ‰c}úƒZ7€#NˆN| ´´ÅGBÉí¤f•ØÈýý�°õèe÷Nƒ¤qõ}&4Äb½ážî Òg¨8 �‹aÜÉ›*Ü##l-òaÝüÛ@ç„M[¿@4°vu"г­ÓWê��GÄm/iŸõ£âÚ”]P¥Î$Bì7ü°™Œg÷:DêAÈ ØÚiÖ7Lö[e¸Ì�*:2•Ši¤68'¤(²Qà1òµ¥´Þ«íÆ_‹`g”Öü|¦l!‰W¬Í‘whù>„9'¤."'ŽBŒàO$XOðsÕírí~záP3Lot~¤�� î6εô#Dñ[Ÿ! ‘WŒ„ “è£ë‰™ÞNݤÖ5ÓÊ3ßÿ°aÙǾû.{^g,¹ª6©Ñ¡k— ;ÈÆÃ(®žÄé=ì>B;\êÇJ©¸djü©ûÉþí û1WTU%íõYŸ%�ÐRÇ*Wï#¥î<+KÓª)ÉNèØª˜µ`=5J[ŒUÇ/WÛ85#£ _sü“=M&qÙÆB¡u,껸̖Þ&ý‚ßxq™\)v:CRžÈž¿>s†wÊ@+ÅÿüO¿È¶ñJ-U>[€ DúBËë§NFи¨¨ÿãŸ=Àƒÿò{Ì-·X1†ÿzjŠÿñÒKÑJÑ›ç5 ºql„Ê8ÜÛ…N‡±fƒáFAËž??Ë�£Ã Ò©•U†› rØ´‰·®á‰7Þå+wßæ;u8úµ‘ç±Póßç1»´ì²ò”ƒèy~ßA¾ýøóœŸ_ çäJQZËDQð•þ!ú”¦¯¿ÉÅÍ&S ˬ•;úëëáÄÊ*g–×XÊàx»Í{««¼ÛvÑökí?î5~ùâ|ò¶øÒ½wÑlô:H Jöëã ‘ ÖóIå¢�5xóo˜Î y§fM£ý*ðb9 c*Ž}ƒcÇÞ ÝŽ0»‹ç“EÁj¦Ø£ 21]>:ÈZi8¶èŒzCÍ…b¡Ý¡£`ÁT¼ÛnñÒÊ2-á_�N‹cÇßäØñ7Ù¼ùRvíº™žžéƒçS©àQ?üo©ƒÃYVlxÍÿ“£Õ^˜wÌLãð�gXZ:¾ëUš�Eƒ«šM¶fͤMnû×”i¦I¦Y©*ŽvÚ¼²¶ÂiÁžŸ›�âÕ—¦Ø4¶�+®ú ý›Ð¨A˜îƒ€cF~�ûù%ˆ V)&6ïaêøt:^zùe~ÿ¿ÉÂÂ<�F“kĸäð!NLMq×Ý÷pbê8/¿ø;vì¤h4âêk®axx$‰½é–[baa�ù¹RªhDîàåÄ “EN‰´ÓÃãY`yyšµµò<çŽ;îà£÷|ŒÓ§NrøÐAò<çÆ›oÁZKo¯3üEƒÃ‡²gïLlÞÌÄÄ?úÁ÷™œÜÌï}ãÐjµxäg?åÔ©ÓaÄÆC¶@Ja"O†vEgEžçdYÆéS'i·Z”UŦ±1Z­EQðôSOpùWJ6C‡‡ü#�¿óûßàô©“<)™ —b�$‚ð‚ëå'øZLÝŽõ eAnÛ²‡¾Þ!y c*^{õUÆÇÇùƒ?üüâgSUY–qç]å™§ÅÂÂ<§N9' ÇÁ~ûÍßðÆk¯24<̮ݗràÝwxWà…üÊ×81uœ/<ø ïü¹ûîüì)F†6YÉÏtpVu—îÞÍòÒÃ##h­ùõ3O°gï\|ñ%<þè/æcŸ¸—|ÿ»¬,/S–%§Nœ`mÕã‹¢ŽÎ›k�²É%#+Ïœa'S¹•ˆzq Î0]dš‰‘þà øŸí;vpbj*÷·lÙÊZk�¹ÙÙ0©á¿ûÈóœ…ùùðy°·I³È=9� r0•ÃS¯LEVed&w…H«ŠPœU;'†3Rf’Åk°FI@P4L;c¥[kFŠ%V‚_––ªlzSlÁË£Êý­ò†Ç$RÙŸ‚FØ<×ENO£�5nܳ*ït—ó2wn#Ï,’£{¦(µF©­Áª ”r†øªr‚מi‘¬W¹¼‘ÉÀ—LR üñQ.‚[¢“åzë‹¿*E¥+iƒ{Vi+:–`¸·VŠOÖô±n-Î@éVà2\­ñLq X+sPÉ_7¾aç³6dtq ¸æF~ Åþh¼®šdÏzUÏÃ6¥ª¨wHÜ�ÔÏ2þG¬-±å¬$$óÞ€Âà÷X��p¡k?ÀfQ7òuÝ£ûû�Î{¿û{:�”ßÝ@‘íïbôO z³ðO“Ð�wóx›i�.Êõ�Jì2‰i?8òÐØn½GÕþ¬¿ƒ´¨Û° (þẶ–ÍÙ�Z“ RºèkÏWñBåï¤Â£ÖÑDø®öä NL�ä7›ö)* ±«É˜¥ãÑ=ë[ûS»/8«¨Ï…Š?)¥êY µ9Knš:|{kN�®AÛ@¨�çy ¥äJž!žû”ߨ”‡ÈôDà±`+0ؤ.�$ xÖ¹~¸j›…“z6“9À†¾§Æ¿yK»žaw~2lžölB†r²ñ…‡2ñÎ�®…e“{BÜé/D?I{ƒÖÊÜ ÷¢‚?GRvRÇŒgléÜtÓQ7mŠ�ÞåŸvý†ŒG¸Ÿuµ&¤¦„ʤˆ�¶aª ƒ™ßÜ�g½2Ή ŒÂVJšo©ÄkodÊPá2¬²h/¦É[£Ý´ÑéÛ@Ñh•Žuø-™º 2”§óï#³| ²Wþã9¯EÏ’¼€ã ø ‹5" ‰’äamœr)íÑ?#×=ý…þ÷é+Æ_¹ñýåÖ]‘Ž‘çI¶ö»J®»Ð¶ÝÉõèßWèÒ“·s©G§€–Wk,XK%J¸�ôòJX*!ŠMÊ)9NVÑ“”sç$ðô6DÆg2ØU¥¨LSŸ6îÙQ껳:Šg.B&I¿ƒ°®-. ÀX'`kù«_¾Æý–�FuÆÉ•U¶õõ†þ¿8=ŠòŒ4Š. .�ûZæ;%£�‚Éž&‡×ÖøÎùh�ü'_¸�Ý[Fé à_FÆÏ ­‡¢[Ö;Þ�ñ“ž‰· ˆ+Püz?ÿð¿ÿ!ÆXö­¬ð“sç¹olWHÛ.-³RV\;2„Öš3«-^��ç³Û\ÖCC).îí¡‘EŒà›Æ\dòt«Íž¼A¿Ö,ÃÜÒ*GÎLsñøˆ¬må/hj�ãEÁù¨ÎÊ@Y�¯ÓЩ\U¾B´Oc¡ÕqQ= gH:Újñ]Ç™itjvž¿øÑã¼;�ˆ}ZóÅþ!¶å{dž¹´·—gΜG)Å̓Ìu:Ü82ÌRéj(¼>3ÏH³à�‹63ßîðÔÙi®h09ÜÏOgfxiq‘%1Ô<òëWxöõ}üÁç>ŵ—_îŒ4•rPº²Ÿ9CˆE±£q5ÙZ⡯Ã+S!Ú-Á0M”+‹åäÉý<økkn2—5 gõõ²‡ŒÊXz´æŠáAN®®q®Õf ˘_m3ß)Ù=Ð�VpÀ;Šœ»&Çxüôy654iö¡z ^^Zä™ÅÅà$8sæ çÎaûöëØ¹óÆ½³Èºù|Ü7ÞÏ10¨5_Ù4Æ8:FÀjej¨EÆRäÐ.£ÐÓÌøËsç˜/KÚ­PŠªêðÞþÇ9sj¸ÅEyÁžf“››½aNvô÷q¾Õb¹tFÃBir­(SªÊЇâʢɕE“JÁKk«<¿ºLÇZf¦�ñÜ3Íž½gû®[�1BAMYòF9ÏwU"Zù7rɦ±‹)Š:�5^}åæçÙ¿ïm¹êêk¡¯Ï9*�1lß±“K¶ïàÍ7^gbóf®¾ö:~ñó‡Y]]å‹_ú ·Üz�=úKŒ©˜™9ÆÄæzv…�Mí’ ã~â9êôùÃlÛ¶�Í[¶0?7Goo·Ýñ†††yýÕW˜š:Î]wßÃðð/½ð<ï½ûÛwìä£÷|Œ÷Þ}‡¥ÅErɆÐZsõ5×ñ­¿‰õÆÆw‰º’´$Ñ3‚c\†zyy™sçÎóÍøïñôSOröìîºûclß±ƒ'”SS,ÌÏó9Áçw÷³œ>u’ÅÅE¶n»ˆÕ•e,Ï#ʲ’½ß­ãÓ§OÑ}t:�ußùcpp�™Ù-6Òߤ§áy‘“g¹Ãr7.:»ÓîÐé€ÒTZ§412×acg®–’vrh¥ÁC˜¸"¾±Þ ˆ|nÀT–²4áå ÑU�˜¤‚΂S'%+ÖX‘3Ĩ«uàÎÍ”"Ï2ç°ñVçÄ g¼‘i�z±_w™w^gXU�e™8L„À�‡Dr�&ý¯\Ôºs®+”Í¥&‚{V¦J�›ãwk¼#¥"SšJ)'[•%¹É(lÆ�dMZãô¦Ê¸ïrmƒ£F© J—±¡m77â´1–ÊdÁ9å³SXX·‘homW‰!z£U.šÙ÷;Ï}f` Ö”Îx®3× SA¦ÉÉ@lÕÁR¡2ÄŠ&lµ”`Âc°•u�—Z’32¿æ�3"Ó>8HäPå!±$úÜÚPD‹¤£qðY¡0ZSä9¶Ò˜*§”8r_@ÙGŠc‘ÚK®^†•º;Y¦i4N¨á „(4Öäë0ë;eE§S¡;ÎØ[V.{ÅWèsœJŠÀ;y?Ïœœª${¸R:`‘¯¯)+•¡Œ@<ƒ¯o€ÌQ!8ú>“ÈZKY–”eEYºZ•±"FÕÈÁk - ”¶¶fÝþb• {°çÎ)ßtoäŠ(:tÉ—©Á$žQ3M=úâÎ�vAæÕÕÀÐ(�Ê$f g*ô-¦tñ•6:ê<� 6s‹8Ë�SÌ/'Cêïìo}}.ïP*²L2—*²¬$Ï\�‹fCÑÓ›ÓìÑ4š¼�Y©)`Q™UJÇ}±G?6I6K"w×K£D­|ΈRRúú°ÇûZ’gøã·}ƇiKJ§…êt IDAT/t¯jï‡=ï·RJëÁ)àeiåî ™ìÊe )”îf6yÕZº�é%È‚Zâlr¿¡¸†t ²üB룗>þ¹ÀÀ¨x¡óò#žsù>µ¥ß‰’¨®6zÖGf[YW‰r¥‚6Y¨Iß‚1˦̊õô•D~§Šo -_T™xJ=£àGàc6ü±á�ªÿUñê�'xSxo=IÛmPlý5ŽA”¹Ø¯Mï/f•ž'Â�s$T%}ðaÞæÓ/ÑíU6VsÂXÄ9Oº�F¾E‘0ë'ø>'¿G^r½S ë»”‘$Y5õ1D¯Mꆦ‹×¥Ê^ý‡®WÚÖä”uŽ‘01^6À}¡‘ÄR|VPˆZ}¶õ½ ö4ùë³FdÒk§§€ŠûJªPèB£sMVteC‘2W0ÇE%hÙ¢•k3ã"4”ÕÎØ�ÞJã"g•áÕ;!Dp¯’VljzoN–¬k•Œ³ÏðßÉùuåº÷ݰµáIæ/�²óÆéîŒ�±Û°7ÖŠC$(ë$X¿>ÝÓÈ_×vÍ2R'LuXTV%ÏH?Æob‹�\7~]ú.ÔF}}JÌ6\àÎõíñаT’1ôŠ£ç@(m=cÀ+ª:‚ÛׯXùqöŽ7¯$Šr£ÿ]ß#OqÂpeD!´6ø­ÿ‹ÛÐ5.ÂÇ ¢¢Ì*jçû"[ù’ðX]ã )-øÔbƒlŸ|ëPèãÇÆhdšÞ$Ú])œ-ã2r|6ÀÉ•UÚÆ²sÀè–ËŠ÷—¸mÌ�ÿoNŸ¦”qÛ¹y„ïÜK)‘{ƧhÛÏ“_Â&Ý7ˆ¤©ÅÛ\Iš<(¶ŒóÕ»®æ;¿rÅ*_\Xäòf{Å10Ñl2¯:a.7÷6ùL�Ã?°¸Ì¶Þž�ñðÂô,M¥¹^à†JkYìt¸wd„‡fœñä¡gß|þ®ÀÛÝž ÚJGhœ;›½|a“ƒ®xsn�©ö*¡Gk–Ë’©•5vô÷2ÝjÓÔƒ£9 ­xêì4KeÅ'G†ƒc`za™§ó.ÿëCO°Öކž›ûúùÂè(;MóŒÓk-žYXæÖ±QúòŒWfæ9±²ÊŽþ^®æØò ‹e šŠœÉ—!²·Ñdxdßç'ósühf†Žµ,­¬òß}ˆ›¯º’/êÓX eéê¿8V¯É2Wx-¬Å¤0wÜ{e­(…ìö¤Àw»x’RеµEÞxãÌΞ _k&³œ�÷°Ie\Ü×˹µ“=Í�ññÚ¬‹€½m|”–1¼>ã>[[{{8¾¼JËÚÆ†ßš¶¶ÚæÆ¬Éç.á嵚�e©r†#G^effŠk®¹—ÞÞ¡°Öl}#ö­ßuK³Ìµs@gŒW†kG†X­ªà´Ø5ÐÇÖÞž=çè.C±­(˜j—aÍ ”°­Ñ`¾,±Ö0;}Œw÷?ÆÚêãYÎgûÙ’å\9<Ⱦ$»äØÊj�'·Œ¡%âX‘³œÀŸ æ9‹eIfáöf/·÷ôñØê¯®®`LÅ;ûe~þ×\÷y´ÎIAš<¾oOn|¢ŒiÑ*g|r7§N¼MUU<óÌÓÜÿ¹Ï°²¼ÌéS§Ø}™+D|îìY~ùÈÏøüdhh˜²,9xðYž³Y ±W]s-XK«Õâ–[oå±G]QØé󇙨²§6g>»ÎŠ �7¥|ÊâàˆŽ;Æ 7ÞÌOü#²,ã+_ÿ]ò<ç×ÏüŠååeæfgebr’'¦ØvÑE<ðÆn»ã#lÙ²•'{”Ù™iö^yuˆˆïïßDoïpPúœ8Ÿï‡’䛡¡!ʪbtÓ¦`X7¦âü¹slÞ²•ÅÅEv_¶‡'{”fOwÝ}}}}üò‘Ÿc­åö�ÜÉ¥—íáßÿ.݇ƒÎ •J–�² 6‚‹‡»×àÀ»wÞÀ�C¯°ººÊ�÷ÞãŠ+®à¾Ï?À¡ƒyw¿« ±}ûN,ΉpæÔ)æçh4›äyŽ©*þñ�¸éæ[X\\ä½wß`qq�O~êÓüø¡a­efî,“c¥#é  &7„–*ÅË/½Ö2>>ÁÈè(Þ{—“'¦èëïç³÷žgŸ~Š3§�£v÷e—qúäIÎ�uÐ]'¦Ž3<2’Üzšš<ˤŽà×g>TûÈP"$�È?s «Žç*EQ(¥8yÂAO �çss³áYcããL'ú�޾þ~8àÞ7 Fziy®ã+Ë„·»hZ¬¢B9Ìy¥Â^¢„V2í.ÆB ƺ¯5àé\Dª ¹¬xš“}cè´ÒAöï>IZ;PS¦7ü/ª{H”,~SWhýj²Ê9B?¼Ã&Ý9âìzŸ¬�Ú~ÆMEw¾Æ¹É5º‘“5!oZòŽ%/ YiD!r‘RÆJÚšÊpu´ý}1 ÜÛ1PEe �RlÒaÔʺ®iŒDNXI?¶ ,URv©¾Áy£ŽtÐ&}÷cêÝki*}Š•�*Èlp^š1�’Bêˆ)×nÀkX¾AŠ’6Ê lrm,,ü&EìëFÄT{럿þm¶¿  ­ã#–u„n>„'Å:]Ûîö†Ëܾ¡µvB.^¡ª¥Õº!P!2&]m.ÚIøq¿ KGûù�}›}aY•å· ç“÷8½Nxwø¥*¦¯Ê²ÒZ“)¶·0ðJ© .åU¹‚z>[èÄÌ<ËkmFòœ;È•b´á ÿoÏ-rÅÈ`È«9¾¼Êh£Ž�ñf“V92XäÁ)°oe…Ã8þËoÞ+z™W$:ÐÄ`hpMÓ•°[ß‘ýiZÆÍT¾Àš;¾ù©›yø¥wYZmó«•%®nrq§‡¥²bso“¡"g±SòÔÙi>>9F‘;#Q«Íp£ O"×� Q ]¬Ëæž&›{šTKyp ìŸ:C§òÁ¿5 uØïŠ<£Ý)y³Ý¢²–éV›«‡¹jxˆ™V‹çæ¹jd�½C,tJ^™™g0Ïùø–qšYFea²ˆ‘»¯8ÆKûP(ÅP–ñ'›7ÓYi³´ÒbÛð0ÍLóÒôqhôå›Ók-Æzš_^E+Åu£ÃljÎLÏò;÷}‘FѢôv¯¥r‘�¿QJdÚ“µá  üFá !¾=}ú=ÞzëqÊ2þ£¡Mô*Åö¾^®Û4̯ÎNÓ2†©•U>µu‚ÃK+áÜ#K+Xë .ÍLsli…ËËlj4¸f°�C‹Ëœ¸��NŽqn­Å;’™Ñ«5Ÿf§ÍxÏtøþì XX8Ç /ü×^s/cãÛ£˜eS.‘H]N-Ž�T.Y©*Z äÇ‘åU/­ ”b¬Yp~­ÍñeŸtõÈ §W[Ì·;Œç¦ä7¯ýÐ9��ööskO_øÍ;ú‹c,«ò¬f¦m48½1È»ùõbYÖ>c-÷öôssO/ÿûœs�>ù6e§Å ·~­óDî�ÔÏTb‘ý5B ÅçmÞ²—S'Þ¦ÑhðÖ›¿ Ž�™™N�:ã|ä®�Ò××ÇÚÚyžóà—¿ À�÷Þåô©SÜu÷=(¥xëÍß°mëÖ°Ïœ?öà ¯×�…µ–N{•ÅEWÏcllŒ«®¾šéóg©ªŠ•åeN�:Éw~”µµUò¢à;ßþÛwìäK_ùÓçÏóó‡À×~ç÷h4›ÌLŸ§Ùìá©'ŸÏ™˜ØVD-S=•·jB,..RO=ñ8W_{Zkf¦ÏóìÓ¿bhh˜üïìßÇ 1$_síu�Íf“V«…Öš—^xž]»/¥§§§6¡¦Q ¼Ð¾ï5”°ê/´÷˱id ›'vpæÜQžþyvíÚÅ{ï¼Ãüü==½èLóÊË/b­ehh˜k¯¿žgŸþ33–¢(xðË_åé'ŸàøñcÒêR;r„Ï|ö>~ü�sÌ/ΰy|[­qŸ±µ5yú̾ô¥¯ðüsÏÐÓÛËu×ßÀÑ#‡ét:´[-ö¿ý-Áïo4<ùØ£TUÅÄä$ccãìß÷6»v_ÇR+úz g<Ï2‰ WP kÅ&£°Úb´Æh0Fóú!ç§S–LLL0+�Aív›²¬C}�S`~~>dlŸ¡) :ó™‹Æ%wE®kkÁ:!íSÑ™‘iç\P×Áð·b<¯,xXSÇ;�l¢2gØÔbˆ‹UŒw-á3$C°�$ò¹—Ã•ŠŽ�\g!‹$“Œ… S^áõFf[ pËžWCU*J ¥rís|òÌÁ9 "Ÿ‰©P‚aÄ1a2…µšJ¹ œÊBeuȰ1Ú­/c*”q…¿óÌeAæh¡B N­ �B‰3Rd¹s ¸Bè¢&“zU–Qå–2Ä&c�sÀÏ}åŠQ£Á–6è?F‚ÌìÿÍÜ›Yv\w~¿Ì¼÷mµvUuW/èºhìè@  ’%j£(É3ž°ÃŽ�ãñÈ3a‡[cû³ÃáŽÛšÑ�%ѤÀMÅ;@ľ ôŽ^ª«k¯Wõî½™þp2óæ}] 9ã ‡oGõÛî’{žó?çü�Ó8U»8´7<‘Њù©^³d8á» ¢l¥½ªäCÊ>ÖÑ«‚1ÈG�øyØòc33šª,°¶lÂç5Ô!”‰PÊz 6b.ÅP;Ñ•×Ä€"iCÄ’£°‚K ÑZœýdL+Ú-K»eãØkµ,y^‘e¥Dý‰0F¡Œosekÿt1Œ-@þôÑg[aŒ©QÀ �“þ%òüÇõˆª×ö_ýøERÇ/:w«ßÙoê—üþ‹î7 lüòzÖc²v‘L·FYB '�O³É�7ø¿¾¡†Jæõ–hðS*@�2åFY,L4ïž*ë Uß! A&U„jè-(QÁÃ1Xö›gø“\\KÓ7þ™u Ä·¶þ.".õnî[q¨‰BöP‹Õ•L Èe]ç†/e‘�%ö\C˜'–-þMð8D$ÏWuÕ†ïtÙÀ 2J|f¢Ü„6q[ bpEì¬èI 1pPò”J¾¼a! 7�î±ÔYè:1†³É­üV¸`š¤ÎñúF÷¤ï²à:רgãråÏiÜ J“ÉÐs±}ê1Ù<Ò-Ê÷jRžT£j,ÇfsvÅ÷¾m¶²-5æuyå×ó5|êû5JÑékRäp�«ë_ ’2¦c4Y¨”Q>Z@£Z*1 @VVäeEQJ2'ë&ó!>Ñ‘ö¨’Sƒ!ó†�ÜBá4¥³˜ÀÄh…0t¨˜dIê«0Ñ:�gD�€eÇ—t¸¯X:&|¤ó&ÎÛ„Ÿ~+£@ø>¾zÁ¾ðkcAm�°Þä[Í®îÍFÿÖ] �Y„Þº^Î…ò mÜÃ{ÚGí©ÿK6"âÌzŸÍÊÆÈ�ó›¼0¿Èçwï SŠÃ##tµ¦o-+ë,¯ôÚ-ÁT/¡hheƒ¢ä\Ypte�÷–W¹{ûÓíFk6ªŠ�ª¢tŽŽÑÜ41Æh+çÔZŸ¹Í·n�ß!F€Â9 újµ¹»7ÂoïšeÔ~Z-`”bà,Ö6ùäÌ6úÖRwær+7Þ| o¿õ&EQ°¶¶†µ–N§ÃìÎ�Œ�OpâÄq>:}šû|ˆn·ËøüƒøŒíÛ�FªäÿæÛZ&¬ªŠ‰ñqNŸ:ÉÈÈ·ßñI.^œ ÝépúÔI677Ùµ{###<ýÔ,.,pûŸd÷ž=<÷ôÓ\¼8ÇôÌ ‡�ÜÚì¯æÓ/S‹’Òøs›¿ ·o<ßÜ»çz—çè÷×yúé§iyõá[o㊽{ùη¾ ˆl–ç´;6ú}ʲäG?øËËËLψQõ¥Ÿ¿À•Wígï¾}<óÔ“¹íöH'´²¶÷âËŽ 8ù£×ëEj­5sÎóõ¿þ*Y–qó-‡¹pþ|L„üàC³¹¹ÉsÏ<ÏyÒC+E·c0J¼ªTOô@3oIˆZ*Çúæ€ü\èÁ&''yñÅãç«vl“d–™§-Ò 8O§âòTÊú¾¶1pQ+Á²ZÞ’÷ÖjªJa‘<Î:O諸|¼•0Ò:„ç\'óå¯ѺZv”Ÿ�o^éÔÝGö [9**ŠMOM£*_Gù3Þ‰Ö)ÉiV•bÜŽÀ!~|;ë£o}òZm ¹B�«R楪œxîºÀ‡ï£*Œ7 …3ƒÏ-¡i· yf"ï>�0&•©½¼ê„ ÔK^·óŠv¤'MeYë|¾§zègFÊoåQhY¥ˆN| dóðFíÈs…19Êç@0)Tå"²µµ7«öÞý­Üƒ¯-CÞÊÄÈá¶Ú#h€¼÷´1!Ò\a¼ó˜6xj.1fù�ÈšâP‘¹œœoY.tR5ÕRÝ–ž˜ƒ`ÄhDö(÷ÊI´dfjýÍø|!_Y Ä ŽAU%QÁe ¥VT�!Ay )íb[©_°2÷”ä8È�̃h«Jô]å{Fùˆ«,ZbtÊr‰È7¥ ¶Ry[ZÊ*‘©U Æãˤý¸Ì�#ÏÆÈ¶ØJSeu„€­$r òƒÒA¡pJû¨WËÿ!Åïuo4pÞˆw’°¤«—Ý1Š'Îóz¿Œ8¸ª™0"DᇴV5¿PJ )#-£içBãSê [£>WŠò Ø+??üØÌ|Î Æ 7 XåB‹¡001�Å&Ó$W€Ž†�I”e’\8σñFæ…2 �)op8­<•³-Ñ›.äg kYl5ÿ|ç_‡%åH�.ÂÉɵ °§‚’œ&QÆÚJ‚hôîÿë£)�^Wò‹Ÿ6,õüÛ=ùãê˜,GñI—GbFt8¹KXÑd¿mü¥Îq•ª£µd‘ Ð(]ÀT\R¦¤kDŸ‘÷é…i5ã‡TR °™œ3 0%F…øƒ«&võbÝS[”a¨ác{z+pŸG/€$ø†ÜJȪtxc“Õ$·g|ÿìZZóÀ¬€ZO.^d¹(90Ú£mdM˜ÎsÎyPgBç·gwðÆÂ›•åΙmäZó“¹KÌm¸arœƒ£=Þ^Z¡pŽõ²Â:GÏf:-Ƴœ3ëœÛØà¶©IÚFqj­Ï‰µuŽ�p÷ö)ޝ®s¶¿Áâ`ÀÕc#üÖô4“þìÒE΋+Ë|å{�ñÛ‰vKÚPk…¶2œ®Õë÷t c¾ŸÃž)ÛâT¬xãÍsæÌ[Ò&ã7F'¸vt„åÍ‚«F{dJqiPðÖâ2J)Ø1Í ˆB#™aÒSm8çÈ´â‰s™n·é—%“-‰–¸abŒÒ9ÞóF„ýc#\3:ÂÎ^À•eiPàÊŠÿdÛ ß[_á§««Xkyã�ãœc—§¥I%¨4Ò•øÎû‚apF³«×á†{KEÁ«ëö�Ìûg½‘`G§Mé$Ò`w¯ËRM1c2î�F€W–ê•Ù�g¥bG§Å¹~r}»ÅÅÍ@\¯šÞ>Ö9šßÈ\ýãmÓü󅋬XËÜù÷9úÎ\sýghÊ'µüí@° IDATA'HäO�µ˜Ù±Ÿógßeyy™gž~Š…ù‹üî—ÿ z‚//-Ñ__gtT’äÞ}ï}t:677¸87Ç-Øž»pž§žxœ{ï€�;wqç�wqôý÷˜Ÿ;ÆÈè {x�Ë…W_úK>¿ÀÄä$k«« Š=F¸úškÈóŒ�»vóÚ«¯011Áƒ=Ìä¶)¾ùØ× üúoþ6###<öÕ¯°±±ÁÞ+¯äÂ… ‘Šftt†N'”›2žŠÿ7]c Ë+Ë|òÎ;Ù½ç ¾õõǘšžâ‘Ï=J–e|÷;ßàÞO?À®Ý»ùÚWþç«++à`ÏW0?‘^·ÇÆF3±w¤YŠ2 [±Xò֯Ϳ ¥¢Öš½»qôØ+œyâ8§O�¤Óé22:ÂâÂOþøGc¸ÿ3qüÃ9q\úãÈ­·Ñëõøñ%!p¿¿Îêê*Æ.œ?Ç‘[oåùçžÃÚŠÕµeÆzãIÛɲþãÄñcŒOLðè~ƒo>ö×8ç(Š‚=Wì¥ßïsþ¼ôÛk¯¾BQh­éõF8îçÏ�#Ïs¶y:9©7´r Æä¯^²Â ¯¼§tYT8 +ë%ùÔˬ¬Ë\Ý»wo¼ßØØ³;wEê$€Ó!zÂ[®Ø»�ñ/þ·Ø7í�!Ó�gukŸEšAQ · É„¥ÓE&Rd,Ó‰Îå<Ф0‰pôåeÝ0žµèd ¥|b`›Ê›²Ø ç‡{ô'P:ä2Ó5­6`mIé,Ö*ŠB×ê&ŒB‘S*Wát­é"C*xÇç0ºÀ˜ c22“{@PSâ(q8ãpÆzùK ’ظ´sÿ×ÊŠÆ P(o¢:)¼ÿ¶Â–P¹PW12Y[!ZŸì ÆxŠL¥ÑÆ`žz/G"I��·=EP�¯Í 6¯‡É o)ÚÖÅ„“W]96ÊŠÁfÁ`PQ–µ­ò ¨RÑË_8õµpØgâ /Qµ—)ª²¢*+…b<­‹1 “´Iú0æ�¨#»£Êãu…ô�NŒ2JùõJIòÎZ—•·ÑéGi”ŠzBqòcyƒƒÑñ³Èä6…V‹LRYqT z½Ð�+=uW)sÐÖú Bú:óû¥ÃGhaåH™*ãÄG„ø±&cA uÖª†ÇFg?×üWÚ’™’L œ)ó}ásˆ‡’—õ*‰R.K ]XôÀRVÊÿùÜ®nj§T­¯K“’“omÆ ’–ïg¿7EÂj],ª6b𨷠}›²>×@%‘TBg¬Î'‰Ï2×ð ‡Ê1íÇh grÞÀ%8„OK0˜UEâç¢ÆQ–arŸ”>Éè]m3`Œ%Ë+�࣭´‰‰4‚Îë3š‹P®½ž¢Œ  óÝ0Ò<Üæ–�¬¼1PGNÔkøn«þKŸµµŒ°õóÿ]�Ùüý ¿[&’²a¿ ­Æx€²£ï¹ÿ G| Ëw²6ZÒÿÞ€w©çM8¹aÓ«ŸÁ ‚·yØ ¯ZTâ] >ªá1ghòe£0a5o¼HdAÚzñ—Ô° &DĤÁ©å¿kV0yVòàxë-„_·å/r�oÝØ¨*‚•qæ¤<$uHW¹Ðk~SK\jãuÃjÅpSÊYþf*e©”�ÔÙ碑¡=Î!éÀzŒ¨¡6 ·‹ýâë €ñ—T~¨ùrx+´ô«�ž³�þ¯«êƒD’q:܆aï�ŸÃìÙªc†¦§fÖÃÆèŸ®al8Ř]ãfÍ[_¦£xa9<$xZ†>�²D£¼Ô«�ƒ‹Ó¾z�¨¯ºî.mG5|Ïú7Wó…Åò5NI’x�±N#TBVAK£+‡(Z…Æ•%¶T 0Úb�­ÉQ�/�óÉžü}œ$uÊ•¡P–RY%d:'×Î'Ÿ‚M]¡  VIÀ3Þ8 ­ò‚B± Jø ”äW�jÆ`¹ÐœIç×Àw3"`Ø(P#|ŸÇ{ºÈ‘Y 8Éu±¶ZŸj¯™hLŠëJ½ñ¯ jèópäB ¸¤ÿ]:"å>É"ÓȇP/ áÞéš Î͹Ӹ¨q}sÍ:BÛ–ɤ\Îi-Á—Bú²N´åü>Xo¸ijÈ]P ‡¡x*\ ¨VÕÓÏ…0qDmvñæ¡>³Šƒà5rD8KŒ÷lðêB8/�+ ›eÁ‚§[ùto”ÛGGã©sýMò^‡Žàvv›”½ÌpÃäÎ9Þ_YãàØcÿh½ÏÏúë¾OvO�³mt„àpì´ò¿ç&vb¸,wE2®# pØ£)?Ì»À«jqÜ~èJžyCø’¿»°À=ããb´°–ÂZº>AÓÝ3Û0JömXËl·ÃlW<¥_]Xâ¶©IF¼qä¥K‹ìáα±hxëøG9=ÉhžóÃssXëøÌ®í´´ægçØ¨*¶wÚììö8³.ÞÕ=c¸´9 ›ö�öØÙíðêÂ2‹ƒwOoãÐÄÿôØ1抂ÅåE¾ýø7ù͇¿ŒÖ¹WH]LQq#œ³2Ɖë^ˆoFåçÝk¯ÿ€³gßEôF¹ºÛåvïäÇg/Я,çÔ&wÍlC)ÅÙþÊ9Þ[Y£²–ÝÝ•sœX[çmÙrÃÄﮬ²R–¬–%¿¶g–w¼„[¿´õø:·¾ÁGë}:Þ�risÀë‹ÒïwÍlãš±QFõ~´,žÇo½õ$½î8“»³Vf«ì'é>¥o(q¸¢âÕKKt�aW·Ã±Õ5ÖË>J)>»k;¯.,Eð¾cŒOô)Ç…�M¦Û2N»Jó‡c“´üóf»–E¤ ÚÓí µŠtDÎ96«æªšÂ9áèÃFBu”•uüñôvþ§¹óTÀ±£Ï15s%3;�)½\ËD— K ÇŽ�×rþ¬�Ï?÷òOþ)ƘHtßý’lX)“ ¿òÒ‹¼ýÖ›üî—ÿ€V«ÅØØ8Ó3Ûi·Úlnnð‰;îàÿú×ÿ'ós²oÿ'CM¹LéØb¿²¶bñ’U>Ìý|†V»ÍÂ¥¾û7ßæÈ­·qÿƒñÁûïóÆk¯Òévù�/}™Á`@Q(%\ë§N�䯛na½¿Î®]»ùWÿòÏbÌÌìßLOÖ?_Æáe~llŒV«Å�wÝͱ?duu…²*¹ç¾ûY_[óô@Š�þ:/¿øsßzÅ`€Òšo}ã1¶MMñ»_þNŸ<ÉÒÒÒÐÓ]¤¼¨¿lÊ�qo ïƒ.äñØÅÃû³|žÚ¶›îÙ£ô7Vùú׿Οüçÿ„3§OᜣÓéò¹G¿Àw¾õM––#mSQ â=ßxíUƒ“““LMÏpêä .œ?�Öšƒ×\ÃퟸƒçŸJ åÕo Q6ÜÖT1ðÂO‚s–v»�É2¾÷Ýïàœãêk1:6Æ+/‰çýŽÙ�<øÐÃ|õ¯þk-eY6¨�PÂ- ”ª›Ðiñ¦v¢È8g)«’W><Ë3ocuc€Öš‡zˆ�;w1Èš°¼¼Ì²ß—FÇÆX]Yñ‘�0¹mk««[&nµÛœ:uš¥¥E®Þ¹�]ï`#ûZ«š7ÜËyƛڊ· 2*F „(ØÔ€o­8ĦŽû¸KŒ€ó‘´Æù=¡´M"€ee :‚Jô’(�*¯Pxù[¬+Q8 lôŽ€.Fä”pI%\ëJ5=‹åv¨Í ”–º­ÌET&Ôz…B¨`r¹®B"2íÄë7CÀ¿L{PÑÊÄ(�™`°Ǩ�o¼çy%^õÊ£×J9ÚsœÔ/æûQ> [+lâä¨è�A�;@E¹\ÇuIÀU8 ÎiÀ�9…© +J64Þ@T¢¯ô*ô‘òF‘\ÑÎ%j Ϩ—½Ó»å;Ce…�üˆI|d™¡ÕÊ|þ„çûR)P–ht¶:Õ›¨ (F{Zœš°"˽/« ˆ’˘ 9ÜÕ�Ñ`2En´§’Ä´a±¶ÞX"¬Nda [½üõ©œê¾wÚ©¥ ´Oœ,µKó…(-}f­¢(e¡¢‡ðÖ¯õ>2Ä('‘NÊ&†’Ð&žBË)O)¤)JÇ 50èÌRƒÒ‹”õ´:¢1‰Ã�òH¦v!°Ñ%ÿ«dÍŽß$¯.îE!ODð¼vamP>b%þu¹š&J\•+=U¿Ðû(E4â•òDîvñ÷®Aok-ÖŠƒ¢Eã Tž>¨pÂÉi£K–eämC«­}$�‰F¬<—y#eq˜Ìb2Ä@fü"e*“¸豆ǀ‚d^Sã@0ÐhÑš®iØ(þµ+P0:x<¥Ñ_±ËÂÌI¿hôååú¾×£·F.?u‹ãò½]mýÃðç_á‘;Ô£ò—\'xxQQtŠ4?[ÿ…nÕµ«ü:ÆbdЪ~Æ ë‰ ï£�Y_PŸG"¢ð^“¿` |@túᨿ致Ë*�Ž•œ3<轃‡{ŒvQ%cE�ݲ#c}ëûºt‘Lÿü‰qÉ u‹Åó�˜Ö}«á,aN—9•"Ü8©ÿ0b6ôŒ­h6œ·¤ÖÚ™Ÿ÷^I�ð`|Ž¿Ð†M=\ê.«w]>׬ )ø(ÖÌŒZ�ðD€ªÎ”éûÏozá_;®nžtL¤Ï¸¼Å‡Œ8ÃTú�¯C\Ø’;…ظ.D>Ô×6CåÓÒ¨äÿ¡#ΪY¥æ)¤‚p£.5B%!iÉøŠT4éÆ:”y$Ý‚/»wœ`ÍsMDý³ßB„‚&nV¦¥ í# ÍæÀ‘mZñ|±âýâ¼gsH,•)ßïJ<’*ãȵ„X·¬¢4-´r ¿Í6 ´.)*(*‚í§„÷Ñ)ñ0~È-8�(fÑo!û±¯Ò“ÒvK6Å�–%¿¹d¼„÷uò&[ÒC{N%m?4@jÅ€&€¯¼Jq™µ–ø}¬‹xð¯•1ÙRz"[áwùh�.8�e«r_¶Ê�îRcÙ�@±%à�î#!Ò�ht _¡ìµé¢À;Õ4ø]c¸ÞP5c{ØšBH6kÒê\Ìr$+Üжæj>~ߥگ±²ÜúU~h]¨áV¢¢ô³÷OÄû–FÑIòZ*��ªb³²LøÈ€µ²â…ù…èÙ®”¢¥uö�ôøŸ½÷$Àço»ŽššÜy¾dï9ãCŠ%7mYâb½A#‚ ý¸H© �Þq3Ͼq¼°ºÊü`Àdžsë”$<º²†RppTêylu�W×xh§$#nÍd+�[6Àý³3âPaê//,.a1q~@ÉoSäÞ¨°â=� kiÍ}³ÓŒd®¬±QYnÞ&àÔ+ KœZësxj‚}½.'×ûÌoèÃLž“+Å'z#™ga0`~³àžíS ¬ãâÆ&O-]äÐø(÷î˜âèÊï,¯2’e|fç ýªê$dm½¸9àÐø+EÉX–ñô…yf;m>»{+Eɳs—0Jñèî8?™»„C8ð÷µÛü7»vó?žýˆù¢àâÂOÿüq¼ëó"ïè ”Ö ‘C¡B^ ç$ó{“x†µÐñî»ÏpÖÂ÷÷F¹µÝåºÑ1ÞY\fO¯Çüæ€míœïŸ�£­·OO²^U¼½(üù×OŒqõØ?:'*›Ö²VV´üoåS­œÛ¦'ùÑÙ¹(²Þ²m‚—æ#�αÕu6¬åîv;�/-amÅ+¯üŸºë÷ètÇk¹1åTø ƒdmɵbg·-´V~ía~‘բĸõæäšôF³Œ]½ŽD è¥8Ði3šÞË?5 œIè‚2%> Þ“xW·ÍÙ$r`$ÏøqŽ�3 „£*-ÿÑôvþ÷yiû·^û[î}ð�Ñ:#®ÅANJE©-„ ³× µÁÚŠŸüäyºÝ.ßÿ»¿å–ÃG"…Pod„�„2膛næÊ«öcŒá�×^e×î=<ð™‡ø›o~��»v322ÂÚÚ ó§(«£3‚Ýp9EÙ¯i—ÏPU###Üu×]”eÁìÎ�Ì_œÃ9ÇÊÊ ËKKÌlßÎ�ƒW³cv–W^z‘ù‹yø³Ÿ§7ÒãÅ^àÄñc\wý Üö‰;ØØØàñÇë03sUÒ²ßú–ú…íïœxi}ÿ=´Ö¹ív¦§§ùη¿ÉÊò2÷Ýÿ{®ØË×¾ò—EÁÎ]»ùÌÃ�ðÒ‹?—þ«*úëë(­iå­Ëî�bß…¯S1:î�µG|£ë>OäMß¶8Çìö+9~êMy饹bÏÏ�_ðío|�µµU¶ïØÀ ?ý ·>ÂôÌ �ûÄÒcããÜtó-|ôÑŠ¢ÀZËk¯¼Â‘[kz¤ÕõåÚãU ‘”­þº,K>uϽœ8~Œ?ƒóßýçÎ�ã�×^�í–áËK‹|û›_G)Å{÷±º²Ìʹúþˆ÷®QÊs‘{ÑÙSé-®npaq‰>:Ï»]`=1ÖÝsϽ8p€Á`“,˸åÈ­‘: `ddD"@ü±¸P'">º–ö§ÿ]}ïk÷�€,ñ ×J{nz°Öx9ÊJ> gã_ ¿PžNðù„ètÖ&ê©B)“¨Š¶–ÏDqò{°þ•~:ëe!‘ÇxÊ!ç|ކ@�¤„î(ß^× ¹"xÔ/ºh€PQ¾ÑÔ˧>w°\ëBœÅ(G+Ëé¶„ͳŒÂ(ÊL‘iK¦-Eeéåe%¿€†Üh:mCž›˜xVøæ+¯Î‰æ ¯ù�›ÀM¥4F¡© âµRHt†ö|çP÷ví”ÊyO|oí¨£C‡”Aàðz’Rȵ7<Ô†]yÀç“ôŠq`0�oçûÛ(ng>‡œ"€ÞZXt€R{èQ)2m<8ÆGh#t6ÖÙ(ÿªÌà´¡*®ò‰¤½¡K›ð{–ý¥†­¼Pî×íB.y¡‚Ìa<§»1B÷’ç:F4(*puníõN>˜^œÕVå±3KбlÄ9êå)Õ=e~f:²@«¥Ç<Ñc»¿ƒÖÚÓY+‘ó¹£!rÀzH no$R£†Êt¤ “6‘ ¡ý¬s”¥¡U(Tn0-Å`P0”lf%›ƒR÷*#å4•Sh'T;¡âÎ;ð�´>TÔ«¯alSC ¸#ùByÊ3cÄ §}ž�ð'Q[¥Ï™`±Zò¥Ä@‚%óï%:ÄøùèÔ‚a´òF<(+¡ïŠýæ¶R'ñ=YKò‹tz�nN«�Óje>B@æ�ñ‘T(…2bÐèTŽ`jF5pûÔ}O§m¿ ²F 6”É9é¹2ßeU IÏÃ?LÕ<’]w¨g·:‚$1¤×ìñ‹å¥ÿjèµþ¾Ñ¤®‡õoK°ªÆ”ö½ðœà»6âˆßȼÑ>úE¥Åð†Ã‘…_c�¼r޲1/°Jâ‚"ÁÇ0;ÓþtCßÅg$Ýí¯Aj€-Û3œ&ë…VŒ•·¡ÏW΃p[ ²dñ>ÁOÖ5€¼æ‰®~­ñl–/TÚxµ$U5Ñ0ÓÉ™”&!X«�ékAÂRËe÷Œ÷M7(¿¡^¦Ù Ï߸(yÁC%O ÜÎRj[‹²J„0ë|�Jðöõ|°„z7º)ìò„½th‡ê�æîA#åcXÓÊÕç…_Æ¥ï¯ØÀÐܹB»Ö/qh4Œ+AÜâ¸l(º¡WÄ:ëÒ¬Z(F\ÿ»dѹl\‡_’ú'ý=¯£$í¬*3f�;TË@a¡­É7,yVI8¬ѱBD'Mæ-ûZkIp•IÔue ²†*kQä�嵌RèÂAa©œŽwsÊ'Vb¨üã”�Ö>T@â BÐ Ï}?x‚Õè',‘u jO÷¤¥�kü¥Êî˜ÎËÐôMOÿd„u·qǸ´úºÕï£A Ž�acÉû´u†ûfù›unœ ˜Œ¯°†4›$®[*™cQÈg‹öL /¡N*)ƒÅ õq½œ4 CÃ5sÑÀöGç¹þ‚§Wù�W(pqÞ)¢ØQ—ú<‰eÆY…Óâ¹ToQiçú$l×¾í^ùàt<å¸�Zë3ÑÊÏÅ' °Ž k™ðç�d†ûvL0°"_5Ú‹×jí¯¯¯ÇnùÌ-×zÀoSm±Æó×zã@íq_7¤óó±6ÞÔ^‡.öU˜›¾™½BÕÊrÆz]–×û ¬å's Ü<9ƾ)ëXž5¼îí±§×ÁgûÌvÚ\?!ô$/Ì/0Ój±ßK&´¡­5›ÖÒßܤ¬¼у�ÖáȽ‡è³ý5þ±‚œ�cª•s×v¡”8Óß`³²Ü0)Ïší´©¬cª•s¦¿ÁD–qÏö)Æ[9/m¬óG“Ó|açv2­yâÜEVÊ’±Ì0Ûíp®¿{}­¬˜håìîvØÙmóæÒ +>¹p[k^YXâÂÆ&×��rÓä8ï.¯Fj™C㣠Œ&SŠév‹•²ââÆ&G¦&qαQY¾{æ<ÇFøï÷íãO>üP(x޽Ůí{¸æÀÍ(ëó@„yâ… åÇ8��þ«l�çåäÉ×8vüEð…‘q®éqï¶I>\]çÌzŸ¶Ö|v÷Ž®¬Iyœ£-¨]ï;R”<~î"SíÓmÉ¡ðÊÂm­ùôŽi‹’×<ÝÐd.àúéµ>áÍ?µÖÇxÐÜ(Íß�9�uBåpÑÛ~O¯Ë±}Š�Þí÷¼ñæ�¹ãŽßŽ€ É­G·¬YVœRŒÃFeyÎÓ];>ÊRQFîÿCã£t�æÕñ v„H$h9øµÑqög-•5Mkæ= Ø5†©vKhÁüqÕh�£Þ pa£)°VÔ€†QŠ*Y›ÛFÇ|ÃÇ„SÜÖá¥õ5úëK|ðÞ3J)…’õ²!5E«Õezæ*æ.|ÀÚê*/½øsî¼ëS<òÙÏÓíõX[]åÒÂ%”¤®§Nžà'Ï=˯ýúÙ65Åêê*¯¿ö*yÞŠÜ󇮻ž,˸ýwðÔ“O`mÉÂÅLï8X,•M}ÏàÚ9Ç¥‹Ç¥M»]² �±…,T_uÙÆŽ-/þøÛýò/ÿíž|E£�‚,ÒÔ!’Ëšê¾×u”€ßje xcŸ VþÙ’{kí�ºj¼#Þ_ Æ”…§ÆçFN7k€W¢y•T|¨¦i«]Vs×l‘ˆ¤©_pMr®R�ý \ýLë/ÖÉo¡5’º»Øxq:ÕÏ 7�ÔAiKÖ@LÄÔ¬oL ¿)< c©5ìá ‡/ú=⌖ IDATÁ]ú¿«§`ªgDEöã5µËFf=•“k‡•—-Žf)/º`€4J(c*™�¼Wølï5Q! ¡%Æ$ uS£|aÃIë³Õ¸kTôòÅ(v}ø}Ø@.¹Ì(0T0‹ç e�ÌÈzÎÔá?~c Æ=Ü¢CG8gõMŠ�¹ »l~ ‡W§íãAt]ÏýP×°IGfió›˜É=¯d^’CQ…Ä\þ™þôLK”@nD¨#ÓØ\a3%† .kSd"iù"‚@IåJ°Z¸Þÿ¨"††£jn6ÏÁG0Ö†µ0î®QϺÝê–JAýa¥ºA¯ñ· P…Èç‰mâЉ��> MúÅ9ݘÃõæúVÅs’õ8Y'ê5/Þ9¹ŸªËäç^}­KÎú˜µ »/ÿm+Á!ÿC Q¬ÍVkÖe��Jå÷¬4b VD=�çêkš‡å½(‰B�ÄËÊ&Í“�êÚ4lÍ~Î8+½]Eã{PŽäyÑ àÚs¥!†�iºÈ‚¬ª�'ÎÏÇó®ï `¾w¤¿³€>–g8à�¥®Ÿ‹´o/­²»×‰t8£yF®¯­­Å¤¤3£(ô Gé,¥µâ}cmäM�í×¾:ZÀÚ:‹œÆ¢´i ˆù8\³g–ß?ŽNhË£½.keEá,³ID¼8(xmq™»g¶ÑÒš�µ¼¹¸B{J3íëu`t$*§ üë;ÞZ_Çœ9Ç�])}Œ„Ê+W¤ÞŽëÆGQp^Ü53Eé,7¼¹¸Ì�“ãÜ>=Éùþ/Í/2ÕnqÏö)° C+“q4¨,WŽöX* zYÆë‹ËìéuÙ7Ò£p–ÇÏÍ¡•âs»wà€—/�Ç!‘m£Í3æ7Œç9gÖûŒç‡ÆGÙÑióô…y*ëøìî¥øáÙ9úUÅámãìéñÚÂ2¥sôËŠ›ÇGù‡»vñ¿|ôÏ¿ü»w]E§ÝÃxNc‡DaU.•€dU¨œ”)4ïòòÞ~çI@胮mµÙ›·èÍL§ÅGý Ú™æ�Åe kÙÛëÒÑšæ)¬åªÑ׌�ðüÜ«eÉzUñèî¼¶¸ÌrQ2pbè”c(¬åäzŸw—Wée†=½.g×7xwy…D‰[Yã¤Ó»FÓÉL4 ,¼4¿ÈMoçŸ�=ÃrU1é §N½ÎUWBdX=Å¡6ôgIÄ€sŽvÎðì…K‘ \%W[]Cð1ÅhfX.J>Xð~[+çêv‡ÊƒõWŽ�PT§==Ô¦­bd@8‚Q e4•uøïC®ˉa mtLF |¬Qd~atœWÖ×°À‰ÆþƒŸ"oÕëKCŽŒï›2—B±s×uÌ]ø€—_z‘+®¸‚=W·úÉÇùàèûìÝ»€ññ n¼ù‰ è÷ét:|é÷ÿ�<Ïyû­7±ÖrãM7pç�wñÔ“OB'4íéŽjç�”¨Y×ù¹ØØØà3=™ӧyïÝwXXXà‘Ï]EžçŒ��Óî´Y[[åâÜwßûi66úTUÉ7û‡®½Ž/ÿáßãÂ…ó¼ñÚ«|xüx¼ÿÌÌUÍ=4Ðqº­¶8YkzMYULMO3=³�óçÎræôiîºû.]âùgŸaûö|ñ·~‡—~þgΈ‘ø·¿ôe6úB_Öæ“cH“iÒïÊ …KÜöb[×× vÎøØKË9}ú4àܹ³ô7úÑØð³Ÿ>ÏF¿Ïää$»vï‰É'·mãs�~�ÿðûÑh°wß>¬µ\šŸgue•]»vsêÔIÅ&WSü„¤£4Û¹( žyê ®»þŽwß~€ýpË‘#<öÕÿ[ /ƒ�/¢¨­øÞw¿CUUlß>[ß³¬øðìÅ_ڦƮ¼òJî¼ë.ÆÇÄ€|þÜ9”R¼ú޾ÿ•7r_}Í!Nœ8N‘Ìóª×ˆF�N§Kåàë�ýµü)ßFÚÓ㨙é£Z5X FŒ5¨œè<‰Š\ÞÈôí“g*2ÏÙ¯�Fíwù ·Ý-Uº}½Bâç “¹zjOg¢V¬«"½�µxÚFûœd Ä';��VK¢�Óà4Ö)L%ŽA§pÚÓ…)­ôpm�Q¢$2ÿªµ%hÛ‚<†FÚ 1©,Çä­Úà£Ä Z”’0·²2~•(@¢N{crÔ•UŠD9¼§V“½>uj%º…Djk¿¾4¿Ò>ÖJ‹™K{#ˆ£™ÖØWZ¨t´RÁßÑÓ Õ†YF5Ö �µšÜ(™ÁZŸ�ZAËY*ÿç”#k²vN§“ÑnZ-MÞ’È•©Ø�¨àdãˆÖÎ@ƒ |2øY÷çÚµ3ݱ‡•Ñô/Ü£J~¾F'çéÆõÃ8¯z4µü­Ž_®ïÿ›?ñW=þ]?{‹"4°�á'ã[ýB½öù÷a]×0¤�| $"œë< �•ùš¥îµdØe)p) &ÆtƒQ™‡j´'­P ö 5Œú<|¤+øå¸Ml̨L~tÉ.”k¸õsŸ‘ ECG*Í�gÁº+çyÁ=€EñôpÎÐÄñõž@¦Ñ5¨¿F)]Ú‚n¨4\ö©ÌãÍ*G {¸Ye%}3´X§Ç–}ܼqÔ&“AHFÜ[\³ ý~Šî É:Ö|fðÎý³\Òh±»Tòç†~“B˽ƒÒ®ò£FâêöˆÏð÷MÂôÿhHʽ@í˘šÓüióªÐÈá™ñK©S´"‡¥ß%Á0¡B�Òº6�h¹¿Ò§­'st±K•BŒº^�B"—)tYË�gIäS‰à¡½‘'„3gFx[™!Ë *7¸–Âæ"['†�Ò‡y* ¨œ�Êá GMDŸN%ï‡[8™ùñzëœÈJŽØŸÖÚæìÛw«m!¬æ�ö̹À´èïM_R7�Ÿ#ÔTjÊߢö,®›Í:ñþ‰¨"•‘žRDLh[BÉ’õ¹^Šbo¹”YH<…¯jµ½÷¹ø¬”%§×úÑk^“žN(‡=ýMa-kc"â7}´ÀÁ�Û©‚Q××½À1Àb« W*!_—°æ)‘LD™wµ1À�/kCõ¥•C¿ÆÄlJqã•WðâûÇx}}­„‹þ\ƒ{}ÔÃXž±§×�ÀKkÙ%tBç761ÀŒ7"œZëóÎÒ ïÞÁ¡n—·|=ß;}š+wìŒí,Ë®ìI™OþzS»ÃGë}>1)Þ¯/^Zâ£õ>÷ÏÎ0žgœío°R” <À³­Õbÿh�]Ýs›,%íœ!ך7—9¾ºÎ'¦'Ù?:ÁÑ•5ޝ®³^VÜ9³�~%@o×6+Ëüæ€[¦&°Î±^–¼ti‘kÆFøµ=³œ^ïóò¥%ÚFóÙ]B!´8(ÐJQú(Ëí�6‹ƒ£yÎÛK+Lµs¦ÛŒç9?8{�pïØϬ¬0(6yöç?â‘û¾(É•(ê••uWF¨Ÿ³(¨*¬›ËrÀË/k+®ÉÛìj·Ø×ë2ÞÊøÁÙ9ZZóàì Kƒ‚/ öMcÌtÛ¼¿*c¹¨,svt[¬®”L·„nÈ:Ç�±ZJñ³‹B«q`¬Çþ‘~|N(ƒ*Glï0›^_\f½¬Ð ZÚð®ÏI0Óisp´é…–Š’?Ù³‡ÿá¤x3¿ûÞsìÙ}ˆv{į­©tV·AˆÇSç/Ò¯ªHÝr ììvØÙiǤʙRܹ}Š~t!Îø•Í‚U·c~~¥èÃZYF`ÿú‰1Þ^ª©FF³Œõ¢Œ†�~UÑb ×þ¢H�ÆùEɯOnã[‹ TÕ€ã>Ï¡ëªOÚrÔÐ(²ƒbv×u¼ñÚßâœã�·ßæÿ½¿¯¹þÆ›¸þÆ›(Ë’7ßx�C‡®å†o¢ øÆc_ãšC×rû’?`áÒ%–——¢aà“wÝï3ñÃ(k¥’u³é徺2ÇæÆ Zknºé&”Rl›šâ¦[³wï>žö››|þ ¿N–e|ë�±º²ÂwÞÅ¡k¯ãÅ~ÆÚÚZôÒãÚënàÏÿüÏã3¦§¯"Ýp‚~p¹§~X×ëò���3»c;Ÿyø³´Z-¾þ×_¥¿¾Î¶©)®¿áFÎ�; ˆgéùsçgÛÔÓÓ3üì'ϳ²¼Ä=÷}šV»ÍØøøeÏK½l›åpCçA” “k©¨uÉä>u´¬ç“ãÛYZ¾È[o½ÅþxÙSÝõ©{hw;<ùã�ç-vÌîä�·ßB(|–xæ©'é÷ûLLLb­åIOÑ´wß>¦§§Ù»woŒ<(Š Z>± ÿ»Z¶XZ^f»�8©ªŠ²ô‰»µæä‰ã}ÿ=Úí6{÷]É… çyýÕWxð¡GX\\ˆeÿE‡1¢MLL0==ö©m8p€‰ñqœsÌîÜÉÕ×âÙ§Ÿ’öNöºÐÿG߯qÏ”^kzf†ù‹bˆèt»ìÝ{%ÿõõ_Æk¿xçu\³g†¢,±a~;)<Œ2ž*C@³Ê*Êæ™óž±bÈs#†�V+Fú•e 8*[ ‡9|‡h‘�ýXÐDÇ¥ xJ:ç¬D\:‡C'ò¦Œ­ÊV(%À©' õ@ŸúÖ–ŠœÌx�ÙdäyF4[`Ó#oÚSôh/tY'ΠΪ˜ŒŸ(YÄsIšçŠVK¨�° g¡, eiljŠ\S”%U%õ3Z€ñV«i0ŠXwYðô5x0Úë^Vyîò«rɉ³Kˆ¼Äá#|Ñ!óRš P«XWRU ý¯KôJ'\镵 ùM[‰ÔPí< ªMä�ò6…<Óè�üW¸ïEü«s*$Ë(PFE¯táÊϼQÄiP‹îã@¡iç™n¡P;Ðiïñß<œðü‡¬ýo}Ô0]ó9ÃnªsõÐkýô�?÷W¸ÝVǯRœ_x×,n�GƒXêßoíh™èý®.JÐIµ QFø±tÕ TוÐ^n TÍÁXª¬w²u�©ª¾ €4Íð ç¹~ Ùä�8 @T3wx#“‹ƒ»¾­k<ⲚÔ&F´¨-ΕߔNž™L$i1êU§Q†¤uÃ�ö�½<]}nHWÉ¥þƒŠ_Ö‹VxÔäF‡A¨%,5`BzŸ(M×׺æóS�Ü…r„…1œ–Zˆkq BÖEŠ«©Â/®*.ÎñÁ‰wCr!2•UòêaãÛß(hÚâŒÅå×’MÄUµéyÔJ/Vò› Ùj\-Ü«°bZÿªC=|’”`J«w†FÕS.ië®ê�ð­d7î•Ô_Qʤã3¹uœnhŒÄu:]TÓ2zOŽØÎI¨nsPÑ8|™œï˸øÚ°øø1 [ÝÅrá:ñ¾¯ë�¬!$õJVHå0¥¥mÕz‰Seé(�¥¥­LÑÎ4íÜIÒ�L£s�ÊD°)±”*»É¦†›h·IÆ€\•´µ£4RF«]�ZÇWÍ*K¥ª:I“?W·Gð 8lÍ1cue-6eÜ›¾å uS`öÄ+J.ô¯ÊøD`**±Ñ�Œ�z´$kÏÐp$ôEÑ ¿¨t½"1¤ý6°0¯]Â%˜žžÖ1^ã§Q¦á1ZŸwùl®yC“UÃóaꆥ>zAÙºJŠd‹ë5ŸV%ÔÏï_µQ@†�‹«x$Uþ}ZgW¦~­5^a “Ó&s«†ªü’á>û°¦¥ãÊJ—.g(<Ç¥Wþwä9c�wÖcY�ýªŠ Q>X]£—|^)JÎõ7#ÎÛ mÁáƒWÒ÷D¡a«*”NQUJt'/;„¹[ÆÕ¿¹øÙE/¨¦mß+¾¸8î®Ø±#Îãý>…s\=6ÂÁÑ•:˜½#]ŽöpÎñƒ³sÜ89Æn_¯åAÁÀºhØÝëÐ6¢ìjÕÜÛs‹ ”¶Š£L©@G¥b´ß¸6¬ jÏÍ£=&òŒ‘Ìpz}ƒÝ½.{ºb øÑ¹9ºÆp·§úÁGذ–™v‹vK{{E®5—6ÌtZr£Lµr~>¿ÀFeyhçvŒRu÷½ìß¿ŸcÇŽÑ_[ ¿¶H¯7™¬.’ò²8À¥¹cXk¹áÆ›øÞw¿ÃèØ_ü­ßñ÷?IQ¬®®299ÉÞ½û8{ö#&&&yó�יݹ“©éi¶m›âýUœƒW_ÍEÚŽ�m§ÛʪÚ8ïåwW.®�é©E1`mu•n¼‰“'N0>>Î�~ð=vì˜å¾ÄV?úÁ÷xè‘Ï119Éc_ý ^å»vïibLÀ¹Æ³ðå±q_ 2”º\nUmˆ÷ ò‹,˜ÞZï5ÑÑžQ?úè#.œ¿Àì¬äxÿýw=h yž37w�'ÿÆn>|„S'Opæ´$†~ð¡Gè÷×ùÉsÏÆ¾ì÷ûìÝ·üwƒ�u¶�Hrz‡ÆipÖ2HŒÓSSìÚ½‡v»ÍûïIî“í;f¹ïþøú×$R`0pË‘#üôùçYZÃåGߣß߈´–?}þYþè�þˆv»ÃÞ}û8~ìC˜Ãw~Š�ΜŽeß¹s&3œ9-ÑΟ�A!ャïpÅÞ},..ļ“ŒŽ�Æk.yCÔèè3;vð§ú߯dÄw^·›¿ÿðõT•è2e)IH­·ÀPˆÎŒÆY ÖPÙJEo0Z8ñ3U�+pFaÚ”5½™Q’„ÖA‹×ÏÂHñ‰Q•¢òr�ÒBT¡=OY1Ø?Ž*k©\I¦JÐ6zñ¥Ph*Wy9C£‘ȹv0b´ ÁÃÛZTµªb~çlÌ_à\® #ÝSóˆ"Ë2Úí6­<£e4íLÑ͉ùJ]Rª‚MW0`@i$ï�~)Ód¹½ƒaÀ°c­P” �»"Ï-Y'5¦1Ž Î³.Ê ©žãåzÚI¾ãY—gJZ«²’`º„�WZQe>ú\k´òÑìVAªP\yæ ekg%ã ;�\ S%Î8”vd9˜–&Ï-&/Å8aª° ÆþÒÚ‘·´§OEÔyŠæ²p¨Bu¬ªÈu…Ò™r>as û k»ñQºAÇTÓ{úñ $ÂõåÖÐl€ª0yEfKr*% *(*MQ)6KÇf!Ž´ÎZoT‘¼’�ØA¿0?ôWÙµ÷¨¿ùÈ':šë›ò´X*P×ø™Aò}ä’,Û9¹·èl è–"kC«­È2‡1!/ˆ¬Ê m˜³íÀøüÿwïdÉq¥i~îqïM-+Kª u‚Њde7»9ÓrlÌfml^æaÍÖÖ¦§wŸvŸ×¶×öaÚÆ¦ÇÖlwšd“M²ÙM‚ €HhIU…Ò:3+õUîûpÜ=JîAîí­&yÒgÓÍÓ͆€#Îq²[%/½nß:V¥é‡<—¼¦(,eY-BAIvÏÿ¤_’�\ˆˆÕK@¦ÁyÑÌs:½û²œç/.ð™í³š•%Ç×6˜i5Ë2”RÜ1=Áhf(œD]çÛ`µ_pdu�ƒÓ“̵š8`&©ÿÒÚZm¾Jq•¬þ¼ÛëüËÝ;9³Ñæðê:wÏLríØóÝo-.qíØ7MŒÑ·–ÂGG×9n�š`£,p8^¾´ÈU£#Ü:1Æ¥n�×–˜hä<27C×ZÎÏKÛ÷­ÅÃL«IáÃFóÑÚ:ÆF˜i4˜hä<}îF! —•⇧Ïc�OÎL1ÙÈù äÛeÉT3g¦Ù`ÿè0®¬±Q–<87ÃPfxéâ"ÿjvÿçÅ ¼ñîKìÛ½“)tfjFBç$›-ýÀ.¯\âø‰·ÑÀ¾Fƒ¦ÑìnñÆÂ ʇ9?¿8�îš™dÇP‹œ ¬¡4·M�ÇäÀ8‰øÈ•檑aæ±<µºÌ¹^ë#Úpyc�í:çx|Ç6Þ¾¼iw†�‰†3€“ëmޝm0d4ãyÎR¿Ï[‹Ë(¥¸Û4çÛŽ­mðû“S¼¸ºJáÇO¼ÇÍ×ßÁøØT¤PZ -ØÒÑÊ*�\yyª€7//Ó+-#™aªÑàôF›Ë½¾àí·Þ Ûí211ÉØø¸§ê±{÷îxN¯×¡áç§,7†²º’Xs¥˜™™a÷ž½œ8~ ç«++¼ûÎÛ4›MºÝ.�F3Ò ]síuh­£áêk®å¶ƒŸàï¿óíx¿½ûöqæÌéhøàÐ{ô{=2¿…ÈŽ¡¡!®¾ö:Þ÷—±<>ò(¯½ü2�ާ4[ºL/Yw———X^ã„1†²`uç®Ý¬¬®ò?ÿÅ¿�ôC7î�âú“»0ZhxdŸ¢ òæXís~‰‡wžiÄ[Öp[8q° ¥Z‚_Mž)L®QY†Î�NÝ’¢o±âQ_&$-@RØßh-{í·†º(Q®$šF8¼{¶ OAï)â©îy¾�8#ˆ§¤Œ©–1•a 7ÞyCÑ/-E!Ñ*”8'懠Ï:Ÿ8T«À#î0J‘g͆¦‘gäY0 8á+§¤P} Õ%£OF_xÕB�” ¹ê½wr–ƒÖ–ÒGÚ(íPF‘5Ä0 Û\·ªYæÄ³¸ôýb#°…Ū2Fà[ XáRWô’ §2OÝè×+݈X„uÖG|¤*½Ú¨�[@ôz§…Ž«é1 ä™Â6¦ôNZ¡½1#ÏÀdÂFmÖZï�-.öÚs¹ç4råM |uÑ�­ e¹é{9¤)lIQÀ1€81Ù „«°&W²Uä”x7hØÕ~„6tFÃ(\YâÊ]$û\e¦èåJk2¥A …•² PÚb”´eprÔV^±qûn±” Eµ4Mh´&w˜¬Z#SD 1t•B}”iL&‰‡Òœ¶p(U€+°E�Õ…ÏËv�Jv Ê@f­ Æd²ÿ6Õ>&F¤„}¤ ¡ÂÁ ¢0® Ö’)hd�;hjèŠn©èŠ~é0=¿/*-…*q´/�ŠÑÂ<"úr®D6Irl‹u%Ö D%ý!†<÷o7•z‘‘©Œ<&˜ö‘Y0Èø,ËkûHL’•H–܈a`˜EÂB$Ú§ô¹J4b#˜P•«FpR‘æW˜F�ÎsTžA^àÃVˆ!5ƒcÜ&ƒ'öe ™2ðÑEÕ˜—œ50,þ!Š+~—´ß]䳪}®æiu^ú¬ôþ$ßUG9¥Õ®AámEbÁŠ�3Â3Ò£ÞZÿ­Çou§è�¾õÙ›µ=�²+ß»Î3àóÜ…Áñª CÖZÖÛ £Òåe[„ CdSRª¬L;¿ÑU¡ˆ PåѪè*eÏVÎçà@G÷Wkô�0\Êâá&âoaº“ª]eH<cmSD'D*h"�� 9ŽàäêÕ”r8DlÕsjsÖºy e¾:Q%ÏMo¦<ÀêBAHB[WÚ <3´bh¬¸ U«Ê¬ñ^mTN¸ìƒ8)²ª�5øÜ+®ö/ž¯ª÷�NI(é:CxÖ@¸ð|ÿÇídáÛÅ_Ú3F&„ÿ±Ü©4I;0˜Šžÿ¤ÂxpøEQW§¥eˆ•“F¯ÓÑ„ŸÆÇÇ —ôŽÒ6á‹�1ä‘X“Ièý_Ru(üäï=ЗÞÈǦïIæ˜JŒhŠÚÄÎ äNÐN‘õsš…—Z‹Ñ§ïȳ�¼Iž5Èò&Ë1&#p :/½¬å¹ß/è÷{ôz}zý’~ßRZÙÈHè°gÀiUy Ø¡ãT2•¼<ðåO)Ò6¬ rÁ è_ü<‹ „Ôæ¡úH)]ûÞ ž9nj½_ï‡P®dŒo%z"Ÿþ–ËQÖTŒ U+(ç6ßŎtücG �wŠÒ>Ö)Òúl.z½® «4š ?ý>ž—œ/çåI û©æK½ÖrßIG^Ë0þ�ÓñžÊË kƒ÷QDÞ+(´…¿G”VaXá=ë¨LzéŒ<´¡­’á ”D¹(â�ðžÑSÆp]£ÏÓJ±g8án›:‰¶§ý tCý‚_­¬ñÉñ²-��²dÁ{!…Ð÷œÂ1€çH~ÝàݤbФ†ü:Tï3›tH5O“ÙèÛvlhˆN¯Çù²@ç²á+�£e �íjˆë gYÌ•phy•Ån/Ò åFËšè*}#DK¬µ76ò¢:’Œyë¹6ô½G"ÀL#禉1¶·šœZoS8ÇçvŠgìk K\hwx`n†�C#|¸²Æ¥n�‘ývíÞé“'è´Û\^\djjšmÛæ˜Û¾�ý®æ×¿ú€µÕUžøâ—ɳŒ¿þë¿Odföª˜îßÄÿƒkðàÿ¢((Š‚†�jÊ Μ>ÍÄÄ${öîe÷î½<óôS¬®®òا‡©©)þþ»GY–\{Ýõ<ú©OóÂÏž«Ý³êÍŠ""DÀ¦žÎ&Rx`¨üBy½>¥bB<¹^ô¥2š��n›õuã““â b-í�6?úá?âœczf†¢ßç§Ïþ€;¼Ñˆ ˜wïÙË#�}Šo}ãoèv:ŒŒV†ok-Y&\óe Tu^ö²,ùõ¯>à½wÉØØ8®¹†½Ïá�RŠ?øçÄ;o½ cããd~�8wî,ËËK(¥£ÓéðÜ3RÖ[n½�••N�<Àu×ßÀÄį¿öj,_7¡xá§Ò?­V ­MŒHó„cûŽ�\ºx�뮿‘ï}ï»<ç)˜n?°�ÿå_ÞÏP£�#Ðá8Ið‹€À!- ¡FÖöÒÓ²(òsï}²[e$zØúñ`4rãu<ƒÖ%}m)T€2‚Ó€C¹¬Š>#Ê9Á °O»£ £iå(Cn% ±,KàzÊJŠã¢Pïþ,טÌatI oQÊë.ªâç7>RP¼¬Ψ¸¾kD'4"Fò åÆH’Ò0æ>|å²8/´OòŠ6B?‚+ž¾È(%^æÆÓ@*Ó ÷.$Þh¨ñQ= ‰|‰Ž$@&à§”r?íÚÊ&MÆ|¥X©ŽÈÚíl)FAüKÓM‚EÇ-¡ßÇ©Òë|rÎVío¼ÑÀ{L-å�ma‡XŸˆWúGhesßÖ!±KÀ…#óüÿ!Ÿ±†ÌZO±#tµÁ(#•òQ#á˰7ržâJ(e´çQ•¬UyJå¿HF?N"½¢¦j�î±eeÚ†UZæRf Ã�!4%‡�ñÆ$#û §}›zã’6>–ÆZ)·ñÞý>ÙYKéJÿ²`YžK>‚¦wòõø¾ÈgÚ×=¼*LÉ{ò{Ùÿ–EíNë?¡ýV)$ÓvÞ˜”;GÃ9OA)ó°´„Ìâ2nƒ“ª–œ‚yn$’ÉG—¥×³“½k + /Ž÷²ÏŒy2ã£|~†LÓÌ ­FF#×”…ÅZ¡ Ë£Ó¢&Ï•8Ä<™Z6‚Jɧ�ëç­Q`4*è†~èjß~�ÉÁd�I×ðt¨¤ØÚÉ|�ßÕvFµßT­%ª£ÊZ§ã\ªÓ¼�|VÉûô¹ æä>DzëÍ׸€FÔ{JÕî›Öîãµå'·å¯ÿ_<6·A=CÞ8”SƒͬҋCSø9/{t|>“:¦’m]B=‘&!ä5ZRÄ�D%R E·þoÐ @¹’UÊWR%ÿ}-Ó @ÿ°vIÅã®�Ä›Y%À®KJUHáÒxní×ô«ê:¹&½Ï•†²/h(k0 ¨äz—\ï¶ø;$yLèýtop7Ð<±]ƒÇ�_´¼ûúO^›ês¥c«6HKRõ±òÊŠ8á{0�K¿Äâ$*“¡ïü ÏuìÈØvõ^­§ÉoÁ(�ÊFmIIüƒ ¡> CŸlÕ^íó1Ò/L•NL5ðJï‹^Á°•UÖ[=0‹™äÔ£§|¸†ªÝc[ˈÊZ9Ú 'µ6™wJEfrY0äâÅv Ö¢ ç•3ñé÷ z½>ý^�~ÏRô¥5ƒðaZ«cnñ"/—W59�ÌËP|58$¶˜ža�­Æ_ØËo› ô0ÇjS>7.íÏ-'žï¢d‚ÌŠ^‘ß%ˆ²}ð·ê¤šèª—EÕ¾¬SÑm¾Oj,¨�DI-�Tƒ\»›ŠVþ«µ&÷Õ}¨ú&ŠäÍ�¨n¹ºa ¢ï9¹§«‰”a§‰tâ×àü—ªR‡ÂºQ›©šæþäÁ²ªôÎqfA€ÎËeÉ�Ì׋’‘Ì0⽘�¬®3ÓÌ™òÓr¯‡R*þ>–gÜêéƒ@xÏ—Ê2>{¨Ù _X,�M[Š›xÝT^’G9iSW™Ïb4„«z­&¶ÓvMŽÉÑQ.-/³n- ¶¤pާÎ^à˜€¸WZJÛ�†�ÇGéz�Ø…n�™–PÚ¼¶p™=ÃÃÌ%€n§×1?fêâWÊÝPŠ•^Ÿ&‡ùìÎmô­ãé³™jqpj<q •DÐ-#@õ�Ñ\ìtÙ9Üb8˘k5xñÒ"Ö9Ý>‹ž:w‘^iylû,™Ñœ+ .øîåEº—aFæòŒ™V“_¯¬‘)ÅCsÓ´ŒáµÅe.uºÜ9=Áîá!Þ]ZáôF‡žuÜ;;Å…Nç„Y+ –{}®Á(ÅR¯Ï«ó‹Ü81ÆÁéI.ø?Ή§ë{¿~›½{Tù!â°­"!ŠóOpiá4¹R<Øf[ž³ZäJ1Ól0šeœowxw©ÇM£¥8¾¶Áå^Ÿ†Ï�ðÞÒ }çXêõ¹sj‚óeÁÿzòÇ»uà{«ãR¿Ïœ¿Ä£ã|qfš=­*Ï@§,Yêqy/œãGg/R:ÇÞ‘!º¥åCï�ýø(“�œý>ß_XÀG>z�GîœV³å£a$¬(EaÉ“Çb¯Ïš72h¥XìöyÖñö� ³ØíEcÉ ã£ôœ‹¹šÚ0™g5ÃÀ‹Þ(ŒUgÚšF³£ÑÀhM¯´tŠ’µ¢àêÑaŽ&ôCí²žd`m ‰éo{ 9E®}瘿tT@£0¼Ì”çñ³(ÃÓLLìdyùËKK>ü!7Üp#Zkâ ŒOLÐé´io´yôÓ’Çàè‘ÃüêÐ!ÿüçÌéS¼öê+”eÉ�7ß‚6†í;vÐjµèt:,.œÀù„‰õ2µÚús�Fƒ¹¹9V¼W¶µ–k¯¿�Õ•FFGyë�×Ù»ï*ö¸€ï|뛌Ž�ñ¥¯üÝn—¿ûÛo°ÿÀÕ9~ŒÅE¡yßF³1LªLÃ}\ ¶2$ëX³ÙdÇö9öìÙǽ÷=À©“'ùÙsÏ µækøÇ¬¯¯ñÊË/Ðëué÷û4[-Ú´Z-^øésŒŽ�±ÿÀÕŒŽU:x8î½Ñ^‰~`±Þhë�<¥ƒB{Ïoíy¾Ã‚å$bÀ·íÓÊÒl Ñé¶9þÇ%]µ±±N7)Ï‘ÃF}fnûv.œ?�þ»ï¹—£‡?äòeY¿§gfÐZ³±±Ë~ÜGÀ„ºçyFÖhòñ笯UbO|òþÇv�Ðu  ±$ÖtPöé*œ´ÞÁeŽÖè /-žßá;S](¿EÒŠ\g �èáªÄ¸’¾`Ò:K×|‹r…èÚN @mÎXW€Ï;ÖÈ4­FŽ1N¶ Vh�œçgÀÞ'öF ÑÏ*\B)ªˆÑ�Æà:ˆ¹´Öqo t¶ø}�òó@DÉ�¦hx£@¦Øû¡½â`(,BGâÓ�WIÚ#¥É48²ø,±±y=O£•££C\È‹X¡SbtñrD;…±áá—±æ°ò ° ʽóÞÏ‘[ÂÏ!å÷1‘öÔ⊞ìÚ•öe¼V«àì§§ÇVûû+}—é=Ó÷nàœ]ñcJ¯6½s›~ùÿÑ:ž¦8@„9ÛàÍ0¬ ÂUu‰·IbË0‡¬—ß�A2kƒâÝû=èQÈ%ã&àÓ²˜ÊÆ0I^ ì4@“þ‚¸˜1[|RÑô¥4žã9©]l W�›,b*á„â$z–Ûôz¹‡4^bAmžµVJ&¢ =õ1“/Ù ‰ ¯zTA®�ãÛÅj…ÞŠ€x賨`%Üß4aÃMЧXôª±¥‰7Op5 ¤6y–oYáôP[~T¨ª} ´x$;' XAIrÂͧ¨”õ9´(XÞC"Ž$ïÍÕ¾!ƒá#zã†6(sj5 ?9­Ê£áj2UÅA¼ùˆßÖŒ;.é“�ç¨ú•i“×~싸a«ßO¡'°ªh�ü .á’éæleAÜâH~Æ<íÀ¨8ÕŠªLg8ªT(«1:'Ër”ÊD WxeÓÒǺÖsˆàT©pg)[P/׳RJ<¨}¿z,…òÑòm*Wz¨à7.*ΧÔvWÍ?jÀe%[‚œAyãiMº{ù˜ÜOTrk.QòCg] ØO�[÷ÝÀù5>í[꺊?·j¨­çùæqã9óñjËæ›¥åNêºÅMÒˆ�jø�iqƒ”¥&¦ÔÌjN6ÏU¸ªò^æ~ŠÄbøkÒ9®ð« 6|H®ßL†& Jö&O åû01j8•|¦Rµdv+W+€`»þ/uºŒxPÄ څƆ«ú,…âÛfÉ3Ú¥x³Ê óí.gÛ`ÈÖû¯.,ñÐÜ ãžjiG«Å�Ñ4LESz´8ÏkEúðª¬Áŵ6›-v 5AÁpž1‘g>y³ãžÙ)r¥8Ûîp|mƒ[&ƸmrœÓÞZ\b{«É=³StÊ’Ån�Ìçr±(ö� ³a-uáÉÍ�&M3d }Ÿx;Óš¥^Ÿ¹f“žuìjòâ¥EŒR|zÇ6ZFóã³)œ”u{«É+ó—i—–•^ÁžaøÔÄ$ÿéÂÖ­åø©�X__cxd,zž…Q˜òž¾÷¡xÆî4y+ç–‰1~vaçl›f¦ÙàÉ3(œc­_róĨ÷tï“)ÍK«äJ3Ýl0j çË‚ÿþ£�X-«ÍìÎ�ײk経ŽL’e Ê¢ÇÚÚgÏåìù�pÎñ£µÖ¬åááƲŒÙVƒck¬,¯ÒÔš‡·ÏðîÒ*—«ÅFYrÑñ ÝEI·,¹wlŒ—VWéö:œ:ýk>që½à-JK¿,)´¥Õ¬ óÎ’wº8`$3<º}–gÏ]¢ãûr¢!ûk~Š�XoÓ÷‘¹Ö,õû1ÁMcüzy5nÙn/¯¯óÂê ‡çÛñ·\)nj ñ˜Q´TÈŸãèy*¥¦ç¿í%ÔJ-­é|LFz¬öû|bx˜×Ö×éõÚ,¯œgrrwÔ!‚~¡‚á�4ª@¡Ø±ëf–—ÏqèÐ!~þüót66˜Ý¶�Ý{öðÊK¯3é_ùêï099ÅØøX\wíÞÃg>û9¶ÍÍqäð‡Xk¹þ†¹ýà'xõ•—)‹ËKg™ž¹JÆM²]P±0€ááa¶mßÁÃ�<Ê[o¼Î¯õ�}úw¸íöƒ¼ýæ|pè}–——xìÓ¿Ãùsg…þÒú½ëëkÜvûAŠ¢ Õjñì³ÏÆ:ÏÎîØˆ@OWÂtí `‰ò}âEžç9gΜâÀ5×06>†1†ññqæ/]äâ… Ürëm˜,ãØGGùŠϳwï>îzâó¼ý曜:u’<ÏùÚþñ&]ÞÔTÿ 62§+š+²^9üy@d­b£F št;&ÔDš¦�f{þùç¹þúëqÎÑi·Y__‹IB�˜\8z�¾}Çîða~üäc„Úu7ÜÀ‘ÃGjã¬ÙhH9ûR¹"¶¹»vî¤Õj¡|´Â÷¿÷@¼ý7668öÑQ~âvíÙË“ÿø}lYRôûdÆÐ÷Ïúηÿk-£cch­9öÑG€$¾öÚë£ÑÆ9Çíïà¹ù§#ÝÐÑ#‡i'9|Ξ9㇉bjjšÅÅŠ¢�1†›n¹•C‡ñ—ÿû_rÑ!Z�ŒÿîswòûÞà�¢Gý× ^ÛMcp™¡ôù|ŒrHÂÙ’²ècËRŒ>Êa²àIm"¸f�¬�.¼üxÖH~•ƒ*�€µJr…Ù€°,W¨,h;’[@—–¦Q çš‘fÎX«A–‹é4e¡…ÿ>$Úõ‹jßàˆN B¤€$Õž¯BDreü ûœÄÝ4 È A«©id¹§"Q‘‹A¼º•2˜4´Fyú[1ˆØ¨ éÀ/žit¦P&DÇ+”¿—èÛ. «¤6°é„-hˆÜ–9g¼Ç¸«" �p·«àþí˜'ªáÎï“„JIy¯ÿ¨¢'ÛTësiá,¶Tàidœs8O$,(ò<-Ù§QJè�2­„³ßH�ñ†‰ .}Ĭìï2#TvYð”ÂÉyç„[_Ä ?S>°"s ¬Š”=�â2P ©Bz·,œ€æ®ò,žòJû=]Ä8¹Æå*bcÎ'G®Ó™„ ‡édïä|Á;P Ý4dÍ ÕÈÐ #ÿó \‰rªì£­D¶èL£2 IfC:”ªX2pBlUB»ì#6´Á˜ÜGà=Õ�ß#µDF(oè�ÑUNæ½õÑÅ! Bú[Ò—aQ÷óÇ(¥áÿc¥u4­Ãf޲ðQ~ߤ�ä> Î[1f2]­K­±Y Bè$a¶FCôG í’„ÃŽLI’F¦ä•kš¹¦a,¹†\<¹Èr$ï@²Ì¢u!ÔµZ ¤2²‡SQzzk�y'GU7 8‰�à|4� �šQ)Ž$‘G›µþêyƒ¿Éгøl‹ zõ‹S°Ž»Ü¸oM�U¡[a5P"¾Ò°‡Ö>§t`þ»�Ã_ ¢.)gRŠºÊ$tM«ºÂ‘–_Q¯‹ªýûÍ÷ù˜#Ý”oþñ7__+QªVßiÿd¢‹Y%Ð&–kcDwýñÕ^¼¾·ÎRúPçÏŒC0Až¢²ê ª¥%[ IDATÉé ñçZç…]Põƒ–N<ôâ¤dÒ‘ï^U – çh/ÜBÃÖÆ¸‹çxdDŽê« …ïÓJåªÆÛÊSÚ \ä’¶úØ~O m«ºVízM¥ L˜ ÄÃUŸ£Ië›Ü*x.{­\%¿×R’‚¨ô3lBã±Å„»Òû­RÎT0£;¿š–ÖçIñ›ËPgí¿/“z†ò† ã'M .UŸ]ÒŸÄUõz§Àcì¢8¾�)´u¬²K>§ã)¼B?¦Ÿ·h³-›Ï]áÇ�‡¤÷ C´Ž.˻櫺UÕF›uµ\„$xG'‹`F}Xù±eŒAåU*´Õ(�£uîËÆ«ƒ¾Å©Gk»Þª™Ç{}Þ„DEââËãdáŒ+øü ¢ÜÉ·É �tü;ã‰a`¸pœow˜­¬Ñ)-÷ÌN1Ö¯ÿ‘<ãs»æ0J1ßíÑÔš½#B³”zS;rø¨\R~)çá~—ÙÑ!æ<Øœ)Ń>¹ðË—Yìõy|×™Rœ^j³Ðí±Ò/˜häLås­&{G†8ßîÒ·–‡æfhÍ/—Vé[ËIJþêÜ9z¿¡AJàû+KüÅq[p[£Å­“ã4´f¡ÛåÕùËL5<47Í¥n�…n�PÚh`¼‘Ó-KZZsdu�}#Clo5™læüøìEšFó™ÉI¾¿¸ˆu–_y�;n¿/ª%^`äØüåóœ¿t‚\)¾2:Áçgg(<:¤�®u]Û`ÿèKý>C™æ‡g.0ÖÈyhÛ4—û}Þ_�G·ÏR*ø×GŽD£Àèè÷Þû%¦§v¼—øÚ>·›®»ƒ…ËçøÙÏ¿ËÆÆ*/m¬s°Ñb{ÓpÓÄg6:ô¬¥ç'ÖÛ´‹Âã0Š7—(�c¶Ù`®Õäв”£©5_œžæ%Oïqø£C<øÉ‡@ɦ¹_”d…Ã@«Jb½ì,{tFáëEÉ+ó—)�pW¼{Yèx¦› †�®ò!d’¨ú'ç.Å{µ‹’ÌHDÀh–ñ^§Í_]¼°%˜ßwŽ_¶7øe{ƒýyƒ13K·WPú±ÔÝâšßÖ(à{œ»‡GyÍÓÁ\^<ÉÔôˆ˜0ïÝÀ'z:;vݯ?”žÿ÷Ýw£cUÄÒý>D¯×£×íròä \} �<öi:�6ÿͯsÓ-·rË­·I[znøëo¸‘OÞs¯¾ò2óóǘ™=×a¨ôk-óóÇøÔ§>Å'ï¹—V«in”‚öÆWí?@¿(ØwÕU¼ùÆëزäK¿ûU†‡‡ùÁ?ü=ëkk|ê3¿ÃÎ]»Y[[åyO ŠÙÙ«¨Z/è®^O€¨ÊvÉUK°¾¾ÎÊê*®¾–ïï;4›M¾òÕ? Ë2¾ýͯãœãà'îà–Ûnç©' ýÙí°¶ºÊŽ�;9î,Ó33<÷“§9xÇ�IOz 3ìÁð`Šô P”ŠB”¥¥´²†Z.((8‚aÀ¯‡N€á2>Å¡¼—qfÄpvÿý÷cŒa÷ž=,/-ÅdÂ<ô°pýû¼ÓÓ3\síuœ¢Á45ÙP†jfBÎß”D´Ê•gÑ¥ÆÊSi!ÄÏo}¢3—Îc¶2 ”ò9or1lÅH�Ð5{'º » ÖmE®gaŸ!‘_¥>Œ ˜@5Ö4�DÔú8”‚RªhKG™YŠÌG;‹2ŽqHF‰ƒ±VbÊüxÐJŒƒs:æ¥ìkG¿pôJ…-Ø£@4 ÷Ë´¥a4C ‰ˆ¹,´%£DgÎÏQ09èÜ¡�P69eÁ1Îä¾P†°Ññýa@e~pîÕÃ:ŸP_«p=Õ+œö»)˜’Þ+"ƒ{e²+Pl¾¹Út‡êSm'¼ÅçÁòé�÷áe«÷Ñ0‘–Ÿ©¦j·x�ÍeýÍǕάWøüÛWÚ‡ý6÷úÍç –pð»`Ô–$òƅ¼¡Ê&1®þ>î[ã}¶~~Í0 ×úÁ¢Ô&0©¾'õB:þà¯ôáYj`LÉÇ´s’{N’îò\jm�JtíDâOþVr¯jÿ¡f3¾_s6Ò �äN(‘ˆ‹�.;‡Z\7>Ja-/\\äàôÓ ¦No´ijÍMD¶´Žô(ÁØ ‰›Æ½?òL<¸>X^e<Ï¢‘aïè0­Nœmw80:Â�‘a”R<{þ“�÷ÎNáœãg/âœã±í³ ÃxžñÝåË|ßFá9·]}5×îÙÃèÈ0Z–ÖV9yþïýˆ�n‡Ç7è�O2– /ÿJ_¼±Ìp©Ûc½_pëä8ãyÆû—W8µÑæž™)f[ Þ[ZáØÚFŒb¸ØéFù‰©©Xžc§Žpçí$bË+úJ�Ó|ø‘z³&Ãå†|~‡;¦'˜n6øÅÅEÚeÉ\«Éý³S¼µ¸„Åóà+Eß·\Éó/ÏžaÞ{Í��ÏðøgþŒf³%ãλJ1„O6Ï4{vîã‹�ÿ)ßûÁ¦ßïñìÆ*_6“üèìE¬sfµ(bß»¦'0ZóªÏ;`´D+„ñÐsŽk´aDkÖ­åÈñ)‹­Ö°x#Yc´R4óЇü*�¡Ü<1Îñµõ˜ø¡¹ε;õ”AZ ÕB8ÚEÉ3ç…Re$ËèYËñu¡Ú72ÄOÖWù‡KuppddŠá‘Iœsl¬_fcc€ãýÿÛ…süÛémq…Ig†�Dvü¶Ç\·¾¼|Îk~{§ˆ÷p rB‰\²a|r;#£³¬¯ÍsìØ1Æ''™˜˜äèáÃ=z˜ÇŸøÍf“ãÇ>âµW^fff–©éi²,gßUûÙ¾c�N‡N§Ãç¿ôe´6œ9}ŠûIJ-\: 7 Q+x£ðêÊzÝ Ÿ¬w�¢ßçµW_áÖÛr×'?ÉÒå%¾÷�o³}û>ýÙÇYY^æW‡ÞàÆ›n&Ë2ITÛé �áý÷Þ¥ÓéFàvbb;�¦DiÕWkW×ñ’#5œ†v,Š‚åå´Ö¬­®²¾¶F»½�B195Åúú:­¡!~öܳ\µÿ7Þt3üäÇOaŒáwÿk¬¯­ñÔ“?à–ú(öƒ#…ç²öÔK¸�t1£Ô!rˆr¾÷(WÑÑEP.P¼¥\nªqS–%w}ò^~ùö[,- …Óùsç"ÿ~–å9r˜½Ïèè(û¯¾†ÇŽñ�ïƒ/ýîW9yâ8ï¾ó6­$GLY>Œ‹FøàœeYòÓg~ÂòòÓÓ3(­xÃçؾc7ßrÏ=ó4#££<òاxêÉÐñå;{æ4oDÐZóæë¯áœcdd„Ý{öòá¯ʼnãÇPJñ¹Ï‘W_y‰ÅO151ÁÆú:+Ë2OæçYüC”Äôô +++LLŒóGôGŒŽ�ñÎÛïðôÓ?–ùÞíóÍçßã…÷Nð?|õ>nÚ7Kž •‡Ð¸(L#Ç(E#Ë(Ê’~a}þ…>eésŠÐ a„:(3Bå‘Cf2 ÏE_”g lYbKá Ñ:C;M®,&ó^±¾ÏB+è”Ãiy¥¥_”(W \I+Ó 74ÃMÍHSÓh:É¡© ,uä�·Vy½Ãûk;KY8Š¢ôrÆz#…¬y®<5Mé�­µ”eQå?Pˆ>®“Içå¹Î‚Š.ÉOKk)¬Ÿ3ñ$6þ£È�‚ÂÊžF)tf0™!kdèLò6H4|P@½Ã’³²ôt.5Í' &ÃÞB)k´×N¬ßû-ØHép¥C•®²=8'QÊú$ËRÇ é…3/¼êæ=¼t'½ßeeÁð�ŸëÞX”M®ÀÖ_çœDUˆ¡ªICA©Á Éâ>Vdžê'Èd²(‰ÂЈŽi­pÒ++¶I–k( ä…&$XÖ¾–J‡Ü¯RO�k«T¦vÕÚ�¤/ª>Õ©S‘…Ü÷+2·tS£šH¶ÞÌ‚)½!ßJŸ@[�2NÎ"~ÂþKНd_m Æ9�Zµ‚�Ú"“ýwì'4VŸlÚÆ¨ß°æh-”X¡¼Î;µjO'èÅ”Vqûî•P²‹ùoÌ´—;œOpm(é+KáÛX–Bq UÈü2Z IJ÷J"œÃuß8úÆa �*T4ôd¾/å¿#Ó’ »ÕT ·2Z MnÆX”’ÏY  Ê‘9Ÿ[É㛉�Sù|º.Ã¥TŒâ‰0@ $ Ÿi´Z2hƒ•Å©–PÝ'lzUuuºÉ¬ash“Ï*¹Àïûýµrµ÷Ö¯í@®æ»ä¾i²á`èHÏUÕïjÐ8�½¬–??¹O:’6×sàý&ì!íƒ:ŽðÛî ÿ¯plºõo~–è�ôÊ�ÏãëåÊGªId˜U„æ—ªàW-âGmõRÉýÕ a <,ÙÔû¢ºHC2P¹èÕR}Æ{d…»Þns{nqÛ‘QAèÅqêêç¥ýT�åú}kß%Ó²†À¤¨�r Ò³¹Nƒç¦ês5–%¢Gx4…j"»ZÝ]zŸACHè�€Åk·˜[µÕÇWè Ço;Ù¶^[\¦�«§½%\Î Œâ\¡p¥£F.çëSíóÏŽcÇo‹2hôˆã'åp;×øÊ)ç'Ï hI8?-ƒƒ*_G:Gä:bÜnц©pml¥Þe.¹¥NæõUŒõsWÞ.V±ªÇ`?Ûdº$ömÓHâ¡U‘¢¢?¼DsV º@é¥K´Qd¹&·M§(1ôKM¯,(¬¥×w¢pØÒ‹!âšN'¼2¦ÖUd2U›(â>=üÖ”äýVK{ÍôâÃãtè�Mr¢~•$côBÒ¾P–z ֈ̮r ¤BqëÙ¸yÍ’k„(síp[|JT??ì¯,=RÅ$ˆ´ºì¨þõgFo”x/ÇÇ=­öØ+Ñ0�¨%Ê'2 ¥Û ˆÃGï*?&<@™V ärqHH3ÑS ‘mÁ¡ÂÕëâTµ\ÖÚÄ%‘=ɰR*€mÐKÀ½ÙáVÍ`Œ}k9ßîFàù <ºc6Öt,Ï„^ÂE­^š~áã(‚÷T{¾�Õ”ÎA�õ.Û·ö†áŠß…U0åp?e ÆòŒck,v{Ü53I†€Ì¿¼¼Ìt³AK‹7ãu㣠g&.{Ÿ˜’ëEÁ…N—«GGhjMß{¦W¦ÌËJ•¨ …µl�mŸ%׊3mN¬·¹sf’ÝC-Nn´ygq™kFG¸yrŒ¥~Ÿ�Ò2ìó6X„"¦´–Ò9Nn´yjm¥f¸ûÆëùê#224,è¤M?yÓÍ|ù¡‡yîÍ7øéo`�ãïV–èhÅÙv›�­OìÞŽsާÎ^Ä!‘ Ó�œ_^^¡tŽŽµô­eºÙ`¾ÛcÏÈGV×)�Ð �ço/.Ç$ÄçÏÓévh5‡±ZÀDï>EYX>:)Þ¼óeÁ§g¦xé‚pâw¬cÈÆ<åÓˆ1Z^¥e {†‡˜jd¼xiëàæ‰1æZM>ìvxÖgY–ó¹Ïü3FG†£@õ§kIæ ;¶íà�»?ÍÏ^úôºÜUôØ®}T“² @ý‰õ6$ɤÖ,tº\hwÈ•âS[ßàìz‡ÆÇyzi‰²,ùèć¼é %•Ö¬•¢Ù¨Æ‡vзŽacÈ’ùøÆÂ]kijÍ�1ÌwºÌ#Q wNOòÚÂå8ùožãÈê:—{=†Œæ•n›HÄ}WÝÎm·=Îäô.?¶E�XX<Í[¯� ç³áÿee‰?›¤©í²š•ÿ5F<#+Kç%!§_òÃf#ÈUç#1ůÀËF_¿]{náð¯~À Ï?ÏŸü韱mnŽv[ !Î9ö¸š]»÷�e¯¿ú Ûææ¸ç¾ûxêÉÐÞhó{ð5:�ëÌnÛÆü¥K¬,Ÿ£ßÛ oH¤Q�­J)æ/ åKQìÚ½‡#‡?䣣G0Æpç]w³²¼ŒR¾o¬¯Ón·¹ûž{ÑZsôèŽ9Ì>ÄÜö¼ÿî/9}ê$ïú ¶ËìÜ� ¸ ÿ˜#®éjsôÞÈð0çÎ�åÁ‡exx˜×^y™…ùyÞq'·Üz?{îYΜ>ÅÒåE~÷÷¿Æï¿`½0?Ïêê »vï®%ÐUL³ò˜6FŒA¯(-dZQjE¡Kïá+Ž,TŒ6•®éÄðT–¢�«ÒQ*Ñý´ Óúþàûߣ×ë±ïªýäyÎÑ#‡e\ìÞÍý>s7t»]®¹æZ.]¼ÀªO|ýÒ/^ ÛéÐl6ö‡p�‹²(Rß|8N�>Íc�}Š�Ž Ñm?ÁØø8Ïüø)Úí6çÏ��}Ñi·ùÖ7þ†²,Ù±sÎÙxíõ7ÜÈž½{yö'bDPZ³wßU=r˜²”d¿¯¿ú +Ë+±ÞGK=GGG™šžæÔÉ“’dxüó_àé=Ç€ÜC6�ÖZV–—9p`?ÿîÏÿœ×_�g~òœsœ]\åßý_ÏðÇ�ÜÂ>t3*Ë�ÎÅ£½™e”MK¯ß§×ëÓîtéô qf±%Úo’šYxebÐe‰uÝÃ@Yô)Ã^#k •Á(¡„É3Æs°—X,ŽR•””ôúe p%Ú>b†Šá†¦‘[1 hçiëEéý‡üz,‹Ð×6òüã�LÓÈ4y&¼ß­FF³ÙðÆ"™ï½^yçÁy^|çÁ>wi¿�z¿Ò‰~¦JE†PŽ£µ 5hI›gU”¨Ò‚Ö˜<óÞôÆ'–… §$z_k% l KËüãÁÙà¸öp_Oõ¥�F•ž¦°²ÿJŒ´ÊY”“úyç ¢rÕ^:®nèW^çwáÚ@¯¤”ðÂ{Ã@ ¡Ò1¡p9š¬´N¬+¥+Q�2H ]›Pù‰k1º"D.)ë ’gƒœ—yl!$±õ\Ûà¤.Iœi\†rï±ïÄ0† ,7 ›ÆÀ,�Êù@-‰† rpF"O¢Á#3"”�B9#|HÎWD;ÿßc6X:ÃŽÒ€@£°…Œ­Ê‘]�Ò ¹²””…�C²­­YBíפè驆ç�g,‘bTV‡�CÒÅ(käÒv™²ôUIY†ˆã°+µŽ9´Æã jR.1 ÈT~Ó¢qbÌVB”i‰jäÐlj†Z†¡¦Æè­Ö•  ²ÌÐho2o°Èäe3o0ˆÑ*�*ÉëH´JÄôB·¤ÿÃhuÉ÷jà÷M:BرgÌ+�~³¿©ÚKÕ΀bظyGÕÄ�ù•µÒ&ŸS�ÿjO “$lx� é½Ò{¤÷l¤Í{òßîHq„Ê1ØÎ¿öÿ•Ϫ®Úª´Á÷60h/Æ´1¡”þ¢0W¬Øò‚3:a2ëêëBu�EâÅ—Ê<n¦~‡ß ù(+`�òÔ"‰ÆV‘ÚW®ÚÖÔ[Çmî‹ø»Ú܂ɸßÜ5•]LÕÆœŠmâúƒYó€\ý¯—5­ôÇ/É9±|sZ¨Ø•îQ6ƒB)üD‰Âwa7I%bŸÊ"€e”XnK …xA`½DÍßV�â�714%Š@Ý(žå‡[˜\Õ@¯7�O„킇¼“§õÇ@Cú¹¼ƒ]8w`¤UK¢˜ýêx½/kä´Wõ�—¼�Ͷ¹6ua\$b×l:¡ÖFjÓoøv´Šž(to0ŒQ)`ãµbúDk+¡Ì™Âåg%„°´ŠnÃ’÷,¦ïhåÕø4êf`]vQ†„þ”A<:ê£Ö— A¥½Å¶Þ>á–u�_Ä7‰-U�«*�\%D ‹¨ÿè‚"PÍ­DBÖ¾‚„f³|ª¢RáÎÀw›jY«C|r(º—Ó[‚½a,Fà`°l[Ë•+Ñ$¥ {”_ÉÃ\2?\\ÓÒç…ŸñSâ�*©ÉÀ›¢h`wUtJÒD^¼UÛ+�~çƒS=êAd<õ1nV›î•A'”½H¨pšÞ5r¡Û£omÌ%`”¢•xØ<¶c€ÐhŬ7"Ìw{œowjÜöF ú1)žwÅ•±­’öpõñçÇ‚rñOõÓoXB;…„’P-æZMòäûñ<ã‰]Û8µÞf¢‘³gXÚàíËËXë¸sfàöÜF‡#Ã5Oj«*å´š!Êóöʱ¸ÖáÅõ.ŸÝ¹ €µ¢ÏwŸmÍÆFØ72ÄÉ�6 ¥ùÜÎmdJñòü" Ý>�nŸa,Ë8´¼Ê Žo^ºšŠ?xìa>u×'"`PEuúqeÍFÆç½ssü—§ž¢(KžY^⦩m\èv¹Éù>ÛlˆøuŽ÷–V¸ybLIO�»Ä\³ÁcÛgYîõycA¼w?»s-ch—%���óíEÉpêì1®¿æv‘‰ÁpŠg~E¯×¡¡��³ÔíqÓä(ÝÒÑ·–<}ž£#ܾs‚smÞ÷T=�]–Õœòcá[>)À}w=Âöéé˜Ç",ó.å…ö}t×mwóúÛ/°Þ^çL¿ÏÞá&xya çEYÒw’0O9X. îåiïÙ|üÔGÜ}ëíh?™�_Ïòjx°ŽcÂd¼îƒ_7>Š‚˜Üxv¨ÅþÑa~qQ¼ˆ-p©Û­ÑŒ½æ¯mÃðPƒ¯Ÿ:éÞû¾Ê�7>2 žÈ˜�™Ýǧ?÷oùÙ3ÿ‘³§ßçL¿Ç¼-™öüÄM­k”Bÿ” y&³Œ¥¢`}m^€5¨¼Uº*†õVù¬-Áë×±{Ï­Ñ0ðÊK/ñàƒqÕþýÜzûA:í6ßÿÞwxè‘ÇØµ{7eY²²¼Œ1†«öàÖÛn§ßïÓïõ8qâ8ûö]Å�«¯á¥—^âÉþç ÇÙ±ëjÅQpéâGñ«ÛäªýûŸ˜`ÏÞ½üâ…çá�þô_`­åÛßü:EQðÄ¿Äôô Oþã÷é´Û¬­­1·¶mßN£Ùä?ü‡¿’G(Ŷ¹ž–ÇFù%L²~ ö^ˆÀ21Ë2¦§§øÕ¡÷ùìŸgÛ¶9ú=1ji­9{æ4;wíb}m�Ý{÷òÔ“?ÀZ˽÷?Ánç÷Þ÷3³³µvÈŒÆxàGù¡DWJ™³EP IDAT’˜Zí½xµŸ{Ñ{MÕò ÈúëÕãàQ¨ÊŠ—¶DbÉ{饗xàÁ‡Xº,FÐÉ©)&'§¢a`c}�7^{c„žÄhÍ÷¿÷œsÜvðt;>üõ¯¸úšk£! 7ئ ýHf �<5ЍÈó¯”âÐûïÑïõŸ`zf†ãÇ>bey­5_øÒWøå;osêä ö8ÀÆÆΟàâÅ ,-É<Íóœõµ5žyZ ×^w=‹‹ ÌÏ‹\¿þ†ç�×_õýgÈóŠ~ àÇOþ°öyÙ'Äβœñ‰ñupyq‘ƒ·䡇æ?ÿ§¿æäÉ¥åÿ~î]Ž_XæßÿÁƒdÞÈc$ ,™«h‚"íIàx6À7ßßZ‡äÄ`\ê�ë(‚þ¡M ™Q<©Éµ!7Æ'hP½¤¤pŽÂY´+¡(PhUÒÊ­Z håŽFîP™½Ò�»B{¢°þ)�uо6ôµõª¥‘ �xžiFÓj†š™€²@Oƒq%=…7í*ã÷+>j èŽJ—>–Âó¥k…óÞÃÁkX°-Þ‹c0 ïm :ËÄØfB¤pÕ&®ôr_;ŸSÏŸ¦Åc9æ A>é­s~!÷t8”âIŠÕ—Ú .gñNu^ �÷:§èÅÒÂ:ì�½<ÏÄJâç²x⇌4Æ„<ÉÞ0`ÄÐ(”öƒ#²(y¿(ŒPÕ8SEîB‰s!*¤ŠæÀGœT`z„€Œ”¿ÿTV¡K|4cqÙÿKÝ{[rœy~¿/«ê˜ëÛÜvh žp„#$HÉ¡r8;³qô¢�bC¡�‰•ô ˜ˆ}ÝÐjGzÛ…BšÝ™¡í�ƒIxÛèn4ÚÜ{ûúsÝ9U™zø2³²Î½M�Ú ©:ªï9uª²Ò|ùe~îÿe¸Ò‚�¢p•ÅZÁ£"Y0ȸ¨¯Œ˜ò9€OT�x-Š©Hå¼\ŒæGtF¶ÆRÒvÐržŽÐÏ-§š%2BØKǹêéÍ9j§D÷…F ™É´_Kë#;Œ*´ý`4BQ2ëûJ÷Sao®6/_£õð-žd|´„@Ž:û9¯œ´ÆÃ”9GfÕŽSe�eŽñ�á—ïÄŒ;¿Û]á3É‚'õ÷àá-à’ ®ò ZXà=À–Â>Ú„'§}*q�«ÇÕoŽÂw!Ξتð_ƒgºFÎã=K~qbÇjxµRS¼D¥ßêþˆy9êNiöWT~ê Åÿß0}ÈЧu�åRJ(IÆ‚Äk9¾§Y�óðMÎè&Z¬ñë„D@ äYš  ¤BÄ"Æc ªÙq9Ý@´ŠŠ"/½c…Kœ(œß¨¥5¬me_~ ðt-FÎ?ëâHÅKÝÓõ”oÒpÀ/M5æ¡ÄšÏú¾ô…¦p:éôO½cƒ‚Ky|µ¯O¢D¯Ù¿e®…>‰IÏm´Fs6»+¬à `½·¦“æÍoÂ+çN¨Ÿß±lçâÚ( Ù§é”ÆŸzœ…>ËŽS(ÔÓÚ4ª îÇzM­çu¸-T-@ïDá–´oõ¿Ô¯£i«qq ®Ôz›„†=Bˆ�(ŒaÚ_{{¥ÇÕc#Q¡>·Õ'8<¢Ñ»[-ÚÆðÆr?–¡ëâé¿®¹Kè9ôy ÷O ’°Î¡éÑ4æ¸ÆßAšKA çÖ682Úe4ÏØ¨,�]šã�$¹ð|¿O…‹ßo˜cËçSز–©VÁûöè÷dÓMi:’@¾tÛ7Žté[Ë¥Í-®åäă’ÏÎr|t„[&ÇÙ¬*^ZX&áóWí×ò�béf [}NŒ�ðŸŸ:ßó÷~”OÞy[ÝþÞ´NÖïYë¸ñøQ¾üàƒ|ëñÇÙtŽï¯¯ò/Žå™Ë‹,ôÜ¿w»Û-žž[Ð<"Ü49ÎéÞz¤ÉÐ/W�h.ö¼¿¶ÂGvM"ë|Ãã]_š;Ï ×Ý�¾T}àœý@¡/úÎqgÑáõ¥U®Ÿã¦Éqž™[À‹ýkigêÝ7Uä¼¹¼ÊZUqÃĹ7¶(òœgWÔöÓîrÿ�ê©­ G•C˜r0 dYîaMwÚä97^{/¼ú"˶0Ü<2ʯ–<Ý6ùÖrÀO.ÌÒwŽÉV�µjD¸nbŒ±$±ð©3§håxX þ-“ð±×ª>w��qª§JËõAYã¢0Sç×7`ºÓfq«Ïï‰ñQzeÅ¥�¹Ûá_Î^Œ¥ß~û§¹õ–‡=¤—Ô<ÆÃ(•fÜ÷À×ùî7ÿ’²ìó£Õeþ|Bóo û/ü>F€ k™. –Ê’ª0lÐnu£Q èØ‚×aøOýAE–;˾}Gèv'ØØXann–_xž£ÇŽ!"­wÞu7»wïfccg-�|æ´ÿßy‡3gÞã�|š,Ëxû­7yáùç„kOžä®»ïæ‡?P¼ý˳§8xÕ-uåÊr“Å…sÜzë­¼ñÚ«¬¯­ñÀÇbnv†³gN32:Êw~aÿ�{þÕ—_âÖÛ浪*ŠBqþ÷ï?@wt,*q§v¢ÛÇy,õÆj6¼GÞG ý-Ë’^o�[>òÖ×Öyô7ÿÈ-·ÞF§Ûea~žÇýYL.üÁ¹÷yí•—hµZìÙ³—ÑÑ1z½Uzk=6Ö×ïÊ�!Ï‚a@|âI‚s©Ç†7TÆ+}œ«½Ñ 2ô°o3 "ŽJë‚w.\wÝu }Z­–Â0½ò2UU±k÷nNœ8É믿ƙÓï!"|ñ _â¥_ÿŠ3§Õ�S•%m)'"ªÀO вÌ`­hÆ~Vd´[õü=|ø*Þ?{†�ÜzÓûöEoÿ‘‘.·ßq'3—.*Í9ÇÛo½ÉZ¯GQE‹çžyZ ‹{§9~õÕ¼àá‡ò\Çàï¿ýMÖ}žŠN·K«UÃß�~ïT\˺Ý.++ˬ¬hTÔ 7ÝÌ{ï¾Cß}®¾æZz½UæfgµÝUɲ7L†£×[¥×[å/þ³¿à�wÞåoÿF#,žxý}Z™áúÚ¸Bײ�´7ËsŠ–BÚdE£]ÈÙ¦3U©0d8±dFQUŠ l¦Þû™ñ‰¹kfpU»²æ;qOæsНÔ�Ë!ŒòÌõ–¨ÖzÅ0Fÿ5|�ÙŸ�Ø0€ØÊë¶=Ü�ˆ76B/”Å!FeAë×g2Uúg‚‹õ8ø1«Îh’Lî�R}WGãˆE-Z¥ÅeFæ¥ÅŠCJ/—;S:�úÎp* x�ÿJ=ߣ,”½ÑIÑï <•sVû2Óh�kYmWa %PzÒç^“CN A¯!xáÚÓo–�É[*]eÞ€äY´|�À `öÆ“`ŒÐµ;1 xo ßìâÅ\22ñ¹BÒçxª¼`-TN£ÏªÊP•e%þ³õQ!W�*‹5¢^sp8¯‘T-B9ÐY©ðOe©¹FBÄI‘C»eèva¤+t»B»ëhµB‚Ò�d9’{CdË37 ÁøWdú[à~þM�à"ßlûÃ ÔØ�ñ§¦ ˜TAß?dtîñ¦ñ*œnè†!x™°î'c_ÇÇø”8c·ÕÙW4Úü‡Ä'xÌÐ<¡Q@ýŽpŤã qá ,">R@,ºPègݤ‘¡Öf'N”�å�çê�”ç^Ñà¼ýÙ9ʤvFü|òÀjºÉpÍ~h,†¡Þ#Â{°$Ûd�ï’F$k¿Ÿ«µ7z}Çv³^0VšKË < ܺ}NÆ‘m¶Sn}µ¦…¦×~Ó(°SÔ€}Ú? oßéð†%ç?׊þøRR�ßçö—PÛ°©mz໺ÞÛÖ,¡�¢Ã�µ1¦6ÚÕuaDëýKPK¯ÓMs˜¿~oãÄÖsN<5Ä®M"N\ÝÏZ×åwq¼¤AéÎnn±¯Óöïw¼º´Ê»'ã=º�˜à˜‡XËÂVŸýÝãEÞ€@)=Ætèݤ£ ¶ÌPïÚ8PÓ²sÁté|?'ãèÂ&Ûè3ùB(Éòéµõ�ÔÍ wîžd4ϨœÎ¹4³¹ÅZYrÍØ(�,ca«ÏÓs |æÐ>…r.&gŸTÖ¿”ÔDhãP^�ºÞ^éñÖJ�b�p°ÛQÜn„Nf°Nó”ܶ{’Ñ,cfc“‹›Ü¾k’Nf8¿¾É+K+#-ÎmmiÙ{÷ðùûî®�"${$1@&´êwÝt/¾õg/]â�Í ~²²ÌôÀÅõhµ,9äÇ}§Ío—É2Ü·‡‘,ãç3—)­åá{Ïs~1;ÏrÀ®VÁ�IÒ癹‹„¹\Ó!¼^½};Æpx¤Ã…µ ÆZ¯.­°«UDÜþÇg.#ÀÇ÷ï%~>£‘SEε“ã,—%¿Y_‹™=vŒn·Ëôô4çÏ€Ã=÷}Œ½ÓÓ<óÔ“ÌÌ\â‘O†‰‰Iž~ò Μ~�cǯæ��?Ä©wßQh’AŸç~þh|Ç�ƒ'|´€Žp�÷H�æE £ŸîI“NöŸwíÚÅææ&÷?øq{ô§\ºt‘±ñqî¹ïc,/ª¢xl|œK/°Öëq͵'#\8ž'Œ[o»�ƒ‡®âõ×^aÕ'ÐÅyF‘…=©DŒÎ/l™ >L~ýñ<܌ҞW…ú}ƒˆA*ÝGUÅNœ8ÁZ¯ÇÍ·|„“×_Ïw¾ù @¡ Z>‡èû~ö“³¹±A·Û¥Ûáu“tøÈQn¿ãNž~ò‰FÂ`õT¯9·ó{îÌÔ�èæâÅ ÑÛ`uµÇw¾¥u¹ñæ[X^Zä�·ßà¾û ÓéòØ£?�etGF"�•å€üƒF’tº]5"�&žžÞë^>ô0?ùñ�â»/ÏÍF8!P#BxOÑjÑßÚŠ¿ï?p F,è³s:x€ÿþŸÿüëõ¿h¿½rc„ÿùO@ŒÕ|¨0 ;’åUåüØè’ÁÖ0÷¡Â`ɰä´óÌCjÞˆN«E+/¢gynÄËéž_‘]„Ò ¥3š`VT©m¬£Û:-Ô(�YÏ[•¬ *"åm±×Ó§8ƒqŽŠ,BÖ´2CËcÜç"q¿£ª(…þÀª9$¦¦©e¼_žW¦Ÿ{!˼vŒ0pþÔ¤�)|ràÜD™ÃY¥S��ŸûóY”Zƒ—‹¼Ì`ÀHæÓùH-£ïwÕúX£F çå-ëôáÌ!™ÃäÞ‹| `*åÇAôr¢Þõ^>‹úM#ÊGãΩQ8šˆÜDu? ê*pê³!á Š y!dN± kT9k�õ†ô}™S—óL¢§vðÖÖÎI¾º ÀoàqÚ¦`_‘RËÑöiô’ ²ŽgÅ&GawŒŽeW"ò¯ŸNÉóµàè–JBA¶ —½fNóA€iLËC µr£Q 9P@€äUCBM#±l/¨Ëz€ò­e‹H#Æ`ŒÅlfF\E€Y3â ½1GÀö3<**jø¹¢ÞòÁÀ£0¡A¼©#l‚Ó‚Êè>�³5>�* mD£<ì8o À^–ÑA.ôûh‰@™9ªÒE{YQ@Ñr´ÛŽ¢mÉüiÚâá’&7!à#5Ôê)‰ÎZ „Hç ÏÕ+J½^ÕÊ¢D(J?ëã°Å_·‰Æ�Ù¹~tÉbÛ|¼Ö¯6F‘HÌ�2w>k©'ÐMÙ  Ï�mßC-‚�‹/«©àwŠ€Oèdi@¥g–<—&)†Z~ÅÎûÿÅ‘ÎÎßö=Ã4¾á\cõbpê­åo+ÙNȃØC„EÛ ïrõK#–µ6œÞ€Zm=SÙ‰|‰BõB‡mê¡ A+P7Ú3ãh·�úZú¦í‡/Ãï g-4çA˜À�:o?†E§Úh’t˜WDÖ‘²Ã“I±OkFÑÐÅ:ÉöÓo ê J¸/iÛpÜŽ£ô[(ñw=Ôs…Ï;Ý›~tõØ%@BâÎÈ3Lm,@lÒýV÷T‰Ð•hufºÓ¸Hã“Vagæ'hPÐàçT­µÓß#Íê€H“`�,Œk]ÕÆKÓïA‹»21”]qqIû á. ºõ*içpbó/Uºˆ$Åú¿MZ Å»¸H©BÞÕJ-Gm»7vª˜7!§%BYyì@æ9…‰j+P9G&Ö«ÿÕ  W!žôC�«) νïT`zºÑQZý34ª�†+¹69¸¤·ÄߥQÖ�_aƒ……ÍÐNÇ=ìÝÐß8x;ÝæÐörê6k¥v,š ]¨ù¹K‰¤~þJʨ+AÕe»m÷ÅuaèÙ8ˇ¦»#(øƒâ@«›14PCå‡â�¿Gç½ÄP=ÍàÁ[&ÃÂì’3°¦ÄAñš"é2×cýn} Û€ØÙrŽñ6ÁˆD£ÀjYÒ=è?Xßd³ª81> èšß°ßõ’rU©¡{bçø¹×Q5X¥q:óB¿ƒÎIñ”+ÑÔð;6·ê†¾ÀCûö`�ã­•ÇFGb½Ÿ»¼H'˸m×D|ûZ‚C½»Ýâ¡ý{i{±M*`|Rµ0@élOYg8ŽŽvéfÓ�6§Wטl^豙ˬ—Ÿ98Ma OÍ-DÃË¡¼C'3ì¶ùÛåÚô³÷Þ…ˆQüÝÀ“½ðUóÖ퇾pÿ}üïßú¯¬ôø�&áò֯ͭr°ÛáÞ½»8·¶Á¹µ c¸nbÌRÔƒ8C¸´±ÅÕ£#,·KÆŠœ7V"tÌüü å $ËrUÖ;a~a†õõU þ«É=Læ9·]µŸ·Vzœî­#À^µŸ¹Í­XßͲd£²é°Ô/1Æðƒ ³\?>Ê‹KËñ¾…¥EžûÍ W¦�ßáX¶§ þýÝ6Ý=Å�.ÌDÐjŠQ.ðüÜ"}ç˜n·óy, #\Óé°ÐëQUK+ ìÛ³gKõø´–LêrZNE©Ýí»Û-f¼a`m0àÍ•^„ 2"<5§�*»|’ÐËžÎ'Šœ›'Çù?çkX¥�Ýý9F;mp¢æt'1aveýé,â1ÇŽßÆ[o<À[Õ€ëMͶ~ÏH�ô˜Nò}8»E»•£Êtý¼r0N—× J’W_}+ï¼õ Oüâq¾úÇ_Ã9ÇÀI>öàƒ8ëX__çÒ… \wý \Ã�ÌÎ\â±GÆGヌkOœ¤ª*ž}úIöNOs퉼óöÛll,³¾6ÏøÄ>D,s3ŠÓM7qâÄI¾úµ?a}}�ï|óˆ_ûÓJ«Õ¢×[e}m�µ^�N»Ãñ«¯akk‹£Ç�óë_ Óíò™Ï~žññqþ·¿ú+_¾áÀÁ“dYæ ©Îµl½V‹ø}ëõäè÷ûXçøàÜ9®=q’¢hqÕá#|ïï¿C»Óæó_øÇ�=tÒ½÷Ýϵ'Oò½ï*èõzt»]FGÇšïÅ‚/r1àW0I²^¿N9ã�ì.òuçUe)­‡óJ—ΰ·uH¥¿oöU�<þ/œÿ€Ù™:��n—ÍÍMžzBiõ¶Ûï`qq‘÷ÏžàÖÛnçÀÁCüà{ß`m­ÇÙ³gŸ˜`µ×‹Íj>Ѭ ‘)Á‹¹nûææ&·ßq'o¾¡9QZí6ôÕ¯ñøÏevFîããã12À;o¿…ˆÐj·aqq�' á®{îå�·ÞŠ#wß{ËKK¼ü›_P•Uîh0D£@·Ûe0pÙÃÈMïÛGžç\¼p!Þðà!Ξ9¿§F�plllP´ZÑ8`­å'/�æêýü§Ÿ¸�Ü»,&£h)¼MѲ”¥Ó³RE]Y9ªj€Ðr*‚Ok&––\+ǺL“Ëæ�V‹"Ëk1ÍÏçq¨�8?÷ C»(è´J\i FZí6´ZŽ<·&@…*3Þ�¿ªIÒ�§!䘩2uÈ3Í+T˜ŒV¦I˜UÇê÷$UåÏW•ª?z§¸ 01 pŒF£#ŒÇɯen¨- Þ�eªè ‰Jq„„S.SÞW+nœ‡ßpFÕ·â•nb=n¾SEq‡'È‹Nß!.«7+>¥ãqòR‹Ë­‡5ª� ¤òk*å6x‘£ð-F•¡ž·™öMø ŸÚ- kc¼Ç¼u•WÛ8fê±­í™äª´�¢±‹ú@—9¤pàñÞU™ža²¬æ3¡žQ†öç‡fà7ø~Ý[ç«})¹xƒ�#�Æ=·W7åáT^�œá¢ìåw¿>êô3²væ=г!£‡P<­6 Í P›\u58?Ž�>K§Ð½©÷¢qšðXTί¯ŠOA•Ê�VËï…笗׽îI|òbüšïŒr‡¨Æ*ë|�Oœ%~ÌT¤QN¢Ž�áT£BUYlåØÚ‚L\4fU™Åæ:³L‡g…£hWdíÒdð�@Éñ‘¦6 äFÇ#Õ/); †Í©�C·ë÷0^~“tì\£;ã˜Å1L•“éÑ`JWøM†®…ëµÌ^ß#ÛNú®­SþS#É {ì‡ßS�ÿ´-URæNžÿážÜ?k‡î68oxGx_:Hÿ_<þýë&CŸ›ô“|ð�K^5z Ö)ï ôœ–—ló+íC•”j€€†‡K°t§JD©• ;¦ÑR±°$.¤pý“0`ÊynC&P¦ì‚e8}w(Çw‚ÄÏ&þ›o\£¾±Ò6¤¿É�ÎÉ�Tã’ï"ñÊ›t£ÝxMT.ø¾ Þ1¾÷k~;9öŸž¦Ñ§u¿¦•KÚ¯ºØ°ÔãY± v ŒTù¼­Tšâ¤ÑRõÖõŸ£1")¨±HDU_ó-^#7 6„{:n™LgpX¯Öëb¯ˆt[ž4›#�ÿ?tjǵ¦�d�ã; Žÿ%F�fT4 ‹†y?Ôý7¾t©¯Û2L�â«VÏg—Ô;êªk«@RWHµ Ñ!*þIêOÚÿ[F½Ó24ÛÞ“õetYæÈ2K‘; . ¥ÇÕ´b¨œz”dfÂ×ψÃ%Ñ©¢µžyõÊâ0€±ûD×èÙæÇøûl(=�}J‹ gvéX„+q(﨓ý ÏüºÌšA)�ùpˆž�KëÚè½ùK2“Ó9@M/�ÐH(ß5ÿ~X]¿m¿%Ö%É&ÿb¸� õi^âB¾Ú)¯¡Žˆˆ E]¶µÎO‘¦È�·s‚µ>y—\ÂÜI(ÊÅW9R¨�°^åLpX I8Mô ðÆò*7NŽÇº­ *\®‰V®ê¶y:YÆMSzÿéÕ5&“d‘›^A¥ïiP?õê…7\$¿%FÿxgÍdc)Cs¬YÀê†B4"ìõð‚æHج*F|…ÛwMª7«ƒµªd_§Í¾ÛŠ~“ IDATN›�ªâ…ù%îÜ=�#ï®®1R¤I1“$æ¡ßã|ÓkËUeùÇ ³Ü¹gŠ#£]ÖÊŠ×VzìnÜ?½€©V�+ [}nÛ5Áò d¢Èyfn�}Ý7MMð«‹çh· n¾úêÆ˜k_Z‚§ZÝUa�æ{AàØ�س‡Kóóœëoñno�{vOE…|;3¬•%-#a_§ÅË«\ÞêsßÞ]Œ9¯,.óÁú&ÇÇFøÈÔg×6è•%×u:<ßëQÙŠåÕvMNÇ�èìÜôÊ¡�µ¬ JF2M°»o¤Í óKlT·íšd²Èyzn�Ò9NŒ�ò‰S<y1ò§‹[[Œz�ë”?T8:a÷…/òî;o³²²Œ¬ £££llnÒjµ±¶ÂÚŠ_>÷,W_} ½^�N§Ãw¾õ vïÞÃmwÜÙxG–òè+>§‹b”òçP!ýO0ÿa«ýf"Ÿ4A±ê�Wº67•î×××ùÒ}…§žøE«Å~ñË<õÄãœ=s@“²'yÞ|ó ^úͯ™˜œäÀ�ƒœ=s†W^ú Ç};ÃÑÎóèÍ®ŽÐ ‹“º�lnmqäèQN¿wŠ­­-pŽçžyšõµcããTUÅóϪ±êškO°wz:~ŸžÞÇg>÷y¾ûíoÑë­Fž•'Æøgž|’²Ðnwçòå9æî»ÿAž{橱râäuœ{ÿý¹’^‡Ã9�Ýn·ÑétÙÚÚŒuô&î¿ùoÿ;þõÿú¯ø7?}™;ONsÓñ=T1 °O¤ê½Ž�x£° É‚ý¼Í<´”‡õ^ÔEâ½9ó<§ÈsÚ…æw‰ImEy‚õ [%ÉÁƒ“œ²mt³Êiå9ÝÜPäŽ,«£´%Î+ÆQ‚”d=çe@$ËT•$jÈŒ¡�ç´ �ÖÊ$x[oçZë¢xÈU'b1N£BbÑZž% ι€¡¥íÔŠW¤òãSᤊxó¡1º×óžù68"E«ÔÞË™Ô Ë¨ûH/’=ŠÕ„ñß*ñIU—+¯d3°ØÒùÈ‚© ¦ôùlÂJQ:È|]çõuêÕ]áâ`¬¶ … #`²‹&sŽÑÞØQ§+R~é‚~0= ¯Ø-’çHH¤.ò-4úÂC Eë¿.˜º¾CÈw'Ö;ÁeÆ+þ›²©#ð7ÿ¼HSn ¯lˆh>ªQùSxÀ´2ï™nbDÀÄ�´(©N$•邌§ù$œIÞu¤ˆ Άh>ư®;|b�nT›S D_'"R­»µ:ÎT^Ä7!²Â¡yj)fçú)ur ­*½ú(i ®Ò3âh]„�/¢€-½A@*ÚÞn`ý¼4™`ò:â$o9²V…i•©Ñr‹+ðcAåÇ#Ñ_Da7�èüëÇÚk ˆ£®1^éÓ;µÕ‡úîßvÔ’x¢;p)±B0â7O†¾ëÀ('bHJª°¯?Ç÷ʼn›n’2e⪒g†«-8‚œ™�Þ“Ì»ÿXÇ•Æ2‘|>¼NÉH5¾×£9Ô²ÈÒâ‚H-V»ÆéÀË(!:h¸æŽ<ßæ¢Ç^�Ƀ7Hó¥Ž~DP2E’Æ®‡E;î2´iêv§Ö×°· §©Ãv\ ã F�d‘4õý5.=þ³ÿž"×ÙÞÛ©¢1’ÜFê·d#Ò"Údb«geR¿¡M¤©æðâÒ>¥îÛ´EÍå„8ŽRkDëì„Æ kÍ®t8[×£ÙZ†:êŠßC}%ná]\ßñ›ˆÀ+4©F°Þf4½¹Ã♼¦Ñ1¾vÒ¬e]—ýŠ¿ûwíLJú{x�&Ñœ/ ÅÙ0¯NyjcApqþÖ(]4†û7\ûíLÊEÊ >q°4Œ¾¼Æbéßí%YI<ÑLj®tè"l­z7Ä$^JÓÑ(àŸ1Æú„Äjh·LÄ™H¨ÖBUAá„ʪ­¦è¦A·Saë¥aŽŠÁù®—ª4mü»ÙÕžQ•Ç�8—ÃÞÒnã1žÒ¯8éŽ,%ß+O¾ÿÓ`ø á'‹È°RÞ·?ý¯¼u ÿÏÞæ]É6(γðÀvãD¢Ëß¾^¥ïMŸÁa‡ÀšBµAvç’RE½§ò¡»$ÞU/Éþÿdo�²Æ0üú7<ï—ªÈ ë=¥‚€ ƒÐ _žõ‹PdÙêˆ�šZ2£¦ “±žx_?1ÖhÝ�®zjö+ËbÀþn›–}ky|fžOœnp‹ÝÛ Š;ì’vnïçÚØ“†¡Í%¿û67XKŸð¿ç™¡Ö¼çÀiTÄzYÑÉ3>ê“ ŸY[§´.F@ÌlnñÂüŸ;´�L„¶1ìvI÷ì™âíÄ3´ÈóÚøâùép®ƒPÇvfèd†Ò9Z™áÁ}»É>Xß`n³Ï­»&ÈDxia™÷×7øÈ® Ž�Žp~}ƒË[}2ªL¢çöµ‡®Âd¹ÇŽw·Õù¹#â=@„ˆØ\X[n?y’ÍÏs¡ðv‹jn�=íŸ:0�ˆ(„�s|êà4Ý,ã× ËTαQY& Ís�ÿ_pº·N&pÛ®IÞ^ª½ÎVV—˜šØ7¢—ç/°d+ºÝcyÎã3—1ÀÚÇFeyÜCmTGF»Œ9‹ý¥Óˆ�©vAߪÚêËÝq\vuÛ#Ì¯éøŒ¶ &»m..¯áœ#aÏx—Þæ€uïaž‰P9G‘©‚hs ÊÅVf¸z7Ï_^dÝGá ëš48·¾I¿ªz¬¯óþÚ:c82Úe¶&——è´2œ+ C'Qº_²ÿÅ¡ýüè‚b„[4‡Ç…�Mþý/-­°é?ÑdÙ …Ã#N÷ÖiÃÜ@Û6Òcß®I Éw©Q@ϲ‚2 †…²jå9{X^žc¶,¡å” CÀïc€f4Q&–n» �‰ ^Ãq¦ �œWÊh"i‹­2®¹úÞxã9vïÞÍ/œ¯~íOU|NNÖh7Þ|3‡�cttŒ×^y™#G�ñð'? p4_ùc}öî{îå¯ÿïÿ €¹™w¸áæ‡X]¾ÌZO•°—.ÍðàCóØ£?evf–/|éËŒŽ�ñ“ÿ�¹ÙYFGG¹î†Y˜×ÄÛEQ°¹±ÁèØ'N^ÇÞ½Ó\¼p�Ÿ?Zúêz…á †¢jiñŠ1] œ‡Z ‚÷ö#��²ªÈ²ŒCW)6~Y–ÜxÓÍì�žæñŸ?ÊåËsÜwÿƒ=vŒŸüè‡,,Ì399žüG¼ôë_°´´ØXÿ×ÙÔ|:ðæ¸"ïV>¢¼¬&í´B¥›-¿&y‰$z ”a-¬o®!"LMM±¾¶F–eTUE9ð­oü-UYräè1lUEžãW_à 7ÝÄ�¾ÿ=œuÜrëm\ž›ckk“N§Ãù>ˆíš ¨"uåé1f&ÆÇùÉ�D»Ýæc<ÈéS§bdÂß|„µ^/æ°V¡ÂÂÞeyy‰ï|ólnnðÑ»ïá;ßþç>ø@Å(k1Þè^äEQÐj·}ÄÆY–ñÞ©wãüŠog·Ûel|‚¹Ù™øÛ=÷},$@s¤†�`hI�­­-&&Ú|ñK_æ{ÿð]*ëø—ßz�óÏ? F“÷«>e¿¤êW8gpÖø-¹)©2]ʸþHsAÈDsÄäyæ£ND¡¬B•ï¸å\…¥"ked…zzK–E¼q*‹TæH Ãa(ÁUX[jÔ€1 $‚X5€'qúlfLôŽ7¢÷·[-ºíF4 ²µ1`Œ&ÅÍ­F`.Åaw!âÑ)ä£qšAÕC×ê~V<6¾Òþ^‡S£Ÿ5«ùŸ°x¬ù`&3Þ‘"ûŒ¯ÓŽVOOƒ)LíUž$Æ�ªa9Ò95 „²}2^±Z†àr‹ÉnPáúV·[9òÌa+=£ü$*Ë8�B2¯Ì…¨$qúlÐ)oc\ÜÑI&óý#9÷1+1Þ8 ÉÕ“?xØ›¶Sã@ž)®ìN¬Óù>txƒG²H¶@2Ÿ ÃožÕ³–�$Ĉg¢I‘ÅÕ2› “¦* ¡�Z—r$øû2QEtËÃKeu�viƒ l–ýL¸'Âvø*a èI’lt+öÒ�è"®ÑŒ0–µêé7´Ý¢Q%® ” >}màx ©uoÆïáë!ІQVc4°P9Œ5µ®*¬¨·ÿÀ’SQQ)ôæ }Y†ÉÕ0€±šZ%~ZŽiîktà©sDÔ§Ô“ŠÚ8PG%ÔC#‘'íuN¿ÿ¿u �ÉŽJŠîûs ¿%öº7Z¦9NR£µ:rõúú–ÜíhmJ{ø˜–ôz¬­·ú«l ÖT&mä ®¶·DehZ¢ ÁMF[©í6µ²4vã6Ú Ï¦s9õ ~…~lh’ø×þ&­£½îikÅ}ÓHàâ¸Ö—‡6‘]KnK7à..TõoÛ¹}d‡Zïö¬M}‡�mþø~:Iòk¸*Í)æYúw¨™.ò;ç[Œ� ›oÑûj»Yª4ª]‚Í©ïâ›ëå8ÒôhGqö—mÅÜ`ÀRÀD‘{o;U8ŠÔÉ…+ƒ$‹dË>u`/‚z{g"\3>ÊÌ †óØhÄ@0tìÐÅq�0l„2ñ³�÷Q012´el&²Gí§eŸÔ`_QðÌåŽ��pí˜F²ŒUWç!ØßióéƒÓέmp Û‰Fƒç—+r®Ÿk´s¤Ó¥æƒ ý%{�«<ŒÊÃû÷b�ã/Î2’ç<俳ºÆÅ�MnžWåu§Í¦µìm·8·¶A7ϸgÏS­O÷jÜïý»wÇu(ìñ*úÊŸFÿ]Jž_;N9 Ï>‹û}.Uú_71ÆÀ: #´$c£¬8·¶ÁÍSXç(�ãf96Úå öçÙË‹ 4½VCÇôzKé01¿¨Ê¬ãE‹›ÆÇ(ü’ÓÊ2zeÅRÀÕ£]a«ªøþ—8>6Â�“ãœ[Ûàí^|îªý\ÚØŒsïp§ÅXÑâ×}¶¬e_QÐÛpt¤Kå,-“qzEiâŽÝSlVo,kérlt„ŸÏÌa�F™œëmÔÒ"<9;�ŽŽŽ� œöÉ�t¹s÷$?8?8úÎ1Ñ*Ø=¨¡¬–V—i\î=n3º�:á÷¸/-®ÔøÖ¢ÐRGF»lU–YÉqÍø(ÓíÏ]V…uå� Kæ†7uÚmº-MÔh†ý\fj°N×Å oONîeyyŽ5_N ! �~ߣ•|©h·2ï}XG ˆ‡Ñ­´ÂÌ‹sXk¨¬ãæîà�7žã½÷ÞãÅ_䳟ÿ<—çæ8zì8p”ùË—ùé?þˆ‡?ùb}}�W_yk-¹ívíÃ'¢¢yqq�[>ò:�.››ÌΜB½X3f.iÁ®]»¸þ†h·;QÙ*"¬®®pãM·°wï âÙgžâàÁCüÉŸý'TUÅw¾õ œs|ù+ÌèØï¾óOzÏwÃÁƒ'jž.hMœFK„n6ÞãmÛ¹æ7Æ':Ÿœœ¤ÓnógþuVWWø‡ï|€ÏñËLLLðô“Oàœc}}�Õ•<ÈÒÒ"ûàÑŸþ¸õö;h·Z,ÌÏ7Æ0î¿=ÿ­÷%~ï¬ÃFH(sXC…#¯„Ò$k9Ô2¡ykË«Xk)Š‚‘‘~ý«þä#œ9}:zÅ_uø0yžsþ¼*û8õÎ;äy޵–~¿Ï·¿ñ·8ç¸å#·räØqþí¿ýëØ¦©Ñ‘Zo÷£BžÕ+L¿? ÓiÓï÷iµÚdymÐ{ù7¿fss“N§Ëž½{9sú=Μ~�‘ÑQúÄ'ùåsÏ2Yçñ¾}ûùÁ÷¿åI²ÃÑjµ¸ëá†9tèP4äyÁÄdÓ0�B_„2´}v:VVVxðÁyá…_réâEN]\â‡/œá+\KeKœ«ô ¶JÄeˆSoìÜh&Êß× m1ÄÉþ"‹Úâß@&uS½µ7(þSï}£ Btü݆ƒïKKÄ0ÓˆL/Üïjd“† ~g|GP4fÉ=)eé&8%½`Ø™’á3ÉbâÐ.)( ¿HÒ¼Nž¼A†® “LÝq:Dû'\ŒMs�±û…À+Òë#ÙQÅA–äZ:Á’‚ÕñK–ÇÛ®ïI˜KªU ïhPU(50èpMê¿Ñ¸¤Ô,¥j¯Õ�ŠìH»ÕvÂÝÖ¯¡¯¥~6*Ñ}ßÅçR‚MêŸ;ê¤@É{dèsà �þV÷eóþ¡òÒî%(�£ ¾6B GE4'°o§Ä¸!þ¯±@ =Ÿ–iõ‡¸J¦xc­IŸ }`ŒÎGcê èD u6&»jeK”–bà”Ž,ü–ùM=šJ¡†ô]>Õ‰?#âxëbE=CüT Ð`mDÞ%ËO$H:H—>/q¦A:þé³^ažÕ¥µ9þAI+=4'‡y—KÓœ-ŒývÈ¡¦bz'ûåJdÍR·=V›Ðï͵¨®×ïò®áw¤Ïš®9z=]ýÆFê6¼£®k0ÀÕýç‘ã)?kö¯ø÷iÙÒè ýìjÖŸFûø¾p„H�zâ ÷�7C09ZÃÍlV–ÉZ�ô†¾éf‡Gº8çxs¥ÇÉñQrïüúr�}�»¦‹‚¶1lYKY©`[·7(Á›¦®kˆ(Ðsh£BìÁ¢ð.BHÇŸ|Oq„WH•#í6‡ÇÆÉ�°VVlT•BÑfePòÂü"÷Oï¦ã±‡ßë­ÑÎLLÊ|b|4Æ�Ì$ –‰‘Q¯, 4R÷c¨×�,�^ßF„#£#t�F¬JnÝ5ÁÉñQÖËŠç—9:6½{w±°Õפ¿yƧh‚4£Ûé °xà\ãâÛ•oEî”®ÞRMOí‰ 1ŸßÜà3v±¿£P>˃ŸÞC7ÏxüÒeVË’›¦Æ¹vl”7–W±Î±eçèd{Ú-vµ ίo²×ÔÑ#kë½èï㌰ê 3UÅé幟8 9~zqŽÒ9®›ãú‰1~zq‡âýŸÏ™j|°¾A+Ëx{¥ÇVe9:Úʼnðöò[v•c£]nœšà‰™yÖÊáíçµå•8<—·¶¢¥�ÎzŸ‘<ãèH—ó›œê©áû÷rv}ƒÓ«ú}$3´ å~Ÿgç(Dhe¥s<13Ï‘]õ<[\^¦ÈT6Æ�gŽO[1\ÜØÄ|öà~~½°ÄŸgÀ9—Ä£ÁÙÞ:ïùºt3Ãfeyןhåî«U´sõþÑd¡�ÖAn5ŪÓ’ªÓÖù¿b+ºEÎÆ 6žFت>Œ£îtÔ 3uêŒ"`Üv'^ãF“w(�°ÎZë¸éº[hµÚôû[<÷ì3œ9}š×_}Å ;2µ'N299Å ß§Õ*øÒ}•N·Ë›¯¿Æòò2÷~ì~^xþ9Þ~ëM~äSÜvûí<÷ì3”eŸùËgØð—.h2ÙÕÕUn¾å^|áyþÄ#äEÁ›o¼Î«/¿ÄmwÜɽ‹÷Ïžá½wßåòÜÇŽ_Í`0 ã�°UUñÞ©w™�›�I}§§�Òiu ¢—ñ 8_ÃR™t>´¯ÉrE„V«À9G§Óezß>ú[}z«+¼õÆëÜñÑ»–ùÁ÷¾Ëääöç_çý³gyûÍ7¸ó£w“eYÃÛ\ߦ g�õÎ8>)dàÄbžÚ W‚¬s^ÄÊt¯õ¤�4LتBgiE•ÚÖÖ”ïœc~~ž�� ½�ñâ/Ÿ§,Köî�æÀÁƒ¼úÊË,//ÑívùÊ×þ ?ÿÙO¹tQñ÷'§¦ãƒsçb_M��(Œ A1¬ò4šÇaÿþllnðøÏ¨ñ¤ÛéòܳOpàà!>þð'ø»÷×1ªáòÜ\L,"¬&FÝßõè÷û<ýÔS<ýÔSäyÎç>÷yŽ?Îêê «« GuìøÕ�œÇŽçâ… Ñ`íÎû°ô8sú=þËöÏøù—ü?~•/Ý5Æ:*kÙê÷l Ô(à9Æ y^’gJa5cšë�5¢*Ï…"WCB°u©ñHiÇ¡yEŠŽ!ï&7ªèö’yš¢ªpƒ’²eßâJÝP1ªè3꥞YGi*_åK1al­õ �JaÔ*CUiŒ°FÞùS4on4ñkåá{¬sTVs-ˆ-5Qv¥ûc™uQµ¥âÀZ*7 t¥:¢WB&r‡‘\ |‚*7}Ä_ŒJdŸ3ÍK*å·WŽ¥O¥Ã>ÓGýDƒ… Ì_jÅoð•,«åç%!FE*�²�Å™ W ¶R(¤Ì3ö<ËÑ$±x~á¼AjÀóŠZ!Â1ºôD〞Æ{æS †ãQÄy ~—;� o�NVësp)ˬ…ƒJåpµ 9‹Ë¼r_Wj|ô†´§Š9˜VFÖ1˜Bp™Kàƒ‚7bXs^Ú®•ØuÔ²'ÚÐ ¡Ï‚¬—�BÚ­Û¿5ïLežác˜ÒQßYN‰ ý=|·C׆ÝèÒçÓ3ˆ‚6¢nGЩ¢ŠtŸùmg¨G9àáÁ÷\µôšM®‡÷]©oþ}�Yl¯ ë¨ëðaÏ_ùˆºŒdÁÿUðó.KÚJË(¶b&ÂÃû÷0»¹Eåà ï£K›Ì'»&&É3£†B )Þ¿Wû›|¹•óÎJ��uÜìó2¼º¼ÊéÕ5Ú·‡ÉVÁÅ�Mû&û\·Ãx‘síØ»Ú-.ml±°µEYÕ™ÉÁ9ÿ×FÛ¬óžÖ{ß9MÿÚ8×M–3=µ‹™…y:�véÃ¥Í-œsô­%³ÂÁ‘Ùæ»Š‚W—V˜(rîÞ3ÅxQðèÅ9*çøô�iZ™ág—æ(ÅyYöùà*Ëú†*Èæ9 ÿ:;Æh&t²Œõª¢m„×—V9Üí°é,ãEÁO.ÍÑᑃӬ—Ïø$¼7O�sdt„ Zg­¬8·¶Nî*m~vq–¾sìë´É3Îoÿn‡;÷Lñý4Ag¿²\5Òe¡?`Õ+Äß\Ye­¬ÈDÉ2ÞZéáМ׎�òÚâ —Ë><|`/ïø$ÊÝ„{lnn‘g€dºÍ4ÐiÕÖ¸-§¹¬ƒg./°:(iM¼øÁº¦Z‡Fº1Ç�ˆpÿôžœ›�Ð>›62UpæÁË÷•�þŒ”V/4R@<í ]Ÿìµ„†Q~¡p¤n3F2¹þÓ( cœW&ëü =ÃÓÖ·£ÈÚ\âf^yýWôû}fggùêŸü)UUñúk¯rìØqîºç^œs|ãoþ-‡®:Ì€ÅÅνÿ>÷Ü÷1D„n¼ ‡FÜ}Ï=<ç½®/]x‹ý¯fæÒ)@=´×{=Î�=Ãþý8|ä(…ç…ãã,--211ÉGﺇɩIž{öi¶6·øÂ—ÿˆ<Ïyöé'YYYáÅûáðáëÉâöS°^ çlSô×mPÓ9§¹Î ¹‡¤Y__g~a‘~ﻬ¬¬ðé?ø{§§ùûo}ƒµµ5Ä÷Þw?Ï>ýƒrÀÅ ç úì߀îÈ¿|þY–—–xä3ŸÝ6Žu¢uÇðÚ/Þ ü×Dç¬Wf8—SJ¥JY'õše¤./jrÝ|�ÌŸÈy3BÝu÷=ìÙ;Í�øýÐ=~5o½ùƒÁ€­­-žyêIVWWUãíÓO>Á¾ü.ùd¼cÝ.­Üè–Ò¨ò77 5³UÕ<¾( î¾÷>Ξ9¡|z««”~–—ùÖßý Î9Nœ¼Žùù˼ðüs<ðñ‡éomÆûöM�ñ_á�؇e9`em�Í­>½Í>³ËkÌ­®óþåUzþž’ï}ïÈóœ¯ý/h·[±~éò.„£,|Øáœ2‡n¼‘7ßxƒ™Å5~ñò|òÖCØAI9èkNÔ0�û|]H…˜Ò¯Í;Z &Ó±ñ�ÆEDÉÔsW±çpãpF¬æ>éªx¶æÑò²,Õ;Ì–Cò Û70P’å „S¸ÄâsYûzè>Ju‰Î;/”Xg(½üg�—?²àñ®^ìÆÚh(©l…+�æÈtµU=µ‚Õ'o~“+c©œªu�¤*±•ñ05y¢s *Æãf4È…ž7lx2µ¸¸\žÂÊxc<|νšw8‚w¶×PxØ2jaCžØ_¬PƼ¶}¬(ÁYKHæ 5’y–àà´(Mk£áJ¼q"õLÇ‹êJ N•´“Þ·U¼ÑFÃWŒÏ1€O«ûÎÝ�Èâ’kÆ‚±º‡ÊüB#$Ø‹÷©�Èëe»Ü@f¼w½�îJôÔü>:Ä$åE˜iB…3\ï´k$©HzmÈZšwÕOù½µW”©ŽÌÐpò®€Ì&‚kM6zJý7Dšø±­óhès5´i»D#BÄ@+èý"ÕÖÛ{©÷Ae\�â¿ 5 ”¾ÞX Î�µ2½îO ¼'F h´^œo…` Q“øˆ”Œ8øõüÒJºÈ邜£z‘mΜ�qpÛÆª)c§�ŽœƒmcI5ð‹+êrkysûÓÛéKu»µÌÕ<\ÝñtCgz]в:êeø¹4BÀ$ߥyÍé_å±¹/ɇ­ÄrÒÈe¤ºúaîat¸C®Ôîôø­?&÷ ßç®ðy‡2¯4”�{’(üðÇy:ŽžŽáGuÒÆ%6a;C$™×ÎiWª¨�ÖåTa¡ë‰oƒÉô”xz%‡ñ!aAH=øÃ¸GE¿‹ �* “û×�M‚'Ùfþlj£€Ñ:7qáü»ƒ%8(ù!æ4aB.þR÷T`bâCÇTéí™f…0¼)5ì´ wI¹ æœ*”Õͪ^àLútÂ8·Ä !_ ÍÔ›uOha¬Vá„Ð"/I&mIIþ¸8lu'yFá†ÊLŠs fÛ/5‹­Û_ˆôFæÇ1òŒd„M@ºøíÜëuÇ„~¾/-C†Ë½Âsi“Û<ØØ0Éöþ´Šéݤ_×¼zGP¯”mVæÆ;s¢Ô»:½&¡~Í»ÙÖ¡ž¶õ ¿‡¹à7(�¶ÃØY§¿À±ÄE� ßõÆ!3ÐÊ eQuØ|†”"™…¼räIiåT©æÈ¼aÀht©8*±º‰°JoÖÖ‹obB_4{ ÂB€Å«Ø†a³}#œnTBd–*§ž<ÍAðT»Åî"çÜÚ•s,üja™–§OœÓ¼ hÎ�ÒZNy#ÂÑÑNŒ�ò¨ÿ½´º‚fÆ€÷lþååE6ÊŠ‰"§�„õ}‚_Bp:ÉãIG„;wO2·Õ�¹nœ§e$Ö}`-+ í¹¤®SEÁfUÑO÷"ÐÎ|Ä€©#¬_ƒ•£_ÚÚ0àgWP2§Õn–±‘¥~ÿ£î‹L¼rPT!›…u؈ב¯4t_ óúüí7ßÁ+¯ÿŠ¢(xâ¿àŸ|„^¯Ç›¯¿Æž={˜˜œDD¸íŽ;Ù½gëkk[ÿî{Kfgfxê‰Ç¹ç¾û¹ûž{Y]]áèÑ#±Ž3—Þe~öL4j}ìc÷q×=÷2?™‰É)~ñØÏ¹êðaþÉ?ýs–—–øá÷þ�V«Í×þôÏpÎñô“O°¹¹Éòò{÷N³k×n&&§ø«¿ú+@¥Ç�\¯FE«Þ±bUV±ˆNg\ÜOIcóWGªB¶¦¥~¿O9°²¢ó¬,K.œÿ€«ŽevæÓÓûøÑ÷¿Gwd„‡>ñ<ö¨zÁ?ô‰G˜Úµ‹ï~û›ZV2‡ÃäœS: bµ÷ð58þêÞëK’ëLðû}7"Ò”7]UíÑ  a IÈ!¹$‡äpÌJçHÿ€tô W­æìêA/ú$�ÝÙ�ÝÙÙš¡A‘ @t7 Óí«ºËû̸W×FTVÃÝs$Ýî¬ÌŒŒ¸ö»ßýü§”²Â['ìÍÝwPhmìZgB§SÒ-KÊR»¼M¶rMSÍù+64О={˜šÚÉêê —/Yëÿ�>úˆ‹/Òh4È‹‚……~ò�?@D¸ïþ¸zõ*gÏœà±Ï?Ø„Áׯ_‰|G\Ì{æ¦YØ´y¦è&–’Æ^záyVWW˜œš¢Ýî ±ÿÇÆÇyìó�óËgŸ duu•9¬âòƒ÷OÑív9|ó­¡ÎFžqx÷¨Œjʲ¤,û)KkáîñæyÆÌÒot�gßø�ù•uºÝ.ÿæßük¾þ�o°sj'¼oÃ]�ïØAÙ-CbâŠ�7ò•\l\ú\ÐÖ½‘…kd~^m «±ãç ê~.\®+0å”�7.ħD~4Ûn‘¼¼ÈËSJ”VV-Ofxœ˜¶ÙQæ¥ 5=Ý�®�+©gÀV¥@ä_"ç”ð†áÏK‹mÛêj§¨06LoPx$�Ø—8™«x+ ï¥Ý‡–ï6Á¹B)eãû72h8C?±ÞÞÓ%¦V6=GâI w^V ÄÉ…�¼ÍE2P¥ E< X{ٟ岨2I»ç"+ydï[�źp¼ÆåZf0á{ªëYã”+ü[Z«>Qç¦cÙzoï{¤ö½×3'ð÷¤ôJí$x ¤¼µo;}õR¨äšà=R!¦W¾J!”»ßsªŠ“Ô]oÛkbÓr£¹Û®ü1ÏøR_�OÞ¢Á+z×áíl-B²{D\•R{¸6aš‚ˆOì¹”+HS¯Ø­Pøä;A™-IE™$¯¶(°È>õ*q'k{Œà–U²H…0N'À‘ p°!KL΂%rúRñ³Ÿ·ä~¦ÒÙ¨»õHåw¯G Ÿ Ž`€` ]º¾ybÔkZ½+G¢©MôY•.…v=¢ŸMâÆHE¶¾SxC‰è�áîsJÿ.&q*×v/übÒ/ÉÏ~Â\÷B¤®�†ô¬ÄÑKö"Õ@d),pd&æ-qD[˜'¯*ósbêhâM<¨âËÐùvèXx 67&™©\ŽÂD„ÐÁ“ÅØy y'üCZœÄ© ‹Y›#©“Æýß:£±øùöVã„ý·�к2GÒÄ¿9M´SYsf,Ê{{@ÝäÞø=ãczúP$bñŠ÷hb-ûß³Ì2ªy¢ÈºšŽ³¤,�`Œr‰œÎY6‚µŠKHÎÊ<Ù�~]Ä­›�åæPk%Hˆ)€2¦¢Ø:“µÖ¤ê©Ò;þÿÖßãˆVÝ$uX¨á ñ0S¯Ÿ †@ômuu¬m‹D£mÜwÃÖþ¦Gß ÇZAWŸ„°©7Río¨Á1^áœ$Áái&Žº®�ðk–&ö /o8/ñ<³g‚vàŸº:­Å«‹³Åh¤Y´V�æ½õuÖµ¦!Š–‹ÃjŒáäÂwŽ …Z>XZá¦�>]|å©V“nÒÐHQ0RÜÝÝäÙy*æâµ¸ùf¬`@;¸vg|",°á·œÕ‡x< øØÛ’¿ø=î•î^E_qâì¹Ð·Í­&W×81¿ÄS»',xem�ÉV“Â1Æ÷� [ÂÈ6µá€S¬vKÞ_\æ®Ñ!N%!ŠnÝ —€XÐ¥¶á´ᦚ"tKÍc;FC›oÏ-òÀøw�q}c“có‹Lµ[<<>âx,¡ß­ÇR·ËmƒL5;ÛL2Ú:H1H<-WCõéyíσ£+Dh5œÇˆÑœYZ¡Ô†££ÃLõ5™qÂAk‰?\Lµ[ìëkqra‰ån—ÏMŽÓRŠ·æ¹²¶ÎíC 'ÖðÝnÇ®±Dï�–(îÈ 9#EÁ©k…¿R–”Æ0Ú̹¶!ìl·x{~c wŽ ¡€ßÎÌÚpCƒýà¹Ë3lhÍåÕužÞ=ÉÛs àæðòÚ:K�’±FƒV¦˜^Ûཅ%öõ·o48±°È¥Õ5”_Þ5Áñù%>Z±ë«DBÈ,€¹�M^ÛÜ$a°ÈY+5¯_·yevc#(ö ôÑ—Ä"ßìv­€!Ð"<ìÁr· ‰ŽN-.Ù|ÊÎÃù•5Vº%|zbŒãó‹!òx³ÁrYµîW­"ZÚ{Å€…Ay—xí¯[xðÝJŒ]ÿ •Õ#S6”�µÒ¶ç°7šTbÃŽXË^x Œ ccsbŽÞq„¿Ír:�¯¼ò–––èïïçÏþâ¯8qìm:�GõçΞá›ßþ}}6oH£Ù¤ÑhP–%}}ýÜq熆†X\\äúÌy.]8 À�¸õÖ[YX˜çÖÛnçô‡páüGc8|ó-4[-††‡™šÚÉââóss<þäSÌÍͲ8¿ÀK/<ÏíwÜÉüü<+ËËìÚy�þ¾>kA+ÖzYD[ašv‚(¥<4[Ï1¾JTæôõõ1::Ê_|šf«Éû§NñÞ©w¹éÀ¾òµ¯óö›`vö:27Ëg?÷yV–—­¶1lnnðáûïq×Ý÷°´¸ÈÀ` …•’²>A�(kQmÙ%ã„Â*¬_–Å~¡ ¥[_O%‰xÒ[ (æfYZYfdd„V«E»Cöì¿é;&&xãõ×âkßøS~öã1;k“> 233úþΉclll019,þ¦FGi6r§Èi5rZ�‚,S¬v¢Räêôtð’ã¶;îä£sg­¢r}�÷Þ=~ϲŒ_üüöìÙK_?ï¿gÃQÝrëm•=QdÖ‚V;/¸,ËœrY‚’9Ë„;‡¸í¦ ¾ûù#üäµ÷ù›_¼I·Ô|ÿ{ßã»ßý.£££¬­­Q&Šþn·ó‰•¦&''dii‰×ß»ÊÊê& J‡»<›n¥™XA¿¢t¬³"Ë„¢¡ÈŠŒ,/ð‹lŒÆ¸\N†MÞò`™+¨V†j(P£4Ýn×YýciûÂØ2"6×A‘#…†MÁl¤t·1èn‰`PŽ· 2Xeûìi*ãx U`Ãù8a}VdäEŽÊlÜ#)mâ]Ó)1 2S)!Ï2rÉ(´¢0* �Fä%+¤v2•eÖÚ½PV¨íÃÈä–×Q¢oéMœL+7q÷“gAA`rÐYä|œ{Œ±|¾ËëàyÞh'A–'áoäåLbˆæ;#^�ìÆ$¥ ™Át=�êë3)Þ�ßû>¿„ÑljÊm~ q 1¹°{¥­WG¡¬�¹PÁ¸ÓdØ—;ã¿J-„‹÷̆ÄÑÉÊ\_%rÉÆ µŸžd­•_oû2Zy�âÈ™W" ïV¼<¨ÂzŠÎý�Ò%û³$kW->Li Q©g4V¼LÔ Ùƒá“ñ œ' ÒWœ£Ý~/µõ¢-íXŒ!ðñ6éo{Kü$x½‰„R"2¹®èØi©„ïQn^\¥¥³ü³�€y4VŒ~Óù´ó`$Îðzó<¨Äêíåh ×1zCoWzrÞ[—6¹ëœõ Ÿó�óuTûµM\�J-éÝöþDØX‘!pù «•$ø&Ôèþ&ùœ òí‚Û¬L®ÍÊ+OÞ}&~ö›/„¨±/ã6vÏ) suÃIèuá�(UÈßVWi6á«¥ºniôåž>ºIé Ì­¡ŽÇÍ%:¾ U ˜Xu­™-k[éŸÛhʹP‰‹Ï%¹Š h«.„ ‘„© ß-"Há¦Hâ}Æ# ÷=lô�ÔÄý”îU©Oªð)É}nR++6xT‘­þj|Dâd:(‰ÈÊq÷Æ©Î+ ‡rK·NLl<¥S}�Æ�Î¥I*ÿ]‰%"üT¸9 †=a>AÖ1žAõœ@Â×!µ9öDZ¯¤™´UE„µ-Ô{ŸŠØƒÛR1|îIê·fQ¤‚6VTÅÛ–ÃÁäñSÇÕ1|:ŒTXèç!r}•w/XöÖ�Æ1[“Q‹³ðòU'!t*×ô˜¬Úa‘t/Ž!AÎ�/\¨®Lò\Üð9ôÉ” pz¼í-b…4\\D\.lTi™NßPXnçΞ+¡ÈÄ͘³Ò* :Ú†MÙè8ÿÃÒ5¢…ÒÖ¨ÊÞóaK Ž‘1ʺj…%õ­ ;(°Œ5Æé·�rUû‰Ç³ñÊ�d�=^ðmùùp+ï¶×'±ü�õ¥ï¡„9í±éMtSÖ$µÿÖ7�'©·Q'Cü35°ëÑ¿ ¹á”[ˆ­ž¸jûÒ«þÉápªá´  Ðñs2*çŒìøu�öºU{ q0Y'€¶{À"ì¦Çú%c 0b ­¢ÉÚæ:ÚÞ]YeL©`5/bãà§åˆS¬—%m,¬Ðs¥Óå�¹sayŽôÅçfQb,c䥦à`-ɼe~o‘$°‹xH´íÑÂØ ÑàÝócß]Ÿvõµm¬``Sk ¥ø¬ë÷ÙåUŠL±Çy@œ[YãÔâO�¹ ÌlnrÝ _ŠÇD«ÉcSãtKÍóWfh(ÅÓ»'éjÍë×­èð@?�"'w¸­¿ÈYLÂW6쑵Ԍæul²äcó‹Ü2ØOÇØ5ùÅe×ήIf66ù�K²ûÙ�~úòŒw\Âàu­ùpi…±fƒ«këìïïãg—®ÒTŠ»Fi)Åïg­’àæÁ~îäGm²Î•nÉMý9í,££»cøýõy–º]† BbâIçAòÊÌ,¥còåõÙyÖKâêúË.D„ÓK+4ŠèÐ, ¢Â€  û²‚á½E+4ÞÛ×fO_+$ÎDqh Ÿ‹«ë.A'¼¿¸Ìš£B>„ýɾ�vS^ؾR�}¶4&öKE¦è$^™HèÃ?­ÄÁæ ¹oë1 Áa×+ ,ä–øO‚£u ÷·¸ãæÛ9~ê8ëkküø‡ßçλŽpÏÑûlßµ–Ó÷Þw‡o¹…ýècLLLðÂs¿`nn޽ûöó¹/<¾ý:º¶}ÿ,&„zIqw çE0:ŠQ”ç5°øHãpº1|pî ‡Â¸÷èý¼úÊË¡Íþþþ�em}�_>û ««+ŒïØA·ÛåW/¾X%®ݻùí+v:Ì /¼Frh×íf“v³ ÝlPd�{¥FbaÑçp|žçœ9ý!§Þ=I_?âÂ…óœ|ç_þê×8î'Ž`px˜– _TBð)�fá O4Ž6W“Y/c=D E‘Ñ(„F#ã/¿p÷ã_üͯX\Ýà—¿ü%ßùÎwh4›¬®¬„9:xèpðjdyéãs\¸pžG>ýžý}=¹ IDATù3tºš7?¸Æc·�“å†.B&™d4› š�E&42ãßfä�Œ¼‘“yQã­Kt×Râ ÜUnP¨¦BšÒp‚B'@—L¡Jå`ß U)ˆDŸçƒDÞT+üÞ4N¸nP9 âÌÑÆ`ó%hû›jäd�ÂZïg‚ÊsT‘{@FJx É­"!ï‚ц<³s"›Ø˜çbC6hãÊyؘý“YŇ4 ÕÌP­ÕPv\\yq|U…d”€$ È3ÇYZc%—Õ¯Œ·Ô§±a‹ % Â”öà!á e";3IJ÷Lˆï]JŒaçÑ”! l˜5èRÆ>ïçJžÈžÈp `­pÙ$¹BhY¯(ñ2�À—ÖøÝz;.ÉÄ�ÍÆÖïÎj_™µl8uªÏ~w1ÃÂeR`CÖ$r0ßfENà¿' þÉÎÙºB YÇÀº¥ÜT¼§'g'É­þYÇç…ëõ—T_ž›1˜¡9Ë”K�Û|Néæ÷˜IäL¸VU#ª´óBg©ÀJlx•(BÅR{OJe<#ïß*B®OL*•ðµTùÀ•-ë³åj½ž€ {ô+}¶þÝ_ëÝbïö„íÇ‘ ÂÒg{™l·¢^˜ïÛI= üu¿Gíï[=’½Þˤ—´¤g_RÏÿÛÿŸJ¯5Ž ®<®tF¸…ƒL¥­2òÑ=Ú >êu{ö'Œð„ªÆ;JÖ&VA9`‘‚D'”5ÁSÀÕë‘‹HÕ¢Üáã=”G°éa“lv!'¿§Aàa+ŒÚßLTºw¡š°Õ>PG©àÆ ¯!bæBÁª]mÚkœMUh”ÈÜ’ƒÉýö‡Äï5<”&â*p÷XCM ˆ•yº8¯v¼ñ$Và£vø!À‹I«Ì]½$ëh’ΓXׄ`A#V­¡z!À’ .„¶cBL“ ?Ö 3œ´ï‡‡³¾wއa ‡Mœ‡ØaC"Ñ!PÕ>{°±�Yõ°h³‹;B:ªWðuÒÇúyä«�kW‡ñdŽˆûÜœu¿ï‡kXðžµeö›ì/ BºzÜ»µ1ظƒI»F¢{¢’”b‰LÏŒ:aCpoÏ…B+öGl²ØÏT«‰6†_^žážÑ!öôµÃün$VÑûûÛŒ5 0¿Ùa¤QðÀØ0¿Z\ ÷Œ¸dÆ”vxÁ(LfBBÐ÷;|¥5F§Ô|´ºÆž¾6OLí £5Ï\¼Êîv‹{džxõú«Ý’=}m†ŠœÁ[�±IHÅÉÄo�̰mû¬4ÖêKº=t÷QŽŸ:NY–\™žæ›ß¾�Õ•–––¸ûÞ£\¾t‰W^þ5_xòIvîÜÅÕ«WxûÍ?Pv»A‰011ÁØØ8›››Üs¯U l¬Û5]ZZâŸ}ó[ÌÍÎòì3?edd”¯ü³¯cŒáâ…óc(Ë.EQpëm·óѹ³dYƯ¿Æ¾}ûÙµk7£ccüõÿú/ìø³ŒÃo£‘ hEYJ %6„�gkÓ\ 8ÚÜ''u Š÷lét:¬®®‘ç9?úá÷Ù·o?_ÿÓo3?7ËK/<�ˆð�?ÿKÖVWù�˧°¸0ÏØØ£cãÌÍÍ16>ί^|ž#÷ݲ†�wW<žÎ2h­ �ô/ÿ¼CâV1àéEËÊ+w¦jÝå�36¯Ã-·ÜÂŽ;x÷ä;�ÃÃÃ|tî,çΞ¡Ýnóð§?ûïœàªËð™Ï>ÆêêjÈŸ°¶ºÊµk3¡ÿ“““¼ù‡?€›ÛûwÑjôµZô·(S"X�œT1044d“ îóüýßý{ëìÛW®\÷ýþµß±±±A»¯���AÞu ƒÑÑQŽÞÿY=ˆD ÝÈܘãî0ÎEë,„<Ê2÷*÷ØÁÿò—Ÿæþ¿^äúõë¼ñÆ|éËÂÌôÕPÇ™ÓVÖÎ+², ‘{•¥ÅEî¿ÿžu^'ÎÍòÅ»¦l †,#S™Êi6›4› ½E´Kœ‘7sòfNVääEž( ìjŒvë¯ YR¤)¨–S ä\J«ÀÑ>6~|„Nùdã�½ªK.Hœ WTP øPŸÆX…€A¡Èª™#y*pÏ"VÚç²Ìe¥ »¶y–Y /Ó!ÇÚ5˜\ù9åB @¡�FŽjZÅ€�µ.�†$9¼Ý†òîUN‰a”8~Öò ÜÙç�Ež"„eL�q+ü™mäÆoî=ªÈ奤| oxIj%*‘±yþŽ À¸| 96ºDn•$^VdœbÀGñF¾&3ñ@H�LëBö P+nL`aÁ(‚7· Õ¨b.ä�ÏG‡6.l• Æ�væìN²ϤHŒ£ì+Ú0ÆqDلωÓX…@¢ðòB¯0þ£íz‹¸F=íy0PõN»Nz£´ÿµu üàý8Óy Ä'ÔN§.Ú�ùɱíW Ì%þ´m‰£ÞúS}‘Ò±T62i«ÐŸ~¶t(̧¿§ 7�2õ¼¯Hz5y2�K¿ùu­F·JÚŠ5U#v$Vþ©Ð2ù.!H"ß”Ø_³Jñ ¿p¨xÏ[§Q�«Uòˆµß½¦SÅnàÂÞx¥€'D¥SQ0¤Í§¨-ð¸e¤„B¨ VáÖ�7, ñn‚ös Ó¥ £TY䉊ԌÎx¤ãŽ‘Ò[#'õ…v«ÆÁSLÖœ\m`Ñ„·6©­cÒxxÜX�÷©áßÊñàKƹ YÁgNW“‘�̃YØÞ¦ª·ð¹€ˆN@¬×ÑÃÒ–ýgoã©}).ćÃ&íXÂXc‰ì.N×%dF¡M†6B¦™sõÅ DJ­È´Ø¼SŠïØrÚ(J#ÁmÞ'!³É‰­Í›Wmh‡¸tå€÷„›Áe¯à,åq8’[~“BX•dP® ÁÓ ©GH„+Ïœm(]ú„ MÚNP]}Aã·dOG%Ïvå¿ÂIøIÊ6Íøuõ]¶Û6™—mž‹Š·­;ÿªŠ�X•NÜ™#0»*D±äyEZ3&_LåC��¨u¼§B&GvpeÖ†[8¹º N1pne•ÛûÃ9¾·¿]9q|¬}Ÿÿð`?M.â•éYîäÑ¡!¾wÝ UßxÿC¾úð¡ùàññ\LæMcQ™gä}ÏMÀU B¨':ÏÿáxÈ/p{_#Yιî*cœÜAxljœV–±QZAÜMÎÒz¾ÓáýÅee0ÏY/m’ÛGvŒ2ÖlعreïädL Uõ¢ôŠ�E­)ŠœÙÍ'–±Vö™#Í‚VžQÃJ·ä¡ñQºÆÐÑš—gf¹e°Ÿ[‡˜^ßà÷×ç+9<$Î@AœU¸7ÔÞ%~öRò°i`Íå„ÈÅ&×½¾±ÉX³Á~mØ××â÷³ l”%�/SüâÊ5ÖË’ÆGØÝ¶¿/u»Ìnl²¯¿M‘S&´L‘ví0.減cØÛ×Çr·dªÝâ³óÂ}cÃôç9/MÛÐ w� q` �]¼Š1†ånÉ-ÃÌw:\ßèÐÊ3Þ_Za­,ÙÑl À›s h‡ûÙëú¸ÒíÒ(K¾´k’c.n¿ºZÓq8WD8»¼Êz…þÇ“O}‰“ïœàÝ“ï077Ë“O}‰_½ô"«wìßs˜á��@ÿ•¥Pv¡Û5dbÞ Ô{ LÈ‹TñsóªÜ±²²ÂõÙYæfgY\Xàýõ÷¸÷¾û)»]ŠFƒ¾¾>®\¾Äìì,÷=ð ™RÌÍÍñÃïÿS;wò­?ûsNøç?úˆ[o»£O‘ÖOóÄ0nÎClL ?‰Á¦UžûW³8 C€wÏ�amc�<Ï™›ŸgdÄæ¸Ù±c‚§¿üþþ?ü-�N‡õõu6Ç×"Ö;c}�ѱ1úúú¹xá<33Ó òÄŸæÚµfgí¹´s|Œ�¾– #¤hæ ´\ƒ �“–¹ÙY^xþ—dN­²ŒŸýäG:|3Íf3x:|3G~ïX__gee…±±ñd.…Á¾Â®¡ÃÕÞ�Â`0Z[…­±Šp›ƒÃ~Ö™áS·Lðø]»yîøE®]»”Ã##,ÌÏìÄÄd%¬ÒVÏâj1ư/ɵqêâ<}ͺa ™ÊPYF³Ñ Ñl¢ŒõêQy†*ròfAÞ,P�ÂZÜ‹€)Q:#ë:cS‚ZECæ­Ñ%ÆZÏ¬Ü óÉx•qBU¯µ4‘žð8UcÛÓ kü“‘‰Ádb½L¤¹Å­µ÷:”¦‚f¢ÈT qˆÒ–lœûÒ*B0VÙ¢P˜<ƒ®`Jmó*ùÖòÌ…ûW§¿O¢kr±apB8 A�“œÛv¯yár¢%õ|T²—"wßÅý"–w¬ðŸ �€lÛmE™q웩 ±/âÉØ—·D7î@h»kbÜ\”‘uyB‚aï à®Ç¨ã DŒCãà$>Ú­ƒçJý„&ûÀTX¸1ÞÖÔ*¬'�+‘77V6@©1ަƫ²†—�ycÙÀx‡öMÒÏXL²šigãêÆ5Hß«÷°eÏÿ¼—ÔÞýçrnmˆ¶{XiƒÉT0LRV}f——$2ûQi(‹0†­¼ëÖ‘HïÂc R\*7úËu¦Ò—Ì��¨´({pØiµñm[aýÙôgsƒ*j0¾]ÛÞßK>°ÝóÛ=›®UoyC*ú:êó,=^~¦†¼B )á…fžïN=417AZ_Ö£ ©µã¯y¦¾þ¿Pn´F[÷zåå�"6çOiÑy¦q�ñ—|8V,Å$„�Š8â>h]#J©Ê‹`íOÎú,í Vq›¸ØáºâcøùÐ?ö´J÷y\?W‡œy�”ÿaÑ#ƒÈ…¸ùÄ ÝÒ£7™j‰x¾Ò©\ˆH: ë^ˆLâiì�QûãØ«ù}_’{ Ñ îÅcL ª¼< éZÛm7BzGr/[jIöz¯P6¾ÙQADðE< n¸­¼º~W‚s¢®Æô˜ÒdS'°aüAV‰â…Оˆq1õ|Œ¼“ÝÈÜX� �Š"±¢¯ö(ößÄqT¤R½¶„qJÕ Þ›Æ¯m:AÞøCL*Ø·Äß–y¯H�ܳÆëw÷XâoŒ-Ú—zz¥ZБHÒ€S 𤒡0S•�¹õ�¨0vŠº‰îÙ(¬«¶U äZ9¡½M4©´ ´ry�ìñQêÄ*Ûy b•FÙ<Ƕe{lh«ðÔƒƒI2Ì��çEáç8z•Àˆ�å(„´[i"{¿rsÖ:N \W l§qü“ÏéoaOUöyý�Iö™¡Zµbzýq¬}ÛŽ˜¨UU¡ÚÓþôjÁ¯„ß/R¹7õ˜J¬†è‰û> #ï­¾ãÏÌpžø]×ÙÃÖsKغtéq• �B]¦úœ/¦öñöéwx}y9�?·»¤»‹^ÅÇŠ_êt9¹¸¼¼^;-�NŽ¡Dxbx8(ÎMÏX+RñG«·â“‹¿è�ã&ì/!æðƒµ„Ll¡<Ï(Š,Ôùëãï†>=5ü)FGÇøÑ¿ÏÚê*_|úË  ñ÷ÿáo1Æp×Ý÷pïÑûøÅÏælmu•V«EQ¤®õ¦‚ϼÝ_ê œ�µ* pŠ16¡®€¦Ý£L¡[vyåí78pà>ôs.YðÊÊ2?úÁ÷ÐZ³s×n6Ö×øõK/ðð#ŸF‰ ᆦ¦vr÷=÷råò%ʲdss“¹ÙY~÷Û߆þÚµ‹FžÓÈ3÷RèÒÛà²Ä êò•+ìß·Ÿ™éiD„oýÙŸsì­7yï”=gZ­Y’Oäâ…ó\¹r™V«Åމ Ûö«¯ðÈg�{@ ƒ­"LSÈèJ›”Ø+RÀ ¯¢`„¯=t€çŽ_äòåèµ088Ä‚ËñT”`áùãJ£Ñ¡š.\_¡Ýjà—çã‹FƒFQ`L ºks 4 ²fƒ¼U EENV—ÊÌÆ7Øç”e&È$„½œ$|| $R…“ï¸q{Ã3_’!b\’Eec�k§”*]†XïV0¯0N) ^Ah6[¿M*ìøB'ßWJ¡$�cÊ Ýíbºe %wI\œ|»-´µ|÷aprÁÊ7ebyGcV(n¥¢ÑYjÜFoz¹ªpu¥4.TèL“|7eŒX �ÌÍ(ãÄoŽÞ4ÆåN°ù#ŒÍ8ë4Í®?J\s*°71ž¼5½÷udÚZÖçra!xøö\îÝ+RSÄ3rþ’©÷¥ç¯DÞ&Æ$°‚`¹øB÷ŒÏC˜ãþ/Ûò94œÒ´ºÉœ‡Õ3µë`B�쥤ð¨5�ð Õë¦ö½V„­U»ÝøkAˆŽåkýš'ü®BVŒº¡kil<Ôïù®zŸ«½4²Í˜$=u¶þè»ï*IÚía䨳†­|hoVˆ‚§íJ hés&þìߥvKÏÖ¥rEü_sƒ6z–èÇQgáM¼¥z¿¢u¤òâS½B¥÷Å—;‰rÐô9?g RLh�¨(±™ªÒgóXWE Uo¯Þnzyí=o[¦†­sØCˆL}Õ¶/½ž¹ÁÝßCXb‹¢Q.ÏQT ‡óªÃ€ ¸Ô38$YiɯÖ2W|Rqv½Ô€Û.‹Ä*¢¹±ö ¤nUúí�ŒCðð’zœ°‰ÜgKSŽîí=žÐN�~ù7ÈWl3 "¹%´EL«ˆ·ÀJÒF½-ozœ.¨‡q±À°¿xI¸³HQkÅ];X+Ô'(Z…Œï¼¸íŸ®mšÿ¡'’—‡C}ÛôØL‰ÅSÅ{DÜüd&ÂF8ÜÅÂ�Ÿv’„{ÂD‹¶Š;lº:lVN»íá"�›ˆŠ]ÑñqðøÓŽˆ¨áˆ­KD‡Dj¦6_~Œ‰WVz�„ I´ H× Å=œ§[W$®éïŸy5âÿÁ…QRb h§ÐQHGYZ0HP2#dZ(K�®J ?Æ#}¬•"šL’—2än�(cé\1X\TÚµÕbÐeì¶í©„}«uû-V(äâþFÅ€ó̉â$‰­Mrl»N¥6Á6À�õ£ék\wa„†”¢±Þef}ƒÉ–õtè÷VŒ®Ü1<@ÇXËúéõ ¦ÚMî±I733ËÁ�>v9«ð‹››|è¬ë•R½ù°¾‹ ¡Å+9¯ÔèÅÒâ*o—pïè8½¼J;SÜ\^áÊÚCEÎç§vðûÙ 6!t.B;Ë(”¢k K�.çVVi 9ÆÀfç)”ðÙÉq¦×ÖyoÉÆâ¾yÈæ,ð!š;]N/­ØðưÞ-ùÅ¥i 6DPi �’ä¶¡&ZM~í ` ËhаîpÆõN̳0:4’!*CÄyÏ&´ð†k›\]ß@‰…“ «ë!dÐ}c#¬v»œryêqþ;ZóÌ¥é ð 0’)›pSAWÙÏ…‘ ŸÜW•¥5$Ðøɘ\$®V�±©ëî£S’ÎZy€IØgëÝö�ótŽ'Û”£Ï}Ž}}}¼ýæÜ}Ï=ˆ³³×yçÄñS¿ÙlrèðÍì¿é&677YYYáË_ýW¯\áí·þÀ§ù »vïæ®#wóúk¿¬ õλîâýSïÒîëÃ'œ½ëî{XX˜§Õjñò¯^äÀÁÃÜÿàÃ,ÌÏñãþ€áá¾úõo°¹¹É™?ä7/¿ìÖ#çžÛï²adŒõ4Ì•¢TY ;Ê®¢ë£úXüÖ[;âE°øÒh[‡rtÌàà £##¼öÛWùöwÿ‚å¥%–±É…7YY^fç®]ÌLÏÐh4xá¹_0::ÆÔÎ]´Z-~úãDDøÆ·¾C_’/FpáuŒ[cðVÁ& ˆ‹¯â”Z,�eŒF—Ö -ø“º�xãåW�cym�F£ÁO<Áõ™†‡Gøôg?Ëk¿¼Ø& IDAT}•ë׬Âîλîâì™3ÌÍÙΟ¯œ—.^àüGçȲŒ»ï=ÊÅ çÉ2ÅÏŸùYÏ�n¢È3—ëÅ*«”K\#PÉÒéth4t]Þ”—žŽåå%Æwì ÕjñΉãLNíäÞ£÷ñì3?…� Š¢à±Ï?Îó¿ü+.þØ}E<ݬ@<É6�U69!±ûî÷š¬GBY–dYÆ…ó066ÎòÊ2›.y¼RŠV»òܨè²dl|œk33\™[¡¯ÕˆtGXe¹"Ë-\ã’ 73T+³–÷¹²‚]Ï[dÆ ã½×_d/�*1>L„³ô·Ñ°ÖñÚÉÁ�µæ ´§6Ñ.‡€�Øœ,ÙDbß{/_†Èjçµ`b4OÏ*{žíÈœ{Äp3™å?º é8%½vuå*ªââÕ;�¸Í)b÷°x/O¡Vø²„XMû ÃÎQj ëEd²10d鼦—LüR£ZKÏ&DŒ)1º¤,»V)²Y"%ҵᙠ!�®£Ã}Út(éâ=I}Î<ë(ààÍÃ^ÝÐ×ñ~Ö*Êóä*Œ/�ã^Q$oqN¤v1ÎO`ݲÛn9ú5„7IÈ-C̃Y‹Š‘ÆÕ�ª€*×S'ñ{�üÕ1lQTù ;²Þ¢ímëÞr×6fZa®ým.½­Þ%G`Td;á@Kz”¼›Ø¶Bc¼·¿ñ×úÝfË]Ž)™©8–ðpø­ÇlˆÙò[µ'þZ*¸þ$¥W[ŸôÙ´&ù Òc&zñ¤Ÿ¬Üè¹úÞJ‹ºS»Gnðò÷š×Ó:SxÑɡJŸóŠýkªä{:NU{¶WÿÒqÜ lA9õyüc×ã�(®oƒ›êïRY@Ëš©ûKÑýÄz:9©b ~IôM^øìáÆ!܈[ìÁ’ &È$Ç¡;®’ Ž�-ðhê{׸-bÒ‹IÑu¦:>¾�rÈTÿÔªL‘“ ýU¼_ü Ýø)±qÔµí³{Ö·vµÙ¤ý—$*Jp‡–¦¦¯Ï“ù`§É\¸š…jšÔdyël¤Ç%ñPâÚz­zB„ö.)œmEÈ•ïarÄDwD¿çM|7!¬�XQKä\Ü䆵®Ç¾5 ï–x¼À«ÞŸ-Ê‚T³àéšdH[�?§q�D»ypÖó•i3ñP¨:™úzÒpHñ®°Ç=øýcŸ¸nŒŠÂîØ=7ÉnÿçÂZ¡ÜT{8°×ü kîx'(——D\¬GG„4sûî ‚RÀz+K'Æ'øÁ�Ö‚‚!MW ¹#P­u–³Ù0ÎÈÉàœ(JL°Øµ‚h§ÕvqmŒô¸¥}Â)˜œU X&ÔÓ´�Æu µ÷ô&ºf9âC×DMñËÇ+Rpè�Ô*?9 u‚ýkOI§÷¬¯GŸêum§ˆ–=·¤žB=ëUKR_¬ÓW˜¢Ðp^UêÓI§ ÛÍ›ßë&9CMºß·›¤pÆ&mS^ žÞX튈ÔÖ´Ò#¼»ëÄð—®Ûïu7yÔuPà³€,�áìÊjP¼1;Ï‘‘¡�g`´Õ ¨áé?çÿ¸h¿zò=>{äv'Ì´óØܹí!p—$¹¤FB‹?/ªÇˆ'æÿí³/…[áÉ]“4EXîv`¿œ^X]çòÚ��Òp¿ÿan�ÇŠ1ÜØ ô1�çxšc««a:w��“çÊ2ÎWxzÉh’)lbh4rv÷µè8�óã;w €Ëkëœ]^å�ñ ôqqu�7f˜j·xx|„¥N—¥n‰ˆÐ5†"±°2¦¤ÈŒuÕn®Ðâ‚›2+Z)NXÛØ`aÙ*¾Ö?Äù•5¾²{üôÒU´�G&Ƙh6øíµ9:Z³ÒíRÃX£ ?ÏØÛ×âÔâ2­yp|”Á"ãÿœŽ–ªC#áöyDàô‡ïsæôi<Äwÿò¯øõK/réâE”ºÌŸÿÕÃôôÕP÷Õ+—Ù³7†”«0λÓàh�ÔOa­y=Òqtœ1Ú&ŸumÁ³1’úGÓ3¼rÜ ØµÖdyŽ.KÖÖV™¾z5ÄÅžÿå/0ưcb‚¡áaN`“ìŽ��óÄSOó“ü!««+”eÉž½{YZ\dmm�÷ß{ÏÞ78È­{÷Pd9™²Ià>¬ŒU4Q1°ß>VWVxèS�°0?<n»ãNöîÝÇÅ èlnpíÚ EQÐétÐZóÿý¿£,KvïÙËÀà`²„v�笀]ÛïÊ[»ù1Æ%$¶^eÙEka÷xTÜ;vŒûî»/àõõ�õ’ÒÏé'Q tË’�þ®Ḭ́ÙÕäEN£a…»Ë{ÚÁ¸õTS‘73h)hz!¸¾ûÐ2¹ñö>�d²g§¶JuÉ@¬‚F¹PB!t¨'¡õæ‹ÚY‰{–Öž�VˆáébÇÔYÂܱú‘v,� g¤2åÒ˹x÷™ã5ñJghcù?_©ãsŒ5Ü“ŽqŠÇ?ºq„( >L�ò6g:($l�=?•ðm‘è©òaŽôŠ·”ÍMùü|úGSÚ-ìK+‡Ñb0U&6 ȵÇšRw)ËMºÝºÓ…M�*…œÜêDÒ>;üaŒFSRRâC#·"B¦2ŒKÖ+> “²ó E•ã“Ü�<Ÿ$Žpßž'ýZç ¤ú%µÁ´¿ ó&B´„vqç!FæÞîŒü€¯;~J¯xϹž]ÃnÇðøúÒç“{?ÖZK*o±wfË-¦vÁŽ/B]0–3µû#³¿¥í«µß½ŒÏ¿œ’e»ÑÄu«&½?²IÕèöA¹á®x¥í–Æ$�“\‹RC�qªóîCpô(•)Ùž·Üzï�nªÃYý·ôž^ë²]Óñ™J‹¤˜,Vû‘ ðëµ{ã�øª(m0NÆ„ÃvƵæ„`•1{Hðɉ}?Šœ(³˜SBx¡Þj¦Ú¿í`:ô%\¯ù5Û|NüãK/™A½ø£À‹|£R >“ÇŠÒM“‚8AE\YÂ^%J�d² Q¡MT×àÉ/uEx\aº []°â}=Fž†Úéõîô®K’´PèÜ Ø‚€^�wü¡Ÿ"\‰Yë�€\<‘Ñ1vÞ´­¬òRÄF–>õH¾Kífød˜ ?·dBF¥ÄËö¥rÄ…õöW½9]óêSŸ¬ôÂÜ=:懛¹û 1L’!¼^9`ãÞ:H øÆ\QÙpâ¾Òµ±$=ê}¹Ú]ÿÞ3‡€;:=‘�€¥fâüV¦ ×±¨“ûëûÕýä÷m ¿¾e-G‚Ò®ÒVŠ]�é>ò{;4YE â,Kb—�€w‚FÛ„ØÄòZ…º ÞÊÒ5¨Ü AC!‚ó°aI´‚"wa8¼k·_cJ”Qhl¢ k|¤E(•B—†R‹URh{üø­U™Ï8#!fp–Y¼©µópðå“–Þ�+.?+&­›T…é÷KVK$ìüúTëØztm§xøä¥ òf ÝZO:\⇿¦ ;�XéÕ=¹ÑܘøÜM2TˆŽ€¿·§¶] í»³ÓHâí“VU©Wªï¦~Ýö¾NšÙö¬•„Ànßw0(~½¸È?5Åõ�Mæ7;v–ì NÂ$|Ú…ÝY+­ÀzÄ…�˜ït8»¼ÊÑÑaþdt”7=ÍÕN‡Ín—Ÿ¿þO?p¯Ý?�èöÝÄÅõûÅþåͽ!æiˆI­Ð¤,KNœ¾ÀÅk³|¶ÝÏ׆Gh9Aú™åU6J̓.¤ÐX£qåòœ/ïžD°‰dòœÝÎSàØü"+�.//GAïC·ßæ"Ø3Z[¹‡ ³kÜ1ña«ÕÂõ™õ ¾¼{’\)–;]®ol²Ö-i4ãÍúûØÛßæòÚ›ZóäÎ4”âõëó4^b³»Iæ üÄe-xu ‘ÌVPI âʵ(Àß“ç,v:o4èCC„“ KÜÔßfO_›¦ž¹4Íh£à‰�,w»<ÅZózeÊå͘|xdhŒ,³1íú£§Êû›ôçm—w`M—œ_]ãÎáVº6 è³—¦,ržÚ5ÁåÕõöçñ�;(µáRžÑÊsV�aNk&ÛMºr%¼µ°Èp³A‘g´²Œ3+kdÀm#ƒ™âòÊ:ÃÍÍL1Ü×dB—–,øpu�fž±£ÝB0\Z·�� õ£DXÜ´Bäí&»úÛ\\^¥ë&¸tÞŸg�µ.ÀþÝ»œlfã°‹�9ìË‘¬�ihcxsΆFÚ×ßf Ï9éÆ=Tä<4>B%àÊÚ:i¬íJq¡/l¾*�àΦ„øoÍXatí>ŸA3SlÔ’ÿ1ÅŸ0áÌ ÆžÎ··üŠ õLŽ�qxßM|xþ¯ýîwœ8qœo¿Å½Gïãö;ïàܹ³ D¡ìíwÞɾ›nÂ8wö û÷ßľýûQüÃßÿ Ïsüqþðû×¹ù–[Èóœf«M»Ý¦ÕjqýÚ5ößtQнûöñâs¿dphˆoýÙŸð£|Ÿ�ÁAžþùÐöGî¥YXóÙÇÈó‚WókÚ©Ç€¹Â ›%zmÙèÚÊ9Jƒv÷^©!‚#^¬§€UˆØú\z3WWùÞ‹/¡µæÈ‘#<úè£4 öîÝÇÂü¡�E»ÇXüŠKkŒvz¯<7˜Ì)Z<�+È­Z+”–ú>€Uæ.ö�(—ø]k›ØXC)Ñ8eƒ¯ËòâÆ¬2ƒä-Ê+,)_Fòn"?殨äûª̨Ö?V©\÷¤§o2Os;Ã*œ×‡6˜R£•F«Ò½ktfÜرKf’øòn<~L¥rF‘òQJ&6¬S’c «àÅAÀ…™Œ2a9ÀÅ7jËÞP” ~äUÚ+@“lµù2‘u9"CRbqŒ§óxéÅT¥7½x‘jŸâ=Rû|£{ýç?–Gsë ©?”rú>¦»;å·ŒÛ^è%í½D¦öñÆã0µµ÷ºh9~ªJ-¶í›¤wl×Jý·z͆ȴo7Šmž»! oWüÈ?þž�¿~£>×ï«ã-Sû.Àvô¤Üà•þn’wKY( RdâZdÉgU««ë ÜS§©WAмR‹âz½< z�¹6Ì-¥¾·ÿk–tý¶[oS½Cªk›ÇC¼õ³$ßCUÆ[Û ÊÿÝýõ®E!‹{ÚIøz¼–Þ·´Ín‚·ì©z ‰Ð±êxý©©±Vø^iç-æSŒ ]à”6ö™Äºü|UºaªïTnwc°“lC|¤�­�ѵ-FY¡«2„Ø}â9ÿX»IÝJ Hì–q}kæ­|‰•„}gÂwqíJªØè)„ÞZïVôäÇš(Cêï½x=Æ÷±ˆ6½-È>Ý2§Óàâ<âu'‰—¯ÇèZWŒ!$z¨à©Üc׫:ÞÊ!Ì{ÒP¸3 oqcr¿oßr•=SŸ� �á)L¿Š—ƒRÀa„°þîGÿÜ¡…� Ð…¦œ@ÐH2N¿OÄ8å@œ%IŠ~(¯u�? 6TB× ›Q]ç6Q¹…BÈ�…�6.±°qqÃ�%­NÎZ˜• 2-6„ˆ´R”%6J‘©º_Ù!Çy¶Œ±e’³LÈ2Û­UºeÃÒÌJûC¶>m,cíuÞöèª%uV`[¸T–5ÎoEqãú\ñպ{¬w¥e¯R%£øOú}cÅÃÖž™ ì4a.{÷;¶UÅ&Â<õ>ÔN³åž?^A [;p¬$½¬[ÕJÎf7&]h‡wíá…·m,á××9µ¶Æmí6ãM~]kZJ±Ã…áù`i…©v3xL¯obŒáÀ€ õgYø\ˆðßMMñ¿;kÊßpšo=ÌØÐp°ò£OÐù¤vU��-Ê5üu{UkƒÑ]þæÑ[àP»ÅM­Vø~ddÈ �JÍ•� öõµ98ÐÇf©yáê5Ú1B!­tKJcnnàÂú¿¿z)ôù ÷ݬà‚åšñ20JÈ ò¤÷ú˜tõ^Z[çÐ`?ûúÛt�áÙË3LµšÜ3:Di /O_ÅOíž$›ï õì›]X´Šq0�(rw6¥¨À{e8>8°‘tÍ�Žðúõy®¬oðÈø(;Z Þš]à£Õ5v¶›<4>Êù•5Jc-.×µ¦£ úh(Å‚K°|)Q Œ�†ØÔ"ÂðÐ(×f§y Ñâ¹+×øüÔJøÕÌ, › ôq÷Èo¹Áën=š™¢PŠv¦8·¼Æüæ&·ò¯.]äØ'´†ý£(¥Ø·s7„\[.œP‚'ú6JÍ#;Ƙ^ß`Ñ)6KÍŠ‰À¥n”£�‚ån!ßÔßǾ¾i1Ž®²Š§À'=3 î)/ø©^ßîë?¥Ôésq}ø3��÷Z£`o‘J•~¯ú´9z”ÏŸà·¯¼Â¾ð8»vïf}m��� ¾ô'_àì™Ó¼ÿÞ)žøâÓdYÆGçÎòò¯^âÁ‡?Å­·ÝN·ÛE”bllÌ)ê5ëë<ùÔÓÌLÏðÞ©“¹û^îàAÎ�=ÃË¿z‰‰ÉIžúÒŸ0??ÏÅ‹P—÷?ø;&'ãÕW~@QÜçZ…e]ËÒÐ5•¹¸ÝJar±¹ ¼bÀŸe*‹'S–PбÞ/ø{¸ëÈÝL_½J£QðËgŸajç.n¹ív–——øùÏ~B£ÑàO¿ó]æù™óªPYÆøŽqò-9 Pb³)9¯["ÚÒ­¥¢Bb$jÁ D­™/asc“¿ùéÏ™_¶!²xÀ&ªßX_ç¶;îàØ[o…öO¾sœÍÍM²,£Ý×ÇÉwNðΉã säî{8qìΟàk_ÿ&}tŽco½É�ƒù—ýסž£‡‚ш±9pd%Š"š¹¢™Æ—––8|óÍ|ð¾õ8¸ó®#Ütð?ýÑhµÛÜ{ßýÌÎ^guuc ïŸ:Åâ‚`f9¯ÿî·(UU6Ê�e�e8úÒ†•Ì” rE–çî 1è²´J¥Q@Ã¥Ù¥°æ>wˮݻÙÜÜ a—€-aŒ>Iñ.J„¡Á•BýÙð)îÆÌ» ±ôw4Lð�*v/<ï+�)T.˜L‚u¸U¨È~¯𼊣óƒ%¾ C„öéÖ¨ÆÓ>VÇ`“7ÛæQ á­÷Q1gF/ëãúi¦ç{T$µ†®ºÖÛ;tïi€˜(ØF,Üe 3]Íg°E¸¡RF)^NÈW‰O“–*7Pû"±Åú‰`\û’0[#P1:FȬ·¸‘-¥ý¬ Z>HYÁyž§,—çÓÏ¡€¶p¯BØ…` ¬R"·ïdòQzû%ïqãÏ»‰ÿ'…j©OªŸ¤ºb =#)ÃÚj’ðOÆ¢y€Ú®­íKÍŽ½*#è%×H"᮪­oÇŸl½^o?ÎËÖGí^…h˜d⸠º}±[ÅÜàæ”'ÛZSØŠ=îˆ|S�ýÐãJõ9’i­ó�½ú²Ýuÿó�žÛ®˜Ú»ÔÞë÷UùÚ8¯µû{…=é5ï¸ê]|)÷IeƘ­`+ϨÔÛL ë+g?oñ  �úúøWê Ê.|(!äÖ‡ø—6'ð½E(Ws­ïÕm±M©í½ê’þ¥Žß¶»GÇ_·À½øPBIeb™‹ãõ 6`-ÙÿæÞ;Ø’ë<ðû�ÓÝ7¼œß›7 “˜€8ȉ$@�@ˆ¤(*¬¼»¶´+ÛZí–]åZ—«¶¶JUÞ²K^É%Ëv­J%­V%ŠJ$%Däœs`€Á fæ½y9ßÐÝǜЧûÞû0�j·ÜÀ�ûn÷é¾sÎw¾üe@q[ÑÎ.¤ *+Ý}øqʲ>yûó¦È ž0ýw¯§ùj]Û†øÊæP8€äŒ<«¦lÀÅ¿Uë—ð†P8¹� «°¡áD6N�¸HbhY�°±ˆ¹|IаV™Þ*´Š!Œ@Öl K`Ùþ áÑ!í‘pºmñKÖ¦ý» ywóm<‘ƒ;lñ|#þ1�ûvul²ƒ,aa‰8OA€2ób N;Æ%j¶ˆÝ®ð,¡šW¹oéïuÖ?»³¹޹$>-—¹™âæTŒDçÚR-íê× ‡†ŽÊ®{Ûi£<Òs«œå|6a§(I„íLÒ̹—2Á ¬¬5� �dûæ·mîy޵f®ô$i� ƒeDj”»Ž©€D "­"EÙW•fFRíR–*�˜8V‚ PÆ¢ÓXÇÅŠ$MHHÆkkéeCK#ëÈ›¦ÚëÀ_›J™„‹!ØxÁV1¸ò©™'©@I�øX[åDª…r‰ñ¨LOˆöbè´ò�°½Ãó¬ †»RV˜Øºÿì|åkôpN.1‹mßßµû· â%^- Ñ*2÷Jg½(nJK¸YÜ/ô|µŒßǽ>ž*(,|òÇEa/š2­e³ETV�O`d*" ÓZ+(²­‚m#cœ¹8EUHž˜_àÀÖª«å½¥Ž ö»:ÆLÌ{{íìÖe¥˜®Õ™¬V0úO\œãÆÁ~®îéá•ÕU”RüÉ‰ÇøWß¾§À#åwxvt‰ì(sÃÏðœ¯øS þß{O°aâ±OD?7>FWðÁò*‹Í˜k†u8›Zšðáò*[*")(’£ƒýt‡ÍTD—÷kËÎ…F“sëèãá•e·/'GFˆ¤$MÚÃÄDWZ¡¡¤Nà˜~o¨”f3æé™y®`¬RæýåUN.¯rt°��Ý]¬Ä1ÍT»ÄÛijWö“¢Xm4y}u�ý}=™�'pêÜ•H�¤&9z’á�$M‘&DƒÅKÎ-Ú,†$MyëÔªT8Þ×C_¤½”éÃR£ÉP¹Äj³£«‹×ç—HQÜ8ªC.=65K#M¹É$M~~v�ŧÆZ¾¯§Ÿr¹’Û F1°ž¦ÔÓ”Z’�"™¨”Y�cúˆ×–ˆ„äòþ^z£€Ç¦gI•âºá!úJ!'.hO‡‹uv”Ëÿ¿V LŽŽhÁ�¥»{¯f¨' }QHwpaCñ\=ÔÏÓ3ó®ìÎî.>Z]sž/kuJRä+úÌP`R§ú 1óŸ$©Itjc—ûôVþªÿ}Bµ»”%2o_‹i�¸‰îÓÎ`øáî+×=ÆŸýøoxåå—øÕöÏxøÁX^^â[ßù.«++9!éÄ–IŽ_{»vïáí·Þ¤··—o~û;!Ø29ÉØè(—íÞÍÎË.ã™§žäܧŸ2>±…á‘frë6æççX]YáË_¹“(ŒxéÅ8ýÑ)nûÒí¼ùæÔL^’#ûÒ]‰ÐáUJ%H• Cˆ(C.IÒÒP¯EK¯[¡ö¢°J�X¤$blccƒ±±Qîýñßr͵×qû�_å©'gzjŠZ­Æ]ßøY>0¡p„|rúcÖVWÙ¾c'BNôO>ö(¯8ÄÐаƒ•P-GH‘¢Ò¥t8��#öJǢX熦tg˜;Â$K«küñOîgjnž��®»î:zzzˆã˜0 ùé�ÿ¥;v^F¥Rq!|¶nÛÎ�7ßÂ_}ÿ{Ôku*•JÎÊý¹gŸf}m��—íâÉ'ž`~^‡Û>:Ê@W*MPJBš�&:he"%©”¤B¢ñ@ÀVlé IDATn ¥r€ D CÒi¯Û4ã œ�Ö»T{¶R!xñ”þ 8ø^8ÞµI’¸0L]ÝÝ—N¨Z­²f5½]„ZЫC÷¤˜T :Ì�å#A*D¨“Çb„ºØ3:Q�èä´zX„ؑë) …Nþ›-$c™.ŒŸÈ˜Z^È ¡é~HGèþ%hE£”º/©Y·6þ¿QŠZÁu*RG‹J4>Êè:ëÙé09ˆ$ bã,ÐÉŽeFÄ¡·þS ‚¤ˆH Bm1ŸIÜíxüÁ®ö$¤ã•,^ý<—~/uÜ­­_Hãu¶–Ç”‚À>�‚fB&Ú¯£ièæP’„fŒ‘žo«l�© Hcã%cà#" �þhe‘ý¶ƒÌxFCz‘ñûþiR<Û ÚCMøã„;›òt¶OÙcæŸ EçêÖ(Qù/¶©±SÛUhy“Â8ýõøYWKÑ ›B³­?:´cxE!ROh_mõgÎ.kîfèüv�…ßæ^ûžˆÂ·�áÍL©ŠwÛóË¢ð¼¶ù4(ZÞùÜ,o§t)W»ù|·ÿ·hÿJÇz±Ö¡ŒßFÁz)W¦øLy¿‹ý+¾ožYåAf¸®?Mï=ßJÜz (ïžôžùýñ=ŠŸN×çžôK¼6_›MeÛ7UöGh ¡ �9 ÌÂ6øÄâë^ÇKŒév°sµ"‹]îzdQ§Ød$¾€Ôr2�„"‡“ü5UœG"öc•gå·¹o»É; ‘ ½u,þ·M˜ßÒ{åਬ·œ [�µ“mHa¾�ˤWm>,–%H¼‰´ñý[F$üj²Ê6[Ûî¢ÍýlLŸYOËË—r¯S™ìu¡yü9 À ½ ñ#|a»=` ÓžÕn׺÷Žÿ�®h�“/å2¸ÓZð;ªÄ}Û:;‘zÃæö¬1ÅÈ,d„¡Ã �Ë�Ëà�cdÍúR6WCjÖ©ç™c«uËÔ߸ž ¹å87VÝŽH—Ú�× <Õf@"±ŠJþ>šA0ˆ@ àA ±Ö“(íÙŒ•6Û7c“”É'�4ÂúT“{©Ð‰ŽT¦4RÖ_Ãʆ’&–,hË?½¿­—„oЉŒg†âD™}oæÏÀÏæj茉r3¸I™<œ]Œ@¾ŠuoAÍš¸¼/mêµJ�B!XnƼ8·ÀH¥ÌMcÃÌ7šœYß@‡ú …–«”¤$‚O×k\ÖÓҵš#É'Ç·;O;™ã£[øðôû¼Û¨sc?ç7j|¸²Æžžn¾69Î;‹Ëœ]Óýºc˨^fÏ4UÊl½Îx¥ÄB#&’‚«»ºÝü„AÀ±ý{œò(¿‚ôÆÈ„”*·Ÿ•GÀ ŸµùnÝÁ6î»òè/ýÏÁÝ»°–Hv?+òŠ�÷Ò&¿04ìBõ—"&«§¨¥)§Vubd« ²á†Je)™®Õ©rYJ=Q8/�4µyq’$%1Š›¼xõ†!+qÜrÿó]yL¯½ð|’:ÃcJ)gW‘-WᎠ‘½�¶�O096Îù‹Óœ@¥R¥··—õõ5y脆ñõ7°±¾î íÛ€ßý�ßqï^¿ÿ Êô_[± T’§ ‰”ú#$*ÉÖûÄø8Ï=û4=½½ìÙ»�7^{•éé)*• ÷|ëçxòñG�@~dd„U#Tøè£S\¸pž0Œ<¥ºUL’Ý@’&)$'¢ÞòcÆDJA($6Ò÷?ÀŽ;(—+ŒOŒsæ“O\[·mçÌ'§ÝïKÍ1E%zh¸¯‚ S£0ñߥ6*¡¦uSaŒlB…2T�ˆÌšL•Nøk˜ë³Q@èO$�Øò¢š=TYX .ß�ãwp<¼¶Ø6×õÙ¢$¤¡$‰A9@”�²Ëx H³\’kK@I_) q|»´;6Û;4Ƚdœçâ�³-¹å+¼ê%ز×-LÍ·¿­ÂC˜¬……H�ÀÓÀÈ2‚ÂC˜Âë…@:·l�‹ég]÷r2Ù'z•W\¸«óBË ‹=këñ­a•ç…à ÕÛ^›!¿öÏŠÄO¶Ž„vY´…”2-* e¬Ð�› ƒ¿™?£,Ë–ƒÊ¼ „±º÷‚ÌÊÅ-·\·³5&üù°R:ƒl…FÞìZ¶‚ ¿ov&< rÝÛ‘Lk–ÔÛ~+Ó;M¯úëGϯÂÿÆ…ïr}TYX*¿ë®"•}T;êÂn*«lTf JdAa T" $ÚµÕZô˜±¦J�(I¦N`/Dlø�Tƒ=U$*ÅÆúu‚—ÄXæ A ‰rÖ˜ÚHR÷QH<°1F…’XFÄÄä4ó¡™já’‰ Hqœj‹AcmfÄ(7�ˆ<��0 ²Þ.Ù| O?J+�ëÕÝv�f¸Ëáº\Ÿïj Íãá\åûcìh­°I;þ~¨µvf@ö_w»í&ö^ñîû„·¯òý6ë]dnÌ« Œ „ðÇMf\jöª�^{I¡¥ Š&{Féíêbe}�Ù8æ'óóìJêï!4‹p¡Ñ  ™P;ÃåÝžufWpå�V"œ]Û`¨\¢;ÔB�$Nø×Û¶ñoÏœA³KËüÁOîã×îú:¥(ÌÖ…Af™"ÄÒVÉEA.Rðƒg^â¹÷>t}¹º¿�;F†XnÆÌ×\ÖÓEµ°'<:5íã#NÁ¡ —gàèP?qšê¸×�&¥ˆcƒýœX\dÁF»Êe_¶…ÚYc@Íìã)6²8(Ê¥�[ûúXkÆ<~q–]Ý]ìëë!VŠS+k •"vtë0LÃ¥%))aïîÞn†Ê%Ë�MÏr{ÿ§jSüÅ#Ïó[¿úâD 21èP™¹N�Â23iÔ |áÙ n}¼·´Âb£I58ЧãüôË͘f’°¯¯‡ž0äÕU¦7ê¤/Œxkq™OÖÖÙÚUåTœÅÖŸßFj`l×ìäØ6Ó„w5v—µb&A±ÜŒé�"úKQÄ»K«¬4›è¥†¼¾°D=IÙÞ]å«“C]×Ê“@è„Ä­—ö*KŒ÷Zœ¤ÄIª“€§h¥@’fÊ£0(’Ûÿp¥@»Ëóp´0·4ƒÅ}X1A>”ƒU¯d4 \{äJ~ôðƒ4 ž|ü1FGG¹ãί!„à£SòÜ3OS.…‰-“AHOO/½½}4 Ò4áŽ;¿F|zö œ<É�yûí·™½8Í›o¼Îå‡sÕÕ_`vv†™‹‰=˜ìÚ½‡Ä’ß|ãu®»áFÒ4¥R©òüsz�•¢ˆcö#” +R ’Ô)±©ÃÊXïJ§h"[kÊ�ÿ:o„0!8$¡www³¸´Ä¯ÿw¿Á'ÌË/½@_?wßóM.œ?ÏÌŒ¶zÃ�J¥BOo/ëë„aÄÓO>Îe»v3::FwOóssÞlAµHCÓ˜œºOšv²R©J´! „$UZŸ*X¯Õyà…WxæÍwPèø÷ÃÃ#ìÚµ›��u”R¼øüs¬¬®Ð×ßO)*ñÆë¯022ÊÑcÇ\>)%_ºãÛ¼ðܳ¬™Xþk««Ô�·Ò¶í;xê©'¹xQ+�'‡Ø=1�‚@Hç(n J®Ç(â,šè—Ëe¶ïØÉ»oë�F�FƒŸ–µÕU*• år…gŸ~ ¥“[·1>>Ϋ¯¼ÌêŠËäÖ­Ùò—B[Š{|—�Òx2`±h‹vZ^!@D†Š?|è}Þ<=�‚#GŽ�$1ÓSS¹f•¥R‰†Úí³®ÕÕ‡³îD…€ñÐqñ…±ò7gžáŸT(²pBæ#„2ù'Ì"rF ºœ0™Jf÷] CËè¸U†÷TÂÐ ©Ãé9¾Ûà]"PBç0P+­xI�D�ª•j˜k”c¾¥@†.vG�ròŠ>Ì2µ¶³F³ T€H¥ö°B& <—”VÇ 7ÆL¡B™pMÊÐ'¶P¿–8wð2}s˜²“M¶ÏSçù�2ß`;¿Næm 6Çÿ"Síu‘È$Ñs•€TkO“HB@)@”µb@i½ž=V#,+ƒL>aAíñQ L}¶k((Çw‘�m_à‘ ¿2Pùt} 㙕·kÄÒ Çü÷ì—£ßiy.ðÚóèü\Û"{Måæ´½·¸puºoŸ áUdמÝyÞ*ë¿ S- Ç] ¬Ñ[ž÷qØÛÿ9xÚ1*ÎñEØý‘�Dy…¤£õüqøPk½â½"/؉¯í´ õ;YèäÍÚ¾”ýw;îü¶m´Ž»¹´6Zúè–´¿ UiÀ–~mßâ•æz¦×¬×nËò÷…ù ™ñŽ5Á°¸40£ð•æMr;;‡¬`ZhÂñºöï¼±e¶ï2^~ûÛôó¸™H¾¿–ÏÑØï05„žR@Ö….c|%¸�êú=•íFc€¤c…Ú¾)ï 5}MýØãÙºŠðr!‰ ¯Ú²†É ÛÝAoê·”¡SRмAOf�²cTÙ½"D*²$äþš0¯»#Mä«p•J‹¬”LMŽåú È^Ê”ê"7e+«í·ß픳æºíƒEÿø¬ÅÖî¹`oŽí!�Û½o¯KE­(ØÆ‡v‡¦B�Ò¬÷-³¿]ÜH3‚ÂzJÃ,¯äÈÆ,ŠãÏá>oqÿ}SÀys¤Z9àÑšNÙ[xú°´ëVYkv&ÂÀAÙãÞ-bDÎo³ð�`ö�¸¸µå:徕]‡V9`ú,ü0s‚ Æ9÷DÅJ#"© ±j,rR…A$P‰€T‚44HÝq$Ò„ê„¡Ôq^³’˜µ’ÒL”É+mp£Ù†cñ€PI¢H£ ˆM¨£\Њ­¬�R×¥°Ïõ¾“žâ$ïÑ`±pnû„HSÛ›˜¸ýÞ´d™^3V'¼Hi�(·8²øÆ¦ÞÛÞZêsà Úð¾;÷ëó]þæ|ú‡&@.ŽSé{߿彼ió¢ÝOáê´î¶9a¾·æý00¾Âà ¥¥}Gd]z]e÷3M‚v�%”JQrë•G¹÷ÙçøÞÌ ºoŸS Π™*.ÖjlíªR b¥xtj–/OŒèxû@Ã;“vtUÙN•ߨ²…ß¿p€¹åeþÏ¿ù!¿|û—Ù>6ŠMŠlßËÞ–û`Ý’ .ÜhÄüу�ñ©I6Ü'îîëç×&&t?’„ µz–ÿ ¸u|„ÞP+ B!82 =ά­³ÚŒ¹b �0˜¯7xvv�;·Œ!üÇéi×£4 /eB�èO6zKaÍÚ‹!±±Ý… ,%]a@ļyl˜HJN¯­3½Qçè`Õ àÕ5Þ]Zq1÷çê Vš1WõuÓ,' /¼÷1½ü_¿î*d�zkM9Æ©&X-Ŧ€>ñ+ëëëîf©ÌZÒ —J§W׉•>Â@2Wo0Wo Œï;Ü81áƒR^*NµÅzš¢i¢Ç.Ä�½6 ]ãÓJ‘4þ� ˆy<¦ëöž k@cñŸGŸ¹ßYG•R\sä(?zøA>8y’]»v!„ IvíÞC©Tftlœ×^y™¾þ~¾v×ÝÜwï�Y_[ãç¾û‹œ>ý1Sγÿàå:tˆ‰-“,--±{÷Ξ=ƒ”’¯~ý.º{zxúÉÇùôìY¾ö3wÓ?0ÀóÏ=é> ^¯süškyèăNH}ìÀ*Q -ë�g† E’šDêZ)ZúN™SÚ ÓóšT$�)iŒÊ5|¢(¢\.S©TDÁÀÀ �ú�¥ÅEö8HWw7/¿ø< ¿æ:öìÛÇ3O>ÁÙ³gX\Xä®{~–N¾ŸS~h��Q€ Oc¨£0tJ‡<´ák%X[¯óÔïðØ«oº�o“““Ü~ûítuu±±±Îá#G‰“„÷L¾ƒC‡�°wÿþö @­¶A­V#*•hÔë(¥¸ÿ§?ac}�-““H)yû­7رs'G�]ÅýOþ±ëÇ 6á¯ôNU½'SZ+i ’¸™õ?Ièííeue…Ÿüíµ0þè•ÌÎÎòñGZ!qãÍ·E�?ª=Dâ8ÎÁ`mu5'¸Bh!ºFÉšd—aqŒÐÖù*ÐÂxB}¨ $÷?þ ÿÓÐçõþýûéëï'Žc7_{÷íwùÂ(ºdÅ@¹\áܹsî÷á}CFÈ®´À7”:Yn(´0ØBÑÆ�/ITIè$Ä%S‰ÅƒBC*ô¸í;§x°³áv¼á'„ÓØé2ôŸã½5] okÞ“�ö&•¶ªIÐ �T RãõbçÃ@ %4Ù/L¿^0c8fYÛ· ÐôjøŠ$È �\RÚ(0D¾H´×@ ðå">÷•¿2Ú;ãËm) 9ÕöÍNWkɬŸ̳­ö‰›AP"URépMA‚hJ‰^+‘„r ?ÆÝP(ÍOù‰…u’Ìc@fc¶žm6œ“ÇdcÉhÉÍäŸÅ1´À±%4jQî£ ÷[„›´U¬7wòvîµGï9�s¡¶VÎ¥Mm»é÷!k¥X¦µ”{ë n+ˆö¾³YÌæ6ÇÎã°{U¶ï‹ÿÝ©ç�žujÓŸÙvkñR.Û¦'$îX&ûÎÓ|~H!Ѧ¿ÿÅXsŸÝ7�G$E+¬jÀ‹Šƒ"ï%ÐΧ¨ µí[A—¯ð×7m~ÿ—¸6Ã…g†µgm˜%ôßk�vìßNÓk7ºVÙbnN�ÐÉ ÿí·¹Ÿf€j—:�hZ8¬T§ƒÔÓþ«|ù6E;ÏQïk¯Ïlñh\( �È,6sh©°Ï\œ'È!÷†B8Ï í~�köÚ³¯*ZE¡²©±B$Ypßó´öYo @|•~Ÿ6m´•�ee<ƒ° VÖêÁ;\�Òo+kÄüŸ?”;8-w-Ì•9Nl?¡É25pH�r@ç0°±Þ .a²ÔDƒÛ<ùqd– í bo˜uï->•uë�à”p–Sôkôæ6Ë%QhÑ)¶T6Wñ‘Fˆú±&¢ó±ëBd?}%,³*ÑßJ¢~£|ñÉŠÌðÙ4R¤ ”ȇoÊ!S�TY((ó·Ð^‘€DÇ×ÌX`4¾ºãJI’ T&ök€1R&H„)Q¬HRƒçŒ°-’X�$) B¤ IAšJâXK�h0M–y m!h!ëíªÖ( ÈÂ@èIUh¥…Îq¦hÆ)2NALÜLhÆ8«O=t‘ÓŸç=2¤K‚nð…ó À¬#¥t®Ë€yàv˜Á«;³ÿ aù¦Wëá”ÛWf¿[…@1I±/t2¢»öõø ßmáÞÏ£6‹kÌ3åþñ˜ÓΣÉ-S ®G[ ç‰hö>,ìÙ`Æç”Â$ê5îéÒðS6‡…”i [Æ[’ˆJ’RðÅ«¯âÑW_e½Vg!ŽùÉ¿8:ʹõ b•åh¦)žP0‚/¥@-ÑÂö=F?k„•úzÀ·‡G þï© ¤@½Ñà�ﻟË&ƹûÆêéÆºë1ÚD­v� RÒDqß‹¯óÜ{�xÖþ×õôð‹ã!Xl4©”©”I”âÕùEö÷õ:O�·—©šÜ½Qè÷ “uË(¡üíÜçŒP% Cî¹áZ³ þL‘jÏŽÔîçüzx¿Yç)xgq™¡r™ÛÆG´PëüE!¸sr Ð1âgjuVš1Õ `¸\b¤RbKµÂÔF…â–±aºÃ€_ŸàwÎkÎïþåtU*ÜvÕ!mÙn,¥Lh&÷(³Ö’Tñ½ñÚI-8 „àúyqn‘ñj™k‡9³¾ÁB£ÉF’rtP’(EW`Öpju�Ëû{Q("!¸ïÜ4[»ª|mrŒ¹8æ£pèîêethÜóÐÊÖ®j7£ÃãÌÌM³Ǽ·´ÂW·Œ1[o Ð‰«×’„ZsYw•5íòÀ½ç¦ØÑUå@oku>^YC “37’„–Wx~u…õZ�ßøíßã7¿û-~ñ+_Ò¹`0{_)£7–n?ù¬cÎ Àœ × )�&Ö´�¿5ã”×N¾Í“¯¼ÌÓ¯¾Ê×n¾™þóßuÆZ¦dÃå Ê[¿v·Ï7š¼8»€P–)ŠçL^�íÝUêIÊÅš6oíª²³»Ê3æyF¼ÛÐ0ÆkÍžA©ÁÍ©QneJ…ÏøWm¨<[�R4’ Ç~e¬O�Ù¹ð=±üºÒFÍQµÞY’Ÿ3M‚+ölßÁðÀs‹‹<úè£ü÷ÿâ_2??Ç?½—ën¸‘Ý{öÒl69}úcúûûÙ½g/»÷ìE ¹ÓÓS:|„Ý»÷P«×8xàç>=ËÍ·ÞÆúúO>ö(AðÝ_úG!XY^qçO­¶Á�ƒ—£RÅÖ­Ûøàäû<æ…ºæÈ!c ž7´ <|­sošq 2VS`B0*㨪…•.r™tÑfØØØ Ñhò7ùtwwó­ï|—f³Á�ôCnºåV¶nÛÎ›Æ uu…ù¹YFÆÆ8þÛvìà±GF©”뮿17‡Q¤=pš(P‰Ë� „I/%BBšè�<õï~r†ßû€W?øˆØÊ«Õ*·Ür c[8zô¨bû‚t!Ÿ|rš�N}HWW7CÃÃ,ÌÏñÌSO"„àæ[¿ÈôÔ>8ù>[·n£`�s&ÙýààüGÄìŒV,nâ²1í- MêráŠ@+VœÍ�²¡‘pýúÖw¾Ëƒ÷ÿ”úŒV�jåK¦„{ãµWi4”Êe†††™�¹ÈÅé)„ÜtËm.qr¶”6ð20£`L¥¶¢F¡¤B �ØKëMþ÷?y‘ßþO/’¤ŠÑÑQn¾ùfv^v}˜yÍùJÈBYúÒ‡sñãÉ'Ÿp¿¯ºbL q…À&ãÕÉr•>÷ŒE·01ä) D$µ¼ô<³-_›Z#Í8ƒzËŠ<liL!-&��äiLÞ¼ IDATçu›è eŘXo^)u.¥•`É8aÉ,Ý ±JG�Kx«=À¤™7£H°= ô˜5“è�E‰Ý¤8>Û&V6l’´ýóXÀŒÓÎ0ÈÖ�.£Y  f6­íq³«Æ4”g™{öì2èÙùpx8¸EP åT$e‰T!a$Q*E„IDIBIj^;0pQx‰™ÍÜš Ì…96dUj-N­×¶O*{ÐÉ0¨¢ÏÑFÂåRpi{ΩüßnÑf .˹ÓÏZ ZðA‘É(Ô/²ƒ¯eŒy[}Õá;³€öêòÆZ¨´ÃïÂ\{uë§ÊïV®yÊSà´ »Í"÷˜+¨õy¹L^à7j6°²´‹Àæ%¢ ¼\f[�(B°øF‡�¶}Ö ¾Y�›QPíÞÊDæ6íKu®E~ùTV‡^䬨/�æËÁ:Ã1y‹y¿,­øDek+×aêiñ¶/ìG·&•ûOcdk*«T¡=Є ¾ê›ÆæñFj©y¯çÛ2Âà<$Êì„ËŸQ¼.¦í®Î“¦û–Ù”Þ¯ökÇ÷¶qÍ8䯟…º`ëfjé“90í ¯…­æìN•âæÃM§Á›iá}Ì~Ⱦ!¼ŸmcÒ6kî +À"ç²à½& ß-õ™¾¦*ë§�pízuë$;b:N¿È>ŒÞFU¸ƒ1/ÓÊ´f~ؽÍ4äšèñ [늢·€M‚äwZÀÝ©!h9€l[Þ8[ïesœ_qº>ÕÒžOÊlvµ‡º=4ÜeÍÃÓÔpɦO–pÕfY™i�æ„LŸ}× Eá8ÚT¹¿sëÐx ˜ßJê°19+`U€­a4Ü>±»úýµkŠ©bãöãi;}\œ ×AÛž åã´Èú¡¼*Í ´C¸ñæÀ¡:}ìBñpƒP¸�ríˆÍ´$ "PÚœ‰DZÎD !J F9� D€ b¤”„�”fL¦Ò T’X‡ö‘*¢¡BÒT’¦2H©Hâ,‡6SÈ �@ˆ€ "кe\(H•D¥‚fª“” ’†ŒZˆ‘ ‹…Ít{Â~p„œF-™ÇÊþ¶ë˃oî05‡¦jCØ8f­pø~ž+·•Z|[;¥@»ëïãMàDZ/¾Ÿmƒ¶Ž´íëóö`æ �R@å¸{†úÃ(Ù­n„¬�”2È”-À”:W†”’@h¡fj6Ÿ %ŠR$‰"IüìÍ7òç= À÷gg¹khˆÉ®j6ûJÑìííàÝ¥vvwÑeB�\^c¤1Ù¥•}a˜;¤€Ÿak¥Ìÿzö,+F8qzjšßÿÁ�èëêbïÖIöo�dïäa˜ñ...òöé3¼uú çææs!X¶‡wõðÝÉ $:ÿÁKóKܹeÔ)MºÃ0w\79IÊB³Éx¥Ì`©ÄzœðÂì׎ ÒÔÒ”?1 'n¿ê¨&s}bÆ œŒñÔBcý¯¦š‘=³^c#I™¨–B°¯¯ÐÂÛ™z“£ƒý$})MOͰ½«Ê #CÔ’„fBp×äB¶‹€¯ô÷sbi‰$Mù­ÿøCî:ù ¿òÕÛèëéAJE¦„IjBÉÀ{Ÿ|Ê_œx„ÓÆsCÿó¶ml‰JÌÕ •J\ب 0�TJ¼8·À|£É�£Cô†!/Ì-0½Qw^ '—W‰•b=IˆÓ”§—–œÍΞ�û]B[+”²ÇÎ�Ý—337ÍûÍ:ÇD/ÏÎÌ+Åõ#CôD�\˜!E{œ\?2¨“+˜®5Ø××Ãz#€rpry••fÌ?a!‰9¹±A3Žù�ïý?~òY~íg†Û®>bÐJæ®ër˜ysvyYw`!B+‘•¬×6xæõ×yüå—yæõ×X5Š€“ŸœÑ;Ìâ%ë-`¶g™Ëÿ.®-kÜ NŽðÏ`äÎ�×ûÛx2äŸY:Q劶ðäúÒ~FsÌ|ËÚÉ:´HþlYkrúKáƒT8ت;þÌÏZ¶+ÚÕ�qeܲuSx¡PVu˜S¿›tºíU,Sü­Úüu©-\ʪͽvuø˜Cžuª³¹nWÎ_?Vø#ZžäËã­ÝÏj¯8Ö"6Ì>™'€oů=³ý"ÍÛ¾A¯tïkÏ‚NÐ5¸BHt¸Hëeà��6oîMù_ôò•ìa’d®éVé¬�……}¯-`£ ¤†+FƒÔ3^:CVJ¡™­TXå¯>ŒRÝ�L2ƒ·n½ÃJŠÙ³P^¹ÚÆ×|eËÒÿM.v|2¶å­3Q@te-ANèã¢Á¤ D›>�Q–èµp ¥ã%Ú¶Ý>öÊçm[f€áƒ�«¤Óí8 å,ß,C«á* ›F´×ª Œ'βI·Y8®¶ì\õúèÊ�G>:Qþq(r È£žüé ds8Éħ׉iS'²IÕ¬ç… ÕëÖ$×Bèoa%¹f�ºœ©³‚È´—´ÎUfÒíÆíoFe† ebÕe›D(¡­F• ç&aêQÊÇ*;Í\µµÂø[�ÙüQiÚ5!Âì'KÖ¬° :qhR^5}h5ý(àOS‘f/Û0$ö™](ͼ+'*ëÁoõÛŘI FE�@dƒ‰ %ˆRÂHQn¦Ä1$‰]oY�qœ’Ä)�DÑH¡ë˜ÎMRš@,±�fÙý– B4>ÕaŒJQ@ ¥Ñ=š¸Ï©2É"uh�¦P:Œ«�„Hêf�%¤(•`ãa;¼iCÖ(=b‹•J[£79|k×En»æ7E†kÀ)ŠÓêë=�Y¢vßù•ÚÆ;¤"[®ôæ‡n+9¤h}Åâpïd®¼›jü­|�øžÖ,¾péÂØ�0¸2;{õ™«Wú&aòµ)Âgõ†‰£E)æ#ùÊñcüøégYݨ±ž$ü§ SüÆ6ò¥©ÏÎÌsëØ°ÊX¥œR5‰ˆc¥Xj4µµ{P&NSž™]àøÐ]aÀõ½½üÎŽËøþÂ/.º÷—××yåƒyåƒ;ÌIëµ³\æ7'&�#·†+eî0J�¹zƒ¾(âòþ^Þ[^%MW èßóq“W=%B5�ììé"2æ·<=ͼ ÏP)•øê®vÆöVcä6Nx RËè2ƒ;¶hÏ€�VÖ¸X«sÍÈ �¼¹¸ÌéÕu®êg[W• 5Öã„Ä>#)ÙÕÓE%˜m4™Þ¨q°¿‡ƒý=Ô”âI“(òÞg^á�ç_ãèžÜ1IoW�˜ s‹¼õÑ'\˜[Èú ü«‰-ˆ�ËJr×Öqæë ž™Ñq«¿>9†‚™ZƒD)êIJU¦Œ–ˬ7Æ*eN.¯HÁ†*E<=3ϫˮ�ƒ»öS Œ§ÚËSeÍ{.ç©c!Ixvm…î²V8 )é CÖ’„jòÚÂ}%ª¨*šÒᆎ� …äyc1߆üÞîÝü?ç/ðw úÞg?å_ÿþ0ÐÛÃ-ÇŽpýáƒìÝ>ÉŽñ1\XËTŸ9C?`£^gjvž‹ó‹œ™ºÈ»�æ��?æôù l'?ù¥tl=‹ ÜjQäp`ZXÜ]A� ÏÍ,ÐP)]a@IHΛœ]aÀ¾¾^Ÿ_re¿0<ÀKÞüÚ+QÒÈÐRíq¦´ÒÂzø:ªÝ¦ó• qÂ综=cBmåð²Åõ7*Ã(GD{ÅDVŸ²÷P\{ø<¥­�Ïœþ˜µµU®>~ ÷ÿ¡«»‡;îü*s³3,.,�¦)ApÙ®ÝlÔj  súã�(—+|ç~‰0 9ñÀ},ÌÏsÏ·¾M¥Rå‘25u�¡¡!çyÐÓÛËÜì,AræÌYg!~lÿ>¢0pg¢=Cœ-„_ÚzvYÅMj§ÊËÑ&itµZEJÉ­_ü2ƒCƒÜï�YYYáKw|…‰‰-œxà~f.NÓh6øÊW¿ÎÂB–T}æâEâf“ÑÑ1Jå2}}}îÙÜÒ ßù_~Ëá4ˬײ|"›]Ç�窫®"Š"nÿÊ�\8Þ%>pðr†‡‡�P{ee…OÏ|BE4›MPŠþõ_šÊ{i6Ny±{ï^¸Ü%M.•ÊìÝ·Ÿ_ý§ÿÄíÑ«öìgr°Ÿ@¤„æÜ+PSª¡ Zt•¡L ¥BÊ”J”)4666˜º Ã”ÝpÓM,..òêË/°´¸èŸJ)VVVøþŸý©ëÛüì'ß{·Ëë þúñ(•BúºµçÁF=feµÁÒZ�Ó–yçô<¯�œåÜL–4XJɱcÇ8~ü8×Ýp#/<—å‰ÑáÚ2:kvv¦¥ÝÍŒ$¢R‰©©i—xø–ã“ EÚÉ�éøø–Þ¨ˆ4­¬“ lh -�MIcðæ3Z†¦²¤©ñqµ83ÇÙ°Á>áhè&M{¥ŽßT~ÈbÖ›~›\™ ¬1‹ ­ †­ Sl,x”—“Ïz 8åZyŒ ©y0Ã'g]iæßñÀ™'ÎRÕ¤��/qÌOlËyïæÎ,oåßÉ„b–ôìêõ/«”ñáë÷Ǿ*T9Éÿ �%rGÿ*™É,�ê´y u�EÚà»45|4™±��J)”¢r`óÇ%1ÞîÊx–Œ9éP4G¨Qä²ì·�8¯|;Þ7Ç„µk4×]Ó¢/ÿh×¶Êx�Ü$ÖG‡ñŠ–þa[%Ï7únæ4·”‹m¨?DûVs7ÚX�·‘êf…�v¿‹Ör­D�¿?6£}¼Ùº‰¼R—B?åvð&eŠk­ÀËnú®*”Ëcàökh³Ë¯£Sízñƒ•µö-¯´Ö]¼W|®Ð2KÜzJeϽDž×Ok´‡Ðº¾0†DÏ”ÍòÉ(ëaœ!4ïÛÿò‚°ý0¿‹k<¶NóÓn퉖'¹Ù²ø¤mýdŠ!­«¨>­b �ù¶Â‰00ÏEVÞ s•BWK ‘êM*Šƒ²ƒ4/I¯§Î"ÀVˆ#¸}+}‹”{ÏkB`«Dg'¥¨(ÙB®v³}÷¹V�¡ì²2ï¹~»NA§‰`e{Ån�LPï'¯¸PY�î}?ûí)œ×€Ê,ƒÜþÂ�ÏijÛVa!XÛ<¯™ëhÖ¿yýÛ‡¯Gx®Yx±ía´ú+"ªv[Ç1g9å‹ýJÁÄ!SBÁ:N|ŠˆE¦hZ�5:ù’c¸ "²hÅC»C¨­•‚/DFÙ"M•Š”ÔÍG¶zlým�¨gñšÍ£*uD²ë›]ZØ\8L&@+>$JNd÷­ÙšÉö†ý3ó€qýõ»®0žÊ #çpa…ÌGC˜Úñhl „‚D@j,ð‘HC©j"^»‡¡B„ ¥Då”r#&n¤Úò?A·• TªCˆ$±~ÖˆSš±¢&ê4hª„ M )±Òyд�“f„¤„R…‚r$¨”4NUÆÚV™pq¬ˆ�Š&š+�ÒÞ–0ŽI!�Q©Ä&.¶Á\… ”),œõOIЭ˜5äóö[åX6¬6Ý}¼xêÂ$ålµü™!�™ß<1“M¯óLðÖdQ,ç<lϽmÔ‘þ/4§ÿTz|"óÌñ×­Vh§NTŠj9OüÑâÖ±�º|Ïw2X¥€”Î# ¤ö$Qš¸ÑѰa CI söÚšRÃÓ Â@8fV¯‚A(! %¡Ã¿þ‹oý ÿÛ÷~@C)Y^⦵Žuw á”ëqB$Ãe@ø¼b[O‚õ8ᓵ ÷<”’Cý½”ƒlïëéâßôtñíÁ!~º0ÏCËË.~z›)i¹V«üüÈGÊUÆLLõD)ž™™çê¡~ºC2èÍ…e.ëéry&*e6< ÖÑr‰¯MŽ¡”âãÕu&«v™²¯®¬òW³Y¬üoÞpƒQ›3̬ „Q`âƒ+M …‚@*ãMqyTf£V'ìׂ¶ÅF“¥8&UŠ@¶uU‘B0R.qzu�¾(ä«[ƈÉ“çX�c¾<1JIJŸže¹3\Ö!†þåø‡+Uþpæ"M¥•‘¯œ<Í+'O·…�.+•ùõÉ-ŒÉ;‹+.ém%è CJ!‹�&Óµ:_@X�cž›™ggO_œaz£ÎûË«!¸kë8±R„aÀÛëZˆÕßÛÇÁÛ1qÈÜúV $’É‘a&FÆ™š�æäÆ÷ô °½\fz£Æs3óìëífwo7ï,i‹y|}ë8S5Ôª®o#N‰„¢; iª)à™™ynïîåhW67ËÇÆRwqe•?ù,?~ÒZÆŒ ÐÝU¡»RE�µÇÔ VÖ6X^[c³k(¸¼T¡7x±¶Î\³¸¼ÌìÂE†r'²2Œ¸ÁŒv‡zµ)^0‚ý«‡ú™o49½ª=vôv3R)»�BÍT±PÏÛë?1=‹&ªÂ«Q�¢HœW@ ¤iBbr (£°4—L 4þðÃlU‚€Ú&¡H.åÒøËœm“b) ›#Gzg‚%”±ðÍ Ñ ­}p×nz»ºYY_caa�é Òxëøµ×“¤ õz�é©)n¸é„LO]à¹gŸá ×\Ëñk®emu•gžz’��A~æ÷Z©ÒÝÝC„,/-qøè•ŒŽ�144ÌC>ÀÄÄ¿ðË¿‚RŠüÕ_06>Ác�fa„Ž_q*5±ímÒ sv¤>¡iùU3&ªG;± wÞØXøV1�¦™b \.3ÐßÏØø8Qe´œ‚é©)¶mÛF7Ù¹ó2¸ï^Êå27Ýr+]]]<ôà(¥¸å‹_bÛ¶í¹äÃ€Ë p)×öíÛÙ³g;wîdËÖmDaÈÅé)Ò4eyi™Z­¦•×AÈï¿ÇT*U.Ûµ‹S§>dæâ4Q©Ä·¾ó]^}ù%N›äÂccã àì™3L]¸ÀêÊ BÂ(bß�ƒüî¿ÿ?8{V?ìíã†Ë/'Š�”⼫]%EWIÐS‘tW$¥ % tH�®J¦³É‡…<ýä4 ºº»áì™O8wîSúû¸ýÎ;y쑇ÜöìÝ [vŸ^\å—ÿí‰K†§õ¶¸îºë(•ôÙj•VplÃ& ùvÇÇ'˜žÎ''.^»÷ìáÏ¿÷=÷û¿±J‰–uÂXÊãñoJ J‰™ ÐÂs�ÀÉ0 pø;:»2¼Sä!U±hö;°¡@õæQ"Ï™äš dƧ¶£ÑŒÂ eiÀÀñ÷ָ͸äx¿O:ä\èn¸08¹ÆâÜ=Ÿj±ì.À©⢵D‘ìTWû·3º»>ùâ¨3‹»…*5P‘W»�_.4�'h©Ã ÌƵ•¤¨4ÉÖ‰²|„ÈwËžWVÑaԟŽóxm¿ß�æ0÷ÜŸ‡N½*–í|é*÷wû…¹o)¸Ù‹uµïAëú*”mˈ}V»í6›zZnÙíê·sV|Öÿ|Þ«Ó»ùû—´öZ~wz«Ó3{³ç›À§-žè„;ìoÛ–ð~³Éo£4n‡‡6Ýù:ò{&dý_? ‘0[Ü"‰”ÎÂü&™ˆ6e¬r “±äŸuêgqŒE8H2æ�­Ù gç¦ójr÷Û¡f´^Ö´žõ¢VX…@h«¹ÀÜ�)„G(¨Län¹½(Ìù.²È%ÖS-µÚ¿ÌDKœ ÊŽ[µÙnŒ*[(¾~^ßöb±åǹakÅE¢ @óÊ™pÙÜé6d¡iœ�ÀÅEk7Ïæ`µB=g•`û}E€ˆÜŸn²rɈ³~x”“yÇm%þþó`Ó¢ÄiiË›{‘áè|œyDÊyâ(;®NHMÙq{ðò PˆT—7×O³×•iÎTÂVH®Ni= &F%žÛ¬W'» T³Â¸m¯)ha†È—Þ/ø›.ƒ™ ÝcÚwsá’Z{õ¸:M�œUŽžc!Uæ ‚�‡…‰ð»ã-§<ûçÍGËæRÞ:ËýÓvÐ÷m£ú–ž‹-T5û\å’wd£Hs4¿qÕ¤Ù’„�ÆŠ4Á)0Š�4†8VD ¨ -h‘(í5,�õv"�‰8ÇÊ(tN¹ZŠå’þDƺ‰�ô24…¢aÞÑé/´•8c¡ ç&Êä`6“j„ó™…N!Z£2sjáfÖ‹µéÔèÙÛOn~²{ŠÏÀo§ÒÃ¥~X£ÌÊŸÛV² ˆb¼ƒË{Q|Ëœo™šOz)\*²]¦ÿòð·y1‡WýüúÑ&¬7 vèÊS[Wq{Û÷pO™-…*V!/óЉ2ÊK}&ÛsÛz¦B¯ÉPè¦�ß¿‡Ã»¶óÖÇg™Kþý¹sü#ã\5Øçàöñê:ã•2#-œ-—¨E™P¿/ ¹zHÇîÿt}ƒÑrÙ) ^[X¢7Š\‚±0äžþA~sëV^XYá­õuNÕjL7›$©¢¦RJBІ¯t1VЏv ŸIòæ�å§ÀÖj…jº¾Ü:>Œ‚åfÌz3Q­0@Äb£É s Ü6>BYJRÓ×¾(¤”¨¥)¿}þœCÝ;FǸnÿ ªG)å…nÒs†Úƒ> Q(´’Àh¾¦’˜RRORM®@)År3æÅ¹9®ìãP/‹�&o..Ó…|y|$©":Áèj³¿¯‡¥fLOòÒÜ"ã•2??6Æ ý}Ü7·ÀýK ,tܬVùZw/Çúi&)¡ìg¸\âñéYÖã„ÛÆG虚a-N¨ìêéâ�¥w¬Õ“”r(¯è¹ýxe�•fÌÃk+®­ë�^M)²9öHnÏJ)¸ñªëøÁ‰¿£®ϯ¯qûè0�÷Zœ°‘¤ô…R¶T˼±°ÌF’pd �8¹¼J#MÙ××ÃÁ¾Ÿže­S‹¾¶uœIòÑÆï6j<½¶Ê¢—fsnf¶¢Ž—ƒ€ñ dW©Ìî¨DEJ%méütA âN~rš�˜�«´ ëg®u¥è2÷—›qN�õñê:®¬ÁH¥Ìl­Î™5­482Ðǹõ æ=去”¦QRU»)“ÄÑCH‚Ì #׿<âú{+ 2¥¬b #-sF«F9 I ŸÞ1£p¤TW�àê+®àñ—^ä±ÇãúoB ósÜtËm¼úòK¼ûÎÛÜþ•¯2>1A•H“”f£A’$TªUŽ_{ÃÃ#|zö,§§øòwE¯¿ö*o¿ùW¿†#Wã“Óë8òÀá£W¢”bl|‚-““¼øÂó€ö4:¼o¯é�0y:$Âä À(D]x2&V �¦Y„KýŠg¨ƒ¡W ®‰ã˜ÕÕ5NtŠ .pÍu×!eÀ¹OÏòî;o344Ì×ïúï¿û.sFñyù‡éëï'�X8ŽyãµWâ®o|ƒ™‹3¤IB­¶Á©S§èêêb``€r¹Ìêê*Í8æê«®¢§§‡0 & æç‰J%êˆj…+!Š"žî”R\yì*.Û½Ç%îî.qøè•|zö ÍFƒ¸Ùä½wÞfii‘(Š‚€_xŽ$IgËäV^õÖ×Ö¨V«|ë;ßåûþ=îûé½€6¸øú5×ÓUŠI¨„P-Aµ,©–¡«ÐSôv‡ôv…”BE*MzÖ*nµV«U®8t‰öŽÏ IDAT˜þ�ž}ú)úúú¹ê _`êÂyšÍ&µ Þzã õ:RJJ¥?øiš2¹u+ƒƒCŸk»H)att”½{÷211áž:|„wÞ~Ëí߃—_Áé�?r!ƒÖÖV[êû,¥@†tU»yéŪð ÷ìB)"� „U �¡eá"¿C3c ]0Ûþyä×j9›¶+Öæ2õ íÕ�{A®É±Æê^@.¼@¡Y›7Fþ$'7¶‹Ã}ÞÅþë…�ðø£üåów†¢T…è…wýj=ÏÛÀ¢ø—OÛ·¿Úõ«åíK˜‡vU+�‹"wÏLFFò˜oœm^Ëòv*˜ÅY–÷3†Ðqh-4|§’- Ñ&õùÓß\t߂ڜi›X5eàë&ªøÂßg2ý¶6{ß玼²¾ð/÷~‘Ë£ãZíè/°éx:-üvŒ˜_¾ã†éP¾]6{æß½Ô¶6+/:<Ûü~ûžËús¶Ù>ø¬vÛÀÜð©ùP;­Ï[Ú/ä/ÐYh֯φó1çJ›pZ’¸ßVÐ(r‰‚}m¥€}.Š÷ û™Bû¾Ì«E1�÷"5 ¹>d²X•kϯ*¿üè"¯M–¦æ°�B@X&XÊÌJ1�-Š�ÀX È\<„®aâ'ÛPB.]ŒHs6;¥€Uâ ûÿæ¿ú¿òï~�fœp¶^çÄÚ²ô2axêiÊJ3f¤\"’’�$å¹™y¾41âÊ®4c£Èy ìëí¦,uüÆF’2Z)3ZÑá†úRøoÆÆœ`ó™™y¶xü3ÆZuÔXKn©V˜¨já͹uí¡°Ûx-<7»ÀH¹ä¼–M>ÝØpåû£�C}”„ QšœºÅxDÌÕüÁÌEΛ0 aðßÞ}— i’º• …pôO ¡D:oƒQ æŒ?7 À÷–V8³¾Á­cÃô—"ŠF’POt øÞ(äÐ@/C¥Ÿ®×Xh4¸e|˜xe�–W¹¼¿—ƒ}=œZYãÂF�D)¶wWÙR*q´Tæú-Û"ɹZ�ÚS¤G V7êìëëá@_6j¼º¸L(_7ÖþkqŒµG\‹c¶uUYh4(E¼¶°Ä@qãè• àá)�€ó+“c”¤ä§ç¦é¯”xlI‡¶)E7^y5¥(0–Î8ä Î`ä ‡®ä�§fm}�gVWxhz–ý=ÝÔ’)�OÏÁ[FY�žº¨-q·wUÙÞUáä’VDÔ“”�VרR)ÓH#¥ˆûÏM#…àò¾žÿ�½÷޶ë:;ûœsû½¯?¼‡^HÀ ØR¬¢DZÅrÉØ˱W&ž¸ÄñØ3ãLVœ�=ÉxO$GË£8¹¨X¶(Q”DŠU콈…xè¯÷÷n=gÏ»œ}νx ([Yk6ÖÅ»÷”]¾ýíoû«ìŒŠ\ægB0IÄ«�¹0b* ihAlNÓ¤¼d„ Ëó)ù>EÏcÈ ”W�ïsyw…7f´‡‹„kúzxk~‘í…hÅÀ‘‘SܰwŸÝ$D˜ÿ\aT<�þ\8º°¤q<ÇÖr)N. ìé*óT£i§–« %B=%¸7!’ùXâûq`Ó%Í&L‚ï‚ï%�{úÝ0E W,.iÕVîœ>%û& ÛâÅôÑÝt’ïé^ Á�ÝWðèóJ¸ùøc�1ü©O%r9\qÕUôôöÒÝÓÛoü€¡¡a>þ©Ÿàoÿú«dsY>ôaå)ð½¾ÃØè(CÃì߰‘R©D±X¢»»‡3§OQ*—¹á}‡X34Ì£?Äìì w|àƒ<öè#*pÕŽdƒ@³ŠÊבÜ]e¹4<˜ùd,™C'”PrîôyK¿¿¸¸ÈÌì,¯¿öµZ•B¡ÀÁë®çÌ•”·P,rîìY$’-[·Réêæå—^`vf†¯e`p�'ŒÙ™zz{ù§¿úë<ûôS6¡íoýÎÿÌôÔ¯½ò2žï³aÃFææf\3„ïûÌÍÌpúô)2™ ÿÔ§yõå—8zä0ËËK8x-K‹‹v “““Tk52™ ­V‹f«É_ù¯�R²ã²]4êu›wààu×ÓÝÝÍßù6  •J—Uf ¯]Ç“O>ÁúÜg-|nÛ [‡‡ð¢&YO… *æTè |VP,”K•J–®J–l2�²Ey1é±´´D­^³y ÆFÏqïß|�L6Ë•WíåìÙ3~û-Õî`aaÞZôA†îž^|áy~åWþGÂ(¤Ñhiºo÷m�¿øé�äò:/‘PÞ.ÊJFè;¨õè‘d/ºtà•Þƒb|èã°¥‚vvÐå· ïêðk2ù¬Yo+Ÿ+Í¡Ñ%öç{öï«üˆÛNÑ7X Ïoà~P‡“˜�6Çl{]ßðÜþ[(ÿ­ôóBåïb Fj•Ϻϟï\¸úөΗr>ؤÇÝFàRuœ¯ž•î­¦Íô{2õw¥bøTWØ–®#ÝŽ\á·H]KÌõ” Ý¾ mQÚ>‘ó¼Ù:�ÛíKJÁ�è»{½“2żŸ¾—îûÅÌ_‡î�§p6¤�ïá&d�Qø:¤�§­k…¥ÓJИ'¥�Òhæ��ÏtÍi*-ˆOÏ©H×é–”°Çùmî}�LÈ¿l�z®­%iº?©ßq Ãä½Äã%`· � ›¾/cþËagâþ¥ÅY¢m@ú‡Û–aü¬Ç€{Xt#Cš@BôÒ��3_Âé¡–T�»+x´]°ãs –sJtç+­$HÍ^Ñï˜C¤·Ä°ŽNWu“.\pâJ �žc#µ0›D[ÁNj:1ú&h°é“;>Ú¦Ï>çô%©´ÑVûZ9`x¢”am‰ŽS 5nææ âzÇØ03ž›�ƒMÂåþ5¸Ÿè„Œ§ÉÎa²ýØ2G¶+ÇìsÂYƒíp²9<ˆW™™SƒsR+5×ÙÅ”˜– ù¤µŠÔܺ4õt€t:$´ ÛÏw@èpËYÉη$}¶Š ûÎý´Ü©ÍíO§­Éuðî´¥—;Â�§7Âýî!LòS�R¾¾ç „¯, �RÀ|,7Ê£@ðLè?_}Ì9ß“øBYÁ39~åž»ø£¯*«ËûggÙR(pM¾@ÑÖú�(bºÞ`@{ä=Áµ*„A¤çÙÄö¯Õ©E›tbâ3ÕÇ–xŸÉY ”MGÖ‹ÿµ½xBP‹"fëMÛîB«Å33Ü2<`s[\¦” ¬RagWÙ’‘HÂÆR��¥M)9:¿È¥•2ëµ’àñ±IÖòìЉ€¿=7Ëwfâ Ÿ~ÿ-” K'UÂPã1`¶Li½~2¾ ¨0MF1`Êîž ÝÙ ¥ÀçøÂ½¹,Ú0L$%ŽN�÷}²éù©ªaÄ–R‘J& ï{d<�Jà3V«S®èébM>ÇS“Ó„\?¨r<:6I£ÙbOw…K+%^Ÿ�g%@ojÄ@.KN) &ëu®è#çyœZªrta‰KÊ%®èåˆN~;—iróÐÕP t³¾O(áär•=ÝþdrÜÒ‹CW¤»\&´I�§€§÷+µgžÏûÜÈ}�}—Å(ât½NÑó¸a°Ï†Ñ(S- YW,°Øl2ÕhðÆüëŠz²&ju~0»Œܵ~ˆ3ËUNk¥‰º²µ7HÉÅ"ûK%fMP‹"ª-%LßR)á¡r@€J|¼³»Ìƒç&�²BPk…V+„à±±IjQÄ–ž²�ç#'N:´AS")-�máíÐ+ Ã…áY%ØR+ääÒ²e$ðИ²òÈe©j€ Ž٠sM7ÄPl™ox3•TÕÙ#Õ@°VDi2¨K=Lòñ‘T‡';—û•¶_æ»ó„S¥J2©…é–—ŒŸq•æµ=—n'ŸÍQkÔyëÍ7¸l÷ …££çxòñǹþÆ÷±uÛ%LMNòÒ Ï³}ÇNúúÕš[34D.—£Ùl21>Æþk®eyi‘|¾Àý÷}ƒK.ÝÎ=Ÿø$“|÷Û�Ífùä§)¥ “E!?ô=;†k.ß“Øg¬‘ŒæMTBnGÙlØ1{N1c�R ³Ÿ)FÓ×ÊWß÷) \}àSS“ ¯å[߸—¡áaîºûÄ­�¾s?·Þq']]]¼öÊË,/-!( ÌÎÌÐÝÝã}� “aç®Ýär9~ð¢(⊫örÙe»øªäg2Yn½ý[·çyÖŠ=“ÉP.Wxæ©'™Ÿ›cçe»èêîæ•—^äÌéS >õS?Ãã�Yߣœó(å…ú<Ê¥€R)C©œ¥PÎ’ È€Ä'[ÌÚ¶'&&-ï°fhˆÛîø_þË?' CZÍ&6mfnnΆòyíÕWÃÙ\ŽJ¥Â©“'8yb„ ÈpðºëxùʼnÂ|Ÿ»>ôaŽy›cGŽ0¸f!`|l PyŒR```�éé)Μ>À–­Ûh4œÕJÏóèàÌéÓ¶ï'OœàB¥««‹ññq^yYáÁšþ¿ú {°¡7=aùgå>kÎ!j/TyÁfVQÒ‡—‹y/mŒ”<ãÑñoü=fIWêƒÐt2]OÜV|X’žq«KÑþ­u*«±9ó�ç¾°=b§ž·÷Sƶï:(;Ôש�ôþÑ&ëm03a6ã�JbH|5�;0¾Hc¤U•¶¼ *ÉyOT•¾~1Ý]áY‹…vkIöõG“UwµÊô:3ßÞÓþÅç³ÎsvþyŒ­²Ï·Ò(Åg­ªŽÕsÖìLk:_¿Ø¶Òó’®s…6ìíôú0¿…³Ö/´†ôó… †[v9gW¸¥ê4¡Â LÕ:•F$ÜyK ¨Ú÷#¨rÃÅß­GP·Ó2R 1Ý6t¨;wNÒùJDº®Åå©%ç�’Àó½ØÂд§€ïz x±bÀÊ.…bfÓ”»<“ãñ\i�S€ÔéÎùÝNL…À LÑÌs;á±PpàèЬ…¸®ßÃ'ÃRعJ¬ =ˆ½tß\E€»FìÇi¡s+I»ÿY%t;éD³Ú€ïL–ýİ‹Ýiô_žþ—P˜¤¼î5{Ê‹ëô„qi—±òÄ€º2 §ž´ÄÛÅûðJe%âè8³ˆô_W!è „¯Ã±˜¤%R‡Ï± -”û¤ùnÆ9ýmëÃ*©�¦¨¦…Ud¦ã÷'‹3i‹Ëë9GP{¸v}ÓŽQtX3d¡$b‰u»�O�ÝÅAcë¡%•¾»\.Û?F¨`Ö¦0�zÝœ.n›6�Gq„ÅÃ!•N´¥Ÿ=‡‡€Nš.… -äë�Bž/ ‚HÅ\õÔõ øa„ßx-�hB³¥B�¨8»B)²Ê’-«Ã’ u h”ÀAýñTŒxO(Œ„ J!ÐjI_xJ1 „$2‰¥DŠ(.Z�a¡û·ãbôô:›HÊjÆ 9—„º¬F1°RYÍs†|š¶¥ÓfÊéØíñÓñW'Î"¹œ:¼ÓöËÝèumšˆ·¹’Ä×X‰"¬`Ñ—Iï=ã5 œµ)Ì>œPxzÙzA†Là«}[€G„'"+è¾óÀ^^{ç$¾øŸe˦M(í¨*A@E ÓßY\bs©HQÇÔnj– Å<ëµ"ÀÊúÕ”µùœU(Œ×êôd2\Ù«¼^Ÿ�'ïûÖÚ¢Zg¬V³Š�‚çqyO—­S€¦Ï4š,4›lÒý<¹\å­¹îÔI‘*|O= ÉxÊ!ò`/ž'¨‡O-.ð§Z °oûv®Ý³!¤Ò0H£„�bÅ�_!Èx�õ��Ö)ð’L–……*Ëù[ÊEæM^Ÿ[`S©ÈUÙ BržG_6C(%ËaÈþþÂH%s~tl’måw­[Ãl£ÉããSd<Á]놈$Ì5Z´¢ˆF‘ñ<6—Šœ«ÖèÏeysn�žl†ë´µÿƒgÇñ„²Â÷…àþ3c´¤d0—e —¥¥ç)ã æMz³Y6ól,x~j†¥VÈMk(/NÏ1Z­Q*æxjAYï—‹Eî>t³T*¸Åɇ=ðâP7Qqhÿµ<ýêsLÍÎðµ…9~!—á™É|!¸~ —RððØ$¡”ìé©°¿¯›oŸ§EŒ×ê\ÞS¡ÞjqÈøï,,Ñ’’¾l œ^ª2×l2˜Ë²£«ÌóÓ³ÔC5_Z?d?ƒü›¤º•?ãLµF1ðéÏ嘨Õysn�ò0­Õ92¯ÂvôéDá‘”)Å€¦¦f¯ÒJfO‚øoÌ)kê®LÀp!ÏáùEæ›-Ùné�>ëxôjkMz4tÌhæÊÜÒ¸zÑ!…\š¯áF)�XÅBIM/½amç㤔d‚€+w^Ƴ¯½B¥Ráé§žä–[o#ðº{º) DQDOo/·Üvƒƒ=r˜¥¥%nxß!žxü1NŒçÆC7³yËÞ9v”™éi–Õ\w÷ô°eë6zz{™ctt”;?ø!? ’’žW‰i ùñIÞ~óMk�~ËmwàyžíkµZedä8[·]‰‘ã y¾ô_¤««›=—_A±X´á”^w=ýý6Ap£QgÍš! …"�Fƒf³ÉÓO=Áìì,¥R‰HJ^yéE6nÚÌÚuë¬õ}¥ÒŇ?zßýö·˜œ˜`íºõŒ��ó;ÿÓoÙP:ÛÖ­å7ÝHFóI�”ä|I)ï©|�rɧ\ÊP*ä Ù¼J ï‰�ŸÍØYX\ZdØ"Š"«�00Bpÿ7ïµ^ù\ŽWµ¢eã¦MÜxèf¾òW¡B4…-µ;ùvøÎý6„U.›cb\í?™L†k®½Ž'¿ÿ¸}vç®Ý¼úòK,,¨äÀc£çÝðhͦU ôôô2;;cù¥¾¾~¦§“9#@ñ—îØÉoüÚ¯Úkÿê7®¦Ò•±ž¨Æ0H1 †÷×g2a��ÏX«<á8Åe¾WǪ·Üƒ±Û‹4·—&riþË=ß‹ÔQm¥Ñ¤ëºÈóÝßKi\Ä{*⽺Qèó(‘+Æsøf#”qèí�¶¬OW8 ý5Óïv¾WSÞ«zÔðY==¹¸:;õûB4à‡íËùæó|m_l»�Ú¹�Ü­Ó~Ðyè,kXm?Ò}�Î_®%¾ç<ÓëØ€ÝèkAQÛž´ÒǺa‡Â$Úi�Û·4œÜw½Ôõt½tx¶ŒV€£®2ŠD©]|«PJ?ðã˜Æ¾IŒ["Z™Nh§&sÜMË¢Mé!¸cI[ö&k2w’µ¸™¤[Y‹þ6"o¬_¥Ð>õ=Giaco‹˜‰O.Ëä�ÈJ ŒÒJ^& Ò&<²{�0ã6p•ñ_™:Z¥†&c¥¤Úæ=”°#ž¸ø/ÆŠB1�Æ«ÃÚLØ�´§^é$�Lx)—©ÛUfH”Ua‡(DI–1sf¤s �$)pt_NÏuòºËÆÚ�2 ]€¯¸ _ùJH¡5E Ln ,M�žŒ=l¾“æv �ºgz“Xï"¡p•9®%trhf,õႈãqº Ԝǭ€Ò†N3ýÐ8ê6žhJÆsMúº:è‹HY#±2͉CæN?+,u_^&qŠ8Zš©çÙÑcè†Lá•?)øê½F"•p2’¨¬êJ¸ê E„ð$‘dðZ´Àoªxï™@Ò UÝžÎ/�ϪäÃmqE*A… B”F"ÄR'’ÅÃ&–lÚ8çJ°ù±þQç˜)‰<�ôPÃ[ _°nãœÉ<,1�0ޠׇŒ4}ÖÞZ‰TBt!¬×@rê’¡.ÌT¥¦Õy·Ó‰äÁm�š.iZ�ºkH¿}&½`ô^áÀ¦“R\÷¢£r@ڻ淢;Fq­”±7�ñp›zb(&7•ÔØW �õ¾mZè-„à·~úÞ:u–ÓS„Rò¿�:ÅïoÙÂŽlŽç§g¹y($¥Ž…¯c_Óß‹ ½aH¿¶N¯E/LÍrÃ`9� ¯ÌÌsÝ@/Y-,Y“ÏQÉdt½ÒZûGRrla‰-å¢U<1>ͦr‘Í%¥€˜o¶¬``C!OI{TÃ(áÕðæÜyß·¡ŠžšŸç÷OŸ¶s´~`�_øðÝ–ŸÁ‹ô^‰†½ž!¡bX* |! „$ã й.•‡AÎWù Ê™ ×ôÒ›Ípri™F$-<_˜šålµÆÁþ^† 9Ž/,1ßl1×l²‘¥Àg@ ñ'ë ¦ë ­é'’’“KUÏ/²»§ÂõÚêþèÂÅÀç¶áA–Z-Bâ´+s�Û»Ê,µBоÏS“*|Ó-Ã,µBŸ"ïyܱn �0b´Z×x¥¨lw& )³ü['~õÇÞ+•b‘V!L2/C3´w‹ÙšB)ÁøØ-à óWÌG!_�™æÓåvuW”§„P!káñöü"ÛÊEfMr¾ÏýgÇÉ Áþþ^ZQÄ+3*œÑö®2Û+%î?£mõ(¢EÖËD"ydl’Z²&Ÿ#ëyÖBþuÅ;»J<<ª¬óQÄîî2χ*ö¿N-UYlµðµÁÃR+dc6ˉz�ñéifæè®Tìºw™máxr™r4l²ÇWÊ2_†ó9«äˆ¤äé‰iª­ÐR £ÌÈû>kò9•s �¥•DQ+BõÝ( QKsMn=ßCêœ8ªJùC'6c�! �;©`º%XÍÔ¦z®hÊþÝ{xöµWáû�?ÎÚµkY·~=·ÝñšÍ&_ûÊ—èä–ÛnàèáÃ,//sÕÞ}lݶMÅxdäø;ôööñÑ{>N¡Xä[Zü¡!÷ÝûuææféíícÃÆ�|ë¾oÚ0Bûvî$›Íh¾9@böÝžöŽ0>%±­¡¢?�gÿÆu(a³ºÐÐ!Ð Å"ÇŽ¡\®°{Ïå ¯å[ß¼—å¥%îøÀéîéáë_û*µZ�5CÃÜ~ç¬ð`iq‰îžz{{ñ<ŸÃo¿ÅÜÜ,»÷¨|¯¿ú G¿Íàà>ý3ÿ€§Ÿ|‚0 ™™™æÀµ×Z% ¨DÁ³³3 ²¼¼Œ÷}ãëds9®¿ñgNŸâ�£G¬rÆÄ=O†¡ ToÔù›¿þ ÍF“+®¼Š¹ùyþù?û óMCƒü‡ód„ ƒO>�”ò¾R}JEŸb1 PðÉæ=‚¬@¡�5D.æ7oÚL±Tâò˯䭷ް‰�?x÷G8þÎ1Þzó ÝWÏ&*• ø¾{¿Žk†YX˜ç‰Ç`ÿ�ƒ,,ÌÛðCƒƒƒlÞ²•ï?ö(arbdÄòLO<®î•Êe2™ ³Ú³-›Í²k÷^yù%Ûv©\N$jïÕüø,éDëwZÏÏ~âRD ì_ |—ÿw�7qèhãÚ�²gÕ©¸¼Õ…ßK·óQÄ %õtò¯ÛçÜš8ê‹mGJ÷‚×é¥U—ÎãèÄs®¾ŽÎÅé£=]Ϋ›‹¸J§©Me…]‡X#ž5n]M•gœ÷mãˆyÝ”xè` ŸœúþøŸ~†ÿîßü«5jQÄð¿oÙÂ!-ÄnF�çq‰¶î?¹\¥àû jo€3ËUŽ/,shHYôg„`S±CJ(Ëu�²öo„CZè?YoðÂô,w®]ƒZ‘d²Ñd³3 WövQÎ(+ÝzYA5 9<·Èžž ý¹,¡”<2:ÁU}ݬÓ!„z³»ÒŸ˜Ÿç_ž•LÀr+äÅ©Yô÷2Y¯[áúP>Gw6Ãéeeq¼Ølrr±Š¯B¾{n‚HJ¶UJ4ˆ�ü÷ÒJ‰m•/Nϲ£PàD½ÀÛ##ìß½C ‹£pEÍSÆÄeÀóB�‚¹f“ÇÆ§¨°XµºM.|YW™¼ïó²V€@œ ³¼�…F1ª˜æQhiq‚¸Ù=0y½éæIÏŸw_Òít¨Ó¬)˲Æáv ë¡h`ò€+·ï Z­o½ù/>ÿ™ CWW7™L†]»÷P¯×™šœà¦[n¥ÕjröÌi^xî9ö_s�ëo|ãc<ùýÇéîéáî�|ŒF£ÁÒÒY�ç¤Ùh°kϦ§§éêîæè‘Ã<ô½í®½âJeÉï„oRýtöTŒú]íŸf]Ø­�Öû�;^sv2ÉäAÅÂ?}æ,×Ý�ãé'Ÿ@ÁO|ò'ñ<�ù¹9¢(¢Z]FÁðÚµœ={–5CC<ðíû©tuqõ�kÈf²<ð�ûBpç]"—Ëqïß~ €ùùy®¸j/ï;Æââ"ÁK/|;Å\@Æ‹Èx‚œ/Èû>ù@PÊ Šy�rÞ§”÷)ä¹¼ È�ÈHD Á��‡—�üž'¨×j”+J oÊóÏ=ÃÂÂ¥R‰r¥Â[Ú»b`p�}WàñG±Öý×]Ï>ó4ÕeE7ÆÆF©Õªz§NžäÔÉ“xžÇÖm—pòĈ tà൜9}ŠsgÏP.• Å@£Ñ௿–X>æÝB±H£^Ox˜²ó²]|á ÊQÆhíP‘/üÑû ò¾2‚ ^ÆÃËø˜¸yàz°¬¾¬ÈL­â=SVz¿O·škb…çVzï|Ï®æ™wSš×V'x¼×íÿ0e5ðJ}·çJ÷šþ®XE]™A›ògͯª¼W°¼X<ûÿË…ËJr�¿¯âö'Ý—‹¥{«}¾M½Xzy¾~¯Ô§óÑrsÏýëÖ±lÎGË\Y€©ã|–ø.-6ÏB2V»[?è0©÷„óŽë9Ðécž1Â}WPÖ©Ÿ¤¾C²¯8õ¸÷ÚùíºmÈõ¹s`Î`ê«9—©p£†¬¶ãDàû¾V (¯ßóð´ËtZ! ¥p@ “Š€t#F6!œg„Ûéô{¥èÍ‚¶K á îÓŽ -†ù�zÉοŒ�¼…ónÏR8�N¤­@!´ŒQÆÏ¥Â2ýR ô•p"~VÕÕ¾˜6-5 —Žr@F&†¼@JO�MXa‡jÇlÈXµõ�1ɺ…Û(]ú]aûêL®†¥0JWA`î§Ã(üµC‹á.lrÝ„(-[îEto“Œ—}Åô[ Ë…Ó¦µ´FázûKßódFÅC[QDZt B$Q-…‡BXÁkÿéåëŠy6jáý3“3 : ƒ'ju2NŽ�žLÀÁþÐŒ$�§BËœ\ZÆ÷<›'`dqÙ&õ„§|k$¨5qËðYÏg¡Ù"DÚDÄßœžæÿ<{Ö <‹¹¿ýs?K&ðð<“ÃLOlùk¬¾=a¼6 ‰Ô×=¯ ï|TBÙAí=±Ül±¿¿[[ã×xkn‘½}Ýl)9µTåå™9úsYn죩•¾€V¤’V^ÖU¦)Ø+3ól*æÙ^)±Ü ypt’¬ܱn õ0ä¥i%H¾¤R¢˜ñ „ZÅ àäÒ2=¹ Û(±®˜ç±ñ)aÄíkÉyß>3FSJö÷÷0\ÈY¡ôCóó<­Cå²Y~éŸP^#¡Â?aóM ¬"JÇ@"!$?û¡�rêÜYƦ'ùÆÂÇÃ&Ì—ˆ$Ì7C6—òAÔéÎfx}n�–”¬+äÉù‚¦fˆ€==] çs<¢Ãå|�ýý½¼:3Ç|S)0Lþ¬¯häáùEQD)ØPÌ3²¸Ì±Å%„Ü6<È›s œ­ª„ž•L@Ó�@É÷˜¨7˜o¶¨µ".-x`V)ŽŒœäª�»H1lÖxB"-ýèE)5îX;È÷F'Xn)Ïß‹± òi„Râ A)ð™o¶8®{{»Yt€RJ­‰ÂPÇÀ�b%-Ĭ™îŠºOÇ’}7!„:¥ˆ-´:ò)îiÀñV0ýš3Êg,½”äs9vmÝÆkGsúôi6oÝÆ¶K/åµW^& Cö^½€§Ÿ|‚wŽå®»?L__?£çα¸¸@K+ºzûú¹âÊ«æÔ©“LOMñ‘�ý™L†gžz’wŽåÆC7qàšƒ9ü6­f“—^T!pŠùu’Z­F­VãôéSäóy®>p�÷oÿ�7ßxÃŽyÏ–õüòGo%ëû¥@àQÌx³Åœ ˜ …¼G.ï‘Í ü,x �Ú0D Ãsii™JW~÷;¸æ õFÃæfØvÉ¥\~Å•VyR«Ö=ç°ßøúß ¥¤§·—|¾Ài�KaÝúõìÝ·Ÿo}ó^@­¿ ›6qîÜYëñÖ? ¡¿ !ÓZB6oÙÊÈñw,Î^¶k7G¿m®·‰[v^¶‹¯|åË<ûŒ ÷TÈüåçî`ÍpQ±!Z1 ¡“I7é°SÚ-~;•¶Cœyy…²Ò�•xÄøysvkk* ‡óÆá×UºñÕ\†0íYÜ¡s«óãé¬)+]�“îБ•úfa&ÏóPº5C¡/ðîŠ|¹CËRWLzª·“¼Æ}áâŽìÏÅ– 6ßVõêçú]·iž3Šöóœ�.®´ãAB™ß±¬¢íN赪;µv¡ö:×ÑNK:×ן…WžÓÕ·¿êç¤io%:›<ïvî…æl…6VÙÅöwå ë ½¶]AW”|ÆìXA¹Ë{§…L8÷ôsB&;™˜S#„÷íyOj~4iÍŸCäÒDS¯[L¿Ý߯ƒÀXþ§­t¥€L+ÜÚÍoC3�œ^R‡*–†&$å9i/U­@çpb`(µ0" :5’4ÑIRj#gL.UÙ>–Ž¥Ó�•6‡ah2ê«fÕH%pR$×�y¦�R8ïWK/‘ø})‰c4bÝQlÈJÈX©3dF l¥Â©±»ýÒý�&;®q?õ°ŒpÑâ±±6M(„ÃÉD›R*Wwk{.pâÑ{Äí j,•RŸ0ŠžB ¤ãE•ôr�íù’¬tƒ4Á1DR¸}tñÖ$Ø2ƒóˆHó†ÚÚ ’´À®O—àà̧>9mkÜ‘xJeZ§nÇ!u¨7f”…!2éÝ£ÐÊÅ·ãqê‹—S‡†-Õ‰%e_²´L«g ÝŽôø1kDÿ–éºU»‰ Ú¥}‘Y'n=�6c±Œ¦ÞH¤óžë’aÞ1áÒ°Œð"NHD2Öï …¯Fp¨’”zxH<éúÂAy^‡nóPVûR†D2L0p¾'ˆPÖâFø+d„�J¤ho�¼ ð„¡TŸHÐ u‚âH-9_b±7DÊÑ‚–�¡naÿÅ;þ.R4ÓÌ�ÞÌdÚ³ÆÁ_£ˆ4;M¦î…è }o‹ˆQ&ARWØ”ÌC ež�é¸ ­¢­]“ÂþxS7¡†bõšg=x"=gFŸ*¤ˆ}—¤^GH<½ÎK"O{‹„­VˆÐáѤ'ñµÔGÉÈ ºŠE>û¿Ä?þwŸ§ÖhP�"þ—'øù¡!~~�²æ¯G�0bM^YûÏ5š¼9·Àuƒ}€ZÒg«5zr*�Šíi¥Dw&@¢Bʘä¿õ0âØÂ;ºËôjËÜGÆ&ÙÓS±Öþ�HÒÄ›ÁÆR�uEuo´Zg Ÿåê>•³à©É6— öݳÕs�&{û{øüè(_�œ´õ”‹þןÿYÊ…ž'µ>Ô¨�]Eªº¦Bæ+OJ7¤“ פçK—z½Éqo™½:— Ósœ]®rǺ5tg3ŒÍ×Y CZÚúuM>ÇÖJ‰á\ŽÓË5–Z-nÀ‚7æYTuíª”xk~‘“KË´¢ˆýý=ÊÚÈ>õ(b®Ñd�N=ßlòÒô,;»*ìëïáôR•×gç)>·²Ü ™o4ß %�Hyq,‡å àõÙyÖòŒ„-þßsgíø>sÏGîïµÖ»†×ò5ã¿¢SÊÁ„§žÌe³ü÷?ñIþè¿~�z³ÁëËËlËd¹¥ÜEO&àÛgÆ(·2Y¯óꌲĽ¢·‹Á\Ž‘¥HÉl½�Öòœ®ÖèÖïæ<ÁŽ®2sÍ¦Í °··›Á|–Ω¤¡¾PʬÑZ�zC Ð�,,1Ûlêü‚W§ç�(/ƒ�¥/LÏ!µ ~G¹dáqäÄ Z-ãAâÅûªF¡0Š#÷�(ä‘ÑIª­�œï!$¼1«Æ¹¡X +ðƬRÄä}Ÿ«ûzxtlÒÒ�ñzƒ|*áuØjZO�(ŠbËaÃ:}2‚w)“ý2å½P ¨¦¢DIºév‹‡Öc Åú(|3´Ò°”’}—íæµ#‡xòÉ'¸ñ}‡8{ö …Bœ'eûŽ�ôööQ.W8üÖ›lØ´‰­Û.AF_ûÊ—(•Ë|àƒwðµ¯|‰Z­Æú ¤P(¨\-™,S““ ¯]Ë£?l´WïÚM ÏOñމ ã”®p¾-VÜV‡",ÿ',"�Ž‹¼J>¼vxˆ‡ü.ÖJŒ/ýʼn¢ˆ¾¾~ö\q¥�Cßl68}ê$¥R‰îîÖ®[ÇC~—¥Å%ÞwÓÍxžÏ�?J«ÕbÍÐ0úÈÇx쑇•÷šk¯Kð&'Ož Q¯³~ý"©<zðŠ¥7ßr¯¾ò2ãZ¨}íu7055iÃ5 «�X˜ŸçKñE‚ `ç®],.,"œ;7Ê¿þ½eCßà#×ïå7PìDBÈz‚|ÅœO9¯…¼ �÷È™¼ È ¼¬@d�dddãýåøÈ{÷íã¨V‚.//[¡=À©“'8uê$…b‘µk×166j•7½ÿ¦§§yýÕW^K¥«‹QM;§&§xö™§ì¸=ÏãQ�¼zhx$V°ióÖ­_ÏÓO>¡ðBÊ„`Ù²¼¼d¿—+–—–¸l÷nþÓŸü oü@)t2�Ç_~þn¼nXe_+|á£6:JȰ<$ËùN[íOþ0|\§–Ò|£)+µ³šÞ:üþJïµU#:]|—%}Æ{¯x_‘ú»r‹?vE8sÒ!ÜÅ�ki‡ëj!|^Ç�Q‘©¿nù»êÿjña5ý¹XÜêTç…æî½Àßw;æ•æË‘í\°žôsé3ò;>Sÿ gïŽ}0ÅU ¤éw§ß‘#Ñ õnüLRáà {!`RÏ®äÙà¶gÆèl°‰ß†Óó*¬S¯©;ݦëi�þkú¨¼PM„ +L¬àƒBxž²¨Jz è¡HuPŽtr¹ÈÈ5RÍ#ÝðÒ9 ºS°"ÆÂfWà”ø+S×lüvãxQN¥“×B«.mM™HŒkÎ&2®M8M#´u¹‡J¤êÅïéFc%·cyíÃ5V6ßMŒz+³Ý�º Å·­2ͤ–&œM¤cK âC¬q‰)’ö�Mz”cµš½Þ×UáwÿáÏ’ËJ/ëɹˆ,½�õþ6©sàãùñ55—^‚¯i4ZŒ‹:—háñ–R�þl†ŒŒ,.³©Tdk¹HKJ¾}vœÞ¬ÊC Q!ƒB)ÙPÈêùñ„ øÌ5š¬×á™rY^˜š¥àû|`ݲBðÆìgª5ö÷÷°®�ç�ÙF–ª©×ùãq^��ßú~]u•ÆÇÿÝñ Ë,hÅ�V`i§-$°yíz~ùS?Íg¿ôEZaȽs³œh5ùž$JÉ(ø>-)™­7ycv�MÚ3e¡ÕâÌì¼ 7tt~‘ñZƒåPÒ�ÍPô}ƪ*ÜÏx­Îd½NVó¹�Hò½Ñ °»§ÂB³¥b÷;ºÊ ä²<91 º/õP)d%*\ZŸçÛÝê�Ó§hµB…&Ân‰2Â*QŽFMn*T˜¬©¾]ÞÓE½òúœF.¶Z e- ydL)µº³j­�³ËU6ê„ߪIØj:Þ‘É/ ç'­5†néÊÖÛâ]—„µ|¬Hr>IJ…:Š/8_•ײ’�Kö^¶›/Þw/QñêË/3>6Æø §O�ä…çŸã¦›oaç®]œ>uŠçŸ{–0ŠØµ{ÍF?ÈçU¢âååenÇßyǬ§\ä×+¶mÐ#d(�¡Ä’¬'È‚BV*o�œ �Sჲ9¥²² 3(÷²Àù®Ë¥—lã䉆‡×dÞøÁë€ÔïÚ½‡ïÜ ” {¯ÞÏSOu’S'O¨¶|Ÿ(Š8rømÖoØÀäÄ$õºª«§Wí·&Ü(z³~Ã&þõïýãã _²>ÿåÿ¾•»ïܤò$”BŸiÌYÎ`Zš#Zéœå–4GåLÎóø…/v¸nøeáþt©çë¦{¥ï´õÛåÑ.¶´¿‘b Û»p�çíF{?ӧыŅžVó½r·;¼/“‘"̾iÏúæ,æJ´~èrñs·ê:öôÞµõÞŒû½ñX©/ilúQÀø"ŠLÑŸôíß:w©:Ëvå¶Þ«ù[U‘+Ð’tŸÛïØKdêjšÑIÓö‹§(í=Xé}IÒb¸Ó+Šw²çá¶¹ëÔF,é0a~“Á•M»îG’Ä‘ºfÎø+lŽç·mÏ­?©ˆ¥N)…�pÇ””)Ä`‘ÈÈÕ+_v c/Uu-ÐOh¢×e’TʃÂ!·¸IRðY‘Ï8Ïg;$bxYa“p`j6™¬Kê­*)‘JÕ¯'ÔÖïÜs&Öz]hA§nÈU0µUÞñ´Ðyþ >y’dABÈ)ܤϦmé(›x'”º”‘ŠŸ¡¥CÒiŠ!“Àˆå!áyI¥€Ë ¥?V9�î´•BÂväJþ]‘YH3¨¤~»×£ö×\á°G„M4ìÂÎàŸ{ì5°siF ÷Œ !ɼgÝF:f�¹iðÏ-^κ0Ò9h�k¬°JYâ»ë "¥X“$=aýov*pÚðXf­KçA»†W"ÉbÑÕ>.Rs¡?^„Œ\·.g\Ææš¦pÒ|€µ´E ºœ-C`�KÀ#=ÈÙ3g¸íÎpÉ¥ÛyíÕW8}ê…B‘uë×ø>]ÝÝôõð²NþZ*سmÖSNóÒQò'-2:ó7RJ�'Ú(R¤F"½ó Â,†n†LLLò~îçyî™§媽ûØÍAž~ò f¦§©.W9pðZFÏ�E&v~~žÙÙvíÞÃâÂãã<÷ÌÓìÚ½‡ÝÄ[o¾ÁÛo½ À?üQΞ>ʼn‘ãäóyrù<ù|žZ­Æìì ûµ¯Òj6Ù²uµZÍZ¹_wÃ� En¨T*sÉö¼õæ„aÈòÒ’²¶—péŽH ¿ý[¿iC4™rÝÎ-üÊGn¢\ÈEM|ãa,Tøœ'É’|V’ËJ²YÈd™ÚSÈJȉô%‘x!‘ˆòù|žF£ÁÐÚµtuuqú”Šß?==ÅÛo½‰çyH)iµB¾ö•/°s×.¢0Üoß±“m—\j•…B‘L&cF?ôàw©×ëø¾O&›µí .Ù¾ÃzÜ~ç]<òЃÔuN“é©)šÍxý» �B±Èú yü±Çø¿þè�,vweùÚý 7¿o�Ú¿|åA¨¼!ñ"¡Þ*|�ݸ ŒD¬@ˆÐ éÌf ™àÞ1¥Kz¤¸‚§´bÀüçùó•8±}çç.Þ&VŹ¥ï uK›x9Ù#T·„A¸I†c•º‰1mž‰a,b›Ùßô[-"57¾RÞøíÕ§ér¼¹""­’¤â\‹XP¨•Îî€%:ù¥ïüá?ù ÿþËËS¯+!Ñt«Åïž8Áí==üâð0³õKq‚á{­�»%¥µö_j¶x{a‰}½]!¨‡�OqëÐE­8Èz"aíoÞ ¥ääR•Í¥[Ë*4È#£“\Ö]¶¹¦ê QDŸöL8¶øṳ̈M ^?uë!nÙw… •؉À¨Ë1^(�óñž¯à.$ZC •ê�Í™¬Þ'•gޱÂ�R2˜Ï±»§ÂÚ|žw–hIi•OŒO1ÝhrhM?=ÙK­÷"Ç€êO‚>w°6“B‰N‰émM^&]µoןáðáÃ\uÕ^jµ*Ç�c˶KøðGï¡ÙlòÕ/ý%7mæºnDJÉK/<�çyìÞs9Ý=½4›-*•.&'&ؼy ÅB‘Á5kxè�ïR®T¸û#ãëó5 ãý»v«\Ä^°mû\b¿Ø-4qæH©ò‰Å€§-ÊÜ­ŠÅQ¿ …Âô P.—S‚á#Çé Ùh°~ÃF¾õÍ{©U«ÜrÛít÷ô* ýz��»vqèý·pÿ}ßàÌ™ÓìØy]]ŠNçóyŽ~›éé)Ö¯ß@©\æÕ—_fqq��›6såÞ½¼ðì³V0}ÕÞ}œ81bCçœ9NOO/]]ÝT«Ëœ9}Š£G“Ëå¹jï>æææT"ãb‘Ï}ö³¼sìXbÆ·÷óO}ÛÖQo4hE!©Ì:gˆðÔq9ëKrI.Ù d2d•—@�*�€V (Å€ôÑ7I<÷}Ÿ×^y™(Š( lÞº�‘wŽ1rü„ÜýÑ{xýÕW9®<J¥² +pîìY&''BÐÕÕÍòò�?ú0WîÝÇÄø˜M.|Ùî=ôööòÔßÔ^\XHôÇ(²Ù,RJªU•È8“É0¸fˆ³gN6mbäøÿò_ü® ¿ppÿö'·³s{�æIÑž5èrÃ6~Îðà®iÄÛfŒ¹+”6ã%{�0Î_i§³Ê…ŠìðÍ­k¥†W¦A+tnÕå°K÷í|m‰ Ü?ß{çƒßJu®â�ÔÙt¥Ò²3Ž® ô¹Ë†[¶"9vCùM)¼ˆ§/TGPiBZHë\3ÃÖŠ�€J�œbBÎÇDî32ž$gž¤f°^ møw¡ Ø}/†{âw›r@´�'ñq;¡¬LÍåH#”ˆ´à1‚Dì7ª-áu¿# ÜX0 °æB[œ�w>�`<BÈ^wW±‘;/ÒaAõójè"®ßýÝ ž™ØU¢ôBì9ài|³‚!ÓÙô§}<1ï’Fz o�:Ÿ·~gPiÒ6ßç’ˆ’!3±|ᢔ瓰̽C\TY&ׄ³n Z»,ÆóF:Š…_Ýo}�+që#&r†>&ögüZ°*u…ÔÄÄxM‡¾˜8ÿ ô5ž“ ÖØÊÚˆo"W[j�­D…Ö2‚É(Œh…!­P+ ¬Å­Ð^‘Q*D’P[F:·ZP©c\ke Š#ð<;éè®úüHàã©ÜQ‚(:A�IÁ»ê—V7Ø%­¬ã„—+Y¥®Yâ¡Ç$’wVÀa7&^‚F€ƒ—n3 B$ßkh :.9«¬Œ?n!³¡ÇÊ‚ø“¨N*¨GQ¼¼m‚a)ˆ<õQʽ|D‘¢Ë&É©çá„ÍÓVBâ…‘ÆOÝGdLß‘:\Š 1…’ÿáž�p`çN>ï}Ôu¬åggytnŽ»z{Yß,²ÔhÒ“ÉЭž_d¦Ñ´!…@ Í<å|�;†ÉùK­�É6vg¢ÞàØü¢ÍY°Øjqj¹Ê¦R6eWO…­ˆP!ƒ"à©…þ||œ×——SÓW©ðÏ>ùÖôô "âq€@k�«×¥�Ž'„¦”oRjÆÏ(�Ç€®òDS Š–ØX.²¹Td¾ÙâáÑ)¶–‹ìê®IÉ›ZÀ{i¥¤„×Ù ¡†Íd½Á†R�óu¢�Ïž9ÃÏôpÏÚ5„R…’RróÐ]™€ã‹KDRRUþ‡�\–é\– ÅoÏ/IÉ�ƒ}”2OŒOYOŒ¡|ާç8W­!„`}_7ÏN/ðùÙI&œ¸Ú÷ÜtŸ¾ýý€Zßn,øärQVÝn2H—N5Tl�°{Ûv~ãç>Ãç¾üçÌÌÏÑ�’ÿ8:ÊÁR™Ÿèíel¹Îl³IW&àŽµƒ¼4=GÌ4š\ÙÛÍ”V !XC^œžc}1Ï\³Ål£ÉcãSte®èålµÆ©¥ªÆ£àÙ)•Dx¹’õB»U,6[|ëì8ØT*R�"+˜ßÝSa{”çÑ9¥T8vê4;·^jÇéû1>¥Ãø™2YkØt6ž€±ZƒÑêB¶– ŒÕê6ò®î ¡”Öíû²)Zg<Ò[ê¯rí�©=p¥?ŒR@&º¥p&ËÔ ö5o‚•FŠÍ±?ÔŒ´ÉÙEd…Hûv]Æ—¿ó-šÍ&=üwÞu/½ø™l–K·ïÀó<úúû^»–f£A³Õâ–Ûî ›Íræô)Ž>ÌÞ}W³ïêýœá‰Çeýú Ü|ëmÌÎÎ266ÊôÿÇÝ›[vgb_Ö9wyK¿×ïõŠ}b!’ HQ4MJ"©�”FcÇŒ5²­‘íp8<ã‡Ãö„È?æ§8ÆG8,†m m�4¢$J¸‹ (‚W� ‚h ÷~Ýýú-÷žSé•Y•UçÜ· A-.àö½ïœZ²²²²²2+³.œÇÛßñ¾ atàÑûï3[à’lÈņr¶Fã�ïz£`p²gb®\¹"ŸþÉáö;îÄ/þòGðòË'ð­¿úªªÂ¯ýûÿ¯ž|%*î'“ ˜=VWVqúô)ÌÍÍã‰/ 7ßr+–—biyüñ‹ªªð�ý&“m|î3á´ÿíw܉·<üHTÞommâå—^ÂüÂæææpäèQ|òÏ>ß¶¸ÿÁ·`2™àÙ<�×^}·Þv;ÞñÎ_ÀÇÿà÷1�qüºëpe}_þò—ñ¹Ï~ëŠGÓÊ�yüæ‡Ã/>ö¨0™NÁ\¡’íH倪 ‡"È*rbpB5 ¸Âú‘ðA¨ª'ç.�œÚpúôüæoý'øÄ0qëm·áì™ÓØÚÚ3ãk_}Û[[˜_XÀp0Ä7¿ñuក{ß|þâ󟯇Ké?ôó¿€O?þIœ—ûm676¢×<÷Ì‚ç˜sX^^ÆÅ‹£Ááá·¾ Ïüàilˆ’ÿØñë0™lãô©àÅÕ4M0þÜt¾ñõ¯ã£ýhf þ»ÿúQü÷ÿÍÛPׯZ©zŒž˜Íd‹Á8³-Œ¾íR®}²û^äo;å»Â²7;Áß•W÷°›Üc²›Îòùn宊ÝÊ[¸úò¾0”-Îà‘Ŷ3{A³p¸ŸôãÆg9WÞ(¼ÍÚK½Qùßè´M½ÁmÍÚ¯õåÝ•'Ì*×i`°íVÇNuþMòڽ̭½ð°ò}¾wj«ï�ÙßöÖ­ßV¿ 'ÉaÞ• ŸpQ‡ý{V=³úÙ×–Up[¹QûbŸ•‰4æ·…Ù#,Ìž�½îQCWSÜßê¨tAÒmê‰CÀ¤1¨9œ¯`–¸ý’7*g2ÑÞ€&ÈÉçRø·ŠJÙâfB”Ž¢ü`Õœ�­Q«²1:¹WfïH<\~R�hÈ)Ç›‘„yP¬'e¡:/–=�Wûšy �dÈ N¬R¹óá°Û”9ÃшB•/¦N±)!í£oa™+E#…p ÎŽR^Ý…Ù=×ò‰†3aéÆLÞl”Øf«+uRù´7¥xb%-J)œ%kW¢»8áD±¦'âÐWä…¾ Å|Ð)�YË"ç0"éDDÈß�($:÷¤VC\³�3ùœŒ?3ÞB‘ó“?\¥„‡8ÇRþ#�s^ªõ ^Sø[uwQ°¬=¼–ŽÄ® s$®*rš êY-œá¤mkŒŒcÏ¡ÐÓøK¨ Ï{¨ê×ÉÉkå>^ÚjY< $‹R>\Ìb@4:†ð>árbH¼ê4�˜ £Ô6ˆP“™vÇ­'Ôž0%‡ÊQ¸ Ö/ƒi effü@G£Ö p ­F�]½JšR _�ƒQœäsÀÖÒS(û³WÙVvb3Sî¦-ÛµK?²û&¿P«L‹I´u 7!p´�1Ë6>„‡bîvqb È,H˜¶–‘î7z¥–Ñ htSœ&«ãàÑ¢¡-<¾ë.üÏÿì¿À¿úÃ?Âw~CSfüÉ… xüâEüÊÊ*Þ¾´„GÄ0p×Òb¼X÷âd‚•á÷È�_;ww--bUò>}é V†8¼ƕí‹É[`±®ñž£‡„A u�cªèÙËë8?™à 1~ÿüy¼l<`PWøÈO¼ ?óȃi=�SŸÍy ]Gó‹ŽÒ§ªÄ0��uP•æ· :mñÔÖ&VFC¬ W+£†Î¡ñÛžã= '7¶ðÊÆ&XYÂu�×7ð½µË¸q~.ÒÝÙ¶Åï\8‹'¶®â¿¼þzÜ07BÃŒÆ{<}é î?¸„)ÞòéSgq`pvi2�§áo?°€‘shÅ(YáÜö7Ì�E*üóýß6Š¥¹Ñÿé/ÿ,}ó›$ôYA •ùQRتQ@ç¿�!4SâVš­ÝpôþÅ?ýÏñÿ>þ <ù×ßá”z]×øÑó?Ä—¿ø¸ëî{ðÎwÿ$žüê8yòÌÏ/à—åWñÜ3?@“ÓàÒ¥Kð¾Åhxíp8ÄÇÿàß`<áæ[îÁÅ‹ñ]¹t÷çéÃX»x'^z P×5Ž;ŽçžùA(;âì™3X=r_ýÊWð;¿óàJq*n=¾ŠøÞ‡ðÁ·ßƒñÐÁ±8iÂ�¨Šç”1jø2±Cå<Ž‚Q & ÁSÀ hè€�“ˆ9É�è”y«.\Æ·¾ùW�ǨL§SüùŸ~ð¶·?ŠS§Ná•—O„¿}VVVñéÇ? (ê·¶¶0±½½ ï=>ñGˆÍÍM,-/ÃÅpCG�Ã�7Ý� ÌŒ‡ßöv|þ3ŸŽsò…çˆms7ÎË'^B]×8~Ýõ "¼ð øÝý»Ù] ]¯~änüöÿðN¼é1Îǽb4©ÅûÝÌþÂÿÝð‘]•-gov–ñʺº©ÜO”Y¹x]Ên³[ë“Øº…{àïdTöÓ×þªÊµ0å£m›šXÊÏcÖ˜®¤¼[*7ƒ3²ä?v¢„©”É‘ŒY�=Õ¥mûÚÚq’äñž‚;¼› Ñ.uï§Î²Ü¬¦C�åN*–ä|~Ù;A¯Ž~šÍæI§H>Ÿ÷jnÛ´QÞï©“ÓÌKúœð½³÷¹ŽÙL%Õc»g�‚ž|Ù�‰§øëH{šÝRÐÙ˜ó§ÞRž™mí6ÿ~;9£Ã6aw.•Ñ1-Ã\Á†J‡ôúBu¥O•àBÝ.okGã@__ÃÇF`=éN :˜¦UÌ~lR8Z“]£îX…›èw$Ì5QØ×é¡A•ÑÍõK¢Ü`3œƒA�9ço G® 5±ÿUPÖwñT®Óši¿ÔP^ÚÐKd`U`udë.Ef‘á8£G6]†–!­�úǧ {Ê šðÒS@% ´U÷Åulˆd˜µ�¢Ÿš·E4ÂD8ô‡³&Ø"Rþö,^mú�¬N¦ÎÔ5>uP²ëI_ž‰ätî9+ß•¬¦[7ÒéšÌ`Ãñ?ÊÆÌprF4dϲ&M�ä�V¼9”°5ô½ŠtL9ÊêJDÓÑošæ³ G:“Û|Œ1(¬¶QébžíàÆ>râ=”Nî‡nåzÊ?íêdnDc˜)kÇ¡Ãç)ÑxdAœæµòæà]#³Q#w xõ8ða>q¸œ”u^x ¶5„SÜ•xG0B˜ ç\U…zAñ¦Œ™C„ùh(‰¡»ÚŒï1³Þñê(äu! 4ö5S8qç=¡r�óhB…0_™Ì‰q;¥¢G0†šAtªsñ)˜o�öîÉÿ¾Hi“Ò;;ŒÖØUÐ[g;%ÃìIW©>Ô›+Ê’w€Cv´SïˆBF6ú¦UâSj€I‘á~ 3/�„±ÑSëz-IëÇœŒSœÈÙ3‰q¿@ ë¹³ ¡ÕU�þkÿ?óI¬] !v>yù>‰K¸on?³x@xóòŽð¢\ì\0VÍUÖ› U…/�9�mßâðhˆÚ¾*— ß³´ˆƒ¾q>(öçê o^>€µÉëMÏŒ—Ö7Ð0ciPãðhˆ—'|ws_º|9»ÈZÓ™ çѶ>Î5W±\FhÇRè&3 ‘?M<ãç×ÂÁeÁË7Å‹áØx„Ú9œÜ^5<¸„¯H_41‚B·�§ê©ýëŸã�}2†M…§û6 d‡8¢Q€õ‘4¬h”6ì�9Åyé%¯›5¶?¹÷^œxíU,//ã«_ù2~ã?úM´m‹§¿ÿ–Ä=÷Þ ¸õ¶ÛqñÂxïqúÔ)Üÿà[pÇ�wa4áÏþä�qý 7àý?ýxïñ{û]xïñËùUÌÏ/àS�?ïLxÛ}oFíBLX'ø ²”Ì{·ë(1ÿÕ>#á áÜHäØÞù6u8âêÆ&ÞùïÆ±ãÇñ‡¿ÿ{¨ë~ñÃüÑ¿ýÀ;{î¸ë.<÷LPJ_½ºŽÍ� ÜpãM8uê5,<ˆ'¾ü%03î½ï~ÌÍÍáDÍg IDATÉ¿|mÛâŽ;ïÂÛ}¾ø…ÏE�”Þòþú{ßÅk¯žÄp8ĉ—^ÄÕõu¬®h¦Süð‡Ïbqi Ï=ûüq¼ôÒK>49"¼û�ÛñÞû ÞqÏMÁðÍa¥"ŒãÃA…ᨖðem�µ¸¸{Ã-£ªÕÀ¡V¨Gõ¸‚T@í€ÊC]–Å0މ¡×ñh„“¯¼ŒÁpˆÿÒ‡ñŸÿ,6ÅÍ3£ª’{Á3O? c~a++«8wö þò‰¯€ˆðÞ÷½/üèGñn†;ïºÓékkÁ˜²µµ½}0>÷éOVVV°¹¹…µµ5ŒÇs¸éæë0™NðêÉWñÔ÷¿�oþÕÿ…Ë—/wp98üüÏÞ†ñß>Їßr4ɲö['¥Ÿfù‚®û$T§һݤ¨Ù2ßëO³$¥´W|cëÞ­D7ÔÆÓî~`Ù-ï¬ú÷ ·Í·W¸®'»ÁÖÅøþGîõ—ú»—Þ¨¹¥uí/}í¿žzþ6wÿÜØ{�™2d? ì±í>^o;»Õa÷„×ÒN_½%%~gµUâ~?¼­TœíÌ{ŠP5æÅsêùÌ‚»¯][·mC×â>YܶCÈC#Úq+úMA⤨g03d/\=[8­›¹z3Ñ[@>„¤„pˆa@bh!(ÄõN}gN‚1?]`ô”Ÿ�ÒŠèû´Æ Q“ª3ýŠ#…»ïfŒcl%6å£%'Î,æ¶Â¤õÛxäÚŒ±TuH® ÊÊ2Rœy“¿ümNCwHÏÒB6— Ðrñp°>¦� gðc�HŸEÁbáʰëDí ·rÌÇA¿“Lû>%^Ä£nÓ?E‡­à›>¼I9‹ý¥†à$wl2âR69qã³Ö ¥;� € ÀVcTlƒƒç€¶Î�y‰8î:ö“⿸�L±šc/ÙK-RÂ~©È�™>Ê_–1”ëa9flÊ‹2?*A5v7+mqxÎɃ ´'<ÄLÞˆ“t;kÐ1’g@„T'²",òÒ»”?yhhñ@Ï­x߈¶Ÿ"¬lRwH“y¸W!(�8ÜÓá…IÑ–xn¨3TÉ òJ…Æ(P†FQ¼Ëø+_aUðT²ŠgOáĨ²Ð€ïX!4h’‡.WV!˜+9Âd½WòØýùß”õA‡…bK£@¢ÂÖYžŠÝõò`�?…Q Á Ípö\ï\&?=@ò,,C��u`ˆ<‰FZ ì!lTù[ då}x0¼ženð£€W~˜Žué‘SåêZúwÝxþåoý~ðÒKø�?û$ά­EèŸÝÚ³[[À¹3X©k<¼¸ˆ‡çðÌæ&–ÈayPãñxæò:®Nò(zÓ}h|‹‹/ⳟù,†£qÄÁù ñ¯÷ÿÎÖˆ½ð#$¢Ô k—.áûO?�p>þñ?|êñ?�Yßqÿýâ쩞ER,§ÉJã€Þû`åÛô;,¸.ÜDGÆ(‰¤®Bh OêqüèùçqÝõ×ãØñc8°¸ˆ'¿ö5¬®‘£GÑ6-†£!þêOâÁ‡Âú•+ çðçö 1"ü Μ>…¯|é‹Â…Á7Üx#¾ÿ×ßCÛ¶hš)þú»ßÁÑ£Çpuý*–.ãóŸý Æã1îºçMh›/¾øΞ9‹_|¯¼|'NœÈÂ唩®¹û&üÔ#wã½ÝŽÕŘ=ˆ¼¬9VÖg  †µÜUæáÛ¾™Y¥ ¼¸®€º&TµC5¨Ä8PCÂU"ûDC’u;ä£ý(n¹å\ý xé¥8zôæÆs�Çxö™À9‡Ûï¸ǯ»ßxò/Ѷ-ñ¹«a{{;ðöS§põj ‘¤žsóó8zô^{õ$Î6g°´´Œûx/¾ð<&“ ¶··qþÂEœ={¯ž<‰/ŸÀ©’Wéî»Wðÿä>üÿèM8~l^è�‹ý�Î'CŒú3{¡ôd‘ÜÌþf§TîËöRf/udà†:ɚغ¥åýÓH%ÓÞÌ]HÊ'ûí[·¾R-÷j�&v; WÔŸÿ•ïöf7ÒžjÖxô—ÙFzû‘?+)´¯E Ä.@(c¹Ö¡û1¤½›ÌÚ8ëµ­kW¤èúË�,iˆŠ±šub]˜j©:ÈËÎC«(å¬8¶:/нò÷6O)õ—a”­ŒaëŠz{á{%¾,³¨zVM¶ìžRÜk_;?*ýýƒYzì\ëëL¼²°É˜ïDšrâ´÷Ì*DåœÒ¢„œŽ§ûc^ÙëÇfáÓ·sHa,ú"yx‘ô’q ÷*è©/Îû¾Ž¨ÞÁ2J«OÔ=¾Gæ><(֣ʗxðÖlìt?ÍD"Ü‹ÉÇ5ö“!ŠS‚I`À“hÛL|ÍØ¯ d&B™AD¦@e¶°ÃÍB7§ ³ˆÊMû†È€M¦ o}){L±ôŒ¾és©—sÜÙ0Fä8 ”Á‘ÑGc;mŸ�Çɧ4>ìShÕðYãIdÐawGFa^°ñßÌÜ3aÍÀ¨BÙœ¬#ÝdIÎt"H—ôU™>'¡¶Ûj.ÂØ‰Æ&_Oå„€›*|¨" ë�'Ÿ|R|Äy/'÷=%eµ]„¹ï#8‘° LG�—ãÛâEëUÜu:oNVÛoc! uqTRç<Ζ5C”s·/…>U§0¥‘.[¯ ÷4ß ª˜%ŽœÊàµXð~¥³,•Àj‡}£’r@0dzcAëB@þ&ô›<¾ ñ”Ù�¸PE¼#KìwŽ|P%M…ºrá/'À9©ëÑzFãCø�–[´ìÍ&§ÇxñCY8‚ ¦¨¤¨¨¨ ˜žá›6ܱì†!™5�(z xáKØçŽx6¶vž,Ý(¯æX&ËiéÚ’²ËŽh°ãÝ“,Y”)ó80µ§MšpŒlÚæ|�cYJsÞ¼d’sfŒh\è�¤s´å"_w‚§FPügž£b¡x1| g¤ž .ùÖPhrRž‚b*yŒ�¼f ™Å¸çÆñ/ÿéŒWΞÁ~é+x꥙bòbÓàskkøœU«‹u…Cƒ:‡�søÆ©-8"´ÌXo[|êå+Øôg¦S¼6™àr»s¬spteï¾ÿüÔ#�@iJÇ̃@ì’RŽ‘N÷’ŸäÛ%ZÒ“¿–fÂ\JF`ÏððQxÁ·¨$ô ð¾c‡1¬^ÙØÂ«›xäÐAܼ@øá•«xúÒܶ8�û.áÌÖ6.M¦;Â�q¾-ø�Ÿ~›“)þàËßA#'Ó¿º¾Ž¯®¯£>O¸­à¶Ñ¸Ta¾ªp!üÈï�=‹5ö¸<�âäö/]<ۋǃ‹ øÐc�à}¿£Ñ \XÎ0^qYHl^ɇÕÄ$Äj‰VéiÝ%™Œi³§ŸzìªÿÎÛ߉Ç|Oþõ·ñÄ·¿�ÓçÏɘOolài9ÉKn�pçxŒëZÆéË—°J ã!€ç77f¬Ì�À֘ѴSøq�µ¶Åéé¯M&8½>ÅéÉÓ ‡Àá•U¼õÍà]½ ‡WWãó¶õr3ñ5æà9`/'}~²�ç'ýÆ­kImTB‰†<Á; Ƀ^Þ_ï1D½©ߨ›W¾›3t[ ‰ŸfL’!ßÈ�®;|ÇÂéóçqâÄKøßþ×ÿåÇÒXZ\À›o¿5ÞóÒpÅ�Kú©†~Uíëzm· F¼úB!áOQìËÛ¹rå ¾ýíoáÛßþÖŽðŽÇs�G˜ŸŸ÷Œç07?�¿üÚ×PU–——ÏýðyTU…¦i@`|ó[áÞõõ+h›kkk¸t馿’½¤ë-ãÁ;nÄc÷Þ‚÷¼åv,Ï�„ð[/­€ç@U…ºv¨kÇ<0ááYîv¡ ®r¨‡„ÑÜÃñÕh7tÀ Jw T T(\ ÇKÍ–š&“ ž{î9<÷Üs{ê×ââ"æðÿ|ìc¨ÌÏÍ£ª*|íkO¢ª+ŒFclmmb{kmÛbskÓÉmÛâòåËñ"áý¤á°ÂO¼û|ð·áƒ¼÷¿ùÔàû“… 2¿l~[¯+ìgÂ{öv©Ø+\SJ²ºþ·÷’y^2J¡YŠÄ�R¯,OÚ©ä~òÛœ£”÷3"³òÎÂã^ê~£Æö�L;ÑÜN}Ú?uwËï·ŽýâoçüFê}]íd†³}öåõÌ£kI¯�ò¸ø¶êfÓÊOáùìðB³¡àìý�'{¥õ¾|%?ÚO›}õïåÙn0ôåŸû~© l‹‘²5ÐÆèµùyÆó¾dû“Ë«Ýß}åÊ÷v×ÄÈÃ`ØúõS…oráð©„�z¤p§a/Ì™œYÇÍ¿” FÊ®uàÎG”  prÎ\È *Sn‹R#³DêÆ *'g§üd}RZèI¾<,€fhe3”̰éóLigêrFã~‘md�•IÂVj/*:ÑVá¬ÎZ!àáHŠu$Z#@(ëßÓ ŠŒdƒøk¹H“'Ö8`ÆAO™ÆvuÇÓ2ÐÊÆÓK��Îø’KÔFíSp÷mÜ˺M12ÿÆ*Ì¿ºQCö¬(§4àÃWˆ¶,�õÈQ •E±¯p³’U²Çzrø2e~œì¦Ýlå ~;ïÝéüe¹Œšœ-£µuÜ£öHóH>K�!$ ø`dÑKž£¢Ná¶ü���MœãÅ¢oi'zžÀä1ŸŒ_Œi“ÑM pÞ�[€¦¦äCø� X9h€—@ÄaÓ[UrŸ7|b�D¨\… áâ_ eUü…OëåߢõmPê€å. =I/0xŽó»rrá.�¨`€|Ck>¾iÑN‚Q@ Q~¦^AÌ­Þ¯ [­~ÊÎgE³xY ñÚ\Ao’Y¯#Üq13u÷´Ü©Š»0êéÙNœÓÈÿoIó·ÛGxì¼~«k ÌÝ~Îê·¥h=9Ê2gÔ0àÔcMÇX§µ4´“ËzQ<·`È%P±9!³þ`½Ø4¼sÜrôþÙ¯üO<õ4>÷íïáå³ç±Uœ=ß¶8ß¶À샤{NuUáðòA]™­+¯ÍªA�OÙ]2¤ôcy$ãá7½ þ•¯¼AÐÏN�Þ÷fÔµžPöM´"ã'…õ"k½–K† ÈçsFÇ�ˆÖTaÖÒOf· ºÊ «Oøin¾a8vp\�¸¡Žšö¶¦SƤñØž2¶[Æ´&-aê�‰'LÛsºñŸ–Ѷ@Óx´�GÛz´m:Ú ÆÃ`4hÛpjU””ÎjWa0ÞUE¨ª„f5¦N§Œiã±±1Áææ[ÛÀÖ„1õN>¾-HÈ8x 4>ÿjF[ºT@uSêgÙžd•Ýòwø¢2[D»‘äD®¡][ÆÌ•Ž”÷Ãѻ0e0„ù‘h8·0;“¿[¥¼‹ådý…žê'T•Cå\øŽÊ$BE„�c â»�q-k=C Ú{ ›î "�ATV(b™øÐò>Öéáòæ&¾ð�§ð½�ÀéµË¸¼±‰ÉtÊQB¸Èra<Æá¥%Ü{Ë-xç}÷ãøÁC1Ëxz5–©÷Cd}äk¯)&¸âÌ‘¹'É<¤>$J+ÔŽä‚K‡º †>�õñÏâÿüÌ_~û–[p÷`„ͶÅ�ócœÛžàØÜ“¶ÅVëñÕ³pû�ܳ´ˆ “)¾ræ<Ô5Þ{<¾~þ"Ö& 6†ÿÓ«¯þ«�ü»øÇï{Töá’ðï¼pO>ó"þê¹xáÔY¬oî¬Ôޝ®àM7߈{n¹÷Ýv3çÆQñ f¾hè …CÞž»EcÜ7ßQÄR×Uõ`I.3J„ÁŠ#­u^=s ÏŸx/Ÿ~ ¯œ:‰s.ô—ßG",.âÐò Ž>‚Ûn¸·Þx3Ž:”ÄLʽL2&'ë—tŽommGù�T°çàmâ¹M‡i@‘—‘àÅ^â+€ÎÕC‡ñôP¼ŸL´1laÏFÄò-sP„a`I5§=ˆðŽÑ`€ª®Â賡ŒLFâÁ!³¨š²äŸ9Ï6[ "œ¿tßþyÉ›ÆU׎¸-€ðÔ‚8槬Žð<¥ûî¸ ÇWWL%—æ³½…ðübŽƒ‡T0ô­efý]¡ûÚ/êæ²¿" fQÅ7ey:õft4#OÌGHõÚ¶ì³òyú»_ánúCcT½ý³í�þë mqyÑ1k}.ûâ æœ tø,ÂiÀ®ãùœ4ŽX>E0 |“Ç¢'ñö„¸‡“�pN¢Ë$99)YÔøaNið&é<~¤R,ò22åµ>Š·b/ƒÀÈìpˆµ$¡s�ç#”?LéYìÈ<侇¦>i/Ç­*,EßÈ<Öû[ã£s Ý´—¹¢Ú:MÞx\�RŒ9FÌr¯@¸pX‹Pñ-UîÄo;{Ï\@î�‰n`÷³(™m_Ž>ŽïâBiæ.K8!Ô.2rÂË^™(b?ØÐºéñ²èHÛF0$Û¸AÜnü<òËžŒ³V˜“T ‹6É�ðÚýG{–ƒa²0Œ˜ÔècOèÆ!-ú(ü¢+Ì!½Sˆ•åƒI!áIBˆ¥;å'ê1 Ð9„{(‡Î:ÿƒA\Ö? Øñÿ“€®m#J^21‚·ûp‚¶ñ>Ë›ã,Ç¡~‡{t�ÏS„3Â+SJùµÁKâ©Ê·”_|›x®rÙćYõæáj¡È�ºÄdïM(Ÿi:´¼Œ÷<ò`Ø#!ñµtàI½Xs˜s×ê’WçÂhœ%Vôðé@O¥ñaÏD€#8†�ú†d„R@ÕÃŽ` Ô,ààâî¼éz€9v�‹ÞªªP»*òÁ�ÍMllmbkk[Œ©ŒíÉMÛ"Â` j‡ª®à˜†°\óãQô®" òÞàZè™<|Kð­‡oZñ¤±ë[€4$)�BB=ê¢,Æ·a)¯iPÁ!Ü»äj‚\ r>*üC¿E^ÆÚ`¼&Àx‚k‡õ�pû-˸í¦!¬bMQf%1$ÇT¢QêY[Ë/&¿tiKK£0Î'zQCu!wDz+´Ú³Ï$عBi݃à.{°{J¹“L´‹Øó7—¬ìR>î¤L�3�YÆ£¬c¯½LDú7 IDATìS2ö•íÃy683ê§âÝ,™±Ì7«Í½¦×3Ê×ÒÞßÅvþ>¤ýàb¿xÛ�ž®õ†­9­¬;Ï¥8ãz \”1|“ͳ]É›  ú"é—mí\ Û‹]缘…Û>>k¬öú¼/ϵ¤½ðÀ÷JRöõ�¤6ßåóýÎÉr.x,ÿ³”Kv4Œ‹Å!Çw–vf‰AÃ:AX€6sGäÜ"Æ"φÎ(yCwå_ wÞÇ]1’u³§?a¡—v#Î;¥›HÓê]‘>d6‰™·…&3Ïà)į(Ñ…�+˜£2“$þ;±qûðî'Ð˃9„ÿQZ¸P/ìwˆº6¥a:)`U•Ò&E/Ë¥ß^O%¶€w ®µBë&ž”¹u æ: pO…%J=¤JÄL”ëZ,ŒùoûÌ*¼¯ï$ ØÉØ`ŸE…~§M¦]œÌ˜¿îÓ7oêB9»$+ù«šã7R™|ÕKÊEm_E�HwF1 È𠇡wŠy¥ÞH7Vô¡¬ýwÆDžÃ·ÐpA|ô j ªy,Í�„ö|ÇC�ÿ:Oçtd"Å“|f¦‹LÐG¢Ëgx9ÐPU‚Wy Y¯»:l OÍpñ;Ué\#ìI8=« 2%SðÒPœ³õÒ� ËÊæÌZRðž8XÉKc¨TÂÁÊÁ1ì£Õ•qwÄ")xPü×È"fÄɾ[Š‹¡èû]¶�ª&ž�wGÑfG˜^GAåãEY.Þ'õ´E‰-¤<†—g¦Y1,ºûBñ£¸î,z¶PÑwk)Í[Í«0s¿·žìÙŒñêÀ=«üëI9þ÷šúZœÍÛöLð³+ŸYìZú¾Ÿ´_ ½¾zºû§Ý’•KöÖÎŽ‡]{êÝâÎOùB¿#©Ûo[Hù»òr˵Y¦)›/z9³[ºndÝ,9|äá™<²›Ü#ëuŸeÝÐçû¦�=$ÎäÞšöÝ,>¥{ºY«OÉ+�|Ö±ˆ—ý3}ÎB’ÛÖ ¼Çª¨'/ 9²„±§ãVTÛÅ•—×Ô)ÒYc²…9# �=Rä[§Êú&Ó9ä´8{M©Íž'´í¸0„ä*òu„ ó. “%�ÄÁDšg,eô_ÍÏ&< “”¯j�Ä¿h £@8ÞÚV:Š'X¨»¼�L8ëÐD±*°™ß1™†’0{å§d˜År£Ìî\¸Ìl � Á\î›UÃ@8  ¸fœ@­©ÚÐrTư®ª”á¨4„ü�wÜ$¥‹ç÷þ,7¬Årc9Ù¸fæ=ëîK‚SÇ;p˹AUHD=*¨Úhg ±³=}°i+ $ìãzKÆ+‰ú>l¼¬(3DúTÞdx/y€†›'o{ŠÞ$|4ð<Òy[jF€¶Ú&7 øx lPh¶°8×`€©Â�½Cãܶ!d�c Z ^q) ˆ«œÐþÀ%e„ ¸Q£Eã —ÕúÈZt‰Ú�ë†ÑÛE‘¯ÆÅ_þÞŽ¿9yº�ÞžüLsÈœ¾�ƒÝÏnö玻÷¼Ý²‰wÙź _è ÍUÈX¶lŠîҰ ì�FA[D?]~9Ìåh\¾$#˜ÊãÉ]5uE¨kÂpXa0¨1ª£Jà(…J\iø”S Úp›7ˆÂ¥ILö„¶b´Ä¨îÛÆ/°1(†C†«0rbU™êƒûŽ£à)PS8A­á�ô4m¸�!Üþ–N á?8ÈC$sžšlá.Ã+[øÎÅ5¼ýÐ n]œÇzÓàÙËëØh<¼z°2ÑŽ€s[Ûxhem‹‘søÂ©sÁè(É *vx™3úÛ*ðCô>½¨<) [ïÐxJó— �ýéÝJNI™žê×ç¹�S¼�`WÐõ�ÙiúLÙlÅ!²0˜Í%X”þmH– ÊS¡}Æ�ŽÒI pg<ƒ"£„åô.ÏH.ïóÊá‰^’ˆäÞåIE�ft f3ÜÅÁ¬ÄvœφAð Ã“XqÊÇ™GˆÿF‡^·ÓÎÊ’+žÏèAé9�Z,ü2Æ”D,+*ô ¿&Ñü¦5¦l™#�iþ4Jˆe=|É `K Ï,hÃyè¤Ðv‡,ãd¤¼B™˜ìä qòdàÄû¼WO'ëõ y%ÎÖ §Ö(ÖNí/'E‚aÀ{‘aê*H÷Tï‰ã'‚…�™Nî|<>HÄ©Ê9¸Š@Ë]Xi Ô�”:7Ôx׉ȣ †Êe%É1ÂÁ&‘%C“YÊ'{N½YEîvú[Ÿõ¥>¼Úµo§÷e½eå\(FßvJ= Kç}™¯\Ëmyoò��GŸÛß¶.[¦›j�bŸ“Òß´­ÍÙúƒüÈñܸĚ !\�£ô ˆç�±ÏBÚˆ“’U0‡!cèF-õY³‡¸иÇQ™Z7�†÷Äâžãö).莼N2½)B˼¬ðžñ##؃cŸÌ®#ïäm' þC#a³Ý3Ül>:èÞËÀi(íÇ�T‚3 ÷#z �B¤±Z§â=§8˜fœ£$X˜¢dz(‚)Àâ YСè4Ëa,ôn!ÀI Ù05Xœ¦<Èys-ˆÃpà‚A`4Àp8Àˆ<†ÔBO¬'v˜HzúœÐÂó­Ÿ¢òS€Žêpb”* ¦¤ ÷:g8² ­¤÷Pœ³c E~#Ü©rŸÄ®[U¥üR`&ò�O÷00¼—ËœSµY:8¬±:bàï1rï8¼‚ƒ^\ßÀ¹í ^]FE„ï]¼Œ¯nàþå¸íÀ^ÝÜ•¦ƒX_+÷ލ¡§e[ËAVÓý’ò�anqÞxŠy�Ä{¢’dž)íÈ{–L©½n>³"Gù#!'PAC¨DùÈÌ–¸¼S>7³˜öÆ0‘Â…¤µ4Sà›J“‚[×DÊ  ¢�Î;¢f®DŰâŽ3ØÂ!Šp!ÎÍ‚q¥~ièºÑ;�辨,ŽAü]fÑ~˜å[çz©Ô·âhâ;€•ãT Žh°HmdàQÊ£žÙª/–׬=uMÝ…qبP 2?Œ˜GiÛ ‰ƒ!•ÅC ÝC$õÜ„%‰ÄhÂÇìvi�ÖúYBo9"‰~Ë GÂÂy#‡ÊUP×vïÁ©YWCÔùÐ{À7MuÈ)܈à\%w&P1<µð¤£¤F1J7z!½ŽW’["¡;則dÈöI ËxEù´c~Lì"Ž£a(3”òŠ©•(ÿÛöök™gYGVwÿë�¤¯Síõ§Y“wǤx·øäÄ×A}¨J!€5‰ngR~«¡ 0‹b¥ ³$ü �»³÷ÕRq©£odå3_ðÀT¢§ˆp®^ûù Í=¦Ùíö…�ËKì3Û<;Qòi·ýÇŽ4K;7½GzßÃh‡dd$ýs&Þ áö¶9kqÝ;÷Ò�˜¿Ãò8ïR6Í ²¸µŠ „ðê™ú�¸Ö@˜&È¢+rRMÊ÷íž°·äñ´mÌ>âÑGo?Îy�:P`wJ "•¬’ô’ûÓßòzkAªû8{P¬ÅÙzd‘î|()Zè+–ÕçI&‹~ø3`O¿“é²§Y[YÙ\þLO±·T¶©óGaÒÐBý©Îš¡Çz^’�G〮§ �A¬s/ Ù œÂ&�ÌiZ‹¦Y“NL]…õT�ÄK.å®Pa•¸Õ2‘ñHG4®f•¼6N˜N�h‰£˜¹§-NŒ)kÓJŠVfÖ‹Vzêöu£aFº¤•sÃR´æHÝž%*J½R"mʼnÈÑ(bø`8Pf%!g!LõÃj'ºãÜA ÎJ^ÐáΆF °ºSQ'‚Ð^e€�ã øSOBüC7é u5´,ŸêÒ®[:QúG2bœˆoÂ3Ö¾¼¯_âHùtQ ¤aX�NjñzˆaÇt|˜B¸!ÖîÜÄp<�ïøÉ´ïpNF+…Ûfe†÷­€Í).â©6-£c#F�˜ÕÌr”în‰åÐxê27Œpú~ Ä5HÝ@<­Ã‰¡ ¸âp±Œ'ËÐëG=Xè"\ü*§ç(Ç#éx#(UBæ¡Rn mãá[FÃSbÂÍô › :féò´a *`* ÓÚ‹q€mø )‡rÒ¡›=Á³iLÝmn7™õ‚ò¿Óû>æP0cîµ¢Ô÷zSh›âoÓ²åûv°0™ü}83AµJÀã3„Èܤ4·- ¬ÞUÂ/Øl¶õÔs¸�㧇(Ǩª`(ª+‡º"¹l²Æh<Äx4ÄS r¹*Ç“£AqíSÈ-4hyŠÆOPù ˆÕ¨kÀUrIs´=Ú»WH.GWšÓ¶Ð¸ÒêÁ2ÇH q$†�P¦ª ÷ªúh–‹YåRãÈWƒÒ*:ƒP¯ßak{ŠÉÈã�‡WáxüÕÓXð®#«€—76qiÚ`ê=ªªÂáñ[¾Åѹ^ÛÜÂBUá±#«xbýJåÖS1d„“¾."÷ŒÖST’k�`0H¢˜Ñr½w$…âH+ÖࢢAf„I=’2¯PF³Y3 jMÊy}bרôW¾ô'ê׵ѹ@“^YbìÓú•ª5å…FÞ©P0À*زæ¤l™W¥#�Â%e|ñœ’gW¶ ЏQ‹ÏÂOQšBfö–ß$S2Ž–ý�ièyž«ô{žªüaÀ ,„¢˜¥ŠWÃ�`röAsêð&/Ž’ÓÍ€XÛ7}ïð΂ÆåJp*²êM©©MËþÑJ[©¿$sC�A¶�:“Pf䛸‰r­¦òâÄÏ’T3¤'ÁÀD­ÔvÌáµñàIÞ(¦) ³xt)ŒøÜª²a�’aÀˆOúƒ$U¨\ PòZÚÀ“|Â({¸BÛ¶ðmï@" ‡#PÕ¨*‡ºÁm‹Á$AæD˜b/w°Èq—‘Á©¬éÁ ”Ýõu,A¾%äÒ:n‘X¨`€†n#›5²ŒÅ£ýÊ%‰wüÿ7‰¼%ç´Ù+jÊN|YFHÈ vúYEd�ÎÐV¿Ò²6s¶€¦5e/]í­¼Ïa7 þ.ÑÃë…¥[®äÓ³ÞüýK¯Gå˜ï¥žY”´ßöû÷4{/]À`ç_!˦ æ°g4æÞk§] bÞPQ·æ—º{§yOuyçUÅPF»ÏÚ¼ú�e§þôãœç{YÃf%¥Í>ù®Äe-Ídì=ÏvƒÓ¾ï[/K9Œ‹|lò¨PàÌ{B—hvâMåߺ0öÍé¾þéßöt½*w-üF0ëÔ™' %”„ØØE�爓&÷KÉÚj\ˆ%¯cH 'jt¢[×�ò˜6ÂTµ Y€B|Z‚(õ(ú©Ø†!‹·–�³åÑ¢¾I‹ ‘ý @>…�‰/$ôRt‡¶'6bÛFÐÌ6y=‡6{&F’YÙ%Ìù·Ycé,À3Z/…ÅÐ9I¨½8•Ôu„NâQÌÖã›-Œ*©Êfôu|h7kÇŠl!Jß,Ì–ØbÉ,úŒiö¨F|iƒR“ÔÑË Z†\Üw”å¦M&BÜ…­ëõ°S(µÉ�x9bP¸HYÊùR¯ŒDã{z@q®èü¥„�´Ê†‚ ÞuM¨ˆ…\Ã)ÐÊyÔ.ÜI1¨�AMá3p k G5Æã £Q…!·z‚g'ÊMÈ�ŒÖ{ùÞemåá+®<<ÕÀ£®Ãa€‚VÁBñ&s›äÂM’ 7uH™�9Q/c¶ˆfe¡“OÈÛz ­ M¸ )àÙ‡“ÜbÈ÷pÑ ®4rÐUØÞžâÌö«£!ˆ€›æ°<`Òz\m¼ýÐAxÖ›_;wwXÀÛ­àôÖ6¾q~ ËÃÞsô°ž†°e�É´Àx xÃùèQ&ÞÚß@¦EÁ óÛbXù[£*ú(ªpäÏlh‰…Æ¢g�g¶3?íÜRzWÚT¥ò�ô,Í�¾ö)‘ËÙûò^�$§"ãOÉ#Hž—©^ŠS¬ÒÞ” ¬»_Ù­ÆeÉ)îœ?f<“Y”›9Mâm—á•ë¸Í—é+©ç}_)N•pH”£z‰½V—k„Qµ½×“q1½~ b‰ø‹¸Hаô]¡�^Ê#xi‰'ÃS•—FÓ¸éïl´(áÉpÐV“5‰8’»0ætôC f�;ÑðÂ0{«È×&—à—ù�Œ ·æ4¿zH8S8†úaVçÌä]¥w± È?ÁóP÷âÚ17YÂÇBøÄpxA¹‚¯‚Œâ™ƒY°é�]•Ö=GÁóѹ 3;À;Žò’âÎEYSÅ.’¹ÃiO¯û—ê6C,yU¾QÆÁ±ÒΉôYss†l¢ðYZ±aQ³‚Ö¸Q¦h0ï“Uvj|�ñ'™:÷šfäïƒ{_u‘ð áGˆ^Âú^¾õo«_ÈX5Íw&}ÜÛè�þì²yò5(SˆÀzÆSœoÈ=}îâ£ïÙNß}õþ¸ÒNmìÖ~þžf<߹ܮíÇŸfÐùîý¡î»ýÙžæê>Ç(Î�´^õ—¡þ×;4C;‘ªêäÊ<M¤|S„ÙtÐV'½þd‰ªQŽÇþÙ¹˜©ô·òfä½äìK%¸.VvÁ;åù"»ïË›¥Y¿–ùnÇz/õtû—Ðg0�õaóu«,êŒh.×ÄÄÄ)\ß©b³„5 ˆ‚Aì·@F)Êê]k‹§Šôñê24¥6aÚ‰í—kA^g”{ëÏq“ÿ. : uÆÓÜò^�J<òA«sÚ^ߤéa7 ™ß)Ã+qÚTØq%›×N9öå|‰u÷/€déJ qQ‚x _8ñt4Ê8�ap“ÁÛP¾Tt‘³0*ÿˆý ï³¹ÑÇüذ�L îO± mt„×ù¡ôÃ6¿�,C•‚ñ6TDƒSÈhžã\GÜÙ[Å  ¤[S*ÛŒ8±xcƒ7JÆ*'Ó‚©GÃ…ò 5 TáôZE@ �à h$¬‹¸’6Ô8 wQèþBíiºèi<=Íž+�T¬**á—ĨÉœƒoÛDž^N†“¸ã×UTø6|7Pµá²ØÊù`ˆF9Ûz4J áU.Sª…)d&W¦ü)é2RNo¢]Þ‡·B/ÖJ[Ñ~#òô¬æJûÞ½·QnõÂ'Œ}6+o÷yRŠé ̽ôÞ”×Oô(ç¸ Îœ~ÇWá™#„;Ìšî Eƒš1¨ £A4†ïѨÂH�CÂ� °x¨Û1£iM4�GÓ„mÃàZyP €á�09 †•(ÿ/Ö.ÅÙÎ�*'—RºøÜ³(™|P&‡S¨â-Ð&…±žêf¸èµ3m ÓÖ�¶ÿm=£i}¸ì;âA�&8<Û68p`÷,-âù+Wq¥iðÐÊ2à›.áÕ�M¼ÿº£˜¯ÎoOpyÚàj<�VÜ´0‡£ãNnlfcÚ¶ŒíI•tу á„?‹Ó‹!CpÊAª3êïhˆJ@$ù,.é*"È·2W ¯¦ïaÔ¬‰¼ÌüKym8ž$Ü>m—g]†å‡—°:zio¦Ì6N”H¹q@e*—ѹ�B½ÙáÅ C'¬†Þè¡«ˆÎgo4 .’WF*gAëHÇ0•Éði`Ò<Ìèð¦xgAW ë¤,´Mj,âE;d•þÁKïÇiì@™->J'3x¦æ 麊j)¼�ÍHøF4ÔÑÀö@èÉzxPV_(�‹ãccÌÐâ ½šL™”_Fœ¾YC9GC4P8EµzÀ(ïvÉ{;ÖÇ ÖŽ|ƒ 7€zZ©â5Õ­AÂøT)tDn‘þ†XmÉ(“.ò4¢÷´M+Ä Ÿù³z@é\öpÁ#J×,báû„Ê1œ|Å@•Œ"€á5€„Èc‹b³`Ê3{o!³¼•[ìoCPÙüʘãßúÛ¶9+•2•�¯Sÿ^á¸ÖôFÕcêÓ}–¬I$�¢w— dÖ¨ �4;v™¼Šd·õ ¯œm@áDæ8d—›N¢Îä¬1ï{·7^þ73¾×ÒÆ__}sâo3½Ñóc¿uî·ý½ð¡½à·#à¤råü4ó�Êr–åqñѲ©0Œ¥=‡× § $ʶK2©£¼júZÔ»iu‘eß3–m… ÝÆe3ÚO™ÝR_�åú²Ÿ¶Êus¿0”kâ,øh—n7%¸pS†#çHNâ1jg–#¹PÂ9– ¼Cûö²KåU,n÷á”wKâzo¬·‹Ž4*'ü:M´J<Â�>„‹q€W׿' õ�<Z9ᨧ2‚m'Gd~Z8½ÛËr×�—WfÐÇÅi„N›©í�Oó[˜÷–T±Ò­.´™øgùmyxÔ(/ ŒÊýo‡$ëŠ*wR›ö#!8ñ£Häâ��¦<Ï‘AÅÕÀxŒF„ÑЉ1Àa8" ‡ŒÁ0„žª}%(´½ž4¹‚ƒgÊp@U¨kŽPk ‡C G5ƒ*\XîB_É%áQéJrâßQô@<ý/ ¦VîhÒ¥ÞáÞŽØTeXÛm 4­Ã´EÑEÓÆÃ5@ã9œÔÃG&–hD•rg¶¶±Ù¦K#oY˜ÃÀ…KŽ_ºº‰•á?sýQTDøì©³€÷; Ò¿ë4­&�7F�À»ãÒËa¬“q@Oþç'û™}ZR�BZC ©BYõ!¬ßzX¢�„г¿“’› �J¼ÊGÍY¡“t½PR–éjüÌ «lÖ÷ˆÁ�fLÉcCOAy—é™®�I¹ny/gù 6 ]Š]#³Ö ì*>%ƒƒiPÁQx‹uÜ*×mžÄwJ¼÷À)³†�]ù � Ùx°Ì%3°܉1s”aLåycDÝý»éZ”÷Œ¡GeUêŒ×�ámÙßlÆ @éá ëI Gf0JÙ’a€×B¥ÕÜ@`hN1Å%ÅÕ�s„xGŠVf„^ »þŠ2›âÚ“¨¨Æa½;…â]1ä\Ã#ó̉1�]0 Ô¡–øþÁ# ðô †0mìöZ'‹|!!~8„‚ †Úðñ^G¸ˆŸ`wp¤tåtÔ£q€IhIdc'. z~Ê!Íg•S£.'Êøˆ„G•Ío •a¥59ÐU¹DP�©?m(Kª1?R2ù T3½ÁCïŠüåß}‰3Cbo²Lhf=Ýzߨdx²�¼ÛOM©G8Y£€a=9»ƒ[ƪ81ÅGü˜¶­º�ÒòÙ¸Ú$¯û�ˆ÷ÈXxž¬�Õ¶ržš$À‚Çv~›þ•Ï^wÚ }õ4Ù› |í ×µÀ'rñ|o�îd¬¦!ôµcá˜õjÆ»½t»ã)°§B{Ì··zi÷,ˆã s2†ç §)/´ÎPƘê�‚™ÖÃù§„•‘ðÓq@,“üñm¹š²�E·åÍEÇ OÉX¸ãCS–ºxÈÖ¤-–yò9ºG ï­³›BRJ^TæÝ©¾>¾6+÷üîœGßïÛ-'¡K=EßE½²èÄ¡E=,–_õHzZ o+ÁU.œ=ÓçÖ ±Žl¯Ë¤^Fžì”‚™;l :N¯ñô�—:£ç€4áì`↔˜2]y\Û¥Þ$L%EWfjýâšÉ}oìä**îë9��¹àZœÅ�pŠø�ű:ú¦c&¥õÉI["c$¯=%äŠN¨bǦҠ¥L(2ä¢m �Â@åI<�Q Û†ò>õA+îL9Ê岬:¨”»””ýéÌ�Ï�̸«ý®ï”ëËßDy¶ àâ¡*‰#þEóí¼1 P/]$6P¥— ††ŠÄàÒ1rÒ±êA„árøŽ–p”Ì<hr¥›â"ä©@`Ç!¬arÄlÜn-®-þÃ$an3£€n<Õ0 Çæ !ÄGPBä8:ïtÚ77 X,Ý0’òŸÌïâÓ!J_q´Z~'ÿ+€j  @ƒk§ ŠLÇ€k�ªêh¦Uá×Ê9° '´ácgw<Å¥¹§§VƒwŽ<ó²ù�nôUðrj$ ¤8 ß*ä® ›ù*† ^¬F ÊO×2¦‚¡©Lµ¸©g£.QöÅ„ž¥|ï–WžÔCìù±ÓX¯=-\~k;)Äv‚»•ó)Ö 9`¾©x¯åŽsÚ²¦œåôÕPHb-錌DÁ¨ Bv*àȇ0B W‚q`àÊ0¬�ñ�09ŒG£a0F=ð¨«6àÁt–Z ò%�—O Wƒ¡ƒ à*‡Áh€Áp€zX¡®¨b¡K‚Óû’"[R>,Zä¢{A\“Ù{ø†àÛ ôç6%ª~‚†ò@ÓmCâ!SŽÛÓnâáÄã¡õŒ)Ì‹&ïç¶¶ñØ‘U03^ÛÜÆ³—¯àáÕƒxààNnlâ»/áú¹1Þzè ¦>„îúÿˆ{›][–ä<심Z{Ÿ{ûöeÿ°›l†LÙ2%ÖȲ‚¶lXô0z¿‡ßÁ0à�AÀNlÈ6`Á6Mˆ"Õ-’Íû{ö^•áAÄ?Yµö9·›²ëÞ}ÖZUY™‘‘‘‘‘‘Ocàðåë+þöçŸáþæëVçý޲K �ê)ŽÌÀïÉ<ÔÏ ¸ñ@3pF’ç9'NmFI¥!ÎiU íI7Y‡±»èsùióîˆÒ Nù1\¥ªŠWMd,Xª¾+àR©éܬêÆDô9­å_+W�ó‚_]D‘·¹{Á¯Î›cÑèÖð®Ñ¬måÓÜyá2Xê›+þ;ÿêQþˆ2'gnûQR÷xùpNá4gÌ�u§ìlXÔµÚ®�QäÁ[Î�@â.Š–—\ŒÕ€ô¦'þJÓ³Ô:„©?È+»*�%íø'ÞQCx²•¨RÒÑ5ubÌY–¥miŸ:2Ð>‰Ò©`úü€EØ»£:ͱ©|sßͱ:gîÌÑA§!Ü!`Ÿ·Íe”÷{8MÏ×`€�Ó§NL?ã`ê�Ã�9ö¹Ó €íhŽ—¥% žáâôû² „‡Ç«1Ç xHZ·ÊqÞe]Ì|CTï{õ÷rï¬WÆ-ôQ'ÇzáGT5Rnr¬×tPU 8_�{|øÒå{âáãàýP�¿ÎÕy™ 7ÿ#ƒ!¼íÌÊ*Íò è¿�xXþ¢P~h¹µN@]~—)iHNºªW*kåg\TYòqx¾*÷±ï®×5L¿þxÿuÑËÿŸW%†u ¿cÿôWŸ"çþ ¿tQÇÕ%Ëc]¾S9Õ|¶ÚÚû’s’‚»ÊÛ8Xë"¢ûZûÝé8S&Ô2?#³¢M +lÐHaûÓ�¦ýG]+Â~Ýñ¼ªs­›4úÖV¨µ¾Gp^u^/Ê}LÙGe®à©²n �Y�⯎€j¨¯uÕ:VÁp5Çj¹ú~5 Ö‹÷·í‡VûFŸY¶Â|5Îvo�Å­fôGMA]ÔÔbq%”ËìÓ|lqÉÛŒ¬Ót:Àw¬W�?Ð×KíêÂ+Þ¹¨T­‚«SÂù¾º²ÈÏÚYÜ8ší’ª1¾|žDÇ·W �0ã`/hŸ \Ä¢zȬ¸À©öûZØ¢&Ùþä6 W`úbî fÊjN”¶•Úkp§¯9Ÿð%åQ'èõV+ "ìèâ­ðà8  #óÒ‘ä�V�×O«*û&(Jÿ¸£"ÿdéG(¾Ó€ë Äp0â."Ý+ýs1.>þ‘" eŒ ÖÁ(Æöê(ŒL�_qQ­´IC¡àAx‰š8† TR`‡mãÁ…7BÒò/¿]L@’)ï‚.ª¤1lL¨Üsn[˜~8d›À�Ãÿvö)˜‡àö*x}ŽW’ŽÍíà˜â~lÌmÑ›Ê J÷)�»âNºTuçŠxú¶Ì7n‹xCZêPš�Pb}Ø÷�}¸íâúvë�+É1¥IàÕyö#ÇÀ©Ÿ†ªŽñ|½ŒÅ…c@£°Æ{4*�?Ïí×ï—Æ±‹{×i€í#�ÕgÚCž·¼r%êÌ´pœ©±ë˜õU2Z„ñ-�H·Mâ0aîÙDìÀa1cГ§z~¼{<ûß~ö]±m6™à¡�AAof�âÀö´a�löÛ†§gs l»9d3Çmþuî×|’Üa»²È_…î–.kÜÁÍ1ÕEÝ·=Íèuì6�Ù16`?°m^^&^dâ>÷ÃvT½å›÷/øƒ/¿Áù³Ÿâi¸Ï‰÷sb‹Âýé»gü�ßø>~úîüÕ7x?'þáÏ~Áüâ/ð‹oßãïÿæÛ�‡® ?W ço|fw]ìIŠHnNC%ùrœ5`$ 嘱®XXIê!LÏšã\É™|•ë6Þu‰Z~×ÊBJ;½ëŸ¨µWníEÎ_Fdª{L¸«Ää‹¶:ÃRvhÑ1�};ü"—]o©¸aZ^çµV $luî×I§”JÎVƒóÆ´ðê:¤ç7ÏWºšà<_£Ãn¥¦WVZ¨¼™4TGSb Áüj𣗢?q±’Òà¿%‚×%£ë=…î&:mµH4±÷«®Q£Mß‘SÔ¼ÏÆ„ÌÈ®Pµè} ⃠­¼Êvƒt ŒÄÏ@ðwq¸U‡¥Ç‘|66Áº®c«G÷Íþ4 Þöp\2…(ƒÈDòPw:êxÇŸGýoÛóI¨ÿB=E<¦Áõ@$í¦ØÌÜ%/0Yàò/è‚VAì…yj8Ò¦�_CÏpY(£“F¬ÓŸÖ&ú»”ã…'Èúä�K*\•¤þqUb5)ôyð1œà×¾ݽò.åzÉSÕžš«º"çš ¸ØWŽB)lAOíºÐÃi.±˜„1æ_˜[Jþì;pÈwª#)ôƺ�Æø/•˜Öw¯åd~ÿUÇ«rå«vÞº.ÊúBð‘:lòÍz¾½{4™ÖIYaû`­²Êzm*dÇ#\x™7ÛþHßõÝ‹µ×‡ßYžn p¢)£z±Ê)gÊœ»Ü±Úsjra›/4¾»d£ˆqg0@á5Ckh%¦b]ñ)ÑVêÍ¢'ê f´òÇkèçEO[ôË·çÇÇ>[¯7™ñü¢?享@W¾uùûV)ão<(ûV=Ñ–,eê÷³#@W‡As0M0줇¯³]Û3¶‘}²Ô¯- ¥ÐêY5¸§ Ù.Ú® Ù½�g¹‰o—˜"‘šz¬€Ê´DŸ(ì0,jdR03ò£1_3T XÔñPïº^øAb¼:aÅ4 Ï4~Ïä‰Ó²-äÃ\g@|AMÅ1ÇQóVFçˆìˆfô`Ä‚éIÖUË«žvZÄ'�.�Äq LDH™€…‡ª×?ýS#†ý@LJvhžïͨ±JåKÀÏ(D¬à4<ø§,eÈ}¤VPý_âŸöý5RQ^…à‡ÑH.F¡´j ïDVhkD Z?:è¡�Cg ”µWYIz&¸"DzDûÈAé È‚{r[p…e:K�¤ÿAá‚R£x£æ*œO)pUíE×rvoˆDjûß¶=¼Ï³äáwX¡ TÞ\!„F£åÞ‰i·ÎEy•ÃÒxááã1Fþç» àNÃaÓê>qлzÆ!㟇˜QR–êg ŒmÃ`Ž!1á4UpUlCðzgt·´‹�é+!ÉJý@b¹®@†`ßn·ÍÒ®¨`ê´Eþ´¿1C¦íÌH:}ÖHIÅval¿ŠÔ?;Ö0õwH€exœ®£¼;oÛ'ùöã뎂·®“³ä,€�¨Î{AR:(ÙÕ˜Šíg%ÎE"²’ÖP§Q‹ÄË}Û7<í;žž6Üö�Û6póÔV›˜“à¶O7˜cà6ðt<Ý€Ûî‡Uo„­èÎT€)Š;ÜõŽW�¸ëœ¾·}Çíé†ÛÓŽÛóŽýf;l·Ìˆþ¹s&�M¡,Éé< sÚ&䘇;,œ?q‡ *~°–öhâŽ2Á¾MìÛÀûíÀ¶M¼¼º¬9úؾ{ºáoþ9ÆüŸ_|…ßþäþ‹ŸýïçÄÿð'ÿ ¿ýé»8wà~þçx�?ûä¾·oøÁmÇûû�O÷ õ:ül†©¶ë!å{PŽG�ˆŸÉâtÄsÒ]"•‘æÒx^”Y%~�vîQ¾ €–´2p^ï„{v8ôIb%×Hœbœs±Eã}ð×o"í+XþÒŒ÷³:ø—m%÷ÔÀUôiYÝ^Eä¯ý«Îƒt0¤àŒÒÞŸ¼Ù�cYaç=¥P­Œxó— Nçrò ëýAe¿º|óþ¹|oÚÅ›|ÐÇ•QôUœGÛ8õU�ÁÐ0oeÄ�:~Wl®Ù8NB�’%Ø[Öþ‘:ÔRNIÇ¡òñäñ®›ðç¡ñíi:R<óã²oÚgé±MK¡Q%wn›9û‡Mg¡ØÙ,–F�Î/ß϶{ÐwŽ1YKŒ«Œiso¨oŽ?�@ Cù˜âðT<¢Û¶…c€ýšÇôƒŽ7lC°ï¶£1Ι!vUá¹ê8¹Ë–Žê¬ Zªi+4ÇbJµà-Î'’7ø'#ÞH Ü™U�ï|\ùƒëCóï×½®ê¿šË=5ÿ:õtÞÊ]²킦rá'åÕ)nÿP�QÒ2Ö’Ro;윕�±Ìª{úg=WàOÐò³­çAˆAx�¿yéƒïW¿Ý[¯³\ùøw¯®�©ãßô,¨m|,n¯Þ}tï÷ém\î/Ÿ¿êºÉƒ~ÆGœ )CÙnùlß M÷iß”VfÅRÿRQÈK—Ñ­r‚ñƘÕçU·u†Ÿ2wAâ ÞZ®ÌåU™åµ2 -ï^Àü±kÓZçué·èì­ú×9ÃA«ÌîÑ{øû`ÛúàÙZ×[íÖ÷?†ß¬ºÚúN�è¿ÚApUóo¨8cXŠ9:€3®ë½·|=>AñxNì5²Å>ËBÑÿµà*8>aæLÈ�CÓ„E­‚tnAB¥šÇÍÐ!'°¯ÈÇ"]4ûèý ç�ºúÖ`\_ä©Ñîe^P=êL¸{µ_ê9‘tã€W”G�¼…i„±¼@Ç‚Ÿ”?QV=k”ÛT”°i‹**.Ôþ¹¸bˆe1²„2Ã�¡z�WQäz{\ž•~×ï,ZXÖ@X4ë£}ߌÒ=Èì´Zµ¾´¦¥‰kkZ¶Æ(|C¸I'ÍNd:\jpËæ11ïp¨’Ü9À0Ϻð°Oö“‹¤òsÕCí‚?e‡Ó«ˆõ/v¸,‹žv­pÀû_?E^Ó ŸªÙ7ÒqÐU�»…¼Å�Î7ž/œÎ�HŸè�L­S£ïj—×9VH‘�–úð´ä -]`˜Á¡ „ó2³2^«[T S°M‡`Þž^0w0c{8 ÛÀØvlûÀ¶o�÷©¦ ^‡/¾Eñ:Ò1�JQ™BpÇ€9Ìß”ã½í›äçÆ3Õs�s˜S`ºóÆS›¼X6à06ÊB;Õ0V ñüžÆ2{ñ¤ø¬¶ûÞÒ|wÁ*K$Öi8åôý*ÝÐ[W«£ÒòzUR¹zX·¶ëmÒÖZþºB-ô߃»³qØÇömÃmßñô´ãÝÓ Ï»àin›b·1±ÁmSs <‰<|Üv�"­¹¤¡0/ÙpÐ3–‚ŠÃw¨È¾a{Ú±?ß°?íØŸ7l7ñÈt,ý˜Éyv,¸>":˜ÏKéj·"EÈ]6¬J‹sxªX¦±aÛ†§W>W &îQsÊÀï==c ÁÏ>yÆŸ~óøË/ðªŠßûü3ì"øÞmÇçûŽ÷ÇÄ7Ç�ÿèÇ?€ªâ«ûÿôÏÿ¿÷ùgø;¿ñ}üñWßtn掊\ž!0c¼3•Pb†D燔íéÈÝVVép‘úα 9Æ<ö{4Ìžéµè!¡¤²}r46+E ®tÝé;ï”ò>Ît X•™†§ûÿËŽ·V‡¶ßý~…åIæHÉö[‡Ö‡U*h< ÐHÅŠòyâï¼»�Zaî.üƒ�'<4Ý*@^ô…Ëê®Î�h‹‚E»<±7Ø>3ý¯{| ’EÝB1}¦óe¬tÖv% ô>g+1¿¨&´’ø X{«�Ýèöµ'å|áéÔ?Ôv\mÛˆÝ`æ^cn«âAÍ€ŸiDœõ „Ý£ÿ _k‘Ѐ ¡!Ã)<ØûŽ�mØuàðÔC[œLœQ(6¾Ç1½ËôשÅÎÀ1^îëu8‚¦©)<Ðiݦª;còi,´#¨å]™¶S4¢êq7ÚÏ´r]UFp¹Rwçg!ïËóª <ºÊªê’RäÔŽß_ø|ê�íå\µt܃r§þtghã�Šê om‹j®S]p…«¤Êi¬Qn�|t®HaÀ¡¶õB@�ý$_(Æ-x��LKEùYþ Ô\òâkÚéϯ¾¯”ñF¤þe{7Öç:ÃsÝÖÇÔy]ü¼£°È×G4x)ÃÞ®óò×C/ÚÒ`ˆ©•}Ò7`û.—–¿¶‹ÛoâãJo»*W>šƒ ÐgÌaàdËaÙ�s;S ˜íS£.©}QÍŒë4‘k¾ØË–> "˜ÀnÉÛã” K î«ç§¦�':­ªK×ÿúÚTk›;öX~üÎÇŒÿ¹“2•‡]éS¹&ï;"ü¡ÈªúXÀ÷!8uyúˆ�­÷Xîj>)Ú–ô‹:»¤]SüÔ÷x8­qDç€bm‡òùTç©ûW8âUsì­ðÚµ·ŒFŠˆ¥|ãDdt†ŠÄBŸ ¢[H[P¬ΧO4)Q½B% ¶0²m¦â~…UjÊÖà>Ù„‡}Û+Z�‘|£¬M¬È*Ìd1ôª÷1”VNý“‘0þ®¥puù�‡W´ÅIÞ§R0A"â­+x¬"¯Š'�ÑÄ«kÉıfô›uŃŒµ€ÚŽqÊãK›5Š»28 ‡äÿK_ßè[¼dß§M®Ç¬µhoWk(‹LnBÜK ™%ú²È�êÈ“ Ýø ¶ÝøÇ�ã~wÅ8€1‘m£1‡‚�*$ëük9Ȥ ¿ŠÏà·Ù£×Ù&ù*°/ê\™d¼æŒŒÃÓòz®Q�óßšvø|�Î <ç,Ü9P#‚Ä»* ü�ø €ˆ.m÷€™sž|+üÉ &nÝ‘Â\i%@6Ð*:÷�§W@ß)Ƹ‹­-_¸C±© ’mß°íö}Ç~Ûþcó îm¶CÝ8 ˆ:…â0Kä¸áÊÈÖ`S¹eœºaWï˜*�{w ˆÍî¶;N÷‚“ò""˜sÚâc\MÑõŸÕÜ÷s¸¸hôãw7‚ÑÖ‹¦ƒ¢µ_úã¾”‰6°RÈ Ž\ÿ¾âSãpíóµNøqµÚ÷lÔíwälÛÀ¾ n·OO7õ>�oèûâ÷õäð: Ÿ0B�!ûÝÈ÷Jõ¼ x$ÚK¡@@[/%Í“.€È;&5J I¬™s_˜vÇçtIÁÃóqC¯¼Óù‰±¥êܶ|'¿ø·Ö¸îš:¥¤`ÖÇ�ýa›!o�¥-Ù ¸ÁÜ6ÅÝ#£‡L¨Zû.YwØo}­`~s�½Óa s±…´­‹mqm9‹ ‰\øQˆ9LJ@t¸ñ`xZ� » ìcz„´`{U¼ÞÝ1à´;çÄ~X$áFÖ1¸@¶÷Tsû½TšqTE*:¦§*# e ø«qu¾/L_”cw¢ áÖñ*p*¾á¬ –MGÇîll~²Û­Âºí¥ÕX_(£0‰¾¥Ðäü‘œ”ÍšéFô7�È´!Cì`é}ðÉMìïiày·´A·�)„,Úô¶YÚ §ØŸÛ ~à#Ü 2¦.3¬o&e(dSljÔ<6¦!¢c‹´))»B‡pþr['>1¥Cܸ´£êÏ�>U5G$çjìxvÆ‚À Éþ':üè‹*Ý]çø£×`Nü÷ò¯ðïÿ{øw¿ÿ=¼Î‰?úòk|ºoøÝÏ>üÎ÷Þáó—ï¶�?þêü�Ï>ÁÏ>yƧû†ßÿÓ_à™iÃüš Ü�tJhŽ<¸Gˆ¶®z8±j•ëù2 þÄdâ)i4Ô Òò^È«0Øæï2*‰{de'2h<ë\›0Öšdá£9šã? »¶¹Èô·#­¤; ¥pÍÏ�9QwT‰¡l/0Ë“Ö2P�}ÑÒ¸^Ôxq¥‡Æô4¯7�àÆö(—ƒR UÓ›M~ñHTV]<£Ü²Îoá•ëX Û_yaEGy�8oüýJí€ÈÍÚ ØAå4²-†wEÇu’Ì‚¥“ˆÝ^W8œét§A’ Ñ?Jc! EÕïŠÓ1û½¿ÎÛ¡ŠmX ¸m‡Àfi‚Ìào»†dÅÜMt‡9|‡� î�š.#s‡ 9`2œ¸7Y›&%¹ÈT@w0|‡¤;WEÁÃ’c@c­‘¹LtÐß›;˜ö4�|¿j ÇázÜw¢•aZ(@’X ¾ôß±+Só�ò[à»ßFîx¥|Žu•ºìò–Lû w»MÚö8#2yó¼ê .Uð;Zw„íÖGï\Á]DF:ÔS±JÉ€ ç ÈHhhl;—Ý`9³áfh„ãCKõ,šîîÈbôOA´£¢—.Ó?ä•å¥ã¥M-±j©´L„2"ÞûƒÙêŒÙ|âã×5–6Ëõh7ï¹Í7êJ—Zš¢~‚k¡QAªt×ê[ê§ü»„�0e�W ÓäæÕø6€Þ¸Vš:ý˜q•öuøœ“xv0úsE'&ßQ‚ë³êà|Ô,Ò†U�ó ¥1Fk¾| Rà�z¡ßä¿6/¥µÝæê¥ãEÜ÷·ÍíÖÀ™–ëVp¸Ní´új‘µ¡�¾ýXÖÔq}T¨WšS¯Nºs`}çLW]¶=¾®[>SõtçûŠŒ”*!²ì9g�f¹¢/uH·å;@ö§ž|:a4E2µ^éÏN�–u’u(÷é¼ÝÎl²hóˆÚ�0d'=ÚK\‘ ¥W‡§JÃíã 5a(OÜ"˜b„GAç�hÆT›'/'¸ÉX'©êŒ]ù]›¼ó\N� ¨æäH��mä:XÓpä÷‘Jq0¢ø»ÄT|ýq•íç�• Gá­Ê"‚\A­‘ZVŸ„žZz‘w«î2¸°Û½ ‡ŒìÜ¢‘þÇÛYUþv2ª 4Šœ>æa÷Ńª$cñ°bÌð%Å2œ4átã fu Ž/°m©.ô†;¤hnëC€cØÄqGNÈË„¾š3@Þ+äÛ 9l§€)¨4>†�‹2‘þ¢ ·A�Ê÷¦Ùµ�¹A°aß7?ÐU±í‡N¾ ¶o.¼·¡žƒ}bnйÓcb;콩ÓòcF®VËß»áilxÞ7l°oÇ.¸?mxÚ,}À7ïß¾ãnt{L`È€ˆ6»‰GÍA0±aª /K'ãÂbÔ1¡‘W¡z@å(Ê�.tcc¥�eNÃ4¼Åù •ÎrTâ{|r˜%ùõ Ðajeó€VP©•Þá¶i0 �^•¼ ÙF]ÁŸ’¶:¤FßܑŌZ"Hã´ºqF†:' v.Äð)fŽ#§'?DøÝMñü4ñÉíÀ» øt·¿§ÝÞ7õÜúÀíK´[®çm°+æPèÈZÊKÑ•ŽÅ&wܶCÜÄR ݆`ÅÀ�1mK¥L�L·f‘·ÄÖ4kÓŒ))ceØŽ§¥av¢\ ÛšQÆrò’N4ÊWåˆìÝßÛEñ<ïð4€oÄvVäð ~xÛñç¾�ßÞüßýCôÕ×ø¿¿üÿñoþó³ ÿü‹¯ð¿ýò ü�ï}‚¿ûÃßÀ—÷;¾<ÌØ…=i⮂—9RUÐLC’郴¥:�ÑË ïÞd(FåŸ}fPÆ)eöbÐ${�WµÏ!q'ä(r9RŒ¹þCcLÞ0¥z¯!öCÞ̋艢µ;q¥AÙ>UiÀEè·Ì{ÞÅ¢‚‹]ÎOF­³üÜ:û1Sd‡ˆZÜÉUþŸþ½¾”j¤ìN�!Š¡öýiLÕ�sµó%oöÛ±£G¥¿ à’ÉÅãyuó,*AK¹< Õ¦ÆóQ»Ë§1Ž%¸©"*¦kuª-´ß•ž²«Iâ#Íæ3ÛEÕ†Ôÿ%�|kL1oYžÉÅóõþÇÔ_ë¾âmë ­÷®~¨ý�…u}o½JÆŽVçÊ¿ª½éªÎ*èiçßáå=޳à<½Å1pÑ×½å&å"OS ÅÈçBäãœfPµh)Ž>ÉIÝP�hRµ”TìRÒ%74•èŸ�ÆÀ\ººÁ@§$ïOR:­(¡9§†®üS§肘¼Á˜y6nü…1]J®K$r£ýÂ\¹ ‰Ha•[:Ìøƒ .e›@w 39€qø8†�, Ö9ài/Pã„#ÙŽ�ñ7-÷ ž‚yáÎ>)l7†zª *†!€«BP&Ä*¸*N‰?:"ò½·×3æë@èdwñ?ÿþ¢À«BÞ ðû{UàýÄö↨ØÚ,AÔ@ Eõ(=ܨE‡ç;Yè­-”VÞÞ~–†9y‚®J¨úÎ\aú5C\ð4I£þ�lS #qïõmÂ4ä¾Z…ãfð •Nß „¹^ìs!Zi•s´r2ȉQ•£ÂÌìc°—Ç4Tr ×1#­±…áM ›-ú wfÀ?ÄŒúâÆÞ}³üíâþݧ¢ªLã5†EYßĝй™àP3ʰ¨ìûa‡�šAÁs¤³Q< ày¸Ý€}7Sô1Æð(ì1£�‡ Æà¦ÁöMílÃ�$KŸ@R…“ÓUÏq º�-Þ×vÉX”D§c5ž‘rÃòi¬ËŒÊ$!…FàøÌÎ1æËå®§4p2ޱuòŠ9*É«+´+ßß3\L7©×IEQœÿ :‰0‡å)³ÝÀ.vÅ.–ÿÝmà“}àÝ“àÝ xÞ�wûÄ'ûÄ»íŽ�m›Ø¶i醞ûmàvl»ÑoZíØs¢æ'BN2õÔæéˆ6Qà˜~Æ�Eå28ÖͯÕ�"Èt cZÄs¤ãø B¢yùT¬ý7 �J=¢ÈK†Þ“þàì‰q7±?C»[ÅþÖí÷û�ÿô'?üþŸý_Þü£ë·0øö˜øò~�þ­OžñÍqàw?ûüÕ7˜Püg¿ý܆à¿ûó?28xõÉ»ó‚éœË£œYtr¹´L€d‹.E\v†1Þ­c|—ÒÆ 5("g#ÕœÜUèQd~îPF·ó­ºKBAcPTåúD�ÌŒ!M¾P1`‚zšóƒC3b>ÓÈÀçnÙIQx �IL%Dgaø¥¼‚Ä“žj*œL›C=ê,œ[:¦r=J3Ô‚5ÖÀ pL/%þé"ŽÖ{Ùf|‹ºÃ`ÜŠ�$ÍÔÎH¹E}29½‡µ±È¶ÒdåÝV†RÂR“f]¡¯Dï�é €Ú´"ëIö^à�ó܈\w*§óLI30'øÞªÐa¶kÉ{ ½Ö;Eu¤Æ-Hàßd¸Iiµ¸Š¡æôÝÏ»Øn¯Mð´ žnvˆ¼¥T絉7;KlàsL±¿ §À³†“BÜ©[wX¤èôÃŽmäæ´ð¯Íº?Tý0 >›ÛÀœŠ×Åë) K¿”Í0EP&�×å)­”p-8NƒkA^t+ÝpÎz¹!ïÊdù®–ú\f72ÖbØáY}d{£Vê<ƒ¸³(ø]>W¡É>_ G„Ç·T&t9ÀòJÊ„¦¡ý~¿.g=šc]uÇAzµêØ•ï„cy?çicm[³¾Ë)¸®KƒS.&Òí.a K‘¤¿2縆8ñª^̉ N ŽKt6;�–‡®‡tɹzv·‘S­G–òZ@:�Ÿœñ¨p8¶×t‹ÚH¬%Àõê{™›ñþ#–=_ö„t>‹Gœs(o•>Jßß�ÿÚ ?„C�ü¦�|˜�œG±#øº�G "k[á~ g�ê�%ZǰÂE�o÷§µÝ·˜d%&Yˆá­¶*,VVëaxÅø/úÀaÁÊ|&ýïÄ V¸s~$…äµÏò›ôGˆgÏÑHÛ;îaú— Ç ™Avy±.Ÿ~M˜S¡¸ùgLC#€"SÜwÅ¢yª' Cs[¨À™:ÑOÛæÞ¸º0==c}Ú™Y„�.ï5ƼròúýC„¤K±7&íÕ\7š7á3] nÙŒþh|o‘~Þÿ® q’N¸ÒìÂ�°ÉŒÕ“¯UxÇ€´þÔ‰²ù:ßò0(hq¸´Ô `s¡ß%p˜Càþ©Àë´¿—úr‡¾Àý°”BnHàBQ8Ëh0a{(†§+� ½›1Ìœœ8nÝò¯Æ§EøÆxf[xfÙ’î¡\¦ÓWà."qØ“§1"WCñfŸ ³>ðuU_-ãÌJ5§1Š"ÌëöĶpª,%g.‹4}‹—§w- qº‡’pŽ�±Òcn‘@¸ò<°Í & ™˜Û„& ¶±[®_ÒKDú߯6°Áèc@0¦G’O7 +£ÝðíÝ݆¥Ø·Íòo7ìû->'6;ÿ`N<Ý^îöýÀ¸»¹QÌyÇ1ïi°„¼"º¾ƒ@SGNº"TƒMÆë¿‰Ëã8óc¥í2T$;F‰Õhd.Ž+˱T ŒV3n_@³§òbK½°¹#;Œ­€.tA^×ä™PÀ¯ôcƒÍx=qEÀ×ꈼóðvÈD0†�° ±³dbЧ}àæFþÛ nìç!•ÖñÌÿ<ü0ð± Œ�gi �²6Ò—Tk«N㢲™/pt›ž†bx$%œ¶4ùlÌߨ˜iS}Š–4w¥1;é¦H¨&†e¹Q>™2B`¸°_Sp›–ª>GQ¦~ïóïãe8tâ_|ýÿÞ÷¿‡¿ùÙ§øú~à÷ÿìø�O?ÁøƒÏñ:ÿë_üà¿ú�OÌaX®9÷ûì¼�sIÓ!ÀVûìé5+‘üÑÇ”5%_]VTÖØr?…àTœ­ÌªC1ÕJî&à­œ3ÛZ÷ó@J4º(jñ«w5`ÃRO-C$_ã:1§åc¯6¼>²¦«~T£¥¨ZÚ¯e/!¸®·.â)íÖ3^jµÅ·–¿!Ór 4Þ g\Bør5B�¿J‡ê<Æ}<ŒïuL¾‡Ü^”t{Õ{ïS•ñi‘Ò~,Nò•F¿ ¥» 5å › ·:wŠzCZh§¥aˆ0¾¸âiNVsý Od©Þv<ß6<Ý6Üö�Û&xÚ7<í»Û�ë6ã4âç M�8à_¥¡ÑþÌ?k¼^â€bîp ¼“‹ ìÛnòc‡ËüÃu�ÀµLÅtó8 ð�è"Í`­Üu£xqÕñ®Í�‹ÐÔ9}<ºÑ¿ãØqÔéVÏ¿aÁɃç¢áåc‘OÑV�~í£ýYYIØ*j,Ÿ �+|¤ýñ·õÁ Ré_Ê/ Pž?ä3dÁ$¬¼rž»±8û͵E &„ ·»G¯ahäÎ@5ãE%…X+¢à˜–qׯõOgâ–ïVºqy Ù'ÒÄå¸û ‡ÆXÎ yaP¼z^:\ ÿW¹¾¼0ÀF�d}å⇜orL,Æ…FŸ”ÁÄ—éî¥î6>•ÞYOý� ­š~0{!�Î�](°0R ¦«Ýv�CF|°Có¿À,µ@ž�´]æg€Pæ�Ô‡eñ×– ³×·ˆölºÑ8ÚX43Ýz¯�Ëht«DtåAÿNü,ìá”é»×]µó’·JÇÏß–9²Lñ¬êª/o�ßGŒíeù_‘g|°îïZo…ÿcñÞvQÏU½�ð´ÖñV�Wð¬0ó÷[»ÁúœÏò«0ª;į`»ª'¿ïÜNk¯kèE;ÈœE}Q 6¾Ú�4ä�ü¾ÂRN‹8�ÁBm{›Æ/½s¥o,Ó5RìT4“³ð…EùŠŠ.¼ÐµµºjRË<óÎ66 T'a^¿^Lð“1½\3=yV} _*L?èpæB^ÕÎZ¤ÖZð2±"´2=* ¶Ûq“mFG‘‘]WÂÏÚÌOŽ“Îò\KŸ  Rq©–RÁrÚÍmáêv¢.Õ¬»îÍ:`JÚÐ;<�Ì1ð2ýÏóõÜ'ôPpÑNcŸ¥4Vž6IĽaâÑ•aY= —¡�(๔B°äa¾#-ÊdEëª7 &�§ºSeµÿFDgEšQ;ì²zþ¹HW36æ¶YCk:GrªŠÿ2]—N÷ AÄñÔæÍ*Øù“¸ªN‚«Ú/äN.*‘Ÿ_Àt xt˜ì°�Å1p`Zº¢­DÂËä` ÖÝmÑ<¦`ƒb›ö7£È}›¿Ÿ%` x‹Ð¶´A–JÈœüÛÝ cDNâmƘž"ÇŒªœžFÎ# k„cŒ!Hh&k¯T¨nƼœ8(a¯�â¼)¼,ä²tÞ ‚Ü>ìѽ<û"øª½;6;äiÚ›ð¿¼ÿÿõóOñüÕ—ø—ß¾Çò“aÁÿõå×øgùW€û{Ÿ8<ØAùb`°Í±zÑ1æt[þË|öåMƒ8tî®PÚbR×HÊî"ªÊxÇ,ÖØa—u§½Á࣠®Á¨GVzâø“®¨70Í¡ëk Í~PßXêRh’0l] P$ePDZ]>Ù–uÛ:ì�¸š— ]Û¹,Ù«YˈsowÂTN˜kú�ºn•)§‹ã¹ÐRÝù©ºLo-u*Ù âkâeLuÆûÑi*Îì©8¨æžCš£àc¯IŸàXÇ\õ!j«c¬hgiqKÔgw{FÜÂÊt”N4þ”HåÿN»x0OÏóº@?¤=yðhò>tÞNÈb²øg-WÈw%¢>pV—ÈE9>ÌwšŽÓø\¹Š.–¸\*9½g5ðÆŠ^óǰ¿|*�%É-c–|»(-}­cö±/Œ}e°À±¾±ð±à©—�T�ï�>ÔèŒÉÃë oÄÊ(¯Û8×J¸Š>Óp2ý' ÉÔÉYh«#ëª2ûܺ¶¿Ï`¯ó±EA.W4ãDJüT¸!Ó~eÑÜn>à�€R•,víb1ÔÆ xòã>ùüŘס‰fÈH|eÑÁ)§!áj ®Ûï*~ÛN ¤)à»> bS㻾®Æ@* Óz{1Rü&l£¿¦i)J¨0é”e'Vñ|;ü& 4ñª9Fþ#“O%áòмê{¥0?›€×kô%~�;o¹KÀ‰¶+Gáù!©,O?·C|§€FÊ }Qàý„¾˜/ô倾лáŸF“uÞ"!Óa˜Ÿð~2]϶Üçäu•ÊÔň´23í}¦däšß“œ³5zNÂÂ&9NìGÖ>Ë€ˆõ±:bW«ª;¤B°¨=ˆ\àe·ˆ_Þ®Á†¥ �ô2o —úΚ£�L»N¯ªa”±Ø`�}r¸þ1¦æz‡åRUw �þEmñ.3ÞáidT-b}˜c@†-ôÑ»¹%�ªíCÅ$LG‚zª’ézBuT~©0ÃÛY�§ì å RCÙϳñ½~ÖßæO¾GðóÌŽuXKíºEòXög…cý^/ré*W#ô*›1_ݨé}` ¡©n�f}aÕK¸ª*Ôà»Ðƒ×¾|8¥P‡Ý1�ý>‹ÍVL¥à¼¦­uDGJûšE±»+êGÐoЧ á˜x}t‰óæt*/Ï›Ö^œ�þ4ïi_ð'® ˆoB’ g+Z “¥]Õ:†9§b· €dpT|ÒY`²�ãârƒRw0òH2|Û7‚Êþa¬RJWâjFÛ¶Öð¹¨Ö8�tŽ„ƒšÎˆ&‹­fsš˜N(ÜñZ rMïZx¾ÉòœL�˜Ç^Ç)¯ê Q[�^/ÒéÛÑ IDATÀ§(Ï5õw1V¦®‹™¤Ñ>(‰‡D±·ú‚–w9Œõs½eÎkµzHÛÑ—ŠÌn­H�û�Ú\ÄNF�8ãå@dŸ$­º@ Ø,õ\úåΕ³-CѸy^2…Ô媾Cæ)(ôAk¾WépuÄSSzÍx7  g•ö -œÆ³>ã�ËõbžJ}§ýÕ«rõ£7 £¯°Õ[3m,@u&(´èn FÒÇ�z^ÔÍù+Á·Qé€åª½H‡w£4š!atW´Äš—r/ˆKËø¹< ÛIAˆ‹„zE€�ÓSà!è-Û ¿ê²³|o}©õÜJ]¿4@ò:ÑÚùyw¹_ÐuFâ™Î°¨Çq]w�Äœ-åj™ LåC'Þ¿v Œm”}Po|”þIyÎm@•™œêXi㌟¨NS§ú龜¶oŒÁ_ëuE ßõÝ«÷ØçõócàøØvyUš½ªGÜ_Ὺ÷êZù2'‚ ääyð.Ë˃¿•™¬‚b–:V˜íû>Û®WD]«uy ÿ€„Š® âfœjÆ–p$ƒëŠÅ,–hn î(v¯o¡�àùòçŠ5År+“÷~tGíÚtæ1a‚Òù¢¢`‘R÷#ój×~Ã!¡±TÚ@/-iUÔ�)ô*ì�Y�Š»EöÉM’áÅÀûEý§wˆ¼�ÁÌûŸ¬›ºx®Ä6Õ¢˜Ê_80¨ŒÎÒL(q˜NÀ×.cƒ<´}³ùbL³Tv èË„¾Wèû‰Ù‘þV¥D¤HžU(,æ4û¤�s¡c`sã8czĽ½¯¾Øè¼‚¾ ³Š${†×â‘S=üÉ›^x8Ü$å°«ªFì×h;Fþ¸(òêÚv[*ù±GiÙ5 u>ø{ÕÀ"¤Šõ*‚^Î÷¯øu̺‘„K(ò»S´Dð{G OÜY2¡›úYL�’Î0�a“R01dBeà�é´dÆÚ1ŠsÀ ¼9ÕÜP ’Ž?|°äSíƒû4ƒÿûWÅËë�ãðy'бMì»âv5eÀß×<èf88 ŸR*FÈ€pÏ0�ÊÒdNÿzÖÌ’†¸>² òÉÓûÝqã¸æbeq¨)$´­•ˆXŠÂNš›Üg@A?r*iBÛ§©[ÝGu­ݨË×4JUs §§µ¶IM3±á¶™c Rm~ÈðPlcFº‰!¹c`s8wð/ŒõD\°AXX†„\± ,¥�„õZºŒ(UÅ.òÊpÐ)AÙ#�GÅ@JÈ�d­eB7lùÒv/�A[–/>FÛ`OgégcàõåŽç7?Çï~ö)þòõð/ŽÿàßÇßúü3|u?ð¿ÿò üà醟¼{|ºïøÞ¾c‚?ÿ‚ßýÞ§ø|ßðO¿ý&@UGÝÞ¾.¶‹�b`¤ïé -ŒF7ÕõÏ1CÙ ÕLzRÃÓƒ¬óçÚß*ˆbú7Wc9ñ;–ú³Û�¦ëû—åÝih|`TW¤1}ý¬¸Ëô {ÐUõÙ°o÷µåM¸Ãùr1×ï|hœ´ðµ [©_:�¢Î åžòœ°¨àÜ>Ç5UÒШ¢ÿÜASa�¢«1¢>Xk©“S ê—ïùwòþèUØ;Õ1à@*~ÎŽ’«Vœf}½éøJéRÝYiXêÁÖÃÏ ˆ]~ª0 q›?³å—øn°�ÛmÃÓí†ç}Ãí¶¹Ãî¬rW¼º|>¬¾CŠšcQE*ÒI#e 2íQ•¶|C RwŠ&ß�;æ¤þî»(lkÄæØ(G9䘔#¤ß&Îqç/b½Ð2\v’@B/’¤½�á¤L.2ÆûÝ¢z�ûtÔg0V™íªq®õu…×Õw^õ(¸ úVã|x[^™‹u¥`Ì]^Ñr¿È›s/§£¬N>ÂÊIŠ”»íÒa OŠ  ƒp Ð) d åwÌ6:LNëM®7È Wx?®J`gØ’³(ÎÑ£¼³ÎŸðw‚­CcmjK3s#ƒ×w˜]�-À´¨µ¯¤É–>©Ÿ1Pi諭üm^ÓNl!?‰�‚;6�: «rmO­í+#`~ !^™ð( ¶Q!ˆ ÈÅ¢5&æ¨÷©h B�§k�4â �;DÜ€vvä<’Ä¥�®4D]ÈÁÒ4YqàrP-Š]Ã/ahçvÅ@Uík­‚€LiFüª‘0N:+‰¦õ@}‡, ¡¶UÀ3pÆA_¤á©ó^—ûe®)<E-‚!ÎK=$ú¢þ71ËŸ¾*ôÕ&ŸL§"I�DÄïsü‰/€å€ :d8­mŽßM[ä}Ó ,Ú5Æ\– WÅOå‡åwŸFUš“6}2øvȈÊr…A·Q wu ´³A¢m¯å¡"ÀÂ1ð˵2ó*õµ0‹�2³Õ†´ÖF½G"­Šž˜sgŸÀS©ÍÇ÷ÂX§r@ä€í°h= §/_L×?`º£‹‘ût 0=ŒÈ€êÀq(æ1qÌS'î÷‰×câõP¼Þ¯¸[(2ö!x¾ n·�çCðrîðz÷£7Å¡æ ˜î(ÞÔ|d‘gÜ_!}*ü0{ £…†G­õÑ»¤€7gá߯¶IJ½…6 È@6òSUGl Lw3¬|²ÖH¹ò*2«dˆ¥éQŸYäiéâ*8‹QÒHËà H<Ìz‹4A´A¤QFÕúÈC�-"~øY#²1}®ÖçÃåYÅ™9Š’¯ ýÍ!-H¾çXÛ±PLfïˆVÄÎ"ž=P=åBi#C²‡¡¾CaíÙ�Ýâ9 E6D$¯æ¿ýÅÏñßüéŸà®ŠOÇÀO¶õË�¿8,šì'ÛŽotâË?ûÔë{ö'øÑØðóãŽoOÆw£�4dO¨ÚQ¸Ú”;.+idt‡@Úp4ª%3Ê_!®ãQ¡è|¶Î°Œ^ϤÚõÚY¸ÂÔØžÒÎ\ö'¶ŸéZ®/]éŠÖ¯Qv¼¼-d¿É^jCÁsÞÐ1gE’ÏœÓÚ¤ãæ÷iüµ}¿ÚYÑÞ)zËciökg‡Á#yÚïSÚÙë4&“FüÓ§fè'§´9ZóÜ’+Zsˆ�TªUÁ.ížúÓ±SEA–0çG¢‹„w#e礶Výª ?îX³ï¢2Ý ¯ ÍCÌA»ûÁM`Nß}ÃóÍv ìÛðtvž’ÓyÀÄœô˜¾ûÈøÁ,Î,êÔá ±›P¥®€&‹iìgÂ$›#7kàî9 tˆêå C&xˆ�ºfî–L�èzÍp=q¨8OÖ X#§\ mÅKë'�®t–D& J¢°ŽúV=SK;(ò´Qš�¼Ë‘—P†Žlçd×] cl»õ·Â–Wc²|æÀÖÆ²gÂO��䣅^Û:]Ë<^/)pU±ìÕÅç˜+O)è¸c€†nÍ9�Ó<*F¥Á‰¾^v\´ñ¨cuT�HÚP-š, ÈLžJ¦tÝJ€ÜAª6)†¦«H>¡ö !@[Gè/ÎVGA%�ʧ‹“"{W~ò™woÕ xv+—ZÑÕZß.ˆ·L÷µçöQ>}Ì+-Ç»ŠBSšçžèÒ· Nð¹å�œƒÐ¼Qè%0œ¯…÷@Ò©I²å}D§l¤ÇöX‹éÈ÷Z_Xœ»µÏ´”…ê8àr0tóÒÀ2n퟼ÏuoíßZ¶í¹¸ÔµyW:òŸ'g ‹-Ì1hâŠ>‘2(æ®dQ23Žß‹qgÁÚf‘×�üŽ÷ÿ¿¼Ì�xvš%8ã´1Ö¼ÿ]ázT�àŒ¿j/ªL¿–¿‚GÜ_ŸÕ1¯[æyŸY81-åj;×õ×þ„PĽìÕ~Û`®åËï•‹‘k$V“�Á‹=2]¥ �uKz¾¿ŠŠœR¯°M÷€HéÐð-¦d"¡ôö�ŒÔ4¥Óu±¢ùêE0†{™9�ãäÅ�QùÓ¥â–�ˆa»¢ÅËU*2‚âšF=Ý…Gû •®fø">¤wœõ‹@æpgÀL[×DXExŽˆÿ+˜¥|×T’BøkîJðdÅ%8¨ïäägìä n¥àaùÍ¿Y ê\,M'|ÂsÀw œóýÄ|˜càU¡÷ ½O3Ú*rÁ5Ü@ètiÎ�¤½ÜQP$½ÂóòÆig!OéΗ¹TY—Ñâˆt_©79L£P>qú““ÖQé£ ½:¤Ì)qø÷p†CÀáÏ‚¿Õ~[*ƒá\Ò2)µÁåµ2CÉŸo àÂ/,iNÌn)ÿeÕgA ¼½ p+°¾9}wxw ™˜"àöÕX<�Ùœ“†v¯Xxˆ,°…øq˜áàõ~ÇýxÅËë+^ïwSa瞨l€ìض cnûŽûîsÃ˼¼N¼¼N¼±ï÷9l÷€óý©bÎ�iùƒ'�’Ž?Hî HdŒÀb:d/†‡óùá¸Õ1/ÎßR™,u0Ft #ö7Õ�\wE÷û@BçkG”„¨sÇÒCX„¾¸˜¤ÎD d»R-µX{JчÝë£S`÷ó"6î.¦¦˜…Ãw w K!´�äUþŒåw¡a o­¢æï˜>—‹FÁ¢m6>áýnFê2êü“r"½Ò€Á[.&}ðIuæô?ve³.r7€/æÄó%ªøzNüQù ??îç¶|5'¾š×ÛFmî†BVÖ”%äŽ%Ø-ï©í�袛Ѥç�*ÖRº¸¡T^Te öÛÂsÖ‰Zá'l…å…Ú}剩ªŸu~‰;ê”®»HilÝ=±²:ºS F“—�öŒm'rH~Õ ¯„K¯Çû þÝkÏýߺ×êQ©Ó=É~e4{/Um„‡‘„L —Æe XzÓ$§Hç€67¦Òü§DÚ‘ÞTGÐÔœcŒx¾º•«Í¡õ¾Š„B7RƱÉt…9$‚†�ó‰ó$pŸÄ8M–)‚]7™Ø„&¾–‘ú·Û†ÛæüY<ÕÛ°C†oÛpÇ€`N“çfä¢1~ZtîœICňÅ{‘räEwxšØœ?L—Çÿ‡øgú©LÅEÙ©N!.ƒA7Rq/ C[c³©²4zBžPr¤—µ¥uVòéUÅwé%ÁY‘"�NzFrÐx.ˆt˜våÕ§¢ó¼Ö2Ô�áWü3‰4Òp&©µ÷¶j¤oN©UÐòöŠ+ ´®S voª–�ÛÒÛùÈ5'"ÎV>£@s$³€¯ õìðç)†X¥\+ÑÓh,zEÿÍ™ÐÞâ9p….¨^ä39¡š;HÞPô|wei×HÓDºØ´v2äOò™" ±òÀB•ÄätÉû¥ª…ftù^C‹@Úo‰_CåFǚƷÌ\ùy•=\('Èê(ˆìC—3(´Ô[ÚaCq•òÙiZù²øüf-Á[RF„™ä‹ül�sñŠãk”› gdªh¥ÖI IçšôöU ñHé¿ ù[ \,²�•.¿/añ4ƒ;:ñ^½Wh|Ám0>X�ÿšÝб¡`§£®1³Z?]‚ìõQ�ç…H×�”‘<]yÿ>OYkztÿªNyð¬¶Ñ­×ï”~?„{m¹—ÕVÿÕuU¶¼³*Å v¹xTá­…loüÞçÜYÐËeø¢\ÔQëOçÀU‰½­ßÄ*æz>ò¡“ J kòW:¼EËÜ ~âi]$p ‹Bé@.ä—¼ÕîÅ"P—·¢hÌf&s0f¹y™ÒJ…r}vFZ‡Ä«œÓ£¼%çwõ˜@CrõÜ^EFˆ¢uŒ+óa¯*³aHà¥*ö Œ²Ýò$Z¤Oå™BžÉrÃ4 š¥1Òà³$Aaô>hÌ=pL`Zš#9N«^ãx}�Ñ>ÜRîUc·ÿ®ÞýØAAÇ€ªí˜ð3;æË�ãåÀ|QÌ×i߇:‚Bh­�ÄàÛ˜ÖЄI&,%ù <u«Ž¶6F“8︊ÔI…DÊ�ÌVéU¨W¬Èò} G?€µíÎp'E:1¤ìpæcÄy¦½=MàÕ%¿ä^Á˜ ‚ʇZg.úq*ôÆ•æìT]OÛ€–¶HôÊXQj}Cì âP¢¼{Äc8¥rÃÙƒ¯ÉÚ«áiÎÍæ�w¦p#~�9ÌH?Õþމ×û/¯wÜïw¼ÞïuÈØ0ü`ZÙà“ņ)7¼Î�——;¾}àÛ÷ŠoßO¼Þ^²ÅáSyˆ9ÚŽ©Íx˜ßœX|±ÎÈeèÊuëà>XÔ|„ÎÐļHØ¡-â~ÄÁ»éÈãtn(`˜ÂïÈ^,R[[ð`t?›ç†ž0çÀTû$uAþ£Œ¤NÔ±5ž0ý¼ÍÔQbÏâ<�ai©Æ˜ÞO:†¥¨Øí\�m“n¬P„>P°� À þ'Tg .ƒçä‰9÷U¤#­ðŒöJ΀àõEq�|®±P¦ÌexºDY¬UB,ŒwÀ?5œ—"3 §?úì ¿ûÛ?HĘ˜q|ªø iFj÷’Cœ:xÚo':V-|QR4Æoõƒq)‹®ÔÞIr5�eÀ©O¼¹2ƒ6±;¿¹½�/ß‘ rPÔÌ×ê•&2›½éÔÉ~/dƒžŸÅµ0Ú =]pÂwë\(jž 2ÝÂ|NõÈÕƒÆ7þ׉ã}ä³ïRæcÊ_ÝÿUúóèZsG},<ÿWð=À|Ž¥Lý^i“Ú2ÈúîÕû�ÚV¤ ½¾v£ÈâD¯üËæ¶ 2ǃ:¿çZ;ô²‚¥Î …Ô£ qöZœÖjZý^Z¢Œ¼fWB©lnXÊa­È*F�¸t#äÙ˜Ú ¤2Zu„í¤ñYÚwƒ®¥\v¤Iù¬}]¾“WÔÔ0Éœ{ïLÁä MõAéCaº™ÞN’_7õnó¾)Üú縤1_†}²Ó¥bÕ„W¼†àp fFLã�ÂPO¡R˜&�Zí:µUŸiâhN�ÀÙ1‹3î–Jè®À넾òl�;ÌjF8N(a> 8 ´Ó b-$S¦Åêx‘H¯¡*i\ßʰǰõ�+é$cåEÒ—ˆ¼¦M+Ð�dV5LzµD÷Æ6â�Ü&;Tç@[é%_ÐûH  ¥¥Û¹k¤^ÂR곕ú{öo:DŒ“ñ÷[L˜Nxj%£‚:Ä÷K˜5�À~Ô@–QŸŸÆ ‡ûŒ4º""8¦`Î�ð"˰�SqŸ÷câåõÀËË+î÷;î÷×`MûŒ}Ã>Ô ÇûÀ¶m�í Øžq`Ãûo_ñÍÓ+¾ÞÜÆ�÷¯Àþ Ü'ðJÄ^�Œ°Mã6bü¬;UçêétÖ]!>Ê�]®ò”¤{RóqDÖŠ•¥ÐaNý}£SÅæó‘Î9�5(˜„’�ÑÃR€;2¢wâIËç/ÅéL?Re\Ñ##²!;ýŒ:í|l9Ѽ ÀN(“ºÊ–2îëõA€3Ç®›ü㉛Ÿ&ùCLÞjÜÕèO¢ÃxDÁÌiÎ]^rúâSzU¾‹ ¨žd êý �±™ÜÅ`”yÀ"ýÝèl¹_Ê.ücÚÔñÌA`ª!n^„±Àæ´ÉïF®–Ægúp æ´Ã‚ïÇÄý8p¿[ê ó…™¡|ßÄóoxzÚ,jñ¶á¶ïûÝ6Øðäå}Üqß¼Wl›âål‡âõ^ç�:cßEÔšäÍ¢¾s>äU3 ·'Oj´~Íñ*ôfz`óƒe÷}DÎæÍs,“…Ðn=™³y˜ÌšîÈßJ¹oA>¥¨‡LZ®hÃó¶ ¶Ýp?!S0tÄxd”ÓÊ-íÏfÔ� ‚M&ö1±Ë0cÓ€4,�¹�‰}³ûÛPìá 08Æ&¡;ÆÜðä[Ì 9L£iVçÕ£¨M<À7UûT¡Á²ÆVçªôwýk,Ä €sô¼ÛéÌÐt½EËØÛ6p€Ñ ·I’Ž\ Ll˜Ø‡Í‰§›àùiàõ¾…Îêæa»gÈ+§šópN‹†ø¼çuíšLQéÔ �Ê}†tÖ‡ÔS´âœSE�‘²c§ŒKeÅ×bÂéV²®zñÙˆ/ù¡ ÔÖô•½þM~TÆþ^µMä‚öj;z’Q¼o¯÷(öµq£*åï#0ô­_4ú�önô]V™g˜2¶0Õ‡YÒé´‡%NƒO£SgÌsV$ïÔ3Ý$�•ËGí…«7ƒ�ѽ§®Qd@Bô- \�k™¦g˜Â;Ãf¨'�TT@#28GºÓ(ü‘®ïM 6@6«_&6?~Úl§V¦°såf_êîäÇ `Æ3Ì1pà~ÜAgñ£ðƒê ÃzãŽñ Ót/3d`úî¾cNƒÃe{ IDATak8“�ªØÐvÈÅ<1þfôât€:>b»Êʃ�³.îX ŸZVú©¼)ÄF§�Ê\ª{,R_ºœ®ö±SJK€²–´PuN-bË�bNø”­™òBsÇ\´’1ËÒ¦² eVV¶åwéð¨þðu®¸¶ZqI1]AYd¶=×x(Kðå_Ü]Æ&;QeŒÃSxeö½¼çÅ,­±�X• O§eJBìB– eé�[ÎWqYôqp|y`«’ëûÚÇb4i]œYÖe³²Ý9ð-è4 œxY¼SYØ…$ßùÚ�Òo ÐSÁ»›œÎI‹B’/ÆøUÙäpÆÚ°‹¤Ø-¾tÔÚç®â3�Ug©äÕh:³j­E0­ç‰ ~¤W‚î[ªçp¬ØÒèFå 'ï;®gëøF kkÛ8½°ò±0E”¾äRù$¡kÍ ^'N-]ífªø==Öls¯ü^ç ï‹ß#CpÁüPX¨óÎB£ÍÙ§Kú$¬v¹�Í‚CSP`_Á‘Òw_Ë™±[})à’!Ô¦ú×ø¸k{ʧe®žê¿z]�¬—fíy{ò ‰G—,Ÿ�¯KI9àÈé«ÚÎ-Ù·«}²¤†2éê.’˜ð#ÚTÖȰ粸½‚�vºKP{�·²e åm£ÌM)²­ #1£—å³.ÁÁ¬sRÆ«¥­ O³Ðˆ.AB[sLËtHd_ìÕ:É/0áË5J …¥(Qø«°[®SúžØÞàï°Œªî/G[;fB|VBµ�p‹eÀ�¿vø‰É÷b°iÅA%€õ¹Ð‹Ô9Éa™žŽb &ŽDÚ�ÑÎ&ÜWv Ð’Ø�ô³ŒGH Žáò¼ÍÍ{ÈâÂÔASŠc¹c€‡¿–¿£ž51 üë^YÚËÜ~qXt‹Ò•4'Á7B~qì cS…�#Ѷ2Ê_»˜oÐzVÎ268 �Å•–pìEç<ò6¡–þ¶ÆûÏå‡@ï�æ{]¨7ô�ë´¢sàJJÇ5ƒ„mê¡Ü4–Äœ.ô>9ŠìV(ЦJÈÃBÁÝ >G�†›î˜*¸3"“ï‡"ïG®e˜aüißðîiÃóÓ†§Û†§§Ï·ÛmÇÜ6ºáy<ív8â>6OS³�‰ñªÁ/7.«GÙÏéy¢““¯#‘ôq2ƒ’½_“k—%ÁNžvÇŒâ–FÇÝõh~N,c›‚)¾yHl^ X¬~ú0mGSÅâÆ“MlÆmÜ6K%´íæ˜*¸OsˆwîQŸ;¹ûÀÓ-àp““í¸ ÅmÀ?Õ�v�qA8lçÀØÊVzU@#ÄA9(Áâc'ËŠöÌ‘—_H™úÑ2×9xÕpKeĤBV™�/ù«Ó$¦;•„‘¾®¬–ùÞ{AbþªB¨x°¿þ’@1tºcÆpùô4ð|ßp¿ïx½ÛΜû1ñF>7ð‰¥#1#œ¥÷ ¨I‡E‹*QFiàï;5ÏFýÒ×ʾZ ê/Ú{éœ_ ±ª kfŠ éŒfÁ¼¿æ›t‚¾í¸º\G�Ç;¼uJGW)g¿Ïï<�$Ïf*Fy˜cP<>ìï±0ki� «±åªºUÄö¹¥½„’®ÆY ËÅœX(­é+¥Í0ró0[AßpØŒü4Y#ug@µSœð_ «c ‹tÙxTŽ’ÚëPø9>Í`—€dàÓLCŒÓ,p©«]Ãô£aøÜ<õÛ.& ÌAkë§hcÜ©dú¥;=e��-`Nþ㸃;íüwßá¨Öÿƒ´ûx ŽW:H_vHñœÓSÿ0‚?£ö# !G«8“rEIÙ0ÄÒÆˆ}à¹>±S@8ˆ´ÍCbÿcŒUàå4¾åK¬Ã$_ôs¡‰Íe_ ât J¨N¦,¬² €ŸµC:ÑH1š‹Ym2&§No§ñà·¦ùcÖ�”W‹œ„æÎh>©ª’ïฌ2¯kIé�âûº¡¶Êšjí^o†CJéZØË¨äùq¦’û6LÒh_@4æf_™«ªŽ­4Àí*�Vö~a$ÆR­ÅÁf›Eº I’�½ü·“VGr ò…+¹oãΉ YûA!ãR R*¼¸–+zRQTJ‡) Kž°PLté+².mšiz¡çÓæ8…3À>é�kfHa“5å~ ±.ƒ]”E—ÿ‚4J7/ÐkQ¶tð­rõgENŽìþ¼'ÞÓe\—~´Û+]®eú>©§: °�uÆw“H�pÐŽÚ8ÇOú+ÿ/k_¸æ:®j¹�“ªÝ}æ›÷ÕéŠÅü€K²SU}îuwv*¶,!„Blv2 C=Ë?(O°ë¼eL彞ÄlR^`û^¬ýýöú®óüÝýÿæú-œw×;Øþ'—ú­0ÛÚ·7ÏŽíݽÞ‡d J wmìBv‡ó®ÍûKΈhòaèœ,Ê›t"pÑFždÌcô"€ ‰(È ÛáŽÚDð›"^Ýg*Žx¥•M½$Ÿ¼–wÖcÊPÉiìŽJâ>Ü~ŠKö^"–Ê’ÙÀšñ« ‘L£”62“l; Š-�Àñ"sE@WÔé¬(‡ÈȘÊ襡Lsöm‹îe;´óª3dŒØy6¸P)|M „Ï«.îpž3 ©„J 7_ ÊaÚuˆÃ%ÝÐÈ®Ôt䎅r¼úã¹s`~9æË1Oâ8Æ÷tF—Ó€— E(\�…3S¨èªÜ{¤ù騡,·…,x"¢¦ÑDîbÈùÃó1ˆ0Unó÷ÑBNh„eYlôcyŸž‘k1~>c:`#¶�éWÎU:Ø|m©�eœ†Wx¦—Be5…øûÊ&}ýsð·—ðF%cà>÷aWÕŽmwÊoƒŒ8Ï%5ÏÒ˜;f8e§*ö±?`x¸á9Gæ§OãÁ9ñ:xÍó, L…_Ë<ö†pÆ`2ÒÑ2�ÏÀãáxÀÇ#rúó�ßésþ: _çÀ8�¯˜]è]nžFþƒ;;€�ø|ŸO~ ŸOÃó'Àó@¶ <Hç@Dµ<ÒAA£Œ{ís›à Û}Æ™' h2ÔÁ�ÂŒû);v†Ý^Ì˼¨ÔwyÚ3¥çUòŒÅ*µvþ!Î×Tm*°UIyVl×H'd¯ò¬Î�°Œˆ�@îÜ8>ž¯Ï¾æÄk:¦ŸxÍçtŠ¡à‹ÞÆ»'ykØíÛâBˆ¾]D�«Ÿ#&ŒÏ!s¤±TQ®wr5ëí4Vù¶NB—/q$¼Oç³ÆÄ\¯ë\î÷Wø×·Dœ±ôzã¦)+y˺Ù�÷pq^ìјŠ_½îzm¯¥.ù›ókOÛ0r%:(ãáê+7ùò”›*óe·@ÍMùȘך¸7ZIÄæËà‹ŽÏjÜϽ s*MöûjLÖôT�¿Ö )…M‘Ňá¸y†ß³íðˆËáªEß™ëaï0¤!Þ@…t$Z§–a _v%5Ê)ÐŽ¢¨w.2m ߟ±6€Ã1gðçaÀô‰�³éÞ?v¶*ãï)#õßQ4‘µG™{oôΉ‘ŽOŽÏœ™JhŒž!¦ã™óJfãÌ6š!µ®}."˜5þ|æYJl1Ê1­R3µœ7%sxß‹SÕ7a¬õTÒ_¬{f!²s”G¡š¦a�§ú¦4 ‘¿R,i·¸º"HæŒ;¶g,oeXßçÛ¶–ÝèÄÕ»À¬²[äßÊ›”öà˜#w”caEpt8û'ë=›«~³ L{Úݬ1jP¬wé�7œäÇ„EŠÝåòïî-|Ñ>ÑgÍIAνM?¹à{A�J{-á[ûzÙŸü½|kÚ{õÛ’¦:½P§jR:·K=J3Ò»|vÛßb"q¯Æy›«UÿB;p‹¨ä.é¡›Ò²®È2}�`çoF¸ÃQçôHWƒÎ|ƒGà¼kSq³8â¶�™å%ë€[½ üÇ!Û$q…ñ®:¿+sÃ?8–Êãëï;ú¸”3Õãï]å�*ŒÔ¹kÎ�–Yñ~¯%«Â ñöÈPn›ž6€ˆÏ—òƒ‡v‡:Li^¹žo¿oøÞ_�+°ùš“Žo¿ÅËò–1úcDdɈ<Ô‘Û2‡H-@•';¾/²—%7xçÂdRØ”¶ª Kùm•Á-ükñ 5óŽøhI�MåàLGZJÀëœȶ¤@;V[V3Ñt ‘]Éʤr‘¶¼å†¢*Gs»ïX s;ì¥Þ»¶0ÂÙFG\:lNø°iµNol âfšk]�o¯Ïìèé’ÉB$.Ÿeì¢Þ@a+÷J{/Ñ^M%4§º¦CÀ_éHÇÀù"lѶ &ŽÉ(_p4Wd8f6ôr‰Ïº;´:n®ÊõX€EŒsZ=›‰5D(^¹"_r…ob�`)Þ‚(ÐÓI‡v[÷(ܰ•¾—íL=�ZØ&Õ(š…yÿ(áÞ^-È8G9p¾}ëe›Ý'_éíùý̪gŽõiÀ™FótŽÙœ5á@ÐwFß»‡Sàëùä3œÓð•qNÙ�CïÌ‘|üã9ðùùÀ_ŸOüýùLÇ@ïÇ�/D]qÜ…Áó ?g®_ ‡¾¦áyFdúqd@Ö x�餰4°OéZ¶Fh—OSºæõƉ‡ë6] „qãÏÇ��gôóãyd„¤•^!ÙÒˆ ž• Ç€¯“‘ÂÑÙ~§ŠC~#—8>žFò<ýÀ‰�ã)Â/‘8ƒFƒ<\˜;èxOOç€áóÃðçÃjgÀs ÛF: Ï�ëg8üàNŸ­ä[î‚BD¶OòÔÔÇZp;Öy´_»'€ø^=äO-|Já­�MqnÊ(."D*Ž)b\ø”.èX–†œLƒÖÖzÙJ<Ìúî˜'̆EJ¡�çÀ9Ÿ™ªËð:¿ðõåxŽñj|" wªüPg ѪÁï.U:ó]™‹}ǯ59uĨ¼vf*â]êjp·zµ8ª¿wyÀ7[$FS=�ªî÷Žwÿ¬ÕG]L~‡Gé¯ôã² �V~Ú…PXºåI×rkÙ÷ðºü[#¿Ð‰-ó@¹ç{]Ïëµ=G<¿ œ§$¾é=ve4�H‰¶!®-÷~¥ýÅxœz1Õ¦mR<™ªCw8ç3—ßý ÙéqV‹;Â`HOaÂsdÔ}Éõ4þF@Ë)“nFžp‹„yÆð” †ãÈ „ÀûïŸîñþ]™ŸÚü·×Ou‡—Ûæ^öº»Åà+÷÷z¢•çïÊáæù¿ëßã–á«G¬ øÒüa3\w â B3çŸÎKþ� ¯ÆŽIÆ[,ìc‚€ºº¶PŽb±*‡%þ<,­[­,´pk�ÁÛ±µÒÀhŠ(Ö‘,‹¢$_·‚“Œ:\_¼WBÞÉcÙZׂ ÿ"ô –ªÌ”¶)Pʼnd¤6O@~N/§„ç.?yìx…®_é>ÛÈ{–© €Å9 Ã#Ò%‚»z›®¬7Ñû2êÆ…7\‚sŠf­ 2µ¨ pr´²?®2.n³ªáp‹h®qŒˆ /%NiY£qŸøóø8,?À8ÒÙ5Ò0'Î#>_Çë‘ÑÆ#v1¼|àñ5q¼ Ç11þ9ñÏ+"Ç©s€ØAÒë)ËñÐè œ·tb�vãB¿gX>Fœ)ðÌÝL›ÄÔ  ³ 2H»y̱—^0¼Îtñäü2·ˆ¶á 9Få?ž¹ÿ<ðñ°NN7œnø‡ÐfT#æì„Û Ç‰a3ŒûÃGîøóþzþúàgà¯�» òl��ç‘g †ç0<Ÿ†Çs`<,�Dˆp¡½/d€Â�Fß?�Éb eÔ s³¦…ÌNÑ‹á5¥ê¦,/ëæ8–‘–ÔòÇä¼ a‹ Dˆ£|’슾Y»´%p§œc;cÄáÝáôøz |}eªªÇÀót|< vàî)fj¢ £Ñ¯ „äÍ·ùeGäüÍ4½`µK7j%Íïý3kÎWæ^5Ì­7¸¡(ìø eκÛsm{Oå³÷}‰”ãÝ2 ‹y©àŸ³–4©÷Ö»z#’/©ÓÃz¬R‡ê•!küï—¾K#hËé֨˸~/EÆ5äZ¯ÞßÅôjGm½B�ø{P»¿Ä=­ž!ÈMýxßlù`�âßúH'f gìWIè«™jòUéšgÈ‘‘õF$z(‰îgêõ€ÙÌ�X!Ñêl›Ü@Ÿyˆª[¬�ê°û9—9À]%“Ð,›»X&6:;&£ÍJ÷�ÅÉ»GŽ wi;ò¦/Zg›¤`Ù­Ä­rðÔ£�Ó‡Ï�a&‡)»[8!ª¦Ñ®=ÆCüžµ> Ÿbߣ;CÏür`ž²Û‚üÍ,ÓÆ{ujvU%­iy¡µ„ÉӔ،{™nr1X©lŒa@ñÿ-"¹IOõå{ Sé9¹ñé""¹çÛýD[Ë5÷u&]Dû!0i<µ&Ð]x‹Á¬êám"%eŸ°*:x˱¡Ã*HË…6U]`)¾àÙefÎ`ï{†JE G<'ÓÔ;r̳ÝÒ!<¾Éá�¸�i¹ðKfÆö'«Sm¬¾­´a{‡ë’1Ï÷ü®¨õ\eøR�ò¯¿¶¦¬ŒøÕj¥×Êû5–wö-¿½£µ½Œü.¤”|i§kG¿[Fü,ç¾Ð|ƒÛö£ªKiYEü!TúïE`Êïž°Õî2/Ý9áþPmzp rrÛÖ_“¾iõ°µ~ûð­—Ì‘[ÇÀ•֮벽‘õ^Ã*ï"úÉkWP8_WYͱºv¨YV7PÒº6}jmÔûÍ’KÛ|Ôy–4Ql.éº3L*a­8Y)D.zETAÜÛr{ ½/ïþtï»v6�Ÿïß÷õç7µF þM‰»ûw|pk{iwÇÇXo�Ûé["ÅK§ØçBòüËß¾MïéŸÊ¯vxß_�k»›3Õpƒã ˜@ $ ÁËÈ‘c’X'U¹�™nÊ@>•»Ûî4Sc�tÞF@º0_Om›,e¬ƒÚù™­M-Ê”@ãiÑäïL±À  C¥˜YŠLdB°„Z¼S¨”gúNÐfùjËA›�õ9ëoøì^hÐ~¢!i¿ë`4¼ƒm&C§F6”âÒ‘‘ëN€F¼ÈÌeG'ôƒí=u„Ô6½Ÿ2>HøO�ƒ…_Þé„Ê9éDÂ1àðÓág;ŠÕMƒë­ÛÆfb)FÛ:+%>Cº¥€a=%=ºX}èðNÓÃ~»TYí¬ÄÝQj‰:3øÆ8bávðã>bί�Y~€8‹Kbå°ðë¸u©þ~kÛÞ%=ûë[9•™Ë;ÿFX¾à�|£r)„ºó±ætù2wd<yç^?�óŒrÃfàÑ�|(ê`J¡9�×™¹ë�ÈkÍÝ[�z'€Sd$ùþ|>ðçÏ}>ð×ÇŸ‹\õe[­Ãëei�x¯1ñ:&ÎÇL'±áÌ#Y��Ç×À1Î48ðåøŠN7¿sÃä*\4=óŒ#añt¡°EÛ†$JóTg�#R }ä9 d>ð:À.xtD¾Ðáü5ÿ^Ù Ÿ1O(Ç#"BéøÈ¨þç3„nÎ8S€rƒé 0N`ž˜öpÆ9w¤c€�OÃߟþ|™ªâÀã˜qÀòá½{á9Â1Pξô€º2Ú\2(ÙrŸyü',óZ‡÷…ßÀ²°ÙõœË|m¾l—‰Õ|ÁÖJŽÄC×7ÐÛ‹¼y›ÒÓìöšEŠ"û¯P<,Ï÷ˆ”þøøç1ê\‰×#RRaüádvF$�.XÚ1P‚ð‘Õ.Žúĵ®SxÉbú5Á°ï†øø£ùÅmßwƒO^<¼ô-÷¯«sÀ—ûÑDŒ ëÛ#¿Ëx™}¨ʱ¶ÞôA£Ìkj—¸ˆéFÂ$4÷WV"ª‡JåyIP*4BþN^Ñh¹ìÌ�÷ÛI°ö¯æRuTiíYŒM äK·\° …:oج¥¨sÓ»ŽÀÅ®Gùr ,Ï­Új=+�rBïux´àÃÝRI›‹Å6 \Jð°ð4û ó³ê¡ÚK‡óaá°=ò]í(¤…Áû7¡W¶[apLL¦}Q9Iع“œ_Ñä^Îáé�C¯D¥ºÚlý}3œ'ïô8^4Ø8ë:¼ÀòU“fëïìCЭ>ïD*u*Z0HÀQâ,û›°ó�z�×ÂÙÖÏúÛŠn0Ãy觯ÁS¢Ó˜ö[;zÁ!à)ß\ïµËó»qz*0.‘;]o/} 2ÔJ‡Šh[–Â{_„ü«Ú2’ÿ@¶e«“‰À*-(ÆM.¬}2ù@[Ÿ«.�uù»ù_´ér;þvú؆·»� ^ïÚÛ®}¾^ws½ûyD²L�bŒRÛe;�AÍ7LÇTža»½$íôœû†°p?�«³¿ÜùÉâhØêžÌ§‹ƒ#ûU�B†Ô)ɡՠücço®½½ý]¿){WîÝ;¿…ç^µ”û ±þÔÎwý¾ƒÅnʽ«ÿ'¬0h½ûý7çÇkao¯GK¯~±–‹5AóßÅs©²5�Q‘ƒ4@! +5ñ:òÀ—Îb%~Î{0 êžë–â¶­J}µ"85*Çûa´«õs¾M'_q¶À!é,WÃ‘Æ –‹ƒ†<ŸGF8žcây„ÁFÐçîÀáðsâ1&žÇ‰ç1ñùˆ.Œƒ~5�­ÒÍ�qvöbÛ™ó8S�Ë)bkã …CÛôÀž#ù=ˆ™i„,w 0š8²GÊŠ†¨Õ­sFd¨�“ù÷-?Gä` Ç€¦üù|Z8[2…�gÎÉÝ9÷ΉsÄNŒ3vî Ò}| üùøüxàïÃÿù0üŸà¯?üõgà¯Ï�Ï�ØqŒYΟLj±~Œ€çxXìü(Þ°0�…¼çœÍ¯ÝPÿYð»âQ¤lóN‡Vü̶�3œ .ísflc-Ÿâ ¶þžÒ–�6ê¬ÜÄ‹æ¸ã°æR.-e•é+J� IDAT5ß­Þ¯Çäµf±»ÊbÏž‡q#qé£NOãÕÙŽ˜ço´�×vôšu?½¥e« ×. SÁ¡qËñ&0¤øúz‘{Õ�¥Û“ž®kÃ{_î~¯¹áû¾çÍk?p1_¶˜û å;£}õÌö1¾ô� ‰S`«iï[þÃ¥[4t_þnÌ9žëNÇ�N¯6NóÝÝ)@™¼;ÒØL_uã¡ós·>ÏwÃ�Ô:ÀÚ¡e9Ýß.²YmwŒô-õgƒ±ëà'µ\•–H’&ÊÒâ ë·~¡G€ùù9–Ñ®ÂAãTȵ�)‡Ô¹XúØ„“è�¶•}ËL·¶~*§õ)Þ··óémç·º™žãýµž1P ÿ÷ãÄ>‘éŸ|~øø§ÀHyYé+xÆÀa%:tkã6O1F¦…cÀ§é°ô– Scyß+çjN.òl_ØèŒÓ©Eþ_�Wƒö0`–rŸQ“”�ÖôRDC§\ÎÛe·]Â\rÂEæh]¨¤âŒKV$h éÈêOÏ] �¨6"ìQøYvU«-Ì~0]�¥s 瀬ÕÞ\j4ÌöÊXÜŠ“â°Èb–®QþRv(…öݨÒ�íØÆk+S8ÙV×]Œ n£¶éß·²t‡Í/Ï–p·þ¾Iky+‚oÛ]/FmK»ekDßöI¡|ë@ ]Nþ:à.”!]u´H‰&ÑÕ‚§Î#ŸFÝ‘å …«¬ÜÂUŸÏn'Âõ=¾ÝÏPÎ/;FïXœè5Å6~-ãц!FÐ!â`^:d˵Pì ˆh ÷™ü×1Ò 1E±³ò´àÑHö¸+âÈüü g ÃÁI•'xˆã<Ã9ü5w ø,�#ÖOG²¸0ü|„�°<ÝóŒ°Io€÷.í³3øÝÈ5 €£ÆúÌþ·ÏÏtàp‹3’cÏݱ¾L'@2YÈi‰ËU¯%Z*ØZÆÍ@ý>éÑg;`Äè¯üv¦®Ê —.Óò‡ó̲q·N�TÏ•~T®è */™vtIïØAÁÓ¯V V)¬†Îz�FÐmΠÌÑUuXn µ¼×h~ÊR}WÞ+=9g�Þù¼ÜÀñíÙn4¼€/µ–mßìCÞ[Ö�ÉYQö„qŒÔ�²cn½1ï�"ÚaŸüηä3©ËĘQ×ß.Åã»ñ€_ðr¹ôÐ$-Tôè±£Á×gFbçÄढà‚sÕÓs¦£ 0» k= ;Ëôn*…„Œ¨Ì€dø&|m¿\"îŨõ-Dm¯@r!ÛVx‘aÌcZ˜ŠFEȳê'‚½dU q2É7Oéuc²=ÖÊX3B³8·Xö]Å-­[:>ýîSX>ÿÝ ©R%¾^¾þòœ§Ü) Ûµ•ý°¤¥Ú-ÀTU¢ð,B& eŒJ*¡¤Ïk§ñ» oõ‹—j�„¨}䫬g›^‚KËEÊ!RiLöœ³Ž8õÖ�eµ·× »,XØþ2Æ ýXÓ¤Œá^wE}p>é˜;åtÃUܬŸÕo– êøz%Éï™ñ2í×Õà²Ež‘Ö@;0:‹!Ƽ%…sÀqLàùøx:>> ¯¯‘4œ†â31cüçsà?†ÿ|8>?>?>>"u3BXbçq˜æ8frÞ(8œX 0HüªÁ®˜ ½‹|M³Â¿<Ǭw‚äóüY)åhت©Ñ3Èê*ú9zfÉo72À*z/ÙY9ª±‡ë.<îcj§±n=Ì;O0Ï8ü z³Y»Ž#ðœåˆl–ó€ÀÜŸü„7ÿ©¨»;ù¼FÉ?ÇÊóœ|t!íõ²FV;¤šØzGÕŽŸ"â7ÐQ®‘Ö»÷5òûîÙRÖѼå[Ønú°IÖb׺:j¾C4Êáù®m‘‡Žà‹ 74Ê‘íµ}¡èíTÒEr¥rAâÝ{È©¯ö¬Už¯)W¨Ów`Ï~N„O‡‰‘K!oz� lD�FŽ Ê¨ÞŸ3tÚ¦%²é‘�²«KË¥¢]�–Æ…‡ð=OhÆÈ-RÑ¥4éL×óØVȺÞ�¥tÀ±˜žqòbUœqGÍtÆ 8NÏÀê§®ïÄ}ž§<Ýñòà‡&»‡# Æñš^|‰:{5XàjÌ0ÏÓ€ïZÎGbÅ—�;ª˜òhX쪤îÊd÷ª)¯Ë1@qC¾žó„:æŠ)/žÄÝ@Ðý©HP3Ö¯ÏÐÆ˜Äwc„“†ó  RP#"£èëžW{mðÓk�ôkú¨¾z@·aƒx.óUÕÍå¾L&g�Ê]J켆Ȕڈ ß�¯uÞ…ÈÂOš.øÀ)³´åt?,9Ô ]*l;ù�I½Uœr/'J�Ék5nܹàk£rè�ÒwK±�%$Yלk KUpm_œNà\”´ÄéÝ%ð^îñG9¶úù|nïç¼,µ;é°£z– šÔ9OK' ¾cR¬•Á­N­”í7ÄfÃw¼ÿn&‘ÿ þ)¯¤ÊznëÜ/˜LÞPÜKÁ¸½F-;yY­}ý�Î69º\b/õ ÚÓ±s™cÅ0·y¾·àÿ:mo¾°™ëxU[XïÁ7<’lwØ\þpéõ;Š:¯™{óÝ•àŠGžýŒÜæçaÇ#>IRqÜJ,ºŽ™4<ä ö$Ëép?1NOãùÄ㈅éùÿrÃá†qÆÜcªãyÄ᫯—á|X:ÝÂ02È4DMZÌ¥hËäñ|�c¥„Dœ;Ì& £Œ7mÃKçõ|Åî Ò�Nd*˜Ø5Aç€!Rÿ<^óÈhK7¸ãÈÝé8òàáÃsWÆê€_8^Àœçéx½ÏcÂ|âåáÈx> çÃÿ ÇÀߎ¿Ÿ±K$êžÉ*†'o Œ13¢1i¯o£M"x ´É�ˆL•¦‹“*Hç{9âYP=ÉÇU—åŽò•¯{FÐY±€e%R¼PF¼æ�mŽ Š©äIê�&£Óïy=ßå�Oàô4š�ùíÀ‰;Hœ|3œt"ÕÔãÈ®ÈLó¼|gîD™(Øòõé4zª !?¼»J¶ÞÐÿê• o8ï ßöox¡çéN¢züä h˜²ŸKß¿»¦£é�{în»þѱ¾yó¢:.˜¨ùô»kw\wCðyß�Àb‰&ýæÒ!Gè4ž� –m0à¢à¡EÐm]ÛJš3`I�ÈIX,Ī/îjøNþRìšN0i!e÷r(ï%€æ*¦kÚ’]åTlcvAœ`”8.•DŸ:ʪä…H1 ,FÿE•©gÂ.½É]Ëá t´C0àoÆ;’F5 –Ùú†öNAÔ:¼hù�{D”Ÿ­oõ2Ï3Þ?ÃHù:'ÎWGÃ0 ¬û™A Õ÷¦WЉák6•s¤sÀ�Ógžë3¯Ë‡ ô.ŽŸs s´“¶ÀÓxó2êí4Ú—�äqËÜt’yV¿c‡LîÈ]Ýc�‰¢×*Å,DÆ?²´ïï<З/ò}¥aùÂ;ùS×Iʳê^:8–Û+_Þ+­¹�äÃux‘Àê=º Zâ××~PÏQ¿€:º®ñí6é{`ØVí`5ùO _JrOJ�çáK@O¢aÙíãBŽ¿úÛ»Ý�VöNÊœRœô¿ä;¾Œ«Üj¸ò—ËuCLå(à‹2_çwœèÕ¤Â#ënê‰ò^Õ­AL lë¸)l‰*v¶Ü8­Èp´íA�£ãUµìíoãH¿ØOl—Þ¸ÿe¹»ë]}»Pùíõ�[i‚¿§¿‚÷Æß”ù©ßÕµ;÷ÿÍu7)µÏ¿½Þ9\âzè nÆÌy×›Ë{ÞØÂHbX¶Å–7Ñ’8÷4;ºp°~e¹<™Ì=îk¯-hôgk´£‚©‹Ì2íÐ.HãïNšÑsÒâÅxIƱX5LZaæ¼w2ªŽíE�óHI£Ì¨„:º[¥~ò áZ8+¼® ˽éÝN ^æ1­Èf¸„¥£ Id;_ÙáºòÂVxv°t?fu ¸À¸—5•ýE¼{z:S&üËá_ŽùE%- ”Ñ#Ѷ~Žf¦š¡-sÉF¡Š\Ñ •¢±>ßpÞ£×F"™óAù™Õ„3y‰Ï㞥ƒ¤ ÿ’~ªNá±yƒ¹•óM!óÄñ’�‘}º›W5îxë)Iw¸vÖɲ¢\ÓÞÊP œ“ûvù·€½,6®þmª”­lW1PyóàaY5оyö9ÎÀ£‰AvXlÑžÀü0œ¯?0rqúÀœãxbŒGâ.cô-AwGœzd€¨¨\Â�‚èßžÆsÔ–G8°r>0gòë4¼rÇÀë8O¦9BñQ’Ÿ ^eª�“Š¿%:áÖÁ¡¼ªœÕàüžðyfZ° ÷Þ>oH|š‡A݇‘"ÇÃØÿuàa¼qÄ!ˆ»c`ÏÃñ|ÏG;È3#Ò¹�Hßp|¾pòáG4ü÷G2̇Ÿ}xœ+ñ<ŸÀó�ˆÀJ]ÀÝË8G'ôœZh°X„-‘0H:lžlòJæ±*¤YoÏX†£ÿñ̜˩ëÅ×+tŠ5'Bâ�ŽŠè”×ñš‡yRiΨ¦Lòk6Wð¢d�ÏŒÊÍCÁ# TåN SKEú®p¤žN0Úõ†glG�͆jzJŒPò§ÅǜڕÍÐQñ«}¡Qx× áò糄p£³o¥ïêÚŸµh^¢Äß¼sÝ `¥‡þÔ€2U ¢­ü­Cà¶N‘¿|ç/tÌXståýûùK„ømŸ×(´µÎú…ÚYÊI©íÚ-E€r¬É×öWã3•”.[2HAõÊâÞWÑÀ(Ò[ÁâRÕœ‘ ÀËFÖBYœfNÁ[÷4L3`»‚`Jôzó¾LÍߦ…¢mòÒt׎²AH L_ lÓk.§ñá.¬~:ƒP¦`�èî~sï2Ñ5Y·[§4^Pìé„ n¨KŸ‡Ìiþ|†SडÚýRŸ`¿Œõl‰òføº¹tL`Žp 7˜80ë,‚.«†áväÐ1xo¬#®»—�ºô©„iÙIÍ ¤I5Ð.Ȫ¾-tÝŽ„‚ϽúG")uA™ƒ<”Æ“îz)m™ü^ÖÙ¶•AÕÇ”/—ÝY£Òm}"M�N7çÀ›unv·t‚æM %û—6Xeÿ­ÎCqKB�ô+ÞÉvïzƒËx.ýtò/‘uܱ’ïÄîa5Á‡„¿BhŠö‡À :xL¾•±¢x‚¦*Ëp0Õm�¨nÛáà]ï2AَЃ„Á/aóŠ8¥ÓjéÔ] %ÛÛFƒ|Lº¿Ð·­U�.òl ÏYláQóÜP}ì!¡°Ïß]®¸`ßs,NëúW´�Ï™ 6‡®ùÕ)Yó‹ ·'T>÷…�©®à ã¡p·ô¼dè‚—È ®e–1!Œ¢ûè ݸŒS³Ei½º¸ÇHoôÜnŒ|³ìˆÄKMÍæ¯úêÅ©³7‘€Q¾›ÑšÒz!öï(pgþ¡v­â‰ÛE>ô®‰Ë jžÂ—’K˜„ro,¯ouð×Íä½8Ð$QZ™ èØØp“N�y:<�ókâTÇ@Umˆ¼S„<£iGoÏ�nÒj=›° ï˜0Ãr( ŒíÛ°¥Óœ€Ëv>1 æùPÉ]ÇRÓ;‘ܳ¿Ü½Q1ÖµHZq�\´•FÄZ©áü¾ä8•¡­~ùz�ô¦ó±øR÷ÎKÌë½Bj*ˆ)~a¤ß õZÇÛeòÙIÇö¹²“óm½¼Òye0ª¸¬¹Ñ„�1v¼°Djg¶Ýtt|Žd_ÏÃá~ÀqÀì�1yàéÄô0dŽtzÎ92%ÁAÿ C ƒ%üÇü¹àé0œN�SΙ~eàu_ÇÄëS Vuäø­;-V¾ÑÊÞ�’]:ßð~·Òºgžç9ó<0C¤¾cô! ½u9øÀ„ÙÄãþ<œ‡LP Ç€åÏ<ì—†ÿp8‡á1:UÅ‘Æøü€ù ó�×qà|�ð™»þú'Á_Ïøþó»Db§ðxR6µQÖcaJÆÅdÒÕŸÂ�õªõ37‡—3T,�DI¿ôzÊ”j“<�Œ%ýœÀ™3Ü{ ¾”åC…#Ÿ‹,M:Zž%o¨öRNLÂ+ÕÜ阧á|µS R yzºÃm¦39ƒ#2¥¢¹ç9xæ‘ö+æ[Êr× Ólð¿™0¶LâÎ(Q e6]hÛõ“¢�–?ÔÍ*—ü7ïï9ýUf6ªýíû×ß_ê\ÒIl–ûïS Ü­ô®l9ŒRý¾�w×§¶ŠÞÆ=.Þ9A4j¶îÉO-?Ý¡àÖnöh[Z¯ Ú­_À2þaœ'[ˆN|ä$™wéÉÒi ò¹¦~Bw·–-ѼÈh-ô"fÖô[0³¾œçcXdU'z¾¤³íNÿT£ï°HÇÇsjê0]c…¹5ÃQ)r�ZhEõO‹s,ÒÐèCƒó4ÙŠƒ�rk'«¢bH>1·³yjДSG@¦WJgù¸Ï0ÜÏ™²1vEõØ´£]^»XjléÃêà�ºˆvmzœ¹à'ÎL7Ô¸Ô�e$¦³ ¿Eú.ô7Iýuk“b[ÌßKyö·:ðä|³”•Þ(E1Î`àxÐLþäµé‘%‡âSS=wb. Ÿ'üË\H¾p¶³Gç¸k[Óµg ŇcÉåN¾CüÉ¥ön®Çã ‹h^P²Lt>‘®mÉ|µlh eÂâˆbaÇ2fªêÔúPÚgŸT©ÏBN·.ÃŽæè¸w*b¦áÊNG?‹Ä“Ì�fÉB—ûüªqM5R‘všýè:—ñ+ÛÆìõ@y®F`eoyíÚj¿TûÝ*n­º4Xü,J¼…J_aw寧@”ã|o ˜Öí"S–y$ºYÚ ]�SU?wúÍTXeLhA&Â¥Ž Þ�-¿ßèWË ‰gÏùâfø¦�µ1ýÃ�Òz~÷]¹u!¬‹h©Ï/ý3 埴½Ã§°Õø¯D¯Òª×œ‹â=&å§i¥&>u.˜Ò¹î÷ä»wcqséËVÏ}¡­Žwƒe7ß½ÿ?¹G÷³óþ^û$W¼îeïÚÕz¾ëÓoûÿS?Þ�ëÞÎÞ§ŸÆëß´<*ýHUgJª=,T2j ðÚø29…aýë@-¼*z¢œ_˜´Ë7+í‰ë@E3W„ë5k£Oµ ÐS\‡ˆTVq¤œŸÞa×15«\’ftœ  !S‘ps-ôÁ1�-/@ŠéÿP‡¹ùÊ÷<Æ+l,d¦ëø±s1Lh|ÖvJÉKr1! R…ÆêÆ'½úMÒï¤COVöae R{Ž{§{@÷�ÆG÷×±”*bœ‡À9Ë90y°ð)§ñQ¢tHW[7–€ÙŠãaXªþE£W•«îK?ô/FºgŸyÖ@{€ àøUy"é0aŸ 4Ž�š79åYÐ`Γ4¤Ö–©ãðN¹Ì…om9$˜ÜØÁ®m‚={ _èDzš¸îÞ¯žk¥a\ʈ8§±Œ/ÃÊþÖ KM2W�DbZ@f= ­ƒÛ��ò5ÜìåðÃ�3Ác*¡rG_#ÍÃ1¯'8{ÀìÀëÓ)ð4üõ>óóñÇÁq8ÇÄÈ„‡§¸I˜stHô}í¸ZåÍ‚.Ûþ^¸ÿ ~•^"B“¦ïZXmÄUYïÌYàY4gí("bÓÀJ«]Jœ¶Nã� È.´}ÔWúh™B§€—Sàu"œ¡{zî,+£ßL_ìH1?ù“ót¸aLÃ+w<ΉsL<‡ãqÄ”t'uî‚»‚= i5I7Þ]*¿VLÆ«*7Áª]ÊÙò»‰³­Þ%EÄMÑÄUÏÔr{Ê ­—2ß"$ÿ·åÖõ•7úÉ7ð¬ñÝ÷åoß­&öxXÊßüçÆ‰aZ<{Eu‹›–¤UrÓ ÷q¯æsŒ™Ãí\ꈦZ6O}‚ç ìë/Ǧ¾Uz–0™â"ZÇŽ{A×BQ}¤ˆ3˽½/«……b b€qG>­Ç¥vK¶Ô2}�ÙNăÇó «y=h”:×N#Ç0Ä^ýÕˆZb×@ð�jFIÞŒç �j>ë‰]p0p®k[k‹{”Õ"ˆ£ižQײ«ÀÑ÷áÙ&&ÆŒ ¯1#å£Qâ½v6T=O—ìq2F²O u�Ÿäà««¥@SRj�»³Ð¶9ë)ËÞ E:¨wÐ-b™6ª…T JÌ©<ð9·7æäƒ®u_þz‡Ž% Šò&Æg�×ñ ùÖ‡ŽÏe”Wù²Ò¥UÛúl–FÃÄ$ÛPG2ƒAªoÞ¨é±hÇR©|²‹I#äÍúV^VÔO¸T7ß.Ži-ô¥²Kx§†�.Á[«ñÝ¥m:À”èˆ^î‚Ò3œb¼6¹$×<-šVNX;T8ŽÅ1jð,ýÉ–zÈkú}_Æ©–EúŠÂ)è#Ûþv½{S�Ïg+ÎÛ!àœ“wˆ¼)˜¾‚më„éK+L}y©q/œ°`…»õd™«¿ª¶d­Ý8N»ÂLÇú¤5‡îQ½áaë²:�¼aŽÝ4dˆ„ËÖ>(ÕÜÌOEòJ‚û{ùPaÀ5R½ç„­»/jÌdðˆ¢œã.c¸èJ;ZÈ;¤.ÂS`oxXøÎNX’Ra›‡Ê—ëmÄ]� vœ+o¹Âßua»Ã4Ù¯›ëFM½w�áMñïÛÖz.�ÏÝaû¶¶w¥ïû¹»çØÏõ\Úúc@BdÞ–xÌé—"\^†Á>~ò/Âq™—ÖÜÌl¸æ„(PY<ùYFZ§bËg€ò‡@Ô¾…ÓùMd{e¼„ÚŽ[MK�ÂÏuÌ(ðâ9¡…� ]UÿØä°6²ô ÎzkñÊϾ]åEzÎIcÖØek*Ä9 +ÁÕÛ5Ó¸õÙ„7+nWð¯djy_  ùüÑ�l{Dƒ>W—�Ëç0$‹äï:ýtø+?g,€Â)�©ATÖPóÝaO.,ò¸ «@m³¬£íåP®tÊÀÚ¢µn €n!•X'—QpÔü‘Î ^±õÇò: Å�ªÅ\È2¡Sp‰#�³F7�´GÁ¾ðͯšÊ&5%¶¬ËVê/u ¬­¯ý7¬}Á:ŸNd1ºØÍGËkìÏÆô«ïëéÈ$N³šð§…Ñõ´ŽNˆÈ?™§CzoÃðxç—ÁŽ÷ð�¯×Äëe/¡ã¢t¦‘áÄœ9ÿ}`ÔeA%Ljè÷i†é£Œ1–QÒá(ˆ÷§£ÿäN�8Û`6Ý2=Uâ¯ä…`iZ?#Ò‰Ö²4 gò…>k˜jl=w>DŠŸçc”ñ¾6Ä8]A_�Œ�œûâ™É6yFA9FD†ÈïÚ¸ýƒ¹8½n˜ãuZäšÏ¨ÒîxŸGjüY÷˜•Ê"'(Â:q†Šâ�|†°š—sµæ»ÒiÌB§ÅxÝrÇ@С3•ÐqCÞ†Òwmæ`1J€í¸£Nó]Î7±µy¦ÔâãLÁ!ƒ›<ƒ|Íû(#…]®,çsF$ï9Ã!ð^3Òþ„¢±8|žá8gÊéHrXò} '€sâ'†�qçˆÔU‡…ñp tÔéâpª Áƒ3?w9ÇËðpUʺü;ÿ®_SOxòŽ˜DéADZ»:–ReêïËA¹Âùùbº™½�EÍVpƒ£h]܈bTk‡DÊŸ›nÞ÷=)DŒîïœߎ[•×z‰CNí±©º8cÒÒsìH+¶Mµ =Ñ9Ö)véÄ*R²8à|í}è &’Yh¯ù95¾©Yþ;²_m¶/× ÙPͪ³Ê“'P¦xsÍêl#w�YîF&,Fvj60ƨ(÷@i˜Ø=oÐaèLüoaÄ?8ÜñÈ6訦Á”ïFËŽqXðׇ4YKrXf÷»Ï�ó¬%wšr‘�»GÂ82Á‘ÂÌ4&¥–Q»ï_Y½·Mdßmœ ŠçŽ�p¶Æœ¹³ƒô$Ôc”ǹk}´Ü×uO‘¼Þ'Up}˾Óà_´®ý°Ö1ö5,@½€ý‘Î2µxtÈ»aH°ëŽ7FPðìš¾ð 24n(Cý²~iñ ¿ÛÈËs’b¬ç0œÂ'ªÝ}‚Yê‹ÄKò ³t‚-5tŠNen„oì w„ÞUzÓÁÒq"Ü9c�~š0™V’5šqçGì†Þ†ÿ2Œ‹*Õ“ å‡KÀE‰ÔÔ×�MÚ,´yáS~mXYä²�CrQ„l)Ösà�àò ·ƒ•HéÆ*}�g´_÷׋¯;€G4æÃ0ŸaPóØOÀ¤S![NF:¬0M™jh`�_‰ñÏÌ2%À€ûÈÈiÔ¼ôÄ)¾¯ø:�ñÇ@ CÀh.¶ß}�'-QTQCùš„ÇÇb¾îú9ÒadÊ\Ñ’âqèÌ×Èà0Ãaá8Ž*EÞe†8°Ø€‡µÁ—ij؆1�,üÑLÀ,Î_˜3LɇÏcàó|>€�‡á£œ+áˆzþ½¨©�ÂóáÁ�#u*Ý^«Ï.Yû…s×€!�;Ë÷ÜjªÅÂÁZ†ÔpR.{ïLBDòÖ|s€Öe³^‡6ŠÐB®-"²ªµ*OÒs· %3òlŸÜ)0 çˆ#…3ºÒhÌAEl–cÀ=wq�‡�†SÕñϘy�N¡OoÚSžï„¯¥’;ƒ Ƴ2dœ‹w@YPö¾-i ‡~gàW ÷–�ŒŠû­Ì^·:6ŽZÐÞýï꾦꿹FýÆö.íê_«±¼v£~7g¤Ž*µõY¿»^éC)17²sÁνõƒ îe­¬º„ZÒJK ‹ákÚ‘0 Ž˜³™Z¥u £XßœÂÅ·û|¯ë 9¥©Þ›9ßÕ9�2Ú—¨ªÎÄ™fhäx3M¤aä¹4Òo��íLò×Í9ç'Ü2½N2î~bŒQÀ{ U4BYï°tJÃÊ>å½`uŽš÷îųcýFýØsg*ÏÑÑìv.ÐÉε¢®ÅÂX¿Œj«B†Z‹t X±™qxðºÃBüO—X®¯L“±ÃÎÂyc�c¶«~šó‰,_=› ]•¾@™”}lA4Ë,�q¨uB›:€ÐÏx– §¥Ê<�6‘"Û ç½id}ñ’…©)Ø='� pbjÈè|ê‚t.‘.¦ÇѬqáU2Q ä+†vpçÞÆ«I£Säk;¡¯œLmÜ£ï‹ìØùÖ;Gíºßme) B27œ@О;|Ú:�„ÇZö½Ö% €«''õÈ3¿èØ*6Â@ ¨�Mî*ªÁõ+Z4�Öà°…eúŽÛ¸9“ï.¬˜óÒ ùTá+ÛÿN¶Ò›üygç5мá=sV uu‘îTµa‚Óü.´HÒ®Þ!¦ÚùVqðoЬõo¹+øÍK”ë:ÙwÀFÜÏM�íÄØï´ôµí>aéàQ®‰ÈÌŠ~�aŸ‹Â—¶FšÆË± :—£Ò•÷né«mN‚üA�ei·ël¯�à”²“ý˜¹¾™ŒÕ–·ÎͤÛK—æe\·¾ãþgƒ®²Í° V0=hôï®uÒ7dïˆó‚Ä ”ïë_ëjÐ×u…/[ßûn?A#ä]%-CŒ^ëk�AÁ}ßï )¬:^ÿÍu‡K»yþÓ`¿oÿqÎ4Œ܂éVFú˜‰¨ee�(r‡»eDLv×gé¬ ¥€ÖØ”Üú¹Éè½Zp #_;A„~ Zó ›Z7JSXL+*ñS"ß‘= {½}Ò[zëRÖ®¡‡m™Z™wÑaK'å&uö˨‰ �/ôµÈ‡b~Ù/Q&ÐEÃYO„›iG!®�–¦nò¼K>{e?]ÒOǺSàÄuÇ@)–"T´ÛdúL±òœŽ�/Çdú  ô–M[> .ÉÿSX¸6æ…TJ©FÉWÇÊ:úk9�mãõû8¤,”ÖW¶öÕk]KhÓÅi“4?í-m!Õ¿ˆƒj Ö¿±|3NÐWô±n‡„à[ç’î%/ÚLüŒí>ö¿Y,ˆ»hj;#~wmÌÿV†0:™|2ŒõÛ¬½©w$ʽÛÚ¯Œ4‡Á_V|lž'æ‡þMŸ²ðkz"h—-ßÓa‘˜¼Ã¸õÙrgÀc¦ñÃx:Ap˜p ÏkD¾…D “RÒMÒ#ç ù%‡7¿!Æ<Ű×Z\¶Q÷\«óÄ€6[]F( &y�m IvA3qv͈/Άĕ¥#àÈEàÈþ…Æ‘¨‘ª¢¢P@øãsZ,î 1ôO:†gîˆtGq8òjóçŽÐú‚Z´‰ÉóÙxìKä]nаá=§HsÃ�<°<°S-(9_{žqþn|»±¨”Ø®y þfÇšò¢¦Rö™s3ŒS¹Tbd÷A£qqFv£é8Ï�“´– Fæîfä.-,±[,Rc ž‹`™BdNvÂìKhƒ³žC8A •z:�ø%•'+^õîÍx{ÿñÞÐîõ}õ^÷kЮewy÷ãÖûÓ„þŸy¸îª\— ¿áÿ¿»îœü}IåC>öF#¸»d¿:3¢�õY|IÓ´¿¢´5 )_FìøÊüíèv1Q½líaóÔ}k†:ÌJ�ÓÆºà”mj?ò!‘*×^ô�¸W¿M^×)ðW÷E3r}?u ¸ê¸@ÀW[r¨½ Æ±óü–6:@Â¥¾ `ÒŸµS�ð™|W0Û�~¢j 'ÿŽ|…Ìnn× ÛÉÓ0ó•Äô>: ú¹”ó•/%㮥u„–ql$5;!›3ÈÐöµ3fXªš}¬mmk±ÕyבëOoríhÜ ñfx— ª1‘ÜÛg0²l¥Xéw¬–<ݶ+ðñ¡e­ß‹ñ¥^I‡¾SºHŸK1»køŽØ¾ÁÉu2¿¹ÿî}m÷í\ÞIîù¦¾ŸÚþŽe’}ó\Û˜ò÷¿i[ë,iúËò¿ië§1üw×cFnŒ‰˜HŽÜÊ)„š”¡B»©Tš!¢¸3}yOyfÍÊXÑFU>Û=>¾ñæøƒF¥E‰ÛŒOdœ\>—¡µm§òP+¯ÌmøuʪÀBx{£6ã„E1ÓR¬¸#·úcà’ƒ/'º“¶¶y=t P'.++™Ø=1 �ߊ>dÚ+¾Õ<,¼ü-— äC»/ý¨c ÒDÌ—D€,R— ¯õ«Â¹¨Lª8øߌ* 1uQ8ò³,ËàgòþÖT)JÝtáz�÷Eð˜¥çÛQ­¨ü(!usé�êf¸Lº"E`Zœß¢7ô Q#¹|RYo»ºàtw ȧæZÿxÛ·úÛ˜ï<]÷å®ÀP!fLÔÊEhÀ$¼Ò:8z'}¶üÊ`/^Þ¹Û_€›cÌcž8’¡´q3ù]ÒÊ<s̈DNÇ€F(.ôiÁoãØ•àßGöoxžÀóŽ�ÈãßÑÑa �eÊîÔTN´Z×X"¥¶È;¬¼ÕP‘lè9Õ,J�Ïiô7F‘ç½x ãå£7{ZѹN¯ƒ+Ü‘ÑgËS°ÌP“~DÀyv¤äÇ?à9|Á_ÊÈ.çþô…ÔúwMO�+Ô_,;Su%nÔ)Põ,ÓO™R‘mÅ¥úÚúŠtóË .-‡ÜɈ™3¥÷�”ŒÞa§×å‚]§n-" ·Ëß„m€œqÀðDäcÖiCcœ—á-én �HÃpNà5&†�0î=ð ÅAÚ/fÈ^ò¿îcSø~ 3ZŒÝDÌ>Öù´ºœ\èfÁ|gŒßŸÅ<%�¿Öñ.eŽžð¦HVùMÛoêm#iÏ÷w°,†3¨ú·×&o.Ý}uq 8£[×zÔ ¸§ñPãÖµ±µn,ø¶ Þg�‹D.£ŒVO‡¤µÑv(üó­=r?¿u”öÒñ†¢ n4ʺÐ2SáL�¹Ò�� ‰®zi`#jbÞ÷ðÒ]ưp¤1Â8Æè] 4è "Ìb­uÀÓöåÅ–¸å8Ãp:N†£»´<êˆ3Mòì±Ò2üJØ*�‘ÚÓqΙ^1¦!Žf‘ÆJ@!?×qj§§c´qX^]Xx„KyïõáÌHþ—Li6Ћ»iÞáy.,Y×fÞ׸˚f—ö;Õ7øø¯/ž õ›kŸô×^­Ïþ÷`~œ4¤Ê�¹n€�¶/¾�‚ Ž3%½f>+Nœ ±VÅ>ôõ¨Œ‘6ìp €P‚C(§°µ^˜MãH%cr;32�Â(§G¼cµB|R3Á…„×3Ôèa7Ý~"IrÖ¥FùÀr¡hcm„*áÈÒn4†Óã_d’­£,á ób?†¼ø‘©æo&F""0Ñ–7|,\-Û$ž<û[ý !“ˆSmà¿cÔ*pêÓu;·pŸðiÈÐ0Ì ébã”÷H¼Õ-÷Æ t´›ÍUÔò Û.ãß‹gùë±µ¯w¼“«A¥Ç)÷—÷gÏŽeUz#DîH¤„ˆW?kŽ-åôó":¬�Ò#qm%ôTävþ6„p\,4À-Fóý£8¼vJì/,�y5ãÚê1¬ß½êË[Ñ¢ X�öÓ‚žË€›ß‡�Î�×Y‹3'lN0Kzm…'ä|�0wL·v •�©ˆxÉ y�næÝÏc1¿ò Õáuàð!�JŸR†Ÿ¸.kCä‘‹ŒÔÎ{qøR0Ê1K´5Ök8ca?lÈN…˜[t0útLsÌ4ÜSF1À…n+£¿'L/%û�j s*¿_ÎIß)�sؘ™«—ç$Þc Œf;ªÃ2gÆöás¶½PéLFÀ�è^J�W¤‘*"ùI• MøG±ïO�%àÛ€%‚ "³ž²³0s'„ñÔ™ï.8`?x,¯;ª½FžÀm8ã®á×ÈyèȺf©ѽŽRžKõ_ ìâÄéqðbÍ5~ÉwMFI)A®Ü=ëBl:e4ëESa‘ùB2ç–¤¦½Š©Óu¯¯ŽWKæéÎgÄÕ0TªwÏ�z³H ×:¯kW=s°{ÐÄ’²*”Œ‹Q³†¤p�5’ÿr,³ÜœÄu”£îFY;O‹Ý'w‚fã ”GõÍJç‚xÙ´ø/¾–¤£í‚¢¥Ã âNËQP{í"4v¾ø}Óq|“ù=CÿEãÄ7õ†x1\x{Í㤉Ø )8Xñ›c?ÉS644Zd[ü¦~ÜãžN¿Üͱ[Îa™ÒÊòÕò¶Û·ehü0¦œãÑʺ·ù=i¬áÒv†èºJ÷Zg¡‚ô)péü/¾±­S«8«å˜ëäÚzz7V4'tw}ŽÆË΄}‹šÀ,¿“ÛRÄho¨oml¬æFÞVáQtY7À\ª»ïï΋—›Û8;<Ñl¹¹ÕáRÚ+šß¸;MÛØõ÷Æá‡]`ßéÍŠoÝrù0ÐJÛ N•Ž–NßM  ny2N¶—U«ß^ÿÍ;ßÕóS™•ÙïC­KÇøÁÝ �ý]}öXÿ·®ŸÚºƒ}a ¿¨ãwm=íßÛap!â ïÞ-à,êé…wʯ`䣿^rQÓI=f<2Ò‘¿¹�´@E�ޱ·;SŸ4o+Ç@):ŽÞކ4–¡™�¼hºT$‚iàQ!’ÌQ®1‰Ä)í@„ÖÝeÜJ¬N�l�еETf Í�Ïûýg™ÅÌVåWå‰*zõlŸ@„5ÓÂh yÏ>õ[YñR�JDC/Iheü÷ú{ýFYc9 ýªf]ê½Ô�ýž–Q: 9wµSYЩx¯¯o;?•ÆŽê< SÒîêýv˜ŽŠ7]¬Ø¿©äÅÄÍwÅ1Àè´$â�B««Khú³å¦6|󎼻(pù ÄÈ’ewV0ƒ¢9£ÜÒXwXn!$ý±]ÉŽº>Âe—ñ®™~™¶W1Õ‡-ß‘÷ºoKã›àîûÄ”ÄCÃM¢¢²@)½ê)'ˆ§ÀcÂ_3û›ÏÃOÔ¬OÖê£�Óˆp†c Ç>ҧǘ›#¢ŸàEÛ16#Î(ÀÀ9¯Ãë0Þ0rÏr–ÆS‡Ð˜ÕüNýn†Ã‚FbZçüNö29¬7dXl4ö®(‹ÒØë†9½ŸU˜]ÏÇŠVÄ65,ƬEŠw½È´e–ót Ø1âŒ0:mâ°0ø�ƒ÷�øq€qFÍs—Eq>޽vZ:©©¹¼hðª€pœÝ ¸,�:¾/Ú¥Sàù«¶Üt¥–�àS¶[,è‡ÎB+ç@ó4²uA{ʨR‘™¦}$,Þ}÷èÓÃBËãä鈬rdÃ5žÉZ-wÐØEÙ•ð†˜yÒ IDATÄáÖ‹8tûÈ÷ûî‰:„Ó¯h–F<4—ž±‹„…±õ,ÐÑ®A#=X Á½Òêó½c`7¬k¤t•Aʺ›ºµ¾wÆü6$®äòîº:öë»ghÒÕ†hÍ­6¶ÂÀmn8ÚàåóuG"eÍŠ“r Œ±ø¾»gýëŸÔC†uvÍÍ€Ånv�j”Ö1Š6‚]õ& ú^ Ð [ËÏ‚{C9 ¶ç«S@œÞuÊLGéV)OJ~rB´X<`ÎÄ_�ùD:þÎ9a¯„áXñ˜¡Mc:NYgÍŒ¦�çBÝÏS(²o“¡Ô2ÅÔmF–ªr^�.Á×9ä½ÿNñ¬z+�m¤ö¢÷ØåñL FGˆìõ[·„«ÏA³ÂO�j@§u�1°”­ä»LAHÞ2X·‘ V­*à2¡Œ �ƒiY^¾“HCFçOþäñ¡ËsGƒÇÚbX;8ÿÜ«m—�̰‡NH92]哌I²së> ž²„Åd­c°r(æ�D¬G�]\Ưo–S­ O³±ÿ¢Ó¼sÜO#ÙH_¸\®•­w±ße ûÑú[è5qJùïÇ"q8p¸u:¡‚ƒÔË!ýÏ糨ÈöÚpw]¶€2T� 5¶¾S “ÆYéQf¸eêʨƒ‡�÷§“�ï�Ö2~Ñ#û—7Ø7 Þ÷ùwœ)kªy÷ ÊÓ ØÖñel MkM® 4G´àIüí�À?λ¢£[·4þyݰ¼Çõ©!uóžs¾Aqì[nhû²þÖ¶ùž•ú’z¿iCf Œ²™ Rƒ|o(ØÞÇÛ¥z“þP§^F{„ê �ö�Ù'�ASשîP„"éï›EãŰóÃ… ¼wñSùQ¨è»Ö„§ûöhé½A½Fõg.ütüèü¸\ ’¶{¢~[Ë÷Ïe>n÷ÞPÜÍÛ{©t‚]ý®Gß?Ø/³ ïûûžöº´o0r[e¾ý üí Q+£þÕ~J|Ñø‡#z:äcj50�¡L验&G°bza�¥BÑDëE³¡°tš†¶½×…g ‡™0pÛªsºwI¦8މ1NH¨•J�¦ö±” ƒ[t¥UN™cYwcÜ�—q” ð:­™ ‚*П±ñ‘ÙJ^KPùÜ\!sº­æ™½ìºÈ.÷¦&ëò«Pjœî‚eíüÆt%}„»Gj§9#ÅO ‰„3�AËw…hÚZÿÒ®]q“ïpѹª[pÏê€,6å00”�ç¢ýÎ@é%¹0ÇÈÃJ­wÔÐIÀ9™/ÝlÃá6`”¢L³ï`)\îÌ3ËëÎCZiI+^í¹~/Ò¾0·2Iµžò›ôDI}FûÍ€ù?$ #yÃ’lai&zjEšuÜí¸Héï®ß ¹]P^ëõåùÚeÖmoS$hÌz±Î1%NÕAp$n^< –Ë£hÔ0ÇÀ<¼,w XDâÁ"Õ–{ìàšäÏÉã·;¡¼ÏÄh¤ÆÑ¼÷LjHx³–¬F*à8 �Ã0ý0pbàôs+_`-–HoŽd Œ)Ãôtð­L¬ømïÖAØ a�%_ç¢ÜešÔ��œž–» ¬#n½ Î46û,�êsóÚV~æ<ðõñÀ×+R�~_? ÇÜTWt ¿ÓïíçOœ«ñšóJ‡ž ýšß9¹ˆûñj«9~‹ýV±ïùïm[î[ç~®C�íÿf×BE4§ê¡zØb¼÷6Øÿì�¸og‡·y¿ük*7¾©/ù Ó«„1.�*)3ÝW 8 iÍG–UcšW`�êì„U­Qú\‹CÒ2ùþAè,ƒZ1Û¯éF�ÏÀt?ŒàoÕ&ÊìÇ_…·V£f¦ç›ýa�3×=ÙÆHaàµS@�s¬;à7Œhä³’b¨ðC¦2td{¬[Æ�ÆQw¼%&Ž–IŽNåjXð“ –Œªx Gî^칦s èÈÈfÕžãâä6WÑ#2«tý|JÁÌöH*Ö¼Šá2Oâ ”1¯<ûRmfù‘g�ÔcGfÙvd‰ÊTr–Î ‘#å< ;Ûç/ÇOàM ê5�lµ±×;§{µ#ÑÙ�‡M­2J}´˜|ŠaŸ¶€¬ï×ÊÎ=qãðŠü‰v#«ôÙ~)�߉Gë:)£Q†_@w•Ðé3s�:Lh¿ÆÅsþIŸE¨Q‘Κ�"ÿVz\ºâÍÇ£¨o,»�\½\_WœòÓ'†�š7î�†Œ4xwu0.}]aîr®�1û·Ð:aò‚�°ªcdõt (=–ñ˜�1dM…‹<KÚ¹ÈçÉ_H+)£¼ætóHÁÀ¢Ü,»2�©ôk~70‚/AG‡áB EŸìxÓiÁb2 Ö|À IÞ´®Drct¿4,xì?oø«Ò6üæ9Pk€ýñÎÖMÕ Q _�ñ…s©g�Éûoâ`i8 k¿öÀ²KšWÁa ¤¶©´�²7ÒÅ6:a„ç¯|_iÕV.×*1¿oxƒõ¿¾Þôñͳ’ï·p}W—–[k{ý¦Î»wîÚ}wïßÖÿn~^&ØVîçvÊ1à¦~Úݼ à–‹swÐöíÓ0-<èÓ-">dUMáWóM&¯Ž+_Ÿ³e¢[oq¬…¥OÌ9âÛWÅ#š£Q«ëÿÿĽۖä:Ž%¸AÉ<²zõÿèÌ<Ô:a"æØÀ&%óðȬ^­s,Ì\¢HÄ�H2‹¯ñ•N×ã‚é ¥ƒQ÷Í—• ¦°%p¦ŽêééD ëÙf çÂÉ~ÊL–35Œ­-�{§©ºµ%#¼Ú]ÜÛ¼1Ç Îír —�$KšAoÁ�õ7_]~EVÞL‹~fÕy%{Vwÿd¹…5”ÿ² $Í™D…?rbYO{+WMÌÛriéÐ`0†—¢·ÈÉÁ±v°®+ÚËÍ'ŠÜEÐ'n¸EOhe³âU±ãÁ¶\'�¥L[! 7Í,`�>ºÏDRNÈéäÏ € ä~,ˆÀ{P`(.ŠX?œºkþY´¶„P¤6¯pª [ÍN>oÕóàæñ.ʤd@cÃÄ™i‘úuX®~6DvcNX�‘ã}pEæz8<óB¯›!Ý‘t™Ž¢rô¦!a¬óøÉUça8ŽÁ€° ¤ƒÅM–S§2¢ÓÊ# à° jäxõ‰']�à ¹Î”‹1²F{ö'ÇŒÛÒÕ¹ r>hˆQ>4¸O  ´Ûí7Hqd~80äB»Ü²bxõáI]·^ZÛ#ßå¬ÞäªÊâ³ÂW‘ª Ä÷HÙ}"ÄnüS‚‡²”Îó´LÚŽ¥£VùÄmêxÏ&–Tv…N¦ãHgVð£û�lß BÉèÀS~j¥€‡�Äöét˜à™0Å)’N‡a¹JÒÊIôåÑ«÷åx_±U×{ÖtïËs+*_z3ÿöed)¤×axº4£¼D~:õzìˆû}âÑAìggU?[dœõ3–þäLDìÊim멎ýþ=;þÞ–ë½0”÷Ÿ3þ›v¬{ ÞuÜ<—LËq³÷ ´Uæ¡K#ë|ÈÂÞ†½a@Õ¯ýÛÓåXƒÌöœÖWŽ�„Ϫ~Ô–ks4Ûq›–˜û²Ò`o§ãéÊ�åJšž~cR‡¥-XsÜé€ôAõQ¶›»ãš�‹1"(m(S?F8áÐ…1ÆF;Ÿ£V+�<,9¶®™·±“-¨¤œX"9ÿa™Xù5`63¨Úåûßýò þV)÷ú»r@yv6(CÅFFÙ{´åœ«Ãú�õ‚I^ªwª7¤£u.YùV©‡-í‚ζ_é|zz<Ñ´¼~Cø××çò·• +WQcà8'¦�V�+F¸m̰X]Ïí®ø¼0«í�ãÔð•Ôò‚�s‰[€ßÛäëéÀ%IE:?W™Ô¹7tœös'ü$•ìl˜DÔ>øÏeÜæ+Oêül§ÖOº©à¯ï½œ—L-œ—3ψ"® G;I&„�2uë_<ÞLy”ì*øippÌ…¶»ÎY¿j¸ŠZF��×±ðv�§Ÿz_+K"¬©Ânóºúu@º|õÀ‘´DÖþ4}6‚IÝyM�yô'dlð¡áa|]Ç}­Íõ‡ÈæÒ÷SøÃcÞÍ4²’jK–KÊ¿�å»g�}(ºÚT­ÿ¸Âvkã98ð Îîãý®-¿ö7øü3tOm)Ó=]Ÿž}÷Î^§þý§öºþ;§6üçÌÉ� ÔRÙ²‡ Hk4¶/à’.áበ¥°[…¦P÷Èv`dý>$<@P 4*½04¸b`HßÕè]•Fç*L¼š—O\³¬�pêœÇΫ¶8ò½ÃÊáT�[ÕüLôµbÀ$˺¬‡{y­Æ>�µþàžýHïÛjm4�Ýú³v¿l¹³JkˆDR÷²ñgï~TºïíÖQdƒÔ:ræÃþx�9�Âc„‘èÑJ¹�p¶6mT®º8…¤!�yFçûÈÂÅnóR îžY?ÈÌŸ‘¿-e\Æø„S[P i­ÎdŽýÔì¤eììa¬ƒ§oÓ®o/è(Ô=ÑéW4šPcb«Ÿ“QÚË·Z]–xH‡‘iDê�ØÿðzÖ³[ƒzåøK@2ãn³¤·ÎÑ™¶«…Ÿ(ÁŸ_«¢yné¹Õ�Æ.“²È’«Ä¡…·åJÙtx¬8 Çá±MÁø±²à²ø{Lø;ŸÏœF˜á=Ž%åg´‚wN6ì´ 4Ì s¾C|É šãˆƒˆß§vÂæóíÎ/G<³ö.p"Ä3iiÓ‘©3Èëãt\—cà±=ÃÌó-f®<#‚IB .ÙwðZ ÀIˆå¾zs^ðç8À½3SW¢èÑv!³ä£�‡‡ì9ÌÂÁp騭2– õ%ÅërSFÅ» $=±Ó “Q䌮N²�ÅÃiTÛ^l“H’•ÃhEVÊUD ©·ÌqñÔ�Πφ“ÍGœÀµü më@©C¼hqæŒaóèd–6J¯z<Žçyb'ŽãÄ8ãØŒ/Øñ>Þ°´ýžçå8®,l‰W˜ê¨²=ñ …Åê nDܤÝRîùR<9Ù5뙯)ÆÏµ> 6•#Kii¯£ôVg�’¸É³=Ãogíy| ,<9¨–~ 5�c©ã'xg¹=ÚËI†Î@.ºVÜ�0Í0ç¬à€!¤ã>žkà;Õ]”i–ì[{r§ü¼™� ïô¸ ²ÈÆžüÒ¥ö+Ÿ]266èˆM�a#²»½ëã™Ì�ØíHWC¶…i‡X:uù£îÕ» #«œ«ÈTÅ7:ÑèÁÉùD3t°Rǂщ뚸®+Ëe¿�l_-r"Þª?XžéøRŽ'² w~óÀ5i¡¦ f˜éœ¼“ÏlbE›S³“Ò#ÔLË5ƒø~›žÞ»Lˆl7®Z€¿Å·è! udÁwûÚOj»:ØèqGé•zZÝ]:«Né¶uˆlÁ%VêÅÂ�Œ¥:µÈ¯ÙHNl÷²â(�´©±Š’�@ë~•Ê׺uÅí¹›á#ÐLutù½¼·Éá"yù›„³˜<ɧ lŸÉÛq»ƒ“¤¯‘º~ FŒÙ¹ï"»aÖ9o‚Î/+RÃúehnÛ™f�ܪjÅ…Ásk«Ò ó*ûµÆÙzõ c•þ¢‘þ•�K¢¦hWyU( ð‘ÀFûËÚÈq•ƒŽ ØŒÚ�q$“Èe EœCâ‰jò% [±ìHâðÄ­• k5ÖüoWfŸ¦»*§8ö /®t¹ç9§¯ðŠvÖèÚiLð\¬ã]„:ºdĆCÛon›³§›ÛE v;^oÍ×Ë8³Š•—ÆwæÖŽ,´° � fâefÉ=)’02OAW:`bÒ¢˜Ò˜èÈÅÞºÈ廬[ îãcû³¦F@5}\Å{úr·üçºóÎÿ¹vþô÷Žƒ?áè;æxjão¯'ÛÛü {™Oøî{µb€Î}.(GžM˜�p´xfÖx3€;íÖ§Z çéA�•®ÊÀ3 6YÇ Ïr²ÒF8ñ4§E„Ù{ÒRÆäŒû²ÝÐ{^x_›.£çĘ3·Ø8P»¤Šñ\i'ãàtb8dO3k‰—0–ÃÄúC¥ó$ß–Ëä%ð1eŒ©žüAø} $�/ÚLà­{VÏ–š8)ФI/eølQÒŽŽaâÒf½²I'U)[3ô^&âQ…à-ÏãoŽë íJtƒ‡@•3ÊøâÄ0¶…8ŽQ«�åœÀ›­2Û½öÕß{)þeØ÷ëƒÌ)ã‰}_öì^rcº�¢+Þβ¢?–HzâÏK9®.[Ê|¢+Cïÿo²-Pìˆß~8=c䪂ÑïW` #sËZÒÛ›KPy ,H]¯'£ãc­æ{þÑHy»´eú-Søštäßt¬ú�À2(ØÛà‡çüðÛ›{ü¦ Ëm}ŠÆ©D< —Ùäî›WòiLO#00´‘NÀ1+0€9Á=¦ƒót „’�V#:ÛÌ^â(¼µ ©ùªöÚLÜÀ[öXë« 夣£|ÕuáÈòâ×àãÚ¿ –“öXIÂ@ªò8·J…ÅööOÑo¼?Fr• …x¾°ô½’®8Ï¥~ôø©“Ud/ÇÃj\P´t8k1–û„Oòoêërûˆã8BgœÎ׉þ0`ã‚Wì7à¿q]¿ñ¾.ü~OœrEAŽ_Š>D\oHMšÝ$J£Û >–æ%êèEÇt«Óºƒ.�[•ǪŸ„æUOI½+°?™ü¹d§ì/óÞG•º Ø{Ð!¿EþkW˜\“wéZ“ûƒÛ$÷O}\•Ìú"¬“gª Û(Gÿ¦@ò¥Ê*CèÉ8�2õñ~Ø¥'[µœ{¶Þ3æÐ}ßQ‡«)™Ò™µ TþËLù—~»’]µb8õ‰�Q]tľÿ• šaß‡È &*‰�öN¦=kdŒQã[‡Å™4 �…HL)ÄéX÷ÖN@؈qŸ‰Iˆ+0 -»¬ð.$+¼N�U ×5q½W8(aõ¾áêúþê?hÃóÍpŠ&g¨×ÖBì:Í¿Á":a¨{ÍOÝþ*Ï£> y ³OGŽŽ@§IXÎwm[åÛh~ðRm t; Qøñz?e¿¨ÕÉùÅ´��’�ÎŽ¯wZ¥ÕÑÎv;¶3®ï|OÙX��š¬ýéùô:6Ù;1=‰oä|<óO¨ –ª5à+¯‰n]h!a™BsëÓ:k»öm£tÎMøK :Ë›ª¥ÊSˆ-”3«÷+’_žÈUä æœ™écÕ©ÅÛ·\;“¢=§=E­çÚ^‰Ÿ#=è$ò€›Á¦¬ïÉ%¿§úk²ÎƒÃå$ú< ×qñÜv´Ë™Í�ðýxwb�Ÿ5åzw¿§³3ÎIð£éÚ½’ùÜÅ‚,¾àß«…üÎr ³”)ÃÈÄ£'; .S]kÝÒ xÉ ²°ºV S»ÍuWH1–CxÚP6]çŠ6|©›Ïx6ÝDÈ~-êÀîõWgHWøIó·.QôkõÓú�=‘? tÿ±ë)£ �´cR´îXQö¡ZاЖ2úµ q÷Ýʾú¿ä<6ûd�Dʼn9Ò*¼ü@œnð?] ØçrŠ�?•ýØÆ®j|?Õåò¯-¿žßr0�ØKY]~òŸ¯]ÏíD÷ùïêÍž0¥ÇÏðžõŽðpýáä9¶™KäÓŸÉeŸeÜa„ÁY“`^È¥oAŒå»`¦¨sŒ<ð‹Û2X m&3sÚHƒÇ– 61Òúîì† Zdd�YsRÙ¶ÎŒ• –[�ѹÇ6Â)IçX¶å­QZÀS¸¤åæÜÆåðö[·ìŽï\ÿ´s»–ÆÕ’QœììX�ìEµuL⢔žTQ CYõeê<@ØÅñÄ+^±Ös>¤‘¦k2�$–À®{� Tj³V¹WmôïË�b»OÂÀ ÎȱÍçà ¯y`Ìθš×UÙiAË#=†óå°#¤‡�ÚktF*M,�?¬¶Ã1£|±PE:#m-˜WÆ·þ.c/êàÁ—¨�ÉÊïRª—–Ó Ž^ùÂ1HÔÖ2Ƥ“tF¸µ³²”¸!�¡%C82ÇÏSgíìD;ýƒ øibðjörF�»bØ&â˳EX*#(žm)ûòìãñT~­3FLa»[»:X`3}rIÉ'å™Å;\z[8;-ª™|9ð Ào‡ÿvà øûÞ{WûÀ�#Rìã ‚ü€Ž¸½f:Ks“öÃÎax Ãë˜ø:.|�o|×y׳‡q «ÅvBÍî¡—|¾á~ÅŽYÓñ6Ã5�ëˆýqßÈ5’��æp¬#³î�̼ŸWÂzmrû"/K`ÚÁ­¦õj…AžÒW§ñ)ë'&Lv˲ ZžK2×ã2jÉñŒÃ†‡ã5¯\aÖ°+Æ*JRúìÌ0Ëm‹îð¦Ó¦œÔFš‹Ì=d¦…±£'ÑÌÀµÔ©µGuŽ;êÄC:n‡!d°QïYã0;#Óg1Æ|…wdÔë ¤3_=aÜøÓÂiºŒr.ñ•zɯXU2g$H´À.½”ËÊâÐÆ ^ÉÑßÌ´ƒãË€¯Zé1ð…‰ÿÿkÿûøÏ�ÿu ü?Ç…_6ñÿÙ…/Lü÷oàŸëÂïixgÀ/ôL¸]Ó‚@ Þr0 –‰ò�MVyË+!e3}åÐàT¬vÑRðË3nQТ oÚ{+ýuЧ–Yà•%^´C§$ìw™Oç·m÷ZPzÚx¤ úŠ3`«¸ÕZ‚N]ä÷úº?þ~ÌÏ·}ÁÑ]ÞsüËiפ_í/ bÞ3L1½Ê‡cbCS"¥œñ ðÞÔ‚AÃ)ï3œ¢!ÌÎv ÌTWCz¹8?Ëyma7ÔØX™ˆ—.·^ÉåܳŸŽËf»�ZÑài“_ÞÁØæl+{6Ò™&ì8jE3“˜ÌÂÁ,Óò)õPÓ£Áp$mÇœ –-šÁ/‹�i»Â2Û:Î ˜³W%´)œóžé¸®Hˆb` ú> NŽ­Í+s`\x+µfö£Wkèöf$—eû ?SÖ‹3nXÌ'RGðèöé¶O–”äÄáLšÝËl¦åF™ýÞLûÚn%¶Eo^#ßø\2·"*û€ØvwŒ\ysä9GÁZÒBy>E÷á§Ð‰–¹XàS)~Xt¥ÌQ–Í¢�˜Ïßùûö«T¶á*YL¸²‡ ¾B€ê‹3YÅiCÞðnXäR÷e²°äh~àº�£ž…Ù!Aîü›}tC^©'Ãm_íÒæ�r UÎŤùÚ¢’ßz¿ôJü]æ�â¢ռȮgÖ €Nè!ÅÛ8y®’eF=Q¥ê4¸ÙÀóÅLèP§ð=–|)×ç(ýbU'p¤7.‰\‡iáþIœó¢¿¤ÇrñiqÈËVi¾TÛ£õcãš Ð N¼±-ÚÁ]og“{á’ãC³vÈ8qŒKG«ªü¬RK?I†H>’Èv,W… Â\}€œ§[w¼E}j›ëP!H ÓU$žLKU·È‹þô̳: ´ëjd¶éH"¥àuô'^3 °‘Už¶XiÂû¨/²¾Æ{)L©–mlro—�¦[biÜÑܘ˜ª+·ëüê”eÞÚb¿·wu'˜'Dô½Ï5>]J5~3ZЈÊ^—ÊÊžµßÎDóÇ÷êÝ»úèƒúw¯Õ6zîÓw÷YÇóuièI¤ˆ´Ù¯y%fÀ•LKÅÐ ¡£'éPá‘|Õô{àI©4>ʹǬÔží63–”n"sïhî_qFËJY¹çÁNÝ?òcøä-²7øpZ:>“¡ÎÄÉè.ûˆJ<÷‘/÷™ÎXï=†/”<&`™aé$í(dŒàÕ¶‘ŠB TÆ=$íl[&­T+Eت48 ôCy¾“•hxÙ¢ÌØŸBp~d^_•ZE)›¿\3ö‡ž»F×QkNñ`}™JЀm[ã’tNN¬C:�ט†—8.àº.Œ·ã‚ãòîŸvàÎÓp¾ìDÔU8‹Ïe¨¬e–ëÜRhô^å‹þKú)ÎT¥¬ýî!nÚ囎šàÕ ªÃ_Æ´ª6*®¤?Ý k‚Ñ´EG.oCb· §>¼³˜yGimæp9ì�GÚÛðs`þ2øëH¸)+Ò«"5å IDAT!�•£@éNî×®a ø‡¿õþ…Õ)¿¿÷]û0î0´ãsUJä}O�Q Ý'üèa­–¤Ÿã:Ä(`U—Çaß¿sÛ úÌü´ãß'0æ�×üŽ+þ®ßŽ‹åI+“$¿&€#`ô‡YÄ%dPø:/¼Î‰wn3[DýI§_ˆ�Ìμ.øuáJÇíûŠ`ÀÛ×$ty¬¾žŒƒN3œcÔa°c†uö·£VD”ÐóðdÏ "àˆ-�–ÑÑÍr)ç}€[U¤o~§1ë?䇙÷b"êLL.ûÍŸ‡ãu:Î1qŒ 6 “«;€Ö¥)ŒÌGËERÅžr³z ¢p-ÛBü¶ ±ÝX„ÎéVPæP�êPÐíå@Nj)޽¥—à ”Z@¹æ­ïº#¼hrÏÜYê 4aްăQ]ÉÔ>�Ëá0ßqÎFÄ5øÜ©òk¥'Ü—¿Û .M60ñÀ¿†W`ê2Çu8þ9�¾þ÷yà¿Æ…_¼üÂéoœÁ¡ÒT|KZV,‚–N,Cçx‡ ¥$å NÐÚ1�� Ìø�Ùpàj‰œôW^ ��îW:º®Å äîµzsuÔ§³HÔm×$ÿ“ta›NÐZH~rHø·WËcfTCêhØ$›o��JË’Wå­·v{ãq…À({ϱe¢*Ì@¯ ImS|Âz…ëíøoxRBÊË5 ±a‡uÞ‚+´Z:p3ÅùNj礈9–°Y‰›T]‹vó¥ï®7Ëæ¿�ÛÐ]11Ÿˆ„Žà{:Éé¸ê,÷‘´?lí÷DÈx˜I[uV�dˆ/ò4!§SØp®€·Þ–ñ� XÊ—žÓP§´ã�ÛÍœwÄBýáÊ7Ãg­N€;�d« 0,ã-‡‹­ƒê$ƒ †¤kùJ©:Ù:‰%·í󤢨vv�•ñ= oÆÇbç²&< H-úPmâµÕ…»`J“Úˆ¥r0Ž˜× v¿õ" Æd«ÙA=w 3êÕ’[NúÌUÍQýìe@Á›b"YïmŸóó�b“/o¶ƒÈ9K½BtQ-Ùò�ðeI&l—oxXÇ¥åqô4})½©1ì�õeA4a¥W2Žx�±lA‹¶%{åUÕ?_É×õWž‡§¸ZÆSÇժݻ~1ZD�Ø4Ä]|kïÜ5‹mA™p A�Ë{j^Ú£VægÐdiÏC ‚Ð/>ñäÀQƒ^Û¡ùRdQ Å©b+ŽáÒm,c>ÌDnµn¥ì©3ÃXÙËš â²"À*•¾°Å‡3¥ ´¿n¶¿I豪¸ £ìKÛŽç~À,ù»µ Bô£~ƒÑûùØ�ûér—J�>¡\ú-}¼ µï&ÿØ" iŠÝêá@BÚŸæ£Å‰»D*÷NÊÜH ù–�ì¼xÕÑûG™2vü,Ý(y–ý©`‰Õáè!›¤Ÿ%ÿøpœÕß!Ÿ[Gn¿ŸjYa÷åî÷ןK¬í?µCNeBÛ.Ÿÿ¾û\¦‚€zá æÇe,lº-–Ÿ]Zö[ûðî§¶¾{œa#R¸oìSÂ>î}ÐÉçM‰ŠfŒ xJ|n!h‘Ɔ¥¸Ü­"ûe`›ÈÒ<�[~%аöþ….)C¥1oˆhkJêÎF¶e¬[^Xã–Y7ÆbßhXÑ &R¼œ-‹¤M ° ¹n†uºÆœÆZjPm­†“´Å�‰M ³+KPIÿUûhp  ÙTŒ¤³b=·˜øg:Œ_±b€“®ô“éAºmÐ�%Zû‹†Óì‹¢Mö8s4MÁ"ÍüˆÖ•4˜™ìsFÚÈvZdÿ3 ydôžô8rœr›;Æ‘“œ¤-V�{&”ÑêΠÒñáWL´[åÅJC4veV´#B´hh±°hˆy�·;*ó–MÍY·ãÂCžäVò a=[ ;v èju°T5î-×ÖK *Õïe¿Þö-^ï÷WãÛÓïĽVE÷üÖÒñ#|O¯S^„7�)€ã@bÏÕ›Æu× ».àŒ`¯½ ×ï7ðû‚¿7ã%¯áô8àqlÄax�¯sàëx_á@7~²ãÀqž°ãAéy]¸æ„Ï^ŽÇï·ã¸âó¾€q!¿#¸í)k‡qûÔÊ5ͺÚÑVYm˜¹Osãn¤ž#rËpÕ™j鸞ü«Œ7³� Ã3HGèÊ›P‡Å>óÇ�:Û„ºÑÉ–mÛNÉ[k…°£A—"/¯iq1õ®�ŽVR¥`¢RάÐr œ�ò qΞ I5^cÁúÞp„œÀ�È*`¢€±  šf]¬É[.ºF²rÑNá�ÎV÷á¹�ÇL9”«ê(”S3ä™ñ ²Ã0NônÜN¸�Àñv¾�ÿžðÿöØÊëíðiµð§¤ �@nsÐÆ1rŒ=zI�õÿ Y©–8rGº¼’†\.+jÊè- Ô&ú´�Î~±ü“¬\I´ º'r­vûN¬ßúp¿ç5qãß?‘Þ+�xÙAŸßý/ü›äg¼¥M#ÆŽB1’6W|¤ÌJÉ?˜¬�ºÃ .5â€o}Õù­Ë}Cœùå’òM§‹†õWìQFµ€YLžÅDry'÷ Þh.ÐAìy¥Ééqv [ÉEÃÅß-±èµe.Q2�6O†jò™:ëC™­%FdÈ–± ZdÐ ½T2.Ë\yÿÊ�#ç…¹À 3èMôy®¶Ña§E¯©�Ø¡Cíî‰0àªUGf�ÂÕô v*õRÒn;K×vFÖß}ìömùÆb[Õ¨ûJÇ]Þ¶{$ê@€îO_��ÄÇLÇ4·D ›c³ê|m³¶’™}ŽÆÂT�¤*åLbÕ<ëãœ/u®íïS. ý„ú"�à›Ku8ÿ.mT�É´Mô©ƒˆW=&uî}ÞÛüðHoS§[��—]Ñ ¶¶ç§y?ñ&ÒMtMüRHö1ÿRžÝ±ö|Ý΄<96ìŽÈËq«1]ð}�D€d¹¾àa¤ÓIͳKe•³d9ýO:È3ÆzÒª«×¹ê÷g}è¹™È+þNy¢~'²ŸfÛN[ó)¹‡÷è(™My™‚É|æ!Ê�« ±–­AVö•%_ÓgT¶ÀîþŽ0Tá9k›Øˆ3 wã0˜„ÛÁÅÔô¤y–¬j¯›Ý -$²Ù«Ë8Ùöéâ†íÝ?tx-UR3Çš+WÙv@m�‘o·N¨/Ÿx)">éÕ?Ñ4™"oÓý¦oA(Žbî]´©¶PÀr-ÇLÞ³…�¥Ežví[3nã¥Ëòd’j‡ öÖÇþ­þsÕÏïìí&ï)îË»”~¢¢ý½]¿×þ‡û¶ïÀÎ'ýºøV?Áxõ»*rÅ€V­Öå#¼Öe]Ý´QÖS™T•±��‘Ë&àÜÒbëÈ~dòxgn[@óÛùØ'zïèXE”¤èŒ¦º¤?*ËŠWú¾-÷’XE`8=\>�\}°9µk"Ïz”Io̪x $èO;;zRòDê³’»]‰\„ lÞ¨ˆÉF §’Œ°8qÄÀg[ðkÂ.À51•N÷u¥Àn,.š+|{¦zÂä§‹yX-³íB:ýãûšc^¹¥ý8óý#•’EV\­KKÏ�±:¬|Dœ àzg‚úƒð{Ô4¾Ýþ,cVþUzkÞ•ÐÖ†Ò�£êƒ¤þ Ån£dJ‘·å��ÜR%ƒC?»ãgcP³ÂIÎÿàúT¿mÏö¿ÿg[û\~ÇÍ|F=xhx¯x¢üš0Ïܳ'ÇÁ€Ü7"÷…%(9É@L0Ιœãò ¼ _ï_¯#÷Q¿‚–†a^¯Î×+t[#Ì+ÏÞï ïkbŽã=12(0Þ€ ÇéñÖ/rœEþ¬W¨ â[„ÐE#†ŸÅ�Î!àD·™““quþ¨X�+‰F,ŽŽqX W ‘Eð dÏ`ÀŒã~¬e¥Þå&ï³Ïµ´7Š MÃi Ä Æø¢Xªž‚B?@ëv¶×Ë%V] ƒaŠóÊËhd±ì"m‹iµ„ºÔÎ §zÈXYë ®a0ZÓtf€[TE.IdÍçØ’ö©ó�ùóFúã…±æ<ƒ_Ý c×`œ¿€ã7|œðãøñs¼1qÅê5Ÿ¸Õv'h ”¾vR-“4Ò6+Û�25Àº–¶å1.}ç€5ö½ëÎ$�¸=kOâ¦#[~ï€={¶m[ÊwÖ\ˆoòŸöŒŽáÃõYmTï×úþÍëÓêýÞïïï ,h@äÉõ`EÄ�X‚d_v5µÈ籋¿õÛªž€£›P“-dSg϶3£�ò·.ªá�/l+ue[8¤êàN±uDÀjÎ^è\Árޱ±ÍlõÚs Èf﹋â+ÄšU¶û~MŸµeL¿CÉ‚—*_INÑW.Ü«X¸Š‡ÛŸµ Ô)(ñ›£¾Ò�f6Ù·±ç·wŸ‡ÈÁªx£¡b œÃ¹…ž³<ó"”5èXSŸméHÝõ·Ë}/[X~”Lª«„ˆŽè‘¾9¨‡œÁ]õÐ:Ò¦§þŽÔN Ê¿a?uö¾  ”WÕ¹tªçà˜©‹ZŽóÝ�¯uÞ\ýJ|ý̬^ŒšåBé"h¬�t¦�{]®]ú¶I{º™Ï´z1Šv滎²†UÎ=¿=Ûe§ß¿Ë^M¿(ý'0w.uè»cþÔæj�íæï­×÷ ¹d¯ËP~Ù:ç4vÇ�Ù>føGT(ïÝW—~7ª{�þîÚ橵»­ÒbïÙ®ù¾ý§R¢ŒWü#*ûSŒýM[}劇; " ¼•8}£·µ=«ÿÚX¦š²”?SÀSHN‹h뜈mj<În¨d‚ å–hPO—§0¬`ò̬„H×€¾µ¯¨ nk³ý¬VÇ…å,$ ÷j§¢˜ËN$÷!$ªµ²<÷µÈnxsürVÃ-#,… œ�ûKE˯¢�¼+þPéÖ4Nñu§ÎºÒúÐsE€ÏغoG�= pÓ@Þâ!p™�ð ²›UÔQãGL ¡”£ßmÀæ‰1-V¼ ˜¿bUÌagòïš žÁËÀ@~ª=ïïRÎ\¦–cM%pÓ7íÜ:p‚bL¤uW¼x—±ÒÀªQnÅ®·hpÔSž¿+ÃZèÃ;2ÀÌ2UZ?G9 ­Öő޴‚.tüq&óSÁúTΞïßxt/×TŸy'ËÝ'5÷%€nˤÍ{=ß+ ã«4`\~W!Gd|€ÁW¯‡ÿbYë€eæ°ÊgCÿ8à8ç|�†÷kàýuÄ–#2ý1Æa8Ï�óŒ`Ìp Ã;÷ìŸ8Æ…ã�N…›··eoMŽHF¦“åæ�úLÔžÓd©},œ²ǸLDú×î‘£'“/ ^˜°pèŒ<ȼÎ%Qšw F½Ýº�Ð,ýHè,(ÜàÀR7 ðaêÛ¹UDfêv6mÊÝÚš¥‹Ê– ¢-3!n�Ä@'_¹¿¨ÍŒê8Æ):%é[ølãΆZìæ–[:»ÍHù?bì,Ü%5t\]vx�Ñ[lüëäÊà·;Þ\ñ™o\§\]éªß æpºØîx)‘¹Ë©DÀF3Ä_©œ·Š 5®�žüH ‡ÍÿHN¯×pÓwHÕ!¾ý^÷‹ªQ[]dÃrŸ/ñŸçzo�«]‚<8=úç>«ƒééúÔÿ‚ÐÐÎ`^¹ü~Úš} ¸¬ªiGXw¦a_Ÿ]Å«òÏÓ‚,‡j;ŸÍºnàQȱjÞ�ZÄŒPÙ-!eÛ¨=˜ –ÙÚxíåâmÓȸÊ(³ „—ðìË)S¦©“‹m^ÓÕ<Í~{n+Ž'ÍçšyìˆÌð+·›©m›’;S9Ûê°f¾?²MŽà²Bg!u¥§âÔ‹AŽª3‡Ë V¯±4fÄg` ð²ª÷ÆV«’7c§ŽÛÊ‚¯rJu«„«ãeâ¼nÜÆ;þ_uAÑh-ohYG. i ›yx­Õ½@ëûBeâ‘gct`@àɦšJ½êb?;8°�eâ­îÝD°`�Á¬åv­qß—Eò]ÖH­0[ßá¸-sê­•úíìe>t]Z×C%c²ÔÓM|›cm­�2Iu—:Ï×Ö¸ÈÙ­ßÊÆ•¶‘ÙËê?u:w²ÂŠ�}% ëëàðHÆSêvq yöGͽvx€Ö`‚·®ãSPàSàœ[¾¹~W]+î–«æ$CìUÔØ¢8»IìrôØ[Êæ>ÌÕÑŽ‰Ùø³—ÈÕLÔ4ûJ¡-aÿt¥�g3ýZTà¥��ôAPXÚß‹½³8š}eá�­{U·ÓÛ6–õ;¦_©œŸdÒO®‚ƒ²�|bÛýøÝÔÀ±‘ŸÜò`½däÇZ;ÈyÅ£€ `ÉÏþ&žEGV «HXÞŽ®{µU«b«]áhGÛ2n=©Z¥`ϵ>]&ÿî€.h(nÿ¾&Ö§Ò¶ w–]umë«U1ÊZnA¥Ú»®Úu›>ßßÖ§k�Z>®±ÝÝ4Þ‡mˆl¡œ;¬{S�µÜæXŸG¥V ˜Ñ|m…¥B¾ªJÚ[&h%ø$ãË[úä2ò4}GæÎÙݱÅÃ:QB-á¾cœTHû„§äb¿ãe`q[…œªxj¶Žõ£²%`°•%þiär�þžˆ¬ :é×>xݹµ‘µ“ °H)½Òul½¦Âu“�%O© –~ºôOÇk¥Pâû¦§Y,Ó™œ›�¿ ö›]ò %H³ �±4$õ§Ôä¡ÅW6JòRü™æß[Y¼2�Ø#›iLÄWleR4}XpÓ‰c $-2e”õ+¼µv-;å¤ ,raheVßþ¦rдöúnã£ô¹?cÕ€±&ëÉ‚Öûùi%$ŽAž¿°ø{Hàfç…ú~¬ÿÞõ]]zö –~öÀÙÚÞo­ûSû-©�PY—Îùø~vD!ÒF�cÄNº£�ðY–CÍl–ópœ#Ð�nøú¸æQræ=GÒ}žÜn%‚×y pˆŒÃ.–ç?øNÆ ÆÌ#Œ³‘Uî¶Ñ Î� 8æ0ŒéË*ýQÇÈFÛŠõìÿn÷´,Ô¬A‚Î2§“™8„ðƒàYÔ L&àâHªp/uŸÊoK ½m-I:¾·Eÿ­}¸!€cÀ-eÀÀ@¶G¹«}ÚI[(cV`/N—”#ƒbÐ\‘å…·¡²l 4oï·õ§Æ!ù65Üû9öÕå!§1)rX•‘‡’u^Äa±mÐРÀAý€Ú:ê˜ÎkÀ‡á=ã Õ‰�Ë ïËðžqÿ=/ø;Ú/½ˆ–“Ôþ¯/IÆúw ^à%¬¸›a"“eÏávs0kµm‡ïåô÷Ù”kÛ÷Iõš}·8Æ¥üS€a/»èâzg/ówW9Á·:þŒ~?žV ìe‹`CqŠ Ô*Ü2RN”´k¹ÙsËgçͶ*þÞ ‡ $Tf²pÁÕÆË„‰sتòeöI䂎'Ú†Ü�¢tÞ'SÑ&À³Ñ’çÙçu"Ç-ÊËAÍÌŸî¸8® ŽòXÐùh½KçF!‹"`ÐçÛ¸VGoõÝ i0@ª^Õ6k0©‰Z§®±ê88÷³¤ÊLÒOÍ1'‡Èó|ú¤¡”UôÇPßÁz¸…OibØ©šZ¦ßÇÍ)Ú–*í*�é ~ë\“U´®ÑN¬ÚŠ~Yœ¡&:~T�Öö0ò|>ïU5-„{x­p.jR‹üXŸª� 7�… ‡êD¢°x^ßlÛèfÝ’ž¦n5£²Ú·ÏZk˜vKö(áÜŸ?‹Ô &÷ Í]ŒéöæÅ¦�‡Æ‘¸÷¶-—~ÿZ–uÁú{¹ÿÜqÅþ:ÖÀÀ}Œ«ŸT+ë®é1Ze5Ipd¨k´-+YV§ük ¯AÅÅwÁ½wI£®ßË¥2Xô@G®N"í×–Š|ÏræÀÅý�„Hú ÀqNšfPLàééomWºÁ ‡ÐU\lëóå)Ï"ù6êŽór( ë,Çe¹:‡Á�8` —Í€P:fqËIE®Dà>s·‰Ÿ|Ræ¡m¶]Ž @2…�ùÐDE–£EZò C§¥áD†�y³Ä¶8ùvÜÓi'ûÕÝy× žþ™hõ­3Ö¿ Ž;E+|T™2LºtÔÁ´OÊ�{¦Ã.‡Í•Ÿ7GõSŒÏ¤Gfø4lè=ÿ²~L‡ñPIßI#32³³¶9 xY¬€�LsÀ.ø,WÃ\±²`X¯¨‰€ÙH|5Yö>›<°;¶Þê1i}ÇAzPrÖº²ËŠæQEpÛk8/á• ­Bx7 Ã.ÍôÌ2ßá·Æ>òE'Óªg Ô™ ‚/âtúA~ržüüz�k«õt+{wÊÛö|½¯:ú©ÍåÎíùè‰ù÷5 ”ßÞ öR§¸†eFu8ÂQÞ9Èû䨃@ˆ•53>Ãó@ËI©D`ŽÜâgâ8/·Ø•è4ø4üž÷ ‡ØIÊÌ\åÔ«žfÒšÏÌD/]’#&™;}€m�€³Ä\®Ý4øu{ ”³ÃJÞÛŠúg݇§:!t™ýÌ•|ÖÕ߆œÎÊÉ*›üßêF„¼eÿ– rþFÚêaÝõ/3Žº# \¨Þ73( ÉÙ‡Q}»aã¤Í�¥á’I+¯í2³æð–©KSD>–fÄE­‚\Й8s¼øáàô‘ÿ8:¡W Dp`æŠ(4¿ydu†Mœy0÷× øõ2üׯ¿ßqØö5C¸o:(ÁI`î©%xæB÷é�¢2\÷}—Á­1ge´«`VØ™…sÁ³Þo§¢-ßÕÂþˆgëß�Yö§¾£û7: ù_äYQûµ¶ïEƒ? jpÓ_;4�zŒòI*ÛÅVæ\ÚÆÒXÕòs=íÔ%€E7¢Â™y½Uÿx1Üë¯�½€ÕV3”Ó¤53`dà HÍ/‹SìŒÜ(I“²(ÌŠQçµD¦úÈ=àó›gиd» íW²TŽÃÝÏ¡Áz[p;çÌýÿ[�¡¾2HSg�x‹äÍ Æ¾óÐåýªÃŠ)y½_ò9sÛ¤¶¤[:+<Ú Œ¹§ŽÍIñUühàt¸eÓ²‰ŽS¾;Т2…VW¶³j§àbÙ$ÿnøex� x¯ð~±‚D4›”?|WI´ \Ä�/†Åñ)ÛeÆ 4êNÜÚ1ÒGáUißêÇ(yØ^e™×åí¹t ¶íº6´*ÜmÓV¿·­ïM�–²ûA𔼑a¦L 6h·Õ®¤¡ QÖÑm•¼•ìð2B'Ú�zOø­‹}o]×R«û¥3ªŽ=‘ijÐèSÒ\uÃM, ?$ÖøÓÜÃIºdˆr¦ÎHî~ckõYÜz‘zzÿŽDM÷ÑáØñºÉ/lºÉr>QüÔ´¦tä˜äÆNtK4%eelo¹¥4âÝœáÓHWQ=/lyÊYÊí¼§çn}‘ ¥ïóM¿½à‹�$³¥ D°„-_wŸÅìq-^*Çürwû-¿ ´zÕ] 57vx®vC+¥OLæ„»ë)9!ŠsCwôû!pbðU~±ù&�-æÝíóÒ±°m\ïþƒ?_ÝØ ‹‹l}¸>á�oÈ#¦ä]yîwIÅ÷:VY²@qù¡ýŸ¼s+µÝ{€éIÎ?^öáùÖO5ÀIÁª“¥…ñó—÷�µhœ8n1•¿Çïç¬ÊÎxª]ëj0Z-„Ô\”{ǹŒÍÊ@¾ ^öªÓ)¤ˆ…*Ú-/8À0*] éxão�Ã< âœÍSYG‹°a'{�ù§ÚÑÁþ/¸Ûð(Æìr_¿»£xÁ†H~¼¿Õ�µ ÝÒ\ÞÁ€Ëc‹‡Ë˜.¼àQ³R<ë[Œ:Cî�Š Ì®ŸŽžB³§¼±tÀ!��ØçÛN^ùa#Ó`sfP€«ž«j!”æ©}y eá;x$&{áØ¼r/À†£6%¤�]­€f_Áµ àmy— »2ÿ� 2i 2ÖJG pKŽrîpDF¿Yl‹sæÎ/_Ã1Äv\6p^ÀÄ*�²8÷KÉ\‘‰v½1ç…y]µ}]éÙÛx`k^ò¿œÿA@ÏlqkìÞ IDATWš&"JÞdFšö€@g{Á²Œ„ûú™‘-ËC3~O]´Û{˸j:ñömÜ µ,¾ƒÈû&ï›4æÄT~Sª˜{ ‘ª‹+µ4þˆB–U zŸ±éµxkä¶­P d›Ô–´¡ïÈ�Õ^¼Àðo5ÚNÉéÈ>ƒvbÝ d !n#”Ÿ�ÞJˆ3ÈÁ¾G¾XÙFcâ<'^çįð¯—á÷×�÷\óŠ1Ì-ö|FrÀr%Mâdž ÏÕé„ù–Q„l넲‚™®�§2²2°±ŽôÏ®OŽí=³÷¹lÛ”òæw­müÁ_ßëÁÞêRdŸÀõŸ\Ÿ¶Ê·o–ëïý•=²c¦E�ö\ì÷Äioÿ N # î®ÏXŒ"áèEC›Øb›”/I‡#Õ ÏÂáÂÛžf¨¡tCt»ÒØîÀ–ƒÜÍr…� #¨é�‚÷JŠZaœz¯%âºÙ¿+_žâ‡«�.Ǽr;¡ìÕáì­+«÷©VÉçÂ[ªöìe&<†pØòX—åu·ÇñcïØ{šo«ß#u¯}^ƒŽõ�ÚÂáoOX™‹;LM‹ šµÖ3Ñ=° 2–1r5!&4•z¤šü—tó†-Ž)KÝ M˜a,óL#m§ãÓs +C�‹·÷ÝuaŒ<ˆÍ ¦c`lA_ÎP‚âRȦ­Äæ¾”{ª³hWðL™Ô¶ï .™ã<®üèÖ–Õ͵­¥¾Uúcùɾ°Ï2ž®}¦CþÈŠ¼Ú)*R:’*÷^´Øª8K T¹{ØöÀ‰ï/ƒÐÕ? åZ>â”sˆÌ^9xÙ)WË/®BÞÜ®O²å€÷®Ìâøx"ÒYáÝ8Þ"G ¹M�/ã®*�®Ó L?Þ‰Q*É뀜6çll¤>Ú•�NÓâ7h}*àH@Éš× µ#¨ª–U�œë|P—;¼ŒŒÔ=Êxïò‹"*q1áYêd—Š)/ øž­7LËïï¹|ö{OåÜôô9ìý±ž‡%Êü%nÚŽ;‚¿$ÚåßâU¹�ÖŸ¯ R Ô)BlŠß~S(w”'[ó3?ºìÃïÏ×ÓÝ×7ïÝçÃóý¾=”ÓÒ»Ö�àè7-í×ߣòSMSóOëˆëü~¡’mß[-JÞcÎ_YÅ€×66üí‡áZâM ¬ÌqëV)ÿõž|ôjsfîòæ'‹˜£ƒ(”q¶~ ®\¢eŽ yì(‚šŽ Ž7z6Äéì•ñ?b ¡¯ü²ø&*pŸ°Ë‰˜ŸÌÆôÚ ÂO÷†ƒ8ºUæx8BQ§òpC'>ÓŽà¬/ùŽ~4.«ïŒËú‚7mïg¾ a¿m[@Ìîó}G^Y% wÿ¦Ë÷ø© ÀèÀʰ¸ˆS+È™òàaåÀªÅ¶~?Õý,f5ûQ¡ØïV÷ ~¿×кhW”ªÐ·wî Ýôbª™…¯F ·8©j8®QAÈËX†Ãíbüžçhã×h§QÒ¯ûxÈþˆ©Žáxa¬Ú°< ˜[´ä²úÜÇ}¦#å}9~¿'®÷Äõ¾0¯[’¥4ä‡(E~9\ hgt|\ÊÔ$Cm»r‚Ò)ª¸fy¶Î⥋gšÝï)Sæ4\Ñïé¼M0Ò ™¯Ýq$CUé‰Îˆ�f²Ïí¨@‹Ä@PŽ ù×VþÕþYÝ̆µ ÈXé{‡:Ûf%ÙŒªžú²`«òwþèù…Œç�±ë˜DÐ(�Œé�êaô.‡*K×ÜôÞbÛç~!²‘£™ëñ) ä’š0Æ©ßoຢRpZðȯðû+ÎÙ˜yŽ‚sd.Ïö�>,63bfÿ•úbÊ*ƒF¨†Œ{)"_ì8ʼn;nsGä»lúäjç´ÒJÏ©Ã`)/Nm[ß.¾¢7û“½ù9‹UÌ0y¹~¦>R‡F£°ëŠ[²ÊqëÃ'\ÜALû^m“Œé6•Uí&L+*¼èX�,e7Wl�hµ®V¸ún:ùÓ¾³œ7„(.eWTDZ3ª 'ž…ÿ¤�­ùúG;%'ÃFꆬ�Ué$Ü-çHûy �U�vâ:ù#m~®cPàÊ­È®<§D§ì›±½d°âÊF*°ÍÃÖ¯ñL8�tˆ¢ƒU:’­Ãvžõ›+ÚFŠÀcèw÷6çë_ër�ŸdLg� êÖ=Õ-1BZ¨o…µG !)ýe ‚6z�ò¶0X³º/Yœ‹¤IXb B©>+]Ä…4ÓÎØV‹‡²Ö6¼{ûf‚wÜhf]åcY Ð¥m jÔƒ«jnEòÕK‘¡M›ReP¾ÔïõýçUä-_5äÂ}ŒJj¥Œ5½wÃÖi­ +[ïw�ÝÀ¾€¤ÛÏÝBáªZåo(RŪ¬h4Ú”7ŸIãÇ·¿|Ðveÿ„÷«ÿ*3çÑ3�¢ÂÙ&J_°ÿ€+PVsàÔª5Ö gÒ‚-ï�ï–ÞõE¿Rn½ÓÉ ÝÇf•L@JⱅΨ“Ö€íN{̈™ÒB‰{[µ6O� j…ˆõßkηå°$άqÛ†‡5¯0ƒ�²RI;rãý±»ò•!ýWdè¨à¥¯MŸÉ\kAä L2,$åßCñGZó‚É’´/Íï(ÅfS‚¦&eØÖþl)g÷6d\»MÂB�UËš”]Èw›¾Â†Çâo ^Aøv¾3vlDzv`Å×~}xµéú»¢¾=x’Ÿ7 x`ñ?·L^+SZ4|ªÛX~ɾ†ÌCצ¿ƒðiMÝG<ü䪢Ÿá®Ö?3€SØÜNèGð¤ã�Ka=�ðTôK5†t:Ñ!oµdwØÀa3ý¤"˜rà8AÉSª„øYw2ÍÈÕ“ óL¬�C G):ˆ'LXô4I�gêôé@y›oßõ[Eðe€p°|ÖŸEƒB#ÍÄkæßÞË–n†×ƒ°"£2E‡šÕæ µ º�tTcº.x~"P`}@3y˜èJ�x(`©/­º7S©“©É�Ñ'†¢Ž�ÜÈ€sÀ^ö5€_ð+ºÎÎGîS�8 !E|tv ¿g¹«#ÊlAk)n*e8W&¸à‚²Û'_ê~÷ž»Öc¹üϯT‚MêVgmS⡬�è`mäcD¶Õè2 ñ§õ:$õíú˾ïüú±ÞÎ;¶íþ·Rø'—Î|Ÿêüc—„Ç?=g�¢ÿdrêC¥¡šŒ:FÉx¥}™��õ .8™ÔÉ!¿�œGT?f0|MÃûÞsâºf8T.Ç{Nüó¾ð�Üc–]Ú¡gÚÊÅCŽ2j dGGíÿYF•/âSüÕ9a]¢v†êщe܃2#5™a^ ½à™ÙŸ9ÅJ:’éË]Ÿ„<¶V&CǾ©± 5 ëvpóž×„ž•›6ktÜ”JÇ¡ƒºeM€‡§•#ƒðQèôU'uàøéVwŸV%|\躉·”Y s�Ï鬣œižºN[«xŸ{Z÷t£vX6Œ| A»Ó50ä½iŽá³6OIHRƒøU/ÃÈ­ƒàBŽZE²Û¹}giúÚ22©»é…ÎÞ:¬<·ªcµ2ØíÔOrømˆ«¶4¡R^¦çYn+É-Ž_+ò‘Ï6%ŸÌ¦eÒM—˜Wp€¥^™ÿ|q]m#²ž�‹¢Sq˜©®Å� zmîæm!‘æËí{±0C÷Æ-:de„ÓéÓí>4 —3iv”®q�zCÈd&Ì9;ñˆ¸6Câ ¬œòÒ¯šÇ*º.M.PË-È㪠›ç50À¯ïò@‚·êÀĉ#Ç/¼nò­„Xƒ-&Â²Š±l¨Ì;xø½')RþÚçØ4³h§]HÙçëAS-oQ8™Gò@Yã¿h3±ÑZϪU’ÞlÿX�7h[킦Æï4u �z„ÕDw£M_ù|eë‘ï ìWû—;ðéÅ·M „€Š4R`ìë9š¥J6+ŽE-q¶ZA%ï·+°À3GB¡Òì¿©3eZ G¬¬¢þì^ýoï´³Ókô-dÿ Þ7e‰læà æ¾…úíu¥u6åÈö®p‡ÃöJ«ô%ˆ/·o-^s�4±¥×aàyGqø°0=áT¹šƒqçdùkßFˆõP�¸È¦ýºÝ\ù»q òÀ“çxXÏRÏŸÆÚ–áYÊ£¢øÌŸ®ï¤ã§rû;ß5ö@óKöpïgí¦4•»lë<Ÿ`ùO®?Áÿ÷0œ¾!‡“…® ™¶æÇ”ƒçéSŒH•R¶VTP ï­mv]ºQVš&wíO…’Jn"¢¼3™EÛÒXe�‰óF·~ÐIJa‰Z¦’£•]² — :UèAR‹”jÞ†Jî—òJ)—Á�e²[Î'cã°›¶õÞãäÒka,¿ë¦åùö¡bp�ýÀsÅ€sÕ@m+x¬@*_'~àÌ0gåTJå�Ÿ u;oأܾÄ3 €¯ûuÀ¾NàëŒÀÀ¿Ž P äøû…8·à À¯<£¬Ä붼ˠ@9”½}ø‰X reÖ<3·Ná¹Ç˜Ì^’÷SyÃÀ$Ô¶txK16ˆ�— yqjÔ'‚…G9Ж3*(ÂÏÀ}û ‘ãïç\ 'ÉBŸøèßÊä«=8øP†²´þúËŸ®m Váüƒ:¿é«+|A0t–›ˆÚÃÖLë&„àÛé9i çߢR K6Le-Nò?€tšžÇ.÷>¦á¸€ß—o¤\ž¸20ðþ=ñ¾ú3ç•üÆõ«m*&bÅAÈË™¼“�I`9 Î0D 9UDª"+¼NЩ–\xØKGj`‡ïêèÅ$zb^HÌËpéør·'Ñ«£W�u)¹•Ò¶•o�Îòžœ—lÈ14ig½,s’b:KIyâR¶Žâgg‡‘°g½ÈMQŸôV9Ä긊a±AH‡n9iHåAçcÕ¥KŠTéi:züÆàøÇ˜­Ù YÖ b+¸sça8OÄAÚ/Ã83 } Vç¤}ÀíäÚ¹£}˜á0Ã9¾ÃuæËÒјÁÄDñ÷•»ñ™8à6;àGLÞð;ýN×–i¼b7û¦‰j"q˜xr¤= #E¹üiûŸ�ÎÞß[Ê“nÿèdh«ì¿¹þT×2›�ZëÞ™n…ùÛ6$òô÷}û²õÝÛêÊâîD�ý`öú7¦!�ºÎñC©ª¥·ò¾ªÚlê¨a —à8©âHS…"–“jò÷'Ä)0Ë8ª5Ñú=œùk°¤7[šX—‰ÏLÙZ+3F®XË÷föcΙAì&°÷âYx˜²‚®€ãä…÷þû颦2ñÞÄ+Ìb—nñ…bQ«‹(�þIf|ô›Ù�);iGŒø^�RÉw@éÛe ï^Î4UaÚ/+$­ô±Óó�_vJ©Æ²ò*§¿£È´™*qÕÿIØ)©B£‰97ØD•Þ¹ËÍŸŠ¸QTkN›×à}¿/¿xú›ø &V/¦rÿNCÚÏçèä¡…¤½d1À9¦=Ü+Uxcž³ö¨+_Îð#]•’kú£,Ú81~—ì°.¬Ÿ¥¿¾’[ÉËD‚öØé‚wï«ø™ž8ú~}~úÜÖ¯�IíìØs«ÏwýñgÙ,„¹¿‡\ÞxÒa?¿~†Ëï/ÿ §”n:H:¢¨|Šê¿ ¨0¥±Í$-³p:Ó†ïÎ2R#q½;¼ÑÔfúãf zéÊUÉ­ÍÊê[`W#DÊ[Ó”U$•é~d»`+k_>»Ó¡^Û†¿ÀPÍ.Úk‘†n5o)’ö6ÖÒ–|ï¿ëž N¼]ZSÛrÔþ8…„ƒûJ‡w¥.I£ü9‰Ì0¯ÌO&·f€˜±Ž9üš«|?¸mÐü:3���å߯cë„—«Þê`ã84¸²t2kz· \õ¬à¦3Œ,·R2:ÕI§éTõ«qBrå»e UÝ›‚¹]OštÃû¦ìöl_¤¡Ã½›,÷Í@dÛ «ç^©´#YÁ´kV@n׿+>úÞ£Ö_®fÉÿ Qþƒk·™n�|~&®<©ÏVy6 <™¿¹ŸyÉO zeJ²4ݬC^Ͻæ3¸5pâ†ó8ñz ¼/àŸ·¿Wž0çï÷…ßï‰ßï+2¢¯xŽÙYÙf#W ¸¸0byþå±é‘çÆq¹-Q옮ä™:Ïb+w«-èzBhe vpÀKôéÎø]R'Sö’ì4Ï …Q¼ð€ZNr—,&3ykr“ÜÉÓå{ÿˆw]¶j-Ç*Ø[ñ2z�œZ%ˆ{s/ºç#ÊV°Á¤®ÛÇ·º´‹¾}wÆw¯þ³µ>íC­ö¢ŒTÅ)mØ]â� f 3)ã aÃi x�†×9p¾ çk`¼ ã5"(P+5‚§÷Á“\ip àÌ39^ÇÀuæ«U*¼Åíû2¼§úËm`âÀœ†é¿/àŸkÍ„«€Ù‚Óõß,°j+=¼ÊÎàü±8H>e»ÿ$cþ§åþ½:Byª“}-÷d<É£xéááÏàýyPãù½Ÿß�—ÛA[¶}w‡Nƒ¦‚5åf»ªù¡¿Ñöʌ彠ý^ÐlìºÃ.�÷mz†iÅÒ!û×^yVN –ç�r¦{Ëøˆð>å*ñsÇßû‰IcD°Žè4#_‡Îš×•A¿™»iÚ’;Ä A¹4�£¸”±÷h üâ;†½’uœg•Ñ6Lð‘5J‘�Zue€"iÊ-«qC�éJñº#ºô*¨ä –àAž+}.ß¶Ðáí*ç�W{T£ZÞœ:AÆ�¶pK½(=µÔåèÁ)$Œ�XÒvºcÖÆ•=Å’—å‹çáe¶·ƒº·×žµÚB„êßgÁœÁ­†¶W5k×Zk+^ÔÉ÷uê"È3i¢Ô· çñ5°?…:R™è�„Çåþ7ºðÁT)¢Â1ßx èh² oÖ0z¸öxl°F?ý~/¯:o �F©/Ö>E‚ZÙq[G(W‘ßcŒ½Ð�®Âƒ�„ÉkÌ„ý w÷c.�hòcË#¢fçCS´ÊØ-ïmß,[<çƒéí;b_ù© +�-CO°AeRnꆋ†­ ûµÈ?Áw п¼üÃoæS¥{ùÄÙíþS½Ÿ®½­ò¦ÿEÿ'®§~­×YåŠ:å]ò 2¿}£Ž-—&�KT-x¹$|¹³´¸¬µÚJHwV«ƒÒD¹åg Œ—‘Âcª% `Y1€\R[J†RØ &+¦R||3åÐeF|8¤ÊI¦]èæâµ7³¨0/eSëà€’RÕÐ&Ÿ‚»M64fž™h‰ðDHHe�Ín‚{Ê·B׳ÒQ¸é8�µ3ùèãêÝé‘Éo0fœWp9ŒÙÍìè1`GìëÄøuÂ~½b¥Àë„�8xø+:»C:@ßç \ÔàäŒB;œÎ à‰ð�úHÕÍUýp‡]#Î4 b¹fd†¾s¥E’’%_ºðMUDJ`$kûoN¼VuÌQ§.c³�‘ŒSY›ü}XÌž¹Ùö1rÕ€-« Ü:KíO‚þ;á/òdkeªœ<µó§‹ãnß¼ñÐG‡U3©Ëä—õ}¼Ú˜ ý½=… W,ò0 �Zu•«Xâ\Tp¯±Õ�§¥‘Æê8ì8àvà˜‘9ýû=a61ýÂ5ß±j`ÎÊn61Fl�vŽ2Ù‰·ÞÀfmã°¬+e]V�8‹î“—^Vm‹sxÀ3Ùúgbû Xé Õ{î`7+ˆÈàø èf9Ÿãš–��²LƒzWôæ*ØSq¾ÉýVFM«^­€Ñ°ÌrGòtÊ�ॻʗÖ2;”ÔÑõÛ�F¢µL ¹#r|¹4<ÐüAê¦-³·U'Y ¹öÅ©å¨ 2·È-ºp Ï#9ˆ>àx傳ó¼¾€×/àõËðú8ޝL×93â *ú†ã°Xq0瘘Ã0�¶KèÔ?àëexOÃÅ”²ç\n¸.Ãû2¿›Ë¶ØïœL®þ¨ÀЧ:£¾5º‡…׳ü:Ê#—úZ4¢¯Yü@Ó�KëÈ=µiKkÖýÝ�»Ûª¨òOÛu]ÝÞO¯ïœú{[ßm#ô´Z๽[#­Ð7<”uëO‹™îÐñ˜rè©ÞsË}—»æ°×½s;ä𠬻€4±¯ž 3B) %ùçÌä‘:¿ÅÂÁ‘ì´ó¦•nüÓ*�úÃëÞ`'R/0Ø7çŒó?±‘ãð4‰Wq MrÒ±Y±l÷/-¿•æØÞªI:p òxÊ·Q²À)ª`@�%r,†ÔÇñc¦kÄa©ë2§Û±8‰,NÞ" Â`ê,özÖ(T%JեߥÜV¼ÛÚP¢í­ĵ|ÈD�%�[‰JŽ¢³+K[€[áÛ�"ðÕ—mƒ®é¹TÅwV�V 7r-œ\EYÎC£Ia+çz>íMãÕ·M3ðá­–²Ë¹bànªˆxÐnÉTDu’çIwÊ[+ŒKK‰ ŽÇ¼3Êz%rÌüAÆ¢ôdT#šÑû{çÏ*—ãháì-q²É®­ ¦7’."^Ëq@9”myß»_òm .ãG'ÅÃ9géן\7�çÓfÙmeßIÙÀÌ ˜ø‹¢Y¨„°'Ù•É[å.â®Î0ê%B°ñvŽF•™W¸£Íü u§8 )ciaM¯Y’Óßå` õzŒÅ°ÖYÓgáQÛd@P¯ÇI Ór3nCºLÒ÷úJ%¾Ñ�~@˜SdWaÜ#„�ï›?W:´�ò CU“:._È\ž?s‹¦;"u  Æ`I4¢þ~Š‹ínWB%Ç7¹Á¹Ë¶Ì¿«iÝ&¶üBì�4¡*Â%i �.ÝR+øLámY²ek²†vÚôïG½ô�ÌÝDÈ.*þ>AóAp+lÿöÕs¡§š#ªè¿ÁË·µ|¾Î� iÅ%$ t>ªnÆFgÝSx8Åñ„m'Ù°Õ€*ãa xÁµHrG« âPœcT«('Á„(í2æðýå>ûžpŠ9#² ðôþd¿+kÒ �à–9sbr»œÜ ´N’W “cFÎWX4™�zrinxd( ž6YõÜkIø­;jË*(ž*(aÍ1�ïì¿g¦ylÙG" †ì°3œÉ™vËÀ€üæ:mÀ® ›3Οâ<�3VØ×ûõ‚}�°×œq<�_a �uŒfz…®¼êÐæÂ¥§"‘G'ƒup ÄDõ3Ê�ä ›#éËYã|OŒkbŽ+¶YÉÀ ³b2k½-nìª\îÙ¶RàYŒ)±²s?µ “m÷þ'/âé'-ü;°<ÈÀÝrýcã«Õ¹,š�¶ëúæù– —oŸ(Yk¹Š ?¬¦�ãà ã8Ï Ô�#6wÄåoœ¿ŽSLÄ>êéÌç–t`ìm6`ãÆ ·ÜN¼'ðÏd~½/p\ðûa(Ý&+âÂãmiÔO ;ê €ŽayÕ5,tAe1²W5óª)ûP}ÝB¯1©{|Ì�÷Øf(tBè¬8ÂA„µÎ¤©<Üe5ù>õ¶¹æKV©:Ð$ÏB>©sæQœ¹GH„æ,uÒ€d˜é¡ì”)GW…c¤´«ÿö·bºlT•iEòëÍÑpSµ8Ãqç¼/àœøÌý^cµÀ×p|Àù|ý¾þeøú—áõËp~Åy6!½×Q�çq8Æé810ì€_Àûxã<€yMÌàAÅžÎÍ× ø5�^˜‡DVòüó~ÿ6ŒŒàùœkÐíüpÏ$gÄn²ä ¡Ðò1 8l•â:lw¿huµ¿·Ò‚ÏÇ�Ô¸;ö^À`ä IDAT;1e…Q÷åçÏj_ôfHŒöGí�8øtÿóZþSPàÓvKñ,:Q_äßÙÉ]éwò“Îvc™­�½�2¼¸gqÊAšÔÁr‚/´(#•5<â$¶~�ý¬Voj¦°;|u€xÃg¬hʳ*°[vPüS6¥¬¸ 'I›]:ÿ %ÛC£EuÍÁØ_Š©ìuưÈФ„ 0É“+Ã_CüM™ürÔºˆgÔMH?•õY;›¨qrß)ÿ„4B<–>eþ”Sš2âCh9ß¿¹¢\¿™öð\ë)½á�Cëç ÌRw¯ðÛª¯1ì$£(³%¼˜W[¼O‡üz­úNûmŒ¥lË6@½?k·n °8Ñ ·Þ81îWªø%-“˜‹~mi ´U½kE%ó¶›î(´ÝDÛZÖ¤OuŸü Ñs#•P²]-cú¥]oUWµZWY,N3ßÊìcLGœ @‘{{½- nÓ„ý `ª÷,u¥ ÝF!Ñ�‰Ý¢]«€QõL‚Ô¿ø´•à~u™· ¯½rmß¹äS¿Ëìk«Ey·¶?<­ë×Ñ[V£åVŸý°½_ÎäÄS:òiê²�·¼Û‘€43Üäà–§ø�#ü<‹¬Ýõ’³L©òÔI¥kœË𩞇ÿ¬!ël©ÃÍ�1³",ÕAZçÈ´ãÝ þPÅ´rÿM<<͇Up/7ãg ›F ²Ô�³…Ên¸m‰FÊ#û»¶º.ÔU÷„ʃ¹µ±¯Z .vW ºê`¹–i"eëÒëß.ïQ%M&U¼�ÓÏ7]êµç"߼Ϲàt)ž?´ôé…uÝäÏ.ÕŽÏoþ¹å¿¹N)ŠB�£‚ïÇ…d I*l:Ü=…ŽSXR`²�|W` aÑ�«d†4:^‹A˜BÔV,™™’cò%Ó˜±4Ä=™.üÔ"%VïBJß|V³+ÀÜGNøuE½e”ÇÄZåš�TºÇªŒÂ%ºÍr¦ •3 aÂ¥ ‡‡ÝN!ÓÙ. —t¯/"««X¬®â G=·&ñÑ�‹È6ƒ×,ÍvéLçÄôÈ63œV—ç¬+·A(,;à<`¯–«ìu¤3ÛàgddbxÐP ÃbÏ ¦s6à#7"Oë´ŒÅÒ«Þce&KAMÆ‹õWó‘ÙÿT²óŠC�„¿²ÒË·¤ï+ÛšJ޶މ«‚—‘äÄWI6�×ôPº1DöW:û�+Î Ô–AÖYÁÜÎIW èÁÌÄõ ÝöïO…¬2ÙúÎ2i’RŸ ø»‹²qì�•ú½ñ*¼*\u-û#èS[.ÿîw‘¦bÑﻓÎ;øÄsA¦WÀ| ²#î'íŨÅö(€aqèc• gê‚÷Œ€ÁyZÔêyX+i4·jI§ˆYlEeã„Û�iGì¡þŽ,Í÷ÓÙ4ƒOJzáÌÉɺqÓ«bâ>S1ƒ3˜Î3Åçcô$kdAiÐù.Q<û¾dÅ«éÄ™3 &„[B´èëBeÝ¡u«K»œÐmüܪ®yvAå,õ#éD‚¦ü\*&å z²éÔ]‡´UõŒ­rnÊ'ïº|—ö\H¸®’Å d­[[ MDàÉc•Àa8Ï §W®è²a¹/¶Mä®tçðúŠ€Àë—áø2Œ—g~jržw;» v8ÆL€çá¹j`Æâœq…¼uÀ_6_jœp?bë­wlEôßÌ+V9\–¬iLFð rͧl¢0Kxs‚_2ʤ0Ç5 -·z¼z@G \¸�ùâ0%h %ûj»’&Œ2ŸõµÓbi´:–FW(Š�ïô¸;ä?gïûò½¿óÈXËúÖŸ½âUœ3,§bbmùƒžh¾ŒÀ‘mθvB~êÏÙb+�AY꽃Kªñ‹®¼ßÑî"x[íõÚhj§H~g�.(+÷±¦YFPl”‚¿ÿˆw§ßÚê-VŸÓù ¥VSäW°€tgÔ!Ä+yná4ª`œ¥N„U=êø£Nð¦’rÁRßëÖ0“�ô€�«"jµ;¸…ÜâBþí€ÁXËåVz@:K/ɸbÅó#Km êr¿œ”Rh¯b‘\Âßšqº�Q÷s�³H´þe=@eïŽFšÑ7oúVجߤ‘ŒáD9¸¨ÛLëÿ¤EEª9gŽ+˜© ]ð+xNš+ž¹ÉY/µ±K¯Ö�Ôô‹ÔS ,tcíoØû÷ ‰Ü¥më}ë9;û[$bèv„÷¤‰Ïô»× -t0MÚn1„;äÝò…e}µ=â@n #xl’Èúµý¶›—1Ûp?WÝöÝ ‚UŸD’ßì�óK.¶Ô•.ôÓýÞõ{‹K/º5y8ØÎºèwE´wd{âÆ¥ ê]GRô~ˆ�·sŸ“ ù- Ý�9®pó —�ì°®oqaÞ·ï¥!‚Ñ´ _½·Š[0ÕrHÂ2 �R©î½>Õ¼ðÏ&ã('û¸Ep{3Qî-°W¦Ñ£cýå3ô{yÖ¡ù»%§W)¸ÈØM.Ê©+™­Á"t4U;¢Ývö”úÞï‡þ¸ömÕ¹‹,Ý¡»ô\Æ©{ˆzŠü*^¾‘KŸvºÙþü¼ÍèýÚ5Rk_ž³Ô𮆇2Ÿ®na×ù?{ÿç×Y}‡F¥=B0ÒÙX#ß&Q#¾O"öÈèÂÜ�g%;(à �/Ô$N…‚`‚(nãYÔ@À¤˜ÍÀ@&á³4xcr0=¶ =ð5 _† Ä'V œ˜8aïÐA×5ð~ÌxL-�†éŽÃÇà§I3|J.*Éa6ó;Gâ¤äv+*Žé¤ùÿY{Û5Éqkt!GV¿÷³gvW†8?`ÁBvduÏlד¶,!Ä—IÃ@‘ÏÉÖÀ˜ç}ãh·Ç©³¸Ú.œNÚF-ï/YïÝö1²sìûîd‰»tÒÅmØGÚ,Éwø[êR‘ÚÍSx)|'ü�&Bô´û¦o)Rœ‚“dÒn(^[Àz-\Ûñz/ì—c¿7 ¯íØ)¯eøëë�¯/Çë—áërû ÃÊ-„Àƒ‡Kaxt|ðr˜{Lê<Úßׯµ®µq­�—y8á®ÀÏZY·«[ ï÷Â{¯8›#ØÀ¾6¾×Æ·m|›ãÛ6.‹@–ãË~Ä‘ºŠÆžë']aÖúAh§‚®5v}ƒC«†ômŒxÇ Ë™nrÒdœ�ñÐl€ïmp¿|òÓ9™ŒQµè~Ëûáv"|ÿOד“ÿ)8¡[黽ýðÄ-æXp$ 3›kö7Lºfýž6�A#ÿi#!ƒ:Ëä§sÉÔEbÃï´ÕY†Ê6z<ç Švr[ þöíteØgÔÄÊg‘‹þL»îÄ-›[L±ƒzbñ®ŸØn¹ÂÀk¼-P¿dÛÛ(¡�«öþˆÀ»Õø£hç�ð›‰yŸ,�#ΓJ\åùå�J]ãŒ- Ë!Èb–@Ç´4Vm(�NÙ#ÆfÉhè6V¦´�{Òt£ÂǘZ%H(({¾šŸÛM|‘y¸áŸ=TÊ ;ûuvŸí¤{:É@ë%,ñ¹¾êb͇ÿvÕaÝ«I Ü3~ŒÅsëñØ�ZÙP¼xÇQq‹µEXϹªÂK…ëN(ëdv('u›°AêØêbfá¶wØ~”�ÀÔÃÝÒqëNÃ¥ƒ»”�œ?´VP½è0OYRôï :pá·ÿMù_µëÀtvk“ ÃßVBÂ|ýÙƒÛ�¨nžôf�œÈKEÛÌ&&ó '—ö‚NúÐE’ 8v®þc›MŸÎAk—ÊmÂÈ„V離ÈÇͦH“º³Lœ{‘B-7¾{ûúõýª“Š´5\û�Ïn˜wNMð„±Ï’âÓu¶ÒÀÿ$Åž¡þgíüûwÿýõªìiŒ Úô»þUr¯¥_�™)ÌPŠçòlUÎD%,Ïºí¸Ÿ´Xu@›è‹/c&ÿ/KÃy!aYÖËYÉ¡jQiÑÉLu‡§#Ûá8_;³c¾ž�ö6BÈÀëŽI|¾$‘Cˆ3�/¡«ù!Ë" À2Ü((ï¹YžAàåTQ¬:´$‘¤+sIƒVôe![5`†�¿W «Ã?^Žz`­ ×¼¾~}/üúuáïïwˆž˜Eà/þZ@dssõ޼=¶P‰ø”Å�­{E&\Êê`à ØÆëÊÀ€yƒaÀZ½B€#ê!;xd-/•’ ÛP¹E=ÑýÀõêâK•¦Cdû†íîÔ¨ÏÉ ETiF0wRc-ǧ:Áä�Ù�£ŽÏý¹¤Ž*Á çÄŠòæâ*ƒÃŠT»š; ¾I·g‹6€t!s¡Ï4Ü}6Ú^“c]1à¾�lþ]ÁÖ(óõkãõ+^®¿ ë—Á¾,ί¹ò¯ÆÔ Ëspšº^ÙnòÛåÀë2\øå»­Ö%ßßûÏŠÕ,ûÚø¶7¾lã·EpáÅ @f¨Æïž+ и±8>QñP�ÍËä"Cqˆ«]ˆÖÁêÏÌIc›¿‡ó@l¿à/+pÕd)éë-;Û!OžÄ¼¤î2ÈÄI;hº2_m¼>¤ø1�ûi; :J–{ß;{u¿Ø[:1�gtÚ ‹w.m—;ª«­›–½9Oç“Ï{§ó; c™—#Jq)áª[Ø¢H-‡“õlç´ñ~¶3g§l_;Ò›VòfØÜ&¯I¯HÌvT]“s�C4Ò㪠ó@j”Çwå#«z ‡‡{®Îl_·�ä mëÝ'G#”:,ÏÙ30`˦ï! Tõûk€$†4ÖÕªì?ûkèL×1À‚Ï&âyµ^¦Ö«Á˜¯Vy:ö¬ùÎÉÏ® äürÔDl~V‡siVG­î»ù¦X›ïÒp�PQfT÷G8³±Þê“÷'ÌMG_ •íJ^²=Þo)@ç:i¦Z¦L<ô6û4ùš$¤NKÖ_B8á&~g‡TúÞŽÏ2‡zÈ^ÕwÀÇ:êÙÍÙn`„oð\Þ¨|ÏD—ê½?ûÄ-Ñxt:Ç$MÏÖÆË$Á_†?ÚQ4{")Qsļ_J>ñ£îJh±^E3üCÒöÓj €>!ÇiŽ[qÀì´ê�aŠûƒë-h{ø¨4i�ΕV‚¿ÒQg3M» \A�r”òÏåsU?P2Gù€šíž«R‹,owòijynA”üm[žîÄ-W‡P6ÞZ¸ ŽpZÝUT”÷æLûHZºÑx Ö!OùLýƒ^¾#òDóy¤^œ�¶ý ™¹�)-¤¬�ÛAïR˜UuŠ0(ÿÏÙaéÜùˆ@j?HcK¤9Ž=.B|Ø*¡·'•�S‘ëêãúRpÕøÖ>ަ& Q‡¹ÃÃIYò­vi©+Pœ¶åiˆ�8…q.QšS½£A޹/ï>Ù™åŸdü“PIqòﯾ®åEo¹[­ÿ*�Ù:Ù÷ºbû‡ëZx-Ãëºb«‡r˸ô±Œ!JÔA²2¨ ëZ¹­Äª`ŸS+5¾ý >ôº[±¬�ËSsÍÊÕ±Ä>ᬠ $wØÞð•˜a}Ë‚@ÓyPi:E%ÈGëØ÷{ËBÉ`æ±Gv$ÊzöM »s ÉDI[µÏçiÝóªìë¤úÊx¥°NE�Ù‘ñ“Æ@»à‡|Þ¸]:¬Ã7"(P§Œ±`r¾î9έ~¾øíÀ÷ŽmI¸Ε//«ld‘Ýv)â#&=pƒd¾:¶º1àBœ)�N,»ÐNx:0µ~â~l_ [+u$á©ÐKh5œÆƒ“÷W7TäMÛ€B÷x^ ëuÅ�ÊoÞ;ƒ‰OLüFíÿ4c5Fõ·cÒ»7amþ¯3²C1«~ôÊäžã!ï ×à+tøë2ìwlÏúÙ€åX_ë××—áú¬_€ýBhÿ²>K¡™) Xë±[=‚T_/ƒýºðZ ï/f÷Â8ž)ÀŒoB'|¯�ËÞxÙÆ×Úx¯‚k@  ¶ ì<·ï³+–x¿‘<�C/’þ»†�VÉô{…�Ò—¨CÐI‹’ÚV×çðÅëIâÔ‰íÂÔñŒÒÉ!Ƥ–"5/§�éÄC´=k*+ …¥ô]vŽ�YwÈ™v²©³^l?«¦º?|çì_]½UÜÞmÔ=�I°Ýáµ_A>?Æï¼´ÅñTiÄÏ’Hç<ç$€¯pÎó<Õ?tP{é áý¢�dõÌvg½�÷¶½SÜ­ä=ú¥u®ÝmÒCêi·úÃeN[ɪ¾>ˆ¸óWˆJ3+¼‘' NÉMzèvvþÇRƒæ"{]u�ÙG�9hÿxê™è;LüeÝï�1lÓò¨5—º¤nd0¢«|øòÉš¡P:my¢842R·z:S}§Mب¿ë¥Ü¦=ð$b5e³(Žïú‚Ž{üºú¡ß6¿û˜'Ørµ�Vè(9²§È”,éôà£s HwŒ|Î`Ÿ˜y� ëàS%  éÀàíÛê*é‹Hâ;zÌJ®©Ì;å#aá;úYúŸÆxÖöcö{­ÖN(ª¨Ôìã#žRÞäʇDgÒs¡Îá"�ŠÔÄ Ž‘åv/V{†Iû·¾õ×íÉS؇Óýlë® Ÿ¶�‹/�gæN¬¿Ó�¹ðqEQé1ÈJb¡¿…–mf;ª":Lä4rB¦d"­f�£çllƒÉÜå/�D Íðïáôî;õ”Y—O™¶R–Ö®pkøÌr+"Úä 9ÿ%±<�wÛ²Kf|¤”²sÊ/–„g]ÁYá$ܲÁòT Z’'†qàò]Æ£.ÝŽg0%cª]:ü-ßán u﨟JÙô*/ò†ÙýÒµy±,}¤�R<›4<ö]l°nJäx”½…K¯y¦¾Rö@Á!ƒ(òûÔBs2©“ç2­rLã8èÙ>Œ¥�;SwžÉ³a°s�‚à@=sÉ]×þ©Æû[�„ðá­»àû×y½"£Ÿšù™‚e‘iy]¨€@,g_x] _¯WfT¶ð× —øüP~tË•°la-� k…”«Ò9;¶à²%G3gŽT´åpG­~_‹á c^‹Qa{:ZÕIû¡ãµ$ç Ë U”Õ›x¸_f«s�€¥±eÛʱê\ ˱dYoÏTÐÔÎþ‘(Š!Ñ<³…YŒ•yvw—yQ„–ìKŒ«Õ쥱(/µµç¶GºwZµé� €þy~{;³Ë)�Yù9c*_”{ÔEÇR ¦ìzgìÃ^Dh}ðmîm]>°L`oA×÷‹-2�6QT…éÌäWwÀÈÓ+-Yf­ô½Ø8:¶MÊý§Ã#´ó/~ûw¦v¼ þ6¤—§aE›ýçÜŽˆº½¶¢08všVÉ+ >1(¶¬žŸv­8Gàºâ\Q=N&8 ¡m…¬Æ7ÿé½îñ¢qóŠ>Ömâ˜åî`œ×Ù–ßêHåxôüþÞýî]]|RLÿ@5¥ì“Ï’)wdœ'¹ôdPNbŽ -q:18ëPrr|]À__†½¯8Œõí0à—Å.ïmx»ã½w8%¶×¹®Ë6–…ƒÿ‹[ËYd-F,®·z-ÇUA�:Ѐ+÷—_à Jc€[ ×*|¶ž©Uv•Üdy 3åên;Ä»�jŽ×ÎíÎv·ßù\}“-ID/p–út¥‰œ`zèõðšçÑt¢j€ÐÀ-@<õ¶QvBnªá]§9W ȧ=<ú²ì²ù˜1Î(C�X½É eè„ïØ>Ѝ£.Ûž‹ÄB_fØ—E�é�^˜¶6ü—Á~®/àú’Õ/^(§ÿÐçf�Èp%*vè¢u-|}—-¼^޽3Ÿ-íƒ�²“â~øþmøþ½àx;~_o¼ì»V üb;1,xg Á ¹zβñ…•��ß¿7~#l‚·“ÚFájŒ?ηzB Î[Ëjg ³×‘¨(;Ä-ÓNGB¯îCÍi\l»½·ŠÝq•ðì�oئàä±_¡�<>aé5:–÷N8Þð?ö¶ jy/÷N­un©fUlDzÕ ºË¹ïÐÇkšd7}œuƢіÃ4J°��ÙŸìŒqëªC½µoŒá߸–öÓ=ÿÝãx§ö{G€m§ã�mÌ«åÓpxtµù8ÇÅmµvÜ\C¹>ù†Ñs,E§ågò•Kvná+5_Ù]eßÅ{<ž¼ª¢xϵÁj>Q]¾c=Ö”K:5êÁ§K~ο{³í™�Ý!Nëê¦ÒÿAÿV=öÊÚNÁ)-ÕÖ¸wûÜΣ8Sœõú<±} Àµæ;XÚè fB€IL¼©%Æmº‚VŒ²ÍÛŽ™²1ƒO69UªŸï–zšvOð’7ܰ2�Õ®0¡g…§?¶zÑnèúD7Ù_ºIdz¤}¾XÍ ZÔay]Ï´ç–¸èU±Vx[gÝz¥ ¤ƒ\UqÓmͼÊÒ3ÞòUqÔØÁÃÞZ��ßOZ°‘eü.põ ³e’pFMe Î œô{&0…• ´˜4´`ÓÞ.œxÙJ\•°}j1·½c›Öý_+Ûv»5ƒ±]¶—k�0R†é<&Lr»'h£IŒ¸oJGÊo#ë?ÊêJA£ìaQtdÔMdµX#aÔOunVOßÛd<»–¨ÛMçyߤ™&zkx²AWø–t hžH]îioÔ*é´%íôŸ�JCî=o]I# ¦k=¼R¸°�•�èʯ:$E,TF‹“™¡ãÁ Rt­KÈã¾(ú1C)Œ~¸ŽÝ`ó1ˆwN™{zèÏ@ÍÄ ‹e_¬`T†úA�>CùðDõí€L�š)Œz5Ð/úDË/YYú^ÎûH¶\1°"8p-|] _¯ ¯kÅÖá†0JÓYÄyª� (\tŒ¬l732/ÃueFÿÕ+Œ"uü(#ùìá±l† ÷¨�*‰Â5”`f¹ð¨§øReò°(vëeâ|ÊCÀU ªS+È1…` ¢ƒÐÆûNù}�”Tu¯7(2 žÙùYÇÞ�v¨Ž÷ èÿn¢cõxXF\¹O Âì»W |{ðíáä–ƒJ˰*”õ-¸²ÕÒ€ã?V*LÜ:¬¶ã‰íƒ0•’àš8A0ÆLßIÀ¹:÷.öƒ}шi]«1¤1¿˜¾·çY ^+â0Ð û΀A®S/'X�kÓ¦]»¶¦0ÐÉg²ESfÛŸ†#â‡:HØj•@|:WC\²bàÄA}OÚªî+NÆø7¿Ocà“ð}¸÷Ë�ïOïý$z?Õg·;Ï—ö?‡ú¬ãT›÷ú“§)ò¯ÜA�¶jsD¶{–^ õ*ø‹BŒ•Ær#ÇpÃÂÆ×µñ×WÐá×Þ› aø2Ç—]û~GÓ4&V ó�+bùñ¯U/+u_ž›Í]Æ®‘Q£ IDATb¡Ké>O½å¹ëÕž¬ê“&èÖ Æ©%Äõs<­¾ï…7ƒüÏ’|VË‹éØÃ\E2h¤,e>9è¹ätËáØÊÌšR7zfxÒP€lV¢c@ÇïAÖŸ8`Þ¦}?hÔ`Õ�ÔÓoÏïÞzR叨á¨÷rÐÖ qÈ;MPoÔúì/¿ÖWüÙ×ʳ YBÒŸtÒ³›]fp¿üí±:a#ƒL€µêFL2ÿ¶…ÿøþ ¼_ÀïËñŸë�÷µñ½<‚ [ë +vCÐQ/ÐË(¹Eö·µ[W”#Q‡JÉ-Y<+J%èÃuNŒSv¶Žõ? µ§ÉP¯ì³"/¶=õÊ|ÿ)³sdïwúýÊ?=FÅúÂU£ÊëóÝ(Ï}ôoY´¸ÊåꔓÕp•Q‡Ë¹JâÓ çý§ü=tþPÎÇ·3{œ“oÝ žòµÎB¿\& ¸çVX]X•dëEÓ¶;äVû÷ò¿8ƒ[ú·“5lØ�¨çœ"�òðƉ&ZÕÑCtŽ4³ý{Å3A¹ 3õIUâUK;ôµ…`WËÇ=­®XDÕZnf »u!„f½Ûmk"i´™X{\`šü÷¤>:øÁ› võ:å“÷Ù‘?^ò¾O™ÕI`„±éýœ–Ÿ™“Õ˜˜}’÷©éËÉfònÕAÛKùNsĽËÔ=Þ+†ºdwP io *ˈE5H"öÒ&솉‘c>µ·‡cÿ–ŒñIo8b?zò¢Ü?¯íó1¢Ùé‘EíÅ<§ZS~•×GÙ9á Îô{oÚŠŸ‰[ Eó£2¯¡©Ìï£ÏDoÉ1 L¶©·MQ:4:}ýDbÀo�›sœk®�´£²Ró¨w’AëLÁWÞzîi Üò鋆t§teéá+b†¾¦:$LÂ3KZ¯ÉK0‘ñ`&¼¥Œ·–ÅœO8"x°’¡vÉ›xºÎV�Ó]†Ñ7Ac&^é¸rì÷=î´ƒºm¿°§+ƒóË)«è?[jyÂq�FcJ*RÍf‘1ß 1BïiÇóf;»\0üvôúgyõGéÐNn½“¹Ø\`ªÓúsË÷êËÑÏ¡7ó¡®6þ ¹@&Ï7ìüˆý8Q�ôtvQ„(m3ÃEËŒÕ>û¥8È–\ <ˆÀ‡;§Rz(Wdv ÔYM߬Ϊ<}’ ÏÐýéú!,úؼ$0`é°Ï¬ýŒPr¥@ :0p½âóu­Ê¢äZŒ"2*™[ ]ÕN;þ# Ók¥@m)”A«lbÈ€ÅL©_ŒË%I¨lÆH§›hƒ‡ª•qá[{’­ò¾6Á%C|@ÐÕdO§,‹[ö«¢]$vk¥¯}‘Lôê® =ê„©˜u2±'ÞÂQã±_~ndßÇøw*ÅÂzIU~7j~WPÙÍ­ ü {­›þí°o~ï x¦ë»W>¤ap#Î'e†@X"ü£¼Ž�'ž®ôP¡­ËkÑù%ŽñØ¥äd¬�÷³uT4ôè¹�ÚÜEÑÄ‘k6³Yk/‰ »"0àkÇVC#0�ã$³NÛ÷s{"—��H­NU°Nþ° XŸ› ŸŠåkö‹]§";- “Õ›ng¡£L[+1>+þ,,¨÷ÏöE£Þ!iþñ)Ä‹gÿɽÖ?_ŸâÄÉ“ŒÒP¶!iˆs¾¼WÆn¡/…X⎒ º•Bé]A•3uAoæá¬-àÿe¦ô·Þí±Œ,ìØÚ„ÁhÄ~šo£¡ì#(™¡ž Ê2 ½x¶—Þ{]�Ã^犮Ñ�hQ\Œ ˆIR(â{t5×ɸ´QÙ“!ï±Z=LÓ;†kã½ôë&΋Ùtò¥cdìg·S=Nȱ ø�­8؇È9D¡rÉþð†G lÅw\'Y·W*å\Òƒ£Û"¦»ùݤ^*‚ı¬:ŒU/Íyœ¼Q7p< \Ž÷—Á¿��:pxe0Z”½L,* Q‹«ÒY–[µy­LhÿK;ÿzø"0°Ò®xÅßß/Ç_ׯ÷õƯ+dâ² _XØË°-2D+XôN¢7W©-�Õ|m¶ðÞ:‹ŒCœ‘à<:Òü6ÂÌè¾Gó“ƒ:è~:IÚ5j†›£ð9cíp�ϧ®×wÎ=ú”|R_É©ç ôÓItÊŒö¯>ôãø.‰çI/)ëS&5-ÓYÝt:]ß³ìû§€À¼N™YMÜá? ¥âí°æûÅ8$Xì5èX €<ÜwcåªTn·Ø"0ú‡ÑrÞ€rHÈLQÁM3w& º´L'�>âÏ‹êwê��§íFØÒ„K»’¼W ˆ}ÂŒè�qkà)øÒP[Óù·ýRUrÞÚˆÕ{›ö�{™Ü¤³û5ÀEÙEŠ­-ñÈ,a“rÜî«W¤­“žoͶÞü£&�6‰†6‹>ø>×E}ª+FIŸ�iv»:ìšu[Ñ–�±Žüà.qÿ-ÏY!mï ¸âêIË­`'ÇLš•ªž(£8.JªBQ5rÌ³ÞæÃ ·Ã™‹°†Ì˜ÑM¾¨ ™ˆuåÓ}àâÿÇÕƒóÌ�¤HúPY.ÝÀq d<-²™v¢8£ ‹˜‡OûñsŒ›ÞK ýóÿ•��+Wš8 N”Ïg`à ÙvÉsí‡IP@øOEtyÿ —U©:ªMŸ% e�–OÀ OLž(zGújêMo]“ã_¶©\4Uwʱ²Ä<Èé«ÉWè¶ŠÛ=pM÷Qa$ýæ8y÷yЪ[åoèsÑïåžú)…9Í`"{=9"o½°7vóq½'Ä8œÔB×5ÖOWâ×�ß…$l„¹ûì4´_0Ë•ß]Ú«Ìû#±Y¤Šè|e4þÙã½›½JÀt\0È‹ô“ÜŒŒìrÕ¥íºô+Õ™4ƱwÁÇeìÂÀæJþ%+æ‹Q¼ÀkL™Ìdô«ϲ_÷àüèâçG ƒË¿Ë<è Ä(87/¡ù “Ï&»üÿí"ßÝ.!†×+·è‰lýUŽû•Žô•Ù’<ËîuÅy¯×*g W,CìIë¹$qpS\ XWêü€‹+ èCeŸ£l)X ýIÌ©³¾ü˜*˜,™eÅļ e¾ZÁ‘¡dÒvËZa›)4áÈ­†TP’1 çýn•Áp%8–¡`S¢ü@#ƒÆ„+#¾²7Cs¬ À,³MwœxÏú¹ÆyõYÉ}édQáHaˆeáTY�„\QÂm„Œ+Þóoï<È1ëaÆgš”ìê¶ßÙÛ%!XëzT »$×òM«—'D•ý°kJÜ•aÌk=Ö¿eàÒh§ €Î†@‰‹}ÌÖ¾\¶b€ Ës¥ƒîɼè(~ò@íwG„qLtû¬µb‹#¦\¿¸J`u ãZ_ª�þ•¼; ÿé·Þÿ'VÀãú�AoOìñûÓÛþðäŸöþ_CÎxÿÞ�åÙ 4°#M”œW‹W|·�0 SMD“?®ê‚/\f°+÷r_†ïmxïPÄ‘³9Ø ØÛû\œÚ(V¦íÅw)Z=ã÷Ü+ÎÆ @ÿ߇‹Ü:nL�‡ŒO¹b€n­2GQôÖ�I¨m,�†‡¥=ìí¤¯ó~ 5y8¼Æ.l—z�ÍÙöôo"×Ä0kgÖIy*k;80»vëòãõ«éÓµ�8?Åë;é8V X®~�8¬& ÖÄëÒ-Ó×òFA@ÀîÀËc 5ž½rå€dßÚPË:—­ŽÖc«áabÁ;Û«±n‡´{.rxû���_†¿ÿ2üõ÷Â{Ç*±ëŠíƒÜp½à¶°Óá¿“Çøý{;¾áÀzG‚`W.b3|¿e¾ƒ'Þæ‘qZú;Õ¹ªAS^Da£t÷†ÿÜ’çf;רªƒÕk‹œÇ,{ÂaÍ~Í"êø~†ãß_J„»ë·Ò äÃ}¼ÕÓéôä0çýšÓ±yšG3A’¹,ïýav5}>©Ù¬éà–'Ç�É�©Ù½‚[Fý�m©€ß"™BꎭªRP¥½º@:ŽÜwœQ#¦[ç~þ¼³wVHwdö‹é(:èsãýO^#©(,ÜrúDs]çòDnˆ —)Æ�Óå�AãŒ+gWŠ—Ñ÷œRÌË9üÆ�LoöYõÕoO«½‡«ÈUç`UMõ“ÖP²ê_´.Å÷Çz†Q.m|·Nf¸Õ–ð¶"�à”óvö(e«¼gǧq6èåÞO|{ÿ¤Ï 1Ë$妵Z)�öHg@kŸãoš L:†w6<ƒOì­O¸lÑk%ãÊÙ|`{»ZŒu§aÌç.U<·?ƒ%C–=è¦4»àü¤NOøOˆÚÙ=yGë +(¹§+Bn¾F©“cÛ‹):d§"æ¸h—{—™‡Â+‡mè0¿kKʧƊÌ¢DNº&Ø ”l•úÃñΤRS‚8÷ûwœưþqY;ýÛæhyÅ­×,'aáöhy.rpè­eÄ�®A®t üV‹óžpA9Rá2¿ã8q÷Ëž½³?¡¯<Ͼ¢lcŽ¢¼L>W,;Ð+ ‰¨yQ!`ŒkÞ,áàöðî-S]ܥþI¼¡ïõÜŠÆ�0Ú YÏ&ŒBv� ±%Vḋ ûôW‚4›nù=£`PF1$xÛAä??úÈúéÓ̱.1Îm™Ôø1}ýà³ó?]‚¼êž x~±òÚVÀüÜü'Pÿå=¡«û¹Ÿ¯pУ¶ñyU6Èåü7²Lmû£Ž’ƒ[c!D쩌 4ð3&G `­…k]yà):»pä¡I%Dó4H02Ÿ�dÉH”¢ŽÊqHP¡³æ>ªÖ*—ôŸ?D$= ¤d:S&sèø¨sB.KÂcö|½¦©1O¤É nÅ4‚uJëêµí�¤)'±Þ<'>ßT&Šô§ñP¼ú‡2Ÿ®Aÿâ:Úc_ C“ên§T‰Ïýaa;îšÐúI�ÇÛˆôm‡ü±ýPqY6•#þ[tʦcd‡ù¹RÉ…W¥êHçG3ö²W8ì_6¬>õÌâô ÷HÄ6xÈ›åxK`àµïüóËKxZ×åqè}êª×Å£2<åÌs±3t"Á.DP šiUUp±ŒEºæíÙñy°Dú®)îv:y·U‘öC�¼—$N©Ïb B0÷vªyÙ|Ì"e¸–Ì-Ä=êñ&=¥éŸ ˜®Âç êLÒáÏö¶\-†‚Ñpa[V_ÂÙèÙ'�Ëw:ó‘ê?äݾ�«§‚8=W ”žÉí,¼¬^>sæ¬t¥—?eýr§­”ÛÉ÷e`$Áý² ïüþËð÷ßç8ðz§#t]°ë¬…�˜\¾wèáïüüý½ñÛ7°Þ¹2-ÊÓ¶ûý üý¶ìMâ Ï >pÜŠ†îp`6N¹BÁ«Ä”¥OÎüOŽh'}ЙàA�âKÑ×EÒ´·„\gFü?ƒ¡a1�ù«¨òÐ òç•ý¢|VFÛ *‡äÞ½£­vD‹MÐP (ˆµfói;ëžö ªoÓ–„ÞN8ÀÌ»z¯qAµ³e º�¿:ÇÃÛ)i\�C…—ÚcT–O+ÛÓ,CåþîçÖ`ý7 [¾k=5>û—ø‰È ýݱ:pgÇ“X5�{)Aôœ£0#P»ZdïÄÙSãÔƒÀ¹•Ì'ºv`u¸òE§Vç6[MOü}·—h}üIÿt=“€S6Ì2 ¯´aóÝÀ€�þý³«yƒÕ;¬~D33^éÉR7}Ü.¬>a1î7¿;RuAx.¿(/V¦t>saŠGš e`À@µíyá»û9å°&"ë'9̓“ž~Æ+*}¤p¸| sú(¾gÚá–ÑÑÖ©¤È3­ëZ† ´¹'=LqÚ2z~†Ð¦oð Œ5)":‰�²¬8@$’¨Ï®)_—œð9ÆÊÐCªÙÄqé¯ÖˆmͲŸ½rÀáé€d�’‹ÿ;“(µW]‰@‚ÚèTqi›6bòMÃ0ü{¥€ú™YÞ=·Bu«¿ÎàGÙ÷^(í? ³Ä[ø™ñ·¶#X0´y«Ûk ¾g¼Òä©K=ÚçÒ˜ƒ& ü`‚x^7Fñq¯È«ìˆÔ‰²Í6 µù‚ \>üPTµ~`Z£SäU›g¥k�#y�¤¨ø„A©D¬ëžc‘ºžõ•,R * O]0Ø|†~mØŒbh8õ_�HÝ—[CV•?åï>ݞ䳕5¶B:iÖY¾³¯§ä=låxWÙ¸¢MâwɇBv}ãùz½d5À•KøxÎï-à2ǦËV'í%1¦€ä®†XÛ™d®ô2<3®(àïOàzãð úI|h‚!Óå;Ã(ºô‹¡-³Äÿ*…˜Â?¤ìÖ~êþÛ1`0ÔYÃòO®Bð'…ý¯êÿ§0ü7ë{¸ŽþÝÆòÆÿ?eó}¨ôVçç«É]V–ägn#S:ŸÎÛeáAßžÏ ¥ß$­z©œ™<bà¡Ðc soAm³ 3ÇeW�ÔŠ âÆ.ñÁþ“¥Ž,ØWt#}ªµrà6v^:.ÏÍn�7ÅF¶á=L®4>4DÉPnµÁÃ([ÿµñ«C¤¦Õ:f¤sˆJüÆDŒö¥à›H@‹�/ݸ…ÿsüJ´nOÄõ�”û5å� zÔx<ßûéùO×�¡êƒªªl":Ó)÷x~ÂÐEjðQ*§Qê= v@W°Á壢BõT¾‹ÈŒ»aQu)™“Ä‹„AÏG3ŠîqÕ€×ð—/|¿Þï+=^ñÛñBdþ_±bÀ‘‡x¾ß¹Rà‡™ãeÀ¯ uNÿþþíx}ÿQ¸Ý«B‘¨>M-gβd½üÁAÖûòJ�«ô´Ü†tÝíåüïI\þy›œO0>õ)ÇÉm´V®í™z¯îÖü\.}ÂåJÏ’��ÙÁm>Q£ 7ÁÊ)ÌìÃ%xšY“UÉ]SÙóvNU‡�8êÞV0bôÃÛöðÆøÙóJ‚wÒÒßÄy2W·.bÏ¿3°Ñ@i=‘Ú¢Ô•\ÁP±;ƒX-‹ûëj—9/·l·¾!æd-¿Ÿk•ô²ó—ݤüa·Š4§“‘Ož†ùpvÍ–Ve ÜG»ª¨ g«q×ÏZâSå½}ûéò‡ž—�ðS‡½ß”·™Â8ðU¿ÌïYµ€•3µp0h5:a¦õ4Kl8¡¸[1º� ãToèªúã™T;ø˜uÛ¨w¢À𠘜i3vˆÝªŒìº_Òæ�º‡òEöãj—óq9¸±lU|+)´õ„‡P'ý®Ï×꾡Q<Ç™ÙõÖ¼â”ml@Úl¶c¬ü\Л|‘÷ºOV2®ÆÂî2�o¶ÛFÞ²Yø6ú+i¯MàèÏ}D¨½¶Ã¹¦—Œa0ÅEê±9ølŒ²£iñÁñ¸É+t DnàØ¶ž-pÅf™¾Žô焾X®å›ß “üŠC}W¥¥öÍÑ:õ‘úíáÖaGŒ ¯ëê�þ}«HÅîÝ:t”·¿úÎ�b$̤T6ńΛàîïYÆÂ¹v¼oó}.5çêcÌw•uKž©ÐL†�„$ö—íE§{LJ‘$j¹ª M†€—~ÒŠe”«êå{ŽÞj¾ºê�ÔÚ.ËæJ ȧöÀñ ù¡p�‰g%îÙ¼ï.“sy6”±Î'‚üï_¯¯+Ú[*xÉ8‹”°-xŠ“45m—Ør\/àË£ÌÞà/\—áëkã{_p¿¼`vaçÖ)ß¾ñýÎUßÀ÷rü^Àïåøº€ïW¬³ »åjÒßÈßúÛVdƒå´yž6“ôE¢”IŽEO:”¸Í»= 3(à;¶h¹_m<}:ÔX¿ŸÁ�s¿ä²%ú%ípŒÐ£è–zÙ×›óMl­ã͹ØANÚËrbŽlê"ýœTŸÆ`Œ'³^ÁQÕ+eý&3Pýþtîà O‡ ö ®©×TŸmêÔ‘�מ…2—bn=WgT€Eq–‚ÂêL‚Þ’òÌr­¼–Ñ q�æóíýsKo}ÝÔ“��Á”¾a^P®S"" ¦ÂË®“×DÎv?ÄžH]eЗî×9¦ç˜Ïk~ØP%^)MËç¤ß ‡–YOÍ}¸Îé3ìÏs[|Aõ�ØM^³Aq?Àrk‰8L>žs«¸€‰å¼Þûè#3%•E> †‚–vÇcÌ~–1<²jÀ0Îi'ÌlÓÁøñ:ˆ¸a†u® Æó3P×¥BwUäÁÞæ{O°Ññ‰;4È*î…Gš>tƒÏï`Íw!cåÔ#Ã'/Êz§=D\vr›|RÔ8»ÊV ö�3ÆÂïå†NñGÜÕ;µUÉC™Äí†CX0ú+«Q8~ä�…“ΖۮqÝ'�»l�ì�=,A{PF"ÜÁ`GâN.°… .’…7u§#ìxÙº&VÌåzM�È¢)�T.{¤8]žd‘TÙ2­DStöLf*¾>õ{þ§t^s“Îߢ;MdÁ¬¼m¤Ùàè"«Cí¾&´`-Øâ–$ ™¾+6Fý^Ç})o¢ íà£YŸÊÉe¼×‹5šnݳê7ƒqmqåPç*(›¢ðTE©Gnv…¤Ü1Ÿ”l�y]‡ð¢í\™aÀ^Ãÿ'ꬕpÈÆD'ëbYî€{ôÊ¥¬Ù¶ì¾Ê€‰wë$&Û!X�>×ëõ +£_ý}Ö‘˜ßJ†£âk�£D„ Ë̼¶&2þe+ï3¡{ú·uÅŽ¨‘u �òò;åeê‘K{žæ‡?á«ö¸=&Pí8€{;„ðAäWŒùD­z¡Ù.ÝQiE÷—œ÷óZ”B¼<_†Þ‹À»�øÙi6bßy­¬¤F§L~ã¯r-p4;«ì�bâ§?Ìï²Õ ¶…ø^×x'ÀóC@(º¬öÑnóìÿŽ?óàíRk7‘%>½)0,Oç‘ 2EàXß7h®u±>æÕƶM¶/ÜH»Ÿdì¯)öî÷ÿM¼>HïÿêuJgŇ}ÁŸåã£Ê}B‰:¢Ry]ü„6Ú¥TN¤›-ßõOۥ̖Éõ"PÌBž”±šò)3é‘ÁH÷ cà2 v %u]³¼�½™’¹Ð�î}E=k!Ï(è,"’íe½‚ne` ê½YL÷11ÊÊÞ󹜞¶ç’¡©3DrµDg©lÐ\q×hxÊpw ÀvOdrÅ1ÊL‰±³nƒ]Ù.A>°¢ÅJ˜QqÐØZ8qùoøñ–%=J& ‘âì|®tñ½Â‰ý°‘+Ú¼ûx´©s†PÉ ¢f{̦¿PÇî[ÂWn€ª^2ý qŠÄ|º�A_‡[ÓBÓCÖk€­HÐx9G?Îx}]øõÛñ~/ì½°}OÔ!ÂoÄ™/Ã{¯XA°ó�al}ŹxaÛ…ÿùÛðë?†—m\XX™æ³ß†í½=‹íèé–¾«½°p7­_¯G» 8�Óç9�íßgñçwË©rÀô|ÙT¯ÿ `Öq=ʼƎëó’ý„VV˜uÒVÊ€Ê1c%TžqþϯîÇxŠ£P IDATËÇã£üÓØËV|À•�­™òÓòÜ'Š—ÛQX©ÌZé[;öÉb2hÜ3°ë;FÝåLTv¶qY®HýÆq~!Pþ„í ¿xßöXí7t¥FDÎ�K~ÖüÒU–Ôn(Ò‘F=«™½SW[=#¸çåU_×&rÎò—ûøUð x?WvünùÕò¼ëøwSÙè‰ÏSööpç]‘œ~hÉ oÐ {6r‹RÞZ:~EH'*«zév|ÈÐÂîRBXŠ>ùœ"¹hÐï2‹…¦Føtÿdd“÷O_Ý#æ³q‹xü˜‘ß2q¾åŽÆÕfÒÿfâÆÈƸŵ”ŽÃrÔ™HùWA³{F‡Ï“ç lAËíæ)T`¨‰ä@ª(˜áÿlÿìºKÖûõº®`tnã³�Î�|¹€—áZ.°Ms¶Û=ðNü¿�ÎÿËf`aAV ö(?³Ÿ®“†É€:!<ß_ȼwÓ’í)“åu/P­b,ûªàÀÿbG­ò¾**êå=‘¸s2k³:—œå|%ýߕÕKF}HÿˆSÎB<ïíÐ]àÝZ}@~Ç|%ª9˜DÓ‚‡wM~¯•Átpà‚I¤ ˜s•ÀÑžÂs«§ïO½ÿ'×½½Ók 8ŽR*'¬5 K «ü=³fƘI`@qÌHŸZw[®£�ùìG¾ƒ�»âþÓõTîA¸ÿׯƒW Ÿ¿G¹`�÷fŠá½ébwòõ¤ëååÉÐÏI+¹G{+.1ŽªM !KG>’$¬2 Ü(3s•¾yvn¡À¬‡e–ñ©Èl¶ XkÅâƒ2p ÜÞÎà•C;…þ¹VogÒ—ƒ½sõœ)BÆdà éùìA'VªÀw5,)Ë(Ò‚%Z^w~(ÒÜÝ�  ÀØñ�m9Ðçþ°HycLç‘ИĔõ©Bš¿:Ñ«-!ìöF{ÿ†ÿEY›Äs‹ÀÀ£ËB¶M‚Âár­Ÿ‘k/Î€]Ö§Ç$ÖŽ`º:tk›à>Ë?ÈåAôKœ‘^¹`¨H×)·#ÃÿÂëká×_ŽïßÀûmø~ç9;wÜêGÐmïñ:ôbŸ ƒÙ X_xãÂÛ/üzmü×—m,ß°mµKÓ{/øŽí'Þà–ZÜTÉÅn Æ ¬œøsÊ­Ú ®B$°)A:Õ�Âü?9üÚâæ�m ;o[Êà œpöy ŸaìÕκ=FJ·tˆÎ-ž>ÔsüèªNChÊ�›ª£Šø0MÑìzÂøLŸÔ™}z8«h°[†–©vJúFO„S128w4Öpªð�ôCà³™¹êe»µþd»·�œA…Ñ_Ñ×õ,ÁŒÄ9VÈ; èÂéãë'„� Àm]˜ûœãÔ… ôC›ÞˆüÞoºŽÚ°¨OLPåf}Õ|ÜðòTî“>¢š¬FÄüºÉgCÏVÅÐÛx�ÿàr—ýñ‹c¼*›Óx®êï¶z‚��¬-~æêt1ÿPÞ€^eáçØ…‰©åg|k��ôVþ�;/Þ*{eŠÖ�S^Û�^úl�ÓG`RCÃÛÙü,´øô)À5áAòO¯¦ÕšuuÌùü\à®vrô˪^ušó «Â5uSG“ڢͨä'z.<|,`txÞgÌ™ï!ø¬WL:®Žü¦‹{Ÿ´–£ì‹ŸÜªVñ–¬?è,e&qëh³¯GVp0Mz?^92•‡V+3ß©870c» *ÊÅ’÷•¦ø:6rÿœþ‹Sî·iζxm×O”œm�ãcC›âò„_;QÆ›>êj+ÝB>Û*­Õ´.¼U:*H0Žš$ê¥pûñ)õ7‚Žwµ=MÄQ–/ŒA>’õÑ·º< ª •²£×¶}ž0 úèðn"rx&€;`[ÿÙ§š—¡ܹTe BU¡äM ú˜j �%!/N¶‰_¦ïP–ó(wGÞGðU"þ¤_àõ××@¶L ±Î´¼–HŒ|Æß•0ÂBaï­„‚Alq¯æÞ6èºt°œcšæ%õ4ÊâÈìè~ov;ˆ' d¡(¯Ê£�'/·}à÷Š2iìåb#[Àèä „c ƒ‡`,¢Ìk}ÿ€ÇoðI%ìƒYǼî²X5@‚L§r|x{º» ÇÕd -åÅmP„“öÊj7ðZXûªñ°ka½Ö낽^X¯Wìøð÷Z±­ ÷º¿Ð+Äá0®S(ßÈá80Ü&ØAŠöûÙ¨~\%o×óóã^—i½{Å.m Ç=áÎÈ iÄ}‚Ùíp B‚pS ¸  ¶Ýš�#ó|¸¼!?:z/û³üpý¯^:Þ?ê /®üù¾ ‚ZÞ-øËw!,ïs~.CàNùÉï�CŠ95îEÛ·1N�e´ÛÙXbÓr_B[£¢Ø²Œ ¨ƒGíìûnÈ•gÁËçÊ'O¹³Ìê´Gö΃µ3(}…qéIüœëºæÜÒ&&†:..æKà4¶*ñÞ‰¦Ò†¾93b¸-RdS_Ù83K—*ã–Ò¹ †�ö£Ü¦Ü`Mâˆ,—ÒÁFØN‰ãeÀÎ�rÎ3¼W”�•"—Ùÿ•šw}ÀÌbpBûrKFøÈ¸´IzØÙß�ˆr¢ÅTUòÃРÊV2ò ÄJp{ªÁEw‰üËo´ø¤VBMó(áç}ítâÌ<ɧZ ‡DœŽú]àãš/m›´�þPhùðôûðUÝ¢–/Úq¯„`b/ö£Ïñæœ=æ»Ýº[°ËCˆs›×šÜ'ïrÛzâȳí�«12£Þñ©7åoœ­%<9A)¾ø›:í‡0C-=gãA ‘î(”z(SH0󃶼~½b…&²]Š$Vg ¬ÕK‘4I»·÷:`˜�îì{–p­•†3‰èT�6è‚ nÂîz{aé� ._Æ�Tƒ»Jº¥7ƒîeLÙ5Á“lýQã¬Û%o`½rL°r/ãõza}½`áyˆ¿ ØÃ'î+ FçeÔM3\’>$ ÁÛC¸‹¬êÞ< w?îêóy ã­ìçz¨ùvŽ�c7+M¨È�*³1ÞU¥øÓÂOòG;¥´3Ê<õmhüØÿÿõ¥ü}÷¡â¨6våŸ8ÄÄçøÄ3^�– Љ»òA¼ñÃÑæøó®ç§1>» †#)ä|p¶hø >Úåð·ÇjðN£h¯})U[&‡4ö;ôÑÆ‚Ábo ,KJ üìý.EÞàg¦¦Qà‰�ÊÂ+¼G¦µg»§�ÚY�žvƒчR˜iP…ø±i§a¢šýì˜Tçö+¹ÛÛñë%œJ‹t”q¬½T�ÁúÀø,{z‡ D8.¤�ršŸ2ù¿q�ŒDàHƒ¢FS÷Œ?ò§óµ„1WvÔœ�ÛãT¦Œèš ØBÑmøš²þ��Š.Ï•fiÅÝ2Ý+œºµí–Û¬Ð�wŽ+W¼�÷·ãýÛñ}9¾—ãý½ñ^¹�Wú‹ÖzøzÁ® X_Àzáûmøý^øõµñë? ¯µðºVØ�p¼ ø_øÞ_oÚó¥oÛt»k;c…–YÖtgk¯átw©ÏnßZ- Ÿ�ûî÷°=ÕP|Süw ²OYñç­tZgwûVreB–¿’¶¦9mò,‚”%ÚÔý<Ë@*ù?ñ¨æ€s\„w2ðÉ^õC®ÒT!T–eÎ@S›ô•‚¨ÔëÞx3Ls•ƒb ±µU ‚²µ¢��žKuÒΆêÁǧÆ%K*½<9zÑh'tùÎÝ¥#·Ø6,†ìTÚÏ9Ëwª�ÖX'HíSƒ&ï—¬8ÚPœr¼êTµBå#Óò��³4ñ)ó&Ê÷Ÿ¦M?tè¡n¨oe@úT�O«>?4y»ª[Nš™õ’7Eõ<Öá2Ž G�‹òuáÛžûÁQç§M9ß{ÀU”øä’—þˆìyr>áüì_õ‘j*ÖîöØT]©ù}±Ü§A|ðáž�DžÌDûŽ¡à{¸7iT¼[uóŠ ™c3(TzR²ÍSaoðä£çÎÝíäž «ö~õ‡ï†›}®¾ÓÀѺÊ?ÐÆl?ß4‚0ƒŠ´)48 ÁÔ1ÒG*8@ÅÄ2~�‚;l1i;ºÒÒÓ¤.nPIÜè¶éåZYõb?à5ÔàQ1k÷¼ûYpg'x®¾<ñµ5î(.<é¦Þµ¶Ÿjû¾cĆöú8¶ÍkñâÔC³Nå Œz tÇÐcß <ÊpB H&e«ZÖÕ¼0vAqù®ÈxX9ÿ¿!s¢ h¡zÈ•ø.uœŸI�þNíó=2XmQ—”?ŠLXý”ÂÎþæÏ й®ÔXY€¾ÍÓî}ÌòѼÚbSö÷ŸÊUwÄ2YÑÐã™v¢âCH(3ý‘N"<„˜|.ÏÔκÛL÷ëõëë+^,$‡Ó�‚b]½Z€ø¬• ½=Є*ûj��û_crvƉ¼Á|üߺ!wØZ=!ð¦å–.2’€)ܶD…‡‚}bŠ)³"¾1øèt†KYõÐfn›kKù_í—¤Ÿ#©Óûk'檸›8xR¦b€É8@d÷¾ÅV_“rÍP§X_+·QÈ,à ,9qàá`²å°wdŸ¹mØ{ÿ߸l5d`a½ öuÁ¾^@ x-¸"‚ðüY#Bm–åЀùc‡L­ß6è÷ãu#Ó'õ$ee@]Ç’„Ð^�!¬| ý�–Šx¬àPç÷(3qÏ �¬Ëj- <]õ:3ðJðIO…Ì…»n8ù€yôü®ˆôǺ>b]&ù} Þª^uÔbâŸQã-ïòo7î[© S{`³V±¬‚™:CÛe–w91‹´ñBC$ÓÖ6bûÑ¿Ñ}¡|ŽáB {mjÝ–“®äÙu¥?³l¥å]æûÄ …ÛÚg\m°`ëâÑÿfF€8Ä4­û:)g›h)p:&Ò‚*òPå˜0Ë k[È/¤¸õœ8'û–žÌF+˜Žy?„j¾À`ƒÓò¶­2›«lM‘O)�¦„6©}zºJ­? -oð'qøO¯á;KHv}ÈÕì�~Óþ ½©|M½. U¼^�‡Ä=�ûèæDœà¹%+”ü^O�“¼ä\Þ«²?V¶‚”])“ØÙñ„Ú ô{zldV«mí ¹2·iVoLö_qÓýÔï�ö§¾�†Dÿ°â)ƒG%³QHµ~eÂ+F¥ª™Ã—¶Zuº(Z@y  PM�'ìèÂXöši)ôÐÂeê¨^ùsØ|~§OJÿ»øÓ‚´~‡¿Pe|cH–ühùR[³�ô7ê�øf2-4œãGSS}/�ßæž»7N\–üø@p I §1@2~ܤGè—‡´7Æ"PË·Z^¶^ïÎwüÔJÅ¡à@NÓ\îˆ 1±G0ƒà<ã¡åûí5†Ý‘gÆésȽǀ@ާÛZOjîc¬®nyNp„Ž{{œ¹ƒ-+ øn•÷ÂYãÆwBê%7¼uuÝ7Ô1‰ }�«ÝIv&hý‡ät <¬;ï¨ìù'í ¬” [4eš#æx;K耲¾ü]m•%ŽùŽø+ Â²»ƒ<£;tŒ³<\R‚„“c*��J:ãØ¤¯4^#¬Gßk¥À”_0[»¢pY—4B­¤b\蕺‡ÖÚ±5k%ü‚Àè%†t@áŒW:¢ý+~M´H‰‘´ÍP¸uc9` ¡¶vÓ?†à ¦{d+°>öñzýúúB/_`–”èµb€Bq÷ð¹Z ¤y¶½Ò¹KßlHðº”l¨Ô¬ÊOìÅÆç¢¤#uœ :óãc,"�êç¥mŠ@—AÒ}éËé™ðšT1±—ÃÕA†£%š‹�Õ.x½ß÷}(Ë®ÏËQ8ÀPGH–{:Ú‹AøéÀé<¸òäÎÚRae€€NtN ì½aoGœ°�ïwlùs!œþ ³q�ã×ûõ~1(`¹õQš“Ø(ÐÕG`ÀœÇõ¨ÀA¨ÒØm¼&úýñ)ÈÓDí_\Å�ÊO]ž¹8tQôà'àB7Oº ÙŠËâØ—œj@`h1ép)¨VG:ÃÁ€'®OÝÿ¿_“‡ÿYyüðù‰|šˆ¢”ŽuGmúZ¸·T€|ŸÏû·×'î ¬¥l�?ØŒ@Ÿà늀S–:nA¦ÛûtX`Ñ�òžÕó€å7‹•f€U˺�á!²DµÀ]xÍÕo+®+·®[2ŽìåXï8pµ'‰_á>]¨Ã‹³ü�aà·Úkv;|7S®ÜóYñÄI ­úÎPg°ÐŒ½ „00°VÎ@¼Æ´ìÕ‘õMCâ¤÷ï}x¤`úp�ûsöÚÿå*2ZO}âWÉ–©%Ñj¼å«i]ˆár4Æò Ÿæ¿’‡„çL‚uœbˆršÚCõQµ‘°®[nÉá? ¶Uù•ºêÐA�\8gq8–ÇùnˆóŠnãÕuE`àúŠ@=à©öa±Úàû{ãûÚø¾€ï—áýZøz¯‹¶$µYÐr;O£†ùÒ~ål%Nj¥ ߤ3D'¥|Oî�zò·¾ÿùšºü6©üpéJƒe¹ú ÷lIvô™/¨?ç³vê3(àdz”UQ¢Þç0·³P |¤ì2ëo§B“»o—É 3èvÝŸùnküÒŽ:.o¥B�ËÕî2ÇÆÊÕeþàå|hááµÒ<¶z[¸.ƒûÂå+ÅiÇ+óÉ2=î¿Sev†zÒ)WæìvZ韪ÝÂÇÔ=&��CKŒX¯\)'’/Œ<ée–)ütFM�Ìé¸éü+Ÿü$ÞâþÝÀwf¨fóŸPNI´¯÷œûNÛ™Ü>à%ÌêŒùóåýùP¾a‹çœ6W|Åê¿£vÿ ŠòÝ¡¼�GLY�¾�2-�}ŒË7ac’Y­½—Ä—3ÇíªXƒRõ£>Þ²9Ú6©cöàc�—ø‡õœÍ^Š^!ôýÇ3!íëx¶¬ºþ“;fÙ“oέ[ôõžåÈÜW¤5O+l[éË$™ÇÒ¿S^¨Žµl‹ÆæÔn ÁèÞø…KÉ ›Òß-µ^œt"AjÚØÓ­õ8«ncÿJ�(:äÎùäV|€j¨ GH^Y~ö§¿(Ñ?Å û¡ãE” € Ž¾MµI˰—Hä�ÀzX•2¸C ‚ã\rÚÓH©*iü’bH]�í©ß|mŒ3Òˆ–ªÝ& ê‰<7!— È|ïAj‰ÛëÖxn¥3—4ê�xÝZgDfpO˜|"};ÿ¼¿kçéOP{«pr¼óñ:œ3£ ‘Ót ë'¼ýw�þs~¢Á½T –!©‚Ox4…_wm®RP<.IßÖõ¯Ltâ=&TÎò_5ß(:Xyqç‡Z Ð]”r&lŽyžwרö¢8Iζ=ñ¨Dûì¼þÇ×ëëë’N%Ë—–ñ‘鿌¦„פjÙß‚ <ƒ ƒõnZe€=]ÅÄ* “ïDBÓ‹8½i˜Œúj,úY ²ì!ÙºHÞøƒ™DÂɪ~~`ÜŠªå­�¿ÚˆKXw³‹5€"ÀIøñç`Ëd‰ýŸM´EZ‚¾"g›Á!›”N/Bí9œA�ÚÊÇÐÛ*XeR•*x;l{¦gmøZ‘ü¶øãµ{!_¬V Úð¹¯UfGÙ\-°*…4gwý©dQRðù¾Ñ5þ`€DCÿtý‘�iø(m”#3~‡ÞñvúW‚íE.CÈLwkÇIuÑ¥} {+^ðÄ�’+ ¼ø�Ç)æn$K3éÜétÅÿ‹SѾ=ÿž—�ï9%kø€ø„à=‘´¥|:°c ¢c¶�aµxò½wÝåIp…ûäQ³r {¶MC£ä‚ï~—2…eE‘ ¥vÞ'h†‘­¿ÇПNž#³™¸ÍIíÜ~GtÂqU½¹%g;º©s‹Ê‚~s:Ë5À3ê×ObSuGßçí”"Q.m™/8jV³ê5tïW�Wþ²W%ÏÕ’—8ä¹·£téÞÇeôýìhE$M¬Ð£{烈rV’§œª„27\ˆ=Ùì¢,^q8½�A¿õ…ðÝiŠA�pbíݶ�Sðô¸R‚÷ø)æÈÙøo®À ln¾‰ àå"íÛ?u©¬ùàµ�ãÕ%ÂíõÞÔ-ÚSÖbG×z8®1a†ŒË°F‘‡a{¼îe§Ü ŽžûÓsá©ù¨>?·ÿ`o|‚PìJª¯zß‘vI·Î=Å}àÂÅ$K*¢�öY5ZýÐ>IM`Çp �6Ž–<ûaE/“QuÝä·Ï‚Oo:bÛf‚7ïÁ-�†æx´þeMú-¶¼FCü�ž~=‡{œåä`^‹<ÃÐ ½Ó´\ÙÙ^0%8s¬ycÊ=’™™€é“Yä¼A3”ÈÌô'ÜpLz¥�g’Î=8`-£…ÊÞ+ó%qrØhÅ"÷�2ý#?xƒ( ߈ÂÚF‚Hþù'ª>.úÔ�Ø´t%ÍOIpqÊGHð (O8ˆq¤�Ÿã:ù¼Ákóu÷·: IDATtú¾J! lJX+ü»Ø=Ò‡œ÷TR¼�-ö¯Ç¢ôté—W›á95u*ý°Mf>ŠÔh¹Åko0|wxì] пyÐ Ü#ÙZ*5E¯ùMÖéõº®k(àrT´ÔJ‰Pz Ò°nºì¥Ef€ñ|0ìûæo-Â)Šž8„�-Y¥QB!™€Ù’tp©òÄóçŒsŽFG–t}Ñt*ýš°¹×†cÀ #T‹àP�ä­mÌÈY]¼¤¨ ß”4®‰CÍ™¹5ÕE8Û4±éÔðÊb]}Æœ°t ½S030` ¸2(P[ø¬±×?÷ùÇñúÔðÝ�…7"0à©”â@dž)ðZ¹ еY…9ï¯c NçtÉgóÆFñ¬NÒ…zÙ‡ïÿøból¿>{’Ã, :“ç–-ç{(ök/Á�Ñ! 1. ³ñî B]6¨ÝHZu‡(S3âÏåu¾:ØB¡_�QÜ3þþ÷WI˜ã÷?¿";EpàÉ26ýé `‚/ËÚîòæ„…2MþfãæzE^“(Θ˜£‚8Ž-¤e »î!O:Q"0Ù]Á­.ë]Bà´–�/ËÀ@4r†ÙÊy„vº>wvE'~I%�-Ï3rB­Z±Nö8‹à�Û²šã*Þ°ûáD U>¿WCð·¥hGû¾k%•½‰¿pº]žº¸-åTÊÝÔ%T)fd ^ÚÑBvwÏü�dLÔØadèU,®4:Ÿ•žž-où%dI‚¢ƒgVô߸¨Øû³ceÈï †î#{³;¡sé…¨�¢Kýºúåfš´=ˆ%‡·˜è 'ßô޾ŸPR f^!‡Ì�å+ê³Ôï%¨ý/¯çBfÓä •8´þþÆþ~ãýû�ïßïßßxÃ÷B�gÇéP‘^•4&”fű»l�Ìôr&›ç¬[œÌ6ÛÑO×}kùã§•ê$æê‹Z怾Z›n:$“Òå§v³¾Ð¡]–²¬Ëùpò´I<£h¸’ ¾µ<Û$THâMÆ“ãìd)ùNhmýˆß¶ØBÍ+eal6;’¶*ÏþÀé,�U`—î+¶í"û[ò &ªèDeBñVôWtÚðn=Ëõ.öKîÝD¥îõö¤ÑÑ&ÛK 3é ¹zNꤪ¾;;³`:H&͘¹_ÇÔOÉÜÆGñ.&ß(¼õ]TNž}.<–Ü$]³Ã›(ü™ïІüçჭЫO²k»ç£:VØþñÕTÚêdVg[ÂÓÕZ„p.4XóŽ·–jÔeÚ]¡¿’ ,¹ZÒž{XI¸Vµ’-fä©ùj‡]=Ÿý¸O±½è%žÿ™ —ÖAUÚ�Š“?Õs¿sè†Vmx¤/£5a�ù?#eZ|Vö|1•$k$>j‹âË¥”u ˆIS^u€]îöœòÐ)­²pÌQw#JŠc,]¥h àãqèGo fKË&âÝÝ‹Ç͸©„è‹·¤¢ÞT¼7´^@r ^ó¸ 7 ²^�p-”ÙïQ˜×J÷\˜l}öè��¢Ÿ{ÊÄ�3ífÍKJÔ Å®œ˜Ùf®O&’¶T 2ÿj;š/qx�ažcÌûÃih˜d®0äSé@ÛèR í$(�ôBû”}KC³R÷­L�ðž�v“4¦è&â�ZÕÿò‘,«€xoÏz´¿õ[ ¥�†’³ã5«S~4 ¹£ú]��’Hù®‡t`¬ê¨¡PAÞDMÚÙ…³ÏFÛ\ë,P{¼:~N”1Ñz,�@'_ïô§²æb¶q\¯ëúæh¡:ØKxQ(Õò`ÈÊyÓ][äH/˜.§YÔ"ŒER4QfF3HA„:z-Ÿoö �Ù,pÅä(‘f"¢'ú†ÿ"± ²ÌXÔ…_ã$¬'ÅÁ¬V°šôQEFá¦V’´¢ë�㨀NŒ9Æ~ë�Œ p1Kk2l\[³¥·ç~Ú]é40ný“ñ‚Z9@«Ã6C{®*ð—aö ¬ïÆ«s;„ À 1»��|VÁ4ë/û°Ž¬LÍFÎnøxŸÏSõíp8Rx„¡×¸:•"y¤iý(0p®?¥´[¯ëŠÆË0VŸ&ú™ŽuEMÓ�ãôçTYÍdÕï�:hœ�¬ó‹�á #˜Fa~ðê»å8—b3U²}ʹ�$€ „Ë÷;’qhë©DnåE«(îþÑþ:üd@ Îp0­â”×ÅìÂ`ݳ?fá5ˉ“¾Ú6.·SAhE Z;e eg~:ld˜Á¬tÄ€§P¹CÎmÖQp€üí¹gz4nߥFÛ•œ�+\ Ž…7Þ0¼qÙn×r-39ÌvE±7Ìw¼CJùX™œ.Û±Íâ@c„ÎÝæåàƒõFÀNù»ï`ÝÞ©Û«±°áØx{H¹¹³Ò® ÆEº§Ù¢™ h¾+˜üAç#éªÎ‚G³Oñ×àÝèÌ tÄ÷1”e'ì,¯KQâ ËŠ… ²4…ÇV OHáêúúÖáNIǺ%/„Aˆ^=C�²~‘¶‘Y€[ÊF}]†˜’¹dÖì:íœ àÎA AT‹ü(9+ãÃþnNΓ.²\‡Y¢Ým€/ïmT,¹4u±ß¶±×†_Žýörú–£¼H=¯Û]ÙÛ�ï ÿûû?¿ñþÏ7ÞÿóÆû?ߨ¿¿�ï�µ.w¼üž{-³\¬ìº˜L‡¿…¾ë@1é2PÆñk}Ú8DÞ)—dËâIÚµ³Ž\ÅC 0æŒ~äD½åè€ÕÌE‰Õ;\ü*8ôÁAõIt Œz¨¦¨t è±´ñæ¶\ ÕáÛzl[ñ@“ñ'_ò\%ÓuºŒÑ Óú�Ñ¢|–7¼p$㎾ՎüþkAvŽÚ¬£WKA2…¥ncåÙ«–“Ò¾ö�ó•öÔ€ �t¹ƒ*ä^×xÿ6¯Qýß§Ç�¾å¼Ó {cK”G ·ÛƒxfÀjФÊ3#7¶âÿÏmžãH¯æIË\΀•/MtJÍ�NM€�~â;†>]‡~9Ö�¶UùnèôÌ­%oËHÁå`«äνð؉ù6­i¨ÈZé�ú¢ÀʺE¿D¡úíÖNò9ÂÍcf>Ü_š+Vè <Ø«õ UóV>1£ *7Æx¥cÝÓM¯ïæCw×3ÍÞEù”°Ês�qÖ*ù£òÓ,‡¦öôB̧®àG«-…Ìô}¶4˜è§ÿØ“ I•¸É¹²§Ö.˜tKø^ð5æ�â÷d¯Á÷,ç»iìV�C‰~•ö_×úO"j:û¬—„k'g7Y[q` …Ź<Ðßàü<ç”VýÒSÔdÝ" gJÓE$©cXàPoo¤µN4‘k ÿØ!ûG½Y©n #�òÕñI­ºãÝÌuMšK—òN>­h)Mpz}ÔÁ‹-x>+áñÀd%˜É,Œ2²ó–‚GŸòw¤PåÄŽÎÍ–Qå•ÛP-—`@ÂQûv5DXá˜y¿ï/ÇõX¿ÙO”Ã?ˆ;W püs%«òž3ÒIZŽc¬’�ÞõÚû+©ßJÐ.ÀW(Å´žnÊØÅHì¼ê1™[¥¨ÔDGt%kFv �ôˆZ_¶÷ßH’ØLaÈ!›MÇÛŽlï@Š–+z�Ok!gè{7QÆÕÑrÄ%Àê´Óñ¯/ÚWþ¦9¾óýmÀ»…ºfÇ}7&G¥—¨ï‹49˜Và5Ü,+í#i½RA¢î’)c‹³ƒVü¨¬‚ò™ýuÏ�ÄÜÂé˜ ¾ýA#˜4÷öX ´�Šø™E@2–ß¹o?ÀCˆK92aøÆÂo,|ã²7°Þ0[e°…ãö;û¾�ýÎ}ÕOYÛ8P§Õ¶Èêܹ·-¶Ó‰·°ñ,û£žx¢ŽÓ¨ \èØØþ†ïw$h;N9–m9…ýh¼†^H¾�áe;s7/ß©ÑÙ�]´,: ¨Óà²JiZH¢œl©�"8gµ˜S7ñ/Ó†5ë%ë(Ãþ�Öá°–×·Æ'Y>ܤ‹óZôƒ�¾yÒ³3E}–g%„ˆ!p§L†©kJ¶)üÉ7‹‰«áÓ¾Ä $oYžu-otg²Þ½+8Fýh=°Áú¶ñ^ Ë‘zqµl° ¼}m¼ßo¼÷ïtê¬|�\·`¡¾}E¶Ñ7åáöÛ�¿ßØÿùû~ãûÿû�÷ßoà÷öÞ¸6ðå ’Q®eø†á÷^øvà ÃÆÿßÚ»n;rëL‚JÛvÏû?꬙ÏÇ%¢˜T÷¬ÉZ»$å…q'2u‚™I?gr+äžI„íÜð$tH'VÛÉäˆ^îXîÍÉÚh«œå÷¨âf�=ƒå„…¾oâ¼ögwò÷^í·F�Ó¸mYöš´ëÉmࢸó‡Y?g©c¸ˆoñÿ°ZYš0¡¥žÃÀsó¶%_Æ-t½â"‚.;ùÙÌj±.zrí]ðp`v�‰A â†/iÝq‘ò:‚ž DQà•§vêÑ•~¡åœEÔÑcŽ/^º+w™q¸å"˜|ºª«oé³Çʤ¯L°§ áÕžQ¥G$wQ›ÖyÕçËÄ*Ó§¼ZÒ1¦dÖ�Áš±j’P! ¬[ôæ¡‹C@вAã-6LxZ÷ÙQá�Hf@1åKXc̵o¬™£e4¯kê­ƒ>“·žßSº=U=ú›ì@4ù‘ê™AÔñ,�0Ç›¼Í UG”(S©$HÔùz&'lýP{Dã€aŒ¾“)•,È‹4[�亅Ä6!x±žïæ ã5¦îÏëWßó@û¼y^HZÙ…fYÃóõVënäX˜I·Û='˜wެ �U�”xI™âV˜£EûÖÞÑÿMËèG¨žA¢´“ z�niÜæC‡ð¦hã ²¶¾R°ö™JVØ¿¾L{Û¶+.S¿ž‰M£(Ý"(NX>¶ÁÀö€F¶jÕøY�<ãP½uÇÛú­™ñ’œU»Ì�ZÙQhšúó9ÏVÃÇÊûr²¹â�µ5–+LWðLt:ÕS ŒØÒ¢‡7=�:ÆÑùõI¯H°Â�u "¡3jpV¤’£¡ƒˆå¤¬Ë¼–Ô_«mÝ hµÁ¹£õÜeX`D¤¼bAS«ÊNÜí‚Æž*3¢@óƒÏgêYÏ®Û&Xe'ø×…®³oâð�~…·˜CãÇ>Ÿá¤–ºõÄ)qÂv+N˜�U†ÖC84�¶ÃIÕ? ±MªI[/ 'q§îd’ Ì¬É;ÍN¼³»æ!¶"j4…O€Ë¼…l¯&;.›xe¼m[Û,´å˜†^Y üÀs:Og6.mÉ›öRðÞðyƒh)0`¼è¢í)hò Å;”qUÔ–"œÄ¢Q§\p*÷“œš®iýW‚ÁÙ’¢*Pf†‹˜ç ¬“ ¼H$C`×ë:û\º-˜r¼yߢŠB˜_áÑíI†«ABž‚VÃ3¬+Ï-0ðÖAßþóœiE7 ?½e�ÀÂL8Hð7þü‚§F1ýÀÂE¶QèåG{ [�³³ñãPå"© i¨×“‡ºÆÁ²Ú•t²©óD͉¡ËyíãcÒ³œ—¡C½*'¬øDõh-­6ž0I b«-f¼o€åÏ1vg‰:ÓædÇ€Ze`Þ ŒÛ~ÑH#ÊCÅþƒo2Cm‚#Õ ã'Õ ÔNÇ„làû˜ ø¬4è?]‘9Ïs™ €žûéWÛhD ø(eÔ»ç�?NƒÉd4^çŸþ™:¦’Â#! iL²&ušÐƒLÆ(¡wÀ#Œ]z†/«BTÁìÔu±ÅN¦ãD$Ë>XËñ~Ŷw¯Å¤€%º2!àAî‰È`#y�pc¢[ñííØŸX:»?’,HÛµ=B4ñI/Ç8vI*÷•˜4ËdA†UÜáŸ�½Ò—²¨¿]tÆ�zÊ«PIwGêGd"]xÀuóû¨¾€ÐO?[®¹ÚmàŸ³@0à/òDÿÁgϤ 5(ŽQûu;Èû—ëçòôr†oÌéZäu“.+òáJ¯ŒnÊê1wç.Цƒª´¼¢úæÄy½�ÿ Þ×dFñ@( ÂÉrÍ€Þ2L”ƒYAƒIô !‹Æô‚íHضx5ǧÇC3\{ÔbÃbO@,,¼ìÕÕ–°XL(#Éf5Ùl…½#g�¨�œckDG-ñ¥nÅPÅÔQàûVÚö%ŸÄèJ{*s\»uÊú8­t?#~wR` .¿;RÄ-Ø&¦û‰à?÷ËGmÅÃOôÅBÙ”¡ûµÊ”àˆÜdPñä4ˆFy«È”®÷=¥ì„IÉ$ëžô|Þ*øÉ„f®µbBýˆ\¹ès/‘®in&^•2• l¥.mšP³Ä®—Ž‹>!ãäÐe€ ]ˆ=¬^0œ¸ÙL:3eÚ:Ì]ÆóÄ|·^cV~è–† ƒþy;á^°Ò YŒ£�Yƒ¬êù¦Âu›Œù ßiÝÕç)^CÉÆ¼·mù±›wéÛ‡‰ñ|¸Æâ§‹d)›ÇÜ)qL¾W9b’‹´(±ûzøÿj;vˆú iQÛ$Žƒ>–=‚�?ÅñÅX“Åi÷.4m@)>·¦Ø…n÷C¬y )’H�±Iߪ¿hå9ÕÅ_�sØY]ýxƒßæ—³[êqUù_Å;Çò_ù†c¨vºïF…7ýä”Â8æwÒ’Ï�`a£3½Ùn„ÐLå߀Ã6wò žöayWÁÕô·íùö£’[+`Úh›��1 }ù8z5ÏÜŒðyâź“Þ×Wd¸ãJÔ¹i=20­g«f*¯}ïvú]µ¬u ííæB T8…q(ŸñÐÀaüˆgÃ˃mQ/=Vn}ÝQñ�ªýôNHŒq”ÿ�‰ƒó6âtK?.#Íâ“ÏŸ~½|àÛGM¯¦â«–®rÖë;«]P]™³£Í¡ÏLï·9ÆÀ4 Ñôd[ý}€Kk ŸC»¼Ž»aê¶çv:ʓҹ | %TXÚlE‚*& <µ2z§ml•8h´YñóÀ™´¶õM¾AÒl# 9l\Æ8K[q˪VÚjÇ+ÖB0 §7lKºU�oèø8A2ÄüeÍs�y�k|'uÖ{ñ¦áˆâ; `èU‘°\V®ÎKUZ¥Äv�fÛ±³#Šƒ})Äò’�“EÁî¢U`ÙPŸr/ï~{ëû©¼»+ÑâúYÜu_NCpJ1hU'"¾Û«ž)ö²˜i©'¬ÄË\ò7ÆÑ Ü�¢ù«àœÀÁÐјSñ]ºy ��Ka¨Ì¤ðCÓø£[; ¤ñ–{J1¶è#û&$>:A�§E+5ÔÕ±VP}Ãí¼ûi©ž0Ts‡0 þiwƽ`;ÙþCY©R¿ž²w*ÛüÝKûxMq’ýjV˜ŸnU4›³êɳ§aà²4ö¥méR+>½r�8!ŒÇÀ˸ôyãXäçuÒÛ1ñÈßô<ñç;òÃ8P—«NpéJ/ÁË#‰K·ô`ò:K&SdµÒŸxŽéˆ°:¦“¬&Q>P”z@o©�ôÜÜMq®þ‰¼rÛ ÷Ðß,¬±’æù.›WÊÂ+QcµŸ?wY°Jw59ƒ–ÃØ#)à¹]Ÿc3AðÊäÀv¸/ø~aûÂþåøØ'ªÑ÷·H T…²Ž]àݱàþ Ò¹gÑÂÆ‚cÛ.^çLÓ’nYqL™²²{fìå°/<ÏÊÙÿ¢›¼¢ ©£�´8uÚio*p{–ü¬>÷t(3?!~؉´/¶v/ZYˆª‘j®W ðsÚ�Kïc"ðoÀvŒ½�%øQýk'†§®º™�‹·ñMÆ"þ‡aeå• X¯W®HlY)àÁ£n_;¼ ï?^xÿzáýyáåË7w ÃëãøäjÂå\©¾‹Å¥æ²ø,J>ãXh‹<¬5}÷�Œ15p²ÊíL pòÞ¯cËJhH‘KÑg‹ÿƒV†ÔÓb·+±ö$ËA7©öîU÷à÷оÒ?i±ÍƒLÖ�áóÐdjOúÂ}ßW[ñLú„·’ »mÐØþ7L èJUÛ_¨ÕUeèñŽ�ùb§·'x¡ k¾èf-Ým‡Ù¬îô¤Ûx‡A+I‚T¶Œ«RbÕDÚ'~óý†—' $x?®5,ùí¸§Û¨óyûàÜ­·¿)á»ÂØs½çˆsžß�Jqãh¯V¡�}v°·à¤¬>å˜g€hÌGSŒÃ§žQ5,º»Îŵÿú3úý�yV¬Ü/^mâ ×=p¤ºa¶>%ÏÍ�ñŒyËêsË£ï½@ðÉ—¿‡ŠöC¦þ‹fLýÅö‚g„3¿9Òd¼rY^ó£îÊ}n1qþÿíxÊY¬ü­@µKz$ÂN…v´uÂSIšC& -‡=ÖLRWaiÂ`ý°óÙ“×͋ΕWW÷twmÜc…ÏHüyÉè�g×´÷iŸ f$6fì�º×Ük%cׄÆÀ4ê–ó³ýÉŽÕò9+—¯Ç˜6ɳi§qàAí=»ª ~Ø6¡‰•SÛt¨ÁN¡(ý”ç?.€7uŸUœN:YI$‘‘ z-å’¶?�jéÁŸG…õq“´Ñ¿%-�*lʭʼnTÏq2Æü­ÙhûÀ«â9\€ïê»nµ\%ã—y#·¢ô2<Rð¬+óùNE½�öm3nhÝ,m)鮤+ò½ÞÕY¿ Ï2†æÜÒ™*ô[Þ/Õh£¿–cs_s5î6W ,XL+ÅZ<t3~¥àÞO@Ø`¾¬¥°xÓ)['KrùŒ×æÊ@l%ÄàC2aÊ’®\™X9…ݦNÅ“q,¢QLÏàÊЂ§‡090*$ezÀG™08=ÛF5 ¦•Á„8hÒÄ®R‡*Sav—�=‚ç8Ê0$½ÏàÖ’º…”é}�\°É@%ÌZ'Ö÷ô9eºÙLñ6èxÊ®MJŽßçAb<•^Ù’ÇUé 7#úšt Rü¯&,‹ßú-�ÞhX²ß/1ôÙÇ#Õ¨Ÿ °*9 �¥b#¯…MÛÔÔ ^òÞ¥ÝV½0¹äc*ï[0¥'#¢Œïì ¼§p¾åS’±5�w =+^ç$Ý,…Ý“–†cQ³m;ôUêD&hI˜t6†ºÙ.`"ÿÜ_[ÝÀrÛ‡„¥¡E'múS«o[M2AÐNúé6)™½wV5pÛ�×*Ù,ü~€ÏΚNÚ!œΦ׿™&ø2%¾ÒwV¹~ Ÿµ«ÚÓ÷ÂÞ/|ökYVÁwÂè%DSÇÚÉÖIM8|Vñì1q£�Cç»kêb£&g†#` â*ßËn'_–‹­Šê¥a¸´�„òð¡Þ7ÛrÉéS+OÒô•Ç„ÿ01撿˶ì^Õ¶äÏ‘•ò^ª‡²©ãPŸ�}?ûÜ©HK¤W²Ö´ã9òþž›8+9"]ùgrëCV¬Æ©>—a½ìÅí„ ‘#ŸzFûö6¬? ?û�?ücÀ¯øÛàÿüýÆŸk…Ka )�êï|w`ØÖ«á$‹õ$!ýŽ%o=ê—¡‘ó1º_™*<«ÉÞþëM7÷ ý‰”kŠ8‡B“ÿ•L[ù[ƒ}ƒlL·‹®K=�Aøy­È/×;°"�êl_p1I‰¿FT Šy v4(Þÿ3¨t "œÁ„9”¼¬9ÃÁy¨¨f[Ù=ƒQ]§ÚwÉDÂÈ„tÀ-¶U[Ö[˜i`‘Xà–vû³ñùd_BËNNsû(4W»ÌG*9%È« ‡è|ÅiÐê<®—‹U�$Ïž¸ ´¨üÄ7S1v—ëß~êøG1&“›gßCNl<7¯wj Øú|”þÉÅÊÝÇqäµR%§<_ŽÑ6u ÊžkÿV«ŽÇúyEÙfòÔWa;Ÿ!¯Eï͇¸'eF?%;ÞB\OQ[Br»êׄ5æ1Ò—yÑ%þ?ucËô>{މ¶*®gEü“þo’¥GӢߒ÷ÏrRÐÎóÅ@: •Ã�+hK ý�íVãÚÀÓ6ý^&D/à\©$úhФWý¨/ÍaÕoë–ûÑÃ÷T¹4V['èøGÇ_ÆÙ:C®†ëù@� eµZý=¶pæ=ô뾎Œ¦œU¬“ú�B>ØhÎUj $$½9§Oy$ÞkïY³Ø‚Iß1á)øÎh•†L¨ñb@ÙkÙÀ¤ä¯•º�ä‚8(�ÁN™ºÌNÛ˜^$ÿµ??¢Š¼ÎïØŠÃcì¡ÇyÝÐUÊ­£èÕ;Yyg@m[mùUÆK=ê|ãÀ¯*ePŽ{k“¸¼Zá§è=Ñ´›^QË.Zu"�73Õµ\�z•ïƒYž{å[ÙPDãá1À°°w¼³ÄËt}ÅrUä8˜:‰  30’p†mt|ÖÆú¬zÿ�>Ÿ…_ÛñúeµUaÙwpû"'íª§´M`˜Tå5ø&úâƒU„º…€U{¤Å¨–ÿ•‡Ü“åe °x½mXöà•áñÉ�”Žª½žüÀ%›|�=&3ødì\Æ*Ž\�g°�¸Eðx¼×I“SÖ± æ+'f¹gì½âÝE´ù;ñ’tæ{»_¼máÏ÷ðÇøó…õ×ïÿù^ÿ³àÿïÂçÿyÃÖÆòxGÔþIü¥Lèä½0`ܦ³œŒ–û•;9ïoÓ.ú¯Æž‰¹‡¼BÙqCm¿,»›V°êO'Í'îã|¨ÂN Ï@»e»üMú¦ŒŠ?Á?;ôµüQœ w îkr`lƒC{Õùr\d¯T©÷¼%áÚÞ«-þ3áÁ¶]Ð1_f£�L­S–¼�¢ÁMú”ú;B�–°‚s8¾M!WmaÁW¼lÛ ðr°Cfã9Ç'ÿöþÀrvÿoÁA¾ŸA“+¼ÍÊÚ©jk¤ƒUÚ¦ÚA“~›ô~›Ÿ”gúgC\Ú:ú Žó´ñõ TÅ‘èµ+úÃf¾;û¾ªb„¼×lê%LZÔ§Âú­ÑüoMY­Àä¿È¯õsUÂÎ@”£@ŠÐ8û}Á8zæÛ*ö[zÜ¥�/x�ߥ(†Ð0Q«wÜ�ëçó8ð2?»ÅÔmVFó:Ôkð¾cêå°¢Fú�.ÿ7ú[»Ô¾ÎgNîq/+ÓF�ìO̱‡ ÔòHøµ&‹‹Á²1Ý&0‚£Nt¢è $OuBÒXŠû,­p™�Fêò†ºùñÙ¯Þ÷À©]ˆc›wdüŠþöSG·œíÆ�*ã-Ól¯wéÔ´.ÛÞ ÇÇD€Žˆ±ÐHä»<Ýð±Y7C§ˆ1¢fÉX�}ª- øsžŠ¶K˜rß~·aWèÓŽs¼qœ†z/Á‚cûÔÉgôï =•mÛbt$>ÙïŽPeïˆÕÝ`&Áò;]æ�oàdUW-‡™”üvs+MA®¨3“¾y^ç�Å;ïwø”ý�¥­>Yµß:³UtÚ~ñ‡¢ÿ&2§>+mãÿñ>€qo÷ÝgGù,‹™t8q™þ¼1^cÇ}Ž¢šyäAö}ðá¡�µÂÊÆÙOÅXJŠÿ¹t‡¾w"�8oçªÅç³îj.—Ñ žÛ¹’¤•¤�Mêü�&HD'ùÙÏPè³RÊÑbc$…éɳÝEâ@äÛ(HlCÛCñn¯ŸñÍeÀÇuê·žkŽ7uÐX6FCqf�ù·ûyV¤v Ny×Çg ‘Y÷¼VÙo„Œ¤�íJ{ïmuý®l —gïö êXŸ›1Šq"  íɬˆýòhÃjõ€‡.-·WŸ±Êmaq�)†�Õ d@ƒe0�Œå²Øä ™�Öže*±'6`Ûr[¡ø{ÛÂ/,¼?Ž_¯%[Îw Aõda2ôV¥ú‰ŠdjŸ•è*aö Z t´_6°�6& 2˜ä^“—ö±4ÜÐï9^6Ñ5¤U�çL]åjØRýVM]UzÙ&vz†ûåH]@óÐ/dR|Q¦¼¥‡DÇ×@r¼ s5uþ.|RÆtÎj• ï(zlÁIÚ5e#ëþÕ…pD1ƒ›Í/Íã„1PÈ;ˆâú—ÅöJÄï²ÎOÆ_kïûÖ6Øß?xý¯ðúû�÷ÿ¼aÿ·ï…×úàeŽ×ú•ïÐ œâœšõ^½ŽÚÆÈ¸çRýæzM¨’"”’žè‘¡Ü(û"λs˜ IMùS±M{UûM—ùëm9Ùìd‚øsÆÈ®µNù#ý�¶D|�þôùp÷\ÿ>°¤“8»\ï¤�¨Pé#¾^b„‡�O€¼ÞJ§tP=B¶Ö7g°éÌNú{¼yÎÒf%?õÀ]¥aW]Ì0]Šm%Œ6ø&ŒÝ· èìÄ@ýÑ_È¥þ®øpǤžÀu§æo9oº%ðídà–¿Œ4�ÖO~ª·H]–:’zªarù;Æ¥¼ÿ¼Ü°Ž ™+À5¦ WûÃviÖ„¶ ǵóƤwûÀÍÊ %?Oë•0(\)^wÐæ3Ç}>lá—ü±ÑÈ×cZ»ÛÕË3"Û,jàw?pZ<$c#�'^ŸzüÆâ·¼|á­jã$éR&7!¹µC)pê ìG—óçIóã\ˆpçÕÚ®i4ó�q.ÃtµE�æž�T[Ô|¶R;Ïuçáûœv™-‹ á]Þ\Ë@¿%m\žtËï,0ð,§Vý�`011µí¸áhW &yt�O9==ms àp§4�6¨1…Û+L1‘`¦EÊsÖ® ßÑShx½†õè}À½›£‡êŽz×Ý Êé�´©ñ'RŽrÌ~„Yr`Œ1U[ÅC9®Åyfü¿áµ£HŒÏŠ¿Ë»óÖe°Ø˜Ä¶Ì­Ÿ†&]:;‡~k¬.Š¿Mî)2×` _åæ0â„3e4�‰T›,¬$Ç®ÕúËü¯àL˜ä è'¿ ¯JqÏj�…-è,4Qš�i¡# ‰ù× ‰:#˜GžQ˜ ù“q�Ú€†m°3i3ÐAÿŠÿôy°jï¾V¼*éUƒl�Ù÷ a�5ÄY±Sï¾ÇÛÁ¹bÀuÐÁüžƒd¦±Ò2›Ç—$Râ,ƒð–B²^±ÚÀ–Õn>¢‚ w?4„Ïï°T=0‰t!ûi!**ÄÆ¥}ŒãTÑÑŒ,ÍÒ>ÎB#7Ö ôa(>f( ˜çPå|^ä=¥ÿwlYaQU¼³×-„E�ÅНˆÀ-¼\B#�1;kc_§“D–¯¨b¶LÿÚZp à[ ¬%e@ Ë� 2u¬ý¸V×ù9˜í«?v?¬Ç ÒÑPûÃ?à;øó„MtŽa»µÇ«ÓóàíVz•‰Ðï äcxÔ™e´¸žò*i Ê»òz0–|fó\·!ZÑ�W’° Ožwýn»:$˜½e�GÕ÷Fò"�F¹h7³:¹ÂÄ3uÛ ªÊšW²ÔÒ«g¡bCý”@­¥Þ¨kl»Ç”Ñ<ñÙ¤?9ËÎRO”{â{'~Ы`Ñî«5ø iy¾àŽÅ%ˆºáôrÀ㕎 š¼î ŽÇ_’È)Üzß•??Ô±Ÿ¬¢1äËS�·~½ ï—ÁwÛÕm¨w °¶”ΟáÌ ¾Ö¨Úl³¶Eµ$�IÜú#¼Ra ç@ÕÛw¯îÂ}ò¤¢L*95’ilõp‚F9Ò¹Í�Êy946~{é¼ÔézO�ÇoŽèÄÊF+ðèÖ�<4î@U^ ƒµ�¬ìKìUÁí3ÿLzšr—â.d¾ÛŽdQR,Ö[�> Ä!sÖ Qjì„cR»“ðÛòÐ/öÇÇêŸt ±|Áö Ë_øñ…÷?ŽŸÿü�Ÿ¿ÿÀŸÿƒ÷_ëÇñ~ÿƒŸ·ãç¼ì“Û{%>÷Ž j òz,þXeyœ¨f«žä�r𓞣çVD™.D­vÑqé°ò�ÁßœÈù¥]"kZŽèÒ´ÖJOë‚1Ñ�ð×Í\SF´3· ² üpû¨[ÃÚ¿tv»N( ¯ë½Ü+kS^9߈A¬ÿ”ⶆ6qËÀÁا�:¸ \ËC­ t¯"³Zq&÷l„n¬—)zlT[ì1 d=�våg8¢i]IBÅ+u¸âH±Ïq嘯�ã2Q—¢�€Ò¬è™z�ùC ±Çà)—>Ú#~ž=÷*éøq„XIgÙð9ÊÒrbè\ð;Ì�àa¬Ò¸ÈfãVŸx¢Rmο µÏgIÅY´4ˆ2|]%Rm�ߪ‹d¬Ú¹ÿŸÀk…Š>ãWœ£Óg4àÞßI¯QcýÊðkNšYè÷oŽ/€v@ü{;䎦¬|e›+*|>]ò¡ìð󸦾yû5�%z^aö+uØÔÙíÊÓSþŸýMä‹1 Û]Ë}‚#“s¡[RšÈ«& {¶Us'9GóŒ#\ø=¹”ܘó„TpÇõaŒÕí8 ò“õÀä‘‘,?øz:­‹ñÜEç ÜÏaˆþÂ?ø(‹ŽâEº†‚~4\V~/wô­¡±}%â<ìŸ7oï)ô9°t3ãÞ¼Avš.t’g*¢ë¸%û¥¾n‹žüaÃÑm;on]Å^}xø¨&± âk¨b'ÎЦn€HšXß—�:¨"H¸(=cŸ>y�E&\ÉAà o…è–{Æi‡°ñTÍ“.†1û±µ$«õ_ãÈbâí—6½m…S¦½5+…‚zC¿¬â0V9îÏŽXí[Í:P{øÖx’“SHJe!¨±ÀŒñ3n/íz¾“fÎ1/ �‹ê4Ù õVA_áTÁõÑ…ñóü{)óguû÷ÕÁ† ¦ŒÀ Ê>¨�™QI’‰c»ƒµ ëÕNºb]ùây43|Qo¨JO*çÀ§ÒlWÏò9/\Í®}Ü×§Z'.ÝŒ4qc÷Sújú*=ˆ´á9±a¨W¥ Ì2À‘ì#3�qQð=Þí‹,×òÖ¸® wcÓ0c*´Q|‚ÐÞ Í2™ë­ƒNë°úU'˜“¨üUËâx |ôõÃÙ8?q§Cñûïë/Å”ã1!vD ìö�ö{âÔ�óÀÓqv•¡£]íR‚Ùýwôi³=ô©ø>z(ú–] bX¤ÁÊîJû¼W’VÏ?ÿ.@êñÍÁ-2ÜÔ�sÍ?]陸ʕ±º†AÖ s—®*#rna2;€>ƒn‰7§××Þg®¬á ~«ÿ±^•‘�#HuÇíÄ¿%{Å’ZyýJýÁ¾ãðbut®b–Ã|F6cØT¶Ñ–¶¼ø.V8´æ|÷”ð|™o�Á@.uµïá± ¼aø8ð~>/®–‹ž>¸/{°‡N*ÕdR€ŒàI¯‡ŽŠO‡ÖMç¨|þ ðë[Öé%,;û´µÓ^ ¡ˆ+>wèëÆKò½DR-“ZÑ5†ì¬†ïgB'xß#6«V‰‘©u7smz¢o(÷¾‘òðP‚Vt¨Ú€ d—ý¼P3– SƒâB[¡wÁ˜“—œ t�*íZ B@°îçøÝO‘¢HFÆwcR@r˜!ìï›éü^xxcýr¼~½ñþç�?þóÆúÙX냟eøYo^0,ûÀ-_(û Àv| ¹ü™E`ÿãùp°Ê xYPy»Ð/T€$ž×!Øä%¸ÍÛ°©§Í9x�ïôi2g¢7_@"‹ðÝ�i´—M­¾s>Q6·ŽòqmÉÀâ\CL�ß�–3éÑÐÊU;Æ$G2–×øfB‘ü¿é¯O3úÄöÎn¾œ?}—âSëß*õ¬þé�Ðg# ç�÷øÌÀ±[í€jˆl”^.Úž¦6‡%L_ªßÒGáCy½äF˜‹ +qd‡€ÑYÚ‹øêá 1¼»X;b ¼¾éÞü2áY$•¿’ÿÖÎïl'žådÄ|aTw°È3cØŒyà™,ôîóÇ–q |ï.zÔ úŒ$¹• µ,øe|ð½^M|å¼2Mâ`vr ¢@jö.ªã)"8“Û¾4sÉÀLþ ‹òUNÕ(�2# ÕŽ´-f;„.¿—Ô\¢.Zªžêí¿NZ„O¯‡é=§š9ÆvkÛûGðÈüxl<ù©©[ž'ãj‚àHtVÊJµÖ�ûÇxûÕ ŽK—б– ¯ˆöË@zìO*ƒõPJÃ� Ô¦Þ�zÁƒgdÌ�Õ#Òâ#QZ7ÚI·z¢_üœÙÎ�äyóc@Á#Ÿp©ÚÌãžnû m)5—@ñ}H¦Ÿ·áí¨8¼•i)-—{ÕøÓ3ƒm}ÎN^)Uæ-Σ15rù}"íY/•×fJƒŽY&iÂW[®Æ—â³’å¡O¸É¹âÃ[ORve¦Óé]O Ž©2y'”% ,úÉkjzCüBŒVFd‡A\õ¾:¬%³÷ã‡pèËM‹ä\îÇ…Ïæ±ðSNÆ6�xm¢•¸�¤éF$~>ÀgE?–^¾‚’‘ä9B=ƺ›¿%j­¸€›íú $7Ù¹$_f-_¦ÙE9)HÛó˜?—À‘¶Ÿ`ÜüSeTm‹V8�]ì)ב¤ö^‰0Dá¢x^uä)KªØ× ¢w¼‰•}ºÂ+rÍwVœz¯LQþ×~Ëù'#ÇѤ,É ~Ú3%̱­gAú¬¶ûË; ³Ð+F0È_cùWj·møùì—Ã~½á¶ñ oÞëƒ÷òØ–ÒJÑàÀÜñ‘‘–_™¢ûây]½�X³‚¥Ms®ÊJ�K싆ñdø¿µ�[IJOÄó�[ýh}“Ý!¼ýœ <?T•2ÐYÛ|©]Ôvÿõ0>ßið;xŽ1\à-¸¯‘®™ígºrMƒ¦>ÏPÆ ü÷c€Q¶d&Õxã© å¡:ëç-Ök¤Ë\XOðb�æ˜ï0Yo¶eBͤ‡5m³­Ïögÿê°Ò?g°éÓJñ°âTMøåé1/¤Ü ¯´}Ÿ]?í‡��Я—Îdꬪãó‹v=qÚI„�úZaîÚ7bx£­T ƒï•)ŽÄìbÞzŽû¦O䜕<[�ß\î„û¿VÝûÄ�˜ÐŸiÚ_6›ð¶w�ˆ~éÕ6Í3>àÀÄsöÍ ”¹§�êâ ïªáÐëÏ6ûñIûr/¿é4×g¬lÖ0åƒ7ϱNЬ{IØù¼qKù`cu .(Ë‚ÄjÞœÓÖ ékÂpb‚ï©™ÑÏǶcîéã‡.lV²Öù”ÅI8É‘ðiwxü¸à急† 2N�àsg«î¹ŸâËÓ³,r«•3U�ŸmY>ÁWûÛ«kjÚ'atÀ—ÉûVµð`âœ}t>ÅüvL!» Úè?ؤ¡b¡ ÂNÛª»oT!ã’Ñ–ÜÒG·É°E>³"Ô‘s—àÛ^ÅAeÁ„üØf¾ø2+{$(m`C\ìl0}W—�’.c½%I•B¦²ÖÉ”Þ.ÎuNgÒŸ`¯Þ!6MÃqìwȉiG³ü¾ôBÞ¨“âf´©cu.¦€òÓ½`®µÂgÁcŠQ¸ÁxEÆ eQpR½ª°Ò^±ëˆ¿,âÙŽœ±09 Á@Ò*ºöG±§±(¥>“\àP^QZ9t©ÑÄW3À ×<üÀ_¯Õ ³lFiºÎ•.ñ<+&T¶.ûi&l2Àfæ–Uj©`Þ˜žX|X±V[€¨Æó^ocªˆ·b÷y³f~¿!—ß\ÏJÐðJ”£ Ëöɤ·›ÔXjOj” £º|TZ\äòèðGä:+kg0PnÊΞ�øìx.m… TµNÒØ ^Ǹ¯.äÀˆjzŽÉ7øÂ!ŒÖûw4ç §lÃPïó¨d�ÀpŽ‘†> dI—ÂTÁl½e�–ëðѱõQàÌ-6þo1b…p!=#B9oH˜¦•Ê^ktl>v&Û«Þ ØË±—cm¯í†Œpø:tv)3A[MŒÔ ,=Qi“3øŸIP—þÚ©;l õ˜‘-<ñß÷• Pcpe„.¢{âÉãy•Š™ðÊPÏÅ?Þ,Ê jÌ »dIV?à ÈG[šï8åÈÓ.‘~_0s i %ºÍvÍ)�6hÆ—º�­Ò²:”ð±ÁÄaá#iQ¼'CÅJ¾_†zËÜJ»ºï¯&þ xJ$›¯À·p/{áÇ�7oû…+ù{Ÿ½ñ"! :Rñ/+,qeà; ÒsÜžG%ßjzXÄÒ*c O([& ¨å—öë­û`Û© Ô÷ |gJN®»Ðƒ°´ ‘jñäÝi&¼UG1Rÿæ§n%rn!<«ûoÇK@tâBÛ°q]„« †Ž¡é Ös{”󹣫 o�×ÚXÞªÁ¡3PrD´ �œBB½Ëfµú ¡®£ ï Ö•1MêrÁÄwÑí &]s¼²êžè»“åNÝò³VÈwÊ‹"ñ5«¹“Ρ¾°Í™(Ò+ü0ù9î�ù^ÉdéÊ9Þk_>>*Øu¢vš‡Æ_tÙÒ¯°hÀU%ytÎÑ RÁÅNž÷ˆ:m„EN`¨i°ú çdß}µ§:ßé× â½TЬå)8!þ—Œ•º |S^yð«ÇɃÜ~üΕÌÚ”H\t^Ã{±äÝqKG ÷P×6Ïo=…`eöñ\2´BàˆyVÇV½zbŸ§'w’à¹Üßô1Ü  ï‡2bõ­�îi³è.è¸Íbwß�§ü®³ÂwLO­Á»È*ùÑ>ÇÄÈ€õ28šg…Ò†O:�{ͮힺõ¡Çˆû Œ÷_oÇä�’iÌÀ­‡¸c|ï:9õI¹ºÒÇBÔS­Õ•Ã�$œÉ¤âclõýkr ycÉÃj_àG”ÕL«‰· ·´Ê€<&.ÉKS¿ñ‡0Ô%¬Ô^¥o½ÆO£] /Ü¿‰«~fôWð·žØ”¤€<ÖHž8 RñU8Ø–Ž÷ôŠÏ¶{à�¤h–C¿7)¥Ô8 èâ›õ£‰=â{u)ñZdŒ à–Â’q€ñ· æh£”C ÖJüsƒGÇ�SXYð £ÒJ¡ñœ3U›ÑIÍ}¤b/Û&ÈIMcq¹íô×Òyjá—cU†8dÕ¬øp˜qîÊ̸ã=”'!‡gPÛ'HGýJ"šÐž-–ªèûiþ“öZ§“ ŸÆÀ/‚J9'sX5îí6ÇËtµ]SxqçŒò Lx•Õ2|4ˆVÛñSájW%y—~ˆÒ®ð[»±7rˆ†•QyÔ±°ôEñ(ÇwßçË$Ñã™î»¥°Ú@gtè²NÙ–_ŸTRò z£ô\=@S1.ú‡¾&8¸{éû�óã7Ï¡¥¤¤ë¦æT"ŠðÃF(ñdÝ*t¬ÇªDYøöÿž2Pcl… ’¿žãÓžç„ôì(?o­s#g¦3)w IDAT�] \øÐÝgV~HB¡&ã r©‡a6–}”ù�÷&†œ;¾Ñ`|k¢™ ß¡q®t»m)4pË1x�ë‘€|§|UâÐúYÏëÜŽGYÒ†Ë5ûÏ}¿cL,“çÆŠŠÛü½¦ŽUÄOÒŒÅÄþÙ‰úT,ÇœV6Ç×-}iÝÓSòÖ+µad¾ˆŠ[FððÞŽÏËñ~Ÿ�cÙN*+¼ƒ™Æ#x¾-ú9Ù#ÑãžWR#xœÛ;d L�ð Q«™“,�ù]�*º½ÏÊ]E¦:8‚BÞFÙ*f#½@DÍ«ºn[ˆãÑm_ºëÕ_ö¦&§Õ6pnˆ{È ·¿úº­Û@KÓÉ©CÿeÇdÐ\/îQ锇áuŠî´�7U)Å\uèÀ2Œn´½ÖNû œÁÇ8_bZ�r.‹¡,g™Ído[�{mÇÏŸ†÷ÿµ°> ¶ßÀgÃ>€ÿþùåøÏ/à?{ã?ØŸ� ƒûNW&ðþwÈ +Û †Ï'&>á»nxîªJŸ Î+©ÿo“ù>ƒÇ‹ãˆëWøºk-lXúøVjfï¦vù‘êK=¢VÍl©'ŸŸ.•^ƒ½„ïÏš‘^V~ÚKÊñMŸ–ÉÜ�-ó¾©+ø\ýIJÏd«þk<«s5)À‰|‹•¼uȹm‘6±óåÝ·+S”�ïž J­×Akž(kQ�uðî+}˜œÞÞr¡ïZØ3ýÿÃa5¾¹oæiwµxRÐ"ß›ó¦Ýî{ëyWœN~Òç�ƒrp½ì!»¬¢-UTÍ×,pôUvV¯û(—¤Ü „j£ïS ƒFñhÁ þüM}}µù-K Õ[—6ÿÅþÝRb•ž×J^óÎK»SA5PmÖš1†i7ˆ’òÉ“ÚÆw²4ÌžõËC�)êãiÕÀrñÛKYeÁPƒÐ¡÷'¯žú“ºÑJÕŸa+_[+T¥^mKñØ /_ݶ"/’B}€Ñ6³Ÿ« �D“ú¸_…ùÜ Ä€Ø^5}jÕ¥öVÿǨspñl Üý¹Æ~Û×N�a7ê´Èw›žÁxǹíQÏ ý*¤‰ ’׉Îm=ï 6SÌWu¿ÑÞ÷ª»ò�8lG»úð|OÎä-R^uJ× Ùè;D?ȯ‰¼“þ–rQê†pëÈ&8á³5Lø‰wÃ9�«=𿤡ˆ; ½ú¥p’ýõy“"5i9>Æ;Gp´UãÒuIÔG@‰£�G8’ø^vÁeo¯�²ÍµêÀ„¿ëÁ–ƒ:O\%œ6ËDTúæ¥"‡ªô.èZžÛËÚÜö†ƒ(„ã•ð�á³E YÄÇ‹ç °— OÎ ŽGà�8m=”¼êÞ±%C®Ø ã8Ÿ‰…½{ !MI?›™Ö°DØi/ç>WÅdÄã)L¦mOÛ§ïK¢µ×s�k¢Uõ!]‰ÔŠ*ð¹ô„w C•„gõ"/FÖ#Ø0µß£ ´‘O”›‘˜n3ØK¡ËIŒ±ƒVê¢.p€¸;~¨ˆ2— ÍäóË¡1ÙùGf=.1f§B®6L†¦2Öñ¯‘¸«ûªx5áî cÔ¨èê¯ñ;ê%‹Žˆálí»Û ¥~GŠ#QÒ™Ï x2ð?¶ªñŒ˜cÕ¥%Ì.ü"š gÛåFò?AWeD¼¢ƒÉÍt]a6«ƒÐ²Gƒ3Æ:J—JGò5ä¡AõG½=��Ã>ès£]f#§Yáöb rËS0ŽÀþMÙµ’Óν~[µ�X"V¼äÝÞ"höqô›zB&u�¿%æ8Ádà×:qÅ6-õg�.J±þ$)ZÙfä›êó1çFV“O>«wߌ¾}.•Û†ª-9ŒEDàØ˜Žï”Ïå–Xä#îÀÁîV M§¡\©GH·¤�©Hdè²MÆ ýò޻ϖ2�Ýl™Î ÓE~8ƒ‘P›ågÛäñ*"0à…pª?/àýr|29°×G¾ìsW— 8YÔl.»§nƒèaÂD!qèÞ… 汄ۗVôZ uÊ�ÈmçœP]â2í3ñV¿™ŠÂ¹å~ oè¼øä‹‡ëzÏBžÁû‡—ßð) ^'[f† Ê)/…¯ú;ñwàÂÐúzŽÝ$ô³ˆ­T"iñµp…¹§Ž¼áC�s±Ó©`ú] +_6l½R ÿê…Z>Þ0C,s ½ÒÂA^\x}€õ1Ø^°Ïø|þqüýŸ�¿ÿÞøŸ€÷/ÇÇŸÏÆ®I^$׊$ILF”¹õÐÊI3ÿ\üK}§zß‘øTrÀÌñ2ªÀÖ;Sñ.‘ÏFøÛ‡Ä÷’jèĵåDVòˆš‚~’lÉ8LÄ=¢—Û˜Èÿ…¼/'¸}®yéw/°¢ë•àVïb/hDC~‚ßš2â�ÕkýœRMÚ8d�ð©¯%ªÛ/ÏÝüóµBÏ·¯•ZúœTMàQ–€ºµì‰UÿKå>ùqìÈ(fç*¹Þ'-D•pÑçõ iêM÷g¿>4ß¡È1ÔY%®\Ú³j‹œYÐwŽWA¸ŒÏýÒÿÃ)ÝÚ#3þ{f+>®=ûà³¢[R:jK“|К¥1*­íp�ѫݙ0" HÅb@®rñmänOùxŒOl'A]ÑÁ/sÏ à虾Nm r'CÁËÎj7zt¡É�â;©uΩÂdwÀŸ ûhœ1 *�ˆ}%ÖIÑñ3xÕÁÊ/)mø�A½§ìÊÁŸÁŸ!;üîSž‡ª-tÓ‘'O¯’Ú¦—ËR.“´ò€ã_Õ,Þãà}&HVÿ¡‘x_6ð¦ÝýçÉÆÌÎŽG×Õ8ûÐþÕ¦ ॠN\ùg1¼3×Ár+ìEg1÷rv3Æ]𑬗ãÎ"¿Ç¶š†‡kZ woXÊìZŸ7kœ} ÿ¹r Ç{ÀÜc%à‰1Ç�Ã6M=O¾-ù \ÑÅ­Åñ[ã„m0UKRÇIûiåöíh6¨­¥mÂüP +V=ýEuÿzÎk¾cÒ6R§9$Ö“m®¥‹ƒ@¢,ÎX¯÷àêyýD)¥¹% ñ¼× Œç„ܽê:¨ò™ÂYk°�Û¹C_!`¼7ÃurI,…º…[Bï]‰�^N“ýŽ8uÂέ“=žï¹+¢ ƒãU l´š?&®$ÓÓí~±8ïçÞ�D–ëx˜ÓÂL¢œ­�‚84˜2ŠdÜ1ùçµdž:+Š´–8�Ú8‘l ¤%‰ŒþÝÄâ{$Øy�Oq1‡70RË!…È~R§Í6ƶO\?h0´ ýzËœ€�y�Íß ˜°íÇ^[ú<™>í ÛPÃ7=x †ÂS³iã2k¸õ·ÉàDq{V‚3™Åpó³<àDóc¦VB}\^P�½9,HkÖ 7^†õ† ÑôÖ”!ø®(M~1Œnû&wÁo¼ËwO¥�¿‡ã~îyƒ§;oèRÑ�må9“ÇOÏdXÿ³»äE“ïE³£o *âKŸvë븗É-¥A¡bÜ(Æ��#yÁç;P:,tõ.)]êÍÊîÄmÉtÜëG¼°Wƣɲ2&Â_µÂ†ÚQtné_2u"»¢#Ù·uâ$g÷$×Ò&tÂ({ùd5‹ï6ÎÄ›5^-4&BˆW&¤ƒy<¿¤ÍÂ=€‹QNˆª€yðz9Þoàç'*CÛÓàF'ˆqä®äKµÃDÕ6ýY]Öuûç"R¢µƒ‘ž²Ë jÏ ¿Æ,üÒˆ¨Ö²½óûM®]l„ð3å ò©2tÊÐô>�媕z¯w{î\¢Û.Šá+ ! –•ýz$bÞ V ˆ�šrñbá½u€=Æl]ACÇQòi² FdŽvMä¼–Š>tMj]±Vý¿-^¬õ²X!PïÀ̹O£�JîZ&\iÇ ï?ñ÷úÓñÇ?†ý—á×_ ÿµð׆?Þ‘P{Ùî*Y_p,˜3 ¿°Ö*>)SížïÇè¿þ[ÓÚ"´ÐsÛ Ìâý ™XÀkE"‚GmûAú#µ0Â`Øñ"òd– *ˆN ùì ²ªœéNÌÍ7€gà.‘.ú¬iQ0ÓIp €úþT‡ÊºÕOÕYßEz7”¬ª˜H‰Îá¨Ùƒ&dóùx�¦@µdÃ'~(Âßtçã(~out3ßÁÛ)õ6Ç®ôT7G%h˜ËY�þ¾]!©Z„ôÏ/:Œù¢há2Q ãªóó„Dƒv¹§GÜð9;{|-~}š wŸCòc,8àSPüvRûñ§\ÜïRc´| |Òü õj×ãÚ³}L\dOHl–ôè]9�¬óé9À+mý&M¿á÷·&»ùtêœûô¤‰÷ÜìŽÿ6‚ß›»6pÜW‰úŒüzmôp8” 5 Ø2±Uq–}v×_uÝõ÷oK "à΂¤ÆGiÞ_$ó¶ŠŠ ÅcÂ|óMÊUeÿÑDDâã"籆+XÒtÅo_‚u€•±÷, ¤Í3ú‹V•|Îxce~P±9cQcÑ×;ÖÃ1«a’ëÂËŽ–Ç/ñÁ÷Þ—JE qH�4ÒÂÈsŽš€5Ÿ=ÿª-Jô)Ýù{Þ߃m�HÁc°9I Äú Õ9ùíI˜°_Ò÷l}*^ÝÚC ‚[,¡Î3Xm5_ÂëÒÎàxjþ'ñBCT;g3¹S}³“vûs,ëv¯`€XÄñ üAOŽ8~„ütÂÁ%HSöƒò²Ð�ÿJäXÜÎNPÉ€ZßǶÉ8“áF¶^ƒT&M86.ý‘`¸Íú‰Šå,�1VÕ µÿî°¾¥^˜2)Üx×ïgÒEá=ž—Jt�ÍW„%Ôá•p¸d4éTÆÙ>I P”1#ÒÀžÒß¼5úåû Ü<¶YÁçß'-I:G”×?L¡ .ó·ó·àÊ€••6ï7°÷ðŠíH8±ò½�´ï®:!Tla±÷zLDŽ•8œXÊ9¥júâRMP¦%<¤±¡œ¿ëDŒä,^íɳ9ÊÞ ¹"þ®çóA|Ÿ|+ü¦ìµD\îV ojwl,?có9àC‡Œ-™ôy?7È>(�=é–çÚ¾‡2ËNû%xÉëÄA%rI+¶1K>QžÎ/«²»mdFË*)[ ¡·òZV6ȇòg¢ìƒÞgèpeªŠ�|üëÇþϯ¿6þúsáÏÃÏøYŽr;/Å&\ÌVVwÇÙH±Ñuà„Qþªy'®zë Ø†C·H¼^ŸË„üý2oË¢Pk[æGU/Ž!?}b’lÍeím^¯*±aŠ!«}8Ä7kÅÛ2êÒ·_?ùÌ”/Ý¢c¢]�y©èëÅ9°‚OžNÙ Ÿ9ågô£÷ªªèÿ«ˈ)’J9H…V�“¶©r tKYëàÅ’àC�ÃcRgè„•´K5ܱϦm5qÀóp%„§–¯‘�-v¿n4Z7�´· •æ¸ntè.ˆ°Éû¦÷÷òŠKO—¾Ñz½ƒ Ï’™’Š¿¡æ€V¨“¿4±áÒÊ8+'ø>]X<\¿­ø©Ð �Rf‰OOxç0[(Ïxõ9÷Šg+<Ý©pí\9tFMZðÆ™8Ÿ»:oDù†5’“·�A´ƒnƒ^ §xW¬�¿¾�v¸‡6’ÿõÖgOÅÃÍÜ—»LþÜq=ýÒ»Š,Ö~ÁoÞiþòcË[?¢me§îyD*åyîÙžé3ÑK7ÇŽf¾iÉ„¦€çJ�êCÁ²£OÕù„­î?u©^€êÙ.Ä(99þj§ÛÂÇ Š×AΑ˔W׸&cõ´?àÊ�xˆs&u8'!ΕØue'Ÿ7¸ fpyÈ$ÏwŸ•ž•÷…½�bƒ�gNÒ(/,Þè’©ò“Ô˜&> ȹ|ÎË.Š�&MÝyËùnË[Çß ¼�µc(\Õ®ù±¿˜É´�‡Â�\O¸6|À1ì<“9>Îû¼Ú­æ nDß&týVŽ/aòć¡’ns@ý†¶}ÁO[Eé��& ¶=HI'(?p§r—³^ú |Û±»|¸˜ÓAÛ­`q~= Å3^³�‹{•j³ƒ_;ÂÆÙÄp½!¿Ù‚È¥Èd �c?t¶–âŽÆòö.á>F¨m]tÌfþ¾è%ÐÊ�ƒè ²Ï1P]£+ôJÏѦ1ëç“w SÙ‰øý(¨$«ÕjϾmìeÀ`t¼^áÁ� •ýÅ¥ÅäUËDx±jÚ}{íèã Øxý?? ¼~ò…Ýk(ëâl´ š+pdŽ�yCy4a: jþ‘%:XØxÁñZÀÏÞ/ÃûeXfù">+¨>â'lXÉ`$üâ�•z_Å%e®¶l_Uò…÷ëUòÔªèíL†\rçª3¿Oƒ(^µqßù]ëþ Ó7ý¤s–ùlÃ6‚ùÇóZÐR“Ï|Þ¢eÛƒ2pVÀuиޯ–¸PúF¿œxËÊ,´m1vX¾@ž+h+9»'J>¦.°ôyÿç\­Õ‡–i\|As¨ e(C™wÊÀÚ'³~æäÝß"÷6/¬Ð÷ï $QàŒ{$í�Òƒ¿—t©ÝýúéKQ�O¾ b>c.§±Öµ l÷°¤rÀÏ3ä[]qr+ÕÝOáœ}T!¯©�•üo3ÞÚ˜|®[kžuM´Q©wµ°¹êÞ¤uEÕÛ�I�¤x⸘òF;;W¥�íÐbOйüÖDy­O �DßÀî•üz|O´Fb`fú°iìöl�ãà€ç=¨p6ÙÀw5Æ{Ž(µK[–ö‚÷,3¬Z‰*÷‹_Îåæî‘XxÞs{ù±Žy^;1áçX :ÝË~ø3ê,ºàçhmº‹hsX<«Mn¯{ˆª�nGtÕ)ÕÞÃ8(•s G$£î(ëÏ9ºÔ§Oêríñˆ7œè]ÔêªS¹žÇ¡�<ÂYuÍó­›ú¥›Ô¡6x¤Ôøž²[©£wð~žw&ŠˆO^±Çƒ¿·‡Ô s¼§¸v²ˆ…ƒ-c¤™òX·7y‘§›—‚q–àîäi1í“Ü”¥Ï'ÿ° ›m=N¬L=.ãø6_34^pÑy”å¤ítù u� ¾/�zéwõûÚÔÝ~Üÿ8|V¶™¤Oëé’²dìƒ"Ôu�úRrJ¾›+œR.1 ÊsJóµÞ8h“’Ï·2× &ÕÝCg*OtÿÈG–ª:ë{ˆÛª!ûœ[áJu¡ D hP]&[ÃÈ=€�z:ÒaðÝa‰ïöº Â÷�E醈Ĝ-7Îf2™>•ã]~;mÔ{Ý¢ )J–gG¤îP@suœ*,±E>·A:��•wsë‘©F•ÀÖý׊”ðd|nè϶½ç ð±J�öæ8–&@�þ8ƺ7/m‹x®ÃFit”¶½Ì7})•+Á­¥^¶iÿøl¯(Þ!½ÛÖ㬸 ¦’ËøF%%§�)óš‹Ã,â]ÜMáemwªÝ©iGïÝÐÕwɹ;¶o¸gR@çm§ŽóÐoq­e.ô«0ý×ã"€î±WêØÞÙJýòxŸNýx9fž£!/9˜B�õskÅjKåÂÏ?Íb"ª*½˜õµjô«½ËÁ–G�ç'_¡Û¹W€¿‚¡°éj'¾ ì—}zKâ—»äÞQULá•ξkÚyœY¤ÑÌ©<€‰ç¤CáÄ2)À2›,“µpVBcÒ^ã9ݙ඀ee:Ÿ ¶\¾o Kbޱ¶By*x&š´(”Æ|¶t¾ðËØvÊ«Í‰Ë -/]ݪ§‹pªFàä¿,á�ör_�ú7üâs~ÜK�õº&ÒN+­r‘ÙóÐñsl.ßKQ«®\à¸ÏT±#yÑg\iáè#¿×¶;GÛôf×Ñv�q£E?V,‰ÎÑD%aÙ¹{™5®èbÂa'ÄY(M>Mû0[ô?e•<«É²àöÆñîŠHêK‘ˆx fsBÅ–÷ ŽÒ "'ÒŽÊ¡ë3 ìò´-‚gçum“;º/'Éæù:Ê&’ਗ਼v:O¾Üö~ð°�¿€í†�ÇJ��d•^ÀRË5×ì?Ì†Õ RÃ}ä{ ZO�dÐzn\OÚŠ:%ŠQ:ž¸bb‰ê4yuØ�Q� Te©h~ù¬?ïÙÎ)‡LzÊHñÝüCç�U€€È‹vœxÊYTµÏàƒ.Ù1-žÏþJ—yóa44ÇÏ =NòÇÀ…O|ŠjŠ€JÓ¥‚þ™h7Ë„:·â~:½ªÊÕË• gºz,>,9k]Å?CT½láµV|Ú²³Õ+…ªWo‘" ‹���-DEvN2rû¾å¹pÔK½Ààx/àgþüã�?^øãýÂÏûU~ðg;>{㟠`[mþyi�IDATV+ à Z×þA¬P¥.jײÙ@ H·ƒžq?™i  +~[¡’®“R؇ ¨ËXSsöõû-@æ¡“Q "ó·Š%“,VRsÁB#…�°Ì€º×Ë׋ïKnõ¾l7íOº%p˜ó�ØÙ®aá²Nšlw`ïæüê@á}ªÎ%ï•m_Žà›Öa4Õ¦j[) &žª»¦á|Âsðè|íy�_ì>8¸jÞ}øê­ðnõ]fw3P1VØŒ¾Kú¾ÂÙ+UDŸpOz4®Ãœdµ1Ï]d©Ü3·ÚЬ’À·mô8L~´ êm LMfV¡ža\?k‡{UÄ<(jƒ®Qo*NNžq¡ƒ‹=+ø¼]\ã:I^èñ5@ž§Ô×i4Å‘³· È�üü“Žß[Š)ù1Ú°ÉkÐï­�.€}íhÔØ9õœú*·ß,ÓÞÛêÓzà¼ê ß½èçBio�»ÞÔ÷ôµ‰‰æ`Òú;.»àº¿ÖÅ"[2„yBoŠ´}ôA“G•?Óci›êèÑ|« 'ò_ï_´ç @w ÃP¼g隦Ԉðþ†s�¶O�~²kPs€«5[ ¦ž6œÓv{�ùÜÉ”íÓß1å®U�� sDW¹"®¢øÔz#ø×ÇïÛÑAn])ëáó80ƒ‡>sH1oÛ·Ží¥=){ÖØ ßæ&#(a[+Kj[Ïb̵º>åL0i^ç:‰Ó›ƒXqããV~]íÒœRí3&1^8¼¬ãiW](ü”Sš±Hø•~j¥º ¿Ç#z¤à³ÊV‚’ 1çø¬ ŸK¡úŒ¹mú�OW;r¥!ÛštŒmTµ’û|Öñ¿mG �Óà:IEND®B`‚openvdb-13.0.0/doc/img/multiparm.png000066400000000000000000000114221510223237100172650ustar00rootroot00000000000000‰PNG  IHDRÝ_"PŠ^sRGB®Îé pHYs  šœ·IDATxÚíÝ}PSg¾ð眓 1$’€Ð¢H�¢3ja×­c-E¢v˜0øGm»j§;£ÎHÇïŒz‡ëÜwvïv]]�­:w 3Pœ�©ëK‹Tƒ jgÇV6 E¤! IÎÉ˹œ.Ë©�Í÷ó=yž#}çË�'OžC,ùùùT~~>`á 1 ŠC0‡¬Vk}·ñññ¸dÈe˜µþþ~  êêêz ÿJ~~¾ÕjÍÉÉáy>TFæþýûˆfä2C*•b‚æp8ôzý¬²òâÅ‹Atá8Nø:„r™Âq\DD~N�Ë0k½½½„à(•Êà²2èxõù|v@.Ì}V¯¡U/r`~ ^ä2ÀB¯—=^ï˜ÓI‘FE‰E"ÔË€\˜çz™e9yŒBĈ†mC"†™Ãx�mG‘H´yóf­VËó|ggçõë×—-[–››[SSƒ ‡\£\æ ¿uËëbqDMMí¤IúÒæ1ŠŠŠìvûŸþô'žç322¼^¯Ïçãy~¶ç¡( ¥:r9Œ0 óÖ[oeggó}êß ´´´©©©¯¯oüˆZ­Þ³gÏÇ<‡ßMÓeeeï¼ó΢E‹ZZZ:„ÕÍAd¥×ëå q»Ý„¢=ŸÛíæD EólÕ<±K`NèD +•Êää人:áŸkoo8ÏÆ�W®\Éóü­[·L&ÓÒ¥K7nÜ(•JY–­©©Û²e‹ÃáÈÌÌloooiiÁµF.‡‹’’—ËuâÄ ŸÏ—••åõzê”êê깪¶¦±téÒ>ø ®®În·Ÿïûï¿ß°aƒÑhä8N©TÚl¶ôôôÊÊÊÑÑQ�F3þÞ`or9´™Íf�FCÓ´Ûí®¨¨ÈËËS(“Þ� ÃL¼=>|øÉ'Ÿ¬[·î£�>:yò¤Pð¾`(¿ñÆ~ø¡ÉdÂÕ bƒ¦(BQ CÓ4EÓ4CS MO¼š»Ì0‚g[º~þùçÛ¶m;|ø0ÏóííícccIIIK–,yðà�Z­Þ¿?Çq]]]W¯^miiÙ»woOO�B¡@½Œ\Sƒƒƒ===:�î‹/¾ày>**jª–v»�¦éÔÔÔG�¥¤¤—/_þÓO?577¿úê« /’ËŸ~úiaaáõë×¥Ré»ï¾{óæÍü×hVõò¿Ž�¯ MÂÊåù]'çt:/^¼ð#W^^.|ÝÐÐÐÐÐ0þÒÝ»wïÞ½ëßøÊ•+¸¾ÈåpTUU¥ÓéŽ?>:::22R__?Õ YYYYZZʲ¬Édnì%K–ó}}}/¸áäæÍ› ![¶lÙ²e !äý÷ßG.—•4E¬VBH¤X�zñâE½^t_ìlZ¤R)`N8Ž)ëåñG7¾ÈÆ+A÷å8k?C v˜›üs%/²ñ 6mxôT5o¦éÛñèÇÁá§.·§ýá#Î힪/¼¤zY&‹>väw²E²?žüˈ}55ÀìryÒÖëó � žÞ¤}Å"qdT¤T"QÆÈGlOP Le¦óÑ2YFæJ†axžgDLÒÒ¥*µzæóÏœ|²6¸Óå²ïY�'!1ñ7ïîÞ¾c»L&×m×ýöƒ}’èè€f}»÷ÙÆN�×éñªT±E! E ç#ÂÁž¾>Ëù÷  Ã;vìèÑ£{öì‘Ëå JKKý�¨Õê#GŽàçó?£(êaWWKkkþky‹c/[šÚÜzÛÚ×7i�;~P#?vä°°Ê•"$""‚a]Qá¶ÂBˆX$ªª®mÿ§1 ‹å’’—ËuâÄ ŸÏ—••åõzF»ººzú+a—Ë XÖåúêˆô+Ò–-s¹\_^ûÊõìBè‰}£¢$òEr©TòseN3EÉ¢e„ð„š¦ccóáW,«T*­V[^^.ü��FáxYYYssó¦M›êêêt:]MMMoooBB®]»†ð?‰X,.++kkk[½z5!äÌ™3ÃÃÃË—//((ˆŽŽfYöܹs£££:�Žã¸ôôtµZ]__¯ÑhV­Ze·ÛÏž=ëõzãââôz½D"ªªªbY÷@ÈÔË„�èhiAᛪØX³Å_¸­àÊß®8ÎiúöYÌ8ùçX…’"•J‹ßÞ.“ɾ¾ÙÔÑÑ)4h½÷�J!·J0))©··7 F$''WTTøÙ½{÷åË—�FcFFÆÎ�;ý_Z²dI]]ÝÕ«W‹‹‹×®]ÛØØ8<<|á‡ñcÇŽ¼¼¼ëׯ ç<}ú´F£9xðà©S§.]º´ÿ~­Vk2™JJJªªªl6Ûúõë7lØÐØØˆû drÙçó%j’ò׿v»õε«×ÞØºõ׿Êo{ð�ïMí”0m>#„÷‰P˜ÊtŸ÷³Z­999Á­A¾xñ¢^¯º¯ÿ'ÂaážD/ÎñìcFžÉeŽã„/æås%Çaj;´` €9°´ Ÿ+XXfºÿòLLÓ·ãÑ�ƒÃO]nOûÃGœÛÎû/Lï%ÕË2Yô±#¿“-’ýñä_FìC¨©f—Ë“°^Ÿ�¡Ÿ¿®nÒ¾b‘82*R*‘(cä#¶'(�¦2ÓyŒh™,#s%Ã0<Ï3"&iéR•Z=‹çHùŸ|²6¸Óå²ïY�'!1ñ7ïîÞ¾c»L&×m×ýöƒ}’èè€f}»÷ÙÆN�×éñªT±Â#JŠÎG„ƒ=}}.–óï&†)**:vìØÑ£G÷ìÙ#—Ë”––&&&úQ«ÕGŽÁÏ+æ1~FQÔî®–ÖÖü×òÇ.^¶4µ¹õ¶µ¯oÒ:wü "F~ìÈaa•+EHDDÃ0º¢Âm…„±HTU]ÛþOcË%%%.—ëĉ>Ÿ/++ËëõŒvuuõôWÂ.—'°¬ËõÕ— é+V¤-[ær¹¾¼ö•ëÙ…ÐûFEIä‹äR©äçÊœf(Š’EË„ýÑ4»˜¿bY¥RiµÚòòráÜh4 ÇËÊÊš››7mÚTWW§Óéjjjz{{víÚÅ0ÌÀÀ€ÿIÄbqYYY[[ÛêÕ« !gΜ^¾|yAAAtt4˲çÎ�ÕétÇ¥§§«Õêúúz�F³jÕ*»Ý~öìY¯×§×ë%ÉÐÐPUU˲¸B¦^&„DGK ßTÅÆš-–ø¸øÂmWþvÅépNÓ·ÏbþÃÉ?Ç*”„©TZüöv™LöõÍ¦ŽŽN¡Aë½oT y¸U‚III½½½5² 99¹¢¢ÂÿÈîÝ»/_¾l4322vîÜéÿÒ’%Kêêê®^½Z\\¼víÚÆÆÆááá .8Ž;väåå]¿~]8çéÓ§5ÍÁƒO�:uéÒ¥ýû÷kµZ“ÉTRRRUUe³ÙÖ¯_¿aÃ†ÆÆFÜ!“Ë>Ÿ/Q“”¿þµÛ­w®]½öÆÖ­¿þU~Ûƒ|ojŸødëñ¾‰ªÅCVë�ÕJa=¾�;Š!�í&“ˆ¡ !j…œ¦épËe�Ç3^ó:tH,·¶¶Þ¸qƒrïÞ=ÿ–111‰D(¨ŸóÙ¿žëúáŽe¯\¾ò÷û÷�c£“.¥ïëÙ¼ß×4M�¿†‹1Ìf³F£¡iÚívWTTäåå)ŠI‡�a˜™Lòðþ¼^¯ßºu«Ó鬭­5›Í¸ÊwMŽãl6[NNNp»ë ½^?i_�×',à „04=qVÚ`0äææb?¹PÑßß/•J±ŸÀœP*•Óí¿<óºxšBlâA†¦¡æäü˜Ç˜ìI0÷¹úèèÑ£2™lΜ9B¡°­­-//�âää#‰t:]VV–Éd Ÿ9s&Ã0eeeõõõ8q&{:Ó4=2R !®®®lÞ­[·.++«¿¿ÿµ×^›?~iié²eËF•Œ�f¶©Ù³g{zzîß¿ŸÇã%''ÿùçŸ÷îÝ#„ †ŒŒ ©Tº~ýúúúúY³f�ªÖÖÖÆ•½½ýÒ¥K<¨ÕjCCC/\¸°xñâÒÒÒ7nDGG÷ôôÔÕÕ-\¸ÐÕÕµ­­-  ¦¦fœI÷øsgooo£ÑxòäI[[[�N'‘HÞ~ûíÇëtº¸¸¸… *•ÊÀÀÀ´´4�gee5ÜÎð¼›}”Édß~ûmoo¯D"yÿý÷¿ùæBH{{{UUÃ0~øá´iÓÚÚÚ/\¸P__/‘HŒF£¿¿?ŸÏ?tè�Çûàƒð>æÎÌÈtfF©T²áèææ¶fÍBEQwîÜ‘H$£Jƶ9œÎ¾¾¾J¥Òl6›Íæêêj??¿»wï2 s÷î]š¦;;;5�££ãØj­­­l;žžž·oßîïï'„(Š˜˜˜ââb�FcccCÓ´P(d»²²rîܹ÷ïß÷ööþí·ßž:�ÕjuhhhDDÄÕ«W-‹‡‡GSS“F£!„(•ÊèèèÒÒRµZ¯P(ÚÛÛÇ.‰°ÏÕjuOOϨÝuuuÉd2www{{{�F#nݺEa_ ¯¯¯‡‡‡——!D(N™2e``ç.V6þÏ- ;¡Öh4iiiÃå£JÚÚpSÃI=ò0\ÈãñØ…‘QÕFV¹ûX]]½råÊ ´¶¶²W‘ÚÚÚÈÈHµZ=þ;{ã§³V«=|ø°¯¯ï»ï¾Ë®È�MÞÌÌÌiÓ¦½ùæ›­­­¥¥¥Ìð]7òåBV¯^­R©Îž=ËápȘ•n‡SRRríÚ5œ¯“52_k¸foo¯Åb™={6Ã0B¡�Ïç�-§�†††yóæQÅç󃂂êëëÙÆÙe‡ÓÓÓ3¶MÓì’wîÜñóó‹Å„���¶…   œœœ¯¾ú*++khhˆa‹ÅR[[¯R©Æ]#/#±…ÎÎÎ"‘èÖ­[×®]óôôlnnööö‰D Ã766òùüiӦݿ¿¨¨ÈÇLJ¦i­V+•J !þþþÃkD#wÁ>·¶¶–H$UUUÇÙÙ™¦i¶'ÙF!·oß áñx4MK$úp6LÞ¹óÈ©ëÑ£GW¬Xù÷ßgggwttŒ-yÔʆJ¥rqqÙ¶m‡Ã¹téRSSÛøœ9s/^Ì0ÌñãLJ††Z­§§'$$¤²²277wݺuEµ´´Ó4}ïÞ½÷Þ{O«Õ uttäææ�F•J5þüÆÆÆñ?w1þÜY(ÆÅÅñù|“É”™™Ùßß_PP°fÍö]Á²²2‘HƆéÙ³g†)//���7 ååå‰dìEŽ}ÔëõMMM[·níèèèêêb{éôéÓqqqK–,ÑjµÙÙÙµµµNNN7nlnn>wîN\€G.—+йsçþ뇲mÛ¶ÌÌÌáEÛ§�ššš‘‘¡×ë­¬¬¶lÙ’��ÝÒÒ²dÉ�WPP0ΆW¯^ wvvþ?ð÷ï*--ůïL–¹ó³4êȧPSS³yóf³ÙÌ0LuuµZ­NMM8zôèc›Åwéüp{öìù[(,,,,,YòÅ_<á¶ø� @:OD˜;ÀDLçÚÚZ¤3Ò&\:Oò»¾{ùå—ŸßƒÇ ¼0ÚÛÛy#ÿ@�üë …\.§ÐÒé Hg¤3 ��΀t¤3Ò�ÎHg@: �é Hg¤3 ��΀t˜,xãüÏßß?::š¢(�FóË/¿tvvŽß‡ÃY»v­T*ÍÏÏ¿qãÆø•-Zd4U*Æà¤3�ÇKJJÚ½{·N§suueæ±Ñ,‹ÝÜÜ>ýôÓ'ÙqEEzà§3—ËåóùB¡P§ÓýñÇlágŸ}–‘‘ÑßßïëëväÈ‘ØØX�NXWWçíí-‰¶oßžžž=Î1 ±XüÉ'Ÿ0 £×ë/]ºôØÏç¼`8r¹\¡P$$$´··O�cš3gŽ»»û¯¿þÊ> ùî»ï0T0I( ¹\Λ€GÖÖÖ–ššj6›u:]nn.F &›‰˜Îýõ×�060™áw6žŸ¹ó¨o‹Àÿ+�@ðDé<¶éééñõõ�9s¦››[gg'»’‘‘AÑëõãìn``ÀÊÊÊÖÖÖÎή»»{xýÄËËËÏÏ�" mmm¯\¹’˜˜XZZZWWÇÖill4›Íf³yhhH �FŒ �a‘J¥z½þQ·\ iš}Ëår‹ŠŠf̘áååEáp8O¸‹ÚÚÚøøø›7o—Puþüùá:!¤¬¬ìúõ믿þúÂ… GÝ…�a˜'ßÀ‹ßœìø|~TTTzzº¯¯¯««+!Äd2I$’±5gΜYQQ¡×ëÝÝÝÙ’Û·o‡††²“_‰Db2™Äb1EQMgÿšššá’úúúÐÐPö’ààà@ñóóëëë+((xå•W¸\.†0w†I‡]w&„ܺu‹¢(•J¥ÓéòòòÒÓÓU*ÕªU«d2٨Ͻ•——'''wvv¶´´°KÃùùù+W®Ü¹s§ÉdÊËËkii©©©Ù±cÇÅ‹ ÅÈm ÃîÝ»5�P(dKjjj¤Ré–-[ gÍšµtéR‡S\\l±X0L0Éqär¹B¡HHHhooGwL|]]]666Oòm|“à9¥P(är9V6&"¬l< ¾¨ €t†‰ë“V6�΀t@:Òé Hg døóÎ999è €‰@.—öw6ÐÍÿÀç û˜ÍÃIEND®B`‚openvdb-13.0.0/doc/math.txt000066400000000000000000000444001510223237100154650ustar00rootroot00000000000000/** @page transformsAndMaps Transforms and Maps @section sMathContents Contents - @ref sTransforms - @ref sLinearTransforms - @ref sFrustumTransforms - @ref sCellVsVertex - @ref sVoxels - @ref sStaggered - @ref sMaps - @ref sGettingMat4 - @ref sCostOfMaps - @ref sGradientAndMaps @section sTransforms Transforms in OpenVDB The OpenVDB @vdblink::tree::Tree Tree@endlink is a sparse representation of a three-dimensional array of voxels, each element of which is addressed via discrete, three-dimensional index space coordinates, typically in the form of a @vdblink::math::Coord Coord@endlink. For example, the following code retrieves the floating-point value of a voxel with index coordinates (1, 2, 3): @code openvdb::FloatGrid grid = ...; openvdb::FloatGrid::Accessor accessor = grid.getAccessor(); openvdb::Coord ijk(1,2,3); float value = accessor.getValue(ijk); @endcode A @vdblink::math::Transform Transform@endlink relates index space coordinates to world space coordinates that give a spatial context for the discretized data. Translation from index coordinates @ijk to world space coordinates @xyz is done with a call to the @vdblink::math::Transform::indexToWorld() indexToWorld@endlink method, and from world space coordinates to index space coordinates with a call to @vdblink::math::Transform::worldToIndex() worldToIndex@endlink: @code // Create a linear transform that scales i, j and k by 0.1 openvdb::math::Transform::Ptr linearTransform = openvdb::math::Transform::createLinearTransform(0.1); // Compute the location in world space that is the image of (1,2,3). // The result will be (0.1, 0.2, 0.3). openvdb::Coord ijk(1,2,3); openvdb::Vec3d worldSpacePoint = linearTransform->indexToWorld(ijk); // Compute the location in index space that is the pre-image of (0.1, 0.2, 0.3). // The result will be (1.0, 2.0, 3.0). openvdb::Vec3d indexSpacePoint = linearTransform->worldToIndex(worldSpacePoint); @endcode In the above example, there are two things to notice. First, world space locations are specified as three-dimensional, double-precision, floating-point vectors, and second, @b worldToIndex does not return discrete coordinates, but rather a floating-point vector. This is a reflection of the fact that not every location in a continuous world space, i.e., not every @xyz, is the image of discrete integral coordinates @ijk. @subsection sLinearTransforms Linear Transforms Currently two different types of transforms are supported: linear and frustum transforms. A linear transform can be composed of scale, translation, rotation, and shear; essentially those things that can be mathematically represented by an invertible, constant-coefficient, 3×3 matrix and a translation (mathematically, an affine map). An essential feature of a linear transformation is that it treats all regions of index space equally: a small box in index space about origin @ijk=(0,0,0) is mapped (sheared, scaled, rotated, etc.) in just the same way that a small box about any other index point is mapped. @code // Create a linear transform from a 4x4 matrix (identity in this example). openvdb::math::Mat4d mat = openvdb::math::Mat4d::identity(); openvdb::math::Transform::Ptr linearTransform = openvdb::math::Transform::createLinearTransform(mat); // Rotate the transform by 90 degrees about the X axis. // As a result the j-index will now map into the -z physical direction, // and the k-index will map to the +y physical direction. linearTransform->preRotate(openvdb::math::pi()/2.0, openvdb::math::X_AXIS); @endcode @subsection sFrustumTransforms Frustum Transforms The frustum transform is a nonlinear transform that treats different index points differently. And while the linear transform can be applied to any point in index or world space, the frustum transform is designed to operate on a subset of space. Specifically, it transforms a given box in index space to a tapered box in world space that is a frustum of a rectangular pyramid. @code // Create the bounding box that will be mapped by the transform into // the shape of a frustum. // The points (0,0,0), (100,0,0), (0,50,0) and (100,50,0) will map to // the corners of the near plane of the frustum, while the corners // of the far plane will be the images of (0,0,120), (100,0,120), // (0,50,120) and (100,50,120). const openvdb::math::BBoxd bbox(/*min=*/openvdb::math::Vec3d(0,0,0), /*max=*/openvdb::math::Vec3d(100,50,120)); // The far plane of the frustum will be twice as big as the near plane. const double taper = 2; // The depth of the frustum will be 10 times the x-width of the near plane. cosnt double depth = 10; // The x-width of the frustum in world space units const double xWidth = 100; // Construct a frustum transform that results in a frustum whose // near plane is centered on the origin in world space. openvdb::math::Transform::Ptr frustumTransform = openvdb::math:::Transform::createFrustumTransform( bbox, taper, depth, xWidth); // The frustum shape can be rotated, scaled, translated and even // sheared if desired. For example, the following call translates // the frustum by 10,15,0 in world space: frustumTransform->postTranslate(openvdb::math::Vec3d(10,15,0)); // Compute the world space image of a given point within // the index space bounding box that defines the frustum. openvdb::Coord ijk(20,10,18); openvdb::Vec3d worldLocation = frustumTransform->indexToWorld(ijk); @endcode @subsection sCellVsVertex Cell-Centered vs. Vertex-Centered Transforms When partitioning world space with a regular grid, two popular configurations are cell-centered and vertex-centered grids. This is really a question of interpretation and transforms. The cell-centered interpretation imagines world space as divided into discrete cells (e.g., cubes) centered on the image of the index-space lattice points. So the physical location @xyz that is the image (result of @b indexToWorld) of a lattice point @ijk is the center of a cube. In the vertex-centered approach, the images of the lattice points form the vertices of cells, so the location @xyz would be a corner, not the center, of a cube. The link between transforms and cell-centered or vertex-centered partitioning of world space is tenuous. It boils down to this: the “first” cell vertex often is aligned with the origin. In the cell-centered case, when the cells are cubes of length Δ on a side, the transform @xyz = (Δi + Δ/2, Δj + Δ/2, Δk + Δ /2) will place the center of the first cube (i.e., the image of (0,0,0)) at the world space location of (Δ/2, Δ/2, Δ/2), and the cube will have walls coincident with the x=0, y=0 and z=0 planes. Using the OpenVDB transforms to create a so-called cell-centered transform could be done like this: @code // -- Constructing a uniform, cell-centered transform -- // The grid spacing const double delta = 0.1; // The offset to cell-center points const openvdb::math::Vec3d offset(delta/2., delta/2., delta/2.); // A linear transform with the correct spacing openvdb::math::Transform::Ptr transform = openvdb::math:::Transform::createLinearTransform(delta); // Add the offset. transform->postTranslate(offset); @endcode In contrast, for the vertex-centered partitions of space the first vertex is just the image of the first lattice point @ijk = (0,0,0), and the transform would lack the offset used in the cell-centered case; so it would simply be @xyz = (Δi, Δj, Δk). @code // -- Constructing a uniform, vertex-centered transform -- // The grid spacing const double delta = 0.1; // A linear transform with the correct spacing openvdb::math::Transform::Ptr transform = openvdb::math:::Transform::createLinearTransform(delta); @endcode @subsection sVoxels Voxel Interpretations A similar and often related concept to cell- and vertex-centered partitioning of world space is the idea of a voxel. A voxel historically refers to the volumetric equivalent of a pixel and as such implies a small region of world space. A voxel could, for instance, be the image under transform of a vertex-centered (or cell-centered) box in index space. In this way the voxel can be seen as a generalization of regular grid cells. The interpretation of data stored in a grid can be related to the concept of a voxel but need not be. An application might interpret the grid value indexed by @ijk as the spatial average of a quantity in a defined world-space voxel centered on the image of that lattice point. But in other situations the value stored at @ijk might be a discrete sample taken from a single point in world space. The @vdblink::math::Transform Transform@endlink class does include methods such as @vdblink::math::Transform::voxelSize() voxelSize@endlink and @vdblink::math::Transform::voxelVolume() voxelVolume@endlink that suppose a particular interpretation of a voxel. They assume a voxel that is the image of a vertex-centered cube in index space, so the @b voxelSize methods return the lengths of line segments in world space that connect vertices: @code openvdb::Coord ijk(0,0,0); openvdb::Coord tmp0(1,0,0), tmp1(0,1,0), tmp2(0,0,1); openvdb::math::Vec3d size; size.x() = (xform.indexToWorld(ijk + tmp0) - xform.indexToWorld(ijk)).length(); size.y() = (xform.indexToWorld(ijk + tmp1) - xform.indexToWorld(ijk)).length(); size.z() = (xform.indexToWorld(ijk + tmp2) - xform.indexToWorld(ijk)).length(); // The voxelSize() for the voxel at (0,0,0) is consistent with // the computation above. assert(xform.voxelSize(ijk) == size); @endcode In the case where the transform is linear, the result of @b voxelSize will be independent of the actual location @ijk, but the voxel size for a nonlinear transform such as a frustum will be spatially varying. The related @b voxelVolume can not in general be computed from the @b voxelSize, because there is no guarantee that a general transform will convert a cube-shaped voxel into another cube. As a result, @b voxelVolume actually returns the determinant of the transform, which will be a correct measure of volume even if the voxel is sheared into a general parallelepiped. @subsection sStaggered Staggered Velocity Grids Staggered velocity data is often used in fluid simulations, and the relationship between data interpretation and transforms is somewhat peculiar when using a vector grid to hold staggered velocity data. In this case the lattice point @ijk identifies a cell in world space by mapping to the cell’s center, but each element of the velocity vector is identified with a different face of the cell. The first element of the vector is identified with the image of the (i−1/2, j, k) face, the second element with (i, j−1/2, k), and the third element with (i, j, k−1/2). @section sMaps Maps in OpenVDB Transforms The actual work of a @vdblink::math::Transform Transform@endlink is performed by an implementation object called a @vdblink::math::MapBase Map@endlink. The @b Map in turn is a polymorphic object whose derived types are designed to optimally represent the most common transformations. Specifically, the @vdblink::math::Transform Transform@endlink holds a @vdblink::math::MapBase MapBase@endlink pointer to a derived type that has been simplified to minimize calculations. When the transform is updated by prepending or appending a linear operation (e.g., with @vdblink::math::Transform::preRotate() preRotate@endlink), the implementation map is recomputed and simplified if possible. For example, in many level-set-oriented applications the transform between index space and world space is simply a uniform scaling of the index points, i.e., @xyz = (Δi, Δj, Δk), where Δ has some world space units. For transforms such as this, the implementation is a @vdblink::math::UniformScaleMap UniformScaleMap@endlink. @code // Create a linear transform that scales i, j and k by 0.1 openvdb::math::Transform::Ptr linearTransform = openvdb::math::Transform::createLinearTransform(0.1); // Create an equivalent map. openvdb::math::UniformScaleMap uniformScale(0.1); // At this time the map holds a openvdb::math::UniformScaleMap. assert(linearTransform->mapType() == openvdb::math::UniformScaleMap::type()); openvdb::Coord ijk(1,2,3); // Applying the transform... openvdb::math::Vec3d transformResult = linearTransform->indexToWorld(ijk); // ...is equivalent to applying the map. openvdb::math::Vec3d mapResult = uniformScale.applyMap(ijk); assert(mapResult == transformResult); @endcode There are specialized maps for a variety of common linear transforms: pure translation (@vdblink::math::TranslationMap TranslationMap@endlink), uniform scale (@vdblink::math::UniformScaleMap UniformScaleMap@endlink), uniform scale and translation (@vdblink::math::UniformScaleTranslateMap UniformScaleTranslateMap@endlink), non-uniform scale (@vdblink::math::ScaleMap ScaleMap@endlink), and non-uniform scale and translation (@vdblink::math::ScaleTranslateMap ScaleTranslateMap@endlink). A general affine map (@vdblink::math::AffineMap AffineMap@endlink) is used for all other cases (those that include non-degenerate rotation or shear). @subsection sGettingMat4 An Equivalent Matrix Representation The matrix representation used within OpenVDB adheres to the minority convention of right-multiplication of the matrix against a vector: @code // Example matrix transform that scales, next translates, // and finally rotates an incoming vector openvdb::math::Mat4d transform = openvdb::math::Mat4d::identity(); transform.preScale(openvdb::math::Vec3d(2,3,2)); transform.postTranslate(openvdb::math::Vec3d(1,0,0)); transform.postRotate(openvdb::math::X_AXIS, openvdb::math::pi()/3.0); // Location of a point in index space openvdb::math::Vec3d indexSpace(1,2,3); // Apply the transform by right-multiplying the matrix. openvdb::math::Vec3d worldSpace = indexSpace * transform; @endcode Any linear map can produce an equivalent @vdblink::math::AffineMap AffineMap@endlink, which in turn can produce an equivalent 4×4 matrix. Starting with a linear transform one can produce a consistent matrix as follows: @code openvdb::math::Mat4d matrix; if (transform->isLinear()) { // Get the equivalent 4x4 matrix. matrix = transform->getBaseMap()->getAffineMap()->getMat4(); } @endcode This could be used as an intermediate form when constructing new linear transforms by combining old ones. @code // Get the matrix equivalent to linearTransformA. openvdb::math::Mat4d matrixA = linearTransformA->getBaseMap()->getAffineMap()->getMat4(); // Invert the matrix equivalent to linearTransformB. openvdb::math::Mat4d matrixBinv = (linearTransformB->getBaseMap()->getAffineMap()->getMat4()).inverse(); // Create a new transform that maps the index space of linearTransformA // to the index space of linearTransformB. openvdb::math::Transform::Ptr linearTransformAtoB = openvdb::math::Trasform::createLinearTransform(matrixA * matrixBinv); @endcode Notice that in the above example, the internal representation used by the transform will be simplified if possible to use one of the various map types. @subsection sCostOfMaps Working Directly with Maps Accessing a transform’s map through virtual function calls introduces some overhead and precludes compile-time optimizations such as inlining. For this reason, the more computationally intensive OpenVDB tools are templated to work directly with any underlying map. This allows the tools direct access to the map’s simplified representation and gives the compiler a free hand to inline. Maps themselves know nothing of index space and world space, but are simply functions xrange = f(xdomain) that map 3-vectors from one space (the domain) to another (the range), or from the range back to the domain (xdomain = f−1(xrange)), by means of the methods @vdblink::math::MapBase::applyMap() applyMap@endlink and @vdblink::math::MapBase::applyInverseMap() applyInverseMap@endlink. @code // Create a simple uniform scale map that scales by 10. openvdb::math::UniformScaleMap usm(10.0); // A point in the domain openvdb::math::Vec3d domainPoint(0,1,3); // The resulting range point openvdb::math::Vec3d rangePoint = usm.applyMap(domainPoint); // The map is inverted thus: assert(domainPoint == usm.applyInverseMap(rangePoint)); @endcode In many tools, the actual map type is not known a priori and must be deduced at runtime prior to calling the appropriate map-specific or map-templated code. The type of map currently being used by a transform can be determined using the @vdblink::math::Transform::mapType() mapType@endlink method: @code // Test for a uniform scale map. if (transform->mapType() == openvdb::math::UniformScaleMap::type()) { // This call would return a null pointer in the case of a map type mismatch. openvdb::math::UniformScaleMap::ConstPtr usm = transform->map(); // Call a function that accepts UniformScaleMaps. dofoo(*usm) } @endcode To simplify this process, the function @vdblink::math::processTypedMap processTypedMap@endlink has been provided. It accepts a transform and a functor templated on the map type. @subsection sGradientAndMaps Maps and Mathematical Operations In addition to supporting the mapping of a point from one space to another, maps also support mapping of local gradients. This results from use of the chain rule of calculus in computing the Jacobian of the map. Essentially, the gradient calculated in the domain of a map can be converted to the gradient in the range of the map, allowing one to compute a gradient in index space and then transform it to a gradient in world space. @code // Compute the gradient at a point in index space in a // floating-point grid using the second-order central difference. openvdb::FloatGrid grid = ...; openvdb::Coord ijk(2,3,5) openvdb::math::Vec3d isGrad = openvdb::math::ISGradient::result(grid, ijk); // Apply the inverse Jacobian transform to convert the result to the // gradient in the world space defined by a map that scales index space // to create voxels of size 0.1 x 0.2 x 0.1 openvdb::math::ScaleMap scalemap(0.1, 0.2, 0.1); openvdb::math::Vec3d wsGrad = scalemap.applyIJT(isGrad); @endcode */ openvdb-13.0.0/doc/nanovdb/000077500000000000000000000000001510223237100154205ustar00rootroot00000000000000openvdb-13.0.0/doc/nanovdb/FAQ.md000066400000000000000000000114461510223237100163570ustar00rootroot00000000000000# FAQ {#NanoVDB_FAQ} * **What is NanoVDB?** As the name indicates it's a mini-version of the much bigger OpenVDB library, both in terms of functionality and scope. In fact, a stand-alone C++11 implementation of NanoVDB is available in the file [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) and the C99 equivalent in the files [CNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CNanoVDB.h), and [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h). However, NanoVDB offers one major advantage over OpenVDB, namely support for GPUs. In short, NanoVDB is a standalone static-topology implementation of the well-known sparse volumetric VDB data structure. In other words, while values can be modified in a NanoVDB grid its tree topology cannot. **What graphics API does NanoVDB support?** We have tested NanoVDB with CUDA, OpenCL, OpenGL, DirectX 12, OptiX, Vulkan, HLSL, and GLSL. We are also working on adding support for WebGL. * **What are the advantages of NanoVDB?** Other then the fact that it runs on the GPU, NanoVDB offers several other advantages over OpenVDB. For its limited applications it's generally faster, uses slightly less memory, is implemented in few header files, and has virtually no dependencies on external libraries (other then C++11 or C99). While NanoVDB inherits most of the memory and data access advantages of OpenVDB (e.g. fast random-access by means of inverse tree-traversal), the improved memory layout of NanoVDB actually results in faster read access performance. * **What are the limitations of NanoVDB?** Other than the fact that NanoVDB obviously lacks many of the features and tools of OpenVDB, the most important limitation of NanoVDB is the fact that it *assumes the topology of the tree structure to be static*. Thus, it is possible to modify the values in a NanoVDB grid, but not its topology, e.g. see [modify_nanovdb_thrust.cu](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_modify_nanovdb_thrust/modify_nanovdb_thrust.cu). * **Does NanoVDB work on the CPU as well as the GPU?** Yes! In fact, it provides performance advantages on the CPU over OpenVDB, primarily due to the defragmented and more cache-friendly memory layout for spatially coherent voxel access. * **What is NanoVDB intended for?** Rendering (e.g. ray-tracing) on the GPU or CPU, and other applications that require fast random access into a sparse volumetric data structure (e.g. collision detection for cloth simulations or static boundary conditions in fluid simulations). Additionally, since NanoVDB is essentially a slimmed-down version of the core data structure in OpenVDB, NanoVDB also serves as a great tool to learn about the implementation details of VDB, and can even serve as a starting point for your own sparse data structure. * **Does NanoVDB depend on and require CUDA?** No, NanoVDB is by design agnostic and works with most graphics APIs, e.g. OpenGL, OpenCL, OptiX, CUDA, HLSL, GLSL, DirectX, and even the CPU! The data structure itself (defined in [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) and [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h)) only depends on C++11 or C99. However, some of the auxiliary math classes are optionally optimized with intrinsic CUDA calls (e.g. fma in Vec3) and some of the [Allocator](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/CudaDeviceBuffer.h) uses CUDA for explicit memory management. It should be straightforward to replace (or remove) these CUDA dependencies if you so desire. * **How does the data structure of NanoVDB compare to that of OpenVDB?** Conceptually they are essentially identical (NanoVDB uses the exact same tree configuration), but there are some implementation differences to minimize dependencies on external libraries in NanoVDB (e.g. no boost and std containers), and more importantly, NanoVDB has additional meta-data encoded in tree nodes specifically to accelerate ray-tracing (e.g. min/max values and AABB of active values). Also, NanoVDB is pointer-less and occupies a contiguous block of memory, i.e. de-fragmentized relative to OpenVDB. Effectively, NanoVDB is a linearized version of the well-known OpenVDB data structure with a few additional information baked into the tree nodes! * **Are there known issues with NanoVDB?** While the are currently no known bugs, there are certainly lots of room for improvements and enhancements. If you have issues or ideas for new feature in NanoVDB please let us know, e.g by submitting a [Github issue](https://github.com/AcademySoftwareFoundation/openvdb/issues). openvdb-13.0.0/doc/nanovdb/HelloWorld.md000066400000000000000000000161241510223237100200210ustar00rootroot00000000000000# NanoVDB Hello World Examples {#NanoVDB_HelloWorld} [The first example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_accessor/openvdb_to_nanovdb_accessor.cc) shows how to convert an OpenVDB level set sphere into a NanoVDB level set, use accessors to print out multiple values from both grids, and save the NanoVDB grid to file. Note that **this example depends on both OpenVDB and NanoVDB**. ```cpp #include // replace with your own dependencies for generating the OpenVDB grid #include // converter from OpenVDB to NanoVDB (includes NanoVDB.h and GridManager.h) #include // Convert an openvdb level set sphere into a nanovdb, use accessors to print out multiple values from both // grids and save the NanoVDB grid to file. // Note, main depends on BOTH OpenVDB and NanoVDB. int main() { try { // Create an OpenVDB grid (here a level set surface but replace this with your own code) auto srcGrid = openvdb::tools::createLevelSetSphere(100.0f, openvdb::Vec3f(0.0f), 1.0f); // Convert the OpenVDB grid, srcGrid, into a NanoVDB grid handle. auto handle = nanovdb::createNanoGrid(*srcGrid); // Define a (raw) pointer to the NanoVDB grid on the host. Note we match the value type of the srcGrid! auto* dstGrid = handle.grid(); if (!dstGrid) throw std::runtime_error("GridHandle does not contain a grid with value type float"); // Get accessors for the two grids. Note that accessors only accelerate repeated access! auto dstAcc = dstGrid->getAccessor(); auto srcAcc = srcGrid->getAccessor(); // Access and print out a cross-section of the narrow-band level set from the two grids for (int i = 97; i < 104; ++i) { printf("(%3i,0,0) OpenVDB cpu: % -4.2f, NanoVDB cpu: % -4.2f\n", i, srcAcc.getValue(openvdb::Coord(i, 0, 0)), dstAcc.getValue(nanovdb::Coord(i, 0, 0))); } nanovdb::io::writeGrid("data/sphere.nvdb", handle); // Write the NanoVDB grid to file and throw if writing fails } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; } return 0; } ``` [The second example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor/read_nanovdb_sphere_accessor.cc) reads a NanoVDB grid from a file (the one saved in the previous example) and prints out multiple values. Note that **this example does not depend on OpenVDB (nor CUDA), only NanoVDB**. ```cpp #include // this is required to read (and write) NanoVDB files on the host /// @brief Read a NanoVDB grid from a file and print out multiple values. /// /// @note Note This example does NOT depend on OpenVDB (nor CUDA), only NanoVDB. int main() { try { auto handle = nanovdb::io::readGrid("data/sphere.nvdb"); // reads first grid from file auto* grid = handle.grid(); // get a (raw) pointer to a NanoVDB grid of value type float if (!grid) throw std::runtime_error("File did not contain a grid with value type float"); auto acc = grid->getAccessor(); // create an accessor for fast access to multiple values for (int i = 97; i < 104; ++i) { printf("(%3i,0,0) NanoVDB cpu: % -4.2f\n", i, acc.getValue(nanovdb::Coord(i, 0, 0))); } } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; } return 0; } ``` [The third example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda/read_nanovdb_sphere_accessor_cuda.cc) reads a NanoVDB grid from a file (the one saved in the first example) and prints out multiple values on both the CPU and GPU. Note that **this example does NOT depend on OpenVDB, only NanoVDB and CUDA**. ```cpp #include // this is required to read (and write) NanoVDB files on the host #include // required for CUDA memory management extern "C" void launch_kernels(const nanovdb::NanoGrid*, const nanovdb::NanoGrid*, cudaStream_t stream); /// @brief Read a NanoVDB grid from a file and print out multiple values on both the cpu and gpu. /// /// @note Note This example does NOT depend on OpenVDB, only NanoVDB and CUDA. int main() { try { // returns a GridHandle using CUDA for memory management. auto handle = nanovdb::io::readGrid("data/sphere.nvdb"); cudaStream_t stream; // Create a CUDA stream to allow for asynchronous copy of pinned CUDA memory. cudaStreamCreate(&stream); handle.deviceUpload(stream, false); // Copy the NanoVDB grid to the GPU asynchronously auto* cpuGrid = handle.grid(); // get a (raw) pointer to a NanoVDB grid of value type float on the CPU auto* deviceGrid = handle.deviceGrid(); // get a (raw) pointer to a NanoVDB grid of value type float on the GPU if (!deviceGrid || !cpuGrid) throw std::runtime_error("GridHandle did not contain a grid with value type float"); launch_kernels(deviceGrid, cpuGrid, stream); // Call a host method to print a grid values on both the CPU and GPU cudaStreamDestroy(stream); // Destroy the CUDA stream } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; } return 0; } ``` NVCC requires the CUDA kernel to be defined in [a separate .cu file](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda/read_nanovdb_sphere_accessor_cuda.cu): ```cpp #include // this defined the core tree data structure of NanoVDB accessible on both the host and device #include // for printf // This is called by the host only void cpu_kernel(const nanovdb::NanoGrid* cpuGrid) { auto cpuAcc = cpuGrid->getAccessor(); for (int i = 97; i < 104; ++i) { printf("(%3i,0,0) NanoVDB cpu: % -4.2f\n", i, cpuAcc.getValue(nanovdb::Coord(i, 0, 0))); } } // This is called by the device only __global__ void gpu_kernel(const nanovdb::NanoGrid* deviceGrid) { if (threadIdx.x > 6) return; int i = 97 + threadIdx.x; auto gpuAcc = deviceGrid->getAccessor(); printf("(%3i,0,0) NanoVDB gpu: % -4.2f\n", i, gpuAcc.getValue(nanovdb::Coord(i, 0, 0))); } // This is called by the client code on the host extern "C" void launch_kernels(const nanovdb::NanoGrid* deviceGrid, const nanovdb::NanoGrid* cpuGrid, cudaStream_t stream) { // Launch the device kernel asynchronously gpu_kernel<<<1, 64, 0, stream>>>(deviceGrid); // Launch the host "kernel" (synchronously) cpu_kernel(cpuGrid); } ``` openvdb-13.0.0/doc/nanovdb/HowToBuild.md000066400000000000000000000110371510223237100177640ustar00rootroot00000000000000# Build instructions {#NanoVDB_HowToBuild} Note that NanoVDB can be built in many different ways, in the sense that its many external dependencies are optional. This includes OpenVDB, TBB, graphics APIs like CUDA, OpenGL, and OpenCL, as well as compression like ZLIB and BLOSC. However, since the core data structure in [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) is self-contained, client code may only depend on this single header file. Also, note that if the environment variable `VDB_DATA_PATH` is set to a directory containing the OpenVDB files from [the OpenVDB web site](http://www.openvdb.org/download), they will be used for the unit and the benchmark tests. Else a simple narrow-band level set sphere is used. Set the environment variable `VDB_SCRATCH_PATH` to define the path to where images generated in the benchmark tests are stored (defaults to the build directory). [//]: # (TODO: add back OPTIX, OPENCL, and OPENGL when these options are added back) To explicitly remove a dependency, `X`, add the argument `-DNANOVDB_USE_X=OFF` where `X = {OPENVDB, TBB, BLOSC, ZLIB, CUDA}`. These options are set in the [NanoVDB root CMakeLists.txt](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CMakeLists.txt). The same file also defines options to build NanoVDB examples, benchmarks, unit-tests, and command-line tools. The default values for these options are `OFF`. A user can override each of these options by passing, for example, `-DNANOVDB_BUILD_UNITTESTS=ON` flag while running cmake from the command line. To see the compiler arguments add `-DCMAKE_VERBOSE_MAKEFILE=ON`. ## First example: building NanoVDB and OpenVDB core NanoVDB is now a module of the larger OpenVDB project. A user can build both libraries together. This will build the OpenVDB core library, install the NanoVDB header files, and build the NanoVDB command-line tools in the `build/nanovdb/cmd` directory. From the 'root' OpenVDB project directory (change the dependency paths to match your environment): ```console foo@bar:~$ mkdir build foo@bar:~$ cd build foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DTBB_ROOT=/path/to/tbb -DBOOST_ROOT=/path/to/boost -DBLOSC_ROOT=/path/to/blosc -DCMAKE_INSTALL_PREFIX=/install/path foo@bar:~$ make -j 4 && make install ``` Note that the default value of `NANOVDB_USE_OPENVDB` is linked to `OPENVDB_BUILD_CORE` option and can be overriden by passing on `-DNANOVDB_USE_OPENVDB=OFF`. The `Boost` library is included because it is a requirement for building OpenVDB. In general, CMake will try to find every optional dependency when a user opts to add an additional dependency. Be sure to check the CMake log to see what dependencies were **not** found. ## Second example: NanoVDB with no dependencies From the 'root' OpenVDB project directory: ```console foo@bar:~$ mkdir build foo@bar:~$ cd build foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DOPENVDB_BUILD_CORE=OFF -DOPENVDB_BUILD_BINARIES=OFF -DNANOVDB_USE_TBB=OFF -DNANOVDB_USE_BLOSC=OFF -DNANOVDB_USE_ZLIB=OFF -DCMAKE_INSTALL_PREFIX=/install/path foo@bar:~$ make -j 4 && make install ``` Another option is to build it from the NanoVDB directory itself, which is much simpler: ```console foo@bar:~$ cd nanovdb/nanovdb foo@bar:~$ mkdir build foo@bar:~$ cd build foo@bar:~$ cmake .. -DCMAKE_INSTALL_PREFIX=/install/path foo@bar:~$ make -j 4 && make install ``` Both options will install the NanoVDB header files to the `/install/path` as well as building `nanovdb_print` and `nanovdb_validate` executable. The path where these executables are installed will be different: in the first option they will be under `build/nanovdb/cmd` directory; whilst in the second option they will be under the `build/cmd/` directory. ## Third example: build 'everything' in NanoVDB along with OpenVDB core From the root OpenVDB directory: ```console foo@bar:~$ mkdir build foo@bar:~$ cd build foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DNANOVDB_BUILD_UNITTESTS=ON -DNANOVDB_BUILD_EXAMPLES=ON -DNANOVDB_BUILD_BENCHMARK=ON -DNANOVDB_USE_INTRINSICS=ON -DNANOVDB_USE_CUDA=ON -DNANOVDB_CUDA_KEEP_PTX=ON -DTBB_ROOT=/path/to/tbb -DBOOST_ROOT=/path/to/boost -DBLOSC_ROOT=/path/to/blosc -DGTEST_ROOT=/path/to/gtest -DCMAKE_INSTALL_PREFIX=/install/path foo@bar:~$ make -j 4 && make install ``` Note that if you already have the correct version of OpenVDB pre-installed, you can configure CMake to link against that library by passing the arguments `-DOPENVDB_BUILD_CORE=OFF -DOPENVDB_BUILD_BINARIES=OFF -DOPENVDB_ROOT=/path/to/openvdb` when invoking `cmake`. openvdb-13.0.0/doc/nanovdb/SourceTree.md000066400000000000000000000162361510223237100200320ustar00rootroot00000000000000# Source tree structure {#NanoVDB_SourceTree} #### Overview of the directory tree of NanoVDB. * [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) C++11 implementation of the core data structure and its access methods. * [CNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CNanoVDB.h) Incomplete but useable C99 implementation of the core data structure and its access methods. Designed in particular for use in OpenCL kernels. Note that this relies on zero-sized arrays for the _reserved padding, so will not work on all compilers (with MSVC being a particular example) * [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h) C99 implementation of the core data structure and its access methods. More complete coverage than CNanoVDB. This version is pointer-less and supports virtually all graphics APIs. * [GridHandle.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/GridHandle.h) defines a handler for the memory allocated to a NanoVDB grid. * [io/IO.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/io/IO.h) implements I/O support. * [tools/CreateNanoGrid.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/tools/CreateNanoGrid.h) defines the converter from OpenVDB to NanoVDB and obviously depends on the OpenVDB library (as the only header file). * [math/Ray.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/math/Ray.h) Ray class. * [math/HDDA.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/math/HDDA.h) HDDA related. * [math/SampleFromVoxels.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/math/SampleFromVoxels.h) interpolation. ```bash foo@bar:~$ tree . ├── CMakeLists.txt ├── cmd │ ├── CMakeLists.txt │ ├── convert │ │ └── nanovdb_convert.cc │ ├── print │ │ └── nanovdb_print.cc │ ├── updateFiles.sh │ └── validate │ └── nanovdb_validate.cc ├── CNanoVDB.h ├── cuda │ ├── DeviceBuffer.h │ ├── GridHandle.cuh │ └── NodeManager.cuh ├── docs │ ├── CMakeLists.txt │ ├── codingstyle.txt │ └── doxygen-config ├── examples │ ├── CMakeLists.txt │ ├── ex_bump_pool_buffer │ │ └── bump_pool_buffer.cc │ ├── ex_collide_level_set │ │ ├── common.h │ │ ├── main.cc │ │ ├── nanovdb.cu │ │ └── openvdb.cc │ ├── ex_index_grid_cuda │ │ ├── index_grid_cuda.cc │ │ └── index_grid_cuda_kernel.cu │ ├── ex_make_custom_nanovdb │ │ └── make_custom_nanovdb.cc │ ├── ex_make_custom_nanovdb_cuda │ │ ├── make_custom_nanovdb_cuda.cc │ │ └── make_custom_nanovdb_cuda_kernel.cu │ ├── ex_make_funny_nanovdb │ │ └── make_funny_nanovdb.cc │ ├── ex_make_nanovdb_sphere │ │ └── make_nanovdb_sphere.cc │ ├── ex_make_typed_grids │ │ └── make_typed_grids.cc │ ├── ex_map_pool_buffer │ │ └── map_pool_buffer.cc │ ├── ex_modify_nanovdb_thrust │ │ ├── modify_nanovdb_thrust.cc │ │ └── modify_nanovdb_thrust.cu │ ├── ex_nodemanager_cuda │ │ ├── nodemanager_cuda.cc │ │ └── nodemanager_cuda_kernel.cu │ ├── ex_openvdb_to_nanovdb │ │ └── openvdb_to_nanovdb.cc │ ├── ex_openvdb_to_nanovdb_accessor │ │ └── openvdb_to_nanovdb_accessor.cc │ ├── ex_openvdb_to_nanovdb_cuda │ │ ├── openvdb_to_nanovdb_cuda.cc │ │ └── openvdb_to_nanovdb_cuda_kernel.cu │ ├── ex_raytrace_fog_volume │ │ ├── common.h │ │ ├── main.cc │ │ ├── nanovdb.cu │ │ └── openvdb.cc │ ├── ex_raytrace_level_set │ │ ├── common.h │ │ ├── main.cc │ │ ├── nanovdb.cu │ │ └── openvdb.cc │ ├── ex_read_nanovdb_sphere │ │ └── read_nanovdb_sphere.cc │ ├── ex_read_nanovdb_sphere_accessor │ │ └── read_nanovdb_sphere_accessor.cc │ ├── ex_read_nanovdb_sphere_accessor_cuda │ │ ├── read_nanovdb_sphere_accessor_cuda.cu │ │ └── read_nanovdb_sphere_accessor_cuda_kernel.cu │ ├── ex_util │ │ └── ComputePrimitives.h │ ├── ex_voxels_to_grid_cuda │ │ └── ex_voxels_to_grid_cuda.cu │ ├── ex_vox_to_nanovdb │ │ ├── vox_to_nanovdb.cc │ │ └── VoxToNanoVDB.h │ └── ex_write_nanovdb_grids │ └── write_nanovdb_grids.cc ├── GridHandle.h ├── HostBuffer.h ├── io │ └── IO.h ├── math │ ├── CSampleFromVoxels.h │ ├── DitherLUT.h │ ├── HDDA.h │ ├── Math.h │ ├── Ray.h │ ├── SampleFromVoxels.h │ └── Stencils.h ├── NanoVDB.h ├── NodeManager.h ├── PNanoVDB.h ├── Readme.md ├── tools │ ├── CreateNanoGrid.h │ ├── CreatePrimitives.h │ ├── cuda │ │ ├── AddBlindData.cuh │ │ ├── GridChecksum.cuh │ │ ├── GridStats.cuh │ │ ├── GridValidator.cuh │ │ ├── IndexToGrid.cuh │ │ ├── PointsToGrid.cuh │ │ └── SignedFloodFill.cuh │ ├── GridBuilder.h │ ├── GridChecksum.h │ ├── GridStats.h │ ├── GridValidator.h │ └── NanoToOpenVDB.h ├── unittest │ ├── CMakeLists.txt │ ├── pnanovdb_validate_strides.h │ ├── TestNanoVDB.cc │ ├── TestNanoVDB.cu │ └── TestOpenVDB.cc └── util ├── CpuTimer.h ├── CreateNanoGrid.h ├── cuda │ ├── CudaAddBlindData.cuh │ ├── CudaDeviceBuffer.h │ ├── CudaGridChecksum.cuh │ ├── CudaGridHandle.cuh │ ├── CudaGridStats.cuh │ ├── CudaGridValidator.cuh │ ├── CudaIndexToGrid.cuh │ ├── CudaNodeManager.cuh │ ├── CudaPointsToGrid.cuh │ ├── CudaSignedFloodFill.cuh │ ├── CudaUtils.h │ ├── GpuTimer.h │ ├── Timer.h │ └── Util.h ├── DitherLUT.h ├── ForEach.h ├── GridBuilder.h ├── GridChecksum.h ├── GridStats.h ├── GridValidator.h ├── HDDA.h ├── HostBuffer.h ├── Invoke.h ├── IO.h ├── NanoToOpenVDB.h ├── NodeManager.h ├── OpenToNanoVDB.h ├── PrefixSum.h ├── Primitives.h ├── Range.h ├── Ray.h ├── Reduce.h ├── SampleFromVoxels.h ├── Stencils.h ├── Timer.h └── Util.hopenvdb-13.0.0/doc/nanovdb/doc.md000066400000000000000000000002741510223237100165120ustar00rootroot00000000000000# NanoVDB {#NanoVDB_MainPage} Welcome to the NanoVDB documentation page. * @subpage NanoVDB_HowToBuild * @subpage NanoVDB_FAQ * @subpage NanoVDB_SourceTree * @subpage NanoVDB_HelloWorld openvdb-13.0.0/doc/points.txt000066400000000000000000000262731510223237100160600ustar00rootroot00000000000000/** @page points OpenVDB Points @section secPtContents Contents - @ref secPtOverview - @ref secPtCompression - @ref secPtLocality - @ref secPtAttributes - @ref secPtTypedAttributeArray - @ref secPtAttributeHandle - @ref secPtAttributePerformance - @ref secPtAttributeSet - @ref secPtPointTree - @ref secPtPointIndexTree - @ref secPtPointDataTree - @ref secPtSparsity - @ref secPtBackground - @ref secPtActiveValues - @ref secPtIndexIterators - @ref secPtIndexFilters - @ref secPtSpaceAndTrans @section secPtOverview Introduction @anchor openvdbPointsOverview The @b OpenVDB library can store point data within an OpenVDB hierarchy in two different ways. A @b PointIndexGrid stores index offsets that reference data stored in an external linear point array, a @b PointDataGrid stores the points with attributes directly in the VDB Grid. This document focuses mainly on the localised style of storage used by @b PointDataGrids. Using this storage mechanism, points are spatially-organised into VDB voxels to provide faster access and a greater opportunity for data compression compared with linear point arrays. See the @ref openvdbPointsHelloWorld "Cookbook" for code examples to get started using @b OpenVDB @b Points. @section secPtCompression Compression A key motivation behind the library is to increase data compression and thus reduce the memory and disk space requirements of the point set. There are three types of compression used in this library to store point attribute data - (1) @b value @b compression where the codec is selected specifically based on the intent of the data, (2) @b uniform @b compression where arrays of identical values can be collapsed down into a single value, (3) @b stream @b compression where the Blosc stream compressor can be used to pack and unpack streams of data using a fast, lossless compression codec. Uniform and stream compression are offered in other applications, notably Houdini, but with the case of stream compression, used only for disk storage. Value compression is provided based on the principal that a good general-purpose compression scheme will usually not be superior to one that is specifically tuned to the range and intention of how the data will be used. The most commonly used style of value compression in OpenVDB Points is quantization for point position data. Floating-point world-space positions will typically use a much higher accuracy than desired around the origin and a much lower accuracy than desired far from the origin, which is as a result of the dynamic range used in floating-point that makes it usable at different orders of magnitude. More tailored position compression is introduced by splitting positions into an integer offset provided by the VDB voxels and grid transform and a reduced precision fixed-point offset from the center of the voxel. In addition, other attributes such as velocity can benefit from value compression. For example, a unit vector scheme can compress a 3 x float vector (12 bytes) into just 2 bytes. @section secPtLocality Locality Data compression isn't the only area to benefit from a spatially organised data set. Due to the effects of L1 and L2 caching in modern CPUs, improved cache locality through storing point data close in memory to their neighbors can bring about a big improvement in performance. A number of point rasterization gather-style tests that compared spatially organised data with randomly organised linear data when dereferenced using a spatial acceleration structure consistently resulted in a performance improvement of between 2x and 3x. @section secPtAttributes Attributes Attribute storage is provided as an independent toolset within the library to allow for use outside of OpenVDB grids. @subsection secPtTypedAttributeArray TypedAttributeArray The TypedAttributeArray stores array data with a specified value type and compression codec, which form the template signature. @code template class TypedAttributeArray: public AttributeArray @endcode The base AttributeArray class from which the TypedAttributeArray derives is not templated and can be used for all non-typed operations such as serialization. Here is an example of floating-point scalar attribute storage using a truncation codec to reduce the footprint from 32-bit to 16-bit: @code openvdb::points::TypedAttributeArray @endcode @subsection secPtAttributeHandle AttributeHandle AttributeHandle and AttributeWriteHandle classes provide access to the array data without requiring knowledge of the codec. This is important as it can allow users to add their own attribute compression schemes without requiring any modification to existing code. AttributeHandles provide benefits to memory usage in allowing data to be packed and unpacked efficiently when using stream compression. When compressed with a stream compression scheme, the AttributeHandle unpacks attribute data into a local (uncompressed) buffer on access and discards this temporary data once the AttributeHandle is destroyed. This has the benefit of retaining the stream compression during access which lowers the peak memory substantially. This is how to create a float AttributeHandle bound to a specific attribute in a leaf: @code auto handle = AttributeHandle::create(leaf->constAttributeArray("attribute_name")); @endcode Note that ensuring const access to the attribute array will prevent redundant copying when using a read-only handle. @subsection secPtAttributePerformance TypedAttributeArray vs AttributeHandle One key benefit of AttributeHandles is that they ensure the data being accessed has been uncompressed and is in-core on creation of the handle to avoid the need to perform these checks when the data is being accessed and modified for improved performance. An AttributeHandle may also be provided a specific codec if known to eliminate the indirection cost. @subsection secPtAttributeSet AttributeSet and Descriptor The AttributeSet stores a collection of attribute arrays along with a Descriptor that tracks the type of each of the attribute arrays. In typical use cases, the Descriptor is shared amongst leaf nodes with many of the algorithms making this assumption for performance reasons. However, it is still possible to configure the data so that leaf nodes in the same grid can use different Descriptors with different numbers and types of attributes. A typical use-case for this might be to reduce precision of an attribute further from a camera where accuracy is deemed less important and can be traded for a reduced memory or disk footprint. @section secPtPointTree The Point Tree @subsection secPtPointIndexTree Point Index Tree As mentioned in the introduction, the PointIndexTree is a structure in OpenVDB that stores an array of offset indices to a linear point array in the leaf nodes. In constrast, the PointDataTree stores the actual data localised in the leaf nodes. The PointIndexTree has this tree configuration: @code typedef tree::Tree4::Type PointIndexTree; @endcode @subsection secPtPointDataTree Point Data Tree The PointDataTree has this tree configuration: @code typedef tree::Tree4::Type PointDataTree; @endcode Note that with both the PointIndexTree and the PointDataTree, the data type is actually a 32-bit unsigned integer, but it is provided in this form to distinguish it from other LeafNodes that store the same data type. None of the other components within the Tree or Grid hierarchy change. It is for this reason that many of the existing features of OpenVDB such as serialization work without requiring additional functionality in OpenVDB. @section secPtSparsity Voxel Values For the PointDataTree, the voxel values represent the end position in the linear attribute arrays attached to each LeafNode. Using the value of the previous voxel (zero for the first voxel), the offset for the start position can be deduced. @subsection secPtBackground Background and Tile Values There are three distinct ways of storing data in an OpenVDB tree: voxel values, tile values, and a background value. Unfortunately the background value and tile values make little sense for point data. While technically it would be valid to use a non-zero background value and tile value, this would simply mean that only the first voxel in the LeafNode contains points which is neither an efficient storage mechanism nor particularly common. For this reason, the LeafNode constructor may take a background value but it is internally overriden to be zero on construction. @subsection secPtActiveValues Active Values Any voxel or tile can be classified as either @b active or @b inactive. The interpretation of this state is application-specific, however there are some conventions, such as using the active state to denote the narrow band in a levelset. For points, the most intuitive use of the active state is to mark a voxel as active if it contains points and inactive otherwise. This allows iteration over the points in a LeafNode to be accelerated to only iterate over voxels that contain points. @subsection secPtIndexIterators Index Iterators @anchor openvdbPointsIterators An index iterator contains a value iterator and an index filter, however the most common usage is provided by the convenience methods on the leaf node: @code auto iterAll = leaf.beginIndexAll(); auto iterOn = leaf.beginIndexOn(); auto iterOff = leaf.beginIndexOff(); for (; iterOn; ++iterOn) { Index32 index = *iterOn; } @endcode These are analagous to the value iterators in the LeafNode and are creating an index iterator that wraps the value iterator together with a null filter. It is also possible to iterate over indices within a specific voxel by using the beginIndexVoxel convenience method on the leaf: @code auto iterVoxel = leaf.beginIndexVoxel(ijk); @endcode For performance and simplicity, it is recommended to use the all/on/off index iterators where possible, as these hide the explicit voxel iteration from the user meaning it is only necessary to iterate over the indices within the leaf. It is also possible to retrieve the voxel coordinate from the index iterator directly. @subsection secPtIndexFilters Index Filters Index filters provide an easy way of only iterating over indices that match a set criteria. One such index filter provided by the library is to iterate over the points within a group: @code openvdb::points::GroupFilter filter("test_point_group"); auto iter = leaf.beginIndexOn(filter); @endcode As the index iterator is templated on the filter, it's possible to construct filters that do relatively complicated operations provided they meet the basic interface requirements of an IndexFilter. @section secPtSpaceAndTrans Voxel Space, Index Space, World Space Points are stored in @b voxel @b space, meaning all point positions lie between (-0.5, -0.5, -0.5) and (0.5, 0.5, 0.5) with the center of the voxel being (0.0, 0.0, 0.0). The position of the point can be extracted in @b index @b space by adding the voxel space position to the ijk value of the voxel. The position of the point can be extracted in @b world @b space by using the grid transform to do an indexToWorld conversion. See the @ref openvdbPointsHelloWorld "Cookbook" for code examples to get started using @b OpenVDB @b Points. */ openvdb-13.0.0/doc/python.txt000066400000000000000000000514441510223237100160630ustar00rootroot00000000000000/** @page python Using OpenVDB in Python This section describes the OpenVDB Python module and includes Python code snippets and some complete programs that illustrate how to perform common tasks. The Python module exposes most of the functionality of the C++ @vdblink::Grid Grid@endlink class, including I/O, metadata management, voxel access and iteration, but almost none of the many @ref secToolUtils "tools". We expect to add support for tools in forthcoming releases. The Python module supports a fixed set of grid types. If the symbol @c PY_OPENVDB_WRAP_ALL_GRID_TYPES is defined at compile time, most of the grid types declared in openvdb.h are accessible in Python, otherwise only @b FloatGrid, @b BoolGrid and @b Vec3SGrid are accessible. To add support for grids with other value types or configurations, search for @c PY_OPENVDB_WRAP_ALL_GRID_TYPES in the module source code, update the code as appropriate and recompile the module. (It is possible that this process will be streamlined in the future with a plugin mechanism.) Note however that adding grid types can significantly increase the time and memory needed to compile the module and can significantly increase the size of the resulting executable. In addition, grids of custom types that are saved to .vdb files or pickled will not be readable by clients using the standard version of the module. Also note that the @vdblink::tree::Tree Tree@endlink class is not exposed in Python. Much of its functionality is either available through the @vdblink::Grid Grid@endlink or is too low-level to be generally useful in Python. Although trees are not accessible in Python, they can of course be operated on indirectly. Of note are the grid methods @b copy, which returns a new grid that shares its tree with the original grid, @b deepCopy, which returns a new grid that owns its own tree, and @b sharesWith, which reports whether two grids share a tree. @section sPyContents Contents - @ref sPyBasics - @ref sPyHandlingMetadata - @ref sPyAccessors - @ref sPyIteration - @ref sPyNumPy - @ref sPyMeshConversion - @ref sPyCppAPI @section sPyBasics Getting started The following example is a complete program that illustrates some of the basic steps to create grids and write them to disk: @code{.py} import pyopenvdb as vdb # A grid comprises a sparse tree representation of voxel data, # user-supplied metadata and a voxel space to world space transform, # which defaults to the identity transform. # A FloatGrid stores one single-precision floating point value per voxel. # Other grid types include BoolGrid and Vec3SGrid. The module-level # attribute pyopenvdb.GridTypes gives the complete list. cube = vdb.FloatGrid() cube.fill(min=(100, 100, 100), max=(199, 199, 199), value=1.0) # Name the grid "cube". cube.name = 'cube' # Populate another FloatGrid with a sparse, narrow-band level set # representation of a sphere with radius 50 voxels, located at # (1.5, 2, 3) in index space. sphere = vdb.createLevelSetSphere(radius=50, center=(1.5, 2, 3)) # Associate some metadata with the grid. sphere['radius'] = 50.0 # Associate a scaling transform with the grid that sets the voxel size # to 0.5 units in world space. sphere.transform = vdb.createLinearTransform(voxelSize=0.5) # Name the grid "sphere". sphere.name = 'sphere' # Write both grids to a VDB file. vdb.write('mygrids.vdb', grids=[cube, sphere]) @endcode This example shows how to read grids from files, and some ways to modify grids: @code{.py} import pyopenvdb as vdb # Read a .vdb file and return a list of grids populated with # their metadata and transforms, but not their trees. filename = 'mygrids.vdb' grids = vdb.readAllGridMetadata(filename) # Look for and read in a level-set grid that has certain metadata. sphere = None for grid in grids: if (grid.gridClass == vdb.GridClass.LEVEL_SET and 'radius' in grid and grid['radius'] > 10.0): sphere = vdb.read(filename, grid.name) else: print 'skipping grid', grid.name if sphere: # Convert the level set sphere to a narrow-band fog volume, in which # interior voxels have value 1, exterior voxels have value 0, and # narrow-band voxels have values varying linearly from 0 to 1. outside = sphere.background width = 2.0 * outside # Visit and update all of the grid's active values, which correspond to # voxels in the narrow band. for iter in sphere.iterOnValues(): dist = iter.value iter.value = (outside - dist) / width # Visit all of the grid's inactive tile and voxel values and update # the values that correspond to the interior region. for iter in sphere.iterOffValues(): if iter.value < 0.0: iter.value = 1.0 iter.active = False # Set exterior voxels to 0. sphere.background = 0.0 sphere.gridClass = vdb.GridClass.FOG_VOLUME @endcode @section sPyHandlingMetadata Handling metadata Metadata of various types (string, bool, int, float, and 2- and 3-element sequences of ints or floats) can be attached both to individual grids and to files on disk, either by supplying a Python dictionary of (name, value) pairs or, in the case of grids, through a dictionary-like interface. Add (name, value) metadata pairs to a grid as you would to a dictionary. A new value overwrites an existing value if the name matches an existing name. @code{.py} >>> import pyopenvdb as vdb >>> grid = vdb.Vec3SGrid() >>> grid['vector'] = 'gradient' >>> grid['radius'] = 50.0 >>> grid['center'] = (10, 15, 10) >>> grid.metadata {'vector': 'gradient', 'radius': 50.0, 'center': (10, 15, 10)} >>> grid['radius'] 50.0 >>> 'radius' in grid, 'misc' in grid (True, False) # OK to overwrite an existing value with a value of another type: >>> grid['center'] = 0.0 # A 4-element sequence is not a supported metadata value type: >>> grid['center'] = (0, 0, 0, 0) File "", line 1, in TypeError: metadata value "(0, 0, 0, 0)" of type tuple is not allowed # Metadata names must be strings: >>> grid[0] = (10.5, 15, 30) File "", line 1, in TypeError: expected str, found int as argument 1 to __setitem__() @endcode Alternatively, replace all or some of a grid’s metadata by supplying a (name, value) dictionary: @code{.py} >>> metadata = { ... 'vector': 'gradient', ... 'radius': 50.0, ... 'center': (10, 15, 10) ... } # Replace all of the grid's metadata. >>> grid.metadata = metadata >>> metadata = { ... 'center': [10.5, 15, 30], ... 'scale': 3.14159 ... } # Overwrite "center" and add "scale": >>> grid.updateMetadata(metadata) @endcode Iterate over a grid’s metadata as you would over a dictionary: @code{.py} >>> for key in grid: ... print '%s = %s' % (key, grid[key]) ... vector = gradient radius = 50.0 scale = 3.14159 center = (10.5, 15.0, 30.0) @endcode Removing metadata is also straightforward: @code{.py} >>> del grid['vector'] >>> del grid['center'] >>> del grid['vector'] # error: already removed File "", line 1, in KeyError: 'vector' >>> grid.metadata = {} # remove all metadata @endcode Some grid metadata is exposed in the form of properties, either because it might be frequently accessed (a grid’s name, for example) or because its allowed values are somehow restricted: @code{.py} >>> grid = vdb.createLevelSetSphere(radius=10.0) >>> grid.metadata {'class': 'level set'} >>> grid.gridClass = vdb.GridClass.FOG_VOLUME >>> grid.metadata {'class': 'fog volume'} # The gridClass property requires a string value: >>> grid.gridClass = 123 File "", line 1, in TypeError: expected str, found int as argument 1 to setGridClass() # Only certain strings are recognized; see pyopenvdb.GridClass # for the complete list. >>> grid.gridClass = 'Hello, world.' >>> grid.metadata {'class': 'unknown'} >>> grid.metadata = {} >>> grid.vectorType = vdb.VectorType.COVARIANT >>> grid.metadata {'vector_type': 'covariant'} >>> grid.name = 'sphere' >>> grid.creator = 'Python' >>> grid.metadata {'vector_type': 'covariant', 'name': 'sphere', 'creator': 'Python'} @endcode Setting these properties to @c None removes the corresponding metadata, but the properties retain default values: @code{.py} >>> grid.creator = grid.vectorType = None >>> grid.metadata {'name': 'sphere'} >>> grid.creator, grid.vectorType ('', 'invariant') @endcode Metadata can be associated with a .vdb file at the time the file is written, by supplying a (name, value) dictionary as the optional @c metadata argument to the @b write function: @code{.py} >>> metadata = { ... 'creator': 'Python', ... 'time': '11:05:00' ... } >>> vdb.write('mygrids.vdb', grids=grid, metadata=metadata) @endcode File-level metadata can be retrieved with either the @b readMetadata function or the @b readAll function: @code{.py} >>> metadata = vdb.readMetadata('mygrids.vdb') >>> metadata {'creator': 'Python', 'time': '11:05:00'} >>> grids, metadata = vdb.readAll('mygrids.vdb') >>> metadata {'creator': 'Python', 'time': '11:05:00'} >>> [grid.name for grid in grids] ['sphere'] @endcode @section sPyAccessors Voxel access Grids provide read-only and read/write accessors for voxel lookup via @ijk index coordinates. Accessors store references to their parent grids, so a grid will not be deleted while it has accessors in use. @code{.py} >>> import pyopenvdb as vdb # Read two grids from a file. >>> grids, metadata = vdb.readAll('smoke2.vdb') >>> [grid.name for grid in grids] ['density', 'v'] # Get read/write accessors to the two grids. >>> dAccessor = grids[0].getAccessor() >>> vAccessor = grids[1].getAccessor() >>> ijk = (100, 103, 101) >>> dAccessor.probeValue(ijk) (0.17614534497261047, True) # Change the value of a voxel. >>> dAccessor.setValueOn(ijk, 0.125) >>> dAccessor.probeValue(ijk) (0.125, True) >>> vAccessor.probeValue(ijk) ((-2.90625, 9.84375, 0.84228515625), True) # Change the active state of a voxel. >>> vAccessor.setActiveState(ijk, False) >>> vAccessor.probeValue(ijk) ((-2.90625, 9.84375, 0.84228515625), False) # Get a read-only accessor to one of the grids. >>> dAccessor = grids[0].getConstAccessor() >>> dAccessor.setActiveState(ijk, False) File "", line 1, in TypeError: accessor is read-only # Delete the accessors once they are no longer needed, # so that the grids can be garbage-collected. >>> del dAccessor, vAccessor @endcode @section sPyIteration Iteration Grids provide read-only and read/write iterators over their values. Iteration is over sequences of value objects (BoolGrid.Values, FloatGrid.Values, etc.) that expose properties such as the number of voxels spanned by a value (one, for a voxel value, more than one for a tile value), its coordinates and its active state. Value objects returned by read-only iterators are immutable; those returned by read/write iterators permit assignment to their active state and value properties, which modifies the underlying grid. Value objects store references to their parent grids, so a grid will not be deleted while one of its value objects is in use. @code{.py} >>> import pyopenvdb as vdb >>> grid = vdb.read('smoke2.vdb', gridname='v') >>> grid.__class__.__name__ 'Vec3SGrid' # Iterate over inactive values and print the coordinates of the first # five voxel values and the bounding boxes of the first five tile values. >>> voxels = tiles = 0 ... N = 5 ... for item in grid.citerOffValues(): # read-only iterator ... if voxels == N and tiles == N: ... break ... if item.count == 1: ... if voxels < N: ... voxels += 1 ... print 'voxel', item.min ... else: ... if tiles < N: ... tiles += 1 ... print 'tile', item.min, item.max ... tile (0, 0, 0) (7, 7, 7) tile (0, 0, 8) (7, 7, 15) tile (0, 0, 16) (7, 7, 23) tile (0, 0, 24) (7, 7, 31) tile (0, 0, 32) (7, 7, 39) voxel (40, 96, 88) voxel (40, 96, 89) voxel (40, 96, 90) voxel (40, 96, 91) voxel (40, 96, 92) # Iterate over and normalize all active values. >>> from math import sqrt >>> for item in grid.iterOnValues(): # read/write iterator ... vector = item.value ... magnitude = sqrt(sum(x * x for x in vector)) ... item.value = [x / magnitude for x in vector] ... @endcode For some operations, it might be more convenient to use one of the grid methods @b mapOn, @b mapOff or @b mapAll. These methods iterate over a grid’s tiles and voxels (active, inactive or both, respectively) and replace each value x with f(x), where f is a callable object. These methods are not multithreaded. @code{.py} >>> import pyopenvdb as vdb >>> from math import sqrt >>> grid = vdb.read('smoke2.vdb', gridname='v') >>> def normalize(vector): ... magnitude = sqrt(sum(x * x for x in vector)) ... return [x / magnitude for x in vector] ... >>> grid.mapOn(normalize) @endcode Similarly, the @b combine method iterates over corresponding pairs of values (tile and voxel) of two grids @e A and @e B of the same type (FloatGrid, Vec3SGrid, etc.), replacing values in @e A with f(a, b), where f is a callable object. This operation assumes that index coordinates @ijk in both grids correspond to the same physical, world space location. Also, the operation always leaves grid @e B empty. @code{.py} >>> import pyopenvdb as vdb >>> density = vdb.read('smoke2.vdb', gridname='density') >>> density.__class__.__name__ 'FloatGrid' >>> sphere = vdb.createLevelSetSphere(radius=50.0, center=(100, 300, 100)) >>> density.combine(sphere, lambda a, b: min(a, b)) @endcode For now, @b combine operates only on tile and voxel values, not on their active states or other attributes. @section sPyNumPy Working with NumPy arrays Large data sets are often handled in Python using NumPy. The @b copyFromArray and @b copyToArray grid methods can be used to exchange data efficiently between scalar-valued grids and three-dimensional NumPy arrays and between vector-valued grids and four-dimensional NumPy arrays. @code{.py} >>> import pyopenvdb as vdb >>> import numpy >>> array = numpy.random.rand(200, 200, 200) >>> array.dtype dtype('float64') # Copy values from a three-dimensional array of doubles # into a grid of floats. >>> grid = vdb.FloatGrid() >>> grid.copyFromArray(array) >>> grid.activeVoxelCount() == array.size True >>> grid.evalActiveVoxelBoundingBox() ((0, 0, 0), (199, 199, 199)) # Copy values from a four-dimensional array of ints # into a grid of float vectors. >>> vecarray = numpy.ndarray((60, 70, 80, 3), int) >>> vecarray.fill(42) >>> vecgrid = vdb.Vec3SGrid() >>> vecgrid.copyFromArray(vecarray) >>> vecgrid.activeVoxelCount() == 60 * 70 * 80 True >>> vecgrid.evalActiveVoxelBoundingBox() ((0, 0, 0), (59, 69, 79)) @endcode When copying from a NumPy array, values in the array that are equal to the destination grid’s background value (or close to it, if the @c tolerance argument to @b copyFromArray is nonzero) are set to the background value and are marked inactive. All other values are marked active. @code{.py} >>> grid.clear() >>> grid.copyFromArray(array, tolerance=0.2) >>> print '%d%% of copied voxels are active' % ( ... round(100.0 * grid.activeVoxelCount() / array.size)) 80% of copied voxels are active @endcode The optional @c ijk argument specifies the index coordinates of the voxel in the destination grid into which to start copying values. That is, array index (0, 0, 0) maps to voxel @ijk. @code{.py} >>> grid.clear() >>> grid.copyFromArray(array, ijk=(-1, 2, 3)) >>> grid.evalActiveVoxelBoundingBox() ((-1, 2, 3), (198, 201, 202)) @endcode The @b copyToArray method also accepts an @c ijk argument. It specifies the index coordinates of the voxel to be copied to array index (0, 0, 0). @code{.py} >>> grid = vdb.createLevelSetSphere(radius=10.0) >>> array = numpy.ndarray((40, 40, 40), int) >>> array.fill(0) # Copy values from a grid of floats into # a three-dimensional array of ints. >>> grid.copyToArray(array, ijk=(-15, -20, -35)) >>> array[15, 20] array([ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3]) @endcode @b copyToArray has no @c tolerance argument, because there is no distinction between active and inactive values in the destination array. @section sPyMeshConversion Mesh conversion Also available if the OpenVDB Python module is compiled with NumPy support (see @ref sPyNumPy "above") are grid methods to convert polygonal meshes to level sets (see @vdblink::tools::meshToLevelSet() tools::meshToLevelSet@endlink for some restrictions) and to convert isosurfaces of scalar-valued grids to meshes. @code{.py} >>> import pyopenvdb as vdb >>> import numpy >>> grid = vdb.read('bunny.vdb', 'ls_bunny') # Convert a volume to a quadrilateral mesh. >>> points, quads = grid.convertToQuads() # World-space vertices of the mesh: >>> points array([[-14.05082607, -0.10118673, -0.40250054], [-14.05230808, -0.05570767, -0.45693323], [-14.05613995, -0.0734246 , -0.42150033], ..., [ 7.25201273, 13.25417805, 6.45283508], [ 7.25596714, 13.31225586, 6.40827513], [ 7.30518484, 13.21096039, 6.40724468]], dtype=float32) # Quadrilateral faces of the mesh, given by # 4-tuples of indices into the vertex list: >>> quads array([[ 5, 2, 1, 4], [ 11, 7, 6, 10], [ 14, 9, 8, 13], ..., [1327942, 1327766, 1339685, 1339733], [1339728, 1327921, 1327942, 1339733], [1339733, 1339685, 1339661, 1339728]], dtype=uint32) # Convert the mesh back to a (single-precision) volume. # Give the resulting grid the original grid's transform. >>> gridFromQuads = vdb.FloatGrid.createLevelSetFromPolygons( ... points, quads=quads, transform=grid.transform) # Alternatively, mesh a volume adaptively for a lower polygon count. # Adaptive meshing generates both triangular and quadrilateral faces. >>> points, triangles, quads = grid.convertToPolygons(adaptivity=0.5) # World-space vertices of the mesh: >>> points array([[-14.02906322, -0.07213751, -0.49265194], [-14.11877823, -0.11127799, -0.17118289], [-13.85006142, -0.08145611, -0.86669081], ..., [ 7.31098318, 12.97358608, 6.55133963], [ 7.20240211, 12.80632019, 6.80356836], [ 7.23679161, 13.28100395, 6.45595646]], dtype=float32) # Triangular faces of the mesh, given by # triples of indices into the vertex list: >>> triangles array([[ 8, 7, 0], [ 14, 9, 8], [ 14, 11, 9], ..., [22794, 22796, 22797], [22784, 22783, 22810], [22796, 22795, 22816]], dtype=uint32) # Quadrilateral faces of the mesh, given by # 4-tuples of indices into the vertex list: >>> quads array([[ 4, 3, 6, 5], [ 8, 9, 10, 7], [ 11, 12, 10, 9], ..., [23351, 23349, 23341, 23344], [23344, 23117, 23169, 23351], [23169, 23167, 23349, 23351]], dtype=uint32) # Convert the mesh to a double-precision volume. >>> doubleGridFromPolys = vdb.DoubleGrid.createLevelSetFromPolygons( ... points, triangles, quads, transform=grid.transform) @endcode The mesh representation is similar to that of the commonly-used Wavefront .obj file format, except that the vertex array is indexed starting from 0 rather than 1. To output mesh data to a file in .obj format, one might do the following: @code{.py} >>> def writeObjFile(filename, points, triangles=[], quads=[]): ... f = open(filename, 'w') ... # Output vertices. ... for xyz in points: ... f.write('v %g %g %g\n' % tuple(xyz)) ... f.write('\n') ... # Output faces. ... for ijk in triangles: ... f.write('f %d %d %d\n' % ... (ijk[0]+1, ijk[1]+1, ijk[2]+1)) # offset vertex indices by one ... for ijkl in quads: ... f.write('f %d %d %d %d\n' % ... (ijkl[0]+1, ijkl[1]+1, ijkl[2]+1, ijkl[3]+1)) ... f.close() ... >>> mesh = grid.convertToPolygons(adaptivity=0.8) >>> writeObjFile('bunny.obj', *mesh) @endcode @section sPyCppAPI C++ glue routines Python objects of type @b FloatGrid, @b Vec3SGrid, etc. are backed by C structs that “inherit” from @c PyObject. The OpenVDB Python extension module includes public functions that you can call in your own extension modules to convert between @vdblink::Grid openvdb::Grids@endlink and PyObjects. See the pyopenvdb.h reference for a description of these functions and a usage example. Your extension module might need to link against the OpenVDB extension module in order to access these functions. On UNIX systems, it might also be necessary to specify the @c RTLD_GLOBAL flag when importing the OpenVDB module, to allow its symbols to be shared across modules. See @b setdlopenflags in the Python @b sys module for one way to do this. */ openvdb-13.0.0/nanovdb/000077500000000000000000000000001510223237100146535ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/000077500000000000000000000000001510223237100163025ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/CMakeLists.txt000066400000000000000000000271321510223237100210470ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ CMake Configuration for NanoVDB #]=======================================================================] cmake_minimum_required(VERSION 3.24) project(NanoVDB LANGUAGES C CXX) include(GNUInstallDirs) ############################################################################### message(STATUS "----------------------------------------------------") message(STATUS "--------------- Configuring NanoVDB ----------------") message(STATUS "----------------------------------------------------") ############################################################################### # add options ############################################################################### option(NANOVDB_BUILD_TOOLS "Build command-line tools" ON) option(NANOVDB_BUILD_UNITTESTS "Build Unit tests" OFF) option(NANOVDB_BUILD_EXAMPLES "Build examples" OFF) #option(NANOVDB_BUILD_BENCHMARK "Build benchmark in examples" OFF) option(NANOVDB_BUILD_PYTHON_MODULE "Build the nanovdb Python module" OFF) option(NANOVDB_USE_INTRINSICS "Build with hardware intrinsics support" OFF) option(NANOVDB_USE_CUDA "Build with CUDA support" OFF) option(NANOVDB_CUDA_KEEP_PTX "Keep CUDA PTX" OFF) option(NANOVDB_USE_OPENVDB "Build with OpenVDB support" OFF) option(NANOVDB_USE_BLOSC "Build with BLOSC support" ${USE_BLOSC}) option(NANOVDB_USE_ZLIB "Build with ZLIB support" ${USE_ZLIB}) option(NANOVDB_USE_TBB "Build with TBB support" ${USE_TBB}) option(NANOVDB_USE_MAGICAVOXEL "Build with MagicaVoxel support" OFF) option(NANOVDB_ALLOW_FETCHCONTENT "Allow FetchContent to download missing dependencies" OFF) ############################################################################### # sanitize user input if(NANOVDB_USE_OPENVDB) if(NOT NANOVDB_USE_TBB) message(FATAL_ERROR "Invalid CMake build configuration: NANOVDB_USE_OPENVDB : [ON] NANOVDB_USE_TBB : [OFF] If you are linking NanoVDB against OpenVDB, then you need to use TBB, (i.e. -DNANOVDB_USE_TBB=ON).") endif() endif() ############################################################################### enable_testing() # Add our cmake modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../cmake") if(UNIX) # For CMake's find Threads module which brings in pthread - This flag # forces the compiler -pthread flag vs -lpthread set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads REQUIRED) endif() #if(NANOVDB_BUILD_UNITTESTS OR NANOVDB_BUILD_BENCHMARK) if(NANOVDB_BUILD_UNITTESTS) find_package(GTest ${MINIMUM_GOOGLETEST_VERSION} REQUIRED) endif() if(NANOVDB_USE_CUDA) set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_STANDARD_REQUIRED ON) # Allow the user to provide CMAKE_CUDA_ARCHITECTURES if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) set(CMAKE_CUDA_ARCHITECTURES 75) endif() enable_language(CUDA) set(NANOVDB_CUDA_EXTENDED_LAMBDA "--expt-extended-lambda") if(CUDA_VERSION_MAJOR GREATER_EQUAL 11) set(NANOVDB_CUDA_EXTENDED_LAMBDA "--extended-lambda") endif() set(CMAKE_CUDA_FLAGS "${NANOVDB_CUDA_EXTENDED_LAMBDA} -use_fast_math -lineinfo ${CMAKE_CUDA_FLAGS}") # workaround for win32 bug when nvcc "--keep" is used. if(WIN32) if(NANOVDB_CUDA_KEEP_PTX) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release") set(CMAKE_CUDA_FLAGS_RELEASE " --source-in-ptx --keep ${CMAKE_CUDA_FLAGS_RELEASE}") endif() endif() if(MSVC) # If a CMAKE_MSVC_RUNTIME_LIBRARY has not been provided and we're building # against openvdb, match the CRT that openvdb has been built against. This # setting is automatically propagated to CXX files but not CUDA sources, so # the VDB_MSVC_RUNTIME_SELECTION variables is used on targets with .cu files if(NOT CMAKE_MSVC_RUNTIME_LIBRARY AND NANOVDB_USE_OPENVDB AND OPENVDB_BUILD_CORE) get_target_property(VDB_MSVC_RUNTIME_SELECTION openvdb MSVC_RUNTIME_LIBRARY) endif() endif() find_package(CUDAToolkit) include(../../cmake/CPM.cmake) # This will automatically clone CCCL from GitHub and make the exported cmake targets available CPMAddPackage( NAME CCCL GITHUB_REPOSITORY nvidia/cccl GIT_TAG main # Fetches the latest commit on the main branch ) find_package(NCCL) endif() if(NANOVDB_USE_OPENVDB) if(NOT OPENVDB_BUILD_CORE AND NOT TARGET OpenVDB::openvdb) find_package(OpenVDB REQUIRED COMPONENTS openvdb) endif() endif() if(NANOVDB_USE_TBB AND NOT TARGET TBB::tbb) find_package(TBB ${MINIMUM_TBB_VERSION} REQUIRED) endif() if(NANOVDB_USE_BLOSC AND NOT TARGET Blosc::blosc) find_package(Blosc ${MINIMUM_BLOSC_VERSION} REQUIRED) endif() if(NANOVDB_USE_ZLIB AND NOT TARGET ZLIB::ZLIB) find_package(ZLIB ${MINIMUM_ZLIB_VERSION} REQUIRED) endif() if(NANOVDB_USE_MAGICAVOXEL) if(NANOVDB_ALLOW_FETCHCONTENT) if(NOT ogt_POPULATED) message(STATUS "Downloading ogt...") FetchContent_Declare( ogt GIT_REPOSITORY https://github.com/jpaver/opengametools.git GIT_TAG master) FetchContent_GetProperties(ogt) if(NOT ogt_POPULATED) FetchContent_Populate(ogt) set(NANOVDB_OGT_INCLUDE_DIRECTORY ${ogt_SOURCE_DIR}/src) endif() endif() endif() endif() ############################################################################### # Installation ############################################################################### # NanoVDB header files set(NANOVDB_INCLUDE_FILES CNanoVDB.h GridHandle.h HostBuffer.h NanoVDB.h NodeManager.h PNanoVDB.h ) # NanoVDB cuda header files set(NANOVDB_INCLUDE_CUDA_FILES cuda/DeviceBuffer.h cuda/DeviceMesh.h cuda/DeviceResource.h cuda/DeviceStreamMap.h cuda/GridHandle.cuh cuda/NodeManager.cuh cuda/TempPool.h cuda/UnifiedBuffer.h ) # NanoVDB io header files set(NANOVDB_INCLUDE_IO_FILES io/IO.h ) # NanoVDB math header files set(NANOVDB_INCLUDE_MATH_FILES math/CSampleFromVoxels.h math/DitherLUT.h math/HDDA.h math/Math.h math/Ray.h math/SampleFromVoxels.h math/Stencils.h ) # NanoVDB tools header files set(NANOVDB_INCLUDE_TOOLS_FILES tools/CreateNanoGrid.h tools/CreatePrimitives.h tools/GridBuilder.h tools/GridChecksum.h tools/GridStats.h tools/GridValidator.h tools/NanoToOpenVDB.h tools/VoxelBlockManager.h ) # NanoVDB tools/cuda header files set(NANOVDB_INCLUDE_TOOLS_CUDA_FILES tools/cuda/AddBlindData.cuh tools/cuda/GridChecksum.cuh tools/cuda/GridStats.cuh tools/cuda/GridValidator.cuh tools/cuda/IndexToGrid.cuh tools/cuda/PointsToGrid.cuh tools/cuda/SignedFloodFill.cuh tools/cuda/MergeGrids.cuh tools/cuda/TopologyBuilder.cuh tools/cuda/RefineGrid.cuh tools/cuda/PruneGrid.cuh tools/cuda/DistributedPointsToGrid.cuh tools/cuda/DilateGrid.cuh tools/cuda/CoarsenGrid.cuh tools/cuda/VoxelBlockManager.cuh ) # NanoVDB util header files set(NANOVDB_INCLUDE_UTIL_FILES util/CpuTimer.h util/CreateNanoGrid.h util/DitherLUT.h util/ForEach.h util/GridBuilder.h util/GridChecksum.h util/GridStats.h util/GridValidator.h util/HDDA.h util/HostBuffer.h util/Invoke.h util/IO.h util/NanoToOpenVDB.h util/NodeManager.h util/OpenToNanoVDB.h util/PrefixSum.h util/Primitives.h util/Range.h util/Ray.h util/Reduce.h util/SampleFromVoxels.h util/Stencils.h util/Timer.h util/Util.h util/MorphologyHelpers.h ) # NanoVDB util/cuda header files set(NANOVDB_INCLUDE_UTIL_CUDA_FILES util/cuda/CudaAddBlindData.cuh util/cuda/CudaGridHandle.cuh util/cuda/CudaIndexToGrid.cuh util/cuda/CudaSignedFloodFill.cuh util/cuda/Timer.h util/cuda/CudaDeviceBuffer.h util/cuda/CudaGridStats.cuh util/cuda/CudaNodeManager.cuh util/cuda/CudaUtils.h util/cuda/Util.h util/cuda/CudaGridChecksum.cuh util/cuda/CudaGridValidator.cuh util/cuda/CudaPointsToGrid.cuh util/cuda/GpuTimer.h util/cuda/Morphology.cuh util/cuda/MorphologyHelpers.cuh util/cuda/DeviceGridTraits.cuh util/cuda/Injection.cuh ) add_library(nanovdb INTERFACE) target_include_directories(nanovdb INTERFACE ../) target_compile_options(nanovdb INTERFACE "$<$:-Wno-invalid-offsetof>" "$<$:/bigobj>") if(WIN32) target_compile_definitions(nanovdb INTERFACE -DNOMINMAX -D_USE_MATH_DEFINES) endif() if(NANOVDB_USE_INTRINSICS) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_INTRINSICS) endif() if(NANOVDB_USE_OPENVDB) if(NOT OPENVDB_BUILD_CORE) target_link_libraries(nanovdb INTERFACE OpenVDB::openvdb) else() target_link_libraries(nanovdb INTERFACE openvdb) endif() target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_OPENVDB) endif() if(NANOVDB_USE_TBB) target_link_libraries(nanovdb INTERFACE TBB::tbb) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_TBB) if(WIN32) # this prevents tbb_debug.lib issue on windows target_compile_definitions(nanovdb INTERFACE -DTBB_USE_PREVIEW_BINARY) endif() endif() if(NANOVDB_USE_BLOSC) target_link_libraries(nanovdb INTERFACE Blosc::blosc) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_BLOSC) endif() if(NANOVDB_USE_ZLIB) target_link_libraries(nanovdb INTERFACE ZLIB::ZLIB) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_ZIP) endif() if(NANOVDB_USE_CUDA) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_CUDA) if(NOT CMAKE_CUDA_ARCHITECTURES) target_compile_options(nanovdb INTERFACE "$<$:-arch=sm_75>") endif() # Add CUDA includes to any C++ units which use NanoVDB target_link_libraries(nanovdb INTERFACE CCCL::CCCL CUDA::cudart) if(NCCL_FOUND) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_NCCL) target_link_libraries(nanovdb INTERFACE NCCL::NCCL) endif() endif() if(NANOVDB_USE_MAGICAVOXEL) target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_MAGICAVOXEL) target_include_directories(nanovdb INTERFACE ${NANOVDB_OGT_INCLUDE_DIRECTORY}) endif() if(TARGET Threads::Threads) target_link_libraries(nanovdb INTERFACE Threads::Threads) endif() set(NANOVDB_INSTALL_ROOT_DIR ${NANOVDB_INSTALL_INCLUDEDIR}/nanovdb) set(NANOVDB_INSTALL_CUDA_DIR ${NANOVDB_INSTALL_ROOT_DIR}/cuda) set(NANOVDB_INSTALL_IO_DIR ${NANOVDB_INSTALL_ROOT_DIR}/io) set(NANOVDB_INSTALL_MATH_DIR ${NANOVDB_INSTALL_ROOT_DIR}/math) set(NANOVDB_INSTALL_TOOLS_DIR ${NANOVDB_INSTALL_ROOT_DIR}/tools) set(NANOVDB_INSTALL_TOOLS_CUDA_DIR ${NANOVDB_INSTALL_TOOLS_DIR}/cuda) set(NANOVDB_INSTALL_UTIL_DIR ${NANOVDB_INSTALL_ROOT_DIR}/util) set(NANOVDB_INSTALL_UTIL_CUDA_DIR ${NANOVDB_INSTALL_UTIL_DIR}/cuda) install(FILES ${NANOVDB_INCLUDE_FILES} DESTINATION ${NANOVDB_INSTALL_ROOT_DIR}) install(FILES ${NANOVDB_INCLUDE_CUDA_FILES} DESTINATION ${NANOVDB_INSTALL_CUDA_DIR}) install(FILES ${NANOVDB_INCLUDE_IO_FILES} DESTINATION ${NANOVDB_INSTALL_IO_DIR}) install(FILES ${NANOVDB_INCLUDE_MATH_FILES} DESTINATION ${NANOVDB_INSTALL_MATH_DIR}) install(FILES ${NANOVDB_INCLUDE_TOOLS_FILES} DESTINATION ${NANOVDB_INSTALL_TOOLS_DIR}) install(FILES ${NANOVDB_INCLUDE_TOOLS_CUDA_FILES} DESTINATION ${NANOVDB_INSTALL_TOOLS_CUDA_DIR}) install(FILES ${NANOVDB_INCLUDE_UTIL_FILES} DESTINATION ${NANOVDB_INSTALL_UTIL_DIR}) install(FILES ${NANOVDB_INCLUDE_UTIL_CUDA_FILES} DESTINATION ${NANOVDB_INSTALL_UTIL_CUDA_DIR}) ############################################################################### # Options ############################################################################### if(NANOVDB_BUILD_TOOLS) add_subdirectory(cmd) endif() if(NANOVDB_BUILD_UNITTESTS) add_subdirectory(unittest) endif() if(NANOVDB_BUILD_EXAMPLES) add_subdirectory(examples) endif() if(NANOVDB_BUILD_PYTHON_MODULE) add_subdirectory(python) endif() openvdb-13.0.0/nanovdb/nanovdb/CNanoVDB.h000066400000000000000000000667011510223237100200170ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 // // Simple C-wrapper for the nanovdb structure // Meant for systems where you lack a C++ compiler. // /// @warning This header file will soon be deprecated in favor of PNanoVDB.h #ifndef __CNANOVDB__ #define __CNANOVDB__ #define CNANOVDB_DATA_ALIGNMENT 32 #define CNANOVDB_ALIGNMENT_PADDING(x, n) (-(x) & ((n)-1)) #define USE_SINGLE_ROOT_KEY #ifdef __OPENCL_VERSION__ #define CNANOVDB_GLOBAL __global #define RESTRICT restrict // OpenCL doesn't define these basic types: typedef unsigned long uint64_t; typedef long int64_t; typedef unsigned int uint32_t; typedef int int32_t; typedef short int16_t; typedef unsigned short uint16_t; typedef unsigned char uint8_t; #else #define CNANOVDB_GLOBAL #define RESTRICT __restrict #endif enum cnanovdb_GridType { cnanovdb_GridType_Unknown = 0, cnanovdb_GridType_Float = 1, cnanovdb_GridType_Double = 2, cnanovdb_GridType_Int16 = 3, cnanovdb_GridType_Int32 = 4, cnanovdb_GridType_Int64 = 5, cnanovdb_GridType_Vec3f = 6, cnanovdb_GridType_Vec3d = 7, cnanovdb_GridType_Mask = 8, cnanovdb_GridType_FP16 = 9, cnanovdb_GridType_End = 10 }; #define ROOT_LEVEL 3 #define DEFINEMASK_int(LOG2DIM, SIZE) \ typedef struct \ { \ uint64_t mWords[SIZE >> 6]; \ } cnanovdb_mask##LOG2DIM; \ \ static void cnanovdb_mask##LOG2DIM##_clear(CNANOVDB_GLOBAL cnanovdb_mask##LOG2DIM *RESTRICT mask) \ { for (uint32_t i = 0; i < (SIZE >> 6); i++) mask->mWords[i] = 0; } \ \ static bool cnanovdb_mask##LOG2DIM##_isOn(const CNANOVDB_GLOBAL cnanovdb_mask##LOG2DIM *RESTRICT mask, uint32_t n) \ { return 0 != (mask->mWords[n >> 6] & (((uint64_t)(1)) << (n & 63))); } \ /**/ #define DEFINEMASK(LOG2DIM) \ DEFINEMASK_int(LOG2DIM, (1U << (3*LOG2DIM))) #define INSTANTIATE(LOG2DIM) \ DEFINEMASK(LOG2DIM) INSTANTIATE(3) INSTANTIATE(4) INSTANTIATE(5) typedef struct { float mMatF[9]; // r,c = 3*r + c float mInvMatF[9]; // r,c = 3*r + c float mVecF[3]; float mTaperF; double mMatD[9]; // r,c = 3*r + c double mInvMatD[9]; // r,c = 3*r + c double mVecD[3]; double mTaperD; } cnanovdb_map; typedef struct { float mVec[3]; } cnanovdb_Vec3F; typedef struct { int32_t mVec[3]; } cnanovdb_coord; static int cnanovdb_coord_compare(const CNANOVDB_GLOBAL cnanovdb_coord *a, const cnanovdb_coord *b) { if (a->mVec[0] < b->mVec[0]) return -1; if (a->mVec[0] > b->mVec[0]) return 1; if (a->mVec[1] < b->mVec[1]) return -1; if (a->mVec[1] > b->mVec[1]) return 1; if (a->mVec[2] < b->mVec[2]) return -1; if (a->mVec[2] > b->mVec[2]) return 1; return 0; } #ifdef USE_SINGLE_ROOT_KEY static uint64_t cnanovdb_coord_to_key(const cnanovdb_coord *RESTRICT ijk) { // Define to workaround a bug with 64-bit shifts in the AMD OpenCL compiler. #if defined(AVOID_64BIT_SHIFT) uint2 key = (uint2)( ((uint32_t)ijk->mVec[2]) >> 12, 0) | (uint2)((((uint32_t)ijk->mVec[1]) >> 12) << 21, ((uint32_t)ijk->mVec[1]) >> 23) | (uint2)(0, (((uint32_t)ijk->mVec[0]) >> 12) << 10); return *(uint64_t *)&key; #else return ((uint64_t) (((uint32_t)ijk->mVec[2]) >> 12)) | (((uint64_t) (((uint32_t)ijk->mVec[1]) >> 12)) << 21) | (((uint64_t) (((uint32_t)ijk->mVec[0]) >> 12)) << 42); #endif } #else static void cnanovdb_coord_to_key(cnanovdb_coord *RESTRICT key, const cnanovdb_coord *RESTRICT ijk) { key->mVec[0] = ijk->mVec[0] & ~((1u << 12) - 1u); key->mVec[1] = ijk->mVec[1] & ~((1u << 12) - 1u); key->mVec[2] = ijk->mVec[2] & ~((1u << 12) - 1u); } #endif static void cnanovdb_map_apply(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src) { float sx = src->mVec[0]; float sy = src->mVec[1]; float sz = src->mVec[2]; dst->mVec[0] = sx * map->mMatF[0] + sy * map->mMatF[1] + sz * map->mMatF[2] + map->mVecF[0]; dst->mVec[1] = sx * map->mMatF[3] + sy * map->mMatF[4] + sz * map->mMatF[5] + map->mVecF[1]; dst->mVec[2] = sx * map->mMatF[6] + sy * map->mMatF[7] + sz * map->mMatF[8] + map->mVecF[2]; } static void cnanovdb_map_applyInverse(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src) { float sx = src->mVec[0] - map->mVecF[0]; float sy = src->mVec[1] - map->mVecF[1]; float sz = src->mVec[2] - map->mVecF[2]; dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[1] + sz * map->mInvMatF[2]; dst->mVec[1] = sx * map->mInvMatF[3] + sy * map->mInvMatF[4] + sz * map->mInvMatF[5]; dst->mVec[2] = sx * map->mInvMatF[6] + sy * map->mInvMatF[7] + sz * map->mInvMatF[8]; } static void cnanovdb_map_applyJacobi(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src) { float sx = src->mVec[0]; float sy = src->mVec[1]; float sz = src->mVec[2]; dst->mVec[0] = sx * map->mMatF[0] + sy * map->mMatF[1] + sz * map->mMatF[2]; dst->mVec[1] = sx * map->mMatF[3] + sy * map->mMatF[4] + sz * map->mMatF[5]; dst->mVec[2] = sx * map->mMatF[6] + sy * map->mMatF[7] + sz * map->mMatF[8]; } static void cnanovdb_map_applyInverseJacobi(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src) { float sx = src->mVec[0]; float sy = src->mVec[1]; float sz = src->mVec[2]; dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[1] + sz * map->mInvMatF[2]; dst->mVec[1] = sx * map->mInvMatF[3] + sy * map->mInvMatF[4] + sz * map->mInvMatF[5]; dst->mVec[2] = sx * map->mInvMatF[6] + sy * map->mInvMatF[7] + sz * map->mInvMatF[8]; } static void cnanovdb_map_applyIJT(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src) { float sx = src->mVec[0]; float sy = src->mVec[1]; float sz = src->mVec[2]; dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[3] + sz * map->mInvMatF[6]; dst->mVec[1] = sx * map->mInvMatF[1] + sy * map->mInvMatF[4] + sz * map->mInvMatF[7]; dst->mVec[2] = sx * map->mInvMatF[2] + sy * map->mInvMatF[5] + sz * map->mInvMatF[8]; } typedef struct { int64_t mByteOffset; // byte offset to the blind data, relative to the GridData. uint64_t mElementCount; // number of elements, e.g. point count uint32_t mFlags; // flags uint32_t mSemantic; // semantic meaning of the data. uint32_t mDataClass; // 4 bytes uint32_t mDataType; // 4 bytes char mName[256]; uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(int64_t)+sizeof(uint64_t)+2*sizeof(uint32_t)+2*sizeof(uint32_t)+256*sizeof(char), CNANOVDB_DATA_ALIGNMENT)]; } cnanovdb_gridblindmetadata; typedef struct { uint64_t mMagic; // 8B magic to validate it is valid grid data. uint64_t mChecksum; // 8B. Checksum of grid buffer. uint32_t mVersion;// 4B. compacted major.minor.path version number. uint32_t mFlags; // 4B. flags for grid. uint32_t mGridIndex;// 4B. Index of this grid in the buffer uint32_t mGridCount; // 4B. Total number of grids in the buffer uint64_t mGridSize; // 8B. byte count of this entire grid occupied in the buffer. char mGridName[256]; // 256B cnanovdb_map mMap; // 264B. affine transformation between index and world space in both single and double precision double mBBox[6]; // 48B. floating-point bounds of active values in WORLD SPACE double mVoxelSize[3]; // 24B. size of a voxel in world units uint32_t mGridClass; // 4B. uint32_t mGridType; // 4B. uint64_t mBlindMetadataOffset; // 8B. offset of GridBlindMetaData structures. int32_t mBlindMetadataCount; // 4B. count of GridBlindMetaData structures. uint32_t _reserved[CNANOVDB_ALIGNMENT_PADDING(8 + 8 + 4 + 4 + 4 + 4 + 8 + 256 + 24 + 24 + sizeof(cnanovdb_map) + 24 + 4 + 4 + 8 + 4, CNANOVDB_DATA_ALIGNMENT) / 4]; } cnanovdb_griddata; static void cnanovdb_griddata_worldToIndex(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src) { cnanovdb_map_applyInverse(dst, &grid->mMap, src); } static void cnanovdb_griddata_indexToWorld(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src) { cnanovdb_map_apply(dst, &grid->mMap, src); } static void cnanovdb_griddata_worldToIndexDir(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src) { cnanovdb_map_applyInverseJacobi(dst, &grid->mMap, src); } static void cnanovdb_griddata_indexToWorldDir(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src) { cnanovdb_map_applyJacobi(dst, &grid->mMap, src); } static void cnanovdb_griddata_applyIJT(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src) { cnanovdb_map_applyIJT(dst, &grid->mMap, src); } typedef struct { uint64_t mNodeOffset[ROOT_LEVEL + 1]; uint32_t mNodeCount[ROOT_LEVEL]; uint32_t mTileCount[ROOT_LEVEL]; uint64_t mVoxelCount; uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(4*sizeof(uint64_t)+(3+3)*sizeof(uint32_t)+sizeof(uint64_t), CNANOVDB_DATA_ALIGNMENT)]; } cnanovdb_treedata; static const CNANOVDB_GLOBAL cnanovdb_treedata * cnanovdb_griddata_tree(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT griddata) { return (const CNANOVDB_GLOBAL cnanovdb_treedata *)(griddata + 1); } #define CREATE_TILEENTRY(VALUETYPE, SUFFIX) \ typedef union \ { \ VALUETYPE value; \ uint64_t child; \ } cnanovdb_tileentry##SUFFIX; \ /**/ typedef struct { cnanovdb_coord mKey; const CNANOVDB_GLOBAL void *mNode[4]; } cnanovdb_readaccessor; static void cnanovdb_readaccessor_insert(cnanovdb_readaccessor *RESTRICT acc, int childlevel, const CNANOVDB_GLOBAL void *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) { acc->mNode[childlevel] = node; acc->mKey.mVec[0] = ijk->mVec[0]; acc->mKey.mVec[1] = ijk->mVec[1]; acc->mKey.mVec[2] = ijk->mVec[2]; } #define CREATE_LEAF_NODE_int(LEVEL, LOG2DIM, CHILDTOTAL, TOTAL, MASK, VALUETYPE, STATSTYPE, SUFFIX) \ typedef struct \ { \ cnanovdb_coord mBBox_min; \ uint8_t mBBoxDif[3]; \ uint8_t mFlags; \ cnanovdb_mask##LOG2DIM mValueMask; \ VALUETYPE mMinimum; \ VALUETYPE mMaximum; \ STATSTYPE mAverage; \ STATSTYPE mStdDevi; \ uint32_t _reserved[ CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_mask##LOG2DIM)+2*sizeof(VALUETYPE)+2*sizeof(STATSTYPE)+sizeof(cnanovdb_coord)+sizeof(uint8_t[3])+sizeof(uint8_t), CNANOVDB_DATA_ALIGNMENT)/4]; \ VALUETYPE mVoxels[1u << (3*LOG2DIM)]; \ } cnanovdb_node##LEVEL##SUFFIX; \ \ static uint32_t \ cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(const cnanovdb_coord *RESTRICT ijk) \ { \ return ( ( ( ijk->mVec[0] & MASK ) >> CHILDTOTAL ) << ( 2 * LOG2DIM ) ) + \ ( ( ( ijk->mVec[1] & MASK ) >> CHILDTOTAL ) << ( LOG2DIM ) ) + \ ( ( ijk->mVec[2] & MASK ) >> CHILDTOTAL ); \ } \ \ static VALUETYPE \ cnanovdb_node##LEVEL##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ return node->mVoxels[n]; \ } \ \ static VALUETYPE \ cnanovdb_node##LEVEL##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT /* DO NOT REMOVE: Required for C99 compliance */ acc) \ { \ (void)(acc); \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ return node->mVoxels[n]; \ } \ \ static bool \ cnanovdb_node##LEVEL##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n)) \ return true; \ return false; \ } \ \ static bool \ cnanovdb_node##LEVEL##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT /* DO NOT REMOVE: Required for C99 compliance */ acc) \ { \ (void)(acc); \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n)) \ return true; \ return false; \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX * \ cnanovdb_tree_getNode##LEVEL##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT tree, uint64_t i) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *basenode = (const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *)((CNANOVDB_GLOBAL uint8_t *)(tree) + tree->mNodeOffset[LEVEL]); \ return basenode + i; \ } \ \ /**/ #define CREATE_LEAF_NODE(LEVEL, LOG2DIM, TOTAL, VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_LEAF_NODE_int(LEVEL, LOG2DIM, (TOTAL-LOG2DIM), TOTAL, ((1u << TOTAL) - 1u), VALUETYPE, STATSTYPE, SUFFIX) #define CREATE_INTERNAL_NODE_int(CHILDLEVEL, LEVEL, LOG2DIM, CHILDTOTAL, TOTAL, MASK, VALUETYPE, STATSTYPE, SUFFIX) \ typedef struct \ { \ cnanovdb_coord mBBox_min, mBBox_max; \ int32_t mOffset; \ uint32_t mFlags; \ cnanovdb_mask##LOG2DIM mValueMask, mChildMask; \ VALUETYPE mMinimum, mMaximum; \ STATSTYPE mAverage, mStdDevi; \ uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_mask##LOG2DIM)+sizeof(VALUETYPE)*2+sizeof(STATSTYPE)*2+sizeof(cnanovdb_coord)*2+sizeof(int32_t)+sizeof(uint32_t), CNANOVDB_DATA_ALIGNMENT)]; \ cnanovdb_tileentry##SUFFIX mTable[1u << (3*LOG2DIM)]; \ } cnanovdb_node##LEVEL##SUFFIX; \ \ static uint32_t \ cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(const cnanovdb_coord *RESTRICT ijk) \ { \ return ( ( ( ijk->mVec[0] & MASK ) >> CHILDTOTAL ) << ( 2 * LOG2DIM ) ) + \ ( ( ( ijk->mVec[1] & MASK ) >> CHILDTOTAL ) << ( LOG2DIM ) ) + \ ( ( ijk->mVec[2] & MASK ) >> CHILDTOTAL ); \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX * \ cnanovdb_node##LEVEL##SUFFIX##_getChild(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, uint32_t n) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *childnode = (const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *)( ((CNANOVDB_GLOBAL uint8_t *)node) + node->mTable[n].child); \ return childnode; \ } \ \ static VALUETYPE \ cnanovdb_node##LEVEL##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \ return cnanovdb_node##CHILDLEVEL##SUFFIX##_getValue(child, ijk); \ } \ return node->mTable[n].value; \ } \ \ static VALUETYPE \ cnanovdb_node##LEVEL##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \ cnanovdb_readaccessor_insert(acc, CHILDLEVEL, child, ijk); \ return cnanovdb_node##CHILDLEVEL##SUFFIX##_getValueAndCache(child, ijk, acc); \ } \ return node->mTable[n].value; \ } \ \ static bool \ cnanovdb_node##LEVEL##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \ return cnanovdb_node##CHILDLEVEL##SUFFIX##_isActive(child, ijk); \ } \ return cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n) ? true : false; \ } \ \ static bool \ cnanovdb_node##LEVEL##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \ { \ uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \ if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \ cnanovdb_readaccessor_insert(acc, CHILDLEVEL, child, ijk); \ return cnanovdb_node##CHILDLEVEL##SUFFIX##_isActiveAndCache(child, ijk, acc); \ } \ return cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n) ? true : false; \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX * \ cnanovdb_tree_getNode##LEVEL##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT tree, uint64_t i) \ { \ const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *basenode = (const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *)((CNANOVDB_GLOBAL uint8_t *)(tree) + tree->mNodeOffset[LEVEL]); \ return basenode + i; \ } \ \ /**/ #define CREATE_INTERNAL_NODE(CHILDLEVEL, LEVEL, LOG2DIM, TOTAL, VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_INTERNAL_NODE_int(CHILDLEVEL, LEVEL, LOG2DIM, (TOTAL-LOG2DIM), TOTAL, ((1u << TOTAL) - 1u), VALUETYPE, STATSTYPE, SUFFIX) #ifdef USE_SINGLE_ROOT_KEY #define DEFINE_KEY(KEY) \ uint64_t KEY; #define KEYSIZE sizeof(uint64_t) #define KEYSEARCH(SUFFIX) \ uint64_t key; \ key = cnanovdb_coord_to_key(ijk); \ \ for (int i = low; i < high; i++) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = tiles + i; \ if (tile->key == key) \ return tile; \ } \ /**/ #else #define DEFINE_KEY(KEY) \ cnanovdb_coord KEY; #define KEYSIZE sizeof(cnanovdb_coord) #define KEYSEARCH(SUFFIX) \ cnanovdb_coord key; \ cnanovdb_coord_to_key(&key, ijk); \ \ while (low != high) \ { \ int32_t mid = low + (( high - low ) >> 1 ); \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = tiles + mid; \ \ int keycmp = cnanovdb_coord_compare(&tile->key, &key); \ if (keycmp == 0) \ { \ return tile; \ } \ \ if (keycmp < 0) \ low = mid + 1; \ else \ high = mid; \ } \ /**/ #endif #define CREATE_ROOTDATA(VALUETYPE, STATSTYPE, SUFFIX) \ typedef struct \ { \ DEFINE_KEY(key); \ int64_t child; \ uint32_t state; \ VALUETYPE value; \ uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(KEYSIZE)+sizeof(VALUETYPE)+sizeof(int64_t)+sizeof(uint32_t), CNANOVDB_DATA_ALIGNMENT)]; \ } cnanovdb_rootdata_tile##SUFFIX; \ \ typedef struct \ { \ cnanovdb_coord mBBox_min, mBBox_max; \ uint32_t mTableSize; \ VALUETYPE mBackground; \ VALUETYPE mMinimum, mMaximum; \ STATSTYPE mAverage, mStdDevi; \ uint32_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_coord)*2+sizeof(uint32_t)+sizeof(VALUETYPE)*3+sizeof(STATSTYPE)*2, CNANOVDB_DATA_ALIGNMENT)/4]; \ } cnanovdb_rootdata##SUFFIX; \ \ static const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX * \ cnanovdb_treedata_root##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT treedata) \ { \ return (const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *) ((const CNANOVDB_GLOBAL uint8_t *)(treedata) + treedata->mNodeOffset[ROOT_LEVEL]); \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX * \ cnanovdb_rootdata##SUFFIX##_getTile(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, uint32_t n) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *basetile = (const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *) (rootdata + 1); \ return basetile + n; \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX * \ cnanovdb_rootdata##SUFFIX##_getChild(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *RESTRICT tile) \ { \ CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *basenode = (CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) (((CNANOVDB_GLOBAL uint8_t *) rootdata) + tile->child); \ return basenode; \ } \ \ static const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX * \ cnanovdb_rootdata##SUFFIX##_findTile(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \ { \ int32_t low = 0, high = rootdata->mTableSize; \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tiles = cnanovdb_rootdata##SUFFIX##_getTile(rootdata, 0); \ \ KEYSEARCH(SUFFIX) \ return 0; \ } \ \ static VALUETYPE \ cnanovdb_rootdata##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \ if (!tile) \ return rootdata->mBackground; \ if (tile->child == 0) \ return tile->value; \ return cnanovdb_node2##SUFFIX##_getValue( cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile), ijk ); \ } \ \ static VALUETYPE \ cnanovdb_rootdata##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \ if (!tile) \ return rootdata->mBackground; \ if (tile->child == 0) \ return tile->value; \ const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *child = cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile); \ cnanovdb_readaccessor_insert(acc, 2, child, ijk); \ return cnanovdb_node2##SUFFIX##_getValueAndCache( child, ijk, acc ); \ } \ \ static bool \ cnanovdb_rootdata##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \ if (!tile) \ return false; \ if (tile->child == 0) \ return tile->state; \ return cnanovdb_node2##SUFFIX##_isActive( cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile), ijk ); \ } \ \ static bool \ cnanovdb_rootdata##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \ { \ const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \ if (!tile) \ return false; \ if (tile->child == 0) \ return tile->state; \ const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *child = cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile); \ cnanovdb_readaccessor_insert(acc, 2, child, ijk); \ return cnanovdb_node2##SUFFIX##_isActiveAndCache( child, ijk, acc ); \ } \ /**/ inline void cnanovdb_readaccessor_init(cnanovdb_readaccessor *RESTRICT acc, const CNANOVDB_GLOBAL void /*cnanovdb_rootdata* */ *RESTRICT rootdata) { acc->mNode[0] = acc->mNode[1] = acc->mNode[2] = 0; acc->mNode[3] = rootdata; } #define DEFINE_ISCACHED(LEVEL, MASK) \ inline bool \ cnanovdb_readaccessor_isCached##LEVEL(cnanovdb_readaccessor *RESTRICT acc, int32_t dirty) \ { \ if (!acc->mNode[LEVEL]) \ return false; \ if (dirty & ~MASK) \ { \ acc->mNode[LEVEL] = 0; \ return false; \ } \ return true; \ } \ /**/ DEFINE_ISCACHED(0, ((1u << 3) - 1u) ) DEFINE_ISCACHED(1, ((1u << 7) - 1u) ) DEFINE_ISCACHED(2, ((1u << 12) - 1u) ) inline int32_t cnanovdb_readaccessor_computeDirty(const cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk) { return (ijk->mVec[0] ^ acc->mKey.mVec[0]) | (ijk->mVec[1] ^ acc->mKey.mVec[1]) | (ijk->mVec[2] ^ acc->mKey.mVec[2]); } #define CREATE_ACCESSOR(VALUETYPE, SUFFIX) \ inline VALUETYPE \ cnanovdb_readaccessor_getValue##SUFFIX(cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk) \ { \ int32_t dirty = cnanovdb_readaccessor_computeDirty(acc, ijk); \ \ if (cnanovdb_readaccessor_isCached0(acc, dirty)) \ return cnanovdb_node0##SUFFIX##_getValue( ((CNANOVDB_GLOBAL cnanovdb_node0##SUFFIX *) acc->mNode[0]), ijk); \ if (cnanovdb_readaccessor_isCached1(acc, dirty)) \ return cnanovdb_node1##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_node1##SUFFIX *) acc->mNode[1]), ijk, acc); \ if (cnanovdb_readaccessor_isCached2(acc, dirty)) \ return cnanovdb_node2##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) acc->mNode[2]), ijk, acc); \ \ return cnanovdb_rootdata##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *)acc->mNode[3]), ijk, acc); \ } \ \ inline bool \ cnanovdb_readaccessor_isActive##SUFFIX(cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk) \ { \ int32_t dirty = cnanovdb_readaccessor_computeDirty(acc, ijk); \ \ if (cnanovdb_readaccessor_isCached0(acc, dirty)) \ return cnanovdb_node0##SUFFIX##_isActive( ((CNANOVDB_GLOBAL cnanovdb_node0##SUFFIX *) acc->mNode[0]), ijk); \ if (cnanovdb_readaccessor_isCached1(acc, dirty)) \ return cnanovdb_node1##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_node1##SUFFIX *) acc->mNode[1]), ijk, acc); \ if (cnanovdb_readaccessor_isCached2(acc, dirty)) \ return cnanovdb_node2##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) acc->mNode[2]), ijk, acc); \ \ return cnanovdb_rootdata##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *)acc->mNode[3]), ijk, acc); \ } \ /**/ #define CREATE_GRIDTYPE(VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_TILEENTRY(VALUETYPE, SUFFIX) \ CREATE_LEAF_NODE(0, 3, 3, VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_INTERNAL_NODE(0, 1, 4, 7, VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_INTERNAL_NODE(1, 2, 5, 12, VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_ROOTDATA(VALUETYPE, STATSTYPE, SUFFIX) \ CREATE_ACCESSOR(VALUETYPE, SUFFIX) \ /**/ CREATE_GRIDTYPE(float, float, F) CREATE_GRIDTYPE(cnanovdb_Vec3F, float, F3) static int cnanovdb_griddata_valid(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid) { if (!grid) return 0; if (grid->mMagic != 0x304244566f6e614eUL && grid->mMagic != 0x314244566f6e614eUL) return 0; return 1; } static int cnanovdb_griddata_validF(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid) { if (!cnanovdb_griddata_valid(grid)) return 0; if (grid->mGridType != cnanovdb_GridType_Float) return 0; return 1; } static int cnanovdb_griddata_validF3(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid) { if (!cnanovdb_griddata_valid(grid)) return 0; if (grid->mGridType != cnanovdb_GridType_Vec3f) return 0; return 1; } #endif openvdb-13.0.0/nanovdb/nanovdb/GridHandle.h000066400000000000000000000633021510223237100204600ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/GridHandle.h \author Ken Museth \date January 8, 2020 \brief Defines GridHandle, which manages a host, and possibly a device, memory buffer containing one or more NanoVDB grids. */ #ifndef NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED #define NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED #include // for std::ifstream #include // for std::cerr/cout #include #include #include // for toGridType #include #include // for updateGridCount namespace nanovdb { // --------------------------> GridHandle <------------------------------------ struct GridHandleMetaData {uint64_t offset, size; GridType gridType;}; /// @brief This class serves to manage a buffer containing one or more NanoVDB Grids. /// /// @note It is important to note that this class does NOT depend on OpenVDB. template class GridHandle { std::vector mMetaData; BufferT mBuffer; template static T* no_const(const T* ptr) { return const_cast(ptr); } public: using BufferType = BufferT; /// @brief Move constructor from a dual host-device buffer /// @param buffer buffer containing one or more NanoGrids that will be moved into this GridHandle /// @throw Will throw and error with the buffer does not contain a valid NanoGrid! /// @note The implementation of this template specialization is in nanovdb/cuda/GridHandle.cuh since it requires CUDA template::hasDeviceDual, int>::type = 0> GridHandle(T&& buffer); /// @brief Move constructor from a host buffer /// @param buffer buffer containing one or more NanoGrids that will be moved into this GridHandle /// @throw Will throw and error with the buffer does not contain a valid NanoGrid! template::hasDeviceDual, int>::type = 0> GridHandle(T&& buffer); /// @brief Constructs an empty GridHandle GridHandle() = default; /// @brief Disallow copy-construction GridHandle(const GridHandle&) = delete; /// @brief Move copy-constructor GridHandle(GridHandle&& other) noexcept { mBuffer = std::move(other.mBuffer); mMetaData = std::move(other.mMetaData); } /// @brief clear this GridHandle to an empty handle void reset() { mBuffer.clear(); mMetaData.clear(); } /// @brief Disallow copy assignment operation GridHandle& operator=(const GridHandle&) = delete; /// @brief Move copy assignment operation GridHandle& operator=(GridHandle&& other) noexcept { mBuffer = std::move(other.mBuffer); mMetaData = std::move(other.mMetaData); return *this; } /// @brief Performs a deep copy of the GridHandle, possibly templated on a different buffer type /// @tparam OtherBufferT Buffer type of the deep copy /// @param buffer optional buffer used for allocation /// @return A new handle of the specified buffer type that contains a deep copy of the current handle template GridHandle copy(const OtherBufferT& buffer = OtherBufferT()) const; /// @brief Return a reference to the buffer BufferT& buffer() { return mBuffer; } /// @brief Return a const reference to the buffer const BufferT& buffer() const { return mBuffer; } /// @brief Returns a non-const pointer to the data. /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized void* data() { return mBuffer.data(); } /// @brief Returns a const pointer to the data. /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized const void* data() const { return mBuffer.data(); } template typename util::enable_if::hasDeviceDual, const void*>::type deviceData() const { return mBuffer.deviceData(); } template typename util::enable_if::hasDeviceDual, const void*>::type deviceData(int device) const { return mBuffer.deviceData(device); } template typename util::enable_if::hasDeviceDual, void*>::type deviceData() { return mBuffer.deviceData(); } template typename util::enable_if::hasDeviceDual, void*>::type deviceData(int device) { return mBuffer.deviceData(device); } //@{ /// @brief Returns the size in bytes of the raw memory buffer managed by this GridHandle. [[deprecated("Use GridHandle::bufferSize instead.")]] uint64_t size() const { return mBuffer.size(); } uint64_t bufferSize() const { return mBuffer.size(); } //@} //@{ /// @brief Return true if this handle is empty, i.e. has no allocated memory bool empty() const { return mBuffer.size() == 0; } bool isEmpty() const { return mBuffer.size() == 0; } //@} /// @brief Return true if this handle is not empty, i.e. contains at least one grid operator bool() const { return !this->empty(); } /// @brief Returns a const host pointer to the @a n'th NanoVDB grid encoded in this GridHandle. /// @tparam ValueT Value type of the grid point to be returned /// @param n Index of the (host) grid pointer to be returned /// @warning Note that the return pointer can be NULL if the GridHandle no host grid, @a n is invalid /// or if the template parameter does not match the specified grid! template const NanoGrid* grid(uint32_t n = 0) const; /// @brief Returns a host pointer to the @a n'th NanoVDB grid encoded in this GridHandle. /// @tparam ValueT Value type of the grid point to be returned /// @param n Index of the (host) grid pointer to be returned /// @warning Note that the return pointer can be NULL if the GridHandle no host grid, @a n is invalid /// or if the template parameter does not match the specified grid! template NanoGrid* grid(uint32_t n = 0) {return const_cast*>(static_cast(this)->template grid(n));} /// @brief Return a const pointer to the @a n'th grid encoded in this GridHandle on the device, e.g. GPU /// @tparam ValueT Value type of the grid point to be returned /// @param n Index of the (device) grid pointer to be returned /// @warning Note that the return pointer can be NULL if the GridHandle has no device grid, @a n is invalid, /// or if the template parameter does not match the specified grid. template typename util::enable_if::hasDeviceDual, const NanoGrid*>::type deviceGrid(uint32_t n=0) const; /// @brief Return a const pointer to the @a n'th grid encoded in this GridHandle on the device, e.g. GPU /// @tparam ValueT Value type of the grid point to be returned /// @param n Index of the grid pointer to be returned /// @param verbose if non-zero error messages will be printed in case something failed /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized, @a n is invalid, /// or if the template parameter does not match the specified grid. template typename util::enable_if::hasDeviceDual, NanoGrid*>::type deviceGrid(uint32_t n=0){return const_cast*>(static_cast(this)->template deviceGrid(n));} /// @brief Upload the grid to the device, e.g. from CPU to GPU /// @note This method is only available if the buffer supports devices template typename util::enable_if::hasDeviceDual, void>::type deviceUpload(void* stream, bool sync = true) { mBuffer.deviceUpload(stream, sync); } /// @brief Upload the host buffer to a specific device buffer. It device buffer doesn't exist it's created first /// @param device Device to upload host data to /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous template typename util::enable_if::hasDeviceDual, void>::type deviceUpload(int device = 0, void* stream = nullptr, bool sync = true) { mBuffer.deviceUpload(device, stream, sync); } /// @brief Download the grid to from the device, e.g. from GPU to CPU /// @note This method is only available if the buffer supports devices template typename util::enable_if::hasDeviceDual, void>::type deviceDownload(void* stream, bool sync = true) { mBuffer.deviceDownload(stream, sync); } template typename util::enable_if::hasDeviceDual, void>::type deviceDownload(int device = 0, void* stream = nullptr, bool sync = true) { mBuffer.deviceDownload(device, stream, sync); } /// @brief Check if the buffer is this handle has any padding, i.e. if the buffer is larger than the combined size of all its grids /// @return true is the combined size of all grid is smaller than the buffer size bool isPadded() const {return mMetaData.empty() ? false : mMetaData.back().offset + mMetaData.back().size != mBuffer.size();} /// @brief Return the total number of grids contained in this buffer uint32_t gridCount() const {return static_cast(mMetaData.size());} /// @brief Return the grid size of the @a n'th grid in this GridHandle /// @param n index of the grid (assumed to be less than gridCount()) /// @return Return the byte size of the specified grid uint64_t gridSize(uint32_t n = 0) const {return mMetaData[n].size; } /// @brief compute the total sum of memory footprints of all the grids in this buffer /// @return the number of bytes occupied by all grids associated with this buffer uint64_t totalGridSize() const { uint64_t sum = 0; for (auto &m : mMetaData) sum += m.size; NANOVDB_ASSERT(sum <= mBuffer.size()); return sum; } /// @brief compute the size of unused storage in this buffer /// @return the number of unused bytes in this buffer. uint64_t freeSize() const {return mBuffer.size() - this->totalGridSize();} /// @brief Test if this buffer has any unused storage left, i.e. memory not occupied by grids /// @return true if there is no extra storage left in this buffer, i.e. empty or fully occupied with grids bool isFull() const { return this->totalGridSize() == mBuffer.size(); } /// @brief Return the GridType of the @a n'th grid in this GridHandle /// @param n index of the grid (assumed to be less than gridCount()) /// @return Return the GridType of the specified grid GridType gridType(uint32_t n = 0) const {return mMetaData[n].gridType; } /// @brief Access to the GridData of the n'th grid in the current handle /// @param n zero-based ID of the grid /// @return Const pointer to the n'th GridData in the current handle const GridData* gridData(uint32_t n = 0) const; /// @brief Returns a const point to the @a n'th grid meta data /// @param n zero-based ID of the grid /// @warning Note that the return pointer can be NULL if the GridHandle was not initialized const GridMetaData* gridMetaData(uint32_t n = 0) const; /// @brief Write a specific grid in this buffer to an output stream /// @param os output stream that the buffer will be written to /// @param n zero-based index of the grid to be written to stream void write(std::ostream& os, uint32_t n) const { if (const GridData* data = this->gridData(n)) { os.write((const char*)data, data->mGridSize); } else { throw std::runtime_error("GridHandle does not contain a #" + std::to_string(n) + " grid"); } } /// @brief Write the entire grid buffer to an output stream /// @param os output stream that the buffer will be written to void write(std::ostream& os) const { for (uint32_t n=0; ngridCount(); ++n) this->write(os, n); } /// @brief Write this entire grid buffer to a file /// @param fileName string name of the output file void write(const std::string &fileName) const { std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc); if (!os.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for output"); this->write(os); } /// @brief Write a specific grid to file /// @param fileName string name of the output file /// @param n zero-based index of the grid to be written to file void write(const std::string &fileName, uint32_t n) const { std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc); if (!os.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for output"); this->write(os, n); } /// @brief Read an entire raw grid buffer from an input stream /// @param is input stream containing a raw grid buffer /// @param pool optional pool from which to allocate the new grid buffer /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid void read(std::istream& is, const BufferT& pool = BufferT()); /// @brief Read a specific grid from an input stream containing a raw grid buffer /// @param is input stream containing a raw grid buffer /// @param n zero-based index of the grid to be read /// @param pool optional pool from which to allocate the new grid buffer /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid void read(std::istream& is, uint32_t n, const BufferT& pool = BufferT()); /// @brief Read a specific grid from an input stream containing a raw grid buffer /// @param is input stream containing a raw grid buffer /// @param gridName string name of the grid to be read /// @param pool optional pool from which to allocate the new grid buffer /// @throw Will throw a std::logic_error if the stream does not contain a valid raw grid with the specified name void read(std::istream& is, const std::string &gridName, const BufferT& pool = BufferT()); /// @brief Read a raw grid buffer from a file /// @param filename string name of the input file containing a raw grid buffer /// @param pool optional pool from which to allocate the new grid buffer void read(const std::string &fileName, const BufferT& pool = BufferT()) { std::ifstream is(fileName, std::ios::in | std::ios::binary); if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input"); this->read(is, pool); } /// @brief Read a specific grid from a file containing a raw grid buffer /// @param filename string name of the input file containing a raw grid buffer /// @param n zero-based index of the grid to be read /// @param pool optional pool from which to allocate the new grid buffer /// @throw Will throw a std::ios_base::failure if the file does not exist and a /// std::logic_error if the files does not contain a valid raw grid void read(const std::string &fileName, uint32_t n, const BufferT& pool = BufferT()) { std::ifstream is(fileName, std::ios::in | std::ios::binary); if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input"); this->read(is, n, pool); } /// @brief Read a specific grid from a file containing a raw grid buffer /// @param filename string name of the input file containing a raw grid buffer /// @param gridName string name of the grid to be read /// @param pool optional pool from which to allocate the new grid buffer /// @throw Will throw a std::ios_base::failure if the file does not exist and a /// std::logic_error if the files does not contain a valid raw grid withe the specified name void read(const std::string &fileName, const std::string &gridName, const BufferT& pool = BufferT()) { std::ifstream is(fileName, std::ios::in | std::ios::binary); if (!is.is_open()) throw std::ios_base::failure("Unable to open file named \"" + fileName + "\" for input"); this->read(is, gridName, pool); } }; // GridHandle // --------------------------> Implementation of private methods in GridHandle <------------------------------------ template inline const GridData* GridHandle::gridData(uint32_t n) const { const void *data = this->data(); if (data == nullptr || n >= mMetaData.size()) return nullptr; return util::PtrAdd(data, mMetaData[n].offset); }// const GridData* GridHandle::gridData(uint32_t n) const template inline const GridMetaData* GridHandle::gridMetaData(uint32_t n) const { const auto *data = this->data(); if (data == nullptr || n >= mMetaData.size()) return nullptr; return util::PtrAdd(data, mMetaData[n].offset); }// const GridMetaData* GridHandle::gridMetaData(uint32_t n) const inline __hostdev__ void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta) { uint64_t offset = 0; for (auto *p=meta, *q=p+data->mGridCount; p!=q; ++p) { *p = {offset, data->mGridSize, data->mGridType}; offset += p->size; data = util::PtrAdd(data, p->size); } }// void cpyGridHandleMeta(const GridData *data, GridHandleMetaData *meta) // template specialization of move constructor from a host buffer template template::hasDeviceDual, int>::type> GridHandle::GridHandle(T&& buffer) { static_assert(util::is_same::value, "Expected U==BufferT"); mBuffer = std::move(buffer); if (auto *data = reinterpret_cast(mBuffer.data())) { if (!data->isValid()) throw std::runtime_error("GridHandle was constructed with an invalid host buffer"); mMetaData.resize(data->mGridCount); cpyGridHandleMeta(data, mMetaData.data()); } }// GridHandle::GridHandle(T&& buffer) template template inline GridHandle GridHandle::copy(const OtherBufferT& other) const { if (mBuffer.isEmpty()) return GridHandle();// return an empty handle auto buffer = OtherBufferT::create(mBuffer.size(), &other); std::memcpy(buffer.data(), mBuffer.data(), mBuffer.size());// deep copy of buffer return GridHandle(std::move(buffer)); }// GridHandle GridHandle::copy(const OtherBufferT& other) const template template inline const NanoGrid* GridHandle::grid(uint32_t n) const { const void *data = mBuffer.data(); if (data == nullptr || n >= mMetaData.size() || mMetaData[n].gridType != toGridType()) return nullptr; return util::PtrAdd>(data, mMetaData[n].offset); }// const NanoGrid* GridHandle::grid(uint32_t n) const template template inline typename util::enable_if::hasDeviceDual, const NanoGrid*>::type GridHandle::deviceGrid(uint32_t n) const { const void *data = mBuffer.deviceData(); if (data == nullptr || n >= mMetaData.size() || mMetaData[n].gridType != toGridType()) return nullptr; return util::PtrAdd>(data, mMetaData[n].offset); }// GridHandle::deviceGrid(uint32_t n) cons template void GridHandle::read(std::istream& is, const BufferT& pool) { GridData data; is.read((char*)&data, sizeof(GridData)); if (data.isValid()) { uint64_t size = data.mGridSize, sum = 0u; while(data.mGridIndex + 1u < data.mGridCount) {// loop over remaining raw grids in stream is.seekg(data.mGridSize - sizeof(GridData), std::ios::cur);// skip grid is.read((char*)&data, sizeof(GridData)); sum += data.mGridSize; } auto buffer = BufferT::create(size + sum, &pool); is.seekg(-int64_t(sum + sizeof(GridData)), std::ios::cur);// rewind to start is.read((char*)(buffer.data()), buffer.size()); *this = GridHandle(std::move(buffer)); } else { is.seekg(-sizeof(GridData), std::ios::cur);// rewind throw std::logic_error("This stream does not contain a valid raw grid buffer"); } }// void GridHandle::read(std::istream& is, const BufferT& pool) template void GridHandle::read(std::istream& is, uint32_t n, const BufferT& pool) { GridData data; is.read((char*)&data, sizeof(GridData)); if (data.isValid()) { if (n>=data.mGridCount) throw std::runtime_error("stream does not contain a #" + std::to_string(n) + " grid"); while(data.mGridIndex != n) { is.seekg(data.mGridSize - sizeof(GridData), std::ios::cur);// skip grid is.read((char*)&data, sizeof(GridData)); } auto buffer = BufferT::create(data.mGridSize, &pool); is.seekg(-sizeof(GridData), std::ios::cur);// rewind is.read((char*)(buffer.data()), data.mGridSize); tools::updateGridCount((GridData*)buffer.data(), 0u, 1u); *this = GridHandle(std::move(buffer)); } else { is.seekg(-sizeof(GridData), std::ios::cur);// rewind sizeof(GridData) bytes to undo initial read throw std::logic_error("This file does not contain a valid raw buffer"); } }// void GridHandle::read(std::istream& is, uint32_t n, const BufferT& pool) template void GridHandle::read(std::istream& is, const std::string &gridName, const BufferT& pool) { static const std::streamsize byteSize = sizeof(GridData); GridData data; is.read((char*)&data, byteSize); is.seekg(-byteSize, std::ios::cur);// rewind if (data.isValid()) { uint32_t n = 0; while(data.mGridName != gridName && n++ < data.mGridCount) { is.seekg(data.mGridSize, std::ios::cur);// skip grid is.read((char*)&data, byteSize);// read sizeof(GridData) bytes is.seekg(-byteSize, std::ios::cur);// rewind } if (n>data.mGridCount) throw std::runtime_error("No raw grid named \""+gridName+"\""); auto buffer = BufferT::create(data.mGridSize, &pool); is.read((char*)(buffer.data()), data.mGridSize); tools::updateGridCount((GridData*)buffer.data(), 0u, 1u); *this = GridHandle(std::move(buffer)); } else { throw std::logic_error("This file does not contain a valid raw buffer"); } }// void GridHandle::read(std::istream& is, const std::string &gridName n, const BufferT& pool) // --------------------------> free-standing functions <------------------------------------ /// @brief Split all grids in a single GridHandle into a vector of multiple GridHandles each with a single grid /// @tparam BufferT Type of the input and output grid buffers /// @param handle GridHandle with grids that will be slip into individual GridHandles /// @param pool optional pool used for allocation of output GridHandle /// @return Vector of GridHandles each containing a single grid template class VectorT = std::vector> inline VectorT> splitGrids(const GridHandle &handle, const BufferT* other = nullptr) { using HandleT = GridHandle; const void *ptr = handle.data(); if (ptr == nullptr) return VectorT(); VectorT handles(handle.gridCount()); for (auto &h : handles) { const GridData *src = reinterpret_cast(ptr); NANOVDB_ASSERT(src->isValid()); auto buffer = BufferT::create(src->mGridSize, other); GridData *dst = reinterpret_cast(buffer.data()); std::memcpy(dst, src, src->mGridSize); tools::updateGridCount(dst, 0u, 1u); h = HandleT(std::move(buffer)); ptr = util::PtrAdd(ptr, src->mGridSize); } return handles; }// splitGrids /// @brief Combines (or merges) multiple GridHandles into a single GridHandle containing all grids /// @tparam BufferT Type of the input and output grid buffers /// @param handles Vector of GridHandles to be combined /// @param pool optional pool used for allocation of output GridHandle /// @return single GridHandle containing all input grids template class VectorT> inline GridHandle mergeGrids(const VectorT> &handles, const BufferT* pool = nullptr) { uint64_t size = 0u; uint32_t counter = 0u, gridCount = 0u; for (auto &h : handles) { gridCount += h.gridCount(); for (uint32_t n=0; n(dst); NANOVDB_ASSERT(data->isValid()); tools::updateGridCount(data, counter++, gridCount); dst = util::PtrAdd(dst, data->mGridSize); src = util::PtrAdd(src, data->mGridSize); } } return GridHandle(std::move(buffer)); }// mergeGrids } // namespace nanovdb #if defined(__CUDACC__) #include #endif// defined(__CUDACC__) #endif // NANOVDB_GRID_HANDLE_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/HostBuffer.h000066400000000000000000000521171510223237100205300ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! @file nanovdb/HostBuffer.h @date April 20, 2021 @brief HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally managed host memory. @details This HostBuffer can be used in multiple ways, most of which are demonstrated in the examples below. Memory in the pool can be managed or unmanged (e.g. internal or external) and can be shared between multiple buffers or belong to a single buffer. Example that uses HostBuffer::create inside io::readGrids to create a full self-managed buffer, i.e. not shared and without padding, per grid in the file. @code auto handles = nanovdb::io::readGrids("file.nvdb"); @endcode Example that uses HostBuffer::createFull. Assuming you have a raw pointer to a NanoVDB grid of unknown type, this examples shows how to create its GridHandle which can be used to enquire about the grid type and meta data. @code void *data;// pointer to a NanoVDB grid of unknown type uint64_t size;// byte size of NanoVDB grid of unknown type auto buffer = nanovdb::HostBuffer::createFull(size, data); nanovdb::GridHandle<> gridHandle(std::move(buffer)); @endcode Example that uses HostBuffer::createPool for internally managed host memory. Suppose you want to read multiple grids in multiple files, but reuse the same fixed sized memory buffer to both avoid memory fragmentation as well as exceeding the fixed memory ceiling! @code auto pool = nanovdb::HostBuffer::createPool(1 << 30);// 1 GB memory pool std::vector> frames;// vector of grid names for (int i=0; i array(new char[size + NANOVDB_DATA_ALIGNMENT]);// scoped pool of 1 GB with padding void *buffer = nanovdb::alignPtr(array.get());// 32B aligned buffer auto pool = nanovdb::HostBuffer::createPool(poolSize, buffer); auto handles = nanovdb::io::readGrids("file.nvdb", 0, pool); @endcode */ #ifndef NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED #define NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED #include // for NANOVDB_DATA_ALIGNMENT; #include // for types like int32_t etc #include // for fprintf #include // for std::malloc/std::realloc/std::free #include // for std::make_shared #include // for std::mutex #include // for std::unordered_set #include // for assert #include // for std::stringstream #include // for memcpy #define checkPtr(ptr, msg) \ { \ ptrAssert((ptr), (msg), __FILE__, __LINE__); \ } namespace nanovdb { template struct BufferTraits { static constexpr bool hasDeviceDual = false; }; // ----------------------------> HostBuffer <-------------------------------------- /// @brief This is a buffer that contains a shared or private pool /// to either externally or internally managed host memory. /// /// @note Terminology: /// Pool: 0 = buffer.size() < buffer.poolSize() /// Buffer: 0 < buffer.size() < buffer.poolSize() /// Full: 0 < buffer.size() = buffer.poolSize() /// Empty: 0 = buffer.size() = buffer.poolSize() class HostBuffer { struct Pool;// forward declaration of private pool struct std::shared_ptr mPool; uint64_t mSize; // total number of bytes for the NanoVDB grid. void* mData; // raw buffer for the NanoVDB grid. #if defined(DEBUG) || defined(_DEBUG) static inline void ptrAssert(void* ptr, const char* msg, const char* file, int line, bool abort = true) { if (ptr == nullptr) { fprintf(stderr, "NULL pointer error: %s %s %d\n", msg, file, line); if (abort) exit(1); } if (uint64_t(ptr) % NANOVDB_DATA_ALIGNMENT) { fprintf(stderr, "Alignment pointer error: %s %s %d\n", msg, file, line); if (abort) exit(1); } } #else static inline void ptrAssert(void*, const char*, const char*, int, bool = true) { } #endif public: /// @brief Return a full buffer or an empty buffer HostBuffer(uint64_t bufferSize = 0); /// @brief Move copy-constructor HostBuffer(HostBuffer&& other); /// @brief Custom descructor ~HostBuffer() { this->clear(); } /// @brief Move copy assignment operation HostBuffer& operator=(HostBuffer&& other); /// @brief Disallow copy-construction HostBuffer(const HostBuffer&) = delete; /// @brief Disallow copy assignment operation HostBuffer& operator=(const HostBuffer&) = delete; /// @brief Return a pool buffer which satisfies: buffer.size == 0, /// buffer.poolSize() == poolSize, and buffer.data() == nullptr. /// If data==nullptr, memory for the pool will be allocated. /// /// @throw If poolSize is zero. static HostBuffer createPool(uint64_t poolSize, void *data = nullptr); /// @brief Return a full buffer which satisfies: buffer.size == bufferSize, /// buffer.poolSize() == bufferSize, and buffer.data() == data. /// If data==nullptr, memory for the pool will be allocated. /// /// @throw If bufferSize is zero. static HostBuffer createFull(uint64_t bufferSize, void *data = nullptr); /// @brief Return a buffer with @c bufferSize bytes managed by /// the specified memory @c pool. If none is provided, i.e. /// @c pool == nullptr or @c pool->poolSize() == 0, one is /// created with size @c bufferSize, i.e. a full buffer is returned. /// /// @throw If the specified @c pool has insufficient memory for /// the requested buffer size. static HostBuffer create(uint64_t bufferSize, const HostBuffer* pool = nullptr); /// @brief Initialize as a full buffer with the specified size. If data is NULL /// the memory is internally allocated. void init(uint64_t bufferSize, void *data = nullptr); //@{ /// @brief Retuns a pointer to the raw memory buffer managed by this allocator. /// /// @warning Note that the pointer can be NULL if the allocator was not initialized! const void* data() const { return mData; } void* data() { return mData; } //@} /// @brief Returns an offset pointer of a specific type from the allocated host memory /// @tparam T Type of the pointer returned /// @param count Numbers of elements of @c parameter type T to skip /// @warning might return NULL template T* data(ptrdiff_t count = 0) const {return mData ? reinterpret_cast(mData) + count : nullptr;} //@{ /// @brief Returns the size in bytes associated with this buffer. uint64_t bufferSize() const { return mSize; } uint64_t size() const { return this->bufferSize(); } //@} /// @brief Returns the size in bytes of the memory pool shared with this instance. uint64_t poolSize() const; /// @brief Return true if memory is managed (using std::malloc and std:free) by the /// shared pool in this buffer. Else memory is assumed to be managed externally. bool isManaged() const; //@{ /// @brief Returns true if this buffer has no memory associated with it bool isEmpty() const { return !mPool || mSize == 0 || mData == nullptr; } bool empty() const { return this->isEmpty(); } //@} /// @brief Return true if this is a pool, i.e. an empty buffer with a nonempty /// internal pool, i.e. this->size() == 0 and this->poolSize() != 0 bool isPool() const { return mSize == 0 && this->poolSize() > 0; } /// @brief Return true if the pool exists, is nonempty but has no more available memory bool isFull() const; /// @brief Clear this buffer so it is empty. void clear(); /// @brief Clears all existing buffers that are registered against the memory pool /// and resets the pool so it can be reused to create new buffers. /// /// @throw If this instance is not empty or contains no pool. /// /// @warning This method is not thread-safe! void reset(); /// @brief Total number of bytes from the pool currently in use by buffers uint64_t poolUsage() const; /// @brief resize the pool size. It will attempt to resize the existing /// memory block, but if that fails a deep copy is performed. /// If @c data is not NULL it will be used as new externally /// managed memory for the pool. All registered buffers are /// updated so GridHandle::grid might return a new address (if /// deep copy was performed). /// /// @note This method can be use to resize the memory pool and even /// change it from internally to externally managed memory or vice versa. /// /// @throw if @c poolSize is less than this->poolUsage() the used memory /// or allocations fail. void resizePool(uint64_t poolSize, void *data = nullptr); }; // HostBuffer class // --------------------------> Implementation of HostBuffer::Pool <------------------------------------ // This is private struct of HostBuffer so you can safely ignore the API struct HostBuffer::Pool { using HashTableT = std::unordered_set; std::mutex mMutex; // mutex for updating mRegister and mFree HashTableT mRegister; void *mData, *mFree; uint64_t mSize, mPadding; bool mManaged; /// @brief External memory ctor Pool(uint64_t size = 0, void* data = nullptr) : mData(data) , mFree(mData) , mSize(size) , mPadding(0) , mManaged(data == nullptr) { if (mManaged) { mData = Pool::alloc(mSize); if (mData == nullptr) throw std::runtime_error("Pool::Pool malloc failed"); } mPadding = alignmentPadding(mData); if (!mManaged && mPadding != 0) { throw std::runtime_error("Pool::Pool: external memory buffer is not aligned to " + std::to_string(NANOVDB_DATA_ALIGNMENT) + " bytes.\nHint: use nanovdb::alignPtr or std::aligned_alloc (C++17 only)"); } mFree = util::PtrAdd(mData, mPadding); } /// @brief Custom destructor ~Pool() { assert(mRegister.empty()); if (mManaged) std::free(mData); } /// @brief Disallow copy-construction Pool(const Pool&) = delete; /// @brief Disallow move-construction Pool(const Pool&&) = delete; /// @brief Disallow copy assignment operation Pool& operator=(const Pool&) = delete; /// @brief Disallow move assignment operation Pool& operator=(const Pool&&) = delete; /// @brief Return the total number of bytes used from this Pool by buffers uint64_t usage() const { return util::PtrDiff(mFree, mData) - mPadding; } /// @brief Allocate a buffer of the specified size and add it to the register void add(HostBuffer* buffer, uint64_t size) { void *alignedFree = util::PtrAdd(mFree, alignmentPadding(mFree)); if (util::PtrAdd(alignedFree, size) > util::PtrAdd(mData, mPadding + mSize)) { std::stringstream ss; ss << "HostBuffer::Pool: insufficient memory\n" << "\tA buffer requested " << size << " bytes with " << NANOVDB_DATA_ALIGNMENT << "-bytes alignment from a pool with " << mSize << " bytes of which\n\t" << (util::PtrDiff(alignedFree, mData) - mPadding) << " bytes are used by " << mRegister.size() << " other buffer(s). " << "Pool is " << (mManaged ? "internally" : "externally") << " managed.\n"; throw std::runtime_error(ss.str()); } buffer->mSize = size; const std::lock_guard lock(mMutex); mRegister.insert(buffer); buffer->mData = alignedFree; mFree = util::PtrAdd(alignedFree, size); } /// @brief Remove the specified buffer from the register void remove(HostBuffer *buffer) { const std::lock_guard lock(mMutex); mRegister.erase(buffer); } /// @brief Replaces buffer1 with buffer2 in the register void replace(HostBuffer *buffer1, HostBuffer *buffer2) { const std::lock_guard lock(mMutex); mRegister.erase( buffer1); mRegister.insert(buffer2); } /// @brief Reset the register and all its buffers void reset() { for (HostBuffer *buffer : mRegister) { buffer->mPool.reset(); buffer->mSize = 0; buffer->mData = nullptr; } mRegister.clear(); mFree = util::PtrAdd(mData, mPadding); } /// @brief Resize this Pool and update registered buffers as needed. If data is no NULL /// it is used as externally managed memory. void resize(uint64_t size, void *data = nullptr) { const uint64_t memUsage = this->usage(); const bool managed = (data == nullptr); if (!managed && alignmentPadding(data) != 0) { throw std::runtime_error("Pool::resize: external memory buffer is not aligned to " + std::to_string(NANOVDB_DATA_ALIGNMENT) + " bytes"); } if (memUsage > size) { throw std::runtime_error("Pool::resize: insufficient memory"); } uint64_t padding = 0; if (mManaged && managed && size != mSize) { // managed -> managed padding = mPadding; data = Pool::realloc(mData, memUsage, size, padding); // performs both copy and free of mData } else if (!mManaged && managed) { // un-managed -> managed data = Pool::alloc(size); padding = alignmentPadding(data); } if (data == nullptr) { throw std::runtime_error("Pool::resize: allocation failed"); } else if (data != mData) { void* paddedData = util::PtrAdd(data, padding); if (!(mManaged && managed)) { // no need to copy if managed -> managed memcpy(paddedData, util::PtrAdd(mData, mPadding), memUsage); } for (HostBuffer* buffer : mRegister) { // update registered buffers buffer->mData = util::PtrAdd(paddedData, util::PtrDiff(buffer->mData, util::PtrAdd(mData, mPadding))); } mFree = util::PtrAdd(paddedData, memUsage); // update the free pointer if (mManaged && !managed) {// only free if managed -> un-managed std::free(mData); } mData = data; mPadding = padding; } mSize = size; mManaged = managed; } /// @brief Return true is all the memory in this pool is in use. bool isFull() const { assert(mFree <= util::PtrAdd(mData, mPadding + mSize)); return mSize > 0 ? mFree == util::PtrAdd(mData, mPadding + mSize) : false; } private: static void* alloc(uint64_t size) { // make sure we alloc enough space to align the result return std::malloc(size + NANOVDB_DATA_ALIGNMENT); } static void* realloc(void* const origData, uint64_t origSize, uint64_t desiredSize, uint64_t& padding) { // make sure we alloc enough space to align the result void* data = std::realloc(origData, desiredSize + NANOVDB_DATA_ALIGNMENT); if (data != nullptr && data != origData) { uint64_t newPadding = alignmentPadding(data); // Number of padding bytes may have changed -- move data if that's the case if (newPadding != padding) { // Realloc should not happen when shrinking down buffer, but let's be safe std::memmove(util::PtrAdd(data, newPadding), util::PtrAdd(data, padding), math::Min(origSize, desiredSize)); padding = newPadding; } } return data; } };// struct HostBuffer::Pool // --------------------------> Implementation of HostBuffer <------------------------------------ inline HostBuffer::HostBuffer(uint64_t size) : mPool(nullptr), mSize(size), mData(nullptr) { if (size>0) { mPool = std::make_shared(size); mData = mPool->mFree; mPool->mRegister.insert(this); mPool->mFree = util::PtrAdd(mPool->mFree, size); } } inline HostBuffer::HostBuffer(HostBuffer&& other) : mPool(other.mPool), mSize(other.mSize), mData(other.mData) { if (mPool && mSize != 0) { mPool->replace(&other, this); } other.mPool.reset(); other.mSize = 0; other.mData = nullptr; } inline void HostBuffer::init(uint64_t bufferSize, void *data) { if (bufferSize == 0) { throw std::runtime_error("HostBuffer: invalid buffer size"); } if (mPool) { mPool.reset(); } if (!mPool || mPool->mSize != bufferSize) { mPool = std::make_shared(bufferSize, data); } mPool->add(this, bufferSize); } inline HostBuffer& HostBuffer::operator=(HostBuffer&& other) { if (mPool) { mPool->remove(this); } mPool = other.mPool; mSize = other.mSize; mData = other.mData; if (mPool && mSize != 0) { mPool->replace(&other, this); } other.mPool.reset(); other.mSize = 0; other.mData = nullptr; return *this; } inline uint64_t HostBuffer::poolSize() const { return mPool ? mPool->mSize : 0u; } inline uint64_t HostBuffer::poolUsage() const { return mPool ? mPool->usage(): 0u; } inline bool HostBuffer::isManaged() const { return mPool ? mPool->mManaged : false; } inline bool HostBuffer::isFull() const { return mPool ? mPool->isFull() : false; } inline HostBuffer HostBuffer::createPool(uint64_t poolSize, void *data) { if (poolSize == 0) { throw std::runtime_error("HostBuffer: invalid pool size"); } HostBuffer buffer; buffer.mPool = std::make_shared(poolSize, data); // note the buffer is NOT registered by its pool since it is not using its memory buffer.mSize = 0; buffer.mData = nullptr; return buffer; } inline HostBuffer HostBuffer::createFull(uint64_t bufferSize, void *data) { if (bufferSize == 0) { throw std::runtime_error("HostBuffer: invalid buffer size"); } HostBuffer buffer; buffer.mPool = std::make_shared(bufferSize, data); buffer.mPool->add(&buffer, bufferSize); return buffer; } inline HostBuffer HostBuffer::create(uint64_t bufferSize, const HostBuffer* pool) { HostBuffer buffer; if (pool == nullptr || !pool->mPool) { buffer.mPool = std::make_shared(bufferSize); } else { buffer.mPool = pool->mPool; } buffer.mPool->add(&buffer, bufferSize); return buffer; } inline void HostBuffer::clear() { if (mPool) {// remove self from the buffer register in the pool mPool->remove(this); } mPool.reset(); mSize = 0; mData = nullptr; } inline void HostBuffer::reset() { if (this->size()>0) { throw std::runtime_error("HostBuffer: only empty buffers can call reset"); } if (!mPool) { throw std::runtime_error("HostBuffer: this buffer contains no pool to reset"); } mPool->reset(); } inline void HostBuffer::resizePool(uint64_t size, void *data) { if (!mPool) { throw std::runtime_error("HostBuffer: this buffer contains no pool to resize"); } mPool->resize(size, data); } } // namespace nanovdb #endif // end of NANOVDB_HOSTBUFFER_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/NanoVDB.h000066400000000000000000010526141510223237100177130ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/NanoVDB.h \author Ken Museth \date January 8, 2020 \brief Implements a light-weight self-contained VDB data-structure in a single file! In other words, this is a significantly watered-down version of the OpenVDB implementation, with few dependencies - so a one-stop-shop for a minimalistic VDB data structure that run on most platforms! \note It is important to note that NanoVDB (by design) is a read-only sparse GPU (and CPU) friendly data structure intended for applications like rendering and collision detection. As such it obviously lacks a lot of the functionality and features of OpenVDB grids. NanoVDB is essentially a compact linearized (or serialized) representation of an OpenVDB tree with getValue methods only. For best performance use the ReadAccessor::getValue method as opposed to the Tree::getValue method. Note that since a ReadAccessor caches previous access patterns it is by design not thread-safe, so use one instantiation per thread (it is very light-weight). Also, it is not safe to copy accessors between the GPU and CPU! In fact, client code should only interface with the API of the Grid class (all other nodes of the NanoVDB data structure can safely be ignored by most client codes)! \warning NanoVDB grids can only be constructed via tools like createNanoGrid or the GridBuilder. This explains why none of the grid nodes defined below have public constructors or destructors. \details Please see the following paper for more details on the data structure: K. Museth, “VDB: High-Resolution Sparse Volumes with Dynamic Topologyâ€�, ACM Transactions on Graphics 32(3), 2013, which can be found here: http://www.museth.org/Ken/Publications_files/Museth_TOG13.pdf NanoVDB was first published there: https://dl.acm.org/doi/fullHtml/10.1145/3450623.3464653 Overview: This file implements the following fundamental class that when combined forms the backbone of the VDB tree data structure: Coord- a signed integer coordinate Vec3 - a 3D vector Vec4 - a 4D vector BBox - a bounding box Mask - a bitmask essential to the non-root tree nodes Map - an affine coordinate transformation Grid - contains a Tree and a map for world<->index transformations. Use this class as the main API with client code! Tree - contains a RootNode and getValue methods that should only be used for debugging RootNode - the top-level node of the VDB data structure InternalNode - the internal nodes of the VDB data structure LeafNode - the lowest level tree nodes that encode voxel values and state ReadAccessor - implements accelerated random access operations Semantics: A VDB data structure encodes values and (binary) states associated with signed integer coordinates. Values encoded at the leaf node level are denoted voxel values, and values associated with other tree nodes are referred to as tile values, which by design cover a larger coordinate index domain. Memory layout: It's important to emphasize that all the grid data (defined below) are explicitly 32 byte aligned, which implies that any memory buffer that contains a NanoVDB grid must also be at 32 byte aligned. That is, the memory address of the beginning of a buffer (see ascii diagram below) must be divisible by 32, i.e. uintptr_t(&buffer)%32 == 0! If this is not the case, the C++ standard says the behaviour is undefined! Normally this is not a concerns on GPUs, because they use 256 byte aligned allocations, but the same cannot be said about the CPU. GridData is always at the very beginning of the buffer immediately followed by TreeData! The remaining nodes and blind-data are allowed to be scattered throughout the buffer, though in practice they are arranged as: GridData: 672 bytes (e.g. magic, checksum, major, flags, index, count, size, name, map, world bbox, voxel size, class, type, offset, count) TreeData: 64 bytes (node counts and byte offsets) ... optional padding ... RootData: size depends on ValueType (index bbox, voxel count, tile count, min/max/avg/standard deviation) Array of: RootData::Tile ... optional padding ... Array of: Upper InternalNodes of size 32^3: bbox, two bit masks, 32768 tile values, and min/max/avg/standard deviation values ... optional padding ... Array of: Lower InternalNodes of size 16^3: bbox, two bit masks, 4096 tile values, and min/max/avg/standard deviation values ... optional padding ... Array of: LeafNodes of size 8^3: bbox, bit masks, 512 voxel values, and min/max/avg/standard deviation values ... optional padding ... Array of: GridBlindMetaData (288 bytes). The offset and count are defined in GridData::mBlindMetadataOffset and GridData::mBlindMetadataCount ... optional padding ... Array of: blind data Notation: "]---[" implies it has optional padding, and "][" implies zero padding [GridData(672B)][TreeData(64B)]---[RootData][N x Root::Tile]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc. ^ ^ ^ ^ ^ ^ ^ | | | | | | GridBlindMetaData* +-- Start of 32B aligned buffer | | | | +-- Node0::DataType* leafData GridType::DataType* gridData | | | | | | | +-- Node1::DataType* lowerData RootType::DataType* rootData --+ | | | +-- Node2::DataType* upperData | +-- RootType::DataType::Tile* tile */ #ifndef NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED #define NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED // The following two header files are the only mandatory dependencies #include // for __hostdev__ and lots of other utility functions #include // for Coord, BBox, Vec3, Vec4 etc // Do not change this value! 32 byte alignment is fixed in NanoVDB #define NANOVDB_DATA_ALIGNMENT 32 // NANOVDB_MAGIC_NUMB previously used for both grids and files (starting with v32.6.0) // NANOVDB_MAGIC_GRID currently used exclusively for grids (serialized to a single buffer) // NANOVDB_MAGIC_FILE currently used exclusively for files // | : 0 in 30 corresponds to 0 in NanoVDB0 #define NANOVDB_MAGIC_NUMB 0x304244566f6e614eUL // "NanoVDB0" in hex - little endian (uint64_t) #define NANOVDB_MAGIC_GRID 0x314244566f6e614eUL // "NanoVDB1" in hex - little endian (uint64_t) #define NANOVDB_MAGIC_FILE 0x324244566f6e614eUL // "NanoVDB2" in hex - little endian (uint64_t) #define NANOVDB_MAGIC_MASK 0x00FFFFFFFFFFFFFFUL // use this mask to remove the number #define NANOVDB_USE_NEW_MAGIC_NUMBERS// enables use of the new magic numbers described above #define NANOVDB_MAJOR_VERSION_NUMBER 32 // reflects changes to the ABI and hence also the file format #define NANOVDB_MINOR_VERSION_NUMBER 9 // reflects changes to the API but not ABI #define NANOVDB_PATCH_VERSION_NUMBER 0 // reflects changes that does not affect the ABI or API #define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 // This replaces a Coord key at the root level with a single uint64_t #define NANOVDB_USE_SINGLE_ROOT_KEY // This replaces three levels of Coord keys in the ReadAccessor with one Coord //#define NANOVDB_USE_SINGLE_ACCESSOR_KEY // Use this to switch between std::ofstream or FILE implementations //#define NANOVDB_USE_IOSTREAMS #define NANOVDB_FPN_BRANCHLESS #if !defined(NANOVDB_ALIGN) #define NANOVDB_ALIGN(n) alignas(n) #endif // !defined(NANOVDB_ALIGN) namespace nanovdb {// ================================================================= // --------------------------> Build types <------------------------------------ /// @brief Dummy type for a voxel whose value equals an offset into an external value array class ValueIndex{}; /// @brief Dummy type for a voxel whose value equals an offset into an external value array of active values class ValueOnIndex{}; /// @brief Dummy type for a voxel whose value equals its binary active state class ValueMask{}; /// @brief Dummy type for a 16 bit floating point values (placeholder for IEEE 754 Half) class Half{}; /// @brief Dummy type for a 4bit quantization of float point values class Fp4{}; /// @brief Dummy type for a 8bit quantization of float point values class Fp8{}; /// @brief Dummy type for a 16bit quantization of float point values class Fp16{}; /// @brief Dummy type for a variable bit quantization of floating point values class FpN{}; /// @brief Dummy type for indexing points into voxels class Point{}; // --------------------------> GridType <------------------------------------ /// @brief return the number of characters (including null termination) required to convert enum type to a string /// /// @note This curious implementation, which subtracts End from StrLen, avoids duplicate values in the enum! template __hostdev__ inline constexpr uint32_t strlen(){return (uint32_t)EnumT::StrLen - (uint32_t)EnumT::End;} /// @brief List of types that are currently supported by NanoVDB /// /// @note To expand on this list do: /// 1) Add the new type between Unknown and End in the enum below /// 2) Add the new type to OpenToNanoVDB::processGrid that maps OpenVDB types to GridType /// 3) Verify that the ConvertTrait in NanoToOpenVDB.h works correctly with the new type /// 4) Add the new type to toGridType (defined below) that maps NanoVDB types to GridType /// 5) Add the new type to toStr (defined below) enum class GridType : uint32_t { Unknown = 0, // unknown value type - should rarely be used Float = 1, // single precision floating point value Double = 2, // double precision floating point value Int16 = 3, // half precision signed integer value Int32 = 4, // single precision signed integer value Int64 = 5, // double precision signed integer value Vec3f = 6, // single precision floating 3D vector Vec3d = 7, // double precision floating 3D vector Mask = 8, // no value, just the active state Half = 9, // half precision floating point value (placeholder for IEEE 754 Half) UInt32 = 10, // single precision unsigned integer value Boolean = 11, // boolean value, encoded in bit array RGBA8 = 12, // RGBA packed into 32bit word in reverse-order, i.e. R is lowest byte. Fp4 = 13, // 4bit quantization of floating point value Fp8 = 14, // 8bit quantization of floating point value Fp16 = 15, // 16bit quantization of floating point value FpN = 16, // variable bit quantization of floating point value Vec4f = 17, // single precision floating 4D vector Vec4d = 18, // double precision floating 4D vector Index = 19, // index into an external array of active and inactive values OnIndex = 20, // index into an external array of active values //IndexMask = 21, // retired ValueIndexMask - available for future use //OnIndexMask = 22, // retired ValueOnIndexMask - available for future use PointIndex = 23, // voxels encode indices to co-located points Vec3u8 = 24, // 8bit quantization of floating point 3D vector (only as blind data) Vec3u16 = 25, // 16bit quantization of floating point 3D vector (only as blind data) UInt8 = 26, // 8 bit unsigned integer values (eg 0 -> 255 gray scale) End = 27,// total number of types in this enum (excluding StrLen since it's not a type) StrLen = End + 11};// this entry is used to determine the minimum size of c-string /// @brief Maps a GridType to a c-string /// @param dst destination string of size 12 or larger /// @param gridType GridType enum to be mapped to a string /// @return Retuns a c-string used to describe a GridType __hostdev__ inline char* toStr(char *dst, GridType gridType) { switch (gridType){ case GridType::Unknown: return util::strcpy(dst, "Unknown"); case GridType::Float: return util::strcpy(dst, "float"); case GridType::Double: return util::strcpy(dst, "double"); case GridType::Int16: return util::strcpy(dst, "int16"); case GridType::Int32: return util::strcpy(dst, "int32"); case GridType::Int64: return util::strcpy(dst, "int64"); case GridType::Vec3f: return util::strcpy(dst, "Vec3f"); case GridType::Vec3d: return util::strcpy(dst, "Vec3d"); case GridType::Mask: return util::strcpy(dst, "Mask"); case GridType::Half: return util::strcpy(dst, "Half"); case GridType::UInt32: return util::strcpy(dst, "uint32"); case GridType::Boolean: return util::strcpy(dst, "bool"); case GridType::RGBA8: return util::strcpy(dst, "RGBA8"); case GridType::Fp4: return util::strcpy(dst, "Float4"); case GridType::Fp8: return util::strcpy(dst, "Float8"); case GridType::Fp16: return util::strcpy(dst, "Float16"); case GridType::FpN: return util::strcpy(dst, "FloatN"); case GridType::Vec4f: return util::strcpy(dst, "Vec4f"); case GridType::Vec4d: return util::strcpy(dst, "Vec4d"); case GridType::Index: return util::strcpy(dst, "Index"); case GridType::OnIndex: return util::strcpy(dst, "OnIndex"); case GridType::PointIndex: return util::strcpy(dst, "PointIndex");// StrLen = 10 + 1 + End case GridType::Vec3u8: return util::strcpy(dst, "Vec3u8"); case GridType::Vec3u16: return util::strcpy(dst, "Vec3u16"); case GridType::UInt8: return util::strcpy(dst, "uint8"); default: return util::strcpy(dst, "End"); } } // --------------------------> GridClass <------------------------------------ /// @brief Classes (superset of OpenVDB) that are currently supported by NanoVDB enum class GridClass : uint32_t { Unknown = 0, LevelSet = 1, // narrow band level set, e.g. SDF FogVolume = 2, // fog volume, e.g. density Staggered = 3, // staggered MAC grid, e.g. velocity PointIndex = 4, // point index grid PointData = 5, // point data grid Topology = 6, // grid with active states only (no values) VoxelVolume = 7, // volume of geometric cubes, e.g. colors cubes in Minecraft IndexGrid = 8, // grid whose values are offsets, e.g. into an external array TensorGrid = 9, // Index grid for indexing learnable tensor features End = 10,// total number of types in this enum (excluding StrLen since it's not a type) StrLen = End + 7};// this entry is used to determine the minimum size of c-string /// @brief Retuns a c-string used to describe a GridClass /// @param dst destination string of size 7 or larger /// @param gridClass GridClass enum to be converted to a string __hostdev__ inline char* toStr(char *dst, GridClass gridClass) { switch (gridClass){ case GridClass::Unknown: return util::strcpy(dst, "?"); case GridClass::LevelSet: return util::strcpy(dst, "SDF"); case GridClass::FogVolume: return util::strcpy(dst, "FOG"); case GridClass::Staggered: return util::strcpy(dst, "MAC"); case GridClass::PointIndex: return util::strcpy(dst, "PNTIDX");// StrLen = 6 + 1 + End case GridClass::PointData: return util::strcpy(dst, "PNTDAT"); case GridClass::Topology: return util::strcpy(dst, "TOPO"); case GridClass::VoxelVolume: return util::strcpy(dst, "VOX"); case GridClass::IndexGrid: return util::strcpy(dst, "INDEX"); case GridClass::TensorGrid: return util::strcpy(dst, "TENSOR"); default: return util::strcpy(dst, "END"); } } // --------------------------> GridFlags <------------------------------------ /// @brief Grid flags which indicate what extra information is present in the grid buffer. enum class GridFlags : uint32_t { HasLongGridName = 1 << 0, // grid name is longer than 256 characters HasBBox = 1 << 1, // nodes contain bounding-boxes of active values HasMinMax = 1 << 2, // nodes contain min/max of active values HasAverage = 1 << 3, // nodes contain averages of active values HasStdDeviation = 1 << 4, // nodes contain standard deviations of active values IsBreadthFirst = 1 << 5, // nodes are typically arranged breadth-first in memory End = 1 << 6, // use End - 1 as a mask for the 5 lower bit flags StrLen = End + 23,// this entry is used to determine the minimum size of c-string }; /// @brief Retuns a c-string used to describe a GridFlags /// @param dst destination string of size 23 or larger /// @param gridFlags GridFlags enum to be converted to a string __hostdev__ inline const char* toStr(char *dst, GridFlags gridFlags) { switch (gridFlags){ case GridFlags::HasLongGridName: return util::strcpy(dst, "has long grid name"); case GridFlags::HasBBox: return util::strcpy(dst, "has bbox"); case GridFlags::HasMinMax: return util::strcpy(dst, "has min/max"); case GridFlags::HasAverage: return util::strcpy(dst, "has average"); case GridFlags::HasStdDeviation: return util::strcpy(dst, "has standard deviation");// StrLen = 22 + 1 + End case GridFlags::IsBreadthFirst: return util::strcpy(dst, "is breadth-first"); default: return util::strcpy(dst, "end"); } } // --------------------------> MagicType <------------------------------------ /// @brief Enums used to identify magic numbers recognized by NanoVDB enum class MagicType : uint32_t { Unknown = 0,// first 64 bits are neither of the cases below OpenVDB = 1,// first 32 bits = 0x56444220UL NanoVDB = 2,// first 64 bits = NANOVDB_MAGIC_NUMB NanoGrid = 3,// first 64 bits = NANOVDB_MAGIC_GRID NanoFile = 4,// first 64 bits = NANOVDB_MAGIC_FILE End = 5, StrLen = End + 14};// this entry is used to determine the minimum size of c-string /// @brief maps 64 bits of magic number to enum __hostdev__ inline MagicType toMagic(uint64_t magic) { switch (magic){ case NANOVDB_MAGIC_NUMB: return MagicType::NanoVDB; case NANOVDB_MAGIC_GRID: return MagicType::NanoGrid; case NANOVDB_MAGIC_FILE: return MagicType::NanoFile; default: return (magic & ~uint32_t(0)) == 0x56444220UL ? MagicType::OpenVDB : MagicType::Unknown; } } /// @brief print 64-bit magic number to string /// @param dst destination string of size 25 or larger /// @param magic 64 bit magic number to be printed /// @return return destination string @c dst __hostdev__ inline char* toStr(char *dst, MagicType magic) { switch (magic){ case MagicType::Unknown: return util::strcpy(dst, "unknown"); case MagicType::NanoVDB: return util::strcpy(dst, "nanovdb"); case MagicType::NanoGrid: return util::strcpy(dst, "nanovdb::Grid");// StrLen = 13 + 1 + End case MagicType::NanoFile: return util::strcpy(dst, "nanovdb::File"); case MagicType::OpenVDB: return util::strcpy(dst, "openvdb"); default: return util::strcpy(dst, "end"); } } // --------------------------> PointType enums <------------------------------------ // Define the type used when the points are encoded as blind data in the output grid enum class PointType : uint32_t { Disable = 0,// no point information e.g. when BuildT != Point PointID = 1,// linear index of type uint32_t to points World64 = 2,// Vec3d in world space World32 = 3,// Vec3f in world space Grid64 = 4,// Vec3d in grid space Grid32 = 5,// Vec3f in grid space Voxel32 = 6,// Vec3f in voxel space Voxel16 = 7,// Vec3u16 in voxel space Voxel8 = 8,// Vec3u8 in voxel space Default = 9,// output matches input, i.e. Vec3d or Vec3f in world space End =10 }; // --------------------------> GridBlindData enums <------------------------------------ /// @brief Blind-data Classes that are currently supported by NanoVDB enum class GridBlindDataClass : uint32_t { Unknown = 0, IndexArray = 1,// indices typically used for mapping into other arrays AttributeArray = 2,// attributes typically associated with points GridName = 3,// grid names of length longer than 256 characters ChannelArray = 4,// channel of values typically used by index grids End = 5 }; /// @brief Blind-data Semantics that are currently understood by NanoVDB enum class GridBlindDataSemantic : uint32_t { Unknown = 0, PointPosition = 1, // 3D coordinates in an unknown space PointColor = 2, // color associated with point PointNormal = 3,// normal associated with point PointRadius = 4,// radius of point PointVelocity = 5,// velocity associated with point PointId = 6,// integer ID of point WorldCoords = 7, // 3D coordinates in world space, e.g. (0.056, 0.8, 1,8) GridCoords = 8, // 3D coordinates in grid space, e.g. (1.2, 4.0, 5.7), aka index-space VoxelCoords = 9, // 3D coordinates in voxel space, e.g. (0.2, 0.0, 0.7) LevelSet = 10, // narrow band level set, e.g. SDF FogVolume = 11, // fog volume, e.g. density Staggered = 12, // staggered MAC grid, e.g. velocity End = 13 }; /// @brief Maps from GridBlindDataSemantic to GridClass /// @note Useful when converting an IndexGrid with blind data of type T into a Grid /// @param semantics GridBlindDataSemantic /// @param defaultClass Default return type used for no match /// @return GridClass __hostdev__ inline GridClass toGridClass(GridBlindDataSemantic semantics, GridClass defaultClass = GridClass::Unknown) { switch (semantics){ case GridBlindDataSemantic::PointPosition: return GridClass::PointData; case GridBlindDataSemantic::PointColor: return GridClass::PointData; case GridBlindDataSemantic::PointNormal: return GridClass::PointData; case GridBlindDataSemantic::PointRadius: return GridClass::PointData; case GridBlindDataSemantic::PointVelocity: return GridClass::PointData; case GridBlindDataSemantic::PointId: return GridClass::PointIndex; case GridBlindDataSemantic::LevelSet: return GridClass::LevelSet; case GridBlindDataSemantic::FogVolume: return GridClass::FogVolume; case GridBlindDataSemantic::Staggered: return GridClass::Staggered; default: return defaultClass; } } /// @brief Maps from GridClass to GridBlindDataSemantic. /// @note Useful when converting a Grid into an IndexGrid with blind data of type T. /// @param gridClass GridClass /// @param defaultSemantic Default return type used for no match /// @return GridBlindDataSemantic __hostdev__ inline GridBlindDataSemantic toSemantic(GridClass gridClass, GridBlindDataSemantic defaultSemantic = GridBlindDataSemantic::Unknown) { switch (gridClass){ case GridClass::PointIndex: return GridBlindDataSemantic::PointId; case GridClass::LevelSet: return GridBlindDataSemantic::LevelSet; case GridClass::FogVolume: return GridBlindDataSemantic::FogVolume; case GridClass::Staggered: return GridBlindDataSemantic::Staggered; default: return defaultSemantic; } } // --------------------------> BuildTraits <------------------------------------ /// @brief Define static boolean tests for template build types template struct BuildTraits { // check if T is an index type static constexpr bool is_index = util::is_same::value; static constexpr bool is_onindex = util::is_same::value; static constexpr bool is_offindex = util::is_same::value; // check if T is a compressed float type with fixed bit precision static constexpr bool is_FpX = util::is_same::value; // check if T is a compressed float type with fixed or variable bit precision static constexpr bool is_Fp = util::is_same::value; // check if T is a POD float type, i.e float or double static constexpr bool is_float = util::is_floating_point::value; // check if T is a template specialization of LeafData, i.e. has T mValues[512] static constexpr bool is_special = is_index || is_Fp || util::is_same::value; }; // BuildTraits // --------------------------> BuildToValueMap <------------------------------------ /// @brief Maps one type (e.g. the build types above) to other (actual) types template struct BuildToValueMap { using Type = T; using type = T; }; template<> struct BuildToValueMap { using Type = uint64_t; using type = uint64_t; }; template<> struct BuildToValueMap { using Type = uint64_t; using type = uint64_t; }; template<> struct BuildToValueMap { using Type = bool; using type = bool; }; template<> struct BuildToValueMap { using Type = float; using type = float; }; template<> struct BuildToValueMap { using Type = float; using type = float; }; template<> struct BuildToValueMap { using Type = float; using type = float; }; template<> struct BuildToValueMap { using Type = float; using type = float; }; template<> struct BuildToValueMap { using Type = float; using type = float; }; template<> struct BuildToValueMap { using Type = uint64_t; using type = uint64_t; }; template using BuildToValueMapT = typename BuildToValueMap::type; // --------------------------> utility functions related to alignment <------------------------------------ /// @brief return true if the specified pointer is 32 byte aligned __hostdev__ inline static bool isAligned(const void* p){return uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;} /// @brief return the smallest number of bytes that when added to the specified pointer results in a 32 byte aligned pointer. __hostdev__ inline static uint64_t alignmentPadding(const void* p) { NANOVDB_ASSERT(p); return (NANOVDB_DATA_ALIGNMENT - (uint64_t(p) % NANOVDB_DATA_ALIGNMENT)) % NANOVDB_DATA_ALIGNMENT; } /// @brief offset the specified pointer so it is 32 byte aligned. Works with both const and non-const pointers. template __hostdev__ inline static T* alignPtr(T* p){return util::PtrAdd(p, alignmentPadding(p));} // --------------------------> isFloatingPoint(GridType) <------------------------------------ /// @brief return true if the GridType maps to a floating point type __hostdev__ inline bool isFloatingPoint(GridType gridType) { return gridType == GridType::Float || gridType == GridType::Double || gridType == GridType::Half || gridType == GridType::Fp4 || gridType == GridType::Fp8 || gridType == GridType::Fp16 || gridType == GridType::FpN; } // --------------------------> isFloatingPointVector(GridType) <------------------------------------ /// @brief return true if the GridType maps to a floating point vec3. __hostdev__ inline bool isFloatingPointVector(GridType gridType) { return gridType == GridType::Vec3f || gridType == GridType::Vec3d || gridType == GridType::Vec4f || gridType == GridType::Vec4d; } // --------------------------> isInteger(GridType) <------------------------------------ /// @brief Return true if the GridType maps to a POD integer type. /// @details These types are used to associate a voxel with a POD integer type __hostdev__ inline bool isInteger(GridType gridType) { return gridType == GridType::Int16 || gridType == GridType::Int32 || gridType == GridType::Int64 || gridType == GridType::UInt32|| gridType == GridType::UInt8; } // --------------------------> isIndex(GridType) <------------------------------------ /// @brief Return true if the GridType maps to a special index type (not a POD integer type). /// @details These types are used to index from a voxel into an external array of values, e.g. sidecar or blind data. __hostdev__ inline bool isIndex(GridType gridType) { return gridType == GridType::Index ||// index both active and inactive values gridType == GridType::OnIndex;// index active values only } // --------------------------> isValue(GridType, GridClass) <------------------------------------ /// @brief return true if the combination of GridType and GridClass is valid. __hostdev__ inline bool isValid(GridType gridType, GridClass gridClass) { if (gridClass == GridClass::LevelSet || gridClass == GridClass::FogVolume) { return isFloatingPoint(gridType); } else if (gridClass == GridClass::Staggered) { return isFloatingPointVector(gridType); } else if (gridClass == GridClass::PointIndex || gridClass == GridClass::PointData) { return gridType == GridType::PointIndex || gridType == GridType::UInt32; } else if (gridClass == GridClass::Topology) { return gridType == GridType::Mask; } else if (gridClass == GridClass::IndexGrid) { return isIndex(gridType); } else if (gridClass == GridClass::VoxelVolume) { return gridType == GridType::RGBA8 || gridType == GridType::Float || gridType == GridType::Double || gridType == GridType::Vec3f || gridType == GridType::Vec3d || gridType == GridType::UInt32 || gridType == GridType::UInt8; } return gridClass < GridClass::End && gridType < GridType::End; // any valid combination } // --------------------------> validation of blind data meta data <------------------------------------ /// @brief return true if the combination of GridBlindDataClass, GridBlindDataSemantic and GridType is valid. __hostdev__ inline bool isValid(const GridBlindDataClass& blindClass, const GridBlindDataSemantic& blindSemantics, const GridType& blindType) { bool test = false; switch (blindClass) { case GridBlindDataClass::IndexArray: test = (blindSemantics == GridBlindDataSemantic::Unknown || blindSemantics == GridBlindDataSemantic::PointId) && isInteger(blindType); break; case GridBlindDataClass::AttributeArray: if (blindSemantics == GridBlindDataSemantic::PointPosition || blindSemantics == GridBlindDataSemantic::WorldCoords) { test = blindType == GridType::Vec3f || blindType == GridType::Vec3d; } else if (blindSemantics == GridBlindDataSemantic::GridCoords) { test = blindType == GridType::Vec3f; } else if (blindSemantics == GridBlindDataSemantic::VoxelCoords) { test = blindType == GridType::Vec3f || blindType == GridType::Vec3u8 || blindType == GridType::Vec3u16; } else { test = blindSemantics != GridBlindDataSemantic::PointId; } break; case GridBlindDataClass::GridName: test = blindSemantics == GridBlindDataSemantic::Unknown && blindType == GridType::Unknown; break; default: // captures blindClass == Unknown and ChannelArray test = blindClass < GridBlindDataClass::End && blindSemantics < GridBlindDataSemantic::End && blindType < GridType::End; // any valid combination break; } //if (!test) printf("Invalid combination: GridBlindDataClass=%u, GridBlindDataSemantic=%u, GridType=%u\n",(uint32_t)blindClass, (uint32_t)blindSemantics, (uint32_t)blindType); return test; } // ----------------------------> Version class <------------------------------------- /// @brief Bit-compacted representation of all three version numbers /// /// @details major is the top 11 bits, minor is the 11 middle bits and patch is the lower 10 bits class Version { uint32_t mData; // 11 + 11 + 10 bit packing of major + minor + patch public: static constexpr uint32_t End = 0, StrLen = 8;// for strlen() /// @brief Default constructor __hostdev__ Version() : mData(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER) << 21 | uint32_t(NANOVDB_MINOR_VERSION_NUMBER) << 10 | uint32_t(NANOVDB_PATCH_VERSION_NUMBER)) { } /// @brief Constructor from a raw uint32_t data representation __hostdev__ Version(uint32_t data) : mData(data) {} /// @brief Constructor from major.minor.patch version numbers __hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch) : mData(major << 21 | minor << 10 | patch) { NANOVDB_ASSERT(major < (1u << 11)); // max value of major is 2047 NANOVDB_ASSERT(minor < (1u << 11)); // max value of minor is 2047 NANOVDB_ASSERT(patch < (1u << 10)); // max value of patch is 1023 } __hostdev__ bool operator==(const Version& rhs) const { return mData == rhs.mData; } __hostdev__ bool operator<( const Version& rhs) const { return mData < rhs.mData; } __hostdev__ bool operator<=(const Version& rhs) const { return mData <= rhs.mData; } __hostdev__ bool operator>( const Version& rhs) const { return mData > rhs.mData; } __hostdev__ bool operator>=(const Version& rhs) const { return mData >= rhs.mData; } __hostdev__ uint32_t id() const { return mData; } __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1); } __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1); } __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1); } __hostdev__ bool isCompatible() const { return this->getMajor() == uint32_t(NANOVDB_MAJOR_VERSION_NUMBER); } /// @brief Returns the difference between major version of this instance and NANOVDB_MAJOR_VERSION_NUMBER /// @return return 0 if the major version equals NANOVDB_MAJOR_VERSION_NUMBER, else a negative age if this /// instance has a smaller major verion (is older), and a positive age if it is newer, i.e. larger. __hostdev__ int age() const {return int(this->getMajor()) - int(NANOVDB_MAJOR_VERSION_NUMBER);} }; // Version /// @brief print the verion number to a c-string /// @param dst destination string of size 8 or more /// @param v version to be printed /// @return returns destination string @c dst __hostdev__ inline char* toStr(char *dst, const Version &v) { return util::sprint(dst, v.getMajor(), ".",v.getMinor(), ".",v.getPatch()); } // ----------------------------> TensorTraits <-------------------------------------- template::value || util::is_specialization::value || util::is_same::value) ? 1 : 0> struct TensorTraits; template struct TensorTraits { static const int Rank = 0; // i.e. scalar static const bool IsScalar = true; static const bool IsVector = false; static const int Size = 1; using ElementType = T; static T scalar(const T& s) { return s; } }; template struct TensorTraits { static const int Rank = 1; // i.e. vector static const bool IsScalar = false; static const bool IsVector = true; static const int Size = T::SIZE; using ElementType = typename T::ValueType; static ElementType scalar(const T& v) { return v.length(); } }; // ----------------------------> FloatTraits <-------------------------------------- template::ElementType)> struct FloatTraits { using FloatType = float; }; template struct FloatTraits { using FloatType = double; }; template<> struct FloatTraits { using FloatType = bool; }; template<> struct FloatTraits // size of empty class in C++ is 1 byte and not 0 byte { using FloatType = uint64_t; }; template<> struct FloatTraits // size of empty class in C++ is 1 byte and not 0 byte { using FloatType = uint64_t; }; template<> struct FloatTraits // size of empty class in C++ is 1 byte and not 0 byte { using FloatType = bool; }; template<> struct FloatTraits // size of empty class in C++ is 1 byte and not 0 byte { using FloatType = double; }; // ----------------------------> mapping BuildType -> GridType <-------------------------------------- /// @brief Maps from a templated build type to a GridType enum template __hostdev__ inline GridType toGridType() { if constexpr(util::is_same::value) { // resolved at compile-time return GridType::Float; } else if constexpr(util::is_same::value) { return GridType::Double; } else if constexpr(util::is_same::value) { return GridType::Int16; } else if constexpr(util::is_same::value) { return GridType::Int32; } else if constexpr(util::is_same::value) { return GridType::Int64; } else if constexpr(util::is_same::value) { return GridType::Vec3f; } else if constexpr(util::is_same::value) { return GridType::Vec3d; } else if constexpr(util::is_same::value) { return GridType::UInt32; } else if constexpr(util::is_same::value) { return GridType::Mask; } else if constexpr(util::is_same::value) { return GridType::Half; } else if constexpr(util::is_same::value) { return GridType::Index; } else if constexpr(util::is_same::value) { return GridType::OnIndex; } else if constexpr(util::is_same::value) { return GridType::Boolean; } else if constexpr(util::is_same::value) { return GridType::RGBA8; } else if constexpr(util::is_same::value) { return GridType::Fp4; } else if constexpr(util::is_same::value) { return GridType::Fp8; } else if constexpr(util::is_same::value) { return GridType::Fp16; } else if constexpr(util::is_same::value) { return GridType::FpN; } else if constexpr(util::is_same::value) { return GridType::Vec4f; } else if constexpr(util::is_same::value) { return GridType::Vec4d; } else if constexpr(util::is_same::value) { return GridType::PointIndex; } else if constexpr(util::is_same::value) { return GridType::Vec3u8; } else if constexpr(util::is_same::value) { return GridType::Vec3u16; } else if constexpr(util::is_same::value) { return GridType::UInt8; } return GridType::Unknown; }// toGridType template [[deprecated("Use toGridType() instead.")]] __hostdev__ inline GridType mapToGridType(){return toGridType();} // ----------------------------> mapping BuildType -> GridClass <-------------------------------------- /// @brief Maps from a templated build type to a GridClass enum template __hostdev__ inline GridClass toGridClass(GridClass defaultClass = GridClass::Unknown) { if constexpr(util::is_same::value) { return GridClass::Topology; } else if constexpr(BuildTraits::is_index) { return GridClass::IndexGrid; } else if constexpr(util::is_same::value) { return GridClass::VoxelVolume; } else if constexpr(util::is_same::value) { return GridClass::PointIndex; } return defaultClass; } template [[deprecated("Use toGridClass() instead.")]] __hostdev__ inline GridClass mapToGridClass(GridClass defaultClass = GridClass::Unknown) { return toGridClass(); } // ----------------------------> BitFlags <-------------------------------------- template struct BitArray; template<> struct BitArray<8> { uint8_t mFlags{0}; }; template<> struct BitArray<16> { uint16_t mFlags{0}; }; template<> struct BitArray<32> { uint32_t mFlags{0}; }; template<> struct BitArray<64> { uint64_t mFlags{0}; }; template class BitFlags : public BitArray { protected: using BitArray::mFlags; public: using Type = decltype(mFlags); BitFlags() {} BitFlags(Type mask) : BitArray{mask} {} BitFlags(std::initializer_list list) { for (auto bit : list) mFlags |= static_cast(1 << bit); } template BitFlags(std::initializer_list list) { for (auto mask : list) mFlags |= static_cast(mask); } __hostdev__ Type data() const { return mFlags; } __hostdev__ Type& data() { return mFlags; } __hostdev__ void initBit(std::initializer_list list) { mFlags = 0u; for (auto bit : list) mFlags |= static_cast(1 << bit); } template __hostdev__ void initMask(std::initializer_list list) { mFlags = 0u; for (auto mask : list) mFlags |= static_cast(mask); } __hostdev__ Type getFlags() const { return mFlags & (static_cast(GridFlags::End) - 1u); } // mask out everything except relevant bits __hostdev__ void setOn() { mFlags = ~Type(0u); } __hostdev__ void setOff() { mFlags = Type(0u); } __hostdev__ void setBitOn(uint8_t bit) { mFlags |= static_cast(1 << bit); } __hostdev__ void setBitOff(uint8_t bit) { mFlags &= ~static_cast(1 << bit); } __hostdev__ void setBitOn(std::initializer_list list) { for (auto bit : list) mFlags |= static_cast(1 << bit); } __hostdev__ void setBitOff(std::initializer_list list) { for (auto bit : list) mFlags &= ~static_cast(1 << bit); } template __hostdev__ void setMaskOn(MaskT mask) { mFlags |= static_cast(mask); } template __hostdev__ void setMaskOff(MaskT mask) { mFlags &= ~static_cast(mask); } template __hostdev__ void setMaskOn(std::initializer_list list) { for (auto mask : list) mFlags |= static_cast(mask); } template __hostdev__ void setMaskOff(std::initializer_list list) { for (auto mask : list) mFlags &= ~static_cast(mask); } __hostdev__ void setBit(uint8_t bit, bool on) { on ? this->setBitOn(bit) : this->setBitOff(bit); } template __hostdev__ void setMask(MaskT mask, bool on) { on ? this->setMaskOn(mask) : this->setMaskOff(mask); } __hostdev__ bool isOn() const { return mFlags == ~Type(0u); } __hostdev__ bool isOff() const { return mFlags == Type(0u); } __hostdev__ bool isBitOn(uint8_t bit) const { return 0 != (mFlags & static_cast(1 << bit)); } __hostdev__ bool isBitOff(uint8_t bit) const { return 0 == (mFlags & static_cast(1 << bit)); } template __hostdev__ bool isMaskOn(MaskT mask) const { return 0 != (mFlags & static_cast(mask)); } template __hostdev__ bool isMaskOff(MaskT mask) const { return 0 == (mFlags & static_cast(mask)); } /// @brief return true if any of the masks in the list are on template __hostdev__ bool isMaskOn(std::initializer_list list) const { for (auto mask : list) { if (0 != (mFlags & static_cast(mask))) return true; } return false; } /// @brief return true if any of the masks in the list are off template __hostdev__ bool isMaskOff(std::initializer_list list) const { for (auto mask : list) { if (0 == (mFlags & static_cast(mask))) return true; } return false; } /// @brief required for backwards compatibility __hostdev__ BitFlags& operator=(Type n) { mFlags = n; return *this; } }; // BitFlags // ----------------------------> Mask <-------------------------------------- /// @brief Bit-mask to encode active states and facilitate sequential iterators /// and a fast codec for I/O compression. template class Mask { public: static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words /// @brief Return the memory footprint in bytes of this Mask __hostdev__ static size_t memUsage() { return sizeof(Mask); } /// @brief Return the number of bits available in this Mask __hostdev__ static uint32_t bitCount() { return SIZE; } /// @brief Return the number of machine words used by this Mask __hostdev__ static uint32_t wordCount() { return WORD_COUNT; } /// @brief Return the total number of set bits in this Mask __hostdev__ uint32_t countOn() const { uint32_t sum = 0; for (const uint64_t *w = mWords, *q = w + WORD_COUNT; w != q; ++w) sum += util::countOn(*w); return sum; } /// @brief Return the number of lower set bits in mask up to but excluding the i'th bit inline __hostdev__ uint32_t countOn(uint32_t i) const { uint32_t n = i >> 6, sum = util::countOn(mWords[n] & ((uint64_t(1) << (i & 63u)) - 1u)); for (const uint64_t* w = mWords; n--; ++w) sum += util::countOn(*w); return sum; } template class Iterator { public: __hostdev__ Iterator() : mPos(Mask::SIZE) , mParent(nullptr) { } __hostdev__ Iterator(uint32_t pos, const Mask* parent) : mPos(pos) , mParent(parent) { } Iterator& operator=(const Iterator&) = default; __hostdev__ uint32_t operator*() const { return mPos; } __hostdev__ uint32_t pos() const { return mPos; } __hostdev__ operator bool() const { return mPos != Mask::SIZE; } __hostdev__ Iterator& operator++() { mPos = mParent->findNext(mPos + 1); return *this; } __hostdev__ Iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; } private: uint32_t mPos; const Mask* mParent; }; // Member class Iterator class DenseIterator { public: __hostdev__ DenseIterator(uint32_t pos = Mask::SIZE) : mPos(pos) { } DenseIterator& operator=(const DenseIterator&) = default; __hostdev__ uint32_t operator*() const { return mPos; } __hostdev__ uint32_t pos() const { return mPos; } __hostdev__ operator bool() const { return mPos != Mask::SIZE; } __hostdev__ DenseIterator& operator++() { ++mPos; return *this; } __hostdev__ DenseIterator operator++(int) { auto tmp = *this; ++mPos; return tmp; } private: uint32_t mPos; }; // Member class DenseIterator using OnIterator = Iterator; using OffIterator = Iterator; __hostdev__ OnIterator beginOn() const { return OnIterator(this->findFirst(), this); } __hostdev__ OffIterator beginOff() const { return OffIterator(this->findFirst(), this); } __hostdev__ DenseIterator beginAll() const { return DenseIterator(0); } /// @brief Initialize all bits to zero. __hostdev__ Mask() { for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = 0; } __hostdev__ Mask(bool on) { const uint64_t v = on ? ~uint64_t(0) : uint64_t(0); for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = v; } /// @brief Copy constructor __hostdev__ Mask(const Mask& other) { for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = other.mWords[i]; } /// @brief Return a pointer to the list of words of the bit mask __hostdev__ uint64_t* words() { return mWords; } __hostdev__ const uint64_t* words() const { return mWords; } template __hostdev__ WordT getWord(uint32_t n) const { static_assert(util::is_same::value); NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT); return reinterpret_cast(mWords)[n]; } template __hostdev__ void setWord(WordT w, uint32_t n) { static_assert(util::is_same::value); NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT); reinterpret_cast(mWords)[n] = w; } /// @brief Assignment operator that works with openvdb::util::NodeMask template __hostdev__ typename util::enable_if::value, Mask&>::type operator=(const MaskT& other) { static_assert(sizeof(Mask) == sizeof(MaskT), "Mismatching sizeof"); static_assert(WORD_COUNT == MaskT::WORD_COUNT, "Mismatching word count"); static_assert(LOG2DIM == MaskT::LOG2DIM, "Mismatching LOG2DIM"); auto* src = reinterpret_cast(&other); for (uint64_t *dst = mWords, *end = dst + WORD_COUNT; dst != end; ++dst) *dst = *src++; return *this; } //__hostdev__ Mask& operator=(const Mask& other){return *util::memcpy(this, &other);} Mask& operator=(const Mask&) = default; __hostdev__ bool operator==(const Mask& other) const { for (uint32_t i = 0; i < WORD_COUNT; ++i) { if (mWords[i] != other.mWords[i]) return false; } return true; } __hostdev__ bool operator!=(const Mask& other) const { return !((*this) == other); } /// @brief Return true if the given bit is set. __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } /// @brief Return true if the given bit is NOT set. __hostdev__ bool isOff(uint32_t n) const { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } /// @brief Return true if all the bits are set in this Mask. __hostdev__ bool isOn() const { for (uint32_t i = 0; i < WORD_COUNT; ++i) if (mWords[i] != ~uint64_t(0)) return false; return true; } /// @brief Return true if none of the bits are set in this Mask. __hostdev__ bool isOff() const { for (uint32_t i = 0; i < WORD_COUNT; ++i) if (mWords[i] != uint64_t(0)) return false; return true; } /// @brief Set the specified bit on. __hostdev__ void setOn(uint32_t n) { mWords[n >> 6] |= uint64_t(1) << (n & 63); } /// @brief Set the specified bit off. __hostdev__ void setOff(uint32_t n) { mWords[n >> 6] &= ~(uint64_t(1) << (n & 63)); } #if defined(__CUDACC__) // the following functions only run on the GPU! __device__ inline void setOnAtomic(uint32_t n) { atomicOr(reinterpret_cast(this) + (n >> 6), 1ull << (n & 63)); } __device__ inline void setOffAtomic(uint32_t n) { atomicAnd(reinterpret_cast(this) + (n >> 6), ~(1ull << (n & 63))); } __device__ inline void setAtomic(uint32_t n, bool on) { on ? this->setOnAtomic(n) : this->setOffAtomic(n); } /* template __device__ inline void setWordAtomic(WordT w, uint32_t n) { static_assert(util::is_same::value); NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT); if constexpr(util::is_same::value) { mask <<= x; } else if constexpr(util::is_same::value) { unsigned int mask = w; if (n >> 1) mask <<= 16; atomicOr(reinterpret_cast(this) + n, mask); } else if constexpr(util::is_same::value) { atomicOr(reinterpret_cast(this) + n, w); } else { atomicOr(reinterpret_cast(this) + n, w); } } */ #endif /// @brief Set the specified bit on or off. __hostdev__ void set(uint32_t n, bool on) { #if 1 // switch between branchless auto& word = mWords[n >> 6]; n &= 63; word &= ~(uint64_t(1) << n); word |= uint64_t(on) << n; #else on ? this->setOn(n) : this->setOff(n); #endif } /// @brief Set all bits on __hostdev__ void setOn() { for (uint32_t i = 0; i < WORD_COUNT; ++i)mWords[i] = ~uint64_t(0); } /// @brief Set all bits off __hostdev__ void setOff() { for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = uint64_t(0); } /// @brief Set all bits off __hostdev__ void set(bool on) { const uint64_t v = on ? ~uint64_t(0) : uint64_t(0); for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = v; } /// brief Toggle the state of all bits in the mask __hostdev__ void toggle() { uint32_t n = WORD_COUNT; for (auto* w = mWords; n--; ++w) *w = ~*w; } __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); } /// @brief Bitwise intersection __hostdev__ Mask& operator&=(const Mask& other) { uint64_t* w1 = mWords; const uint64_t* w2 = other.mWords; for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= *w2; return *this; } /// @brief Bitwise union __hostdev__ Mask& operator|=(const Mask& other) { uint64_t* w1 = mWords; const uint64_t* w2 = other.mWords; for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 |= *w2; return *this; } /// @brief Bitwise difference __hostdev__ Mask& operator-=(const Mask& other) { uint64_t* w1 = mWords; const uint64_t* w2 = other.mWords; for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= ~*w2; return *this; } /// @brief Bitwise XOR __hostdev__ Mask& operator^=(const Mask& other) { uint64_t* w1 = mWords; const uint64_t* w2 = other.mWords; for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 ^= *w2; return *this; } NANOVDB_HOSTDEV_DISABLE_WARNING template __hostdev__ uint32_t findFirst() const { uint32_t n = 0u; const uint64_t* w = mWords; for (; n < WORD_COUNT && !(ON ? *w : ~*w); ++w, ++n); return n < WORD_COUNT ? (n << 6) + util::findLowestOn(ON ? *w : ~*w) : SIZE; } NANOVDB_HOSTDEV_DISABLE_WARNING template __hostdev__ uint32_t findNext(uint32_t start) const { uint32_t n = start >> 6; // initiate if (n >= WORD_COUNT) return SIZE; // check for out of bounds uint32_t m = start & 63u; uint64_t b = ON ? mWords[n] : ~mWords[n]; if (b & (uint64_t(1u) << m)) return start; // simple case: start is on/off b &= ~uint64_t(0u) << m; // mask out lower bits while (!b && ++n < WORD_COUNT) b = ON ? mWords[n] : ~mWords[n]; // find next non-zero word return b ? (n << 6) + util::findLowestOn(b) : SIZE; // catch last word=0 } NANOVDB_HOSTDEV_DISABLE_WARNING template __hostdev__ uint32_t findPrev(uint32_t start) const { uint32_t n = start >> 6; // initiate if (n >= WORD_COUNT) return SIZE; // check for out of bounds uint32_t m = start & 63u; uint64_t b = ON ? mWords[n] : ~mWords[n]; if (b & (uint64_t(1u) << m)) return start; // simple case: start is on/off b &= (uint64_t(1u) << m) - 1u; // mask out higher bits while (!b && n) b = ON ? mWords[--n] : ~mWords[--n]; // find previous non-zero word return b ? (n << 6) + util::findHighestOn(b) : SIZE; // catch first word=0 } private: uint64_t mWords[WORD_COUNT]; }; // Mask class // ----------------------------> Map <-------------------------------------- /// @brief Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation struct Map { // 264B (not 32B aligned!) float mMatF[9]; // 9*4B <- 3x3 matrix float mInvMatF[9]; // 9*4B <- 3x3 matrix float mVecF[3]; // 3*4B <- translation float mTaperF; // 4B, placeholder for taper value double mMatD[9]; // 9*8B <- 3x3 matrix double mInvMatD[9]; // 9*8B <- 3x3 matrix double mVecD[3]; // 3*8B <- translation double mTaperD; // 8B, placeholder for taper value /// @brief Default constructor for the identity map __hostdev__ Map() : mMatF{ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f} , mInvMatF{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f} , mVecF{0.0f, 0.0f, 0.0f} , mTaperF{1.0f} , mMatD{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0} , mInvMatD{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0} , mVecD{0.0, 0.0, 0.0} , mTaperD{1.0} { } __hostdev__ Map(double s, const Vec3d& t = Vec3d(0.0, 0.0, 0.0)) : mMatF{float(s), 0.0f, 0.0f, 0.0f, float(s), 0.0f, 0.0f, 0.0f, float(s)} , mInvMatF{1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s)} , mVecF{float(t[0]), float(t[1]), float(t[2])} , mTaperF{1.0f} , mMatD{s, 0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, s} , mInvMatD{1.0 / s, 0.0, 0.0, 0.0, 1.0 / s, 0.0, 0.0, 0.0, 1.0 / s} , mVecD{t[0], t[1], t[2]} , mTaperD{1.0} { } /// @brief Initialize the member data from 3x3 or 4x4 matrices /// @note This is not _hostdev__ since then MatT=openvdb::Mat4d will produce warnings template void set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper = 1.0); /// @brief Initialize the member data from 4x4 matrices /// @note The last (4th) row of invMat is actually ignored. /// This is not _hostdev__ since then Mat4T=openvdb::Mat4d will produce warnings template void set(const Mat4T& mat, const Mat4T& invMat, double taper = 1.0) { this->set(mat, invMat, mat[3], taper); } template void set(double scale, const Vec3T& translation, double taper = 1.0); /// @brief Apply the forward affine transformation to a vector using 64bit floating point arithmetics. /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation template __hostdev__ Vec3T applyMap(const Vec3T& ijk) const { return math::matMult(mMatD, mVecD, ijk); } /// @brief Apply the forward affine transformation to a vector using 32bit floating point arithmetics. /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation template __hostdev__ Vec3T applyMapF(const Vec3T& ijk) const { return math::matMult(mMatF, mVecF, ijk); } /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 64bit floating point arithmetics, /// e.g. scale and rotation WITHOUT translation. /// @note Typically this operation is used for scale and rotation from index -> world mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return linear forward 3x3 mapping of the input vector template __hostdev__ Vec3T applyJacobian(const Vec3T& ijk) const { return math::matMult(mMatD, ijk); } /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 32bit floating point arithmetics, /// e.g. scale and rotation WITHOUT translation. /// @note Typically this operation is used for scale and rotation from index -> world mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return linear forward 3x3 mapping of the input vector template __hostdev__ Vec3T applyJacobianF(const Vec3T& ijk) const { return math::matMult(mMatF, ijk); } /// @brief Apply the inverse affine mapping to a vector using 64bit floating point arithmetics. /// @note Typically this operation is used for the world -> index mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param xyz 3D vector to be mapped - typically floating point world coordinates /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1 template __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return math::matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2])); } /// @brief Apply the inverse affine mapping to a vector using 32bit floating point arithmetics. /// @note Typically this operation is used for the world -> index mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param xyz 3D vector to be mapped - typically floating point world coordinates /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1 template __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return math::matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2])); } /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics, /// e.g. inverse scale and inverse rotation WITHOUT translation. /// @note Typically this operation is used for scale and rotation from world -> index mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1 template __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return math::matMult(mInvMatD, xyz); } /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 32bit floating point arithmetics, /// e.g. inverse scale and inverse rotation WITHOUT translation. /// @note Typically this operation is used for scale and rotation from world -> index mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1 template __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return math::matMult(mInvMatF, xyz); } /// @brief Apply the transposed inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics, /// e.g. inverse scale and inverse rotation WITHOUT translation. /// @note Typically this operation is used for scale and rotation from world -> index mapping /// @tparam Vec3T Template type of the 3D vector to be mapped /// @param ijk 3D vector to be mapped - typically floating point index coordinates /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1 template __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return math::matMultT(mInvMatD, xyz); } template __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return math::matMultT(mInvMatF, xyz); } /// @brief Return a voxels size in each coordinate direction, measured at the origin __hostdev__ Vec3d getVoxelSize() const { return this->applyMap(Vec3d(1)) - this->applyMap(Vec3d(0)); } }; // Map template inline void Map::set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper) { float * mf = mMatF, *vf = mVecF, *mif = mInvMatF; double *md = mMatD, *vd = mVecD, *mid = mInvMatD; mTaperF = static_cast(taper); mTaperD = taper; for (int i = 0; i < 3; ++i) { *vd++ = translate[i]; //translation *vf++ = static_cast(translate[i]); //translation for (int j = 0; j < 3; ++j) { *md++ = mat[j][i]; //transposed *mid++ = invMat[j][i]; *mf++ = static_cast(mat[j][i]); //transposed *mif++ = static_cast(invMat[j][i]); } } } template inline void Map::set(double dx, const Vec3T& trans, double taper) { NANOVDB_ASSERT(dx > 0.0); const double mat[3][3] = { {dx, 0.0, 0.0}, // row 0 {0.0, dx, 0.0}, // row 1 {0.0, 0.0, dx} }; // row 2 const double idx = 1.0 / dx; const double invMat[3][3] = { {idx, 0.0, 0.0}, // row 0 {0.0, idx, 0.0}, // row 1 {0.0, 0.0, idx} }; // row 2 this->set(mat, invMat, trans, taper); } // ----------------------------> GridBlindMetaData <-------------------------------------- struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData { // 288 bytes static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less! int64_t mDataOffset; // byte offset to the blind data, relative to GridBlindMetaData::this. uint64_t mValueCount; // number of blind values, e.g. point count uint32_t mValueSize;// byte size of each value, e.g. 4 if mDataType=Float and 1 if mDataType=Unknown since that amounts to char GridBlindDataSemantic mSemantic; // semantic meaning of the data. GridBlindDataClass mDataClass; // 4 bytes GridType mDataType; // 4 bytes char mName[MaxNameSize]; // note this includes the NULL termination // no padding required for 32 byte alignment /// @brief Empty constructor GridBlindMetaData() : mDataOffset(0) , mValueCount(0) , mValueSize(0) , mSemantic(GridBlindDataSemantic::Unknown) , mDataClass(GridBlindDataClass::Unknown) , mDataType(GridType::Unknown) { util::memzero(mName, MaxNameSize); } GridBlindMetaData(int64_t dataOffset, uint64_t valueCount, uint32_t valueSize, GridBlindDataSemantic semantic, GridBlindDataClass dataClass, GridType dataType) : mDataOffset(dataOffset) , mValueCount(valueCount) , mValueSize(valueSize) , mSemantic(semantic) , mDataClass(dataClass) , mDataType(dataType) { util::memzero(mName, MaxNameSize); } /// @brief Copy constructor that resets mDataOffset and zeros out mName GridBlindMetaData(const GridBlindMetaData &other) : mDataOffset(util::PtrDiff(util::PtrAdd(&other, other.mDataOffset), this)) , mValueCount(other.mValueCount) , mValueSize(other.mValueSize) , mSemantic(other.mSemantic) , mDataClass(other.mDataClass) , mDataType(other.mDataType) { util::strncpy(mName, other.mName, MaxNameSize); } /// @brief Copy assignment operator that resets mDataOffset and copies mName /// @param rhs right-hand instance to copy /// @return reference to itself const GridBlindMetaData& operator=(const GridBlindMetaData& rhs) { mDataOffset = util::PtrDiff(util::PtrAdd(&rhs, rhs.mDataOffset), this); mValueCount = rhs.mValueCount; mValueSize = rhs. mValueSize; mSemantic = rhs.mSemantic; mDataClass = rhs.mDataClass; mDataType = rhs.mDataType; util::strncpy(mName, rhs.mName, MaxNameSize); return *this; } __hostdev__ void setBlindData(const void* blindData) { mDataOffset = util::PtrDiff(blindData, this); } /// @brief Sets the name string /// @param name c-string source name /// @return returns false if @c name has too many characters __hostdev__ bool setName(const char* name){return util::strncpy(mName, name, MaxNameSize)[MaxNameSize-1] == '\0';} /// @brief returns a const void point to the blind data /// @note assumes that setBlinddData was called __hostdev__ const void* blindData() const { NANOVDB_ASSERT(mDataOffset != 0); return util::PtrAdd(this, mDataOffset); } /// @brief Get a const pointer to the blind data represented by this meta data /// @tparam BlindDataT Expected value type of the blind data. /// @return Returns NULL if mGridType!=toGridType(), else a const point of type BlindDataT. /// @note Use mDataType=Unknown if BlindDataT is a custom data type unknown to NanoVDB. template __hostdev__ const BlindDataT* getBlindData() const { return mDataOffset && (mDataType == toGridType()) ? util::PtrAdd(this, mDataOffset) : nullptr; } /// @brief return true if this meta data has a valid combination of semantic, class and value tags. /// @note this does not check if the mDataOffset has been set! It is intended to catch invalid combinations /// of semantic, class and value tags. __hostdev__ bool isValid() const { auto check = [&]()->bool{ switch (mDataType){ //case GridType::Unknown: return mValueSize==1u;// i.e. we encode data as mValueCount chars case GridType::Float: return mValueSize==4u; case GridType::Double: return mValueSize==8u; case GridType::Int16: return mValueSize==2u; case GridType::Int32: return mValueSize==4u; case GridType::Int64: return mValueSize==8u; case GridType::Vec3f: return mValueSize==12u; case GridType::Vec3d: return mValueSize==24u; case GridType::Half: return mValueSize==2u; case GridType::RGBA8: return mValueSize==4u; case GridType::Fp8: return mValueSize==1u; case GridType::Fp16: return mValueSize==2u; case GridType::Vec4f: return mValueSize==16u; case GridType::Vec4d: return mValueSize==32u; case GridType::Vec3u8: return mValueSize==3u; case GridType::Vec3u16: return mValueSize==6u; default: return true;}// all other combinations are valid }; //if (!check()) { // char str[20]; // printf("Inconsistent blind data properties: size=%u, GridType=\"%s\"\n",(uint32_t)mValueSize, toStr(str, mDataType) ); //} return nanovdb::isValid(mDataClass, mSemantic, mDataType) && check(); } /// @brief return size in bytes of the blind data represented by this blind meta data /// @note This size includes possible padding for 32 byte alignment. The actual amount /// of bind data is mValueCount * mValueSize __hostdev__ uint64_t blindDataSize() const { return math::AlignUp(mValueCount * mValueSize); } }; // GridBlindMetaData // ----------------------------> NodeTrait <-------------------------------------- /// @brief Struct to derive node type from its level in a given /// grid, tree or root while preserving constness template struct NodeTrait; // Partial template specialization of above Node struct template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = typename GridOrTreeOrRootT::LeafNodeType; using type = typename GridOrTreeOrRootT::LeafNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = const typename GridOrTreeOrRootT::LeafNodeType; using type = const typename GridOrTreeOrRootT::LeafNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType; using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType; using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType; using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType; using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = typename GridOrTreeOrRootT::RootNodeType; using type = typename GridOrTreeOrRootT::RootNodeType; }; template struct NodeTrait { static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported"); using Type = const typename GridOrTreeOrRootT::RootNodeType; using type = const typename GridOrTreeOrRootT::RootNodeType; }; template using NodeTraitT = typename NodeTrait::type; // ------------> Froward decelerations of accelerated random access methods <--------------- template struct GetValue; template struct SetValue; template struct SetVoxel; template struct GetState; template struct GetDim; template struct GetLeaf; template struct ProbeValue; template struct GetNodeInfo; // ----------------------------> CheckMode <---------------------------------- /// @brief List of different modes for computing for a checksum enum class CheckMode : uint32_t { Disable = 0, // no computation Empty = 0, Half = 1, Partial = 1, // fast but approximate Default = 1, // defaults to Partial Full = 2, // slow but accurate End = 3, // marks the end of the enum list StrLen = 9 + End}; /// @brief Prints CheckMode enum to a c-string /// @param dst Destination c-string /// @param mode CheckMode enum to be converted to string /// @return destinations string @c dst __hostdev__ inline char* toStr(char *dst, CheckMode mode) { switch (mode){ case CheckMode::Half: return util::strcpy(dst, "half"); case CheckMode::Full: return util::strcpy(dst, "full"); default: return util::strcpy(dst, "disabled");// StrLen = 8 + 1 + End } } // ----------------------------> Checksum <---------------------------------- /// @brief Class that encapsulates two CRC32 checksums, one for the Grid, Tree and Root node meta data /// and one for the remaining grid nodes. class Checksum { /// Three types of checksums: /// 1) Empty: all 64 bits are on (used to signify a disabled or undefined checksum) /// 2) Half: Upper 32 bits are on and not all of lower 32 bits are on (lower 32 bits checksum head of grid) /// 3) Full: Not all of the 64 bits are one (lower 32 bits checksum head of grid and upper 32 bits checksum tail of grid) union { uint32_t mCRC32[2]; uint64_t mCRC64; };// mCRC32[0] is checksum of Grid, Tree and Root, and mCRC32[1] is checksum of nodes public: static constexpr uint32_t EMPTY32 = ~uint32_t{0}; static constexpr uint64_t EMPTY64 = ~uint64_t(0); /// @brief default constructor initiates checksum to EMPTY __hostdev__ Checksum() : mCRC64{EMPTY64} {} /// @brief Constructor that allows the two 32bit checksums to be initiated explicitly /// @param head Initial 32bit CRC checksum of grid, tree and root data /// @param tail Initial 32bit CRC checksum of all the nodes and blind data __hostdev__ Checksum(uint32_t head, uint32_t tail) : mCRC32{head, tail} {} /// @brief /// @param checksum /// @param mode __hostdev__ Checksum(uint64_t checksum, CheckMode mode = CheckMode::Full) : mCRC64{mode == CheckMode::Disable ? EMPTY64 : checksum} { if (mode == CheckMode::Partial) mCRC32[1] = EMPTY32; } /// @brief return the 64 bit checksum of this instance [[deprecated("Use Checksum::data instead.")]] __hostdev__ uint64_t checksum() const { return mCRC64; } [[deprecated("Use Checksum::head and Ckecksum::tail instead.")]] __hostdev__ uint32_t& checksum(int i) {NANOVDB_ASSERT(i==0 || i==1); return mCRC32[i]; } [[deprecated("Use Checksum::head and Ckecksum::tail instead.")]] __hostdev__ uint32_t checksum(int i) const {NANOVDB_ASSERT(i==0 || i==1); return mCRC32[i]; } __hostdev__ uint64_t full() const { return mCRC64; } __hostdev__ uint64_t& full() { return mCRC64; } __hostdev__ uint32_t head() const { return mCRC32[0]; } __hostdev__ uint32_t& head() { return mCRC32[0]; } __hostdev__ uint32_t tail() const { return mCRC32[1]; } __hostdev__ uint32_t& tail() { return mCRC32[1]; } /// @brief return true if the 64 bit checksum is partial, i.e. of head only [[deprecated("Use Checksum::isHalf instead.")]] __hostdev__ bool isPartial() const { return mCRC32[0] != EMPTY32 && mCRC32[1] == EMPTY32; } __hostdev__ bool isHalf() const { return mCRC32[0] != EMPTY32 && mCRC32[1] == EMPTY32; } /// @brief return true if the 64 bit checksum is fill, i.e. of both had and nodes __hostdev__ bool isFull() const { return mCRC64 != EMPTY64 && mCRC32[1] != EMPTY32; } /// @brief return true if the 64 bit checksum is disables (unset) __hostdev__ bool isEmpty() const { return mCRC64 == EMPTY64; } __hostdev__ void disable() { mCRC64 = EMPTY64; } /// @brief return the mode of the 64 bit checksum __hostdev__ CheckMode mode() const { return mCRC64 == EMPTY64 ? CheckMode::Disable : mCRC32[1] == EMPTY32 ? CheckMode::Partial : CheckMode::Full; } /// @brief return true if the checksums are identical /// @param rhs other Checksum __hostdev__ bool operator==(const Checksum &rhs) const {return mCRC64 == rhs.mCRC64;} /// @brief return true if the checksums are not identical /// @param rhs other Checksum __hostdev__ bool operator!=(const Checksum &rhs) const {return mCRC64 != rhs.mCRC64;} };// Checksum /// @brief Maps 64 bit checksum to CheckMode enum /// @param checksum 64 bit checksum with two CRC32 codes /// @return CheckMode enum __hostdev__ inline CheckMode toCheckMode(const Checksum &checksum){return checksum.mode();} // ----------------------------> Grid <-------------------------------------- /* The following class and comment is for internal use only Memory layout: Grid -> 39 x double (world bbox and affine transformation) Tree -> Root 3 x ValueType + int32_t + N x Tiles (background,min,max,tileCount + tileCount x Tiles) N2 upper InternalNodes each with 2 bit masks, N2 tiles, and min/max values N1 lower InternalNodes each with 2 bit masks, N1 tiles, and min/max values N0 LeafNodes each with a bit mask, N0 ValueTypes and min/max Example layout: ("---" implies it has a custom offset, "..." implies zero or more) [GridData][TreeData]---[RootData][ROOT TILES...]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc. */ /// @brief Struct with all the member data of the Grid (useful during serialization of an openvdb grid) /// /// @note The transform is assumed to be affine (so linear) and have uniform scale! So frustum transforms /// and non-uniform scaling are not supported (primarily because they complicate ray-tracing in index space) /// /// @note No client code should (or can) interface with this struct so it can safely be ignored! struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData { // sizeof(GridData) = 672B static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less uint64_t mMagic; // 8B (0) magic to validate it is valid grid data. Checksum mChecksum; // 8B (8). Checksum of grid buffer. Version mVersion; // 4B (16) major, minor, and patch version numbers BitFlags<32> mFlags; // 4B (20). flags for grid. uint32_t mGridIndex; // 4B (24). Index of this grid in the buffer uint32_t mGridCount; // 4B (28). Total number of grids in the buffer uint64_t mGridSize; // 8B (32). byte count of this entire grid occupied in the buffer. char mGridName[MaxNameSize]; // 256B (40) Map mMap; // 264B (296). affine transformation between index and world space in both single and double precision Vec3dBBox mWorldBBox; // 48B (560). floating-point AABB of active values in WORLD SPACE (2 x 3 doubles) Vec3d mVoxelSize; // 24B (608). size of a voxel in world units GridClass mGridClass; // 4B (632). GridType mGridType; // 4B (636). int64_t mBlindMetadataOffset; // 8B (640). offset to beginning of GridBlindMetaData structures that follow this grid. uint32_t mBlindMetadataCount; // 4B (648). count of GridBlindMetaData structures that follow this grid. uint32_t mData0; // 4B (652) unused uint64_t mData1; // 8B (656) is use for the total number of values indexed by an IndexGrid uint64_t mData2; // 8B (664) padding to 32 B alignment /// @brief Use this method to initiate most member data GridData& operator=(const GridData&) = default; //__hostdev__ GridData& operator=(const GridData& other){return *util::memcpy(this, &other);} __hostdev__ void init(std::initializer_list list = {GridFlags::IsBreadthFirst}, uint64_t gridSize = 0u, const Map& map = Map(), GridType gridType = GridType::Unknown, GridClass gridClass = GridClass::Unknown) { #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS mMagic = NANOVDB_MAGIC_GRID; #else mMagic = NANOVDB_MAGIC_NUMB; #endif mChecksum.disable();// all 64 bits ON means checksum is disabled mVersion = Version(); mFlags.initMask(list); mGridIndex = 0u; mGridCount = 1u; mGridSize = gridSize; mGridName[0] = '\0'; mMap = map; mWorldBBox = Vec3dBBox();// invalid bbox mVoxelSize = map.getVoxelSize(); mGridClass = gridClass; mGridType = gridType; mBlindMetadataOffset = mGridSize; // i.e. no blind data mBlindMetadataCount = 0u; // i.e. no blind data mData0 = 0u; // zero padding mData1 = 0u; // only used for index and point grids #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS mData2 = 0u;// unused #else mData2 = NANOVDB_MAGIC_GRID; // since version 32.6.0 (will change in the future) #endif } /// @brief return true if the magic number and the version are both valid __hostdev__ bool isValid() const { // Before v32.6.0: toMagic(mMagic) = MagicType::NanoVDB and mData2 was undefined // For v32.6.0: toMagic(mMagic) = MagicType::NanoVDB and toMagic(mData2) = MagicType::NanoGrid // After v32.7.X: toMagic(mMagic) = MagicType::NanoGrid and mData2 will again be undefined const MagicType magic = toMagic(mMagic); if (magic == MagicType::NanoGrid || toMagic(mData2) == MagicType::NanoGrid) return true; bool test = magic == MagicType::NanoVDB;// could be GridData or io::FileHeader if (test) test = mVersion.isCompatible(); if (test) test = mGridCount > 0u && mGridIndex < mGridCount; if (test) test = mGridClass < GridClass::End && mGridType < GridType::End; return test; } // Set and unset various bit flags __hostdev__ void setMinMaxOn(bool on = true) { mFlags.setMask(GridFlags::HasMinMax, on); } __hostdev__ void setBBoxOn(bool on = true) { mFlags.setMask(GridFlags::HasBBox, on); } __hostdev__ void setLongGridNameOn(bool on = true) { mFlags.setMask(GridFlags::HasLongGridName, on); } __hostdev__ void setAverageOn(bool on = true) { mFlags.setMask(GridFlags::HasAverage, on); } __hostdev__ void setStdDeviationOn(bool on = true) { mFlags.setMask(GridFlags::HasStdDeviation, on); } __hostdev__ bool setGridName(const char* src) { const bool success = (util::strncpy(mGridName, src, MaxNameSize)[MaxNameSize-1] == '\0'); if (!success) mGridName[MaxNameSize-1] = '\0'; return success; // returns true if input grid name is NOT longer than MaxNameSize characters } // Affine transformations based on double precision template __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world template __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index template __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world template __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index template __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); } // Affine transformations based on single precision template __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world template __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index template __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world template __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index template __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); } // @brief Return a non-const void pointer to the tree __hostdev__ void* treePtr() { return this + 1; }// TreeData is always right after GridData // @brief Return a const void pointer to the tree __hostdev__ const void* treePtr() const { return this + 1; }// TreeData is always right after GridData /// @brief Return a non-const void pointer to the first node at @c LEVEL /// @tparam LEVEL Level of the node. LEVEL 0 means leaf node and LEVEL 3 means root node template __hostdev__ const void* nodePtr() const { static_assert(LEVEL >= 0 && LEVEL <= 3, "invalid LEVEL template parameter"); const void *treeData = this + 1;// TreeData is always right after GridData const uint64_t nodeOffset = *util::PtrAdd(treeData, 8*LEVEL);// skip LEVEL uint64_t return nodeOffset ? util::PtrAdd(treeData, nodeOffset) : nullptr; } /// @brief Return a non-const void pointer to the first node at @c LEVEL /// @tparam LEVEL of the node. LEVEL 0 means leaf node and LEVEL 3 means root node /// @warning If not nodes exist at @c LEVEL NULL is returned template __hostdev__ void* nodePtr() { static_assert(LEVEL >= 0 && LEVEL <= 3, "invalid LEVEL template parameter"); void *treeData = this + 1;// TreeData is always right after GridData const uint64_t nodeOffset = *util::PtrAdd(treeData, 8*LEVEL);// skip LEVEL uint64_t return nodeOffset ? util::PtrAdd(treeData, nodeOffset) : nullptr; } /// @brief Return number of nodes at @c LEVEL /// @tparam Level of the node. LEVEL 0 means leaf node and LEVEL 2 means upper node template __hostdev__ uint32_t nodeCount() const { static_assert(LEVEL >= 0 && LEVEL < 3, "invalid LEVEL template parameter"); return *util::PtrAdd(this + 1, 4*(8 + LEVEL));// TreeData is always right after GridData } /// @brief Returns a const reference to the blindMetaData at the specified linear offset. /// /// @warning The linear offset is assumed to be in the valid range __hostdev__ const GridBlindMetaData* blindMetaData(uint32_t n) const { NANOVDB_ASSERT(n < mBlindMetadataCount); return util::PtrAdd(this, mBlindMetadataOffset) + n; } __hostdev__ const char* gridName() const { if (mFlags.isMaskOn(GridFlags::HasLongGridName)) {// search for first blind meta data that contains a name NANOVDB_ASSERT(mBlindMetadataCount > 0); for (uint32_t i = 0; i < mBlindMetadataCount; ++i) { const auto* metaData = this->blindMetaData(i);// EXTREMELY important to be a pointer if (metaData->mDataClass == GridBlindDataClass::GridName) { NANOVDB_ASSERT(metaData->mDataType == GridType::Unknown); return metaData->template getBlindData(); } } NANOVDB_ASSERT(false); // should never hit this! } return mGridName; } /// @brief Return memory usage in bytes for this class only. __hostdev__ static uint64_t memUsage() { return sizeof(GridData); } /// @brief return AABB of active values in world space __hostdev__ const Vec3dBBox& worldBBox() const { return mWorldBBox; } /// @brief return AABB of active values in index space __hostdev__ const CoordBBox& indexBBox() const {return *(const CoordBBox*)(this->nodePtr<3>());} /// @brief return the root table has size __hostdev__ uint32_t rootTableSize() const { const void *root = this->nodePtr<3>(); return root ? *util::PtrAdd(root, sizeof(CoordBBox)) : 0u; } /// @brief test if the grid is empty, e.i the root table has size 0 /// @return true if this grid contains not data whatsoever __hostdev__ bool isEmpty() const {return this->rootTableSize() == 0u;} /// @brief return true if RootData follows TreeData in memory without any extra padding /// @details TreeData is always following right after GridData, but the same might not be true for RootData __hostdev__ bool isRootConnected() const { return *(const uint64_t*)((const char*)(this + 1) + 24) == 64u;} }; // GridData // Forward declaration of accelerated random access class template class ReadAccessor; template using DefaultReadAccessor = ReadAccessor; /// @brief Highest level of the data structure. Contains a tree and a world->index /// transform (that currently only supports uniform scaling and translation). /// /// @note This the API of this class to interface with client code template class Grid : public GridData { public: using TreeType = TreeT; using RootType = typename TreeT::RootType; using RootNodeType = RootType; using UpperNodeType = typename RootNodeType::ChildNodeType; using LowerNodeType = typename UpperNodeType::ChildNodeType; using LeafNodeType = typename RootType::LeafNodeType; using DataType = GridData; using ValueType = typename TreeT::ValueType; using BuildType = typename TreeT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using CoordType = typename TreeT::CoordType; using AccessorType = DefaultReadAccessor; /// @brief Disallow constructions, copy and assignment /// /// @note Only a Serializer, defined elsewhere, can instantiate this class Grid(const Grid&) = delete; Grid& operator=(const Grid&) = delete; ~Grid() = delete; __hostdev__ Version version() const { return DataType::mVersion; } __hostdev__ DataType* data() { return reinterpret_cast(this); } __hostdev__ const DataType* data() const { return reinterpret_cast(this); } /// @brief Return memory usage in bytes for this class only. //__hostdev__ static uint64_t memUsage() { return sizeof(GridData); } /// @brief Return the memory footprint of the entire grid, i.e. including all nodes and blind data __hostdev__ uint64_t gridSize() const { return DataType::mGridSize; } /// @brief Return index of this grid in the buffer __hostdev__ uint32_t gridIndex() const { return DataType::mGridIndex; } /// @brief Return total number of grids in the buffer __hostdev__ uint32_t gridCount() const { return DataType::mGridCount; } /// @brief @brief Return the total number of values indexed by this IndexGrid /// /// @note This method is only defined for IndexGrid = NanoGrid template __hostdev__ typename util::enable_if::is_index, const uint64_t&>::type valueCount() const { return DataType::mData1; } /// @brief @brief Return the total number of points indexed by this PointGrid /// /// @note This method is only defined for PointGrid = NanoGrid template __hostdev__ typename util::enable_if::value, const uint64_t&>::type pointCount() const { return DataType::mData1; } /// @brief Return a const reference to the tree __hostdev__ const TreeT& tree() const { return *reinterpret_cast(this->treePtr()); } /// @brief Return a non-const reference to the tree __hostdev__ TreeT& tree() { return *reinterpret_cast(this->treePtr()); } /// @brief Return a new instance of a ReadAccessor used to access values in this grid __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); } /// @brief Return a const reference to the size of a voxel in world units __hostdev__ const Vec3d& voxelSize() const { return DataType::mVoxelSize; } /// @brief Return a const reference to the Map for this grid __hostdev__ const Map& map() const { return DataType::mMap; } /// @brief world to index space transformation template __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); } /// @brief index to world space transformation template __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); } /// @brief transformation from index space direction to world space direction /// @warning assumes dir to be normalized template __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); } /// @brief transformation from world space direction to index space direction /// @warning assumes dir to be normalized template __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); } /// @brief transform the gradient from index space to world space. /// @details Applies the inverse jacobian transform map. template __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); } /// @brief world to index space transformation template __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); } /// @brief index to world space transformation template __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); } /// @brief transformation from index space direction to world space direction /// @warning assumes dir to be normalized template __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); } /// @brief transformation from world space direction to index space direction /// @warning assumes dir to be normalized template __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); } /// @brief Transforms the gradient from index space to world space. /// @details Applies the inverse jacobian transform map. template __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); } /// @brief Computes a AABB of active values in world space //__hostdev__ const Vec3dBBox& worldBBox() const { return DataType::mWorldBBox; } /// @brief Computes a AABB of active values in index space /// /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes /// it more useful for clipping rays. //__hostdev__ const BBox& indexBBox() const { return this->tree().bbox(); } /// @brief Return the total number of active voxels in this tree. __hostdev__ uint64_t activeVoxelCount() const { return this->tree().activeVoxelCount(); } /// @brief Methods related to the classification of this grid __hostdev__ bool isValid() const { return DataType::isValid(); } __hostdev__ const GridType& gridType() const { return DataType::mGridType; } __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; } __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; } __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; } __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; } __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; } __hostdev__ bool isGridIndex() const { return DataType::mGridClass == GridClass::IndexGrid; } __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; } __hostdev__ bool isMask() const { return DataType::mGridClass == GridClass::Topology; } __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; } __hostdev__ bool hasMinMax() const { return DataType::mFlags.isMaskOn(GridFlags::HasMinMax); } __hostdev__ bool hasBBox() const { return DataType::mFlags.isMaskOn(GridFlags::HasBBox); } __hostdev__ bool hasLongGridName() const { return DataType::mFlags.isMaskOn(GridFlags::HasLongGridName); } __hostdev__ bool hasAverage() const { return DataType::mFlags.isMaskOn(GridFlags::HasAverage); } __hostdev__ bool hasStdDeviation() const { return DataType::mFlags.isMaskOn(GridFlags::HasStdDeviation); } __hostdev__ bool isBreadthFirst() const { return DataType::mFlags.isMaskOn(GridFlags::IsBreadthFirst); } /// @brief return true if the specified node type is laid out breadth-first in memory and has a fixed size. /// This allows for sequential access to the nodes. template __hostdev__ bool isSequential() const { return NodeT::FIXED_SIZE && this->isBreadthFirst(); } /// @brief return true if the specified node level is laid out breadth-first in memory and has a fixed size. /// This allows for sequential access to the nodes. template __hostdev__ bool isSequential() const { return NodeTrait::type::FIXED_SIZE && this->isBreadthFirst(); } /// @brief return true if nodes at all levels can safely be accessed with simple linear offsets __hostdev__ bool isSequential() const { return UpperNodeType::FIXED_SIZE && LowerNodeType::FIXED_SIZE && LeafNodeType::FIXED_SIZE && this->isBreadthFirst(); } /// @brief Return a c-string with the name of this grid __hostdev__ const char* gridName() const { return DataType::gridName(); } /// @brief Return a c-string with the name of this grid, truncated to 255 characters __hostdev__ const char* shortGridName() const { return DataType::mGridName; } /// @brief Return checksum of the grid buffer. __hostdev__ const Checksum& checksum() const { return DataType::mChecksum; } /// @brief Return true if this grid is empty, i.e. contains no values or nodes. //__hostdev__ bool isEmpty() const { return this->tree().isEmpty(); } /// @brief Return the count of blind-data encoded in this grid __hostdev__ uint32_t blindDataCount() const { return DataType::mBlindMetadataCount; } /// @brief Return the index of the first blind data with specified name if found, otherwise -1. __hostdev__ int findBlindData(const char* name) const; /// @brief Return the index of the first blind data with specified semantic if found, otherwise -1. __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const; /// @brief Returns a const pointer to the blindData at the specified linear offset. /// /// @warning Pointer might be NULL and the linear offset is assumed to be in the valid range // this method is deprecated !!!! [[deprecated("Use Grid::getBlindData() instead.")]] __hostdev__ const void* blindData(uint32_t n) const { printf("\nnanovdb::Grid::blindData is unsafe and hence deprecated! Please use nanovdb::Grid::getBlindData instead.\n\n"); NANOVDB_ASSERT(n < DataType::mBlindMetadataCount); return this->blindMetaData(n).blindData(); } template __hostdev__ const BlindDataT* getBlindData(uint32_t n) const { if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds return this->blindMetaData(n).template getBlindData();// NULL if mismatching BlindDataT } template __hostdev__ BlindDataT* getBlindData(uint32_t n) { if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds return const_cast(this->blindMetaData(n).template getBlindData());// NULL if mismatching BlindDataT } __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); } private: static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned"); }; // Class Grid template __hostdev__ int Grid::findBlindDataForSemantic(GridBlindDataSemantic semantic) const { for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i) { if (this->blindMetaData(i).mSemantic == semantic) return int(i); } return -1; } template __hostdev__ int Grid::findBlindData(const char* name) const { auto test = [&](int n) { const char* str = this->blindMetaData(n).mName; for (int i = 0; i < GridBlindMetaData::MaxNameSize; ++i) { if (name[i] != str[i]) return false; if (name[i] == '\0' && str[i] == '\0') return true; } return true; // all len characters matched }; for (int i = 0, n = this->blindDataCount(); i < n; ++i) if (test(i)) return i; return -1; } // ----------------------------> Tree <-------------------------------------- struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData { // sizeof(TreeData) == 64B int64_t mNodeOffset[4];// 32B, byte offset from this tree to first leaf, lower, upper and root node. If mNodeCount[N]=0 => mNodeOffset[N]==mNodeOffset[N+1] uint32_t mNodeCount[3]; // 12B, total number of nodes of type: leaf, lower internal, upper internal uint32_t mTileCount[3]; // 12B, total number of active tile values at the lower internal, upper internal and root node levels uint64_t mVoxelCount; // 8B, total number of active voxels in the root and all its child nodes. // No padding since it's always 32B aligned TreeData& operator=(const TreeData&) = default; __hostdev__ void setRoot(const void* root) { NANOVDB_ASSERT(root); mNodeOffset[3] = util::PtrDiff(root, this); } /// @brief Get a non-const void pointer to the root node (never NULL) __hostdev__ void* getRoot() { return util::PtrAdd(this, mNodeOffset[3]); } /// @brief Get a const void pointer to the root node (never NULL) __hostdev__ const void* getRoot() const { return util::PtrAdd(this, mNodeOffset[3]); } template __hostdev__ void setFirstNode(const NodeT* node) {mNodeOffset[NodeT::LEVEL] = (node ? util::PtrDiff(node, this) : 0);} /// @brief Return true if the root is empty, i.e. has not child nodes or constant tiles __hostdev__ bool isEmpty() const {return mNodeOffset[3] ? *util::PtrAdd(this, mNodeOffset[3] + sizeof(CoordBBox)) == 0 : true;} /// @brief Return the index bounding box of all the active values in this tree, i.e. in all nodes of the tree __hostdev__ CoordBBox bbox() const {return mNodeOffset[3] ? *util::PtrAdd(this, mNodeOffset[3]) : CoordBBox();} /// @brief return true if RootData is layout out immediately after TreeData in memory __hostdev__ bool isRootNext() const {return mNodeOffset[3] ? mNodeOffset[3] == sizeof(TreeData) : false; } };// TreeData // ----------------------------> GridTree <-------------------------------------- /// @brief defines a tree type from a grid type while preserving constness template struct GridTree { using Type = typename GridT::TreeType; using type = typename GridT::TreeType; }; template struct GridTree { using Type = const typename GridT::TreeType; using type = const typename GridT::TreeType; }; template using GridTreeT = typename GridTree::type; // ----------------------------> Tree <-------------------------------------- /// @brief VDB Tree, which is a thin wrapper around a RootNode. template class Tree : public TreeData { static_assert(RootT::LEVEL == 3, "Tree depth is not supported"); static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported"); static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported"); static_assert(RootT::LeafNodeType::LOG2DIM == 3, "Tree configuration is not supported"); public: using DataType = TreeData; using RootType = RootT; using RootNodeType = RootT; using UpperNodeType = typename RootNodeType::ChildNodeType; using LowerNodeType = typename UpperNodeType::ChildNodeType; using LeafNodeType = typename RootType::LeafNodeType; using ValueType = typename RootT::ValueType; using BuildType = typename RootT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using CoordType = typename RootT::CoordType; using AccessorType = DefaultReadAccessor; using Node3 = RootT; using Node2 = typename RootT::ChildNodeType; using Node1 = typename Node2::ChildNodeType; using Node0 = LeafNodeType; /// @brief This class cannot be constructed or deleted Tree() = delete; Tree(const Tree&) = delete; Tree& operator=(const Tree&) = delete; ~Tree() = delete; __hostdev__ DataType* data() { return reinterpret_cast(this); } __hostdev__ const DataType* data() const { return reinterpret_cast(this); } /// @brief return memory usage in bytes for the class __hostdev__ static uint64_t memUsage() { return sizeof(DataType); } __hostdev__ RootT& root() {return *reinterpret_cast(DataType::getRoot());} __hostdev__ const RootT& root() const {return *reinterpret_cast(DataType::getRoot());} __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); } /// @brief Return the value of the given voxel (regardless of state or location in the tree.) __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->root().getValue(ijk); } __hostdev__ ValueType getValue(int i, int j, int k) const { return this->root().getValue(CoordType(i, j, k)); } /// @brief Return the active state of the given voxel (regardless of state or location in the tree.) __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); } /// @brief Return true if this tree is empty, i.e. contains no values or nodes //__hostdev__ bool isEmpty() const { return this->root().isEmpty(); } /// @brief Combines the previous two methods in a single call __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); } /// @brief Return a const reference to the background value. __hostdev__ const ValueType& background() const { return this->root().background(); } /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree __hostdev__ void extrema(ValueType& min, ValueType& max) const; /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree //__hostdev__ const BBox& bbox() const { return this->root().bbox(); } /// @brief Return the total number of active voxels in this tree. __hostdev__ uint64_t activeVoxelCount() const { return DataType::mVoxelCount; } /// @brief Return the total number of active tiles at the specified level of the tree. /// /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper /// internal nodes, and the root level. Note active values at the leaf level are /// referred to as active voxels (see activeVoxelCount defined above). __hostdev__ const uint32_t& activeTileCount(uint32_t level) const { NANOVDB_ASSERT(level > 0 && level <= 3); // 1, 2, or 3 return DataType::mTileCount[level - 1]; } template __hostdev__ uint32_t nodeCount() const { static_assert(NodeT::LEVEL < 3, "Invalid NodeT"); return DataType::mNodeCount[NodeT::LEVEL]; } __hostdev__ uint32_t nodeCount(int level) const { NANOVDB_ASSERT(level < 3); return DataType::mNodeCount[level]; } __hostdev__ uint32_t totalNodeCount() const { return DataType::mNodeCount[0] + DataType::mNodeCount[1] + DataType::mNodeCount[2]; } /// @brief return a pointer to the first node of the specified type /// /// @warning Note it may return NULL if no nodes exist template __hostdev__ NodeT* getFirstNode() { const int64_t nodeOffset = DataType::mNodeOffset[NodeT::LEVEL]; return nodeOffset ? util::PtrAdd(this, nodeOffset) : nullptr; } /// @brief return a const pointer to the first node of the specified type /// /// @warning Note it may return NULL if no nodes exist template __hostdev__ const NodeT* getFirstNode() const { const int64_t nodeOffset = DataType::mNodeOffset[NodeT::LEVEL]; return nodeOffset ? util::PtrAdd(this, nodeOffset) : nullptr; } /// @brief return a pointer to the first node at the specified level /// /// @warning Note it may return NULL if no nodes exist template __hostdev__ typename NodeTrait::type* getFirstNode() { return this->template getFirstNode::type>(); } /// @brief return a const pointer to the first node of the specified level /// /// @warning Note it may return NULL if no nodes exist template __hostdev__ const typename NodeTrait::type* getFirstNode() const { return this->template getFirstNode::type>(); } /// @brief Template specializations of getFirstNode __hostdev__ LeafNodeType* getFirstLeaf() { return this->getFirstNode(); } __hostdev__ const LeafNodeType* getFirstLeaf() const { return this->getFirstNode(); } __hostdev__ typename NodeTrait::type* getFirstLower() { return this->getFirstNode<1>(); } __hostdev__ const typename NodeTrait::type* getFirstLower() const { return this->getFirstNode<1>(); } __hostdev__ typename NodeTrait::type* getFirstUpper() { return this->getFirstNode<2>(); } __hostdev__ const typename NodeTrait::type* getFirstUpper() const { return this->getFirstNode<2>(); } template __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const { return this->root().template get(ijk, args...); } template __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) { return this->root().template set(ijk, args...); } private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned"); }; // Tree class template __hostdev__ void Tree::extrema(ValueType& min, ValueType& max) const { min = this->root().minimum(); max = this->root().maximum(); } // --------------------------> RootData <------------------------------------ /// @brief Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode) /// /// @note No client code should (or can) interface with this struct so it can safely be ignored! template struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData { using ValueT = typename ChildT::ValueType; using BuildT = typename ChildT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using CoordT = typename ChildT::CoordType; using StatsT = typename ChildT::FloatType; static constexpr bool FIXED_SIZE = false; /// @brief Return a key based on the coordinates of a voxel #ifdef NANOVDB_USE_SINGLE_ROOT_KEY using KeyT = uint64_t; template __hostdev__ static KeyT CoordToKey(const CoordType& ijk) { static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof"); static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits } __hostdev__ static CoordT KeyToCoord(const KeyT& key) { static constexpr uint64_t MASK = (1u << 21) - 1; // used to mask out 21 lower bits return CoordT(((key >> 42) & MASK) << ChildT::TOTAL, // x are the upper 21 bits ((key >> 21) & MASK) << ChildT::TOTAL, // y are the middle 21 bits ( key & MASK) << ChildT::TOTAL); // z are the lower 21 bits } #else using KeyT = CoordT; __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; } __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; } #endif math::BBox mBBox; // 24B. AABB of active values in index space. uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node ValueT mBackground; // background value, i.e. value of any unset voxel ValueT mMinimum; // typically 4B, minimum of all the active values ValueT mMaximum; // typically 4B, maximum of all the active values StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. __hostdev__ static constexpr uint32_t padding() { return sizeof(RootData) - (24 + 4 + 3 * sizeof(ValueT) + 2 * sizeof(StatsT)); } struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile { template __hostdev__ void setChild(const CoordType& k, const void* ptr, const RootData* data) { key = CoordToKey(k); state = false; child = util::PtrDiff(ptr, data); } template __hostdev__ void setValue(const CoordType& k, bool s, const ValueType& v) { key = CoordToKey(k); state = s; value = v; child = 0; } __hostdev__ bool isChild() const { return child != 0; } __hostdev__ bool isValue() const { return child == 0; } __hostdev__ bool isActive() const { return child == 0 && state; } __hostdev__ CoordT origin() const { return KeyToCoord(key); } KeyT key; // NANOVDB_USE_SINGLE_ROOT_KEY ? 8B : 12B int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value. uint32_t state; // 4B. state of tile value ValueT value; // value of tile (i.e. no child node) }; // Tile /// @brief Returns a pointer to the tile at the specified linear offset. /// /// @warning The linear offset is assumed to be in the valid range __hostdev__ const Tile* tile(uint32_t n) const { NANOVDB_ASSERT(n < mTableSize); return reinterpret_cast(this + 1) + n; } __hostdev__ Tile* tile(uint32_t n) { NANOVDB_ASSERT(n < mTableSize); return reinterpret_cast(this + 1) + n; } template class TileIter { protected: using TileT = typename util::match_const::type; using NodeT = typename util::match_const::type; TileT *mBegin, *mPos, *mEnd; public: __hostdev__ TileIter() : mBegin(nullptr), mPos(nullptr), mEnd(nullptr) {} __hostdev__ TileIter(DataT* data, uint32_t pos = 0) : mBegin(reinterpret_cast(data + 1))// tiles reside right after the RootData , mPos(mBegin + pos) , mEnd(mBegin + data->mTableSize) { NANOVDB_ASSERT(data); NANOVDB_ASSERT(mBegin <= mPos);// pos > mTableSize is allowed NANOVDB_ASSERT(mBegin <= mEnd);// mTableSize = 0 is possible } __hostdev__ inline operator bool() const { return mPos < mEnd; } __hostdev__ inline auto pos() const {return mPos - mBegin; } __hostdev__ inline TileIter& operator++() { ++mPos; return *this; } __hostdev__ inline TileT& operator*() const { NANOVDB_ASSERT(mPos < mEnd); return *mPos; } __hostdev__ inline TileT* operator->() const { NANOVDB_ASSERT(mPos < mEnd); return mPos; } __hostdev__ inline DataT* data() const { NANOVDB_ASSERT(mBegin); return reinterpret_cast(mBegin) - 1; } __hostdev__ inline bool isChild() const { NANOVDB_ASSERT(mPos < mEnd); return mPos->child != 0; } __hostdev__ inline bool isValue() const { NANOVDB_ASSERT(mPos < mEnd); return mPos->child == 0; } __hostdev__ inline bool isValueOn() const { NANOVDB_ASSERT(mPos < mEnd); return mPos->child == 0 && mPos->state != 0; } __hostdev__ inline NodeT* child() const { NANOVDB_ASSERT(mPos < mEnd && mPos->child != 0); return util::PtrAdd(this->data(), mPos->child);// byte offset relative to RootData::this } __hostdev__ inline ValueT value() const { NANOVDB_ASSERT(mPos < mEnd && mPos->child == 0); return mPos->value; } };// TileIter using TileIterator = TileIter; using ConstTileIterator = TileIter; __hostdev__ TileIterator beginTile() { return TileIterator(this); } __hostdev__ ConstTileIterator cbeginTile() const { return ConstTileIterator(this); } __hostdev__ inline TileIterator probe(const CoordT& ijk) { const auto key = CoordToKey(ijk); TileIterator iter(this); for(; iter; ++iter) if (iter->key == key) break; return iter; } __hostdev__ inline ConstTileIterator probe(const CoordT& ijk) const { const auto key = CoordToKey(ijk); ConstTileIterator iter(this); for(; iter; ++iter) if (iter->key == key) break; return iter; } __hostdev__ inline Tile* probeTile(const CoordT& ijk) { auto iter = this->probe(ijk); return iter ? iter.operator->() : nullptr; } __hostdev__ inline const Tile* probeTile(const CoordT& ijk) const { return const_cast(this)->probeTile(ijk); } __hostdev__ inline ChildT* probeChild(const CoordT& ijk) { auto iter = this->probe(ijk); return iter && iter.isChild() ? iter.child() : nullptr; } __hostdev__ inline const ChildT* probeChild(const CoordT& ijk) const { return const_cast(this)->probeChild(ijk); } /// @brief Returns a const reference to the child node in the specified tile. /// /// @warning A child node is assumed to exist in the specified tile __hostdev__ ChildT* getChild(const Tile* tile) { NANOVDB_ASSERT(tile->child); return util::PtrAdd(this, tile->child); } __hostdev__ const ChildT* getChild(const Tile* tile) const { NANOVDB_ASSERT(tile->child); return util::PtrAdd(this, tile->child); } __hostdev__ const ValueT& getMin() const { return mMinimum; } __hostdev__ const ValueT& getMax() const { return mMaximum; } __hostdev__ const StatsT& average() const { return mAverage; } __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; } __hostdev__ void setMin(const ValueT& v) { mMinimum = v; } __hostdev__ void setMax(const ValueT& v) { mMaximum = v; } __hostdev__ void setAvg(const StatsT& v) { mAverage = v; } __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; } /// @brief This class cannot be constructed or deleted RootData() = delete; RootData(const RootData&) = delete; RootData& operator=(const RootData&) = delete; ~RootData() = delete; }; // RootData // --------------------------> RootNode <------------------------------------ /// @brief Top-most node of the VDB tree structure. template class RootNode : public RootData { public: using DataType = RootData; using ChildNodeType = ChildT; using RootType = RootNode; // this allows RootNode to behave like a Tree using RootNodeType = RootType; using UpperNodeType = ChildT; using LowerNodeType = typename UpperNodeType::ChildNodeType; using LeafNodeType = typename ChildT::LeafNodeType; using ValueType = typename DataType::ValueT; using FloatType = typename DataType::StatsT; using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using CoordType = typename ChildT::CoordType; using BBoxType = math::BBox; using AccessorType = DefaultReadAccessor; using Tile = typename DataType::Tile; static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf template class BaseIter { protected: using DataT = typename util::match_const::type; using TileT = typename util::match_const::type; typename DataType::template TileIter mTileIter; __hostdev__ BaseIter() : mTileIter() {} __hostdev__ BaseIter(DataT* data) : mTileIter(data){} public: __hostdev__ operator bool() const { return bool(mTileIter); } __hostdev__ uint32_t pos() const { return uint32_t(mTileIter.pos()); } __hostdev__ TileT* tile() const { return mTileIter.operator->(); } __hostdev__ CoordType getOrigin() const {return mTileIter->origin();} __hostdev__ CoordType getCoord() const {return this->getOrigin();} }; // Member class BaseIter template class ChildIter : public BaseIter { static_assert(util::is_same::type, RootNode>::value, "Invalid RootT"); using BaseT = BaseIter; using NodeT = typename util::match_const::type; using BaseT::mTileIter; public: __hostdev__ ChildIter() : BaseT() {} __hostdev__ ChildIter(RootT* parent) : BaseT(parent->data()) { while (mTileIter && mTileIter.isValue()) ++mTileIter; } __hostdev__ NodeT& operator*() const {return *mTileIter.child();} __hostdev__ NodeT* operator->() const {return mTileIter.child();} __hostdev__ ChildIter& operator++() { ++mTileIter; while (mTileIter && mTileIter.isValue()) ++mTileIter; return *this; } __hostdev__ ChildIter operator++(int) { auto tmp = *this; this->operator++(); return tmp; } }; // Member class ChildIter using ChildIterator = ChildIter; using ConstChildIterator = ChildIter; __hostdev__ ChildIterator beginChild() { return ChildIterator(this); } __hostdev__ ConstChildIterator cbeginChild() const { return ConstChildIterator(this); } template class ValueIter : public BaseIter { using BaseT = BaseIter; using BaseT::mTileIter; public: __hostdev__ ValueIter() : BaseT(){} __hostdev__ ValueIter(RootT* parent) : BaseT(parent->data()) { while (mTileIter && mTileIter.isChild()) ++mTileIter; } __hostdev__ ValueType operator*() const {return mTileIter.value();} __hostdev__ bool isActive() const {return mTileIter.isValueOn();} __hostdev__ ValueIter& operator++() { ++mTileIter; while (mTileIter && mTileIter.isChild()) ++mTileIter; return *this; } __hostdev__ ValueIter operator++(int) { auto tmp = *this; this->operator++(); return tmp; } }; // Member class ValueIter using ValueIterator = ValueIter; using ConstValueIterator = ValueIter; __hostdev__ ValueIterator beginValue() { return ValueIterator(this); } __hostdev__ ConstValueIterator cbeginValueAll() const { return ConstValueIterator(this); } template class ValueOnIter : public BaseIter { using BaseT = BaseIter; using BaseT::mTileIter; public: __hostdev__ ValueOnIter() : BaseT(){} __hostdev__ ValueOnIter(RootT* parent) : BaseT(parent->data()) { while (mTileIter && !mTileIter.isValueOn()) ++mTileIter; } __hostdev__ ValueType operator*() const {return mTileIter.value();} __hostdev__ ValueOnIter& operator++() { ++mTileIter; while (mTileIter && !mTileIter.isValueOn()) ++mTileIter; return *this; } __hostdev__ ValueOnIter operator++(int) { auto tmp = *this; this->operator++(); return tmp; } }; // Member class ValueOnIter using ValueOnIterator = ValueOnIter; using ConstValueOnIterator = ValueOnIter; __hostdev__ ValueOnIterator beginValueOn() { return ValueOnIterator(this); } __hostdev__ ConstValueOnIterator cbeginValueOn() const { return ConstValueOnIterator(this); } template class DenseIter : public BaseIter { using BaseT = BaseIter; using NodeT = typename util::match_const::type; using BaseT::mTileIter; public: __hostdev__ DenseIter() : BaseT(){} __hostdev__ DenseIter(RootT* parent) : BaseT(parent->data()){} __hostdev__ NodeT* probeChild(ValueType& value) const { if (mTileIter.isChild()) return mTileIter.child(); value = mTileIter.value(); return nullptr; } __hostdev__ bool isValueOn() const{return mTileIter.isValueOn();} __hostdev__ DenseIter& operator++() { ++mTileIter; return *this; } __hostdev__ DenseIter operator++(int) { auto tmp = *this; ++mTileIter; return tmp; } }; // Member class DenseIter using DenseIterator = DenseIter; using ConstDenseIterator = DenseIter; __hostdev__ DenseIterator beginDense() { return DenseIterator(this); } __hostdev__ ConstDenseIterator cbeginDense() const { return ConstDenseIterator(this); } __hostdev__ ConstDenseIterator cbeginChildAll() const { return ConstDenseIterator(this); } /// @brief This class cannot be constructed or deleted RootNode() = delete; RootNode(const RootNode&) = delete; RootNode& operator=(const RootNode&) = delete; ~RootNode() = delete; __hostdev__ AccessorType getAccessor() const { return AccessorType(*this); } __hostdev__ DataType* data() { return reinterpret_cast(this); } __hostdev__ const DataType* data() const { return reinterpret_cast(this); } /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree __hostdev__ const BBoxType& bbox() const { return DataType::mBBox; } /// @brief Return the total number of active voxels in the root and all its child nodes. /// @brief Return a const reference to the background value, i.e. the value associated with /// any coordinate location that has not been set explicitly. __hostdev__ const ValueType& background() const { return DataType::mBackground; } /// @brief Return the number of tiles encoded in this root node __hostdev__ const uint32_t& tileCount() const { return DataType::mTableSize; } __hostdev__ const uint32_t& getTableSize() const { return DataType::mTableSize; } /// @brief Return a const reference to the minimum active value encoded in this root node and any of its child nodes __hostdev__ const ValueType& minimum() const { return DataType::mMinimum; } /// @brief Return a const reference to the maximum active value encoded in this root node and any of its child nodes __hostdev__ const ValueType& maximum() const { return DataType::mMaximum; } /// @brief Return a const reference to the average of all the active values encoded in this root node and any of its child nodes __hostdev__ const FloatType& average() const { return DataType::mAverage; } /// @brief Return the variance of all the active values encoded in this root node and any of its child nodes __hostdev__ FloatType variance() const { return math::Pow2(DataType::mStdDevi); } /// @brief Return a const reference to the standard deviation of all the active values encoded in this root node and any of its child nodes __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } /// @brief Return the expected memory footprint in bytes with the specified number of tiles __hostdev__ static uint64_t memUsage(uint32_t tableSize) { return sizeof(RootNode) + tableSize * sizeof(Tile); } /// @brief Return the actual memory footprint of this root node __hostdev__ uint64_t memUsage() const { return sizeof(RootNode) + DataType::mTableSize * sizeof(Tile); } /// @brief Return true if this RootNode is empty, i.e. contains no values or nodes __hostdev__ bool isEmpty() const { return DataType::mTableSize == uint32_t(0); } /// @brief Return the value of the given voxel __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } /// @brief return the state and updates the value of the specified voxel __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } template __hostdev__ typename OpT::Type get(const CoordType& ijk, ArgsT&&... args) const { if (const Tile* tile = this->probeTile(ijk)) { if constexpr(OpT::LEVEL < LEVEL) if (tile->isChild()) return this->getChild(tile)->template get(ijk, args...); return OpT::get(*tile, args...); } return OpT::get(*this, args...); } template __hostdev__ void set(const CoordType& ijk, ArgsT&&... args) { if (Tile* tile = DataType::probeTile(ijk)) { if constexpr(OpT::LEVEL < LEVEL) if (tile->isChild()) return this->getChild(tile)->template set(ijk, args...); return OpT::set(*tile, args...); } return OpT::set(*this, args...); } private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned"); static_assert(sizeof(typename DataType::Tile) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData::Tile) is misaligned"); template friend class ReadAccessor; template friend class Tree; template __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const { if (const Tile* tile = this->probeTile(ijk)) { if (tile->isChild()) { const auto* child = this->getChild(tile); acc.insert(ijk, child); return child->getDimAndCache(ijk, ray, acc); } return 1 << ChildT::TOTAL; //tile value } return ChildNodeType::dim(); // background } template __hostdev__ typename OpT::Type getAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) const { if (const Tile* tile = this->probeTile(ijk)) { if constexpr(OpT::LEVEL < LEVEL) { if (tile->isChild()) { const ChildT* child = this->getChild(tile); acc.insert(ijk, child); return child->template getAndCache(ijk, acc, args...); } } return OpT::get(*tile, args...); } return OpT::get(*this, args...); } template __hostdev__ void setAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) { if (Tile* tile = DataType::probeTile(ijk)) { if constexpr(OpT::LEVEL < LEVEL) { if (tile->isChild()) { ChildT* child = this->getChild(tile); acc.insert(ijk, child); return child->template setAndCache(ijk, acc, args...); } } return OpT::set(*tile, args...); } return OpT::set(*this, args...); } }; // RootNode class // After the RootNode the memory layout is assumed to be the sorted Tiles // --------------------------> InternalNode <------------------------------------ /// @brief Struct with all the member data of the InternalNode (useful during serialization of an openvdb InternalNode) /// /// @note No client code should (or can) interface with this struct so it can safely be ignored! template struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData { using ValueT = typename ChildT::ValueType; using BuildT = typename ChildT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using StatsT = typename ChildT::FloatType; using CoordT = typename ChildT::CoordType; using MaskT = typename ChildT::template MaskType; static constexpr bool FIXED_SIZE = true; union Tile { ValueT value; int64_t child; //signed 64 bit byte offset relative to this InternalData, i.e. child-pointer = Tile::child + this /// @brief This class cannot be constructed or deleted Tile() = delete; Tile(const Tile&) = delete; Tile& operator=(const Tile&) = delete; ~Tile() = delete; }; math::BBox mBBox; // 24B. node bounding box. | uint64_t mFlags; // 8B. node flags. | 32B aligned MaskT mValueMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned MaskT mChildMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned ValueT mMinimum; // typically 4B ValueT mMaximum; // typically 4B StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes // possible padding, e.g. 28 byte padding when ValueType = bool /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. __hostdev__ static constexpr uint32_t padding() { return sizeof(InternalData) - (24u + 8u + 2 * (sizeof(MaskT) + sizeof(ValueT) + sizeof(StatsT)) + (1u << (3 * LOG2DIM)) * (sizeof(ValueT) > 8u ? sizeof(ValueT) : 8u)); } alignas(32) Tile mTable[1u << (3 * LOG2DIM)]; // sizeof(ValueT) x (16*16*16 or 32*32*32) __hostdev__ static uint64_t memUsage() { return sizeof(InternalData); } __hostdev__ void setChild(uint32_t n, const void* ptr) { NANOVDB_ASSERT(mChildMask.isOn(n)); mTable[n].child = util::PtrDiff(ptr, this); } template __hostdev__ void setValue(uint32_t n, const ValueT& v) { NANOVDB_ASSERT(!mChildMask.isOn(n)); mTable[n].value = v; } /// @brief Returns a pointer to the child node at the specifed linear offset. __hostdev__ ChildT* getChild(uint32_t n) { NANOVDB_ASSERT(mChildMask.isOn(n)); return util::PtrAdd(this, mTable[n].child); } __hostdev__ const ChildT* getChild(uint32_t n) const { NANOVDB_ASSERT(mChildMask.isOn(n)); return util::PtrAdd(this, mTable[n].child); } __hostdev__ ValueT getValue(uint32_t n) const { NANOVDB_ASSERT(mChildMask.isOff(n)); return mTable[n].value; } __hostdev__ bool isActive(uint32_t n) const { NANOVDB_ASSERT(mChildMask.isOff(n)); return mValueMask.isOn(n); } __hostdev__ bool isChild(uint32_t n) const { return mChildMask.isOn(n); } template __hostdev__ void setOrigin(const T& ijk) { mBBox[0] = ijk; } __hostdev__ const ValueT& getMin() const { return mMinimum; } __hostdev__ const ValueT& getMax() const { return mMaximum; } __hostdev__ const StatsT& average() const { return mAverage; } __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; } // GCC 13 (and possibly prior versions) has a regression that results in invalid // warnings when -Wstringop-overflow is turned on. For details, refer to // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101854 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106757 #if defined(__GNUC__) && (__GNUC__ < 14) && !defined(__APPLE__) && !defined(__llvm__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif __hostdev__ void setMin(const ValueT& v) { mMinimum = v; } __hostdev__ void setMax(const ValueT& v) { mMaximum = v; } __hostdev__ void setAvg(const StatsT& v) { mAverage = v; } __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; } #if defined(__GNUC__) && (__GNUC__ < 14) && !defined(__APPLE__) && !defined(__llvm__) #pragma GCC diagnostic pop #endif /// @brief This class cannot be constructed or deleted InternalData() = delete; InternalData(const InternalData&) = delete; InternalData& operator=(const InternalData&) = delete; ~InternalData() = delete; }; // InternalData /// @brief Internal nodes of a VDB tree template class InternalNode : public InternalData { public: using DataType = InternalData; using ValueType = typename DataType::ValueT; using FloatType = typename DataType::StatsT; using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool using LeafNodeType = typename ChildT::LeafNodeType; using ChildNodeType = ChildT; using CoordType = typename ChildT::CoordType; static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; template using MaskType = typename ChildT::template MaskType; template using MaskIterT = typename Mask::template Iterator; static constexpr uint32_t LOG2DIM = Log2Dim; static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers) static constexpr uint32_t MASK = (1u << TOTAL) - 1u; static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node /// @brief Visits child nodes of this node only template class ChildIter : public MaskIterT { static_assert(util::is_same::type, InternalNode>::value, "Invalid ParentT"); using BaseT = MaskIterT; using NodeT = typename util::match_const::type; ParentT* mParent; public: __hostdev__ ChildIter() : BaseT() , mParent(nullptr) { } __hostdev__ ChildIter(ParentT* parent) : BaseT(parent->mChildMask.beginOn()) , mParent(parent) { } ChildIter& operator=(const ChildIter&) = default; __hostdev__ NodeT& operator*() const { NANOVDB_ASSERT(*this); return *mParent->getChild(BaseT::pos()); } __hostdev__ NodeT* operator->() const { NANOVDB_ASSERT(*this); return mParent->getChild(BaseT::pos()); } __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return (*this)->origin(); } __hostdev__ CoordType getCoord() const {return this->getOrigin();} }; // Member class ChildIter using ChildIterator = ChildIter; using ConstChildIterator = ChildIter; __hostdev__ ChildIterator beginChild() { return ChildIterator(this); } __hostdev__ ConstChildIterator cbeginChild() const { return ConstChildIterator(this); } /// @brief Visits all tile values in this node, i.e. both inactive and active tiles class ValueIterator : public MaskIterT { using BaseT = MaskIterT; const InternalNode* mParent; public: __hostdev__ ValueIterator() : BaseT() , mParent(nullptr) { } __hostdev__ ValueIterator(const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOff()) , mParent(parent) { } ValueIterator& operator=(const ValueIterator&) = default; __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos()); } __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos()); } __hostdev__ CoordType getCoord() const {return this->getOrigin();} __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->data()->isActive(BaseT::mPos); } }; // Member class ValueIterator __hostdev__ ValueIterator beginValue() const { return ValueIterator(this); } __hostdev__ ValueIterator cbeginValueAll() const { return ValueIterator(this); } /// @brief Visits active tile values of this node only class ValueOnIterator : public MaskIterT { using BaseT = MaskIterT; const InternalNode* mParent; public: __hostdev__ ValueOnIterator() : BaseT() , mParent(nullptr) { } __hostdev__ ValueOnIterator(const InternalNode* parent) : BaseT(parent->data()->mValueMask.beginOn()) , mParent(parent) { } ValueOnIterator& operator=(const ValueOnIterator&) = default; __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos()); } __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos()); } __hostdev__ CoordType getCoord() const {return this->getOrigin();} }; // Member class ValueOnIterator __hostdev__ ValueOnIterator beginValueOn() const { return ValueOnIterator(this); } __hostdev__ ValueOnIterator cbeginValueOn() const { return ValueOnIterator(this); } /// @brief Visits all tile values and child nodes of this node class DenseIterator : public Mask::DenseIterator { using BaseT = typename Mask::DenseIterator; const DataType* mParent; public: __hostdev__ DenseIterator() : BaseT() , mParent(nullptr) { } __hostdev__ DenseIterator(const InternalNode* parent) : BaseT(0) , mParent(parent->data()) { } DenseIterator& operator=(const DenseIterator&) = default; __hostdev__ const ChildT* probeChild(ValueType& value) const { NANOVDB_ASSERT(mParent && bool(*this)); const ChildT* child = nullptr; if (mParent->mChildMask.isOn(BaseT::pos())) { child = mParent->getChild(BaseT::pos()); } else { value = mParent->getValue(BaseT::pos()); } return child; } __hostdev__ bool isValueOn() const { NANOVDB_ASSERT(mParent && bool(*this)); return mParent->isActive(BaseT::pos()); } __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(mParent && bool(*this)); return mParent->offsetToGlobalCoord(BaseT::pos()); } __hostdev__ CoordType getCoord() const {return this->getOrigin();} }; // Member class DenseIterator __hostdev__ DenseIterator beginDense() const { return DenseIterator(this); } __hostdev__ DenseIterator cbeginChildAll() const { return DenseIterator(this); } // matches openvdb /// @brief This class cannot be constructed or deleted InternalNode() = delete; InternalNode(const InternalNode&) = delete; InternalNode& operator=(const InternalNode&) = delete; ~InternalNode() = delete; __hostdev__ DataType* data() { return reinterpret_cast(this); } __hostdev__ const DataType* data() const { return reinterpret_cast(this); } /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32) __hostdev__ static uint32_t dim() { return 1u << TOTAL; } /// @brief Return memory usage in bytes for the class __hostdev__ static size_t memUsage() { return DataType::memUsage(); } /// @brief Return a const reference to the bit mask of active voxels in this internal node __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } __hostdev__ const MaskType& getValueMask() const { return DataType::mValueMask; } /// @brief Return a const reference to the bit mask of child nodes in this internal node __hostdev__ const MaskType& childMask() const { return DataType::mChildMask; } __hostdev__ const MaskType& getChildMask() const { return DataType::mChildMask; } /// @brief Return the origin in index space of this leaf node __hostdev__ CoordType origin() const { return DataType::mBBox.min() & ~MASK; } /// @brief Return a const reference to the minimum active value encoded in this internal node and any of its child nodes __hostdev__ const ValueType& minimum() const { return this->getMin(); } /// @brief Return a const reference to the maximum active value encoded in this internal node and any of its child nodes __hostdev__ const ValueType& maximum() const { return this->getMax(); } /// @brief Return a const reference to the average of all the active values encoded in this internal node and any of its child nodes __hostdev__ const FloatType& average() const { return DataType::mAverage; } /// @brief Return the variance of all the active values encoded in this internal node and any of its child nodes __hostdev__ FloatType variance() const { return DataType::mStdDevi * DataType::mStdDevi; } /// @brief Return a const reference to the standard deviation of all the active values encoded in this internal node and any of its child nodes __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } /// @brief Return a const reference to the bounding box in index space of active values in this internal node and any of its child nodes __hostdev__ const math::BBox& bbox() const { return DataType::mBBox; } /// @brief If the first entry in this node's table is a tile, return the tile's value. /// Otherwise, return the result of calling getFirstValue() on the child. __hostdev__ ValueType getFirstValue() const { return DataType::mChildMask.isOn(0) ? this->getChild(0)->getFirstValue() : DataType::getValue(0); } /// @brief If the last entry in this node's table is a tile, return the tile's value. /// Otherwise, return the result of calling getLastValue() on the child. __hostdev__ ValueType getLastValue() const { return DataType::mChildMask.isOn(SIZE - 1) ? this->getChild(SIZE - 1)->getLastValue() : DataType::getValue(SIZE - 1); } /// @brief Return the value of the given voxel __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } /// @brief return the state and updates the value of the specified voxel __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ChildNodeType* probeChild(const CoordType& ijk) { const uint32_t n = CoordToOffset(ijk); return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr; } __hostdev__ const ChildNodeType* probeChild(const CoordType& ijk) const { const uint32_t n = CoordToOffset(ijk); return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr; } /// @brief Return the linear offset corresponding to the given coordinate __hostdev__ static uint32_t CoordToOffset(const CoordType& ijk) { return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) | // note, we're using bitwise OR instead of + (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ((ijk[2] & MASK) >> ChildT::TOTAL); } /// @return the local coordinate of the n'th tile or child node __hostdev__ static Coord OffsetToLocalCoord(uint32_t n) { NANOVDB_ASSERT(n < SIZE); const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1); return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1)); } /// @brief modifies local coordinates to global coordinates of a tile or child node __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk <<= ChildT::TOTAL; ijk += this->origin(); } __hostdev__ Coord offsetToGlobalCoord(uint32_t n) const { Coord ijk = InternalNode::OffsetToLocalCoord(n); this->localToGlobalCoord(ijk); return ijk; } /// @brief Return true if this node or any of its child nodes contain active values __hostdev__ bool isActive() const { return DataType::mFlags & uint32_t(2); } template __hostdev__ typename OpT::Type get(const CoordType& ijk, ArgsT&&... args) const { const uint32_t n = CoordToOffset(ijk); if constexpr(OpT::LEVEL < LEVEL) if (this->isChild(n)) return this->getChild(n)->template get(ijk, args...); return OpT::get(*this, n, args...); } template __hostdev__ void set(const CoordType& ijk, ArgsT&&... args) { const uint32_t n = CoordToOffset(ijk); if constexpr(OpT::LEVEL < LEVEL) if (this->isChild(n)) return this->getChild(n)->template set(ijk, args...); return OpT::set(*this, n, args...); } private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned"); template friend class ReadAccessor; template friend class RootNode; template friend class InternalNode; template __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const { if (DataType::mFlags & uint32_t(1u)) return this->dim(); // skip this node if the 1st bit is set //if (!ray.intersects( this->bbox() )) return 1<getChild(n); acc.insert(ijk, child); return child->getDimAndCache(ijk, ray, acc); } return ChildNodeType::dim(); // tile value } template __hostdev__ typename OpT::Type getAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) const { const uint32_t n = CoordToOffset(ijk); if constexpr(OpT::LEVEL < LEVEL) { if (this->isChild(n)) { const ChildT* child = this->getChild(n); acc.insert(ijk, child); return child->template getAndCache(ijk, acc, args...); } } return OpT::get(*this, n, args...); } template __hostdev__ void setAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) { const uint32_t n = CoordToOffset(ijk); if constexpr(OpT::LEVEL < LEVEL) { if (this->isChild(n)) { ChildT* child = this->getChild(n); acc.insert(ijk, child); return child->template setAndCache(ijk, acc, args...); } } return OpT::set(*this, n, args...); } }; // InternalNode class // --------------------------> LeafData <------------------------------------ /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) /// /// @note No client code should (or can) interface with this struct so it can safely be ignored! template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = ValueT; using BuildType = ValueT; using FloatType = typename FloatTraits::FloatType; using ArrayType = ValueT; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. ValueType mMinimum; // typically 4B ValueType mMaximum; // typically 4B FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes FloatType mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes alignas(32) ValueType mValues[1u << 3 * LOG2DIM]; /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafData) - (12 + 3 + 1 + sizeof(MaskT) + 2 * (sizeof(ValueT) + sizeof(FloatType)) + (1u << (3 * LOG2DIM)) * sizeof(ValueT)); } __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ static bool hasStats() { return true; } __hostdev__ ValueType getValue(uint32_t i) const { return mValues[i]; } __hostdev__ void setValueOnly(uint32_t offset, const ValueType& value) { mValues[offset] = value; } __hostdev__ void setValue(uint32_t offset, const ValueType& value) { mValueMask.setOn(offset); mValues[offset] = value; } __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } __hostdev__ ValueType getMin() const { return mMinimum; } __hostdev__ ValueType getMax() const { return mMaximum; } __hostdev__ FloatType getAvg() const { return mAverage; } __hostdev__ FloatType getDev() const { return mStdDevi; } // GCC 11 (and possibly prior versions) has a regression that results in invalid // warnings when -Wstringop-overflow is turned on. For details, refer to // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101854 #if defined(__GNUC__) && (__GNUC__ < 12) && !defined(__APPLE__) && !defined(__llvm__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif __hostdev__ void setMin(const ValueType& v) { mMinimum = v; } __hostdev__ void setMax(const ValueType& v) { mMaximum = v; } __hostdev__ void setAvg(const FloatType& v) { mAverage = v; } __hostdev__ void setDev(const FloatType& v) { mStdDevi = v; } #if defined(__GNUC__) && (__GNUC__ < 12) && !defined(__APPLE__) && !defined(__llvm__) #pragma GCC diagnostic pop #endif template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } __hostdev__ void fill(const ValueType& v) { for (auto *p = mValues, *q = p + 512; p != q; ++p) *p = v; } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafFnBase <------------------------------------ /// @brief Base-class for quantized float leaf nodes template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = float; using FloatType = float; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. float mMinimum; // 4B - minimum of ALL values in this node float mQuantum; // = (max - min)/15 4B uint16_t mMin, mMax, mAvg, mDev; // quantized representations of statistics of active values // no padding since it's always 32B aligned __hostdev__ static uint64_t memUsage() { return sizeof(LeafFnBase); } __hostdev__ static bool hasStats() { return true; } /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafFnBase) - (12 + 3 + 1 + sizeof(MaskT) + 2 * 4 + 4 * 2); } __hostdev__ void init(float min, float max, uint8_t bitWidth) { mMinimum = min; mQuantum = (max - min) / float((1 << bitWidth) - 1); } __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } /// @brief return the quantized minimum of the active values in this node __hostdev__ float getMin() const { return mMin * mQuantum + mMinimum; } /// @brief return the quantized maximum of the active values in this node __hostdev__ float getMax() const { return mMax * mQuantum + mMinimum; } /// @brief return the quantized average of the active values in this node __hostdev__ float getAvg() const { return mAvg * mQuantum + mMinimum; } /// @brief return the quantized standard deviation of the active values in this node /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1 __hostdev__ float getDev() const { return mDev * mQuantum; } /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1 __hostdev__ void setMin(float min) { mMin = uint16_t((min - mMinimum) / mQuantum + 0.5f); } /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1 __hostdev__ void setMax(float max) { mMax = uint16_t((max - mMinimum) / mQuantum + 0.5f); } /// @note min <= avg <= max or 0 <= (avg-min)/(min-max) <= 1 __hostdev__ void setAvg(float avg) { mAvg = uint16_t((avg - mMinimum) / mQuantum + 0.5f); } /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1 __hostdev__ void setDev(float dev) { mDev = uint16_t(dev / mQuantum + 0.5f); } template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } }; // LeafFnBase // --------------------------> LeafData <------------------------------------ /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) /// /// @note No client code should (or can) interface with this struct so it can safely be ignored! template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafFnBase { using BaseT = LeafFnBase; using BuildType = Fp4; using ArrayType = uint8_t; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; alignas(32) uint8_t mCode[1u << (3 * LOG2DIM - 1)]; // LeafFnBase is 32B aligned and so is mCode __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ static constexpr uint32_t padding() { static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase"); return sizeof(LeafData) - sizeof(BaseT) - (1u << (3 * LOG2DIM - 1)); } __hostdev__ static constexpr uint8_t bitWidth() { return 4u; } __hostdev__ float getValue(uint32_t i) const { #if 0 const uint8_t c = mCode[i>>1]; return ( (i&1) ? c >> 4 : c & uint8_t(15) )*BaseT::mQuantum + BaseT::mMinimum; #else return ((mCode[i >> 1] >> ((i & 1) << 2)) & uint8_t(15)) * BaseT::mQuantum + BaseT::mMinimum; #endif } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafBase <------------------------------------ template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafFnBase { using BaseT = LeafFnBase; using BuildType = Fp8; using ArrayType = uint8_t; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; alignas(32) uint8_t mCode[1u << 3 * LOG2DIM]; __hostdev__ static constexpr int64_t memUsage() { return sizeof(LeafData); } __hostdev__ static constexpr uint32_t padding() { static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase"); return sizeof(LeafData) - sizeof(BaseT) - (1u << 3 * LOG2DIM); } __hostdev__ static constexpr uint8_t bitWidth() { return 8u; } __hostdev__ float getValue(uint32_t i) const { return mCode[i] * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/255 + min } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafData <------------------------------------ template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafFnBase { using BaseT = LeafFnBase; using BuildType = Fp16; using ArrayType = uint16_t; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; alignas(32) uint16_t mCode[1u << 3 * LOG2DIM]; __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ static constexpr uint32_t padding() { static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase"); return sizeof(LeafData) - sizeof(BaseT) - 2 * (1u << 3 * LOG2DIM); } __hostdev__ static constexpr uint8_t bitWidth() { return 16u; } __hostdev__ float getValue(uint32_t i) const { return mCode[i] * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/65535 + min } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafData <------------------------------------ template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafFnBase { // this class has no additional data members, however every instance is immediately followed by // bitWidth*64 bytes. Since its base class is 32B aligned so are the bitWidth*64 bytes using BaseT = LeafFnBase; using BuildType = FpN; static constexpr bool FIXED_SIZE = false; __hostdev__ static constexpr uint32_t padding() { static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase"); return 0; } __hostdev__ uint8_t bitWidth() const { return 1 << (BaseT::mFlags >> 5); } // 4,8,16,32 = 2^(2,3,4,5) __hostdev__ size_t memUsage() const { return sizeof(*this) + this->bitWidth() * 64; } __hostdev__ static size_t memUsage(uint32_t bitWidth) { return 96u + bitWidth * 64; } __hostdev__ float getValue(uint32_t i) const { #ifdef NANOVDB_FPN_BRANCHLESS // faster const int b = BaseT::mFlags >> 5; // b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits #if 0 // use LUT uint16_t code = reinterpret_cast(this + 1)[i >> (4 - b)]; const static uint8_t shift[5] = {15, 7, 3, 1, 0}; const static uint16_t mask[5] = {1, 3, 15, 255, 65535}; code >>= (i & shift[b]) << b; code &= mask[b]; #else // no LUT uint32_t code = reinterpret_cast(this + 1)[i >> (5 - b)]; code >>= (i & ((32 >> b) - 1)) << b; code &= (1 << (1 << b)) - 1; #endif #else // use branched version (slow) float code; auto* values = reinterpret_cast(this + 1); switch (BaseT::mFlags >> 5) { case 0u: // 1 bit float code = float((values[i >> 3] >> (i & 7)) & uint8_t(1)); break; case 1u: // 2 bits float code = float((values[i >> 2] >> ((i & 3) << 1)) & uint8_t(3)); break; case 2u: // 4 bits float code = float((values[i >> 1] >> ((i & 1) << 2)) & uint8_t(15)); break; case 3u: // 8 bits float code = float(values[i]); break; default: // 16 bits float code = float(reinterpret_cast(values)[i]); } #endif return float(code) * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/UNITS + min } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafData <------------------------------------ // Partial template specialization of LeafData with bool template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = bool; using BuildType = bool; using FloatType = bool; // dummy value type using ArrayType = MaskT; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. MaskT mValues; // LOG2DIM(3): 64B. uint64_t mPadding[2]; // 16B padding to 32B alignment __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafData) - 12u - 3u - 1u - 2 * sizeof(MaskT) - 16u; } __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ static bool hasStats() { return false; } __hostdev__ bool getValue(uint32_t i) const { return mValues.isOn(i); } __hostdev__ bool getMin() const { return false; } // dummy __hostdev__ bool getMax() const { return false; } // dummy __hostdev__ bool getAvg() const { return false; } // dummy __hostdev__ bool getDev() const { return false; } // dummy __hostdev__ void setValue(uint32_t offset, bool v) { mValueMask.setOn(offset); mValues.set(offset, v); } __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } __hostdev__ void setMin(const bool&) {} // no-op __hostdev__ void setMax(const bool&) {} // no-op __hostdev__ void setAvg(const bool&) {} // no-op __hostdev__ void setDev(const bool&) {} // no-op template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafData <------------------------------------ // Partial template specialization of LeafData with ValueMask template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = bool; using BuildType = ValueMask; using FloatType = bool; // dummy value type using ArrayType = void; // type used for the internal mValue array - void means missing static constexpr bool FIXED_SIZE = true; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. uint64_t mPadding[2]; // 16B padding to 32B alignment __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ static bool hasStats() { return false; } __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT) + 2 * 8u); } __hostdev__ bool getValue(uint32_t i) const { return mValueMask.isOn(i); } __hostdev__ bool getMin() const { return false; } // dummy __hostdev__ bool getMax() const { return false; } // dummy __hostdev__ bool getAvg() const { return false; } // dummy __hostdev__ bool getDev() const { return false; } // dummy __hostdev__ void setValue(uint32_t offset, bool) { mValueMask.setOn(offset); } __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } __hostdev__ void setMin(const ValueType&) {} // no-op __hostdev__ void setMax(const ValueType&) {} // no-op __hostdev__ void setAvg(const FloatType&) {} // no-op __hostdev__ void setDev(const FloatType&) {} // no-op template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafIndexBase <------------------------------------ // Partial template specialization of LeafData with ValueIndex template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafIndexBase { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = uint64_t; using FloatType = uint64_t; using ArrayType = void; // type used for the internal mValue array - void means missing static constexpr bool FIXED_SIZE = true; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. uint64_t mOffset, mPrefixSum; // 8B offset to first value in this leaf node and 9-bit prefix sum __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafIndexBase) - (12u + 3u + 1u + sizeof(MaskT) + 2 * 8u); } __hostdev__ static uint64_t memUsage() { return sizeof(LeafIndexBase); } __hostdev__ bool hasStats() const { return mFlags & (uint8_t(1) << 4); } // return the offset to the first value indexed by this leaf node __hostdev__ const uint64_t& firstOffset() const { return mOffset; } __hostdev__ void setMin(const ValueType&) {} // no-op __hostdev__ void setMax(const ValueType&) {} // no-op __hostdev__ void setAvg(const FloatType&) {} // no-op __hostdev__ void setDev(const FloatType&) {} // no-op __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } protected: /// @brief This class should be used as an abstract class and only constructed or deleted via child classes LeafIndexBase() = default; LeafIndexBase(const LeafIndexBase&) = default; LeafIndexBase& operator=(const LeafIndexBase&) = default; ~LeafIndexBase() = default; }; // LeafIndexBase // --------------------------> LeafData <------------------------------------ // Partial template specialization of LeafData with ValueIndex template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafIndexBase { using BaseT = LeafIndexBase; using BuildType = ValueIndex; // return the total number of values indexed by this leaf node, excluding the optional 4 stats __hostdev__ static uint32_t valueCount() { return uint32_t(512); } // 8^3 = 2^9 // return the offset to the last value indexed by this leaf node (disregarding optional stats) __hostdev__ uint64_t lastOffset() const { return BaseT::mOffset + 511u; } // 2^9 - 1 // if stats are available, they are always placed after the last voxel value in this leaf node __hostdev__ uint64_t getMin() const { return this->hasStats() ? BaseT::mOffset + 512u : 0u; } __hostdev__ uint64_t getMax() const { return this->hasStats() ? BaseT::mOffset + 513u : 0u; } __hostdev__ uint64_t getAvg() const { return this->hasStats() ? BaseT::mOffset + 514u : 0u; } __hostdev__ uint64_t getDev() const { return this->hasStats() ? BaseT::mOffset + 515u : 0u; } __hostdev__ uint64_t getValue(uint32_t i) const { return BaseT::mOffset + i; } // dense leaf node with active and inactive voxels }; // LeafData // --------------------------> LeafData <------------------------------------ template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData : public LeafIndexBase { using BaseT = LeafIndexBase; using BuildType = ValueOnIndex; __hostdev__ uint32_t valueCount() const { return util::countOn(BaseT::mValueMask.words()[7]) + (BaseT::mPrefixSum >> 54u & 511u); // last 9 bits of mPrefixSum do not account for the last word in mValueMask } __hostdev__ uint64_t lastOffset() const { return BaseT::mOffset + this->valueCount() - 1u; } __hostdev__ uint64_t getMin() const { return this->hasStats() ? this->lastOffset() + 1u : 0u; } __hostdev__ uint64_t getMax() const { return this->hasStats() ? this->lastOffset() + 2u : 0u; } __hostdev__ uint64_t getAvg() const { return this->hasStats() ? this->lastOffset() + 3u : 0u; } __hostdev__ uint64_t getDev() const { return this->hasStats() ? this->lastOffset() + 4u : 0u; } __hostdev__ uint64_t getValue(uint32_t i) const { //return mValueMask.isOn(i) ? mOffset + mValueMask.countOn(i) : 0u;// for debugging uint32_t n = i >> 6; const uint64_t w = BaseT::mValueMask.words()[n], mask = uint64_t(1) << (i & 63u); if (!(w & mask)) return uint64_t(0); // if i'th value is inactive return offset to background value uint64_t sum = BaseT::mOffset + util::countOn(w & (mask - 1u)); if (n--) sum += BaseT::mPrefixSum >> (9u * n) & 511u; return sum; } }; // LeafData // --------------------------> LeafData <------------------------------------ template class MaskT, uint32_t LOG2DIM> struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData { static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof"); static_assert(sizeof(MaskT) == sizeof(Mask), "Mismatching sizeof"); using ValueType = uint64_t; using BuildType = Point; using FloatType = typename FloatTraits::FloatType; using ArrayType = uint16_t; // type used for the internal mValue array static constexpr bool FIXED_SIZE = true; CoordT mBBoxMin; // 12B. uint8_t mBBoxDif[3]; // 3B. uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN MaskT mValueMask; // LOG2DIM(3): 64B. uint64_t mOffset; // 8B uint64_t mPointCount; // 8B alignas(32) uint16_t mValues[1u << 3 * LOG2DIM]; // 1KB // no padding /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment /// /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT) + 2 * 8u + (1u << 3 * LOG2DIM) * 2u); } __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } __hostdev__ uint64_t offset() const { return mOffset; } __hostdev__ uint64_t pointCount() const { return mPointCount; } __hostdev__ uint64_t first(uint32_t i) const { return i ? uint64_t(mValues[i - 1u]) + mOffset : mOffset; } __hostdev__ uint64_t last(uint32_t i) const { return uint64_t(mValues[i]) + mOffset; } __hostdev__ uint64_t getValue(uint32_t i) const { return uint64_t(mValues[i]); } __hostdev__ void setValueOnly(uint32_t offset, uint16_t value) { mValues[offset] = value; } __hostdev__ void setValue(uint32_t offset, uint16_t value) { mValueMask.setOn(offset); mValues[offset] = value; } __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); } __hostdev__ ValueType getMin() const { return mOffset; } __hostdev__ ValueType getMax() const { return mPointCount; } __hostdev__ FloatType getAvg() const { return 0.0f; } __hostdev__ FloatType getDev() const { return 0.0f; } __hostdev__ void setMin(const ValueType&) {} __hostdev__ void setMax(const ValueType&) {} __hostdev__ void setAvg(const FloatType&) {} __hostdev__ void setDev(const FloatType&) {} template __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } /// @brief This class cannot be constructed or deleted LeafData() = delete; LeafData(const LeafData&) = delete; LeafData& operator=(const LeafData&) = delete; ~LeafData() = delete; }; // LeafData // --------------------------> LeafNode <------------------------------------ /// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels) template class MaskT = Mask, uint32_t Log2Dim = 3> class LeafNode : public LeafData { public: struct ChildNodeType { static constexpr uint32_t TOTAL = 0; static constexpr uint32_t DIM = 1; __hostdev__ static uint32_t dim() { return 1u; } }; // Voxel using LeafNodeType = LeafNode; using DataType = LeafData; using ValueType = typename DataType::ValueType; using FloatType = typename DataType::FloatType; using BuildType = typename DataType::BuildType; using CoordType = CoordT; static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; template using MaskType = MaskT; template using MaskIterT = typename Mask::template Iterator; /// @brief Visits all active values in a leaf node class ValueOnIterator : public MaskIterT { using BaseT = MaskIterT; const LeafNode* mParent; public: __hostdev__ ValueOnIterator() : BaseT() , mParent(nullptr) { } __hostdev__ ValueOnIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOn()) , mParent(parent) { } ValueOnIterator& operator=(const ValueOnIterator&) = default; __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos()); } __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos()); } }; // Member class ValueOnIterator __hostdev__ ValueOnIterator beginValueOn() const { return ValueOnIterator(this); } __hostdev__ ValueOnIterator cbeginValueOn() const { return ValueOnIterator(this); } /// @brief Visits all inactive values in a leaf node class ValueOffIterator : public MaskIterT { using BaseT = MaskIterT; const LeafNode* mParent; public: __hostdev__ ValueOffIterator() : BaseT() , mParent(nullptr) { } __hostdev__ ValueOffIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOff()) , mParent(parent) { } ValueOffIterator& operator=(const ValueOffIterator&) = default; __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos()); } __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos()); } }; // Member class ValueOffIterator __hostdev__ ValueOffIterator beginValueOff() const { return ValueOffIterator(this); } __hostdev__ ValueOffIterator cbeginValueOff() const { return ValueOffIterator(this); } /// @brief Visits all values in a leaf node, i.e. both active and inactive values class ValueIterator { const LeafNode* mParent; uint32_t mPos; public: __hostdev__ ValueIterator() : mParent(nullptr) , mPos(1u << 3 * Log2Dim) { } __hostdev__ ValueIterator(const LeafNode* parent) : mParent(parent) , mPos(0) { NANOVDB_ASSERT(parent); } ValueIterator& operator=(const ValueIterator&) = default; __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->getValue(mPos); } __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos); } __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->isActive(mPos); } __hostdev__ operator bool() const { return mPos < (1u << 3 * Log2Dim); } __hostdev__ ValueIterator& operator++() { ++mPos; return *this; } __hostdev__ ValueIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; } }; // Member class ValueIterator __hostdev__ ValueIterator beginValue() const { return ValueIterator(this); } __hostdev__ ValueIterator cbeginValueAll() const { return ValueIterator(this); } static_assert(util::is_same::Type>::value, "Mismatching BuildType"); static constexpr uint32_t LOG2DIM = Log2Dim; static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node static constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations static constexpr uint32_t LEVEL = 0; // level 0 = leaf static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node __hostdev__ DataType* data() { return reinterpret_cast(this); } __hostdev__ const DataType* data() const { return reinterpret_cast(this); } /// @brief Return a const reference to the bit mask of active voxels in this leaf node __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } __hostdev__ const MaskType& getValueMask() const { return DataType::mValueMask; } /// @brief Return a const reference to the minimum active value encoded in this leaf node __hostdev__ ValueType minimum() const { return DataType::getMin(); } /// @brief Return a const reference to the maximum active value encoded in this leaf node __hostdev__ ValueType maximum() const { return DataType::getMax(); } /// @brief Return a const reference to the average of all the active values encoded in this leaf node __hostdev__ FloatType average() const { return DataType::getAvg(); } /// @brief Return the variance of all the active values encoded in this leaf node __hostdev__ FloatType variance() const { return Pow2(DataType::getDev()); } /// @brief Return a const reference to the standard deviation of all the active values encoded in this leaf node __hostdev__ FloatType stdDeviation() const { return DataType::getDev(); } __hostdev__ uint8_t flags() const { return DataType::mFlags; } /// @brief Return the origin in index space of this leaf node __hostdev__ CoordT origin() const { return DataType::mBBoxMin & ~MASK; } /// @brief Compute the local coordinates from a linear offset /// @param n Linear offset into this nodes dense table /// @return Local (vs global) 3D coordinates __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n) { NANOVDB_ASSERT(n < SIZE); const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1); return CoordT(n >> 2 * LOG2DIM, m >> LOG2DIM, m & MASK); } /// @brief Converts (in place) a local index coordinate to a global index coordinate __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk += this->origin(); } __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const { return OffsetToLocalCoord(n) + this->origin(); } /// @brief Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!) __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; } /// @brief Return the bounding box in index space of active values in this leaf node __hostdev__ math::BBox bbox() const { math::BBox bbox(DataType::mBBoxMin, DataType::mBBoxMin); if (this->hasBBox()) { bbox.max()[0] += DataType::mBBoxDif[0]; bbox.max()[1] += DataType::mBBoxDif[1]; bbox.max()[2] += DataType::mBBoxDif[2]; } else { // very rare case bbox = math::BBox(); // invalid } return bbox; } /// @brief Return the total number of voxels (e.g. values) encoded in this leaf node __hostdev__ static uint32_t voxelCount() { return 1u << (3 * LOG2DIM); } __hostdev__ static uint32_t padding() { return DataType::padding(); } /// @brief return memory usage in bytes for the leaf node __hostdev__ uint64_t memUsage() const { return DataType::memUsage(); } /// @brief This class cannot be constructed or deleted LeafNode() = delete; LeafNode(const LeafNode&) = delete; LeafNode& operator=(const LeafNode&) = delete; ~LeafNode() = delete; /// @brief Return the voxel value at the given offset. __hostdev__ ValueType getValue(uint32_t offset) const { return DataType::getValue(offset); } /// @brief Return the voxel value at the given coordinate. __hostdev__ ValueType getValue(const CoordT& ijk) const { return DataType::getValue(CoordToOffset(ijk)); } /// @brief Return the first value in this leaf node. __hostdev__ ValueType getFirstValue() const { return this->getValue(0); } /// @brief Return the last value in this leaf node. __hostdev__ ValueType getLastValue() const { return this->getValue(SIZE - 1); } /// @brief Sets the value at the specified location and activate its state. /// /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) __hostdev__ void setValue(const CoordT& ijk, const ValueType& v) { DataType::setValue(CoordToOffset(ijk), v); } /// @brief Sets the value at the specified location but leaves its state unchanged. /// /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) __hostdev__ void setValueOnly(uint32_t offset, const ValueType& v) { DataType::setValueOnly(offset, v); } __hostdev__ void setValueOnly(const CoordT& ijk, const ValueType& v) { DataType::setValueOnly(CoordToOffset(ijk), v); } /// @brief Return @c true if the voxel value at the given coordinate is active. __hostdev__ bool isActive(const CoordT& ijk) const { return DataType::mValueMask.isOn(CoordToOffset(ijk)); } __hostdev__ bool isActive(uint32_t n) const { return DataType::mValueMask.isOn(n); } /// @brief Return @c true if any of the voxel value are active in this leaf node. __hostdev__ bool isActive() const { //NANOVDB_ASSERT( bool(DataType::mFlags & uint8_t(2)) != DataType::mValueMask.isOff() ); //return DataType::mFlags & uint8_t(2); return !DataType::mValueMask.isOff(); } __hostdev__ bool hasBBox() const { return DataType::mFlags & uint8_t(2); } /// @brief Return @c true if the voxel value at the given coordinate is active and updates @c v with the value. __hostdev__ bool probeValue(const CoordT& ijk, ValueType& v) const { const uint32_t n = CoordToOffset(ijk); v = DataType::getValue(n); return DataType::mValueMask.isOn(n); } __hostdev__ const LeafNode* probeLeaf(const CoordT&) const { return this; } /// @brief Return the linear offset corresponding to the given coordinate __hostdev__ static uint32_t CoordToOffset(const CoordT& ijk) { return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK); } /// @brief Updates the local bounding box of active voxels in this node. Return true if bbox was updated. /// /// @warning It assumes that the origin and value mask have already been set. /// /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast. /// However, it should only only be called if either the value mask has changed or if the /// active bounding box is still undefined. e.g. during construction of this node. __hostdev__ bool updateBBox(); template __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const { return OpT::get(*this, CoordToOffset(ijk), args...); } template __hostdev__ auto get(const uint32_t n, ArgsT&&... args) const { return OpT::get(*this, n, args...); } template __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) { return OpT::set(*this, CoordToOffset(ijk), args...); } template __hostdev__ auto set(const uint32_t n, ArgsT&&... args) { return OpT::set(*this, n, args...); } private: static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned"); template friend class ReadAccessor; template friend class RootNode; template friend class InternalNode; template __hostdev__ uint32_t getDimAndCache(const CoordT&, const RayT& /*ray*/, const AccT&) const { if (DataType::mFlags & uint8_t(1u)) return this->dim(); // skip this node if the 1st bit is set //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM; return ChildNodeType::dim(); } template __hostdev__ auto //__hostdev__ decltype(OpT::get(util::declval(), util::declval(), util::declval()...)) getAndCache(const CoordType& ijk, const AccT&, ArgsT&&... args) const { return OpT::get(*this, CoordToOffset(ijk), args...); } template //__hostdev__ auto // occasionally fails with NVCC __hostdev__ decltype(OpT::set(util::declval(), util::declval(), util::declval()...)) setAndCache(const CoordType& ijk, const AccT&, ArgsT&&... args) { return OpT::set(*this, CoordToOffset(ijk), args...); } }; // LeafNode class // --------------------------> LeafNode::updateBBox <------------------------------------ template class MaskT, uint32_t LOG2DIM> __hostdev__ inline bool LeafNode::updateBBox() { static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!"); if (DataType::mValueMask.isOff()) { DataType::mFlags &= ~uint8_t(2); // set 2nd bit off, which indicates that this nodes has no bbox return false; } auto update = [&](uint32_t min, uint32_t max, int axis) { NANOVDB_ASSERT(min <= max && max < 8); DataType::mBBoxMin[axis] = (DataType::mBBoxMin[axis] & ~MASK) + int(min); DataType::mBBoxDif[axis] = uint8_t(max - min); }; uint64_t *w = DataType::mValueMask.words(), word64 = *w; uint32_t Xmin = word64 ? 0u : 8u, Xmax = Xmin; for (int i = 1; i < 8; ++i) { // last loop over 7 remaining 64 bit words if (w[i]) { // skip if word has no set bits word64 |= w[i]; // union 8 x 64 bits words into one 64 bit word if (Xmin == 8) Xmin = i; // only set once Xmax = i; } } NANOVDB_ASSERT(word64); update(Xmin, Xmax, 0); update(util::findLowestOn(word64) >> 3, util::findHighestOn(word64) >> 3, 1); const uint32_t *p = reinterpret_cast(&word64), word32 = p[0] | p[1]; const uint16_t *q = reinterpret_cast(&word32), word16 = q[0] | q[1]; const uint8_t *b = reinterpret_cast(&word16), byte = b[0] | b[1]; NANOVDB_ASSERT(byte); update(util::findLowestOn(static_cast(byte)), util::findHighestOn(static_cast(byte)), 2); DataType::mFlags |= uint8_t(2); // set 2nd bit on, which indicates that this nodes has a bbox return true; } // LeafNode::updateBBox // --------------------------> Template specializations and traits <------------------------------------ /// @brief Template specializations to the default configuration used in OpenVDB: /// Root -> 32^3 -> 16^3 -> 8^3 template using NanoLeaf = LeafNode; template using NanoLower = InternalNode, 4>; template using NanoUpper = InternalNode, 5>; template using NanoRoot = RootNode>; template using NanoTree = Tree>; template using NanoGrid = Grid>; /// @brief Trait to map from LEVEL to node type template struct NanoNode; // Partial template specialization of above Node struct template struct NanoNode { using Type = NanoLeaf; using type = NanoLeaf; }; template struct NanoNode { using Type = NanoLower; using type = NanoLower; }; template struct NanoNode { using Type = NanoUpper; using type = NanoUpper; }; template struct NanoNode { using Type = NanoRoot; using type = NanoRoot; }; template using NanoNodeT = typename NanoNode::type; using FloatTree = NanoTree; using Fp4Tree = NanoTree; using Fp8Tree = NanoTree; using Fp16Tree = NanoTree; using FpNTree = NanoTree; using DoubleTree = NanoTree; using Int32Tree = NanoTree; using UInt32Tree = NanoTree; using Int64Tree = NanoTree; using Vec3fTree = NanoTree; using Vec3dTree = NanoTree; using Vec4fTree = NanoTree; using Vec4dTree = NanoTree; using Vec3ITree = NanoTree; using MaskTree = NanoTree; using BoolTree = NanoTree; using IndexTree = NanoTree; using OnIndexTree = NanoTree; using FloatGrid = Grid; using Fp4Grid = Grid; using Fp8Grid = Grid; using Fp16Grid = Grid; using FpNGrid = Grid; using DoubleGrid = Grid; using Int32Grid = Grid; using UInt32Grid = Grid; using Int64Grid = Grid; using Vec3fGrid = Grid; using Vec3dGrid = Grid; using Vec4fGrid = Grid; using Vec4dGrid = Grid; using Vec3IGrid = Grid; using MaskGrid = Grid; using BoolGrid = Grid; using PointGrid = Grid; using IndexGrid = Grid; using OnIndexGrid = Grid; // --------------------------> callNanoGrid <------------------------------------ /** * @brief Below is an example of the struct used for generic programming with callNanoGrid * @details For an example see "struct Crc32TailOld" in nanovdb/tools/GridChecksum.h or * "struct IsNanoGridValid" in nanovdb/tools/GridValidator.h * @code * struct OpT { // define these two static functions with non-const GridData * template * static auto known( GridData *gridData, args...); * static auto unknown( GridData *gridData, args...); * // or alternatively these two static functions with const GridData * template * static auto known(const GridData *gridData, args...); * static auto unknown(const GridData *gridData, args...); * }; * @endcode * * @brief Here is an example of how to use callNanoGrid in client code * @code * return callNanoGrid(gridData, args...); * @endcode */ /// @brief Use this function, which depends a pointer to GridData, to call /// other functions that depend on a NanoGrid of a known ValueType. /// @details This function allows for generic programming by converting GridData /// to a NanoGrid of the type encoded in GridData::mGridType. template auto callNanoGrid(GridDataT *gridData, ArgsT&&... args) { static_assert(util::is_same::value, "Expected gridData to be of type GridData* or const GridData*"); switch (gridData->mGridType){ case GridType::Float: return OpT::template known(gridData, args...); case GridType::Double: return OpT::template known(gridData, args...); case GridType::Int16: return OpT::template known(gridData, args...); case GridType::Int32: return OpT::template known(gridData, args...); case GridType::Int64: return OpT::template known(gridData, args...); case GridType::Vec3f: return OpT::template known(gridData, args...); case GridType::Vec3d: return OpT::template known(gridData, args...); case GridType::UInt32: return OpT::template known(gridData, args...); case GridType::Mask: return OpT::template known(gridData, args...); case GridType::Index: return OpT::template known(gridData, args...); case GridType::OnIndex: return OpT::template known(gridData, args...); case GridType::Boolean: return OpT::template known(gridData, args...); case GridType::RGBA8: return OpT::template known(gridData, args...); case GridType::Fp4: return OpT::template known(gridData, args...); case GridType::Fp8: return OpT::template known(gridData, args...); case GridType::Fp16: return OpT::template known(gridData, args...); case GridType::FpN: return OpT::template known(gridData, args...); case GridType::Vec4f: return OpT::template known(gridData, args...); case GridType::Vec4d: return OpT::template known(gridData, args...); case GridType::UInt8: return OpT::template known(gridData, args...); default: return OpT::unknown(gridData, args...); } }// callNanoGrid // --------------------------> ReadAccessor <------------------------------------ /// @brief A read-only value accessor with three levels of node caching. This allows for /// inverse tree traversal during lookup, which is on average significantly faster /// than calling the equivalent method on the tree (i.e. top-down traversal). /// /// @note By virtue of the fact that a value accessor accelerates random access operations /// by re-using cached access patterns, this access should be reused for multiple access /// operations. In other words, never create an instance of this accessor for a single /// access only. In general avoid single access operations with this accessor, and /// if that is not possible call the corresponding method on the tree instead. /// /// @warning Since this ReadAccessor internally caches raw pointers to the nodes of the tree /// structure, it is not safe to copy between host and device, or even to share among /// multiple threads on the same host or device. However, it is light-weight so simple /// instantiate one per thread (on the host and/or device). /// /// @details Used to accelerated random access into a VDB tree. Provides on average /// O(1) random access operations by means of inverse tree traversal, /// which amortizes the non-const time complexity of the root node. template class ReadAccessor { using GridT = NanoGrid; // grid using TreeT = NanoTree; // tree using RootT = NanoRoot; // root node using LeafT = NanoLeaf; // Leaf node using FloatType = typename RootT::FloatType; using CoordValueType = typename RootT::CoordType::ValueType; mutable const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const) public: using BuildType = BuildT; using ValueType = typename RootT::ValueType; using CoordType = typename RootT::CoordType; static const int CacheLevels = 0; /// @brief Constructor from a root node __hostdev__ ReadAccessor(const RootT& root) : mRoot{&root} { } /// @brief Constructor from a grid __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) { } /// @brief Constructor from a tree __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) { } /// @brief Reset this access to its initial state, i.e. with an empty cache /// @node Noop since this template specialization has no cache __hostdev__ void clear() {} __hostdev__ const RootT& root() const { return *mRoot; } /// @brief Defaults constructors ReadAccessor(const ReadAccessor&) = default; ~ReadAccessor() = default; ReadAccessor& operator=(const ReadAccessor&) = default; __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } template __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const { return mRoot->getDimAndCache(ijk, ray, *this); } template __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const { return mRoot->template get(ijk, args...); } template __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) const { return const_cast(mRoot)->template set(ijk, args...); } private: /// @brief Allow nodes to insert themselves into the cache. template friend class RootNode; template friend class InternalNode; template class, uint32_t> friend class LeafNode; /// @brief No-op template __hostdev__ void insert(const CoordType&, const NodeT*) const {} }; // ReadAccessor class /// @brief Node caching at a single tree level template class ReadAccessor //e.g. 0, 1, 2 { static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 should be 0, 1, or 2"); using GridT = NanoGrid; // grid using TreeT = NanoTree; using RootT = NanoRoot; // root node using LeafT = NanoLeaf; // Leaf node using NodeT = typename NodeTrait::type; using CoordT = typename RootT::CoordType; using ValueT = typename RootT::ValueType; using FloatType = typename RootT::FloatType; using CoordValueType = typename RootT::CoordT::ValueType; // All member data are mutable to allow for access methods to be const mutable CoordT mKey; // 3*4 = 12 bytes mutable const RootT* mRoot; // 8 bytes mutable const NodeT* mNode; // 8 bytes public: using BuildType = BuildT; using ValueType = ValueT; using CoordType = CoordT; static const int CacheLevels = 1; /// @brief Constructor from a root node __hostdev__ ReadAccessor(const RootT& root) : mKey(CoordType::max()) , mRoot(&root) , mNode(nullptr) { } /// @brief Constructor from a grid __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) { } /// @brief Constructor from a tree __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) { } /// @brief Reset this access to its initial state, i.e. with an empty cache __hostdev__ void clear() { mKey = CoordType::max(); mNode = nullptr; } __hostdev__ const RootT& root() const { return *mRoot; } /// @brief Defaults constructors ReadAccessor(const ReadAccessor&) = default; ~ReadAccessor() = default; ReadAccessor& operator=(const ReadAccessor&) = default; __hostdev__ bool isCached(const CoordType& ijk) const { return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2]; } __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } template __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const { if (this->isCached(ijk)) return mNode->getDimAndCache(ijk, ray, *this); return mRoot->getDimAndCache(ijk, ray, *this); } template __hostdev__ typename OpT::Type get(const CoordType& ijk, ArgsT&&... args) const { if constexpr(OpT::LEVEL <= LEVEL0) if (this->isCached(ijk)) return mNode->template getAndCache(ijk, *this, args...); return mRoot->template getAndCache(ijk, *this, args...); } template __hostdev__ void set(const CoordType& ijk, ArgsT&&... args) const { if constexpr(OpT::LEVEL <= LEVEL0) if (this->isCached(ijk)) return const_cast(mNode)->template setAndCache(ijk, *this, args...); return const_cast(mRoot)->template setAndCache(ijk, *this, args...); } private: /// @brief Allow nodes to insert themselves into the cache. template friend class RootNode; template friend class InternalNode; template class, uint32_t> friend class LeafNode; /// @brief Inserts a leaf node and key pair into this ReadAccessor __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const { mKey = ijk & ~NodeT::MASK; mNode = node; } // no-op template __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} }; // ReadAccessor template class ReadAccessor //e.g. (0,1), (1,2), (0,2) { static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 must be 0, 1, 2"); static_assert(LEVEL1 >= 0 && LEVEL1 <= 2, "LEVEL1 must be 0, 1, 2"); static_assert(LEVEL0 < LEVEL1, "Level 0 must be lower than level 1"); using GridT = NanoGrid; // grid using TreeT = NanoTree; using RootT = NanoRoot; using LeafT = NanoLeaf; using Node1T = typename NodeTrait::type; using Node2T = typename NodeTrait::type; using CoordT = typename RootT::CoordType; using ValueT = typename RootT::ValueType; using FloatType = typename RootT::FloatType; using CoordValueType = typename RootT::CoordT::ValueType; // All member data are mutable to allow for access methods to be const #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY // 44 bytes total mutable CoordT mKey; // 3*4 = 12 bytes #else // 68 bytes total mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes #endif mutable const RootT* mRoot; mutable const Node1T* mNode1; mutable const Node2T* mNode2; public: using BuildType = BuildT; using ValueType = ValueT; using CoordType = CoordT; static const int CacheLevels = 2; /// @brief Constructor from a root node __hostdev__ ReadAccessor(const RootT& root) #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY : mKey(CoordType::max()) #else : mKeys{CoordType::max(), CoordType::max()} #endif , mRoot(&root) , mNode1(nullptr) , mNode2(nullptr) { } /// @brief Constructor from a grid __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) { } /// @brief Constructor from a tree __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) { } /// @brief Reset this access to its initial state, i.e. with an empty cache __hostdev__ void clear() { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY mKey = CoordType::max(); #else mKeys[0] = mKeys[1] = CoordType::max(); #endif mNode1 = nullptr; mNode2 = nullptr; } __hostdev__ const RootT& root() const { return *mRoot; } /// @brief Defaults constructors ReadAccessor(const ReadAccessor&) = default; ~ReadAccessor() = default; ReadAccessor& operator=(const ReadAccessor&) = default; #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY __hostdev__ bool isCached1(CoordValueType dirty) const { if (!mNode1) return false; if (dirty & int32_t(~Node1T::MASK)) { mNode1 = nullptr; return false; } return true; } __hostdev__ bool isCached2(CoordValueType dirty) const { if (!mNode2) return false; if (dirty & int32_t(~Node2T::MASK)) { mNode2 = nullptr; return false; } return true; } __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const { return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); } #else __hostdev__ bool isCached1(const CoordType& ijk) const { return (ijk[0] & int32_t(~Node1T::MASK)) == mKeys[0][0] && (ijk[1] & int32_t(~Node1T::MASK)) == mKeys[0][1] && (ijk[2] & int32_t(~Node1T::MASK)) == mKeys[0][2]; } __hostdev__ bool isCached2(const CoordType& ijk) const { return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] && (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] && (ijk[2] & int32_t(~Node2T::MASK)) == mKeys[1][2]; } #endif __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } template __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if (this->isCached1(dirty)) { return mNode1->getDimAndCache(ijk, ray, *this); } else if (this->isCached2(dirty)) { return mNode2->getDimAndCache(ijk, ray, *this); } return mRoot->getDimAndCache(ijk, ray, *this); } template __hostdev__ typename OpT::Type get(const CoordType& ijk, ArgsT&&... args) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if constexpr(OpT::LEVEL <= LEVEL0) { if (this->isCached1(dirty)) return mNode1->template getAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= LEVEL1) { if (this->isCached2(dirty)) return mNode2->template getAndCache(ijk, *this, args...); } return mRoot->template getAndCache(ijk, *this, args...); } template __hostdev__ void set(const CoordType& ijk, ArgsT&&... args) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if constexpr(OpT::LEVEL <= LEVEL0) { if (this->isCached1(dirty)) return const_cast(mNode1)->template setAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= LEVEL1) { if (this->isCached2(dirty)) return const_cast(mNode2)->template setAndCache(ijk, *this, args...); } return const_cast(mRoot)->template setAndCache(ijk, *this, args...); } private: /// @brief Allow nodes to insert themselves into the cache. template friend class RootNode; template friend class InternalNode; template class, uint32_t> friend class LeafNode; /// @brief Inserts a leaf node and key pair into this ReadAccessor __hostdev__ void insert(const CoordType& ijk, const Node1T* node) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY mKey = ijk; #else mKeys[0] = ijk & ~Node1T::MASK; #endif mNode1 = node; } __hostdev__ void insert(const CoordType& ijk, const Node2T* node) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY mKey = ijk; #else mKeys[1] = ijk & ~Node2T::MASK; #endif mNode2 = node; } template __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} }; // ReadAccessor /// @brief Node caching at all (three) tree levels template class ReadAccessor { using GridT = NanoGrid; // grid using TreeT = NanoTree; using RootT = NanoRoot; // root node using NodeT2 = NanoUpper; // upper internal node using NodeT1 = NanoLower; // lower internal node using LeafT = NanoLeaf; // Leaf node using CoordT = typename RootT::CoordType; using ValueT = typename RootT::ValueType; using FloatType = typename RootT::FloatType; using CoordValueType = typename RootT::CoordT::ValueType; // All member data are mutable to allow for access methods to be const #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY // 44 bytes total mutable CoordT mKey; // 3*4 = 12 bytes #else // 68 bytes total mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes #endif mutable const RootT* mRoot; mutable const void* mNode[3]; // 4*8 = 32 bytes public: using BuildType = BuildT; using ValueType = ValueT; using CoordType = CoordT; static const int CacheLevels = 3; /// @brief Constructor from a root node __hostdev__ ReadAccessor(const RootT& root) #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY : mKey(CoordType::max()) #else : mKeys{CoordType::max(), CoordType::max(), CoordType::max()} #endif , mRoot(&root) , mNode{nullptr, nullptr, nullptr} { } /// @brief Constructor from a grid __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) { } /// @brief Constructor from a tree __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) { } __hostdev__ const RootT& root() const { return *mRoot; } /// @brief Defaults constructors ReadAccessor(const ReadAccessor&) = default; ~ReadAccessor() = default; ReadAccessor& operator=(const ReadAccessor&) = default; /// @brief Return a const point to the cached node of the specified type /// /// @warning The return value could be NULL. template __hostdev__ const NodeT* getNode() const { using T = typename NodeTrait::type; static_assert(util::is_same::value, "ReadAccessor::getNode: Invalid node type"); return reinterpret_cast(mNode[NodeT::LEVEL]); } template __hostdev__ const typename NodeTrait::type* getNode() const { using T = typename NodeTrait::type; static_assert(LEVEL >= 0 && LEVEL <= 2, "ReadAccessor::getNode: Invalid node type"); return reinterpret_cast(mNode[LEVEL]); } /// @brief Reset this access to its initial state, i.e. with an empty cache __hostdev__ void clear() { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY mKey = CoordType::max(); #else mKeys[0] = mKeys[1] = mKeys[2] = CoordType::max(); #endif mNode[0] = mNode[1] = mNode[2] = nullptr; } #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY template __hostdev__ bool isCached(CoordValueType dirty) const { if (!mNode[NodeT::LEVEL]) return false; if (dirty & int32_t(~NodeT::MASK)) { mNode[NodeT::LEVEL] = nullptr; return false; } return true; } __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const { return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); } #else template __hostdev__ bool isCached(const CoordType& ijk) const { return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2]; } #endif __hostdev__ ValueType getValue(const CoordType& ijk) const {return this->template get>(ijk);} __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get>(CoordType(i, j, k)); } __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get>(ijk); } __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get>(ijk, v); } __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get>(ijk); } template __hostdev__ typename OpT::Type get(const CoordType& ijk, ArgsT&&... args) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if constexpr(OpT::LEVEL <=0) { if (this->isCached(dirty)) return ((const LeafT*)mNode[0])->template getAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= 1) { if (this->isCached(dirty)) return ((const NodeT1*)mNode[1])->template getAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= 2) { if (this->isCached(dirty)) return ((const NodeT2*)mNode[2])->template getAndCache(ijk, *this, args...); } return mRoot->template getAndCache(ijk, *this, args...); } template __hostdev__ void set(const CoordType& ijk, ArgsT&&... args) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if constexpr(OpT::LEVEL <= 0) { if (this->isCached(dirty)) return ((LeafT*)mNode[0])->template setAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= 1) { if (this->isCached(dirty)) return ((NodeT1*)mNode[1])->template setAndCache(ijk, *this, args...); } else if constexpr(OpT::LEVEL <= 2) { if (this->isCached(dirty)) return ((NodeT2*)mNode[2])->template setAndCache(ijk, *this, args...); } return ((RootT*)mRoot)->template setAndCache(ijk, *this, args...); } template __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY const CoordValueType dirty = this->computeDirty(ijk); #else auto&& dirty = ijk; #endif if (this->isCached(dirty)) { return ((LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); } else if (this->isCached(dirty)) { return ((NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); } else if (this->isCached(dirty)) { return ((NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); } return mRoot->getDimAndCache(ijk, ray, *this); } private: /// @brief Allow nodes to insert themselves into the cache. template friend class RootNode; template friend class InternalNode; template class, uint32_t> friend class LeafNode; /// @brief Inserts a leaf node and key pair into this ReadAccessor template __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const { #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY mKey = ijk; #else mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK; #endif mNode[NodeT::LEVEL] = node; } }; // ReadAccessor ////////////////////////////////////////////////// /// @brief Free-standing function for convenient creation of a ReadAccessor with /// optional and customizable node caching. /// /// @details createAccessor<>(grid): No caching of nodes and hence it's thread-safe but slow /// createAccessor<0>(grid): Caching of leaf nodes only /// createAccessor<1>(grid): Caching of lower internal nodes only /// createAccessor<2>(grid): Caching of upper internal nodes only /// createAccessor<0,1>(grid): Caching of leaf and lower internal nodes /// createAccessor<0,2>(grid): Caching of leaf and upper internal nodes /// createAccessor<1,2>(grid): Caching of lower and upper internal nodes /// createAccessor<0,1,2>(grid): Caching of all nodes at all tree levels template ReadAccessor createAccessor(const NanoGrid& grid) { return ReadAccessor(grid); } template ReadAccessor createAccessor(const NanoTree& tree) { return ReadAccessor(tree); } template ReadAccessor createAccessor(const NanoRoot& root) { return ReadAccessor(root); } ////////////////////////////////////////////////// /// @brief This is a convenient class that allows for access to grid meta-data /// that are independent of the value type of a grid. That is, this class /// can be used to get information about a grid without actually knowing /// its ValueType. class GridMetaData { // 768 bytes (32 byte aligned) GridData mGridData; // 672B TreeData mTreeData; // 64B CoordBBox mIndexBBox; // 24B. AABB of active values in index space. uint32_t mRootTableSize, mPadding{0}; // 8B public: template GridMetaData(const NanoGrid& grid) { mGridData = *grid.data(); mTreeData = *grid.tree().data(); mIndexBBox = grid.indexBBox(); mRootTableSize = grid.tree().root().getTableSize(); } GridMetaData(const GridData* gridData) { if (GridMetaData::safeCast(gridData)) { *this = *reinterpret_cast(gridData); //util::memcpy(this, (const GridMetaData*)gridData); } else {// otherwise copy each member individually mGridData = *gridData; mTreeData = *reinterpret_cast(gridData->treePtr()); mIndexBBox = gridData->indexBBox(); mRootTableSize = gridData->rootTableSize(); } } GridMetaData& operator=(const GridMetaData&) = default; /// @brief return true if the RootData follows right after the TreeData. /// If so, this implies that it's safe to cast the grid from which /// this instance was constructed to a GridMetaData __hostdev__ bool safeCast() const { return mTreeData.isRootNext(); } /// @brief return true if it is safe to cast the grid to a pointer /// of type GridMetaData, i.e. construction can be avoided. __hostdev__ static bool safeCast(const GridData *gridData){ NANOVDB_ASSERT(gridData && gridData->isValid()); return gridData->isRootConnected(); } /// @brief return true if it is safe to cast the grid to a pointer /// of type GridMetaData, i.e. construction can be avoided. template __hostdev__ static bool safeCast(const NanoGrid& grid){return grid.tree().isRootNext();} __hostdev__ bool isValid() const { return mGridData.isValid(); } __hostdev__ const GridType& gridType() const { return mGridData.mGridType; } __hostdev__ const GridClass& gridClass() const { return mGridData.mGridClass; } __hostdev__ bool isLevelSet() const { return mGridData.mGridClass == GridClass::LevelSet; } __hostdev__ bool isFogVolume() const { return mGridData.mGridClass == GridClass::FogVolume; } __hostdev__ bool isStaggered() const { return mGridData.mGridClass == GridClass::Staggered; } __hostdev__ bool isPointIndex() const { return mGridData.mGridClass == GridClass::PointIndex; } __hostdev__ bool isGridIndex() const { return mGridData.mGridClass == GridClass::IndexGrid; } __hostdev__ bool isPointData() const { return mGridData.mGridClass == GridClass::PointData; } __hostdev__ bool isMask() const { return mGridData.mGridClass == GridClass::Topology; } __hostdev__ bool isUnknown() const { return mGridData.mGridClass == GridClass::Unknown; } __hostdev__ bool hasMinMax() const { return mGridData.mFlags.isMaskOn(GridFlags::HasMinMax); } __hostdev__ bool hasBBox() const { return mGridData.mFlags.isMaskOn(GridFlags::HasBBox); } __hostdev__ bool hasLongGridName() const { return mGridData.mFlags.isMaskOn(GridFlags::HasLongGridName); } __hostdev__ bool hasAverage() const { return mGridData.mFlags.isMaskOn(GridFlags::HasAverage); } __hostdev__ bool hasStdDeviation() const { return mGridData.mFlags.isMaskOn(GridFlags::HasStdDeviation); } __hostdev__ bool isBreadthFirst() const { return mGridData.mFlags.isMaskOn(GridFlags::IsBreadthFirst); } __hostdev__ uint64_t gridSize() const { return mGridData.mGridSize; } __hostdev__ uint32_t gridIndex() const { return mGridData.mGridIndex; } __hostdev__ uint32_t gridCount() const { return mGridData.mGridCount; } __hostdev__ const char* shortGridName() const { return mGridData.mGridName; } __hostdev__ const Map& map() const { return mGridData.mMap; } __hostdev__ const Vec3dBBox& worldBBox() const { return mGridData.mWorldBBox; } __hostdev__ const CoordBBox& indexBBox() const { return mIndexBBox; } __hostdev__ Vec3d voxelSize() const { return mGridData.mVoxelSize; } __hostdev__ uint32_t blindDataCount() const { return mGridData.mBlindMetadataCount; } __hostdev__ uint64_t activeVoxelCount() const { return mTreeData.mVoxelCount; } __hostdev__ const uint32_t& activeTileCount(uint32_t level) const { return mTreeData.mTileCount[level - 1]; } __hostdev__ uint32_t nodeCount(uint32_t level) const { return mTreeData.mNodeCount[level]; } __hostdev__ const Checksum& checksum() const { return mGridData.mChecksum; } __hostdev__ uint32_t rootTableSize() const { return mRootTableSize; } __hostdev__ bool isEmpty() const { return mRootTableSize == 0; } __hostdev__ Version version() const { return mGridData.mVersion; } }; // GridMetaData /// @brief Class to access points at a specific voxel location /// /// @note If GridClass::PointIndex AttT should be uint32_t and if GridClass::PointData Vec3f template class PointAccessor : public DefaultReadAccessor { using AccT = DefaultReadAccessor; const NanoGrid& mGrid; const AttT* mData; public: PointAccessor(const NanoGrid& grid) : AccT(grid.tree().root()) , mGrid(grid) , mData(grid.template getBlindData(0)) { NANOVDB_ASSERT(grid.gridType() == toGridType()); NANOVDB_ASSERT((grid.gridClass() == GridClass::PointIndex && util::is_same::value) || (grid.gridClass() == GridClass::PointData && util::is_same::value)); } /// @brief return true if this access was initialized correctly __hostdev__ operator bool() const { return mData != nullptr; } __hostdev__ const NanoGrid& grid() const { return mGrid; } /// @brief Return the total number of point in the grid and set the /// iterators to the complete range of points. __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const { const uint64_t count = mGrid.blindMetaData(0u).mValueCount; begin = mData; end = begin + count; return count; } /// @brief Return the number of points in the leaf node containing the coordinate @a ijk. /// If this return value is larger than zero then the iterators @a begin and @a end /// will point to all the attributes contained within that leaf node. __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const { auto* leaf = this->probeLeaf(ijk); if (leaf == nullptr) { return 0; } begin = mData + leaf->minimum(); end = begin + leaf->maximum(); return leaf->maximum(); } /// @brief get iterators over attributes to points at a specific voxel location __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const { begin = end = nullptr; if (auto* leaf = this->probeLeaf(ijk)) { const uint32_t offset = NanoLeaf::CoordToOffset(ijk); if (leaf->isActive(offset)) { begin = mData + leaf->minimum(); end = begin + leaf->getValue(offset); if (offset > 0u) begin += leaf->getValue(offset - 1); } } return end - begin; } }; // PointAccessor template class PointAccessor : public DefaultReadAccessor { using AccT = DefaultReadAccessor; const NanoGrid& mGrid; const AttT* mData; public: PointAccessor(const NanoGrid& grid) : AccT(grid.tree().root()) , mGrid(grid) , mData(grid.template getBlindData(0)) { NANOVDB_ASSERT(mData); NANOVDB_ASSERT(grid.gridType() == GridType::PointIndex); NANOVDB_ASSERT((grid.gridClass() == GridClass::PointIndex && util::is_same::value) || (grid.gridClass() == GridClass::PointData && util::is_same::value) || (grid.gridClass() == GridClass::PointData && util::is_same::value) || (grid.gridClass() == GridClass::PointData && util::is_same::value) || (grid.gridClass() == GridClass::PointData && util::is_same::value)); } /// @brief return true if this access was initialized correctly __hostdev__ operator bool() const { return mData != nullptr; } __hostdev__ const NanoGrid& grid() const { return mGrid; } /// @brief Return the total number of point in the grid and set the /// iterators to the complete range of points. __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const { const uint64_t count = mGrid.blindMetaData(0u).mValueCount; begin = mData; end = begin + count; return count; } /// @brief Return the number of points in the leaf node containing the coordinate @a ijk. /// If this return value is larger than zero then the iterators @a begin and @a end /// will point to all the attributes contained within that leaf node. __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const { auto* leaf = this->probeLeaf(ijk); if (leaf == nullptr) return 0; begin = mData + leaf->offset(); end = begin + leaf->pointCount(); return leaf->pointCount(); } /// @brief get iterators over attributes to points at a specific voxel location __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const { if (auto* leaf = this->probeLeaf(ijk)) { const uint32_t n = NanoLeaf::CoordToOffset(ijk); if (leaf->isActive(n)) { begin = mData + leaf->first(n); end = mData + leaf->last(n); return end - begin; } } begin = end = nullptr; return 0u; // no leaf or inactive voxel } }; // PointAccessor /// @brief Class to access values in channels at a specific voxel location. /// /// @note The ChannelT template parameter can be either const and non-const. template class ChannelAccessor : public DefaultReadAccessor { static_assert(BuildTraits::is_index, "Expected an index build type"); using BaseT = DefaultReadAccessor; const NanoGrid& mGrid; ChannelT* mChannel; public: using ValueType = ChannelT; using TreeType = NanoTree; using AccessorType = ChannelAccessor; /// @brief Ctor from an IndexGrid and an integer ID of an internal channel /// that is assumed to exist as blind data in the IndexGrid. __hostdev__ ChannelAccessor(const NanoGrid& grid, uint32_t channelID = 0u) : BaseT(grid.tree().root()) , mGrid(grid) , mChannel(nullptr) { NANOVDB_ASSERT(isIndex(grid.gridType())); NANOVDB_ASSERT(grid.gridClass() == GridClass::IndexGrid); this->setChannel(channelID); } /// @brief Ctor from an IndexGrid and an external channel __hostdev__ ChannelAccessor(const NanoGrid& grid, ChannelT* channelPtr) : BaseT(grid.tree().root()) , mGrid(grid) , mChannel(channelPtr) { NANOVDB_ASSERT(isIndex(grid.gridType())); NANOVDB_ASSERT(grid.gridClass() == GridClass::IndexGrid); } /// @brief return true if this access was initialized correctly __hostdev__ operator bool() const { return mChannel != nullptr; } /// @brief Return a const reference to the IndexGrid __hostdev__ const NanoGrid& grid() const { return mGrid; } /// @brief Return a const reference to the tree of the IndexGrid __hostdev__ const TreeType& tree() const { return mGrid.tree(); } /// @brief Return a vector of the axial voxel sizes __hostdev__ const Vec3d& voxelSize() const { return mGrid.voxelSize(); } /// @brief Return total number of values indexed by the IndexGrid __hostdev__ const uint64_t& valueCount() const { return mGrid.valueCount(); } /// @brief Change to an external channel /// @return Pointer to channel data __hostdev__ ChannelT* setChannel(ChannelT* channelPtr) {return mChannel = channelPtr;} /// @brief Change to an internal channel, assuming it exists as as blind data /// in the IndexGrid. /// @return Pointer to channel data, which could be NULL if channelID is out of range or /// if ChannelT does not match the value type of the blind data __hostdev__ ChannelT* setChannel(uint32_t channelID) { return mChannel = const_cast(mGrid.template getBlindData(channelID)); } /// @brief Return the linear offset into a channel that maps to the specified coordinate __hostdev__ uint64_t getIndex(const math::Coord& ijk) const { return BaseT::getValue(ijk); } __hostdev__ uint64_t idx(int i, int j, int k) const { return BaseT::getValue(math::Coord(i, j, k)); } /// @brief Return the value from a cached channel that maps to the specified coordinate __hostdev__ ChannelT& getValue(const math::Coord& ijk) const { return mChannel[BaseT::getValue(ijk)]; } __hostdev__ ChannelT& operator()(const math::Coord& ijk) const { return this->getValue(ijk); } __hostdev__ ChannelT& operator()(int i, int j, int k) const { return this->getValue(math::Coord(i, j, k)); } /// @brief return the state and updates the value of the specified voxel __hostdev__ bool probeValue(const math::Coord& ijk, typename util::remove_const::type& v) const { uint64_t idx; const bool isActive = BaseT::probeValue(ijk, idx); v = mChannel[idx]; return isActive; } /// @brief Return the value from a specified channel that maps to the specified coordinate /// /// @note The template parameter can be either const or non-const template __hostdev__ T& getValue(const math::Coord& ijk, T* channelPtr) const { return channelPtr[BaseT::getValue(ijk)]; } }; // ChannelAccessor #if 0 // This MiniGridHandle class is only included as a stand-alone example. Note that aligned_alloc is a C++17 feature! // Normally we recommend using GridHandle defined in util/GridHandle.h but this minimal implementation could be an // alternative when using the IO methods defined below. struct MiniGridHandle { struct BufferType { uint8_t *data; uint64_t size; BufferType(uint64_t n=0) : data(std::aligned_alloc(NANOVDB_DATA_ALIGNMENT, n)), size(n) {assert(isValid(data));} BufferType(BufferType &&other) : data(other.data), size(other.size) {other.data=nullptr; other.size=0;} ~BufferType() {std::free(data);} BufferType& operator=(const BufferType &other) = delete; BufferType& operator=(BufferType &&other){data=other.data; size=other.size; other.data=nullptr; other.size=0; return *this;} static BufferType create(size_t n, BufferType* dummy = nullptr) {return BufferType(n);} } buffer; MiniGridHandle(BufferType &&buf) : buffer(std::move(buf)) {} const uint8_t* data() const {return buffer.data;} };// MiniGridHandle #endif namespace io { /// @brief Define compression codecs /// /// @note NONE is the default, ZIP is slow but compact and BLOSC offers a great balance. /// /// @throw NanoVDB optionally supports ZIP and BLOSC compression and will throw an exception /// if its support is required but missing. enum class Codec : uint16_t { NONE = 0, ZIP = 1, BLOSC = 2, End = 3, StrLen = 6 + End }; __hostdev__ inline const char* toStr(char *dst, Codec codec) { switch (codec){ case Codec::NONE: return util::strcpy(dst, "NONE"); case Codec::ZIP: return util::strcpy(dst, "ZIP"); case Codec::BLOSC : return util::strcpy(dst, "BLOSC");// StrLen = 5 + 1 + End default: return util::strcpy(dst, "END"); } } __hostdev__ inline Codec toCodec(const char *str) { if (util::streq(str, "none")) return Codec::NONE; if (util::streq(str, "zip")) return Codec::ZIP; if (util::streq(str, "blosc")) return Codec::BLOSC; return Codec::End; } /// @brief Data encoded at the head of each segment of a file or stream. /// /// @note A file or stream is composed of one or more segments that each contain // one or more grids. struct FileHeader {// 16 bytes uint64_t magic;// 8 bytes Version version;// 4 bytes version numbers uint16_t gridCount;// 2 bytes Codec codec;// 2 bytes bool isValid() const {return magic == NANOVDB_MAGIC_NUMB || magic == NANOVDB_MAGIC_FILE;} }; // FileHeader ( 16 bytes = 2 words ) // @brief Data encoded for each of the grids associated with a segment. // Grid size in memory (uint64_t) | // Grid size on disk (uint64_t) | // Grid name hash key (uint64_t) | // Numer of active voxels (uint64_t) | // Grid type (uint32_t) | // Grid class (uint32_t) | // Characters in grid name (uint32_t) | // AABB in world space (2*3*double) | one per grid in file // AABB in index space (2*3*int) | // Size of a voxel in world units (3*double) | // Byte size of the grid name (uint32_t) | // Number of nodes per level (4*uint32_t) | // Numer of active tiles per level (3*uint32_t) | // Codec for file compression (uint16_t) | // Padding due to 8B alignment (uint16_t) | // Version number (uint32_t) | struct FileMetaData {// 176 bytes uint64_t gridSize, fileSize, nameKey, voxelCount; // 4 * 8 = 32B. GridType gridType; // 4B. GridClass gridClass; // 4B. Vec3dBBox worldBBox; // 2 * 3 * 8 = 48B. CoordBBox indexBBox; // 2 * 3 * 4 = 24B. Vec3d voxelSize; // 24B. uint32_t nameSize; // 4B. uint32_t nodeCount[4]; //4 x 4 = 16B uint32_t tileCount[3];// 3 x 4 = 12B Codec codec; // 2B uint16_t blindDataCount;// 2B Version version;// 4B }; // FileMetaData // the following code block uses std and therefore needs to be ignored by CUDA and HIP #if !defined(__CUDA_ARCH__) && !defined(__HIP__) // Note that starting with version 32.6.0 it is possible to write and read raw grid buffers to // files, e.g. os.write((const char*)&buffer.data(), buffer.size()) or more conveniently as // handle.write(fileName). In addition to this simple approach we offer the methods below to // write traditional uncompressed nanovdb files that unlike raw files include metadata that // is used for tools like nanovdb_print. /// /// @brief This is a standalone alternative to io::writeGrid(...,Codec::NONE) defined in util/IO.h /// Unlike the latter this function has no dependencies at all, not even NanoVDB.h, so it also /// works if client code only includes PNanoVDB.h! /// /// @details Writes a raw NanoVDB buffer, possibly with multiple grids, to a stream WITHOUT compression. /// It follows all the conventions in util/IO.h so the stream can be read by all existing client /// code of NanoVDB. /// /// @note This method will always write uncompressed grids to the stream, i.e. Blosc or ZIP compression /// is never applied! This is a fundamental limitation and feature of this standalone function. /// /// @throw std::invalid_argument if buffer does not point to a valid NanoVDB grid. /// /// @warning This is pretty ugly code that involves lots of pointer and bit manipulations - not for the faint of heart :) template // StreamT class must support: "void write(const char*, size_t)" void writeUncompressedGrid(StreamT& os, const GridData* gridData, bool raw = false) { NANOVDB_ASSERT(gridData->mMagic == NANOVDB_MAGIC_NUMB || gridData->mMagic == NANOVDB_MAGIC_GRID); NANOVDB_ASSERT(gridData->mVersion.isCompatible()); if (!raw) {// segment with a single grid: FileHeader, FileMetaData, gridName, Grid #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS FileHeader head{NANOVDB_MAGIC_FILE, gridData->mVersion, 1u, Codec::NONE}; #else FileHeader head{NANOVDB_MAGIC_NUMB, gridData->mVersion, 1u, Codec::NONE}; #endif const char* gridName = gridData->gridName(); const uint32_t nameSize = util::strlen(gridName) + 1;// include '\0' const TreeData* treeData = (const TreeData*)(gridData->treePtr()); NANOVDB_ASSERT(gridData->mBlindMetadataCount <= uint32_t( 1u << 16 ));// due to uint32_t -> uin16_t conversion FileMetaData meta{gridData->mGridSize, gridData->mGridSize, 0u, treeData->mVoxelCount, gridData->mGridType, gridData->mGridClass, gridData->mWorldBBox, treeData->bbox(), gridData->mVoxelSize, nameSize, {treeData->mNodeCount[0], treeData->mNodeCount[1], treeData->mNodeCount[2], 1u}, {treeData->mTileCount[0], treeData->mTileCount[1], treeData->mTileCount[2]}, Codec::NONE, uint16_t(gridData->mBlindMetadataCount), gridData->mVersion }; // FileMetaData os.write((const char*)&head, sizeof(FileHeader)); // write header os.write((const char*)&meta, sizeof(FileMetaData)); // write meta data os.write(gridName, nameSize); // write grid name } if (gridData->mGridCount!=1 || gridData->mGridIndex != 0) { GridData data; data = *gridData;// deep copy data.mGridIndex = 0; data.mGridCount = 1; os.write((const char*)&data, sizeof(GridData)); os.write((const char*)gridData + sizeof(GridData), gridData->mGridSize - sizeof(GridData)); } else { os.write((const char*)gridData, gridData->mGridSize);// write the grid } }// writeUncompressedGrid /// @brief Write an IndexGrid to a stream and append blind data /// @tparam StreamT Type of stream to write the IndexGrid and blind data to /// @tparam ValueT Type of the blind data /// @param os Output stream to write to /// @param gridData GridData containing an IndexGrid WITHOUT existing blind data /// @param blindData Raw point to array of blind data /// @param semantic GridBlindDataSemantic of the blind data /// @param raw If true the IndexGrid and blind data are streamed raw, i.e. without a file header. template // StreamT class must support: "void write(const char*, size_t)" void writeUncompressedGrid(StreamT& os, const GridData* gridData, const ValueT *blindData, GridBlindDataSemantic semantic = GridBlindDataSemantic::Unknown, bool raw = false) { NANOVDB_ASSERT(gridData->mMagic == NANOVDB_MAGIC_NUMB || gridData->mMagic == NANOVDB_MAGIC_GRID); NANOVDB_ASSERT(gridData->mVersion.isCompatible()); NANOVDB_ASSERT(blindData); char str[256]; if (gridData->mGridClass != GridClass::IndexGrid) { fprintf(stderr, "nanovdb::writeUncompressedGrid: expected an IndexGrid but got \"%s\"\n", toStr(str, gridData->mGridClass)); exit(EXIT_FAILURE); } else if (gridData->mBlindMetadataCount != 0u) {// to-do: allow for existing blind data in grid fprintf(stderr, "nanovdb::writeUncompressedGrid: index grid already has \"%i\" blind data\n", gridData->mBlindMetadataCount); exit(EXIT_FAILURE); } const size_t gridSize = gridData->mGridSize + sizeof(GridBlindMetaData) + gridData->mData1*sizeof(ValueT); if (!raw) {// segment with a single grid: FileHeader, FileMetaData, gridName, Grid #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS FileHeader head{NANOVDB_MAGIC_FILE, gridData->mVersion, 1u/*grid count*/, Codec::NONE}; #else FileHeader head{NANOVDB_MAGIC_NUMB, gridData->mVersion, 1u/*grid count*/, Codec::NONE}; #endif const char* gridName = gridData->gridName(); const uint32_t nameSize = util::strlen(gridName) + 1;// include '\0' const TreeData* treeData = (const TreeData*)(gridData->treePtr()); FileMetaData meta{gridSize, gridSize, 0u, treeData->mVoxelCount, gridData->mGridType, gridData->mGridClass, gridData->mWorldBBox, treeData->bbox(), gridData->mVoxelSize, nameSize, {treeData->mNodeCount[0], treeData->mNodeCount[1], treeData->mNodeCount[2], 1u}, {treeData->mTileCount[0], treeData->mTileCount[1], treeData->mTileCount[2]}, Codec::NONE, 1u, gridData->mVersion }; // FileMetaData os.write((const char*)&head, sizeof(FileHeader)); // write header os.write((const char*)&meta, sizeof(FileMetaData)); // write meta data os.write(gridName, nameSize); // write grid name }// if (!raw) GridData data; data = *gridData;// deep copy data.mGridIndex = 0; data.mGridCount = 1; data.mGridSize = gridSize;// increment by blind data + meta data data.mBlindMetadataCount = 1u; data.mBlindMetadataOffset = gridData->mGridSize; os.write((const char*)&data, sizeof(GridData)); os.write((const char*)gridData + sizeof(GridData), gridData->mGridSize - sizeof(GridData));// write the IndexGrid GridBlindMetaData meta(sizeof(GridBlindMetaData), gridData->mData1, sizeof(ValueT), semantic, GridBlindDataClass::ChannelArray, toGridType()); meta.setName("channel_0"); os.write((const char*)&meta, sizeof(GridBlindMetaData)); os.write((const char*)blindData, gridData->mData1*sizeof(ValueT)); }// writeUncompressedGrid /// @brief write multiple NanoVDB grids to a single file, without compression. /// @note To write all grids in a single GridHandle simply use handle.write("fieNane") template class VecT> void writeUncompressedGrids(const char* fileName, const VecT& handles, bool raw = false) { #ifdef NANOVDB_USE_IOSTREAMS // use this to switch between std::ofstream or FILE implementations std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc); #else struct StreamT { FILE* fptr; StreamT(const char* name) { fptr = fopen(name, "wb"); } ~StreamT() { fclose(fptr); } void write(const char* data, size_t n) { fwrite(data, 1, n, fptr); } bool is_open() const { return fptr != NULL; } } os(fileName); #endif if (!os.is_open()) { fprintf(stderr, "nanovdb::writeUncompressedGrids: Unable to open file \"%s\"for output\n", fileName); exit(EXIT_FAILURE); } for (auto& h : handles) { for (uint32_t n=0; n class VecT> VecT readUncompressedGrids(StreamT& is, const typename GridHandleT::BufferType& pool = typename GridHandleT::BufferType()) { VecT handles; GridData data; is.read((char*)&data, sizeof(GridData)); if (data.isValid()) {// stream contains a raw grid buffer uint64_t size = data.mGridSize, sum = 0u; while(data.mGridIndex + 1u < data.mGridCount) { is.skip(data.mGridSize - sizeof(GridData));// skip grid is.read((char*)&data, sizeof(GridData));// read sizeof(GridData) bytes sum += data.mGridSize; } is.skip(-int64_t(sum + sizeof(GridData)));// rewind to start auto buffer = GridHandleT::BufferType::create(size + sum, &pool); is.read((char*)(buffer.data()), buffer.size()); handles.emplace_back(std::move(buffer)); } else {// Header0, MetaData0, gridName0, Grid0...HeaderN, MetaDataN, gridNameN, GridN is.skip(-sizeof(GridData));// rewind FileHeader head; while(is.read((char*)&head, sizeof(FileHeader))) { if (!head.isValid()) { fprintf(stderr, "nanovdb::readUncompressedGrids: invalid magic number = \"%s\"\n", (const char*)&(head.magic)); exit(EXIT_FAILURE); } else if (!head.version.isCompatible()) { char str[20]; fprintf(stderr, "nanovdb::readUncompressedGrids: invalid major version = \"%s\"\n", toStr(str, head.version)); exit(EXIT_FAILURE); } else if (head.codec != Codec::NONE) { char str[8]; fprintf(stderr, "nanovdb::readUncompressedGrids: invalid codec = \"%s\"\n", toStr(str, head.codec)); exit(EXIT_FAILURE); } FileMetaData meta; for (uint16_t i = 0; i < head.gridCount; ++i) { // read all grids in segment is.read((char*)&meta, sizeof(FileMetaData));// read meta data is.skip(meta.nameSize); // skip grid name auto buffer = GridHandleT::BufferType::create(meta.gridSize, &pool); is.read((char*)buffer.data(), meta.gridSize);// read grid handles.emplace_back(std::move(buffer)); }// loop over grids in segment }// loop over segments } return handles; } // readUncompressedGrids /// @brief Read a multiple un-compressed NanoVDB grids from a file and return them as a vector. template class VecT> VecT readUncompressedGrids(const char* fileName, const typename GridHandleT::BufferType& buffer = typename GridHandleT::BufferType()) { #ifdef NANOVDB_USE_IOSTREAMS // use this to switch between std::ifstream or FILE implementations struct StreamT : public std::ifstream { StreamT(const char* name) : std::ifstream(name, std::ios::in | std::ios::binary){} void skip(int64_t off) { this->seekg(off, std::ios_base::cur); } }; #else struct StreamT { FILE* fptr; StreamT(const char* name) { fptr = fopen(name, "rb"); } ~StreamT() { fclose(fptr); } bool read(char* data, size_t n) { size_t m = fread(data, 1, n, fptr); return n == m; } void skip(int64_t off) { fseek(fptr, (long int)off, SEEK_CUR); } bool is_open() const { return fptr != NULL; } }; #endif StreamT is(fileName); if (!is.is_open()) { fprintf(stderr, "nanovdb::readUncompressedGrids: Unable to open file \"%s\"for input\n", fileName); exit(EXIT_FAILURE); } return readUncompressedGrids(is, buffer); } // readUncompressedGrids #endif // if !defined(__CUDA_ARCH__) && !defined(__HIP__) } // namespace io // ----------------------------> Implementations of random access methods <-------------------------------------- /** * @brief Below is an example of a struct used for random get methods. * @note All member methods, data, and types are mandatory. * @code template struct GetOpT { using Type = typename BuildToValueMap::Type;// return type static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot& root, args...) { } __hostdev__ static Type get(const typename NanoRoot::Tile& tile, args...) { } __hostdev__ static Type get(const NanoUpper& node, uint32_t n, args...) { } __hostdev__ static Type get(const NanoLower& node, uint32_t n, args...) { } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t n, args...) { } }; @endcode * @brief Below is an example of the struct used for random set methods * @note All member methods and data are mandatory. * @code template struct SetOpT { static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static void set(NanoRoot& root, args...) { } __hostdev__ static void set(typename NanoRoot::Tile& tile, args...) { } __hostdev__ static void set(NanoUpper& node, uint32_t n, args...) { } __hostdev__ static void set(NanoLower& node, uint32_t n, args...) { } __hostdev__ static void set(NanoLeaf& leaf, uint32_t n, args...) { } }; @endcode **/ /// @brief Implements Tree::getValue(math::Coord), i.e. return the value associated with a specific coordinate @c ijk. /// @tparam BuildT Build type of the grid being called /// @details The value at a coordinate either maps to the background, a tile value or a leaf value. template struct GetValue { using Type = typename NanoLeaf::ValueType; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot& root) { return root.mBackground; } __hostdev__ static Type get(const typename NanoRoot::Tile& tile) { return tile.value; } __hostdev__ static Type get(const NanoUpper& node, uint32_t n) { return node.mTable[n].value; } __hostdev__ static Type get(const NanoLower& node, uint32_t n) { return node.mTable[n].value; } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t n) { return leaf.getValue(n); } // works with all build types }; // GetValue template struct SetValue { static_assert(!BuildTraits::is_special, "SetValue does not support special value types, e.g. Fp4, Fp8, Fp16, FpN"); using ValueT = typename NanoLeaf::ValueType; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static void set(NanoRoot&, const ValueT&) {} // no-op __hostdev__ static void set(typename NanoRoot::Tile& tile, const ValueT& v) { tile.value = v; } __hostdev__ static void set(NanoUpper& node, uint32_t n, const ValueT& v) { node.mTable[n].value = v; } __hostdev__ static void set(NanoLower& node, uint32_t n, const ValueT& v) { node.mTable[n].value = v; } __hostdev__ static void set(NanoLeaf& leaf, uint32_t n, const ValueT& v) { leaf.mValues[n] = v; } }; // SetValue template struct SetVoxel { static_assert(!BuildTraits::is_special, "SetVoxel does not support special value types. e.g. Fp4, Fp8, Fp16, FpN"); using ValueT = typename NanoLeaf::ValueType; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static void set(NanoRoot&, const ValueT&) {} // no-op __hostdev__ static void set(typename NanoRoot::Tile&, const ValueT&) {} // no-op __hostdev__ static void set(NanoUpper&, uint32_t, const ValueT&) {} // no-op __hostdev__ static void set(NanoLower&, uint32_t, const ValueT&) {} // no-op __hostdev__ static void set(NanoLeaf& leaf, uint32_t n, const ValueT& v) { leaf.mValues[n] = v; } }; // SetVoxel /// @brief Implements Tree::isActive(math::Coord) /// @tparam BuildT Build type of the grid being called template struct GetState { using Type = bool; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return false; } __hostdev__ static Type get(const typename NanoRoot::Tile& tile) { return tile.state > 0; } __hostdev__ static Type get(const NanoUpper& node, uint32_t n) { return node.mValueMask.isOn(n); } __hostdev__ static Type get(const NanoLower& node, uint32_t n) { return node.mValueMask.isOn(n); } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t n) { return leaf.mValueMask.isOn(n); } }; // GetState /// @brief Implements Tree::getDim(math::Coord) /// @tparam BuildT Build type of the grid being called template struct GetDim { using Type = uint32_t; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return 0u; } // background __hostdev__ static Type get(const typename NanoRoot::Tile&) { return 4096u; } __hostdev__ static Type get(const NanoUpper&, uint32_t) { return 128u; } __hostdev__ static Type get(const NanoLower&, uint32_t) { return 8u; } __hostdev__ static Type get(const NanoLeaf&, uint32_t) { return 1u; } }; // GetDim /// @brief Return the pointer to the leaf node that contains math::Coord. Implements Tree::probeLeaf(math::Coord) /// @tparam BuildT Build type of the grid being called template struct GetLeaf { using Type = const NanoLeaf*; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return nullptr; } __hostdev__ static Type get(const typename NanoRoot::Tile&) { return nullptr; } __hostdev__ static Type get(const NanoUpper&, uint32_t) { return nullptr; } __hostdev__ static Type get(const NanoLower&, uint32_t) { return nullptr; } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t) { return &leaf; } }; // GetLeaf /// @brief Return point to the lower internal node where math::Coord maps to one of its values, i.e. terminates /// @tparam BuildT Build type of the grid being called template struct GetLower { using Type = const NanoLower*; static constexpr int LEVEL = 1;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return nullptr; } __hostdev__ static Type get(const typename NanoRoot::Tile&) { return nullptr; } __hostdev__ static Type get(const NanoUpper&, uint32_t) { return nullptr; } __hostdev__ static Type get(const NanoLower& node, uint32_t) { return &node; } }; // GetLower /// @brief Return point to the upper internal node where math::Coord maps to one of its values, i.e. terminates /// @tparam BuildT Build type of the grid being called template struct GetUpper { using Type = const NanoUpper*; static constexpr int LEVEL = 2;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return nullptr; } __hostdev__ static Type get(const typename NanoRoot::Tile&) { return nullptr; } __hostdev__ static Type get(const NanoUpper& node, uint32_t) { return &node; } }; // GetUpper /// @brief Return point to the root Tile where math::Coord maps to one of its values, i.e. terminates /// @tparam BuildT Build type of the grid being called template struct GetTile { using Type = const typename NanoRoot::Tile*; static constexpr int LEVEL = 3;// minimum level for the descent during top-down traversal __hostdev__ static Type get(const NanoRoot&) { return nullptr; } __hostdev__ static Type get(const typename NanoRoot::Tile &tile) { return &tile; } }; // GetTile /// @brief Implements Tree::probeLeaf(math::Coord) /// @tparam BuildT Build type of the grid being called template struct ProbeValue { using Type = bool; static constexpr int LEVEL = 0;// minimum level for the descent during top-down traversal using ValueT = typename BuildToValueMap::Type; __hostdev__ static Type get(const NanoRoot& root, ValueT& v) { v = root.mBackground; return false; } __hostdev__ static Type get(const typename NanoRoot::Tile& tile, ValueT& v) { v = tile.value; return tile.state > 0u; } __hostdev__ static Type get(const NanoUpper& node, uint32_t n, ValueT& v) { v = node.mTable[n].value; return node.mValueMask.isOn(n); } __hostdev__ static Type get(const NanoLower& node, uint32_t n, ValueT& v) { v = node.mTable[n].value; return node.mValueMask.isOn(n); } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t n, ValueT& v) { v = leaf.getValue(n); return leaf.mValueMask.isOn(n); } }; // ProbeValue /// @brief Implements Tree::getNodeInfo(math::Coord) /// @tparam BuildT Build type of the grid being called template struct GetNodeInfo { using ValueType = typename NanoLeaf::ValueType; using FloatType = typename NanoLeaf::FloatType; struct NodeInfo { uint32_t level, dim; ValueType minimum, maximum; FloatType average, stdDevi; CoordBBox bbox; }; static constexpr int LEVEL = 0; using Type = NodeInfo; __hostdev__ static Type get(const NanoRoot& root) { return NodeInfo{3u, NanoUpper::DIM, root.minimum(), root.maximum(), root.average(), root.stdDeviation(), root.bbox()}; } __hostdev__ static Type get(const typename NanoRoot::Tile& tile) { return NodeInfo{3u, NanoUpper::DIM, tile.value, tile.value, static_cast(tile.value), 0, CoordBBox::createCube(tile.origin(), NanoUpper::DIM)}; } __hostdev__ static Type get(const NanoUpper& node, uint32_t n) { return NodeInfo{2u, node.dim(), node.minimum(), node.maximum(), node.average(), node.stdDeviation(), node.bbox()}; } __hostdev__ static Type get(const NanoLower& node, uint32_t n) { return NodeInfo{1u, node.dim(), node.minimum(), node.maximum(), node.average(), node.stdDeviation(), node.bbox()}; } __hostdev__ static Type get(const NanoLeaf& leaf, uint32_t n) { return NodeInfo{0u, leaf.dim(), leaf.minimum(), leaf.maximum(), leaf.average(), leaf.stdDeviation(), leaf.bbox()}; } }; // GetNodeInfo } // namespace nanovdb =================================================================== #endif // end of NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/NodeManager.h000066400000000000000000000337671510223237100206530ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/NodeManager.h \author Ken Museth \date February 12, 2021 \brief This class allows for sequential access to nodes in a NanoVDB tree on both the host and device. \details The ordering of the sequential access to nodes is always breadth-first! */ #include // for NanoGrid etc #include // for HostBuffer #ifndef NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED #define NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED namespace nanovdb { /// @brief NodeManager allows for sequential access to nodes template class NodeManager; /// @brief NodeManagerHandle manages the memory of a NodeManager template class NodeManagerHandle; /// @brief brief Construct a NodeManager and return its handle /// /// @param grid grid whose nodes will be accessed sequentially /// @param buffer buffer from which to allocate the output handle /// /// @note This is the only way to create a NodeManager since it's using /// managed memory pointed to by a NodeManagerHandle. template NodeManagerHandle createNodeManager(const NanoGrid &grid, const BufferT& buffer = BufferT()); struct NodeManagerData {// 40B = 5*8B __hostdev__ NodeManagerData(void *grid) : mPadding{0}, mGrid(grid), mPtr{0,0,0}{} union {int64_t mPadding; uint8_t mLinear;};// 8B of which 1B is used for a binary flag void *mGrid;// 8B pointer to either host or device grid union {int64_t *mPtr[3], mOff[3];};// 24B, use mOff if mLinear!=0 }; /// @brief This class serves to manage a raw memory buffer of a NanoVDB NodeManager or LeafManager. template class NodeManagerHandle { GridType mGridType{GridType::Unknown}; BufferT mBuffer; template const NodeManager* getMgr() const { return mGridType == toGridType() ? (const NodeManager*)mBuffer.data() : nullptr; } template typename util::enable_if::hasDeviceDual, const NodeManager*>::type getDeviceMgr() const { return mGridType == toGridType() ? (const NodeManager*)mBuffer.deviceData() : nullptr; } template static T* no_const(const T* ptr) { return const_cast(ptr); } public: /// @brief Move constructor from a buffer NodeManagerHandle(GridType gridType, BufferT&& buffer) : mGridType(gridType) { mBuffer = std::move(buffer); } /// @brief Empty ctor NodeManagerHandle() = default; /// @brief Disallow copy-construction NodeManagerHandle(const NodeManagerHandle&) = delete; /// @brief Disallow copy assignment operation NodeManagerHandle& operator=(const NodeManagerHandle&) = delete; /// @brief Move copy assignment operation NodeManagerHandle& operator=(NodeManagerHandle&& other) noexcept { mGridType = other.mGridType; mBuffer = std::move(other.mBuffer); other.mGridType = GridType::Unknown; return *this; } /// @brief Move copy-constructor NodeManagerHandle(NodeManagerHandle&& other) noexcept { mGridType = other.mGridType; mBuffer = std::move(other.mBuffer); other.mGridType = GridType::Unknown; } /// @brief Default destructor ~NodeManagerHandle() { this->reset(); } /// @brief clear the buffer void reset() { mBuffer.clear(); } /// @brief Return a reference to the buffer BufferT& buffer() { return mBuffer; } /// @brief Return a const reference to the buffer const BufferT& buffer() const { return mBuffer; } /// @brief Returns a non-const pointer to the data. /// /// @warning Note that the return pointer can be NULL if the NodeManagerHandle was not initialized void* data() { return mBuffer.data(); } /// @brief Returns a const pointer to the data. /// /// @warning Note that the return pointer can be NULL if the NodeManagerHandle was not initialized const void* data() const { return mBuffer.data(); } /// @brief Returns the size in bytes of the raw memory buffer managed by this NodeManagerHandle's allocator. uint64_t size() const { return mBuffer.size(); } /// @brief Returns a const pointer to the NodeManager encoded in this NodeManagerHandle. /// /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid! template const NodeManager* mgr() const { return this->template getMgr(); } /// @brief Returns a pointer to the NodeManager encoded in this NodeManagerHandle. /// /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid! template NodeManager* mgr() { return no_const(this->template getMgr()); } /// @brief Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device, e.g. GPU /// /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid! template typename util::enable_if::hasDeviceDual, const NodeManager*>::type deviceMgr() const { return this->template getDeviceMgr(); } /// @brief Return a const pointer to the NodeManager encoded in this NodeManagerHandle on the device, e.g. GPU /// /// @warning Note that the return pointer can be NULL if the template parameter does not match the specified grid! template typename util::enable_if::hasDeviceDual, NodeManager*>::type deviceMgr() { return no_const(this->template getDeviceMgr()); } /// @brief Upload the NodeManager to the device, e.g. from CPU to GPU /// /// @note This method is only available if the buffer supports devices template typename util::enable_if::hasDeviceDual, void>::type deviceUpload(void* deviceGrid, void* stream = nullptr, bool sync = true) { assert(deviceGrid); auto *data = reinterpret_cast(mBuffer.data()); void *tmp = data->mGrid; data->mGrid = deviceGrid; mBuffer.deviceUpload(stream, sync); data->mGrid = tmp; } /// @brief Download the NodeManager to from the device, e.g. from GPU to CPU /// /// @note This method is only available if the buffer supports devices template typename util::enable_if::hasDeviceDual, void>::type deviceDownload(void* stream = nullptr, bool sync = true) { auto *data = reinterpret_cast(mBuffer.data()); void *tmp = data->mGrid; mBuffer.deviceDownload(stream, sync); data->mGrid = tmp; } };// NodeManagerHandle /// @brief This class allows for sequential access to nodes in a NanoVDB tree /// /// @details Nodes are always arranged breadth first during sequential access of nodes /// at a particular level. template class NodeManager : private NodeManagerData { using DataT = NodeManagerData; using GridT = NanoGrid; using TreeT = typename GridTree::type; template using NodeT = typename NodeTrait::type; using RootT = NodeT<3>;// root node using Node2 = NodeT<2>;// upper internal node using Node1 = NodeT<1>;// lower internal node using Node0 = NodeT<0>;// leaf node public: static constexpr bool FIXED_SIZE = Node0::FIXED_SIZE && Node1::FIXED_SIZE && Node2::FIXED_SIZE; NodeManager(const NodeManager&) = delete; NodeManager(NodeManager&&) = delete; NodeManager& operator=(const NodeManager&) = delete; NodeManager& operator=(NodeManager&&) = delete; ~NodeManager() = delete; /// @brief return true if the nodes have both fixed size and are arranged breadth-first in memory. /// This allows for direct and memory-efficient linear access to nodes. __hostdev__ static bool isLinear(const GridT &grid) {return FIXED_SIZE && grid.isBreadthFirst();} /// @brief return true if the nodes have both fixed size and are arranged breadth-first in memory. /// This allows for direct and memory-efficient linear access to nodes. __hostdev__ bool isLinear() const {return DataT::mLinear!=0u;} /// @brief Return the memory footprint in bytes of the NodeManager derived from the specified grid __hostdev__ static uint64_t memUsage(const GridT &grid) { uint64_t size = sizeof(NodeManagerData); if (!NodeManager::isLinear(grid)) { const uint32_t *p = grid.tree().mNodeCount; size += sizeof(int64_t)*(p[0]+p[1]+p[2]); } return size; } /// @brief Return the memory footprint in bytes of this instance __hostdev__ uint64_t memUsage() const {return NodeManager::memUsage(this->grid());} /// @brief Return a reference to the grid __hostdev__ GridT& grid() { return *reinterpret_cast(DataT::mGrid); } __hostdev__ const GridT& grid() const { return *reinterpret_cast(DataT::mGrid); } /// @brief Return a reference to the tree __hostdev__ TreeT& tree() { return this->grid().tree(); } __hostdev__ const TreeT& tree() const { return this->grid().tree(); } /// @brief Return a reference to the root __hostdev__ RootT& root() { return this->tree().root(); } __hostdev__ const RootT& root() const { return this->tree().root(); } /// @brief Return the number of tree nodes at the specified level /// @details 0 is leaf, 1 is lower internal, and 2 is upper internal level __hostdev__ uint64_t nodeCount(int level) const { return this->tree().nodeCount(level); } __hostdev__ uint64_t leafCount() const { return this->tree().nodeCount(0); } __hostdev__ uint64_t lowerCount() const { return this->tree().nodeCount(1); } __hostdev__ uint64_t upperCount() const { return this->tree().nodeCount(2); } /// @brief Return the i'th leaf node with respect to breadth-first ordering template __hostdev__ const NodeT& node(uint32_t i) const { NANOVDB_ASSERT(i < this->nodeCount(LEVEL)); const NodeT* ptr = nullptr; if (DataT::mLinear) { ptr = util::PtrAdd>(DataT::mGrid, DataT::mOff[LEVEL]) + i; } else { ptr = util::PtrAdd>(DataT::mGrid, DataT::mPtr[LEVEL][i]); } NANOVDB_ASSERT(ptr && isAligned(ptr)); return *ptr; } /// @brief Return the i'th node with respect to breadth-first ordering template __hostdev__ NodeT& node(uint32_t i) { NANOVDB_ASSERT(i < this->nodeCount(LEVEL)); NodeT* ptr = nullptr; if (DataT::mLinear) { ptr = util::PtrAdd>(DataT::mGrid, DataT::mOff[LEVEL]) + i; } else { ptr = util::PtrAdd>(DataT::mGrid, DataT::mPtr[LEVEL][i]); } NANOVDB_ASSERT(ptr && isAligned(ptr)); return *ptr; } /// @brief Return the i'th leaf node with respect to breadth-first ordering __hostdev__ const Node0& leaf(uint32_t i) const { return this->node<0>(i); } __hostdev__ Node0& leaf(uint32_t i) { return this->node<0>(i); } /// @brief Return the i'th lower internal node with respect to breadth-first ordering __hostdev__ const Node1& lower(uint32_t i) const { return this->node<1>(i); } __hostdev__ Node1& lower(uint32_t i) { return this->node<1>(i); } /// @brief Return the i'th upper internal node with respect to breadth-first ordering __hostdev__ const Node2& upper(uint32_t i) const { return this->node<2>(i); } __hostdev__ Node2& upper(uint32_t i) { return this->node<2>(i); } }; // NodeManager class template NodeManagerHandle createNodeManager(const NanoGrid &grid, const BufferT& buffer) { NodeManagerHandle handle(toGridType(), BufferT::create(NodeManager::memUsage(grid), &buffer)); auto *data = reinterpret_cast(handle.data()); NANOVDB_ASSERT(data && isAligned(data)); NANOVDB_ASSERT(toGridType() == grid.gridType()); *data = NodeManagerData((void*)&grid); if (NodeManager::isLinear(grid)) { data->mLinear = uint8_t(1u); data->mOff[0] = util::PtrDiff(grid.tree().template getFirstNode<0>(), &grid); data->mOff[1] = util::PtrDiff(grid.tree().template getFirstNode<1>(), &grid); data->mOff[2] = util::PtrDiff(grid.tree().template getFirstNode<2>(), &grid); } else { int64_t *ptr0 = data->mPtr[0] = reinterpret_cast(data + 1); int64_t *ptr1 = data->mPtr[1] = data->mPtr[0] + grid.tree().nodeCount(0); int64_t *ptr2 = data->mPtr[2] = data->mPtr[1] + grid.tree().nodeCount(1); // Performs depth first traversal but breadth first insertion for (auto it2 = grid.tree().root().cbeginChild(); it2; ++it2) { *ptr2++ = util::PtrDiff(&*it2, &grid); for (auto it1 = it2->cbeginChild(); it1; ++it1) { *ptr1++ = util::PtrDiff(&*it1, &grid); for (auto it0 = it1->cbeginChild(); it0; ++it0) { *ptr0++ = util::PtrDiff(&*it0, &grid); }// loop over child nodes of the lower internal node }// loop over child nodes of the upper internal node }// loop over child nodes of the root node } return handle;// // is converted to r-value so return value is move constructed! }// createNodeManager } // namespace nanovdb #if defined(__CUDACC__) #include #endif// defined(__CUDACC__) #endif // NANOVDB_NODEMANAGER_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/PNanoVDB.h000066400000000000000000005274171510223237100200420ustar00rootroot00000000000000 // Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/PNanoVDB.h \author Andrew Reidmeyer \brief This file is a portable (e.g. pointer-less) C99/GLSL/HLSL port of NanoVDB.h, which is compatible with most graphics APIs. */ #ifndef NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED #define NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED // ------------------------------------------------ Configuration ----------------------------------------------------------- // platforms //#define PNANOVDB_C //#define PNANOVDB_HLSL //#define PNANOVDB_GLSL // addressing mode // PNANOVDB_ADDRESS_32 // PNANOVDB_ADDRESS_64 #if defined(PNANOVDB_C) #ifndef PNANOVDB_ADDRESS_32 #define PNANOVDB_ADDRESS_64 #endif #elif defined(PNANOVDB_HLSL) #ifndef PNANOVDB_ADDRESS_64 #define PNANOVDB_ADDRESS_32 #endif #elif defined(PNANOVDB_GLSL) #ifndef PNANOVDB_ADDRESS_64 #define PNANOVDB_ADDRESS_32 #endif #endif // bounds checking //#define PNANOVDB_BUF_BOUNDS_CHECK // enable HDDA by default on HLSL/GLSL, make explicit on C #if defined(PNANOVDB_C) //#define PNANOVDB_HDDA #ifdef PNANOVDB_HDDA #ifndef PNANOVDB_CMATH #define PNANOVDB_CMATH #endif #endif #elif defined(PNANOVDB_HLSL) #define PNANOVDB_HDDA #elif defined(PNANOVDB_GLSL) #define PNANOVDB_HDDA #endif #ifdef PNANOVDB_CMATH #ifndef __CUDACC_RTC__ #include #endif #endif // ------------------------------------------------ Buffer ----------------------------------------------------------- #if defined(PNANOVDB_BUF_CUSTOM) // NOP #elif defined(PNANOVDB_C) #define PNANOVDB_BUF_C #elif defined(PNANOVDB_HLSL) #define PNANOVDB_BUF_HLSL #elif defined(PNANOVDB_GLSL) #define PNANOVDB_BUF_GLSL #endif #if defined(PNANOVDB_BUF_C) #ifndef __CUDACC_RTC__ #include #endif #if defined(__CUDACC__) #define PNANOVDB_BUF_FORCE_INLINE static __host__ __device__ __forceinline__ #elif defined(_WIN32) #define PNANOVDB_BUF_FORCE_INLINE static inline __forceinline #else #define PNANOVDB_BUF_FORCE_INLINE static inline __attribute__((always_inline)) #endif typedef struct pnanovdb_buf_t { uint32_t* data; #ifdef PNANOVDB_BUF_BOUNDS_CHECK uint64_t size_in_words; #endif }pnanovdb_buf_t; PNANOVDB_BUF_FORCE_INLINE pnanovdb_buf_t pnanovdb_make_buf(uint32_t* data, uint64_t size_in_words) { pnanovdb_buf_t ret; ret.data = data; #ifdef PNANOVDB_BUF_BOUNDS_CHECK ret.size_in_words = size_in_words; #endif return ret; } #if defined(PNANOVDB_ADDRESS_32) PNANOVDB_BUF_FORCE_INLINE uint32_t pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint32_t byte_offset) { uint32_t wordaddress = (byte_offset >> 2u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK return wordaddress < buf.size_in_words ? buf.data[wordaddress] : 0u; #else return buf.data[wordaddress]; #endif } PNANOVDB_BUF_FORCE_INLINE uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint32_t byte_offset) { uint64_t* data64 = (uint64_t*)buf.data; uint32_t wordaddress64 = (byte_offset >> 3u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK uint64_t size_in_words64 = buf.size_in_words >> 1u; return wordaddress64 < size_in_words64 ? data64[wordaddress64] : 0llu; #else return data64[wordaddress64]; #endif } PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint32_t byte_offset, uint32_t value) { uint32_t wordaddress = (byte_offset >> 2u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK if (wordaddress < buf.size_in_words) { buf.data[wordaddress] = value; } #else buf.data[wordaddress] = value; #endif } PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint32_t byte_offset, uint64_t value) { uint64_t* data64 = (uint64_t*)buf.data; uint32_t wordaddress64 = (byte_offset >> 3u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK uint64_t size_in_words64 = buf.size_in_words >> 1u; if (wordaddress64 < size_in_words64) { data64[wordaddress64] = value; } #else data64[wordaddress64] = value; #endif } #elif defined(PNANOVDB_ADDRESS_64) PNANOVDB_BUF_FORCE_INLINE uint32_t pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint64_t byte_offset) { uint64_t wordaddress = (byte_offset >> 2u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK return wordaddress < buf.size_in_words ? buf.data[wordaddress] : 0u; #else return buf.data[wordaddress]; #endif } PNANOVDB_BUF_FORCE_INLINE uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint64_t byte_offset) { uint64_t* data64 = (uint64_t*)buf.data; uint64_t wordaddress64 = (byte_offset >> 3u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK uint64_t size_in_words64 = buf.size_in_words >> 1u; return wordaddress64 < size_in_words64 ? data64[wordaddress64] : 0llu; #else return data64[wordaddress64]; #endif } PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint64_t byte_offset, uint32_t value) { uint64_t wordaddress = (byte_offset >> 2u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK if (wordaddress < buf.size_in_words) { buf.data[wordaddress] = value; } #else buf.data[wordaddress] = value; #endif } PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint64_t byte_offset, uint64_t value) { uint64_t* data64 = (uint64_t*)buf.data; uint64_t wordaddress64 = (byte_offset >> 3u); #ifdef PNANOVDB_BUF_BOUNDS_CHECK uint64_t size_in_words64 = buf.size_in_words >> 1u; if (wordaddress64 < size_in_words64) { data64[wordaddress64] = value; } #else data64[wordaddress64] = value; #endif } #endif typedef uint32_t pnanovdb_grid_type_t; #define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn #elif defined(PNANOVDB_BUF_HLSL) #if defined(PNANOVDB_BUF_HLSL_RW) #if defined(PNANOVDB_BUF_HLSL_64) #define pnanovdb_buf_t RWStructuredBuffer #else #define pnanovdb_buf_t RWStructuredBuffer #endif #else #if defined(PNANOVDB_BUF_HLSL_64) #define pnanovdb_buf_t StructuredBuffer #else #define pnanovdb_buf_t StructuredBuffer #endif #endif #if defined(PNANOVDB_ADDRESS_32) uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint byte_offset) { #if defined(PNANOVDB_BUF_HLSL_64) uint2 val = buf[(byte_offset >> 3u)]; return ((byte_offset & 4u) == 0u) ? val.x : val.y; #else return buf[(byte_offset >> 2u)]; #endif } uint2 pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint byte_offset) { uint2 ret; #if defined(PNANOVDB_BUF_HLSL_64) ret = buf[(byte_offset >> 3u)]; #else ret.x = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); ret.y = pnanovdb_buf_read_uint32(buf, byte_offset + 4u); #endif return ret; } void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint byte_offset, uint value) { // NOP, by default no write in HLSL #if defined(PNANOVDB_BUF_HLSL_RW) #if defined(PNANOVDB_BUF_HLSL_64) if ((byte_offset & 4u) == 0u) {buf[(byte_offset >> 3u)].x = value;} else {buf[(byte_offset >> 3u)].y = value;} #else buf[(byte_offset >> 2u)] = value; #endif #endif } void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint byte_offset, uint2 value) { // NOP, by default no write in HLSL #if defined(PNANOVDB_BUF_HLSL_RW) #if defined(PNANOVDB_BUF_HLSL_64) buf[(byte_offset >> 3u)] = value; #else pnanovdb_buf_write_uint32(buf, byte_offset + 0u, value.x); pnanovdb_buf_write_uint32(buf, byte_offset + 4u, value.y); #endif #endif } #elif defined(PNANOVDB_ADDRESS_64) uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint64_t byte_offset) { #if defined(PNANOVDB_BUF_HLSL_64) uint2 val = buf[uint(byte_offset >> 3u)]; return ((uint(byte_offset) & 4u) == 0u) ? val.x : val.y; #else return buf[uint(byte_offset >> 2u)]; #endif } uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint64_t byte_offset) { uint64_t ret; #if defined(PNANOVDB_BUF_HLSL_64) uint2 raw = buf[uint(byte_offset >> 3u)]; ret = uint64_t(raw.x) | (uint64_t(raw.y) << 32u); #else ret = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); ret = ret | (uint64_t(pnanovdb_buf_read_uint32(buf, byte_offset + 4u)) << 32u); #endif return ret; } void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint64_t byte_offset, uint value) { // NOP, by default no write in HLSL #if defined(PNANOVDB_BUF_HLSL_RW) #if defined(PNANOVDB_BUF_HLSL_64) if ((byte_offset & 4u) == 0u) {buf[uint(byte_offset >> 3u)].x = value;} else {buf[uint(byte_offset >> 3u)].y = value;} #else buf[uint(byte_offset >> 2u)] = value; #endif #endif } void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint64_t byte_offset, uint64_t value) { // NOP, by default no write in HLSL #if defined(PNANOVDB_BUF_HLSL_RW) #if defined(PNANOVDB_BUF_HLSL_64) uint2 raw = uint2(uint(value), uint(value >> 32u)); buf[uint(byte_offset >> 3u)] = raw; #else pnanovdb_buf_write_uint32(buf, byte_offset + 0u, uint(value)); pnanovdb_buf_write_uint32(buf, byte_offset + 4u, uint(value >> 32u)); #endif #endif } #endif #define pnanovdb_grid_type_t uint #define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn #elif defined(PNANOVDB_BUF_GLSL) struct pnanovdb_buf_t { uint unused; // to satisfy min struct size? }; uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint byte_offset) { return pnanovdb_buf_data[(byte_offset >> 2u)]; } uvec2 pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint byte_offset) { uvec2 ret; ret.x = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); ret.y = pnanovdb_buf_read_uint32(buf, byte_offset + 4u); return ret; } void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint byte_offset, uint value) { // NOP, by default no write in HLSL } void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint byte_offset, uvec2 value) { // NOP, by default no write in HLSL } #define pnanovdb_grid_type_t uint #define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn #endif // ------------------------------------------------ Basic Types ----------------------------------------------------------- // force inline #if defined(PNANOVDB_C) #if defined(__CUDACC__) #define PNANOVDB_FORCE_INLINE static __host__ __device__ __forceinline__ #elif defined(_WIN32) #define PNANOVDB_FORCE_INLINE static inline __forceinline #else #define PNANOVDB_FORCE_INLINE static inline __attribute__((always_inline)) #endif #elif defined(PNANOVDB_HLSL) #define PNANOVDB_FORCE_INLINE #elif defined(PNANOVDB_GLSL) #define PNANOVDB_FORCE_INLINE #endif // struct typedef, static const, inout #if defined(PNANOVDB_C) #define PNANOVDB_STRUCT_TYPEDEF(X) typedef struct X X; #if defined(__CUDA_ARCH__) #define PNANOVDB_STATIC_CONST constexpr __constant__ #else #define PNANOVDB_STATIC_CONST static const #endif #define PNANOVDB_INOUT(X) X* #define PNANOVDB_IN(X) const X* #define PNANOVDB_DEREF(X) (*X) #define PNANOVDB_REF(X) &X #elif defined(PNANOVDB_HLSL) #define PNANOVDB_STRUCT_TYPEDEF(X) #define PNANOVDB_STATIC_CONST static const #define PNANOVDB_INOUT(X) inout X #define PNANOVDB_IN(X) X #define PNANOVDB_DEREF(X) X #define PNANOVDB_REF(X) X #elif defined(PNANOVDB_GLSL) #define PNANOVDB_STRUCT_TYPEDEF(X) #define PNANOVDB_STATIC_CONST const #define PNANOVDB_INOUT(X) inout X #define PNANOVDB_IN(X) X #define PNANOVDB_DEREF(X) X #define PNANOVDB_REF(X) X #endif // basic types, type conversion #if defined(PNANOVDB_C) #define PNANOVDB_NATIVE_64 #ifndef __CUDACC_RTC__ #include #endif #if !defined(PNANOVDB_MEMCPY_CUSTOM) #ifndef __CUDACC_RTC__ #include #endif #define pnanovdb_memcpy memcpy #endif typedef uint32_t pnanovdb_uint32_t; typedef int32_t pnanovdb_int32_t; typedef int32_t pnanovdb_bool_t; #define PNANOVDB_FALSE 0 #define PNANOVDB_TRUE 1 typedef uint64_t pnanovdb_uint64_t; typedef int64_t pnanovdb_int64_t; typedef struct pnanovdb_coord_t { pnanovdb_int32_t x, y, z; }pnanovdb_coord_t; typedef struct pnanovdb_vec3_t { float x, y, z; }pnanovdb_vec3_t; typedef struct pnanovdb_uvec4_t { pnanovdb_uint32_t x, y, z, w; }pnanovdb_uvec4_t; typedef struct pnanovdb_ivec4_t { pnanovdb_int32_t x, y, z, w; }pnanovdb_ivec4_t; typedef struct pnanovdb_vec4_t { float x, y, z, w; }pnanovdb_vec4_t; PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return (pnanovdb_int32_t)v; } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return (pnanovdb_int64_t)v; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return (pnanovdb_uint64_t)v; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return (pnanovdb_uint32_t)v; } PNANOVDB_FORCE_INLINE float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { float vf; pnanovdb_memcpy(&vf, &v, sizeof(vf)); return vf; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { pnanovdb_uint32_t vu; pnanovdb_memcpy(&vu, &v, sizeof(vu)); return vu; } PNANOVDB_FORCE_INLINE double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { double vf; pnanovdb_memcpy(&vf, &v, sizeof(vf)); return vf; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { pnanovdb_uint64_t vu; pnanovdb_memcpy(&vu, &v, sizeof(vu)); return vu; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return (pnanovdb_uint32_t)v; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return (pnanovdb_uint32_t)(v >> 32u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return ((pnanovdb_uint64_t)x) | (((pnanovdb_uint64_t)y) << 32u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return ((pnanovdb_uint64_t)x); } PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return a == b; } PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a == 0; } #ifdef PNANOVDB_CMATH PNANOVDB_FORCE_INLINE float pnanovdb_floor(float v) { return floorf(v); } #endif PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return (pnanovdb_int32_t)v; } PNANOVDB_FORCE_INLINE float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return (float)v; } PNANOVDB_FORCE_INLINE float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return (float)v; } PNANOVDB_FORCE_INLINE float pnanovdb_min(float a, float b) { return a < b ? a : b; } PNANOVDB_FORCE_INLINE float pnanovdb_max(float a, float b) { return a > b ? a : b; } #elif defined(PNANOVDB_HLSL) typedef uint pnanovdb_uint32_t; typedef int pnanovdb_int32_t; typedef bool pnanovdb_bool_t; #define PNANOVDB_FALSE false #define PNANOVDB_TRUE true typedef int3 pnanovdb_coord_t; typedef float3 pnanovdb_vec3_t; typedef uint4 pnanovdb_uvec4_t; typedef int4 pnanovdb_ivec4_t; typedef float4 pnanovdb_vec4_t; pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return int(v); } pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return uint(v); } float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { return asfloat(v); } pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { return asuint(v); } float pnanovdb_floor(float v) { return floor(v); } pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return int(v); } float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return float(v); } float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return float(v); } float pnanovdb_min(float a, float b) { return min(a, b); } float pnanovdb_max(float a, float b) { return max(a, b); } #if defined(PNANOVDB_ADDRESS_32) typedef uint2 pnanovdb_uint64_t; typedef int2 pnanovdb_int64_t; pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return int2(v); } pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uint2(v); } double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return asdouble(v.x, v.y); } pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { uint2 ret; asuint(v, ret.x, ret.y); return ret; } pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return v.x; } pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return v.y; } pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uint2(x, y); } pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uint2(x, 0); } bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return (a.x == b.x) && (a.y == b.y); } bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a.x == 0 && a.y == 0; } #else typedef uint64_t pnanovdb_uint64_t; typedef int64_t pnanovdb_int64_t; pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return int64_t(v); } pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uint64_t(v); } double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return asdouble(uint(v), uint(v >> 32u)); } pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { uint2 ret; asuint(v, ret.x, ret.y); return uint64_t(ret.x) + (uint64_t(ret.y) << 32u); } pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return uint(v); } pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return uint(v >> 32u); } pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uint64_t(x) + (uint64_t(y) << 32u); } pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uint64_t(x); } bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return a == b; } bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a == 0; } #endif #elif defined(PNANOVDB_GLSL) #define pnanovdb_uint32_t uint #define pnanovdb_int32_t int #define pnanovdb_bool_t bool #define PNANOVDB_FALSE false #define PNANOVDB_TRUE true #define pnanovdb_uint64_t uvec2 #define pnanovdb_int64_t ivec2 #define pnanovdb_coord_t ivec3 #define pnanovdb_vec3_t vec3 #define pnanovdb_uvec4_t uvec4 #define pnanovdb_ivec4_t ivec4 #define pnanovdb_vec4_t vec4 pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return int(v); } pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return ivec2(v); } pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uvec2(v); } pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return uint(v); } float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { return uintBitsToFloat(v); } pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { return floatBitsToUint(v); } double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return packDouble2x32(uvec2(v.x, v.y)); } pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { return unpackDouble2x32(v); } pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return v.x; } pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return v.y; } pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uvec2(x, y); } pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uvec2(x, 0); } bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return (a.x == b.x) && (a.y == b.y); } bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a.x == 0 && a.y == 0; } float pnanovdb_floor(float v) { return floor(v); } pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return int(v); } float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return float(v); } float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return float(v); } float pnanovdb_min(float a, float b) { return min(a, b); } float pnanovdb_max(float a, float b) { return max(a, b); } #endif // ------------------------------------------------ Coord/Vec3 Utilties ----------------------------------------------------------- #if defined(PNANOVDB_C) PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) { pnanovdb_vec3_t v; v.x = a; v.y = a; v.z = a; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_add(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x + b.x; v.y = a.y + b.y; v.z = a.z + b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_sub(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x - b.x; v.y = a.y - b.y; v.z = a.z - b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_mul(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x * b.x; v.y = a.y * b.y; v.z = a.z * b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_div(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x / b.x; v.y = a.y / b.y; v.z = a.z / b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_min(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x < b.x ? a.x : b.x; v.y = a.y < b.y ? a.y : b.y; v.z = a.z < b.z ? a.z : b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_max(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) { pnanovdb_vec3_t v; v.x = a.x > b.x ? a.x : b.x; v.y = a.y > b.y ? a.y : b.y; v.z = a.z > b.z ? a.z : b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_coord_to_vec3(const pnanovdb_coord_t coord) { pnanovdb_vec3_t v; v.x = pnanovdb_int32_to_float(coord.x); v.y = pnanovdb_int32_to_float(coord.y); v.z = pnanovdb_int32_to_float(coord.z); return v; } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_coord_uniform(const pnanovdb_int32_t a) { pnanovdb_coord_t v; v.x = a; v.y = a; v.z = a; return v; } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) { pnanovdb_coord_t v; v.x = a.x + b.x; v.y = a.y + b.y; v.z = a.z + b.z; return v; } PNANOVDB_FORCE_INLINE pnanovdb_uvec4_t pnanovdb_uvec4_add(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { pnanovdb_uvec4_t ret; ret.x = a.x + b.x; ret.y = a.y + b.y; ret.z = a.z + b.z; ret.w = a.w + b.w; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uvec4_t pnanovdb_uvec4_sub(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { pnanovdb_uvec4_t ret; ret.x = a.x - b.x; ret.y = a.y - b.y; ret.z = a.z - b.z; ret.w = a.w - b.w; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_vec4_t pnanovdb_vec4_add(pnanovdb_vec4_t a, pnanovdb_vec4_t b) { pnanovdb_vec4_t ret; ret.x = a.x + b.x; ret.y = a.y + b.y; ret.z = a.z + b.z; ret.w = a.w + b.w; return ret; } #elif defined(PNANOVDB_HLSL) pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) { return float3(a, a, a); } pnanovdb_vec3_t pnanovdb_vec3_add(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a + b; } pnanovdb_vec3_t pnanovdb_vec3_sub(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a - b; } pnanovdb_vec3_t pnanovdb_vec3_mul(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a * b; } pnanovdb_vec3_t pnanovdb_vec3_div(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a / b; } pnanovdb_vec3_t pnanovdb_vec3_min(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return min(a, b); } pnanovdb_vec3_t pnanovdb_vec3_max(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return max(a, b); } pnanovdb_vec3_t pnanovdb_coord_to_vec3(pnanovdb_coord_t coord) { return float3(coord); } pnanovdb_coord_t pnanovdb_coord_uniform(pnanovdb_int32_t a) { return int3(a, a, a); } pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) { return a + b; } pnanovdb_uvec4_t pnanovdb_uvec4_add(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { return a + b; } pnanovdb_uvec4_t pnanovdb_uvec4_sub(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { return a - b; } pnanovdb_vec4_t pnanovdb_vec4_add(pnanovdb_vec4_t a, pnanovdb_vec4_t b) { return a + b; } #elif defined(PNANOVDB_GLSL) pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) { return vec3(a, a, a); } pnanovdb_vec3_t pnanovdb_vec3_add(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a + b; } pnanovdb_vec3_t pnanovdb_vec3_sub(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a - b; } pnanovdb_vec3_t pnanovdb_vec3_mul(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a * b; } pnanovdb_vec3_t pnanovdb_vec3_div(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a / b; } pnanovdb_vec3_t pnanovdb_vec3_min(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return min(a, b); } pnanovdb_vec3_t pnanovdb_vec3_max(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return max(a, b); } pnanovdb_vec3_t pnanovdb_coord_to_vec3(const pnanovdb_coord_t coord) { return vec3(coord); } pnanovdb_coord_t pnanovdb_coord_uniform(pnanovdb_int32_t a) { return ivec3(a, a, a); } pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) { return a + b; } pnanovdb_uvec4_t pnanovdb_uvec4_add(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { return a + b; } pnanovdb_uvec4_t pnanovdb_uvec4_sub(pnanovdb_uvec4_t a, pnanovdb_uvec4_t b) { return a - b; } pnanovdb_vec4_t pnanovdb_vec4_add(pnanovdb_vec4_t a, pnanovdb_vec4_t b) { return a + b; } #endif // ------------------------------------------------ Uint64 Utils ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint32_countbits(pnanovdb_uint32_t value) { #if defined(PNANOVDB_C) #if defined(_MSC_VER) && (_MSC_VER >= 1928) && defined(PNANOVDB_USE_INTRINSICS) return __popcnt(value); #elif (defined(__GNUC__) || defined(__clang__)) && defined(PNANOVDB_USE_INTRINSICS) return __builtin_popcount(value); #else value = value - ((value >> 1) & 0x55555555); value = (value & 0x33333333) + ((value >> 2) & 0x33333333); value = (value + (value >> 4)) & 0x0F0F0F0F; return (value * 0x01010101) >> 24; #endif #elif defined(PNANOVDB_HLSL) return countbits(value); #elif defined(PNANOVDB_GLSL) return bitCount(value); #endif } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_countbits(pnanovdb_uint64_t value) { return pnanovdb_uint32_countbits(pnanovdb_uint64_low(value)) + pnanovdb_uint32_countbits(pnanovdb_uint64_high(value)); } #if defined(PNANOVDB_ADDRESS_32) PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_offset(pnanovdb_uint64_t a, pnanovdb_uint32_t b) { pnanovdb_uint32_t low = pnanovdb_uint64_low(a); pnanovdb_uint32_t high = pnanovdb_uint64_high(a); low += b; if (low < b) { high += 1u; } return pnanovdb_uint32_as_uint64(low, high); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_uint64_diff(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { pnanovdb_uint32_t low = pnanovdb_uint64_low(a); pnanovdb_uint32_t high = pnanovdb_uint64_high(a); low -= pnanovdb_uint64_low(b); if (low > pnanovdb_uint64_low(a)) { high -= 1u; } high -= pnanovdb_uint64_high(b); return pnanovdb_uint64_as_int64(pnanovdb_uint32_as_uint64(low, high)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_dec(pnanovdb_uint64_t a) { pnanovdb_uint32_t low = pnanovdb_uint64_low(a); pnanovdb_uint32_t high = pnanovdb_uint64_high(a); if (low == 0u) { high -= 1u; } low -= 1u; return pnanovdb_uint32_as_uint64(low, high); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_to_uint32_lsr(pnanovdb_uint64_t a, pnanovdb_uint32_t b) { pnanovdb_uint32_t low = pnanovdb_uint64_low(a); pnanovdb_uint32_t high = pnanovdb_uint64_high(a); return (b >= 32u) ? (high >> (b - 32)) : ((low >> b) | ((b > 0) ? (high << (32u - b)) : 0u)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_bit_mask(pnanovdb_uint32_t bit_idx) { pnanovdb_uint32_t mask_low = bit_idx < 32u ? 1u << bit_idx : 0u; pnanovdb_uint32_t mask_high = bit_idx >= 32u ? 1u << (bit_idx - 32u) : 0u; return pnanovdb_uint32_as_uint64(mask_low, mask_high); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_and(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return pnanovdb_uint32_as_uint64( pnanovdb_uint64_low(a) & pnanovdb_uint64_low(b), pnanovdb_uint64_high(a) & pnanovdb_uint64_high(b) ); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_uint64_any_bit(pnanovdb_uint64_t a) { return pnanovdb_uint64_low(a) != 0u || pnanovdb_uint64_high(a) != 0u; } #else PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_offset(pnanovdb_uint64_t a, pnanovdb_uint32_t b) { return a + b; } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_uint64_diff(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return pnanovdb_uint64_as_int64(a - b); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_dec(pnanovdb_uint64_t a) { return a - 1u; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_to_uint32_lsr(pnanovdb_uint64_t a, pnanovdb_uint32_t b) { return pnanovdb_uint64_low(a >> b); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_bit_mask(pnanovdb_uint32_t bit_idx) { return 1llu << bit_idx; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_and(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return a & b; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_uint64_any_bit(pnanovdb_uint64_t a) { return a != 0llu; } #endif // ------------------------------------------------ Address Type ----------------------------------------------------------- #if defined(PNANOVDB_ADDRESS_32) struct pnanovdb_address_t { pnanovdb_uint32_t byte_offset; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_address_t) PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) { pnanovdb_address_t ret = address; ret.byte_offset += byte_offset; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_neg(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) { pnanovdb_address_t ret = address; ret.byte_offset -= byte_offset; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_product(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset, pnanovdb_uint32_t multiplier) { pnanovdb_address_t ret = address; ret.byte_offset += byte_offset * multiplier; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset) { pnanovdb_address_t ret = address; // lose high bits on 32-bit ret.byte_offset += pnanovdb_uint64_low(byte_offset); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64_product(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset, pnanovdb_uint32_t multiplier) { pnanovdb_address_t ret = address; ret.byte_offset += pnanovdb_uint64_low(byte_offset) * multiplier; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_address_diff(pnanovdb_address_t a, pnanovdb_address_t b) { return pnanovdb_uint64_diff(pnanovdb_uint32_as_uint64_low(a.byte_offset),pnanovdb_uint32_as_uint64_low(b.byte_offset)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_address_mask(pnanovdb_address_t address, pnanovdb_uint32_t mask) { return address.byte_offset & mask; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_mask_inv(pnanovdb_address_t address, pnanovdb_uint32_t mask) { pnanovdb_address_t ret = address; ret.byte_offset &= (~mask); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_null() { pnanovdb_address_t ret = { 0 }; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_is_null(pnanovdb_address_t address) { return address.byte_offset == 0u; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_in_interval(pnanovdb_address_t address, pnanovdb_address_t min_address, pnanovdb_address_t max_address) { return address.byte_offset >= min_address.byte_offset && address.byte_offset < max_address.byte_offset; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_add(pnanovdb_address_t a, pnanovdb_address_t b) { pnanovdb_address_t sum = a; sum.byte_offset += b.byte_offset; return sum; } #elif defined(PNANOVDB_ADDRESS_64) struct pnanovdb_address_t { pnanovdb_uint64_t byte_offset; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_address_t) PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) { pnanovdb_address_t ret = address; ret.byte_offset += byte_offset; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_neg(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) { pnanovdb_address_t ret = address; ret.byte_offset -= byte_offset; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_product(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset, pnanovdb_uint32_t multiplier) { pnanovdb_address_t ret = address; ret.byte_offset += pnanovdb_uint32_as_uint64_low(byte_offset) * pnanovdb_uint32_as_uint64_low(multiplier); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset) { pnanovdb_address_t ret = address; ret.byte_offset += byte_offset; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64_product(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset, pnanovdb_uint32_t multiplier) { pnanovdb_address_t ret = address; ret.byte_offset += byte_offset * pnanovdb_uint32_as_uint64_low(multiplier); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_address_diff(pnanovdb_address_t a, pnanovdb_address_t b) { return pnanovdb_uint64_diff(a.byte_offset, b.byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_address_mask(pnanovdb_address_t address, pnanovdb_uint32_t mask) { return pnanovdb_uint64_low(address.byte_offset) & mask; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_mask_inv(pnanovdb_address_t address, pnanovdb_uint32_t mask) { pnanovdb_address_t ret = address; ret.byte_offset &= (~pnanovdb_uint32_as_uint64_low(mask)); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_null() { pnanovdb_address_t ret = { 0 }; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_is_null(pnanovdb_address_t address) { return address.byte_offset == 0llu; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_in_interval(pnanovdb_address_t address, pnanovdb_address_t min_address, pnanovdb_address_t max_address) { return address.byte_offset >= min_address.byte_offset && address.byte_offset < max_address.byte_offset; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_add(pnanovdb_address_t a, pnanovdb_address_t b) { pnanovdb_address_t sum = a; sum.byte_offset += b.byte_offset; return sum; } #endif // ------------------------------------------------ High Level Buffer Read ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint32(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_buf_read_uint32(buf, address.byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_read_uint64(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_buf_read_uint64(buf, address.byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_read_int32(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, address)); } PNANOVDB_FORCE_INLINE float pnanovdb_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_uint32_as_float(pnanovdb_read_uint32(buf, address)); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_read_int64(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_uint64_as_int64(pnanovdb_read_uint64(buf, address)); } PNANOVDB_FORCE_INLINE double pnanovdb_read_double(pnanovdb_buf_t buf, pnanovdb_address_t address) { return pnanovdb_uint64_as_double(pnanovdb_read_uint64(buf, address)); } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_read_coord(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_coord_t ret; ret.x = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 0u))); ret.y = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 4u))); ret.z = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 8u))); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_vec3_t ret; ret.x = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 0u)); ret.y = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 4u)); ret.z = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 8u)); return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint16(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(address, 3u)); return (raw >> (pnanovdb_address_mask(address, 2) << 3)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint8(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(address, 3u)); return (raw >> (pnanovdb_address_mask(address, 3) << 3)) & 255; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3u16(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_vec3_t ret; const float scale = 1.f / 65535.f; ret.x = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 0u))) - 0.5f; ret.y = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 2u))) - 0.5f; ret.z = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 4u))) - 0.5f; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3u8(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_vec3_t ret; const float scale = 1.f / 255.f; ret.x = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 0u))) - 0.5f; ret.y = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 1u))) - 0.5f; ret.z = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 2u))) - 0.5f; return ret; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_read_bit(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint32_t bit_offset) { pnanovdb_address_t word_address = pnanovdb_address_mask_inv(address, 3u); pnanovdb_uint32_t bit_index = (pnanovdb_address_mask(address, 3u) << 3u) + bit_offset; pnanovdb_uint32_t value_word = pnanovdb_buf_read_uint32(buf, word_address.byte_offset); return ((value_word >> bit_index) & 1) != 0u; } #if defined(PNANOVDB_C) PNANOVDB_FORCE_INLINE short pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); return (short)(raw >> (pnanovdb_address_mask(address, 2) << 3)); } #elif defined(PNANOVDB_HLSL) PNANOVDB_FORCE_INLINE float pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); return f16tof32(raw >> (pnanovdb_address_mask(address, 2) << 3)); } #elif defined(PNANOVDB_GLSL) PNANOVDB_FORCE_INLINE float pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) { pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); return unpackHalf2x16(raw >> (pnanovdb_address_mask(address, 2) << 3)).x; } #endif // ------------------------------------------------ High Level Buffer Write ----------------------------------------------------------- PNANOVDB_FORCE_INLINE void pnanovdb_write_uint32(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint32_t value) { pnanovdb_buf_write_uint32(buf, address.byte_offset, value); } PNANOVDB_FORCE_INLINE void pnanovdb_write_uint64(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint64_t value) { pnanovdb_buf_write_uint64(buf, address.byte_offset, value); } PNANOVDB_FORCE_INLINE void pnanovdb_write_int32(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_int32_t value) { pnanovdb_write_uint32(buf, address, pnanovdb_int32_as_uint32(value)); } PNANOVDB_FORCE_INLINE void pnanovdb_write_int64(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_int64_t value) { pnanovdb_buf_write_uint64(buf, address.byte_offset, pnanovdb_int64_as_uint64(value)); } PNANOVDB_FORCE_INLINE void pnanovdb_write_float(pnanovdb_buf_t buf, pnanovdb_address_t address, float value) { pnanovdb_write_uint32(buf, address, pnanovdb_float_as_uint32(value)); } PNANOVDB_FORCE_INLINE void pnanovdb_write_double(pnanovdb_buf_t buf, pnanovdb_address_t address, double value) { pnanovdb_write_uint64(buf, address, pnanovdb_double_as_uint64(value)); } PNANOVDB_FORCE_INLINE void pnanovdb_write_coord(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) value) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 0u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).x)); pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 4u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).y)); pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 8u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).z)); } PNANOVDB_FORCE_INLINE void pnanovdb_write_vec3(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_vec3_t) value) { pnanovdb_write_float(buf, pnanovdb_address_offset(address, 0u), PNANOVDB_DEREF(value).x); pnanovdb_write_float(buf, pnanovdb_address_offset(address, 4u), PNANOVDB_DEREF(value).y); pnanovdb_write_float(buf, pnanovdb_address_offset(address, 8u), PNANOVDB_DEREF(value).z); } // ------------------------------------------------ Core Structures ----------------------------------------------------------- #define PNANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL// "NanoVDB0" in hex - little endian (uint64_t) #define PNANOVDB_MAGIC_GRID 0x314244566f6e614eUL// "NanoVDB1" in hex - little endian (uint64_t) #define PNANOVDB_MAGIC_FILE 0x324244566f6e614eUL// "NanoVDB2" in hex - little endian (uint64_t) #define PNANOVDB_MAJOR_VERSION_NUMBER 32// reflects changes to the ABI #define PNANOVDB_MINOR_VERSION_NUMBER 9// reflects changes to the API but not ABI #define PNANOVDB_PATCH_VERSION_NUMBER 0// reflects bug-fixes with no ABI or API changes #define PNANOVDB_GRID_TYPE_UNKNOWN 0 #define PNANOVDB_GRID_TYPE_FLOAT 1 #define PNANOVDB_GRID_TYPE_DOUBLE 2 #define PNANOVDB_GRID_TYPE_INT16 3 #define PNANOVDB_GRID_TYPE_INT32 4 #define PNANOVDB_GRID_TYPE_INT64 5 #define PNANOVDB_GRID_TYPE_VEC3F 6 #define PNANOVDB_GRID_TYPE_VEC3D 7 #define PNANOVDB_GRID_TYPE_MASK 8 #define PNANOVDB_GRID_TYPE_HALF 9 #define PNANOVDB_GRID_TYPE_UINT32 10 #define PNANOVDB_GRID_TYPE_BOOLEAN 11 #define PNANOVDB_GRID_TYPE_RGBA8 12 #define PNANOVDB_GRID_TYPE_FP4 13 #define PNANOVDB_GRID_TYPE_FP8 14 #define PNANOVDB_GRID_TYPE_FP16 15 #define PNANOVDB_GRID_TYPE_FPN 16 #define PNANOVDB_GRID_TYPE_VEC4F 17 #define PNANOVDB_GRID_TYPE_VEC4D 18 #define PNANOVDB_GRID_TYPE_INDEX 19 #define PNANOVDB_GRID_TYPE_ONINDEX 20 //#define PNANOVDB_GRID_TYPE_INDEXMASK 21 // retired - available for future use //#define PNANOVDB_GRID_TYPE_ONINDEXMASK 22 // retired - available for future use #define PNANOVDB_GRID_TYPE_POINTINDEX 23 #define PNANOVDB_GRID_TYPE_VEC3U8 24 #define PNANOVDB_GRID_TYPE_VEC3U16 25 #define PNANOVDB_GRID_TYPE_UINT8 26 #define PNANOVDB_GRID_TYPE_END 27 #define PNANOVDB_GRID_TYPE_CAP 32 #define PNANOVDB_GRID_CLASS_UNKNOWN 0 #define PNANOVDB_GRID_CLASS_LEVEL_SET 1 // narrow band level set, e.g. SDF #define PNANOVDB_GRID_CLASS_FOG_VOLUME 2 // fog volume, e.g. density #define PNANOVDB_GRID_CLASS_STAGGERED 3 // staggered MAC grid, e.g. velocity #define PNANOVDB_GRID_CLASS_POINT_INDEX 4 // point index grid #define PNANOVDB_GRID_CLASS_POINT_DATA 5 // point data grid #define PNANOVDB_GRID_CLASS_TOPOLOGY 6 // grid with active states only (no values) #define PNANOVDB_GRID_CLASS_VOXEL_VOLUME 7 // volume of geometric cubes, e.g. minecraft #define PNANOVDB_GRID_CLASS_INDEX_GRID 8 // grid whose values are offsets, e.g. into an external array #define PNANOVDB_GRID_CLASS_TENSOR_GRID 9 // grid which can have extra metadata and features #define PNANOVDB_GRID_CLASS_END 10 #define PNANOVDB_GRID_FLAGS_HAS_LONG_GRID_NAME (1 << 0) #define PNANOVDB_GRID_FLAGS_HAS_BBOX (1 << 1) #define PNANOVDB_GRID_FLAGS_HAS_MIN_MAX (1 << 2) #define PNANOVDB_GRID_FLAGS_HAS_AVERAGE (1 << 3) #define PNANOVDB_GRID_FLAGS_HAS_STD_DEVIATION (1 << 4) #define PNANOVDB_GRID_FLAGS_IS_BREADTH_FIRST (1 << 5) #define PNANOVDB_GRID_FLAGS_END (1 << 6) #define PNANOVDB_LEAF_TYPE_DEFAULT 0 #define PNANOVDB_LEAF_TYPE_LITE 1 #define PNANOVDB_LEAF_TYPE_FP 2 #define PNANOVDB_LEAF_TYPE_INDEX 3 //#define PNANOVDB_LEAF_TYPE_INDEXMASK 4 // retired - available for future use #define PNANOVDB_LEAF_TYPE_POINTINDEX 5 // BuildType = Unknown, float, double, int16_t, int32_t, int64_t, Vec3f, Vec3d, Mask, ... // bit count of values in leaf nodes, i.e. 8*sizeof(*nanovdb::LeafNode::mValues) or zero if no values are stored PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_value_strides_bits[PNANOVDB_GRID_TYPE_CAP] = { 0, 32, 64, 16, 32, 64, 96, 192, 0, 16, 32, 1, 32, 4, 8, 16, 0, 128, 256, 0, 0, 0, 0, 16, 24, 48, 8, 0 }; // bit count of the Tile union in InternalNodes, i.e. 8*sizeof(nanovdb::InternalData::Tile) PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_table_strides_bits[PNANOVDB_GRID_TYPE_CAP] = { 64, 64, 64, 64, 64, 64, 128, 192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 256, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; // bit count of min/max values, i.e. 8*sizeof(nanovdb::LeafData::mMinimum) or zero if no min/max exists PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_minmax_strides_bits[PNANOVDB_GRID_TYPE_CAP] = { 0, 32, 64, 16, 32, 64, 96, 192, 8, 16, 32, 8, 32, 32, 32, 32, 32, 128, 256, 64, 64, 0, 0, 64, 24, 48, 8, 0 }; // bit alignment of the value type, controlled by the smallest native type, which is why it is always 0, 8, 16, 32, or 64, e.g. for Vec3f it is 32 PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_minmax_aligns_bits[PNANOVDB_GRID_TYPE_CAP] = { 0, 32, 64, 16, 32, 64, 32, 64, 8, 16, 32, 8, 32, 32, 32, 32, 32, 32, 64, 64, 64, 0, 0, 64, 8, 16, 8, 0 }; // bit alignment of the stats (avg/std-dev) types, e.g. 8*sizeof(nanovdb::LeafData::mAverage) PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_stat_strides_bits[PNANOVDB_GRID_TYPE_CAP] = { 0, 32, 64, 32, 32, 64, 32, 64, 8, 32, 32, 8, 32, 32, 32, 32, 32, 32, 64, 64, 64, 0, 0, 64, 32, 32, 32, 0 }; // one of the 4 leaf types defined above, e.g. PNANOVDB_LEAF_TYPE_INDEX = 3 PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_leaf_type[PNANOVDB_GRID_TYPE_CAP] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 2, 2, 2, 2, 0, 0, 3, 3, 0, 0, 5, 0, 0, 0, 0 }; struct pnanovdb_map_t { float matf[9]; float invmatf[9]; float vecf[3]; float taperf; double matd[9]; double invmatd[9]; double vecd[3]; double taperd; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_map_t) struct pnanovdb_map_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_map_handle_t) #define PNANOVDB_MAP_SIZE 264 #define PNANOVDB_MAP_OFF_MATF 0 #define PNANOVDB_MAP_OFF_INVMATF 36 #define PNANOVDB_MAP_OFF_VECF 72 #define PNANOVDB_MAP_OFF_TAPERF 84 #define PNANOVDB_MAP_OFF_MATD 88 #define PNANOVDB_MAP_OFF_INVMATD 160 #define PNANOVDB_MAP_OFF_VECD 232 #define PNANOVDB_MAP_OFF_TAPERD 256 PNANOVDB_FORCE_INLINE float pnanovdb_map_get_matf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATF + 4u * index)); } PNANOVDB_FORCE_INLINE float pnanovdb_map_get_invmatf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATF + 4u * index)); } PNANOVDB_FORCE_INLINE float pnanovdb_map_get_vecf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECF + 4u * index)); } PNANOVDB_FORCE_INLINE float pnanovdb_map_get_taperf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERF)); } PNANOVDB_FORCE_INLINE double pnanovdb_map_get_matd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATD + 8u * index)); } PNANOVDB_FORCE_INLINE double pnanovdb_map_get_invmatd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATD + 8u * index)); } PNANOVDB_FORCE_INLINE double pnanovdb_map_get_vecd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECD + 8u * index)); } PNANOVDB_FORCE_INLINE double pnanovdb_map_get_taperd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERD)); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_matf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float matf) { pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATF + 4u * index), matf); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_invmatf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float invmatf) { pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATF + 4u * index), invmatf); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_vecf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float vecf) { pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECF + 4u * index), vecf); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_taperf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float taperf) { pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERF), taperf); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_matd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double matd) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATD + 8u * index), matd); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_invmatd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double invmatd) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATD + 8u * index), invmatd); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_vecd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double vecd) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECD + 8u * index), vecd); } PNANOVDB_FORCE_INLINE void pnanovdb_map_set_taperd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double taperd) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERD), taperd); } struct pnanovdb_grid_t { pnanovdb_uint64_t magic; // 8 bytes, 0 pnanovdb_uint64_t checksum; // 8 bytes, 8 pnanovdb_uint32_t version; // 4 bytes, 16 pnanovdb_uint32_t flags; // 4 bytes, 20 pnanovdb_uint32_t grid_index; // 4 bytes, 24 pnanovdb_uint32_t grid_count; // 4 bytes, 28 pnanovdb_uint64_t grid_size; // 8 bytes, 32 pnanovdb_uint32_t grid_name[256 / 4]; // 256 bytes, 40 pnanovdb_map_t map; // 264 bytes, 296 double world_bbox[6]; // 48 bytes, 560 double voxel_size[3]; // 24 bytes, 608 pnanovdb_uint32_t grid_class; // 4 bytes, 632 pnanovdb_uint32_t grid_type; // 4 bytes, 636 pnanovdb_int64_t blind_metadata_offset; // 8 bytes, 640 pnanovdb_uint32_t blind_metadata_count; // 4 bytes, 648 pnanovdb_uint32_t data0; // 4 bytes, 652 pnanovdb_uint64_t data1; // 8 bytes, 656 pnanovdb_uint64_t data2; // 8 bytes, 664 }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_t) struct pnanovdb_grid_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_handle_t) #define PNANOVDB_GRID_SIZE 672 #define PNANOVDB_GRID_OFF_MAGIC 0 #define PNANOVDB_GRID_OFF_CHECKSUM 8 #define PNANOVDB_GRID_OFF_VERSION 16 #define PNANOVDB_GRID_OFF_FLAGS 20 #define PNANOVDB_GRID_OFF_GRID_INDEX 24 #define PNANOVDB_GRID_OFF_GRID_COUNT 28 #define PNANOVDB_GRID_OFF_GRID_SIZE 32 #define PNANOVDB_GRID_OFF_GRID_NAME 40 #define PNANOVDB_GRID_OFF_MAP 296 #define PNANOVDB_GRID_OFF_WORLD_BBOX 560 #define PNANOVDB_GRID_OFF_VOXEL_SIZE 608 #define PNANOVDB_GRID_OFF_GRID_CLASS 632 #define PNANOVDB_GRID_OFF_GRID_TYPE 636 #define PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET 640 #define PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT 648 #define PNANOVDB_GRID_OFF_DATA0 652 #define PNANOVDB_GRID_OFF_DATA1 656 #define PNANOVDB_GRID_OFF_DATA2 664 PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_magic(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAGIC)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_checksum(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_CHECKSUM)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_version(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VERSION)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_flags(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_FLAGS)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_index(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_INDEX)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_COUNT)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_grid_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_SIZE)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_name(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_NAME + 4u * index)); } PNANOVDB_FORCE_INLINE pnanovdb_map_handle_t pnanovdb_grid_get_map(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { pnanovdb_map_handle_t ret; ret.address = pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAP); return ret; } PNANOVDB_FORCE_INLINE double pnanovdb_grid_get_world_bbox(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_WORLD_BBOX + 8u * index)); } PNANOVDB_FORCE_INLINE double pnanovdb_grid_get_voxel_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VOXEL_SIZE + 8u * index)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_class(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_CLASS)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_type(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_TYPE)); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_grid_get_blind_metadata_offset(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_blind_metadata_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_data0(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA0)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_data1(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA1)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_data2(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA2)); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_magic(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t magic) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAGIC), magic); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_checksum(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t checksum) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_CHECKSUM), checksum); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_version(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t version) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VERSION), version); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_flags(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t flags) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_FLAGS), flags); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_index(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_index) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_INDEX), grid_index); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_count) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_COUNT), grid_count); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t grid_size) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_SIZE), grid_size); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_name(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, pnanovdb_uint32_t grid_name) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_NAME + 4u * index), grid_name); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_world_bbox(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, double world_bbox) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_WORLD_BBOX + 8u * index), world_bbox); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_voxel_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, double voxel_size) { pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VOXEL_SIZE + 8u * index), voxel_size); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_class(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_class) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_CLASS), grid_class); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_type(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_type) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_TYPE), grid_type); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_blind_metadata_offset(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t blind_metadata_offset) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET), blind_metadata_offset); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_blind_metadata_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t metadata_count) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT), metadata_count); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_data0(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t data0) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA0), data0); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_data1(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t data1) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA1), data1); } PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_data2(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t data2) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_DATA2), data2); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_make_version(pnanovdb_uint32_t major, pnanovdb_uint32_t minor, pnanovdb_uint32_t patch_num) { return (major << 21u) | (minor << 10u) | patch_num; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_major(pnanovdb_uint32_t version) { return (version >> 21u) & ((1u << 11u) - 1u); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_minor(pnanovdb_uint32_t version) { return (version >> 10u) & ((1u << 11u) - 1u); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_patch(pnanovdb_uint32_t version) { return version & ((1u << 10u) - 1u); } #define PNANOVDB_GRIDBLINDMETADATA_CLASS_UNKNOWN 0 #define PNANOVDB_GRIDBLINDMETADATA_CLASS_INDEX_ARRAY 1 #define PNANOVDB_GRIDBLINDMETADATA_CLASS_ATTRIBUTE_ARRAY 2 #define PNANOVDB_GRIDBLINDMETADATA_CLASS_GRID_NAME 3 #define PNANOVDB_GRIDBLINDMETADATA_CLASS_CHANNEL_ARRAY 4 #define PNANOVDB_GRIDBLINDMETADATA_CLASS_END 5 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_UNKNOWN 0 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_POSITION 1 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_COLOR 2 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_NORMAL 3 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_RADIUS 4 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_VELOCITY 5 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_POINT_ID 6 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_WORLD_COORDS 7 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_GRID_COORDS 8 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_VOXEL_COORDS 9 #define PNANOVDB_GRIDBLINDMETADATA_SEMANTIC_END 10 struct pnanovdb_gridblindmetadata_t { pnanovdb_int64_t data_offset; // 8 bytes, 0 pnanovdb_uint64_t value_count; // 8 bytes, 8 pnanovdb_uint32_t value_size; // 4 bytes, 16 pnanovdb_uint32_t semantic; // 4 bytes, 20 pnanovdb_uint32_t data_class; // 4 bytes, 24 pnanovdb_uint32_t data_type; // 4 bytes, 28 pnanovdb_uint32_t name[256 / 4]; // 256 bytes, 32 }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_gridblindmetadata_t) struct pnanovdb_gridblindmetadata_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_gridblindmetadata_handle_t) #define PNANOVDB_GRIDBLINDMETADATA_SIZE 288 #define PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_OFFSET 0 #define PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_COUNT 8 #define PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_SIZE 16 #define PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC 20 #define PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS 24 #define PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE 28 #define PNANOVDB_GRIDBLINDMETADATA_OFF_NAME 32 PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_gridblindmetadata_get_data_offset(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_OFFSET)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_gridblindmetadata_get_value_count(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_COUNT)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_value_size(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_SIZE)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_semantic(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_data_class(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_data_type(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_name(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t index) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_NAME + 4u * index)); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_data_offset(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_int64_t data_offset) { pnanovdb_write_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_OFFSET), data_offset); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_value_count(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint64_t value_count) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_COUNT), value_count); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_value_size(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t value_size) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_VALUE_SIZE), value_size); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_semantic(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t semantic) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC), semantic); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_data_class(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t data_class) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS), data_class); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_data_type(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t data_type) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE), data_type); } PNANOVDB_FORCE_INLINE void pnanovdb_gridblindmetadata_set_name(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t index, pnanovdb_uint32_t name) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_NAME + 4u * index), name); } struct pnanovdb_tree_t { pnanovdb_uint64_t node_offset_leaf; pnanovdb_uint64_t node_offset_lower; pnanovdb_uint64_t node_offset_upper; pnanovdb_uint64_t node_offset_root; pnanovdb_uint32_t node_count_leaf; pnanovdb_uint32_t node_count_lower; pnanovdb_uint32_t node_count_upper; pnanovdb_uint32_t tile_count_lower; pnanovdb_uint32_t tile_count_upper; pnanovdb_uint32_t tile_count_root; pnanovdb_uint64_t voxel_count; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_tree_t) struct pnanovdb_tree_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_tree_handle_t) #define PNANOVDB_TREE_SIZE 64 #define PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF 0 #define PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER 8 #define PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER 16 #define PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT 24 #define PNANOVDB_TREE_OFF_NODE_COUNT_LEAF 32 #define PNANOVDB_TREE_OFF_NODE_COUNT_LOWER 36 #define PNANOVDB_TREE_OFF_NODE_COUNT_UPPER 40 #define PNANOVDB_TREE_OFF_TILE_COUNT_LOWER 44 #define PNANOVDB_TREE_OFF_TILE_COUNT_UPPER 48 #define PNANOVDB_TREE_OFF_TILE_COUNT_ROOT 52 #define PNANOVDB_TREE_OFF_VOXEL_COUNT 56 PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LEAF)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LOWER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_UPPER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LOWER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_UPPER)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_ROOT)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_voxel_count(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_VOXEL_COUNT)); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_leaf) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF), node_offset_leaf); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_lower) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER), node_offset_lower); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_upper) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER), node_offset_upper); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_root) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT), node_offset_root); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_leaf) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LEAF), node_count_leaf); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_lower) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LOWER), node_count_lower); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_upper) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_UPPER), node_count_upper); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_lower) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LOWER), tile_count_lower); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_upper) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_UPPER), tile_count_upper); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_root) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_ROOT), tile_count_root); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_voxel_count(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t voxel_count) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_VOXEL_COUNT), voxel_count); } struct pnanovdb_root_t { pnanovdb_coord_t bbox_min; pnanovdb_coord_t bbox_max; pnanovdb_uint32_t table_size; pnanovdb_uint32_t pad1; // background can start here // background, min, max }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_t) struct pnanovdb_root_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_handle_t) #define PNANOVDB_ROOT_BASE_SIZE 28 #define PNANOVDB_ROOT_OFF_BBOX_MIN 0 #define PNANOVDB_ROOT_OFF_BBOX_MAX 12 #define PNANOVDB_ROOT_OFF_TABLE_SIZE 24 PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_root_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MIN)); } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_root_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MAX)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_get_tile_count(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_TABLE_SIZE)); } PNANOVDB_FORCE_INLINE void pnanovdb_root_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MIN), bbox_min); } PNANOVDB_FORCE_INLINE void pnanovdb_root_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MAX), bbox_max); } PNANOVDB_FORCE_INLINE void pnanovdb_root_set_tile_count(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, pnanovdb_uint32_t tile_count) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_TABLE_SIZE), tile_count); } struct pnanovdb_root_tile_t { pnanovdb_uint64_t key; pnanovdb_int64_t child; // signed byte offset from root to the child node, 0 means it is a constant tile, so use value pnanovdb_uint32_t state; pnanovdb_uint32_t pad1; // value can start here // value }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_tile_t) struct pnanovdb_root_tile_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_tile_handle_t) #define PNANOVDB_ROOT_TILE_BASE_SIZE 20 #define PNANOVDB_ROOT_TILE_OFF_KEY 0 #define PNANOVDB_ROOT_TILE_OFF_CHILD 8 #define PNANOVDB_ROOT_TILE_OFF_STATE 16 PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_tile_get_key(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_KEY)); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_root_tile_get_child(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_CHILD)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_tile_get_state(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_STATE)); } PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_key(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_uint64_t key) { pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_KEY), key); } PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_child(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_int64_t child) { pnanovdb_write_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_CHILD), child); } PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_state(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_uint32_t state) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_STATE), state); } struct pnanovdb_upper_t { pnanovdb_coord_t bbox_min; pnanovdb_coord_t bbox_max; pnanovdb_uint64_t flags; pnanovdb_uint32_t value_mask[1024]; pnanovdb_uint32_t child_mask[1024]; // min, max // alignas(32) pnanovdb_uint32_t table[]; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_upper_t) struct pnanovdb_upper_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_upper_handle_t) #define PNANOVDB_UPPER_TABLE_COUNT 32768 #define PNANOVDB_UPPER_BASE_SIZE 8224 #define PNANOVDB_UPPER_OFF_BBOX_MIN 0 #define PNANOVDB_UPPER_OFF_BBOX_MAX 12 #define PNANOVDB_UPPER_OFF_FLAGS 24 #define PNANOVDB_UPPER_OFF_VALUE_MASK 32 #define PNANOVDB_UPPER_OFF_CHILD_MASK 4128 PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_upper_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MIN)); } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_upper_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MAX)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_upper_get_flags(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_FLAGS)); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_get_value_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index) { pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); return ((value >> (bit_index & 31u)) & 1) != 0u; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_get_child_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index) { pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_CHILD_MASK + 4u * (bit_index >> 5u))); return ((value >> (bit_index & 31u)) & 1) != 0u; } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MIN), bbox_min); } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MAX), bbox_max); } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_value_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_VALUE_MASK + 4u * (bit_index >> 5u)); pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } if (value) valueMask |= (1u << (bit_index & 31u)); pnanovdb_write_uint32(buf, addr, valueMask); } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_child_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_CHILD_MASK + 4u * (bit_index >> 5u)); pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } if (value) valueMask |= (1u << (bit_index & 31u)); pnanovdb_write_uint32(buf, addr, valueMask); } struct pnanovdb_lower_t { pnanovdb_coord_t bbox_min; pnanovdb_coord_t bbox_max; pnanovdb_uint64_t flags; pnanovdb_uint32_t value_mask[128]; pnanovdb_uint32_t child_mask[128]; // min, max // alignas(32) pnanovdb_uint32_t table[]; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_lower_t) struct pnanovdb_lower_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_lower_handle_t) #define PNANOVDB_LOWER_TABLE_COUNT 4096 #define PNANOVDB_LOWER_BASE_SIZE 1056 #define PNANOVDB_LOWER_OFF_BBOX_MIN 0 #define PNANOVDB_LOWER_OFF_BBOX_MAX 12 #define PNANOVDB_LOWER_OFF_FLAGS 24 #define PNANOVDB_LOWER_OFF_VALUE_MASK 32 #define PNANOVDB_LOWER_OFF_CHILD_MASK 544 PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_lower_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MIN)); } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_lower_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MAX)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_lower_get_flags(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_FLAGS)); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_get_value_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index) { pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); return ((value >> (bit_index & 31u)) & 1) != 0u; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_get_child_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index) { pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_CHILD_MASK + 4u * (bit_index >> 5u))); return ((value >> (bit_index & 31u)) & 1) != 0u; } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MIN), bbox_min); } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MAX), bbox_max); } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_value_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_VALUE_MASK + 4u * (bit_index >> 5u)); pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } if (value) valueMask |= (1u << (bit_index & 31u)); pnanovdb_write_uint32(buf, addr, valueMask); } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_child_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_CHILD_MASK + 4u * (bit_index >> 5u)); pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } if (value) valueMask |= (1u << (bit_index & 31u)); pnanovdb_write_uint32(buf, addr, valueMask); } struct pnanovdb_leaf_t { pnanovdb_coord_t bbox_min; pnanovdb_uint32_t bbox_dif_and_flags; pnanovdb_uint32_t value_mask[16]; // min, max // alignas(32) pnanovdb_uint32_t values[]; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_leaf_t) struct pnanovdb_leaf_handle_t { pnanovdb_address_t address; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_leaf_handle_t) #define PNANOVDB_LEAF_TABLE_COUNT 512 #define PNANOVDB_LEAF_BASE_SIZE 80 #define PNANOVDB_LEAF_OFF_BBOX_MIN 0 #define PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS 12 #define PNANOVDB_LEAF_OFF_VALUE_MASK 16 #define PNANOVDB_LEAF_TABLE_NEG_OFF_BBOX_DIF_AND_FLAGS 84 #define PNANOVDB_LEAF_TABLE_NEG_OFF_MINIMUM 16 #define PNANOVDB_LEAF_TABLE_NEG_OFF_QUANTUM 12 PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_leaf_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p) { return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_MIN)); } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_get_bbox_dif_and_flags(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p) { return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS)); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_get_value_mask(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, pnanovdb_uint32_t bit_index) { pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); return ((value >> (bit_index & 31u)) & 1) != 0u; } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_MIN), bbox_min); } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_set_bbox_dif_and_flags(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, pnanovdb_uint32_t bbox_dif_and_flags) { pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS), bbox_dif_and_flags); } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_set_value_mask(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 4u * (bit_index >> 5u)); pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } if (value) valueMask |= (1u << (bit_index & 31u)); pnanovdb_write_uint32(buf, addr, valueMask); } struct pnanovdb_grid_type_constants_t { pnanovdb_uint32_t root_off_background; pnanovdb_uint32_t root_off_min; pnanovdb_uint32_t root_off_max; pnanovdb_uint32_t root_off_ave; pnanovdb_uint32_t root_off_stddev; pnanovdb_uint32_t root_size; pnanovdb_uint32_t value_stride_bits; pnanovdb_uint32_t table_stride; pnanovdb_uint32_t root_tile_off_value; pnanovdb_uint32_t root_tile_size; pnanovdb_uint32_t upper_off_min; pnanovdb_uint32_t upper_off_max; pnanovdb_uint32_t upper_off_ave; pnanovdb_uint32_t upper_off_stddev; pnanovdb_uint32_t upper_off_table; pnanovdb_uint32_t upper_size; pnanovdb_uint32_t lower_off_min; pnanovdb_uint32_t lower_off_max; pnanovdb_uint32_t lower_off_ave; pnanovdb_uint32_t lower_off_stddev; pnanovdb_uint32_t lower_off_table; pnanovdb_uint32_t lower_size; pnanovdb_uint32_t leaf_off_min; pnanovdb_uint32_t leaf_off_max; pnanovdb_uint32_t leaf_off_ave; pnanovdb_uint32_t leaf_off_stddev; pnanovdb_uint32_t leaf_off_table; pnanovdb_uint32_t leaf_size; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_type_constants_t) // The following table with offsets will nedd to be updates as new GridTypes are added in NanoVDB.h PNANOVDB_STATIC_CONST pnanovdb_grid_type_constants_t pnanovdb_grid_type_constants[PNANOVDB_GRID_TYPE_CAP] = { {28, 28, 28, 28, 28, 32, 0, 8, 20, 32, 8224, 8224, 8224, 8224, 8224, 270368, 1056, 1056, 1056, 1056, 1056, 33824, 80, 80, 80, 80, 96, 96}, {28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, {32, 40, 48, 56, 64, 96, 64, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 104, 128, 4224}, {28, 30, 32, 36, 40, 64, 16, 8, 20, 32, 8224, 8226, 8228, 8232, 8256, 270400, 1056, 1058, 1060, 1064, 1088, 33856, 80, 82, 84, 88, 96, 1120}, {28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, {32, 40, 48, 56, 64, 96, 64, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 104, 128, 4224}, {28, 40, 52, 64, 68, 96, 96, 16, 20, 32, 8224, 8236, 8248, 8252, 8256, 532544, 1056, 1068, 1080, 1084, 1088, 66624, 80, 92, 104, 108, 128, 6272}, {32, 56, 80, 104, 112, 128, 192, 24, 24, 64, 8224, 8248, 8272, 8280, 8288, 794720, 1056, 1080, 1104, 1112, 1120, 99424, 80, 104, 128, 136, 160, 12448}, {28, 29, 30, 31, 32, 64, 0, 8, 20, 32, 8224, 8225, 8226, 8227, 8256, 270400, 1056, 1057, 1058, 1059, 1088, 33856, 80, 80, 80, 80, 96, 96}, {28, 30, 32, 36, 40, 64, 16, 8, 20, 32, 8224, 8226, 8228, 8232, 8256, 270400, 1056, 1058, 1060, 1064, 1088, 33856, 80, 82, 84, 88, 96, 1120}, {28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, {28, 29, 30, 31, 32, 64, 1, 8, 20, 32, 8224, 8225, 8226, 8227, 8256, 270400, 1056, 1057, 1058, 1059, 1088, 33856, 80, 80, 80, 80, 96, 160}, {28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, {28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 352}, {28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 608}, {28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 1120}, {28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 96}, {28, 44, 60, 76, 80, 96, 128, 16, 20, 64, 8224, 8240, 8256, 8260, 8288, 532576, 1056, 1072, 1088, 1092, 1120, 66656, 80, 96, 112, 116, 128, 8320}, {32, 64, 96, 128, 136, 160, 256, 32, 24, 64, 8224, 8256, 8288, 8296, 8320, 1056896, 1056, 1088, 1120, 1128, 1152, 132224, 80, 112, 144, 152, 160, 16544}, {32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 96}, {32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 96}, {28, 28, 28, 28, 28, 32, 0, 8, 20, 32, 8224, 8224, 8224, 8224, 8224, 270368, 1056, 1056, 1056, 1056, 1056, 33824, 80, 80, 80, 80, 96, 96}, {28, 28, 28, 28, 28, 32, 0, 8, 20, 32, 8224, 8224, 8224, 8224, 8224, 270368, 1056, 1056, 1056, 1056, 1056, 33824, 80, 80, 80, 80, 96, 96}, {32, 40, 48, 56, 64, 96, 16, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 96, 96, 1120}, {28, 31, 34, 40, 44, 64, 24, 8, 20, 32, 8224, 8227, 8232, 8236, 8256, 270400, 1056, 1059, 1064, 1068, 1088, 33856, 80, 83, 88, 92, 96, 1632}, {28, 34, 40, 48, 52, 64, 48, 8, 20, 32, 8224, 8230, 8236, 8240, 8256, 270400, 1056, 1062, 1068, 1072, 1088, 33856, 80, 86, 92, 96, 128, 3200}, {28, 29, 30, 32, 36, 64, 8, 8, 20, 32, 8224, 8225, 8228, 8232, 8256, 270400, 1056, 1057, 1060, 1064, 1088, 33856, 80, 81, 84, 88, 96, 608}, {28, 28, 28, 28, 28, 32, 0, 8, 20, 32, 8224, 8224, 8224, 8224, 8224, 270368, 1056, 1056, 1056, 1056, 1056, 33824, 80, 80, 80, 80, 96, 96}, }; // ------------------------------------------------ Basic Lookup ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_gridblindmetadata_handle_t pnanovdb_grid_get_gridblindmetadata(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, pnanovdb_uint32_t index) { pnanovdb_gridblindmetadata_handle_t meta = { grid.address }; pnanovdb_uint64_t byte_offset = pnanovdb_grid_get_blind_metadata_offset(buf, grid); meta.address = pnanovdb_address_offset64(meta.address, byte_offset); meta.address = pnanovdb_address_offset_product(meta.address, PNANOVDB_GRIDBLINDMETADATA_SIZE, index); return meta; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_grid_get_gridblindmetadata_value_address(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, pnanovdb_uint32_t index) { pnanovdb_gridblindmetadata_handle_t meta = pnanovdb_grid_get_gridblindmetadata(buf, grid, index); pnanovdb_int64_t byte_offset = pnanovdb_gridblindmetadata_get_data_offset(buf, meta); pnanovdb_address_t address = pnanovdb_address_offset64(meta.address, pnanovdb_int64_as_uint64(byte_offset)); return address; } PNANOVDB_FORCE_INLINE pnanovdb_tree_handle_t pnanovdb_grid_get_tree(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid) { pnanovdb_tree_handle_t tree = { grid.address }; tree.address = pnanovdb_address_offset(tree.address, PNANOVDB_GRID_SIZE); return tree; } PNANOVDB_FORCE_INLINE pnanovdb_root_handle_t pnanovdb_tree_get_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t tree) { pnanovdb_root_handle_t root = { tree.address }; pnanovdb_uint64_t byte_offset = pnanovdb_tree_get_node_offset_root(buf, tree); root.address = pnanovdb_address_offset64(root.address, byte_offset); return root; } PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_get_tile(pnanovdb_grid_type_t grid_type, pnanovdb_root_handle_t root, pnanovdb_uint32_t n) { pnanovdb_root_tile_handle_t tile = { root.address }; tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_size)); tile.address = pnanovdb_address_offset_product(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_size), n); return tile; } PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_get_tile_zero(pnanovdb_grid_type_t grid_type, pnanovdb_root_handle_t root) { pnanovdb_root_tile_handle_t tile = { root.address }; tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_size)); return tile; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_root_tile_get_child_mask(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t tile) { return !pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile)); } PNANOVDB_FORCE_INLINE pnanovdb_upper_handle_t pnanovdb_root_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, pnanovdb_root_tile_handle_t tile) { pnanovdb_upper_handle_t upper = { root.address }; upper.address = pnanovdb_address_offset64(upper.address, pnanovdb_int64_as_uint64(pnanovdb_root_tile_get_child(buf, tile))); return upper; } PNANOVDB_FORCE_INLINE void pnanovdb_root_set_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, pnanovdb_root_tile_handle_t tile, pnanovdb_upper_handle_t upper) { pnanovdb_root_tile_set_child(buf, tile, pnanovdb_address_diff(upper.address, root.address)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_coord_to_key(PNANOVDB_IN(pnanovdb_coord_t) ijk) { #if defined(PNANOVDB_NATIVE_64) pnanovdb_uint64_t iu = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x) >> 12u; pnanovdb_uint64_t ju = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).y) >> 12u; pnanovdb_uint64_t ku = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).z) >> 12u; return (ku) | (ju << 21u) | (iu << 42u); #else pnanovdb_uint32_t iu = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x) >> 12u; pnanovdb_uint32_t ju = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).y) >> 12u; pnanovdb_uint32_t ku = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).z) >> 12u; pnanovdb_uint32_t key_x = ku | (ju << 21); pnanovdb_uint32_t key_y = (iu << 10) | (ju >> 11); return pnanovdb_uint32_as_uint64(key_x, key_y); #endif } PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_find_tile(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t tile_count = pnanovdb_uint32_as_int32(pnanovdb_root_get_tile_count(buf, root)); pnanovdb_root_tile_handle_t tile = pnanovdb_root_get_tile_zero(grid_type, root); pnanovdb_uint64_t key = pnanovdb_coord_to_key(ijk); for (pnanovdb_uint32_t i = 0u; i < tile_count; i++) { if (pnanovdb_uint64_is_equal(key, pnanovdb_root_tile_get_key(buf, tile))) { return tile; } tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_size)); } pnanovdb_root_tile_handle_t null_handle = { pnanovdb_address_null() }; return null_handle; } // ----------------------------- Grid Type Safe Set --------------------------------------- PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_first_gridblindmetadata(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_gridblindmetadata_handle_t gridblindmetadata) { pnanovdb_grid_set_blind_metadata_offset(buf, p, pnanovdb_address_diff(gridblindmetadata.address, p.address)); } // ----------------------------- Tree Type Safe Set --------------------------------------- PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_first_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_leaf_handle_t leaf) { pnanovdb_tree_set_node_offset_leaf(buf, p, pnanovdb_address_diff(leaf.address, p.address)); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_first_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_lower_handle_t lower) { pnanovdb_tree_set_node_offset_lower(buf, p, pnanovdb_address_diff(lower.address, p.address)); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_first_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_upper_handle_t upper) { pnanovdb_tree_set_node_offset_upper(buf, p, pnanovdb_address_diff(upper.address, p.address)); } PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_first_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_root_handle_t root) { pnanovdb_tree_set_node_offset_root(buf, p, pnanovdb_address_diff(root.address, p.address)); } // ----------------------------- Leaf Node --------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) { return (((PNANOVDB_DEREF(ijk).x & 7) >> 0) << (2 * 3)) + (((PNANOVDB_DEREF(ijk).y & 7) >> 0) << (3)) + ((PNANOVDB_DEREF(ijk).z & 7) >> 0); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_min); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_max); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_ave); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_stddev); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node, pnanovdb_uint32_t n) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_table) + ((PNANOVDB_GRID_TYPE_GET(grid_type, value_stride_bits) * n) >> 3u); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); return pnanovdb_leaf_get_table_address(grid_type, buf, leaf, n); } // ----------------------------- Leaf FP Types Specialization --------------------------------------- PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t value_log_bits) { // value_log_bits // 2 3 4 pnanovdb_uint32_t value_bits = 1u << value_log_bits; // 4 8 16 pnanovdb_uint32_t value_mask = (1u << value_bits) - 1u; // 0xF 0xFF 0xFFFF pnanovdb_uint32_t values_per_word_bits = 5u - value_log_bits; // 3 2 1 pnanovdb_uint32_t values_per_word_mask = (1u << values_per_word_bits) - 1u; // 7 3 1 pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); float minimum = pnanovdb_read_float(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_MINIMUM)); float quantum = pnanovdb_read_float(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_QUANTUM)); pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, ((n >> values_per_word_bits) << 2u))); pnanovdb_uint32_t value_compressed = (raw >> ((n & values_per_word_mask) << value_log_bits)) & value_mask; return pnanovdb_uint32_to_float(value_compressed) * quantum + minimum; } PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp4_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { return pnanovdb_leaf_fp_read_float(buf, address, ijk, 2u); } PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp8_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { return pnanovdb_leaf_fp_read_float(buf, address, ijk, 3u); } PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp16_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { return pnanovdb_leaf_fp_read_float(buf, address, ijk, 4u); } PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fpn_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t bbox_dif_and_flags = pnanovdb_read_uint32(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_BBOX_DIF_AND_FLAGS)); pnanovdb_uint32_t flags = bbox_dif_and_flags >> 24u; pnanovdb_uint32_t value_log_bits = flags >> 5; // b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits return pnanovdb_leaf_fp_read_float(buf, address, ijk, value_log_bits); } // ----------------------------- Leaf Index Specialization --------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_index_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { return (pnanovdb_leaf_get_bbox_dif_and_flags(buf, leaf) & (1u << 28u)) != 0u; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) { return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, min_address), 512u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) { return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, max_address), 513u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) { return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, ave_address), 514u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) { return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, dev_address), 515u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); pnanovdb_uint64_t offset = pnanovdb_read_uint64(buf, value_address); return pnanovdb_uint64_offset(offset, n); } // ----------------------------- Leaf OnIndex Specialization --------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_onindex_get_value_count(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { pnanovdb_uint64_t val_mask = pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 8u * 7u)); pnanovdb_uint64_t prefix_sum = pnanovdb_read_uint64( buf, pnanovdb_address_offset(leaf.address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table) + 8u)); return pnanovdb_uint64_countbits(val_mask) + (pnanovdb_uint64_to_uint32_lsr(prefix_sum, 54u) & 511u); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_last_offset(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { return pnanovdb_uint64_offset( pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table))), pnanovdb_leaf_onindex_get_value_count(buf, leaf) - 1u); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_onindex_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { return (pnanovdb_leaf_get_bbox_dif_and_flags(buf, leaf) & (1u << 28u)) != 0u; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) { pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(min_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) { idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 1u); } return idx; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) { pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(max_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) { idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 2u); } return idx; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) { pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(ave_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) { idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 3u); } return idx; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) { pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(dev_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) { idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 4u); } return idx; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(value_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; pnanovdb_uint32_t word_idx = n >> 6u; pnanovdb_uint32_t bit_idx = n & 63u; pnanovdb_uint64_t val_mask = pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 8u * word_idx)); pnanovdb_uint64_t mask = pnanovdb_uint64_bit_mask(bit_idx); pnanovdb_uint64_t value_index = pnanovdb_uint32_as_uint64_low(0u); if (pnanovdb_uint64_any_bit(pnanovdb_uint64_and(val_mask, mask))) { pnanovdb_uint32_t sum = 0u; sum += pnanovdb_uint64_countbits(pnanovdb_uint64_and(val_mask, pnanovdb_uint64_dec(mask))); if (word_idx > 0u) { pnanovdb_uint64_t prefix_sum = pnanovdb_read_uint64(buf, pnanovdb_address_offset(value_address, 8u)); sum += pnanovdb_uint64_to_uint32_lsr(prefix_sum, 9u * (word_idx - 1u)) & 511u; } pnanovdb_uint64_t offset = pnanovdb_read_uint64(buf, value_address); value_index = pnanovdb_uint64_offset(offset, sum); } return value_index; } // ----------------------------- Leaf PointIndex Specialization --------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_offset(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { return pnanovdb_read_uint64(buf, pnanovdb_leaf_get_min_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_point_count(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) { return pnanovdb_read_uint64(buf, pnanovdb_leaf_get_max_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf)); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_first(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) { return pnanovdb_uint64_offset(pnanovdb_leaf_pointindex_get_offset(buf, leaf), (i == 0u ? 0u : pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i - 1u)))); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_last(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) { return pnanovdb_uint64_offset(pnanovdb_leaf_pointindex_get_offset(buf, leaf), pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i))); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_value(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) { return pnanovdb_uint32_as_uint64_low(pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i))); } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_value_only(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i, pnanovdb_uint32_t value) { pnanovdb_address_t addr = pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i); pnanovdb_uint32_t raw32 = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(addr, 3u)); if ((i & 1) == 0u) { raw32 = (raw32 & 0xFFFF0000) | (value & 0x0000FFFF); } else { raw32 = (raw32 & 0x0000FFFF) | (value << 16u); } pnanovdb_write_uint32(buf, addr, raw32); } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_on(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) { pnanovdb_uint32_t word_idx = i >> 5; pnanovdb_uint32_t bit_idx = i & 31; pnanovdb_address_t addr = pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 4u * word_idx); pnanovdb_uint32_t val_mask = pnanovdb_read_uint32(buf, addr); val_mask = val_mask | (1u << bit_idx); pnanovdb_write_uint32(buf, addr, val_mask); } PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_value(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i, pnanovdb_uint32_t value) { pnanovdb_leaf_pointindex_set_on(buf, leaf, i); pnanovdb_leaf_pointindex_set_value_only(buf, leaf, i, value); } // ------------------------------------------------ Lower Node ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_lower_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) { return (((PNANOVDB_DEREF(ijk).x & 127) >> 3) << (2 * 4)) + (((PNANOVDB_DEREF(ijk).y & 127) >> 3) << (4)) + ((PNANOVDB_DEREF(ijk).z & 127) >> 3); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_min); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_max); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_ave); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_stddev); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_table) + PNANOVDB_GRID_TYPE_GET(grid_type, table_stride) * n; return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_lower_get_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n) { pnanovdb_address_t table_address = pnanovdb_lower_get_table_address(grid_type, buf, node, n); return pnanovdb_read_int64(buf, table_address); } PNANOVDB_FORCE_INLINE pnanovdb_leaf_handle_t pnanovdb_lower_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, pnanovdb_uint32_t n) { pnanovdb_leaf_handle_t leaf = { lower.address }; leaf.address = pnanovdb_address_offset64(leaf.address, pnanovdb_int64_as_uint64(pnanovdb_lower_get_table_child(grid_type, buf, lower, n))); return leaf; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); pnanovdb_address_t value_address; if (pnanovdb_lower_get_child_mask(buf, lower, n)) { pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); value_address = pnanovdb_leaf_get_value_address(grid_type, buf, child, ijk); PNANOVDB_DEREF(level) = 0u; } else { value_address = pnanovdb_lower_get_table_address(grid_type, buf, lower, n); PNANOVDB_DEREF(level) = 1u; } return value_address; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t level; return pnanovdb_lower_get_value_address_and_level(grid_type, buf, lower, ijk, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n, pnanovdb_int64_t child) { pnanovdb_address_t table_address = pnanovdb_lower_get_table_address(grid_type, buf, node, n); pnanovdb_write_int64(buf, table_address, child); } PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, pnanovdb_uint32_t n, pnanovdb_leaf_handle_t leaf) { pnanovdb_lower_set_table_child(grid_type, buf, lower, n, pnanovdb_address_diff(leaf.address, lower.address)); } // ------------------------------------------------ Upper Node ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_upper_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) { return (((PNANOVDB_DEREF(ijk).x & 4095) >> 7) << (2 * 5)) + (((PNANOVDB_DEREF(ijk).y & 4095) >> 7) << (5)) + ((PNANOVDB_DEREF(ijk).z & 4095) >> 7); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_min); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_max); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_ave); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_stddev); return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_table) + PNANOVDB_GRID_TYPE_GET(grid_type, table_stride) * n; return pnanovdb_address_offset(node.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_upper_get_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n) { pnanovdb_address_t bufAddress = pnanovdb_upper_get_table_address(grid_type, buf, node, n); return pnanovdb_read_int64(buf, bufAddress); } PNANOVDB_FORCE_INLINE pnanovdb_lower_handle_t pnanovdb_upper_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, pnanovdb_uint32_t n) { pnanovdb_lower_handle_t lower = { upper.address }; lower.address = pnanovdb_address_offset64(lower.address, pnanovdb_int64_as_uint64(pnanovdb_upper_get_table_child(grid_type, buf, upper, n))); return lower; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); pnanovdb_address_t value_address; if (pnanovdb_upper_get_child_mask(buf, upper, n)) { pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); value_address = pnanovdb_lower_get_value_address_and_level(grid_type, buf, child, ijk, level); } else { value_address = pnanovdb_upper_get_table_address(grid_type, buf, upper, n); PNANOVDB_DEREF(level) = 2u; } return value_address; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t level; return pnanovdb_upper_get_value_address_and_level(grid_type, buf, upper, ijk, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n, pnanovdb_int64_t child) { pnanovdb_address_t bufAddress = pnanovdb_upper_get_table_address(grid_type, buf, node, n); pnanovdb_write_int64(buf, bufAddress, child); } PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, pnanovdb_uint32_t n, pnanovdb_lower_handle_t lower) { pnanovdb_upper_set_table_child(grid_type, buf, upper, n, pnanovdb_address_diff(lower.address, upper.address)); } // ------------------------------------------------ Root ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_background_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_background); return pnanovdb_address_offset(root.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_min); return pnanovdb_address_offset(root.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_max); return pnanovdb_address_offset(root.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_ave); return pnanovdb_address_offset(root.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_stddev); return pnanovdb_address_offset(root.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_tile_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t root_tile) { pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value); return pnanovdb_address_offset(root_tile.address, byte_offset); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); pnanovdb_address_t ret; if (pnanovdb_address_is_null(tile.address)) { ret = pnanovdb_address_offset(root.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_off_background)); PNANOVDB_DEREF(level) = 4u; } else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) { ret = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value)); PNANOVDB_DEREF(level) = 3u; } else { pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); ret = pnanovdb_upper_get_value_address_and_level(grid_type, buf, child, ijk, level); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t level; return pnanovdb_root_get_value_address_and_level(grid_type, buf, root, ijk, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_bit(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) bit_index) { pnanovdb_uint32_t level; pnanovdb_address_t address = pnanovdb_root_get_value_address_and_level(grid_type, buf, root, ijk, PNANOVDB_REF(level)); PNANOVDB_DEREF(bit_index) = level == 0u ? pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x & 7) : 0u; return address; } PNANOVDB_FORCE_INLINE float pnanovdb_root_fp4_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { float ret; if (level == 0) { ret = pnanovdb_leaf_fp4_read_float(buf, address, ijk); } else { ret = pnanovdb_read_float(buf, address); } return ret; } PNANOVDB_FORCE_INLINE float pnanovdb_root_fp8_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { float ret; if (level == 0) { ret = pnanovdb_leaf_fp8_read_float(buf, address, ijk); } else { ret = pnanovdb_read_float(buf, address); } return ret; } PNANOVDB_FORCE_INLINE float pnanovdb_root_fp16_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { float ret; if (level == 0) { ret = pnanovdb_leaf_fp16_read_float(buf, address, ijk); } else { ret = pnanovdb_read_float(buf, address); } return ret; } PNANOVDB_FORCE_INLINE float pnanovdb_root_fpn_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { float ret; if (level == 0) { ret = pnanovdb_leaf_fpn_read_float(buf, address, ijk); } else { ret = pnanovdb_read_float(buf, address); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_index_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { pnanovdb_uint64_t ret; if (level == 0) { ret = pnanovdb_leaf_index_get_value_index(buf, address, ijk); } else { ret = pnanovdb_read_uint64(buf, address); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_onindex_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) { pnanovdb_uint64_t ret; if (level == 0) { ret = pnanovdb_leaf_onindex_get_value_index(buf, address, ijk); } else { ret = pnanovdb_read_uint64(buf, address); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_pointindex_get_point_range( pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level, PNANOVDB_INOUT(pnanovdb_uint64_t)range_begin, PNANOVDB_INOUT(pnanovdb_uint64_t)range_end ) { pnanovdb_uint32_t local_range_begin = 0u; pnanovdb_uint32_t local_range_end = 0u; pnanovdb_uint64_t offset = pnanovdb_uint32_as_uint64_low(0u); if (level == 0) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); // recover leaf address pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(value_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_POINTINDEX, leaf_off_table) + 2u * n) }; if (n > 0u) { local_range_begin = pnanovdb_read_uint16(buf, pnanovdb_address_offset_neg(value_address, 2u)); } local_range_end = pnanovdb_read_uint16(buf, value_address); offset = pnanovdb_leaf_pointindex_get_offset(buf, leaf); } PNANOVDB_DEREF(range_begin) = pnanovdb_uint64_offset(offset, local_range_begin); PNANOVDB_DEREF(range_end) = pnanovdb_uint64_offset(offset, local_range_end); return pnanovdb_uint32_as_uint64_low(local_range_end - local_range_begin); } PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_pointindex_get_point_address_range( pnanovdb_buf_t buf, pnanovdb_grid_type_t value_type, pnanovdb_address_t value_address, pnanovdb_address_t blindmetadata_value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level, PNANOVDB_INOUT(pnanovdb_address_t)address_begin, PNANOVDB_INOUT(pnanovdb_address_t)address_end ) { pnanovdb_uint64_t range_begin; pnanovdb_uint64_t range_end; pnanovdb_uint64_t range_size = pnanovdb_root_pointindex_get_point_range(buf, value_address, ijk, level, PNANOVDB_REF(range_begin), PNANOVDB_REF(range_end)); pnanovdb_uint32_t stride = 12u; // vec3f if (value_type == PNANOVDB_GRID_TYPE_VEC3U8) { stride = 3u; } else if (value_type == PNANOVDB_GRID_TYPE_VEC3U16) { stride = 6u; } PNANOVDB_DEREF(address_begin) = pnanovdb_address_offset64_product(blindmetadata_value_address, range_begin, stride); PNANOVDB_DEREF(address_end) = pnanovdb_address_offset64_product(blindmetadata_value_address, range_end, stride); return range_size; } // ------------------------------------------------ ReadAccessor ----------------------------------------------------------- struct pnanovdb_readaccessor_t { pnanovdb_coord_t key; pnanovdb_leaf_handle_t leaf; pnanovdb_lower_handle_t lower; pnanovdb_upper_handle_t upper; pnanovdb_root_handle_t root; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_readaccessor_t) PNANOVDB_FORCE_INLINE void pnanovdb_readaccessor_init(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, pnanovdb_root_handle_t root) { PNANOVDB_DEREF(acc).key.x = 0x7FFFFFFF; PNANOVDB_DEREF(acc).key.y = 0x7FFFFFFF; PNANOVDB_DEREF(acc).key.z = 0x7FFFFFFF; PNANOVDB_DEREF(acc).leaf.address = pnanovdb_address_null(); PNANOVDB_DEREF(acc).lower.address = pnanovdb_address_null(); PNANOVDB_DEREF(acc).upper.address = pnanovdb_address_null(); PNANOVDB_DEREF(acc).root = root; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached0(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) { if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).leaf.address)) { return PNANOVDB_FALSE; } if ((dirty & ~((1u << 3) - 1u)) != 0) { PNANOVDB_DEREF(acc).leaf.address = pnanovdb_address_null(); return PNANOVDB_FALSE; } return PNANOVDB_TRUE; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached1(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) { if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).lower.address)) { return PNANOVDB_FALSE; } if ((dirty & ~((1u << 7) - 1u)) != 0) { PNANOVDB_DEREF(acc).lower.address = pnanovdb_address_null(); return PNANOVDB_FALSE; } return PNANOVDB_TRUE; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached2(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) { if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).upper.address)) { return PNANOVDB_FALSE; } if ((dirty & ~((1u << 12) - 1u)) != 0) { PNANOVDB_DEREF(acc).upper.address = pnanovdb_address_null(); return PNANOVDB_FALSE; } return PNANOVDB_TRUE; } PNANOVDB_FORCE_INLINE int pnanovdb_readaccessor_computedirty(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) { return (PNANOVDB_DEREF(ijk).x ^ PNANOVDB_DEREF(acc).key.x) | (PNANOVDB_DEREF(ijk).y ^ PNANOVDB_DEREF(acc).key.y) | (PNANOVDB_DEREF(ijk).z ^ PNANOVDB_DEREF(acc).key.z); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); return pnanovdb_leaf_get_table_address(grid_type, buf, leaf, n); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); pnanovdb_address_t value_address; if (pnanovdb_lower_get_child_mask(buf, lower, n)) { pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); PNANOVDB_DEREF(acc).leaf = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); value_address = pnanovdb_leaf_get_value_address_and_cache(grid_type, buf, child, ijk, acc); PNANOVDB_DEREF(level) = 0u; } else { value_address = pnanovdb_lower_get_table_address(grid_type, buf, lower, n); PNANOVDB_DEREF(level) = 1u; } return value_address; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t level; return pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, lower, ijk, acc, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); pnanovdb_address_t value_address; if (pnanovdb_upper_get_child_mask(buf, upper, n)) { pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); PNANOVDB_DEREF(acc).lower = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); value_address = pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, child, ijk, acc, level); } else { value_address = pnanovdb_upper_get_table_address(grid_type, buf, upper, n); PNANOVDB_DEREF(level) = 2u; } return value_address; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t level; return pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, upper, ijk, acc, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); pnanovdb_address_t ret; if (pnanovdb_address_is_null(tile.address)) { ret = pnanovdb_address_offset(root.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_off_background)); PNANOVDB_DEREF(level) = 4u; } else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) { ret = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value)); PNANOVDB_DEREF(level) = 3u; } else { pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); PNANOVDB_DEREF(acc).upper = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); ret = pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, child, ijk, acc, level); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t level; return pnanovdb_root_get_value_address_and_level_and_cache(grid_type, buf, root, ijk, acc, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) { int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); pnanovdb_address_t value_address; if (pnanovdb_readaccessor_iscached0(acc, dirty)) { value_address = pnanovdb_leaf_get_value_address_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); PNANOVDB_DEREF(level) = 0u; } else if (pnanovdb_readaccessor_iscached1(acc, dirty)) { value_address = pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc, level); } else if (pnanovdb_readaccessor_iscached2(acc, dirty)) { value_address = pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc, level); } else { value_address = pnanovdb_root_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc, level); } return value_address; } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) { pnanovdb_uint32_t level; return pnanovdb_readaccessor_get_value_address_and_level(grid_type, buf, acc, ijk, PNANOVDB_REF(level)); } PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address_bit(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) bit_index) { pnanovdb_uint32_t level; pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address_and_level(grid_type, buf, acc, ijk, PNANOVDB_REF(level)); PNANOVDB_DEREF(bit_index) = level == 0u ? pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x & 7) : 0u; return address; } // ------------------------------------------------ ReadAccessor GetDim ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { return 1u; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_lower_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); pnanovdb_uint32_t ret; if (pnanovdb_lower_get_child_mask(buf, lower, n)) { pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); PNANOVDB_DEREF(acc).leaf = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); ret = pnanovdb_leaf_get_dim_and_cache(grid_type, buf, child, ijk, acc); } else { ret = (1u << (3u)); // node 0 dim } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_upper_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); pnanovdb_uint32_t ret; if (pnanovdb_upper_get_child_mask(buf, upper, n)) { pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); PNANOVDB_DEREF(acc).lower = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); ret = pnanovdb_lower_get_dim_and_cache(grid_type, buf, child, ijk, acc); } else { ret = (1u << (4u + 3u)); // node 1 dim } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); pnanovdb_uint32_t ret; if (pnanovdb_address_is_null(tile.address)) { ret = 1u << (5u + 4u + 3u); // background, node 2 dim } else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) { ret = 1u << (5u + 4u + 3u); // tile value, node 2 dim } else { pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); PNANOVDB_DEREF(acc).upper = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); ret = pnanovdb_upper_get_dim_and_cache(grid_type, buf, child, ijk, acc); } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_readaccessor_get_dim(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) { int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); pnanovdb_uint32_t dim; if (pnanovdb_readaccessor_iscached0(acc, dirty)) { dim = pnanovdb_leaf_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); } else if (pnanovdb_readaccessor_iscached1(acc, dirty)) { dim = pnanovdb_lower_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc); } else if (pnanovdb_readaccessor_iscached2(acc, dirty)) { dim = pnanovdb_upper_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc); } else { dim = pnanovdb_root_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc); } return dim; } // ------------------------------------------------ ReadAccessor IsActive ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); return pnanovdb_leaf_get_value_mask(buf, leaf, n); } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); pnanovdb_bool_t is_active; if (pnanovdb_lower_get_child_mask(buf, lower, n)) { pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); PNANOVDB_DEREF(acc).leaf = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); is_active = pnanovdb_leaf_is_active_and_cache(grid_type, buf, child, ijk, acc); } else { is_active = pnanovdb_lower_get_value_mask(buf, lower, n); } return is_active; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); pnanovdb_bool_t is_active; if (pnanovdb_upper_get_child_mask(buf, upper, n)) { pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); PNANOVDB_DEREF(acc).lower = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); is_active = pnanovdb_lower_is_active_and_cache(grid_type, buf, child, ijk, acc); } else { is_active = pnanovdb_upper_get_value_mask(buf, upper, n); } return is_active; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_root_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) { pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); pnanovdb_bool_t is_active; if (pnanovdb_address_is_null(tile.address)) { is_active = PNANOVDB_FALSE; // background } else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) { pnanovdb_uint32_t state = pnanovdb_root_tile_get_state(buf, tile); is_active = state != 0u; // tile value } else { pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); PNANOVDB_DEREF(acc).upper = child; PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); is_active = pnanovdb_upper_is_active_and_cache(grid_type, buf, child, ijk, acc); } return is_active; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_is_active(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) { int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); pnanovdb_bool_t is_active; if (pnanovdb_readaccessor_iscached0(acc, dirty)) { is_active = pnanovdb_leaf_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); } else if (pnanovdb_readaccessor_iscached1(acc, dirty)) { is_active = pnanovdb_lower_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc); } else if (pnanovdb_readaccessor_iscached2(acc, dirty)) { is_active = pnanovdb_upper_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc); } else { is_active = pnanovdb_root_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc); } return is_active; } // ------------------------------------------------ Map Transforms ----------------------------------------------------------- PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_vec3_t dst; float sx = PNANOVDB_DEREF(src).x; float sy = PNANOVDB_DEREF(src).y; float sz = PNANOVDB_DEREF(src).z; dst.x = sx * pnanovdb_map_get_matf(buf, map, 0) + sy * pnanovdb_map_get_matf(buf, map, 1) + sz * pnanovdb_map_get_matf(buf, map, 2) + pnanovdb_map_get_vecf(buf, map, 0); dst.y = sx * pnanovdb_map_get_matf(buf, map, 3) + sy * pnanovdb_map_get_matf(buf, map, 4) + sz * pnanovdb_map_get_matf(buf, map, 5) + pnanovdb_map_get_vecf(buf, map, 1); dst.z = sx * pnanovdb_map_get_matf(buf, map, 6) + sy * pnanovdb_map_get_matf(buf, map, 7) + sz * pnanovdb_map_get_matf(buf, map, 8) + pnanovdb_map_get_vecf(buf, map, 2); return dst; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_inverse(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_vec3_t dst; float sx = PNANOVDB_DEREF(src).x - pnanovdb_map_get_vecf(buf, map, 0); float sy = PNANOVDB_DEREF(src).y - pnanovdb_map_get_vecf(buf, map, 1); float sz = PNANOVDB_DEREF(src).z - pnanovdb_map_get_vecf(buf, map, 2); dst.x = sx * pnanovdb_map_get_invmatf(buf, map, 0) + sy * pnanovdb_map_get_invmatf(buf, map, 1) + sz * pnanovdb_map_get_invmatf(buf, map, 2); dst.y = sx * pnanovdb_map_get_invmatf(buf, map, 3) + sy * pnanovdb_map_get_invmatf(buf, map, 4) + sz * pnanovdb_map_get_invmatf(buf, map, 5); dst.z = sx * pnanovdb_map_get_invmatf(buf, map, 6) + sy * pnanovdb_map_get_invmatf(buf, map, 7) + sz * pnanovdb_map_get_invmatf(buf, map, 8); return dst; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_jacobi(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_vec3_t dst; float sx = PNANOVDB_DEREF(src).x; float sy = PNANOVDB_DEREF(src).y; float sz = PNANOVDB_DEREF(src).z; dst.x = sx * pnanovdb_map_get_matf(buf, map, 0) + sy * pnanovdb_map_get_matf(buf, map, 1) + sz * pnanovdb_map_get_matf(buf, map, 2); dst.y = sx * pnanovdb_map_get_matf(buf, map, 3) + sy * pnanovdb_map_get_matf(buf, map, 4) + sz * pnanovdb_map_get_matf(buf, map, 5); dst.z = sx * pnanovdb_map_get_matf(buf, map, 6) + sy * pnanovdb_map_get_matf(buf, map, 7) + sz * pnanovdb_map_get_matf(buf, map, 8); return dst; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_inverse_jacobi(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_vec3_t dst; float sx = PNANOVDB_DEREF(src).x; float sy = PNANOVDB_DEREF(src).y; float sz = PNANOVDB_DEREF(src).z; dst.x = sx * pnanovdb_map_get_invmatf(buf, map, 0) + sy * pnanovdb_map_get_invmatf(buf, map, 1) + sz * pnanovdb_map_get_invmatf(buf, map, 2); dst.y = sx * pnanovdb_map_get_invmatf(buf, map, 3) + sy * pnanovdb_map_get_invmatf(buf, map, 4) + sz * pnanovdb_map_get_invmatf(buf, map, 5); dst.z = sx * pnanovdb_map_get_invmatf(buf, map, 6) + sy * pnanovdb_map_get_invmatf(buf, map, 7) + sz * pnanovdb_map_get_invmatf(buf, map, 8); return dst; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_world_to_indexf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); return pnanovdb_map_apply_inverse(buf, map, src); } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_index_to_worldf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); return pnanovdb_map_apply(buf, map, src); } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_world_to_index_dirf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); return pnanovdb_map_apply_inverse_jacobi(buf, map, src); } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_index_to_world_dirf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) { pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); return pnanovdb_map_apply_jacobi(buf, map, src); } // ------------------------------------------------ DitherLUT ----------------------------------------------------------- // This table was generated with /************** static constexpr inline uint32 SYSwang_inthash(uint32 key) { // From http://www.concentric.net/~Ttwang/tech/inthash.htm key += ~(key << 16); key ^= (key >> 5); key += (key << 3); key ^= (key >> 13); key += ~(key << 9); key ^= (key >> 17); return key; } static void ut_initDitherR(float *pattern, float offset, int x, int y, int z, int res, int goalres) { // These offsets are designed to maximize the difference between // dither values in nearby voxels within a given 2x2x2 cell, without // producing axis-aligned artifacts. The are organized in row-major // order. static const float theDitherOffset[] = {0,4,6,2,5,1,3,7}; static const float theScale = 0.125F; int key = (((z << res) + y) << res) + x; if (res == goalres) { pattern[key] = offset; return; } // Randomly flip (on each axis) the dithering patterns used by the // subcells. This key is xor'd with the subcell index below before // looking up in the dither offset list. key = SYSwang_inthash(key) & 7; x <<= 1; y <<= 1; z <<= 1; offset *= theScale; for (int i = 0; i < 8; i++) ut_initDitherR(pattern, offset+theDitherOffset[i ^ key]*theScale, x+(i&1), y+((i&2)>>1), z+((i&4)>>2), res+1, goalres); } // This is a compact algorithm that accomplishes essentially the same thing // as ut_initDither() above. We should eventually switch to use this and // clean the dead code. static fpreal32 * ut_initDitherRecursive(int goalres) { const int nfloat = 1 << (goalres*3); float *pattern = new float[nfloat]; ut_initDitherR(pattern, 1.0F, 0, 0, 0, 0, goalres); // This has built an even spacing from 1/nfloat to 1.0. // however, our dither pattern should be 1/(nfloat+1) to nfloat/(nfloat+1) // So we do a correction here. Note that the earlier calculations are // done with powers of 2 so are exact, so it does make sense to delay // the renormalization to this pass. float correctionterm = nfloat / (nfloat+1.0F); for (int i = 0; i < nfloat; i++) pattern[i] *= correctionterm; return pattern; } theDitherMatrix = ut_initDitherRecursive(3); for (int i = 0; i < 512/8; i ++) { for (int j = 0; j < 8; j ++) std::cout << theDitherMatrix[i*8+j] << "f, "; std::cout << std::endl; } **************/ PNANOVDB_STATIC_CONST float pnanovdb_dither_lut[512] = { 0.14425f, 0.643275f, 0.830409f, 0.331384f, 0.105263f, 0.604289f, 0.167641f, 0.666667f, 0.892788f, 0.393762f, 0.0818713f, 0.580897f, 0.853801f, 0.354776f, 0.916179f, 0.417154f, 0.612086f, 0.11306f, 0.79922f, 0.300195f, 0.510721f, 0.0116959f, 0.947368f, 0.448343f, 0.362573f, 0.861598f, 0.0506823f, 0.549708f, 0.261209f, 0.760234f, 0.19883f, 0.697856f, 0.140351f, 0.639376f, 0.576998f, 0.0779727f, 0.522417f, 0.0233918f, 0.460039f, 0.959064f, 0.888889f, 0.389864f, 0.327485f, 0.826511f, 0.272904f, 0.77193f, 0.709552f, 0.210526f, 0.483431f, 0.982456f, 0.296296f, 0.795322f, 0.116959f, 0.615984f, 0.0545809f, 0.553606f, 0.732943f, 0.233918f, 0.545809f, 0.0467836f, 0.865497f, 0.366472f, 0.803119f, 0.304094f, 0.518519f, 0.0194932f, 0.45614f, 0.955166f, 0.729045f, 0.230019f, 0.54191f, 0.042885f, 0.269006f, 0.768031f, 0.705653f, 0.206628f, 0.479532f, 0.978558f, 0.292398f, 0.791423f, 0.237817f, 0.736842f, 0.424951f, 0.923977f, 0.136452f, 0.635478f, 0.323587f, 0.822612f, 0.986355f, 0.487329f, 0.674464f, 0.175439f, 0.88499f, 0.385965f, 0.573099f, 0.0740741f, 0.51462f, 0.0155945f, 0.202729f, 0.701754f, 0.148148f, 0.647174f, 0.834308f, 0.335283f, 0.265107f, 0.764133f, 0.951267f, 0.452242f, 0.896686f, 0.397661f, 0.08577f, 0.584795f, 0.8577f, 0.358674f, 0.920078f, 0.421053f, 0.740741f, 0.241715f, 0.678363f, 0.179337f, 0.109162f, 0.608187f, 0.17154f, 0.670565f, 0.491228f, 0.990253f, 0.42885f, 0.927875f, 0.0662768f, 0.565302f, 0.62768f, 0.128655f, 0.183236f, 0.682261f, 0.744639f, 0.245614f, 0.814815f, 0.315789f, 0.378168f, 0.877193f, 0.931774f, 0.432749f, 0.495127f, 0.994152f, 0.0350877f, 0.534113f, 0.97076f, 0.471735f, 0.214425f, 0.71345f, 0.526316f, 0.0272904f, 0.783626f, 0.2846f, 0.222222f, 0.721248f, 0.962963f, 0.463938f, 0.276803f, 0.775828f, 0.966862f, 0.467836f, 0.405458f, 0.904483f, 0.0701754f, 0.569201f, 0.881092f, 0.382066f, 0.218324f, 0.717349f, 0.654971f, 0.155945f, 0.818713f, 0.319688f, 0.132554f, 0.631579f, 0.0623782f, 0.561404f, 0.748538f, 0.249513f, 0.912281f, 0.413255f, 0.974659f, 0.475634f, 0.810916f, 0.311891f, 0.499025f, 0.998051f, 0.163743f, 0.662768f, 0.226121f, 0.725146f, 0.690058f, 0.191033f, 0.00389864f, 0.502924f, 0.557505f, 0.0584795f, 0.120858f, 0.619883f, 0.440546f, 0.939571f, 0.752437f, 0.253411f, 0.307992f, 0.807018f, 0.869396f, 0.37037f, 0.658869f, 0.159844f, 0.346979f, 0.846004f, 0.588694f, 0.0896686f, 0.152047f, 0.651072f, 0.409357f, 0.908382f, 0.596491f, 0.0974659f, 0.339181f, 0.838207f, 0.900585f, 0.401559f, 0.34308f, 0.842105f, 0.779727f, 0.280702f, 0.693957f, 0.194932f, 0.25731f, 0.756335f, 0.592593f, 0.0935673f, 0.0311891f, 0.530214f, 0.444444f, 0.94347f, 0.506823f, 0.00779727f, 0.68616f, 0.187135f, 0.124756f, 0.623782f, 0.288499f, 0.787524f, 0.350877f, 0.849903f, 0.436647f, 0.935673f, 0.873294f, 0.374269f, 0.538012f, 0.0389864f, 0.60039f, 0.101365f, 0.57115f, 0.0721248f, 0.758285f, 0.259259f, 0.719298f, 0.220273f, 0.532164f, 0.0331384f, 0.321637f, 0.820663f, 0.00974659f, 0.508772f, 0.469786f, 0.968811f, 0.282651f, 0.781676f, 0.539961f, 0.0409357f, 0.727096f, 0.22807f, 0.500975f, 0.00194932f, 0.563353f, 0.0643275f, 0.290448f, 0.789474f, 0.477583f, 0.976608f, 0.251462f, 0.750487f, 0.31384f, 0.812865f, 0.94152f, 0.442495f, 0.879142f, 0.380117f, 0.37232f, 0.871345f, 0.309942f, 0.808967f, 0.192982f, 0.692008f, 0.130604f, 0.62963f, 0.621832f, 0.122807f, 0.559454f, 0.0604289f, 0.660819f, 0.161793f, 0.723197f, 0.224172f, 0.403509f, 0.902534f, 0.840156f, 0.341131f, 0.411306f, 0.910331f, 0.473684f, 0.97271f, 0.653021f, 0.153996f, 0.0916179f, 0.590643f, 0.196881f, 0.695906f, 0.384016f, 0.883041f, 0.0955166f, 0.594542f, 0.157895f, 0.65692f, 0.945419f, 0.446394f, 0.633528f, 0.134503f, 0.844055f, 0.345029f, 0.906433f, 0.407407f, 0.165692f, 0.664717f, 0.103314f, 0.602339f, 0.126706f, 0.625731f, 0.189084f, 0.688109f, 0.91423f, 0.415205f, 0.851852f, 0.352827f, 0.875244f, 0.376218f, 0.937622f, 0.438596f, 0.317739f, 0.816764f, 0.255361f, 0.754386f, 0.996101f, 0.497076f, 0.933723f, 0.434698f, 0.567251f, 0.0682261f, 0.504873f, 0.00584795f, 0.247563f, 0.746589f, 0.185185f, 0.684211f, 0.037037f, 0.536062f, 0.0994152f, 0.598441f, 0.777778f, 0.278752f, 0.465887f, 0.964912f, 0.785575f, 0.28655f, 0.847953f, 0.348928f, 0.0292398f, 0.528265f, 0.7154f, 0.216374f, 0.39961f, 0.898636f, 0.961014f, 0.461988f, 0.0487329f, 0.547758f, 0.111111f, 0.610136f, 0.649123f, 0.150097f, 0.212476f, 0.711501f, 0.797271f, 0.298246f, 0.859649f, 0.360624f, 0.118908f, 0.617934f, 0.0565302f, 0.555556f, 0.329435f, 0.82846f, 0.516569f, 0.0175439f, 0.867446f, 0.368421f, 0.805068f, 0.306043f, 0.578947f, 0.079922f, 0.267057f, 0.766082f, 0.270955f, 0.76998f, 0.707602f, 0.208577f, 0.668616f, 0.169591f, 0.606238f, 0.107212f, 0.520468f, 0.0214425f, 0.45809f, 0.957115f, 0.419103f, 0.918129f, 0.356725f, 0.855751f, 0.988304f, 0.489279f, 0.426901f, 0.925926f, 0.450292f, 0.949318f, 0.512671f, 0.0136452f, 0.239766f, 0.738791f, 0.676413f, 0.177388f, 0.699805f, 0.20078f, 0.263158f, 0.762183f, 0.773879f, 0.274854f, 0.337232f, 0.836257f, 0.672515f, 0.173489f, 0.734893f, 0.235867f, 0.0253411f, 0.524366f, 0.586745f, 0.0877193f, 0.423002f, 0.922027f, 0.48538f, 0.984405f, 0.74269f, 0.243665f, 0.680312f, 0.181287f, 0.953216f, 0.454191f, 0.1423f, 0.641326f, 0.493177f, 0.992203f, 0.430799f, 0.929825f, 0.204678f, 0.703704f, 0.890838f, 0.391813f, 0.894737f, 0.395712f, 0.0838207f, 0.582846f, 0.0448343f, 0.54386f, 0.231969f, 0.730994f, 0.146199f, 0.645224f, 0.832359f, 0.333333f, 0.793372f, 0.294347f, 0.980507f, 0.481481f, 0.364522f, 0.863548f, 0.80117f, 0.302144f, 0.824561f, 0.325536f, 0.138402f, 0.637427f, 0.614035f, 0.11501f, 0.0526316f, 0.551657f, 0.0760234f, 0.575049f, 0.88694f, 0.387914f, }; PNANOVDB_FORCE_INLINE float pnanovdb_dither_lookup(pnanovdb_bool_t enabled, int offset) { return enabled ? pnanovdb_dither_lut[offset & 511] : 0.5f; } // ------------------------------------------------ HDDA ----------------------------------------------------------- #ifdef PNANOVDB_HDDA // Comment out to disable this explicit round-off check #define PNANOVDB_ENFORCE_FORWARD_STEPPING #define PNANOVDB_HDDA_FLOAT_MAX 1e38f struct pnanovdb_hdda_t { pnanovdb_int32_t dim; float tmin; float tmax; pnanovdb_coord_t voxel; pnanovdb_coord_t step; pnanovdb_vec3_t delta; pnanovdb_vec3_t next; }; PNANOVDB_STRUCT_TYPEDEF(pnanovdb_hdda_t) PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_hdda_pos_to_ijk(PNANOVDB_IN(pnanovdb_vec3_t) pos) { pnanovdb_coord_t voxel; voxel.x = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).x)); voxel.y = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).y)); voxel.z = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).z)); return voxel; } PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_hdda_pos_to_voxel(PNANOVDB_IN(pnanovdb_vec3_t) pos, int dim) { pnanovdb_coord_t voxel; voxel.x = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).x)) & (~(dim - 1)); voxel.y = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).y)) & (~(dim - 1)); voxel.z = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).z)) & (~(dim - 1)); return voxel; } PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_hdda_ray_start(PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction) { pnanovdb_vec3_t pos = pnanovdb_vec3_add( pnanovdb_vec3_mul(PNANOVDB_DEREF(direction), pnanovdb_vec3_uniform(tmin)), PNANOVDB_DEREF(origin) ); return pos; } PNANOVDB_FORCE_INLINE void pnanovdb_hdda_init(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda, PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction, float tmax, int dim) { PNANOVDB_DEREF(hdda).dim = dim; PNANOVDB_DEREF(hdda).tmin = tmin; PNANOVDB_DEREF(hdda).tmax = tmax; pnanovdb_vec3_t pos = pnanovdb_hdda_ray_start(origin, tmin, direction); pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); PNANOVDB_DEREF(hdda).voxel = pnanovdb_hdda_pos_to_voxel(PNANOVDB_REF(pos), dim); // x if (PNANOVDB_DEREF(direction).x == 0.f) { PNANOVDB_DEREF(hdda).next.x = PNANOVDB_HDDA_FLOAT_MAX; PNANOVDB_DEREF(hdda).step.x = 0; PNANOVDB_DEREF(hdda).delta.x = 0.f; } else if (dir_inv.x > 0.f) { PNANOVDB_DEREF(hdda).step.x = 1; PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x + dim - pos.x) * dir_inv.x; PNANOVDB_DEREF(hdda).delta.x = dir_inv.x; } else { PNANOVDB_DEREF(hdda).step.x = -1; PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x - pos.x) * dir_inv.x; PNANOVDB_DEREF(hdda).delta.x = -dir_inv.x; } // y if (PNANOVDB_DEREF(direction).y == 0.f) { PNANOVDB_DEREF(hdda).next.y = PNANOVDB_HDDA_FLOAT_MAX; PNANOVDB_DEREF(hdda).step.y = 0; PNANOVDB_DEREF(hdda).delta.y = 0.f; } else if (dir_inv.y > 0.f) { PNANOVDB_DEREF(hdda).step.y = 1; PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y + dim - pos.y) * dir_inv.y; PNANOVDB_DEREF(hdda).delta.y = dir_inv.y; } else { PNANOVDB_DEREF(hdda).step.y = -1; PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y - pos.y) * dir_inv.y; PNANOVDB_DEREF(hdda).delta.y = -dir_inv.y; } // z if (PNANOVDB_DEREF(direction).z == 0.f) { PNANOVDB_DEREF(hdda).next.z = PNANOVDB_HDDA_FLOAT_MAX; PNANOVDB_DEREF(hdda).step.z = 0; PNANOVDB_DEREF(hdda).delta.z = 0.f; } else if (dir_inv.z > 0.f) { PNANOVDB_DEREF(hdda).step.z = 1; PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z + dim - pos.z) * dir_inv.z; PNANOVDB_DEREF(hdda).delta.z = dir_inv.z; } else { PNANOVDB_DEREF(hdda).step.z = -1; PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z - pos.z) * dir_inv.z; PNANOVDB_DEREF(hdda).delta.z = -dir_inv.z; } } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_update(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda, PNANOVDB_IN(pnanovdb_vec3_t) origin, PNANOVDB_IN(pnanovdb_vec3_t) direction, int dim) { if (PNANOVDB_DEREF(hdda).dim == dim) { return PNANOVDB_FALSE; } // compute valid voxel range pnanovdb_coord_t voxel_max = { (PNANOVDB_DEREF(hdda).voxel.x + PNANOVDB_DEREF(hdda).dim - 1) & (~(dim - 1)), (PNANOVDB_DEREF(hdda).voxel.y + PNANOVDB_DEREF(hdda).dim - 1) & (~(dim - 1)), (PNANOVDB_DEREF(hdda).voxel.z + PNANOVDB_DEREF(hdda).dim - 1) & (~(dim - 1)) }; pnanovdb_coord_t voxel_min = { PNANOVDB_DEREF(hdda).voxel.x & (~(dim - 1)), PNANOVDB_DEREF(hdda).voxel.y & (~(dim - 1)), PNANOVDB_DEREF(hdda).voxel.z & (~(dim - 1)) }; PNANOVDB_DEREF(hdda).dim = dim; pnanovdb_vec3_t pos = pnanovdb_vec3_add( pnanovdb_vec3_mul(PNANOVDB_DEREF(direction), pnanovdb_vec3_uniform(PNANOVDB_DEREF(hdda).tmin)), PNANOVDB_DEREF(origin) ); pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); PNANOVDB_DEREF(hdda).voxel = pnanovdb_hdda_pos_to_voxel(PNANOVDB_REF(pos), dim); // clamp voxel to valid range PNANOVDB_DEREF(hdda).voxel.x = PNANOVDB_DEREF(hdda).voxel.x < voxel_max.x ? PNANOVDB_DEREF(hdda).voxel.x : voxel_max.x; PNANOVDB_DEREF(hdda).voxel.y = PNANOVDB_DEREF(hdda).voxel.y < voxel_max.y ? PNANOVDB_DEREF(hdda).voxel.y : voxel_max.y; PNANOVDB_DEREF(hdda).voxel.z = PNANOVDB_DEREF(hdda).voxel.z < voxel_max.z ? PNANOVDB_DEREF(hdda).voxel.z : voxel_max.z; PNANOVDB_DEREF(hdda).voxel.x = PNANOVDB_DEREF(hdda).voxel.x > voxel_min.x ? PNANOVDB_DEREF(hdda).voxel.x : voxel_min.x; PNANOVDB_DEREF(hdda).voxel.y = PNANOVDB_DEREF(hdda).voxel.y > voxel_min.y ? PNANOVDB_DEREF(hdda).voxel.y : voxel_min.y; PNANOVDB_DEREF(hdda).voxel.z = PNANOVDB_DEREF(hdda).voxel.z > voxel_min.z ? PNANOVDB_DEREF(hdda).voxel.z : voxel_min.z; if (PNANOVDB_DEREF(hdda).step.x != 0) { PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x - pos.x) * dir_inv.x; if (PNANOVDB_DEREF(hdda).step.x > 0) { PNANOVDB_DEREF(hdda).next.x += dim * dir_inv.x; } } if (PNANOVDB_DEREF(hdda).step.y != 0) { PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y - pos.y) * dir_inv.y; if (PNANOVDB_DEREF(hdda).step.y > 0) { PNANOVDB_DEREF(hdda).next.y += dim * dir_inv.y; } } if (PNANOVDB_DEREF(hdda).step.z != 0) { PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z - pos.z) * dir_inv.z; if (PNANOVDB_DEREF(hdda).step.z > 0) { PNANOVDB_DEREF(hdda).next.z += dim * dir_inv.z; } } return PNANOVDB_TRUE; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_step(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda) { pnanovdb_bool_t ret; if (PNANOVDB_DEREF(hdda).next.x < PNANOVDB_DEREF(hdda).next.y && PNANOVDB_DEREF(hdda).next.x < PNANOVDB_DEREF(hdda).next.z) { #ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING if (PNANOVDB_DEREF(hdda).next.x <= PNANOVDB_DEREF(hdda).tmin) { PNANOVDB_DEREF(hdda).next.x += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.x + 1.0e-6f; } #endif PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.x; PNANOVDB_DEREF(hdda).next.x += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.x; PNANOVDB_DEREF(hdda).voxel.x += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.x; ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; } else if (PNANOVDB_DEREF(hdda).next.y < PNANOVDB_DEREF(hdda).next.z) { #ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING if (PNANOVDB_DEREF(hdda).next.y <= PNANOVDB_DEREF(hdda).tmin) { PNANOVDB_DEREF(hdda).next.y += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.y + 1.0e-6f; } #endif PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.y; PNANOVDB_DEREF(hdda).next.y += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.y; PNANOVDB_DEREF(hdda).voxel.y += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.y; ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; } else { #ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING if (PNANOVDB_DEREF(hdda).next.z <= PNANOVDB_DEREF(hdda).tmin) { PNANOVDB_DEREF(hdda).next.z += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.z + 1.0e-6f; } #endif PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.z; PNANOVDB_DEREF(hdda).next.z += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.z; PNANOVDB_DEREF(hdda).voxel.z += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.z; ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; } return ret; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_ray_clip( PNANOVDB_IN(pnanovdb_vec3_t) bbox_min, PNANOVDB_IN(pnanovdb_vec3_t) bbox_max, PNANOVDB_IN(pnanovdb_vec3_t) origin, PNANOVDB_INOUT(float) tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction, PNANOVDB_INOUT(float) tmax ) { pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); pnanovdb_vec3_t t0 = pnanovdb_vec3_mul(pnanovdb_vec3_sub(PNANOVDB_DEREF(bbox_min), PNANOVDB_DEREF(origin)), dir_inv); pnanovdb_vec3_t t1 = pnanovdb_vec3_mul(pnanovdb_vec3_sub(PNANOVDB_DEREF(bbox_max), PNANOVDB_DEREF(origin)), dir_inv); pnanovdb_vec3_t tmin3 = pnanovdb_vec3_min(t0, t1); pnanovdb_vec3_t tmax3 = pnanovdb_vec3_max(t0, t1); float tnear = pnanovdb_max(tmin3.x, pnanovdb_max(tmin3.y, tmin3.z)); float tfar = pnanovdb_min(tmax3.x, pnanovdb_min(tmax3.y, tmax3.z)); pnanovdb_bool_t hit = tnear <= tfar; PNANOVDB_DEREF(tmin) = pnanovdb_max(PNANOVDB_DEREF(tmin), tnear); PNANOVDB_DEREF(tmax) = pnanovdb_min(PNANOVDB_DEREF(tmax), tfar); return hit; } PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_zero_crossing( pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction, float tmax, PNANOVDB_INOUT(float) thit, PNANOVDB_INOUT(float) v ) { pnanovdb_coord_t bbox_min = pnanovdb_root_get_bbox_min(buf, PNANOVDB_DEREF(acc).root); pnanovdb_coord_t bbox_max = pnanovdb_root_get_bbox_max(buf, PNANOVDB_DEREF(acc).root); pnanovdb_vec3_t bbox_minf = pnanovdb_coord_to_vec3(bbox_min); pnanovdb_vec3_t bbox_maxf = pnanovdb_coord_to_vec3(pnanovdb_coord_add(bbox_max, pnanovdb_coord_uniform(1))); pnanovdb_bool_t hit = pnanovdb_hdda_ray_clip(PNANOVDB_REF(bbox_minf), PNANOVDB_REF(bbox_maxf), origin, PNANOVDB_REF(tmin), direction, PNANOVDB_REF(tmax)); if (!hit || tmax > 1.0e20f) { return PNANOVDB_FALSE; } pnanovdb_vec3_t pos = pnanovdb_hdda_ray_start(origin, tmin, direction); pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos)); pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); float v0 = pnanovdb_read_float(buf, address); pnanovdb_int32_t dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); pnanovdb_hdda_t hdda; pnanovdb_hdda_init(PNANOVDB_REF(hdda), origin, tmin, direction, tmax, dim); while (pnanovdb_hdda_step(PNANOVDB_REF(hdda))) { pnanovdb_vec3_t pos_start = pnanovdb_hdda_ray_start(origin, hdda.tmin + 1.0001f, direction); ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos_start)); dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); pnanovdb_hdda_update(PNANOVDB_REF(hdda), origin, direction, dim); if (hdda.dim > 1 || !pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(ijk))) { continue; } while (pnanovdb_hdda_step(PNANOVDB_REF(hdda)) && pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(hdda.voxel))) { ijk = hdda.voxel; pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); PNANOVDB_DEREF(v) = pnanovdb_read_float(buf, address); if (PNANOVDB_DEREF(v) * v0 < 0.f) { PNANOVDB_DEREF(thit) = hdda.tmin; return PNANOVDB_TRUE; } } } return PNANOVDB_FALSE; } #endif #endif // end of NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/Readme.md000066400000000000000000000012411510223237100200170ustar00rootroot00000000000000 # NanoVDB: A lightweight GPU friendly version of VDB initially targeting rendering applications. * [Build instructions for make and cmake](../../doc/nanovdb/HowToBuild.md) * [Frequently asked questions](../../doc/nanovdb/FAQ.md) * [Source tree](../../doc/nanovdb/SourceTree.md) * [Examples](../../doc/nanovdb/HelloWorld.md) ### Copyright Contributors to the OpenVDB Project ### SPDX-License-Identifier: Apache-2.0 [![CircleCI](https://circleci.com/gh/NVIDIA-Omniverse/NanoVDB.svg?style=svg&circle-token=6c3b9bb166841033a0e0c1a9ee5ac49f73d89152)](https://circleci.com/gh/NVIDIA-Omniverse/NanoVDB) openvdb-13.0.0/nanovdb/nanovdb/cmd/000077500000000000000000000000001510223237100170455ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/cmd/CMakeLists.txt000066400000000000000000000037121510223237100216100ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # #[=======================================================================[ CMake Configuration for NanoVDB Command Line Tools #]=======================================================================] cmake_minimum_required(VERSION 3.24) project(NanoVDBExamples LANGUAGES CXX) include(GNUInstallDirs) ############################################################################### message(STATUS "----------------------------------------------------") message(STATUS "--------- Configuring NanoVDB Cmd Tools ------------") message(STATUS "----------------------------------------------------") ############################################################################### # ----------------------------------------------------------------------------- # workaround for win32 bug when nvcc "--keep" is used. if(WIN32 AND NANOVDB_CUDA_KEEP_PTX) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release") endif() # ----------------------------------------------------------------------------- if(NOT NANOVDB_USE_OPENVDB) message(WARNING " - OpenVDB required to build nanovdb_convert. Skipping.") else() add_executable(nanovdb_convert convert/nanovdb_convert.cc) target_link_libraries(nanovdb_convert PRIVATE nanovdb) install(TARGETS nanovdb_convert RUNTIME DESTINATION ${NANOVDB_INSTALL_BINDIR}) endif() # ----------------------------------------------------------------------------- # nanovdb_print add_executable(nanovdb_print print/nanovdb_print.cc) target_link_libraries(nanovdb_print PRIVATE nanovdb) install(TARGETS nanovdb_print RUNTIME DESTINATION ${NANOVDB_INSTALL_BINDIR}) # ----------------------------------------------------------------------------- # nanovdb_validate add_executable(nanovdb_validate validate/nanovdb_validate.cc) target_link_libraries(nanovdb_validate PRIVATE nanovdb) install(TARGETS nanovdb_validate RUNTIME DESTINATION ${NANOVDB_INSTALL_BINDIR}) openvdb-13.0.0/nanovdb/nanovdb/cmd/convert/000077500000000000000000000000001510223237100205255ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/cmd/convert/nanovdb_convert.cc000066400000000000000000000357661510223237100242440ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb_convert.cc \author Ken Museth \date May 21, 2020 \brief Command-line tool that converts between openvdb and nanovdb files */ #include #include #include #include // this is required to read (and write) NanoVDB files on the host #include #include void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE) { std::cerr << "\nUsage: " << progName << " [options] *.vdb output.nvdb\n" << "Which: converts one or more OpenVDB files to a single NanoVDB file\n\n" << "Usage: " << progName << " [options] *.nvdb output.vdb\n" << "Which: converts one or more NanoVDB files to a single OpenVDB file\n\n" << "Options:\n" << "-a,--abs-error float\t Absolute error tolerance used for variable bit depth quantization\n" << "-b,--blosc\tUse BLOSC compression on the output file\n" << "-c,--checksum mode\t where mode={none, partial, full}\n" << "-d,--dither\tApply dithering during blocked compression\n" << "-f,--force\tOverwrite output file if it already exists\n" << "--fp4\tQuantize float grids to 4 bits\n" << "--fp8\tQuantize float grids to 8 bits\n" << "--fp16\tQuantize float grids to 16 bits\n" << "--fpN\tQuantize float grids to variable bit depth (use -a or -r to specify a tolerance)\n" << "--index\tProduce an IndexGrid where all float values are encoded as sidecar data\n" << "--onIndex\tProduce an IndexGrid where active float values are encoded as sidecar data\n" << "-g,--grid name\tConvert all grids matching the specified string name\n" << "-h,--help\tPrints this message\n" << "-r,--rel-error float\t Relative error tolerance used for variable bit depth quantization\n" << "-s,--stats mode\t where mode={none, bbox, extrema, all}\n" << "-v,--verbose\tPrint verbose information to the terminal\n" << "--version\tPrint version information to the terminal\n" << "-z,--zip\tUse ZIP compression on the output file\n"; exit(exitStatus); } void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS) { char str[8]; nanovdb::toStr(str, nanovdb::Version()); printf("\n%s was build against NanoVDB version %s\n", progName, str); exit(exitStatus); } int main(int argc, char* argv[]) { int exitStatus = EXIT_SUCCESS; nanovdb::io::Codec codec = nanovdb::io::Codec::NONE;// compression codec for the file nanovdb::tools::StatsMode sMode = nanovdb::tools::StatsMode::Default; nanovdb::CheckMode cMode = nanovdb::CheckMode::Default; nanovdb::GridType qMode = nanovdb::GridType::Unknown;//specify the quantization mode bool verbose = false, overwrite = false, dither = false, absolute = true; float tolerance = -1.0f; std::string gridName; std::vector fileNames; auto toLowerCase = [](std::string &str) { std::transform(str.begin(), str.end(), str.begin(),[](unsigned char c){return std::tolower(c);}); }; for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg[0] == '-') { if (arg == "-v" || arg == "--verbose") { verbose = true; } else if (arg == "--version") { version(argv[0]); } else if (arg == "-f" || arg == "--force") { overwrite = true; } else if (arg == "--fp4") { qMode = nanovdb::GridType::Fp4; } else if (arg == "--fp8") { qMode = nanovdb::GridType::Fp8; } else if (arg == "--fp16") { qMode = nanovdb::GridType::Fp16; } else if (arg == "--fpN") { qMode = nanovdb::GridType::FpN; } else if (arg == "--index") { qMode = nanovdb::GridType::Index; } else if (arg == "--onIndex") { qMode = nanovdb::GridType::OnIndex; } else if (arg == "-h" || arg == "--help") { usage(argv[0], EXIT_SUCCESS); } else if (arg == "-b" || arg == "--blosc") { codec = nanovdb::io::Codec::BLOSC; } else if (arg == "-d" || arg == "--dither") { dither = true; } else if (arg == "-z" || arg == "--zip") { codec = nanovdb::io::Codec::ZIP; } else if (arg == "-c" || arg == "--checksum") { if (i + 1 == argc) { std::cerr << "Expected a mode to follow the -c,--checksum option\n" << std::endl; usage(argv[0]); } else { std::string str(argv[++i]); toLowerCase(str); if (str == "none") { cMode = nanovdb::CheckMode::Disable; } else if (str == "partial") { cMode = nanovdb::CheckMode::Partial; } else if (str == "full") { cMode = nanovdb::CheckMode::Full; } else { std::cerr << "Expected one of the following checksum modes: {none, partial, full}\n" << std::endl; usage(argv[0]); } } } else if (arg == "-s" || arg == "--stats") { if (i + 1 == argc) { std::cerr << "Expected a mode to follow the -s,--stats option\n" << std::endl; usage(argv[0]); } else { std::string str(argv[++i]); toLowerCase(str); if (str == "none") { sMode = nanovdb::tools::StatsMode::Disable; } else if (str == "bbox") { sMode = nanovdb::tools::StatsMode::BBox; } else if (str == "extrema") { sMode = nanovdb::tools::StatsMode::MinMax; } else if (str == "all") { sMode = nanovdb::tools::StatsMode::All; } else { std::cerr << "Expected one of the following stats modes: {none, bbox, extrema, all}\n" << std::endl; usage(argv[0]); } } } else if (arg == "-a" || arg == "--abs-error") { if (i + 1 == argc) { std::cerr << "Expected a float to follow the -a,--abs-error option\n" << std::endl; usage(argv[0]); } else { qMode = nanovdb::GridType::FpN; absolute = true; tolerance = static_cast(atof(argv[++i])); } } else if (arg == "-r" || arg == "--rel-error") { if (i + 1 == argc) { std::cerr << "Expected a float to follow the -r,--rel-error option\n" << std::endl; usage(argv[0]); } else { qMode = nanovdb::GridType::FpN; absolute = false; tolerance = static_cast(atof(argv[++i])); } } else if (arg == "-g" || arg == "--grid") { if (i + 1 == argc) { std::cerr << "Expected a grid name to follow the -g,--grid option\n" << std::endl; usage(argv[0]); } else { gridName.assign(argv[++i]); } } else { std::cerr << "\nIllegal option: \"" << arg << "\"\n"; usage(argv[0]); } } else if (!arg.empty()) { fileNames.push_back(arg); } } if (fileNames.size() < 2) { std::cerr << "Expected at least one input file followed by exactly one output file\n" << std::endl; usage(argv[0]); } const std::string outputFile = fileNames.back();// last file is always the output file const std::string ext = outputFile.substr(outputFile.find_last_of(".") + 1); bool toNanoVDB = false; if (ext == "nvdb") { toNanoVDB = true; } else if (ext == "vdb") { if (qMode != nanovdb::GridType::Unknown) { std::cerr << "The options are incompatible an output of type OpenVDB" << std::endl; usage(argv[0]); } } else { std::cerr << "Unrecognized file extension: \"" << ext << "\"\n" << std::endl; usage(argv[0]); } fileNames.pop_back();// remove the output file name if (!overwrite) { std::ifstream is(outputFile, std::ios::in | std::ios::binary); if (is.peek() != std::ifstream::traits_type::eof()) { std::cout << "Overwrite the existing output file named \"" << outputFile << "\"? [Y]/N: "; std::string answer; getline(std::cin, answer); toLowerCase(answer); if (!answer.empty() && answer != "y" && answer != "yes") { std::cout << "Please specify a different output file" << std::endl; exit(EXIT_SUCCESS); } } } openvdb::initialize(); // Note, unlike OpenVDB, NanoVDB allows for multiple write operations into the same output file stream. // Hence, NanoVDB grids can be read, converted and written to file one at a time whereas all // the OpenVDB grids has to be written to file in a single operation. auto openToNano = [&](const openvdb::GridBase::Ptr& base) { const bool includeStats = false, includeTiles = false; const int verb = verbose ? 1 : 0; if (qMode == nanovdb::GridType::OnIndex) { return nanovdb::tools::openToIndexVDB(base, 1u, includeStats, includeTiles, verb); } else if (qMode == nanovdb::GridType::Index) { return nanovdb::tools::openToIndexVDB(base, 1u, includeStats, includeTiles, verb); } if (auto floatGrid = openvdb::GridBase::grid(base)) { nanovdb::tools::CreateNanoGrid s(*floatGrid); s.setStats(sMode); s.setChecksum(cMode); s.enableDithering(dither); s.setVerbose(verbose ? 1 : 0); switch (qMode) { case nanovdb::GridType::Fp4: return s.getHandle(); case nanovdb::GridType::Fp8: return s.getHandle(); case nanovdb::GridType::Fp16: return s.getHandle(); case nanovdb::GridType::FpN: if (absolute) { return s.getHandle(nanovdb::tools::AbsDiff(tolerance)); } else { return s.getHandle(nanovdb::tools::RelDiff(tolerance)); } default: break; }// end of switch } return nanovdb::tools::openToNanoVDB(base, sMode, cMode, verb); }; try { if (toNanoVDB) { // OpenVDB -> NanoVDB std::ofstream os(outputFile, std::ios::out | std::ios::binary); for (auto& inputFile : fileNames) { if (inputFile.substr(inputFile.find_last_of(".") + 1) != "vdb") { std::cerr << "Since the last file has extension .nvdb the remaining input files were expected to have extensions .vdb\n" << std::endl; usage(argv[0]); } if (verbose) std::cout << "Opening OpenVDB file named \"" << inputFile << "\"" << std::endl; openvdb::io::File file(inputFile); file.open(false); //disable delayed loading if (gridName.empty()) {// convert all grid in the file auto grids = file.getGrids(); std::vector > handles; for (auto& grid : *grids) { if (verbose) std::cout << "Converting OpenVDB grid named \"" << grid->getName() << "\" to NanoVDB" << std::endl; handles.push_back(openToNano(grid)); } // loop over OpenVDB grids in file auto handle = nanovdb::mergeGrids(handles); nanovdb::io::writeGrid(os, handle, codec); } else {// convert only grid with matching name auto grid = file.readGrid(gridName); if (verbose) std::cout << "Converting OpenVDB grid named \"" << grid->getName() << "\" to NanoVDB" << std::endl; auto handle = openToNano(grid); nanovdb::io::writeGrid(os, handle, codec); } } // loop over input files } else { // NanoVDB -> OpenVDB openvdb::io::File file(outputFile); openvdb::GridPtrVecPtr grids(new openvdb::GridPtrVec()); for (auto& inputFile : fileNames) { if (inputFile.substr(inputFile.find_last_of(".") + 1) != "nvdb") { std::cerr << "Since the last file has extension .vdb the remaining input files were expected to have extensions .nvdb\n" << std::endl; usage(argv[0]); } if (verbose) std::cout << "Opening NanoVDB file named \"" << inputFile << "\"" << std::endl; if (gridName.empty()) { auto handles = nanovdb::io::readGrids(inputFile, verbose); for (auto &h : handles) { for (uint32_t i = 0; i < h.gridCount(); ++i) { if (verbose) std::cout << "Converting NanoVDB grid named \"" << h.gridMetaData(i)->shortGridName() << "\" to OpenVDB" << std::endl; grids->push_back(nanovdb::tools::nanoToOpenVDB(h, i)); } } } else { auto handle = nanovdb::io::readGrid(inputFile, gridName); if (!handle) { std::cerr << "File did not contain a NanoVDB grid named \"" << gridName << "\"\n" << std::endl; usage(argv[0]); } if (verbose) std::cout << "Converting NanoVDB grid named \"" << handle.gridMetaData()->shortGridName() << "\" to OpenVDB" << std::endl; grids->push_back(nanovdb::tools::nanoToOpenVDB(handle)); } } // loop over input files file.write(*grids); } } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; exitStatus = EXIT_FAILURE; } catch (...) { std::cerr << "Exception oof unexpected type caught" << std::endl; exitStatus = EXIT_FAILURE; } return exitStatus; } openvdb-13.0.0/nanovdb/nanovdb/cmd/print/000077500000000000000000000000001510223237100202015ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/cmd/print/nanovdb_print.cc000066400000000000000000000421411510223237100233550ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb_print.cc \author Ken Museth \date May 21, 2020 \brief Command-line tool that prints information about grids in a nanovdb file */ #include // this is required to read (and write) NanoVDB files on the host #include #include void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE) { std::cerr << "\nUsage: " << progName << " [options] *.nvdb\n" << "Which: Prints grid information from one or more NanoVDB files\n\n" << "Options:\n" << "-g,--grid name\tPrint all grids matching the specified string name\n" << "-h,--help\tPrints this message\n" << "-l,--long\tPrints out extra grid information\n" << "-s,--short\tOnly prints out a minimum amount of grid information\n" << "-v,--verbose\tPrint information about the meaning of the labels\n" << "--version\tPrint version information to the terminal\n"; exit(exitStatus); } void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS) { char str[8]; nanovdb::toStr(str, nanovdb::Version()); printf("\n%s was build against NanoVDB version %s\n", progName, str); exit(exitStatus); } int main(int argc, char* argv[]) { int exitStatus = EXIT_SUCCESS; enum Mode : int { Short = 0, Default = 1, Long = 2 } mode = Default; char str[32]; bool verbose = false; std::string gridName; std::vector fileNames; for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg[0] == '-') { if (arg == "-h" || arg == "--help") { usage(argv[0], EXIT_SUCCESS); } else if (arg == "--version") { version(argv[0]); } else if (arg == "-s" || arg == "--short") { mode = Short; } else if (arg == "-l" || arg == "--long") { mode = Long; } else if (arg == "-v" || arg == "--verbose") { verbose = true; } else if (arg == "-g" || arg == "--grid") { if (i + 1 == argc) { std::cerr << "\nExpected a grid name to follow the -g,--grid option\n"; usage(argv[0]); } else { gridName.assign(argv[++i]); } } else { std::cerr << "\nIllegal option: \"" << arg << "\"\n"; usage(argv[0]); } } else if (!arg.empty()) { fileNames.push_back(arg); } } if (fileNames.size() == 0) { std::cerr << "\nExpected at least one input NanoVDB file\n"; usage(argv[0]); } const auto nameKey = nanovdb::io::stringHash(gridName); auto format = [](uint64_t b) { std::stringstream ss; ss << std::setprecision(4); if (b >> 40) { ss << double(b) / double(1ULL << 40) << " TB"; } else if (b >> 30) { ss << double(b) / double(1ULL << 30) << " GB"; } else if (b >> 20) { ss << double(b) / double(1ULL << 20) << " MB"; } else if (b >> 10) { ss << double(b) / double(1ULL << 10) << " KB"; } else { ss << b << " Bytes"; } return ss.str(); }; const int padding = 2; auto width = [&](size_t& n, const std::string& str) { const auto size = str.length() + padding; if (size > n) n = size; }; auto Vec3dToStr = [](const nanovdb::Vec3d& v) { std::stringstream ss; ss << std::setprecision(3); ss << "(" << v[0] << "," << v[1] << "," << v[2] << ")"; return ss.str(); }; auto wbboxToStr = [](const nanovdb::math::BBox& bbox) { std::stringstream ss; if (bbox.empty()) { ss << "empty grid"; } else { ss << std::setprecision(3); ss << "(" << bbox[0][0] << "," << bbox[0][1] << "," << bbox[0][2] << ")"; ss << " -> "; ss << "(" << bbox[1][0] << "," << bbox[1][1] << "," << bbox[1][2] << ")"; } return ss.str(); }; auto ibboxToStr = [](const nanovdb::CoordBBox& bbox) { std::stringstream ss; if (bbox.empty()) { ss << "empty grid"; } else { ss << "(" << bbox[0][0] << "," << bbox[0][1] << "," << bbox[0][2] << ")"; ss << " -> "; ss << "(" << bbox[1][0] << "," << bbox[1][1] << "," << bbox[1][2] << ")"; } return ss.str(); }; auto resToStr = [](const nanovdb::CoordBBox& bbox) { std::stringstream ss; auto dim = bbox.dim(); ss << dim[0] << " x " << dim[1] << " x " << dim[2]; return ss.str(); }; auto nodesToStr = [](const uint32_t* nodes) { std::stringstream ss; ss << nodes[2] << "->" << nodes[1] << "->" << nodes[0]; return ss.str(); }; try { for (auto& file : fileNames) { auto list = nanovdb::io::readGridMetaData(file); if (!gridName.empty()) { std::vector tmp; for (auto& m : list) { if (nameKey == m.nameKey && gridName == m.gridName) tmp.emplace_back(m); } list = tmp; } if (list.size() == 0) continue; const auto numberWidth = std::to_string(list.size()).length() + padding; auto nameWidth = std::string("Name").length() + padding; auto typeWidth = std::string("Type").length() + padding; auto classWidth = std::string("Class").length() + padding; auto codecWidth = std::string("Codec").length() + padding; auto ibboxWidth = std::string("Index Bounding Box").length() + padding; auto wbboxWidth = std::string("World Bounding Box").length() + padding; auto sizeWidth = std::string("Size").length() + padding; auto fileWidth = std::string("File").length() + padding; auto voxelsWidth = std::string("# Voxels").length() + padding; auto voxelSizeWidth = std::string("Scale").length() + padding; auto versionWidth = std::string("Version").length() + padding; auto configWidth = std::string("32^3->16^3->8^3").length() + padding; auto tileWidth = std::string("# Active tiles").length() + padding; auto resWidth = std::string("Resolution").length() + padding; auto blindWidth = std::string("Blind data count").length() + padding; for (auto& m : list) { width(nameWidth, m.gridName); width(typeWidth, nanovdb::toStr(str, m.gridType)); width(classWidth, nanovdb::toStr(str, m.gridClass)); width(codecWidth, nanovdb::io::toStr(str, m.codec)); width(wbboxWidth, wbboxToStr(m.worldBBox)); width(ibboxWidth, ibboxToStr(m.indexBBox)); width(resWidth, resToStr(m.indexBBox)); width(sizeWidth, format(m.gridSize)); width(fileWidth, format(m.fileSize)); width(versionWidth, nanovdb::toStr(str, m.version)); width(configWidth, nodesToStr(m.nodeCount)); width(tileWidth, nodesToStr(m.tileCount)); width(voxelsWidth, std::to_string(m.voxelCount)); width(voxelSizeWidth, Vec3dToStr(m.voxelSize)); width(blindWidth, std::to_string(m.blindDataCount)); } std::cout << "\nThe file \"" << file << "\" contains the following "; if (list.size()>1) { std::cout << list.size() << " grids:\n"; } else { std::cout << "grid:\n"; } std::cout << std::left << std::setw(numberWidth) << "#" << std::left << std::setw(nameWidth) << "Name" << std::left << std::setw(typeWidth) << "Type"; if (mode != Short) { std::cout << std::left << std::setw(classWidth) << "Class" << std::left << std::setw(versionWidth) << "Version" << std::left << std::setw(codecWidth) << "Codec" << std::left << std::setw(sizeWidth) << "Size" << std::left << std::setw(fileWidth) << "File" << std::left << std::setw(voxelSizeWidth) << "Scale"; } std::cout << std::left << std::setw(voxelsWidth) << "# Voxels" << std::left << std::setw(resWidth) << "Resolution"; if (mode == Long) { std::cout << std::left << std::setw(configWidth) << "32^3->16^3->8^3" << std::left << std::setw(tileWidth) << "# Active tiles" << std::left << std::setw(ibboxWidth) << "Index Bounding Box" << std::left << std::setw(wbboxWidth) << "World Bounding Box" << std::left << std::setw(blindWidth) << "Blind data count"; } std::cout << std::endl; int n = 0; for (auto& m : list) { if (!gridName.empty() && (nameKey != m.nameKey || gridName != m.gridName)) continue; std::cout << std::left << std::setw(numberWidth) << ++n << std::left << std::setw(nameWidth) << m.gridName << std::left << std::setw(typeWidth) << nanovdb::toStr(str, m.gridType); if (mode != Short) { std::cout << std::left << std::setw(classWidth) << nanovdb::toStr(str, m.gridClass) << std::left << std::setw(versionWidth) << nanovdb::toStr(str+10, m.version) << std::left << std::setw(codecWidth) << nanovdb::io::toStr(str + 20, m.codec) << std::left << std::setw(sizeWidth) << format(m.gridSize) << std::left << std::setw(fileWidth) << format(m.fileSize) << std::left << std::setw(voxelSizeWidth) << Vec3dToStr(m.voxelSize); } std::cout << std::left << std::setw(voxelsWidth) << m.voxelCount << std::left << std::setw(resWidth) << resToStr(m.indexBBox); if (mode == Long) { std::cout << std::left << std::setw(configWidth) << nodesToStr(m.nodeCount) << std::left << std::setw(tileWidth) << nodesToStr(m.tileCount) << std::left << std::setw(ibboxWidth) << ibboxToStr(m.indexBBox) << std::left << std::setw(wbboxWidth) << wbboxToStr(m.worldBBox) << std::left << std::setw(blindWidth) << m.blindDataCount; } std::cout << std::endl; }// loop over FileGridMetaData in list from a single file }// loop over files if (verbose) { size_t w = 0; switch (mode) { case Mode::Short: width(w, "\"Name\":"); width(w, "\"Type\":"); width(w, "\"# Voxels\":"); width(w, "\"Resolution\":"); std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty." << std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc." << std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid." << std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!\n"; break; case Mode::Default: width(w, "\"Name\":"); width(w, "\"Type\":"); width(w, "\"Class\":"); width(w, "\"Version\":"); width(w, "\"Codec\":"); width(w, "\"Size\":"); width(w, "\"File\":"); width(w, "\"Scale\":"); width(w, "\"# Voxels\":"); width(w, "\"Resolution\":"); std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty." << std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc." << std::left << std::setw(w) << "\n\"Class\":" << "class of the grid, e.g. FOG for Fog volume, LS for level set, etc." << std::left << std::setw(w) << "\n\"Version\":" << "major.minor.patch version numbers of the grid." << std::left << std::setw(w) << "\n\"Codec\":" << "codec of the optional compression applied to the out-of-core grid, i.e. on disk." << std::left << std::setw(w) << "\n\"Size\":" << "In-core memory footprint of the grid, i.e. in ram." << std::left << std::setw(w) << "\n\"File\":" << "Out-of-core memory footprint of the grid, i.e. on disk." << std::left << std::setw(w) << "\n\"Scale\":" << "Scale of the grid, i.e. the size of a voxel in world units." << std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid." << std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!\n"; break; case Mode::Long: width(w, "\"Name\":"); width(w, "\"Type\":"); width(w, "\"Class\":"); width(w, "\"Version\":"); width(w, "\"Codec\":"); width(w, "\"Size\":"); width(w, "\"File\":"); width(w, "\"Scale\":"); width(w, "\"# Voxels\":"); width(w, "\"Resolution\":"); width(w, "\"32^3->16^3->8^3\":"); width(w, "\"# Active tiles\":"); width(w, "\"Index Bounding Box\":"); width(w, "\"World Bounding Box\":"); std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty." << std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc." << std::left << std::setw(w) << "\n\"Class\":" << "class of the grid, e.g. FOG for Fog volume, LS for level set, etc." << std::left << std::setw(w) << "\n\"Version\":" << "major.minor.patch version numbers of the grid." << std::left << std::setw(w) << "\n\"Codec\":" << "codec of the optional compression applied to the out-of-core grid, i.e. on disk." << std::left << std::setw(w) << "\n\"Size\":" << "In-core memory footprint of the grid, e.g. in RAM on the CPU." << std::left << std::setw(w) << "\n\"File\":" << "Out-of-core memory footprint of the grid, i.e. compressed on disk." << std::left << std::setw(w) << "\n\"Scale\":" << "Scale of the grid, i.e. the size of a voxel in world units." << std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid. Note this includes both active tiles and voxels." << std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!" << std::left << std::setw(w) << "\n\"32^3->16^3->8^3\":" << "Number of nodes at each level of the tree structure from the root to leaf level." << std::left << std::setw(w) << "\n\"# Active tiles\":" << "Number of active tiles at each level of the tree structure from the root to leaf level." << std::left << std::setw(w) << "\n\"Index Bounding Box\":" << "coordinate bounding box of all the active values in a grid. Note that both min and max coordinates are inclusive!" << std::left << std::setw(w) << "\n\"World Bounding Box\":" << "world-space bounding box of all the active values in a grid. Note that min is inclusive and max is exclusive!\n"; break; default: throw std::runtime_error("Internal error in switch!"); break; } } } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; exitStatus = EXIT_FAILURE; } catch (...) { std::cerr << "Exception of unexpected type caught" << std::endl; exitStatus = EXIT_FAILURE; } return exitStatus; }// main openvdb-13.0.0/nanovdb/nanovdb/cmd/updateFiles.py000066400000000000000000000170701510223237100216710ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 import argparse import os from pathlib import Path def open_file(file_path): """ Opens a file. If utf-8 decoding fails, try windows-1252. Args: file_path: Path of the file to open. Returns: The content of the file in an arbitrary format. """ try: with open(file_path, "r", encoding="utf-8", errors="replace") as file: return file.read() except UnicodeDecodeError: with open(file_path, "r", encoding="windows-1252", errors="replace") as file: return file.read() def write_file(file_path, content): """ Writes a file. If utf-8 decoding fails, try windows-1252. Args: file_path: Path of the file to open. Returns: None. """ try: with open(file_path, "w", encoding="utf-8", errors="replace") as file: file.write(content) except UnicodeDecodeError: with open(file_path, "w", encoding="windows-1252", errors="replace") as file: file.write(content) def update_files(dir_path): """ Updates the content of files ending in .h, .cuh, .cc, .cu, and .cpp to call the appropriate API as we update NanoVDB from version 32.6 to version 32.7. This includes changes in namespaces, function names, and include directories. Args: Directory path: will include files in downstream directories. Returns: None. Writes the contents of the file. """ # List of file extensions to search for file_extensions = [".h", ".cuh", ".cc", ".cu", ".cpp"] nspace_dic = { "math": [ "Ray", "DDA<", "HDDA", "Vec3<", "Vec4<", "BBox<", "ZeroCrossing", "TreeMarcher", "PointTreeMarcher", "BoxStencil<", "CurvatureStencil<", "GradStencil<", "WenoStencil<", "AlignUp", "Min", "Max", "Abs", "Clamp", "Sqrt", "Sign", "Maximum<", "Delta<", "RoundDown<", "pi<", "isApproxZero<", "Round<", "createSampler", "SampleFromVoxels<", ], "tools": [ "createNanoGrid", "StatsMode", "createLevelSetSphere", "createFogVolumeSphere", "createFogVolumeSphere createFogVolumeSphere", "createFogVolumeTorus", "createLevelSetBox", "CreateNanoGrid", "updateGridStats", "evalChecksum", "validateChecksum", "checkGrid", "Extrema", ], "util": [ "is_floating_point", "findLowestOn", "findHighestOn", "Range", "streq", "strcpy", "strcat", "empty(", "Split", "invoke", "forEach", "reduce", "prefixSum", "is_same", "is_specialization", "PtrAdd", "PtrDiff", ], } rename_dic = { # list from func4 in updateFiles.sh "nanovdb::build::": "nanovdb::tools::build::", "nanovdb::BBoxR": "nanovdb::Vec3dBBox", "nanovdb::BBox": "nanovdb::Vec3dBbox", # scope and rename, i.e. list from func2 in updateFiles.sh "nanovdb::cudaCreateNodeManager": "nanovdb::cuda::createNodeManager", "nanovdb::cudaVoxelsToGrid": "nanovdb::cuda::voxelsToGrid", "nanovdb::cudaPointsToGrid": "nanovdb::cuda::pointsToGrid", "nanovdb::DitherLUT": "nanovdb::math::DitherLUT", "nanovdb::PackedRGBA8": "nanovdb::math::Rgba8", "nanovdb::Rgba8": "nanovdb::math::Rgba8", "nanovdb::CpuTimer": "nanovdb::util::Timer", "nanovdb::GpuTimer": "nanovdb::util::cuda::Timer", "nanovdb::CountOn": "nanovdb::util::countOn", } movdir_dic = { # list comes from func3 calls on updateFiles.sh "util/GridHandle.h": "GridHandle.h", "util/BuildGrid.h": "tools/GridBuilder.h", "util/GridBuilder.h": "tools/GridBuilder.h", "util/IO.h": "io/IO.h", "util/CSampleFromVoxels.h": "math/CSampleFromVoxels.h", "util/DitherLUT.h": "math/DitherLUT.h", "util/HDDA.h": "math/HDDA.h", "util/Ray.h": "math/Ray.h", "util/SampleFromVoxels.h": "math/SampleFromVoxels.h", "util/Stencils.h": "nanovdb/math/Stencils.h", "util/CreateNanoGrid.h": "tools/CreateNanoGrid.h", "util/Primitives.h": "tools/CreatePrimitives.h", "util/GridChecksum.h": "tools/GridChecksum.h", "util/GridStats.h": "tools/GridStats.h", "util/GridChecksum.h": "tools/GridChecksum.h", "util/GridValidator.h": "tools/GridValidator.h", "util/NanoToOpenVDB.h": "tools/NanoToOpenVDB.h", "util/cuda/CudaGridChecksum.cuh": "tools/cuda/CudaGridChecksum.cuh", "util/cuda/CudaGridStats.cuh": "tools/cuda/CudaGridStats.cuh", "util/cuda/CudaGridValidator.cuh": "tools/cuda/CudaGridValidator.cuh", "util/cuda/CudaIndexToGrid.cuh": "tools/cuda/CudaIndexToGrid.cuh", "util/cuda/CudaPointsToGrid.cuh": "tools/cuda/PointsToGrid.cuh", "util/cuda/CudaSignedFloodFill.cuh": "tools/cuda/CudaSignedFloodFill.cuh", "util/cuda/CudaDeviceBuffer.h": "cuda/DeviceBuffer.h", "util/cuda/CudaGridHandle.cuh": "cuda/GridHandle.cuh", "util/cuda/CudaUtils.h": "util/cuda/Util.h", "util/cuda/GpuTimer.h": "util/cuda/Timer.h", } # Iterate over files in the directory and its subdirectories for root, dirs, files in os.walk(dir_path): for file in files: if any(file.endswith(ext) for ext in file_extensions): file_path = os.path.join(root, file) print(f"Processing file: {file_path}") content = open_file(file_path) # Correspond to func1 $file in updateFiles.sh for key, vals in nspace_dic.items(): for val in vals: old_word = "nanovdb::" + val new_word = "nanovdb::" + key + "::" + val content = content.replace(old_word, new_word) # Correspond to func4 and func2 in updateFiles.sh for key, val in rename_dic.items(): content = content.replace(key, val) # Correspond to func3 in updateFiles.sh for key, val in movdir_dic.items(): old_path = "" new_path = "" content = content.replace(old_path, new_path) write_file(file_path, content) # Example use: # To update all the files using NanoVDB in the current directory (and directories downstream): # python ./nanovdb/nanovdb/cmd/updateFiles.py # To update all the files using NanoVDB in a directory called foo (and directories downstream): # python ./nanovdb/nanovdb/cmd/updateFiles.py -d /path/to/foo if __name__ == "__main__": parser = argparse.ArgumentParser(description="Synthetic Data Generation for USD") parser.add_argument( "-d", "--directory", type=str, default=None, help="Path to directory containing .h, .cc, and .cu files using NanoVDB.", ) args = parser.parse_args() dir_path = os.getcwd() if args.directory is None else Path(args.directory).resolve() update_files(dir_path) openvdb-13.0.0/nanovdb/nanovdb/cmd/updateFiles.sh000077500000000000000000000105601510223237100216530ustar00rootroot00000000000000#!/bin/bash # Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 #Usage process all files in this directory or optionally specify a target directory # Define directory in which to find files dir="." if [ "$1" ]; then dir="$1" fi # Check if dir is not a directory if [ ! -d "$dir" ]; then echo -e "\nUsage: '$0 '\n" exit 1 fi # E.g.: func1 $file "math" "Coord" "Vec3" "Vec4" func1 () { for ((i=3; i<=$#; i++)); do arg="s/nanovdb::${!i}/nanovdb::$2::${!i}/g" #echo "sed -i $arg $1" sed -i $arg $1 done } # E.G.: func2 file namespace old new : nanovdb::old -> nanovdb::namespace::new in file func2 () { arg="s/nanovdb::$3/nanovdb::$2::$4/g" #echo "sed -i $arg $1" sed -i $arg $1 } # E.G.: func3 file path1/old.h path2/new.h -> in file func3 () { arg="s;;;g" #echo "sed -i $arg $1" sed -i $arg $1 } # E.g.: func4 file old new new -> old func4 () { arg="s;$2;$3;g" #echo "sed -i $arg $1" sed -i $arg $1 } # Loop through files in the target directory for file in $(find "$dir" -name '*.h' -or -name '*.cuh' -or -name '*.cc' -or -name '*.cu' -or -name '*.cpp'); do if [ -f "$file" ]; then echo "Processing file: $file" func1 $file math Ray "DDA<" HDDA "Vec3<" "Vec4<" "BBox<" ZeroCrossing TreeMarcher PointTreeMarcher\ "BoxStencil<" "CurvatureStencil<" "GradStencil<" "WenoStencil<" AlignUp Min Max Abs Clamp\ Sqrt Sign "Maximum<" "Delta<" "RoundDown<" "pi<" "isApproxZero<" "Round<" createSampler "SampleFromVoxels<" func1 $file tools createNanoGrid StatsMode createLevelSetSphere\ createFogVolumeSphere createFogVolumeSphere createFogVolumeSphere\ createFogVolumeTorus createLevelSetBox CreateNanoGrid updateGridStats\ evalChecksum validateChecksum checkGrid Extrema func1 $file util is_floating_point findLowestOn findHighestOn Range streq strcpy strcat "empty("\ Split invoke forEach reduce prefixSum is_same is_specialization PtrAdd PtrDiff func4 $file "nanovdb::build::" "nanovdb::tools::build::" func4 $file "nanovdb::BBoxR" "nanovdb::Vec3dBBox" func4 $file "nanovdb::BBox" "nanovdb::Vec3dBbox" func2 $file cuda cudaCreateNodeManager createNodeManager func2 $file cuda cudaVoxelsToGrid voxelsToGrid func2 $file cuda cudaPointsToGrid pointsToGrid func2 $file math DitherLUT DitherLUT func2 $file math PackedRGBA8 Rgba8 func2 $file math Rgba8 Rgba8 func2 $file util CpuTimer Timer func2 $file util GpuTimer "cuda::Timer" func2 $file util CountOn countOn func3 $file "util/GridHandle.h" "GridHandle.h" func3 $file "util/BuildGrid.h" "tools/GridBuilder.h" func3 $file "util/GridBuilder.h" "tools/GridBuilder.h" func3 $file "util/IO.h" "io/IO.h" func3 $file "util/CSampleFromVoxels.h" "math/CSampleFromVoxels.h" func3 $file "util/DitherLUT.h" "math/DitherLUT.h" func3 $file "util/HDDA.h" "math/HDDA.h" func3 $file "util/Ray.h" "math/Ray.h" func3 $file "util/SampleFromVoxels.h" "math/SampleFromVoxels.h" func3 $file "util/Stencils.h" "nanovdb/math/Stencils.h" func3 $file "util/CreateNanoGrid.h" "tools/CreateNanoGrid.h" func3 $file "util/Primitives.h" "tools/CreatePrimitives.h" func3 $file "util/GridChecksum.h" "tools/GridChecksum.h" func3 $file "util/GridStats.h" "tools/GridStats.h" func3 $file "util/GridChecksum.h" "tools/GridChecksum.h" func3 $file "util/GridValidator.h" "tools/GridValidator.h" func3 $file "util/NanoToOpenVDB.h" "tools/NanoToOpenVDB.h" func3 $file "util/cuda/CudaGridChecksum.cuh" "tools/cuda/CudaGridChecksum.cuh" func3 $file "util/cuda/CudaGridStats.cuh" "tools/cuda/CudaGridStats.cuh" func3 $file "util/cuda/CudaGridValidator.cuh" "tools/cuda/CudaGridValidator.cuh" func3 $file "util/cuda/CudaIndexToGrid.cuh" "tools/cuda/CudaIndexToGrid.cuh" func3 $file "util/cuda/CudaPointsToGrid.cuh" "tools/cuda/PointsToGrid.cuh" func3 $file "util/cuda/CudaSignedFloodFill.cuh" "tools/cuda/CudaSignedFloodFill.cuh" func3 $file "util/cuda/CudaDeviceBuffer.h" "cuda/DeviceBuffer.h" func3 $file "util/cuda/CudaGridHandle.cuh" "cuda/GridHandle.cuh" func3 $file "util/cuda/CudaUtils.h" "util/cuda/Util.h" func3 $file "util/cuda/GpuTimer.h" "util/cuda/Timer.h" fi done openvdb-13.0.0/nanovdb/nanovdb/cmd/validate/000077500000000000000000000000001510223237100206365ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/cmd/validate/nanovdb_validate.cc000066400000000000000000000102311510223237100244420ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb_validate.cc \author Ken Museth \date October 13, 2020 \brief Command-line tool that validates Grids in nanovdb files */ #include // this is required to read (and write) NanoVDB files on the host #include #include #include void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE) { std::cerr << "\nUsage: " << progName << " [options] *.nvdb\n" << "Which: Validates grids in one or more NanoVDB files\n\n" << "Options:\n" << "-g,--grid name\tOnly validate grids matching the specified string name\n" << "-h,--help\tPrints this message\n" << "-p,--partial\tPerform partial (i.e. fast) validation tests\n" << "-v,--verbose\tPrint verbose information information useful for debugging\n" << "--version\tPrint version information to the terminal\n"; exit(exitStatus); } void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS) { char str[8]; nanovdb::toStr(str, nanovdb::Version()); printf("\n%s was build against NanoVDB version %s\n", progName, str); exit(exitStatus); } int main(int argc, char* argv[]) { int exitStatus = EXIT_SUCCESS; bool verbose = false; nanovdb::CheckMode mode = nanovdb::CheckMode::Full; std::string gridName; std::vector fileNames; for (int i = 1; i < argc; ++i) { std::string arg = argv[i]; if (arg[0] == '-') { if (arg == "-h" || arg == "--help") { usage(argv[0], EXIT_SUCCESS); } else if (arg == "--version") { version(argv[0]); } else if (arg == "-v" || arg == "--verbose") { verbose = true; } else if (arg == "-p" || arg == "--partial") { mode = nanovdb::CheckMode::Partial; } else if (arg == "-g" || arg == "--grid") { if (i + 1 == argc) { std::cerr << "\nExpected a grid name to follow the -g,--grid option\n"; usage(argv[0]); } else { gridName.assign(argv[++i]); } } else { std::cerr << "\nIllegal option: \"" << arg << "\"\n"; usage(argv[0]); } } else if (!arg.empty()) { fileNames.push_back(arg); } } if (fileNames.size() == 0) { std::cerr << "\nExpected at least one input NanoVDB file\n"; usage(argv[0]); } const auto nameKey = nanovdb::io::stringHash(gridName); try { for (auto& file : fileNames) { auto list = nanovdb::io::readGridMetaData(file); if (!gridName.empty()) { std::vector tmp; for (auto& m : list) { if (nameKey == m.nameKey && gridName == m.gridName) tmp.emplace_back(m); } list = std::move(tmp); } if (list.size() == 0) continue; if (verbose) std::cout << "\nThe file \"" << file << "\" contains the following matching " << list.size() << " grid(s):\n"; for (auto& m : list) { auto handle = nanovdb::io::readGrid(file, m.gridName); const bool test = nanovdb::tools::validateGrids(handle, mode, verbose); if (verbose) { std::cout << "Grid named \"" << m.gridName << "\": " << (test ? "passed" : "failed") << std::endl; } else if (!test) { std::cout << "Grid named \"" << m.gridName << "\": failed" << std::endl; } } } } catch (const std::exception& e) { std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl; exitStatus = EXIT_FAILURE; } catch (...) { std::cerr << "Exception oof unexpected type caught" << std::endl; exitStatus = EXIT_FAILURE; } return exitStatus; } openvdb-13.0.0/nanovdb/nanovdb/cuda/000077500000000000000000000000001510223237100172165ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/cuda/DeviceBuffer.h000066400000000000000000000462031510223237100217250ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file DeviceBuffer.h \author Ken Museth \date January 8, 2020 \brief DeviceBuffer has one pinned host buffer and multiple device CUDA buffers \note This file has no device-only kernel functions, which explains why it's a .h and not .cuh file. */ #ifndef NANOVDB_CUDA_DEVICEBUFFER_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_DEVICEBUFFER_H_HAS_BEEN_INCLUDED #include #include // for std::shared_ptr #include // for BufferTraits #include // for cudaMalloc/cudaMallocManaged/cudaFree namespace nanovdb {// ================================================================ namespace cuda {// =================================================================== // ----------------------------> DeviceBuffer <-------------------------------------- /// @brief Simple memory buffer using un-managed pinned host memory when compiled with NVCC. /// Obviously this class is making explicit used of CUDA so replace it with your own memory /// allocator if you are not using CUDA. /// @note While CUDA's pinned host memory allows for asynchronous memory copy between host and device /// it is significantly slower then cached (un-pinned) memory on the host. class DeviceBuffer { uint64_t mSize; // total number of bytes managed by this buffer (assumed to be identical for host and device) void *mCpuData, **mGpuData; // raw pointers to the host and device buffers int mDeviceCount, mManaged;// if mManaged is non-zero this class is responsible for allocating and freeing memory buffers. Otherwise this is assumed to be handled externally /// @brief Initialize buffer /// @param size byte size of buffer to be initialized /// @param device id of the device on which to initialize the buffer /// @note All existing buffers are first cleared /// @warning size is expected to be non-zero. Use clear() clear buffer! void init(uint64_t size, int device, cudaStream_t stream); public: using PtrT = std::shared_ptr; /// @brief Default constructor of an empty buffer DeviceBuffer() : mSize(0), mCpuData(nullptr), mGpuData(nullptr), mDeviceCount(0), mManaged(0){} /// @brief Constructor with a specified device and size /// @param size byte size of buffer to be initialized /// @param device id of the device on which to initialize the buffer /// @param stream cuda stream DeviceBuffer(uint64_t size, int device = cudaCpuDeviceId, cudaStream_t stream = 0) : DeviceBuffer() { this->init(size, device, stream); } /// @brief Constructor /// @param size byte size of buffer to be initialized /// @param host If true buffer is initialized only on the host/CPU, else on the current device/GPU /// @param stream optional stream argument (defaults to stream NULL) DeviceBuffer(uint64_t size, bool host, void* stream) : DeviceBuffer() { int device = cudaCpuDeviceId; if (!host) cudaCheck(cudaGetDevice(&device)); this->init(size, device, reinterpret_cast(stream)); } /// @brief Constructor for externally managed host and device buffers /// @param size byte size of the two external buffers /// @param cpuData host buffer, assumed to NOT be NULL /// @param gpuData device buffer, assumed to NOT be NULL; /// @note The device buffer, @c gpuData, will be associated /// with the current device ID given by cudaGetDevice DeviceBuffer(uint64_t size, void* cpuData, void* gpuData) : mSize(size) , mCpuData(cpuData) , mManaged(0) { cudaCheck(cudaGetDeviceCount(&mDeviceCount)); mGpuData = new void*[mDeviceCount]();// NULL initialization NANOVDB_ASSERT(cpuData); NANOVDB_ASSERT(gpuData); int device = 0; cudaCheck(cudaGetDevice(&device)); mGpuData[device] = gpuData; } /// @brief Constructor for externally managed host and multiple device buffers /// @param size byte size of the two external buffers /// @param cpuData host buffer, assumed to NOT be NULL /// @param list list of device IDs and external device buffers, all assumed to not be NULL DeviceBuffer(uint64_t size, void* cpuData, std::initializer_list> list) : mSize(size) , mCpuData(cpuData) , mManaged(0) { NANOVDB_ASSERT(cpuData); cudaCheck(cudaGetDeviceCount(&mDeviceCount)); mGpuData = new void*[mDeviceCount]();// NULL initialization for (auto &p : list) { NANOVDB_ASSERT(p.first>=0 && p.firstclear(); }; /// @brief Static factory method that return an instance of this buffer /// @param size byte size of buffer to be initialized /// @param dummy this argument is currently ignored but required to match the API of the HostBuffer /// @param host If true buffer is initialized only on the host/CPU, else only on the device/GPU /// @param stream optional stream argument (defaults to stream NULL) /// @return An instance of this class using move semantics static DeviceBuffer create(uint64_t size, const DeviceBuffer* dummy, bool host, void* stream){return DeviceBuffer(size, host, stream);} /// @brief Static factory method that returns an instance of this buffer /// @param size byte size of buffer to be initialized /// @param dummy this argument is currently ignored but required to match the API of the HostBuffer /// @param device id of the device on which to initialize the buffer /// @param stream cuda stream static DeviceBuffer create(uint64_t size, const DeviceBuffer* dummy = nullptr, int device = cudaCpuDeviceId, cudaStream_t stream = 0){return DeviceBuffer(size, device, stream);} /// @brief Static factory method that returns an instance of this buffer that wraps externally managed memory /// @param size byte size of buffer specified by external memory /// @param cpuData pointer to externally managed host memory /// @param gpuData pointer to externally managed device memory /// @return An instance of this class using move semantics static DeviceBuffer create(uint64_t size, void* cpuData, void* gpuData) {return DeviceBuffer(size, cpuData, gpuData);} /// @brief Static factory method that returns an instance of this buffer that wraps externally managed host and device memory /// @param size byte size of buffer to be initialized /// @param cpuData pointer to externally managed host memory /// @param list list of device IDs and device memory pointers static DeviceBuffer create(uint64_t size, void* cpuData, std::initializer_list> list) {return DeviceBuffer(size, cpuData, list);} /// @brief Static factory method that returns an instance of this buffer constructed from a HostBuffer /// @param buffer host buffer from which to copy data /// @param device id of the device on which to initialize the buffer /// @param stream cuda stream static DeviceBuffer create(const HostBuffer& buffer, int device = cudaCpuDeviceId, cudaStream_t stream = 0) {return DeviceBuffer(buffer, device, stream);} /////////////////////////////////////////////////////////////////////// /// @{ /// @brief Factory methods that create a shared pointer to an DeviceBuffer instance static PtrT createPtr(uint64_t size, const DeviceBuffer* = nullptr, int device = cudaCpuDeviceId, cudaStream_t stream = 0) {return std::make_shared(size, device, stream);} static PtrT createPtr(uint64_t size, void* cpuData, void* gpuData) {return std::make_shared(size, cpuData, gpuData);} static PtrT createPtr(uint64_t size, void* cpuData, std::initializer_list> list) {return std::make_shared(size, cpuData, list);} static PtrT createPtr(const HostBuffer& buffer, int device = cudaCpuDeviceId, cudaStream_t stream = 0) {return std::make_shared(buffer, device, stream);} /// @} /////////////////////////////////////////////////////////////////////// /// @brief Disallow copy assignment operation DeviceBuffer& operator=(const DeviceBuffer&) = delete; /// @brief Move copy assignment operation DeviceBuffer& operator=(DeviceBuffer&& other) noexcept; /////////////////////////////////////////////////////////////////////// /// @brief Retuns a raw void pointer to the host/CPU buffer managed by this allocator. /// @warning Note that the pointer can be NULL! void* data() const { return mCpuData; } /// @brief Returns an offset pointer of a specific type from the allocated host memory /// @tparam T Type of the pointer returned /// @param count Numbers of elements of @c parameter type T to skip /// @warning might return NULL template T* data(ptrdiff_t count = 0, int device = cudaCpuDeviceId) const { NANOVDB_ASSERT(device >= cudaCpuDeviceId && device < mDeviceCount); void *ptr = device == cudaCpuDeviceId ? mCpuData : mGpuData[device]; return ptr ? reinterpret_cast(ptr) + count : nullptr; } /// @brief Returns a byte offset void pointer from the allocated host memory /// @param byteOffset offset of return pointer in units of bytes /// @warning assumes that this instance is not empty! void* data(ptrdiff_t byteOffset, int device = cudaCpuDeviceId) const { NANOVDB_ASSERT(device >= cudaCpuDeviceId && device < mDeviceCount); void *ptr = device == cudaCpuDeviceId ? mCpuData : mGpuData[device]; return ptr ? reinterpret_cast(ptr) + byteOffset : nullptr; } /////////////////////////////////////////////////////////////////////// /// @brief Retuns a raw pointer to the specified device/GPU buffer managed by this allocator. /// @warning Note that the pointer can be NULL! void* deviceData(int device) const { NANOVDB_ASSERT(device >= 0 && device < mDeviceCount); return mGpuData[device]; } /// @brief Retuns a raw pointer to the current device/GPU buffer managed by this allocator. /// @warning Note that the pointer can be NULL! void* deviceData() const { int device = cudaCpuDeviceId; cudaCheck(cudaGetDevice(&device)); return this->deviceData(device); } /////////////////////////////////////////////////////////////////////// /// @brief Uploads buffer on the host to a specific device. If it doesn't exist it's created first. /// @param device Device ID that the data is copied to /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous. /// @warning Assumes that the host buffer already exists! /// @note determine the current device with cudaGetDevice void deviceUpload(int device = 0, cudaStream_t stream = 0, bool sync = true); void deviceUpload(int device, void* stream, bool sync){this->deviceUpload(device, cudaStream_t(stream), sync);} /// @brief Upload buffer from the host to ALL the existing devices, i.e. CPU -> GPU. /// If no device buffers exist one is created for the current device (typically 0) /// and subsequently populated with the host data. /// @param stream CUDA stream. /// @param sync if false the memory copy is asynchronous. /// @warning Assumes that the host buffer already exists! void deviceUpload(cudaStream_t stream, bool sync); void deviceUpload(void* stream, bool sync) {this->deviceUpload(cudaStream_t(stream), sync);} /////////////////////////////////////////////////////////////////////// /// @brief Download data from a specified device to the host. If the host buffer des not exist it will first be allocated /// @param device device ID to download source data from /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous. /// @warning Assumes that the specifed device buffer already exists! void deviceDownload(int device = 0, cudaStream_t stream = 0, bool sync = true); void deviceDownload(int device, void* stream , bool sync) {this->deviceDownload(device, cudaStream_t(stream), sync);} /// @brief Download the buffer from the current device to the host, i.e. GPU -> CPU. /// If the host buffer des not exist it will first be allocated /// @param stream CUDA stream /// @param sync if false the memory copy is asynchronous /// @note If the host/CPU buffer does not exist it is first allocated /// @warning Assumes that the device/GPU buffer already exists void deviceDownload(void* stream, bool sync); /////////////////////////////////////////////////////////////////////// /// @brief Returns the size in bytes of the raw memory buffer managed by this allocator. uint64_t size() const { return mSize; } uint64_t capacity() const {return this->size();} /// @brief Returns the number of buffers that are not NULL int bufferCount() const { int count = mCpuData ? 1 : 0; for (int i=0; iempty(); } /// @} /// @brief De-allocate all memory managed by this allocator and set all pointers to NULL void clear(cudaStream_t stream = 0); void clear(void* stream){this->clear(cudaStream_t(stream));} }; // DeviceBuffer class // --------------------------> Implementations below <------------------------------------ inline DeviceBuffer& DeviceBuffer::operator=(DeviceBuffer&& other) noexcept { if (mManaged) {// first free all the managed data buffers cudaCheck(cudaFreeHost(mCpuData)); for (int i=0; i= cudaCpuDeviceId && device < mDeviceCount); if (device == cudaCpuDeviceId) { cudaCheck(cudaMallocHost((void**)&mCpuData, size)); // un-managed pinned memory on the host (can be slow to access!). Always 32B aligned checkPtr(mCpuData, "cuda::DeviceBuffer::init: failed to allocate host buffer"); } else { cudaCheck(util::cuda::mallocAsync(mGpuData+device, size, stream)); // un-managed memory on the device, always 32B aligned! checkPtr(mGpuData[device], "cuda::DeviceBuffer::init: failed to allocate device buffer"); } mSize = size; mManaged = 1;// i.e. this instance is responsible for allocating and delete memory } // DeviceBuffer::init inline void DeviceBuffer::deviceUpload(int device, cudaStream_t stream, bool sync) { NANOVDB_ASSERT(device >= 0 && device < mDeviceCount);// should be device and not the host checkPtr(mCpuData, "uninitialized cpu source data"); if (mGpuData[device] == nullptr) { if (mManaged==0) throw std::runtime_error("DeviceBuffer::deviceUpload called on externally managed memory that wasn\'t allocated."); cudaCheck(util::cuda::mallocAsync(mGpuData+device, mSize, stream)); // un-managed memory on the device, always 32B aligned! } checkPtr(mGpuData[device], "uninitialized gpu destination data"); cudaCheck(cudaMemcpyAsync(mGpuData[device], mCpuData, mSize, cudaMemcpyHostToDevice, stream)); if (sync) cudaCheck(cudaStreamSynchronize(stream)); } // DeviceBuffer::deviceUpload inline void DeviceBuffer::deviceUpload(cudaStream_t stream, bool sync) { int device = 0; cudaGetDevice(&device); this->deviceUpload(device, stream, sync); } // DeviceBuffer::deviceUpload inline void DeviceBuffer::deviceDownload(int device, cudaStream_t stream, bool sync) { NANOVDB_ASSERT(device >= 0 && device < mDeviceCount); checkPtr(mGpuData[device], "uninitialized gpu source data");// no source data on the specified device if (mCpuData == nullptr) { if (mManaged==0) throw std::runtime_error("DeviceBuffer::deviceDownload called on uninitialized cpu destination memory that is externally managed."); cudaCheck(cudaMallocHost((void**)&mCpuData, mSize)); // un-managed pinned memory on the host (can be slow to access!). Always 32B aligned } checkPtr(mCpuData, "uninitialized cpu destination data"); cudaCheck(cudaMemcpyAsync(mCpuData, mGpuData[device], mSize, cudaMemcpyDeviceToHost, stream)); if (sync) cudaCheck(cudaStreamSynchronize(stream)); } // DeviceBuffer::deviceDownload inline void DeviceBuffer::deviceDownload(void* stream, bool sync) { int device = 0; cudaCheck(cudaGetDevice(&device)); this->deviceDownload(device, cudaStream_t(stream), sync); } // DeviceBuffer::deviceDownload inline void DeviceBuffer::clear(cudaStream_t stream) { if (mManaged) {// free all the managed data buffers cudaCheck(cudaFreeHost(mCpuData)); for (int i=0; i struct BufferTraits { static constexpr bool hasDeviceDual = true; }; }// namespace nanovdb #endif // end of NANOVDB_CUDA_DEVICEBUFFER_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/DeviceMesh.h000066400000000000000000000177141510223237100214150ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file DeviceMesh.h \brief nanovdb::cuda::DeviceMesh encapsulates device IDs, CUDA streams, and NCCL communicators in order to facilitate multi-GPU applications. */ #ifndef NANOVDB_CUDA_DEVICEMESH_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_DEVICEMESH_H_HAS_BEEN_INCLUDED #include #include #include #include #ifdef NANOVDB_USE_NCCL #include #endif namespace nanovdb { namespace cuda { namespace detail { /// @brief RAII class that caches/restores the current device at construction/destruction class DeviceGuard { public: DeviceGuard() { cudaGetDevice(&deviceId); } ~DeviceGuard() { cudaSetDevice(deviceId); } /// @{ /// @brief DeviceGuard is not copyable nor movable DeviceGuard(const DeviceGuard&) = delete; DeviceGuard& operator=(const DeviceGuard&) = delete; DeviceGuard(DeviceGuard&& other) = delete; DeviceGuard& operator=(DeviceGuard&& other) = delete; /// @} private: int deviceId = -1; }; } /// @brief POD struct representing a device id and a stream on that device struct DeviceNode { int id = -1; cudaStream_t stream = cudaStream_t(0); }; /// @brief This class wraps a vector of per-device IDs and CUDA streams and holds inter-device connectivity information and NCCL comms. class DeviceMesh { using DeviceVecT = std::vector; using const_iterator = DeviceVecT::const_iterator; using size_type = DeviceVecT::size_type; public: /// @brief Constructs a device mesh for all devices on the host and initializes a CUDA stream (and NCCL communicator) for each device DeviceMesh(); /// @brief Destroys the per-device CUDA stream and finalizes and destroys the per-device NCCL communicators ~DeviceMesh(); /// @brief Disallow copy-construction DeviceMesh(const DeviceMesh&) = delete; /// @brief Move constructor. Underlying CUDA streams and NCCL communicators are not reinitialized. /// @param DeviceMesh instance that will be moved into this DeviceMesh. DeviceMesh(DeviceMesh&&) noexcept; /// @brief Disallow copy-assignment DeviceMesh& operator=(const DeviceMesh&) = delete; /// @brief Move assignment. Underlying CUDA streams and NCCL communicators are not reinitialized. /// @param DeviceMesh instance that will be moved into this DeviceMesh. DeviceMesh& operator=(DeviceMesh&&) noexcept; /// @brief Returns the number of devices size_type deviceCount() const { return mDeviceNodes.size(); }; /// @brief Returns a const reference to the DeviceNode for a particular device const DeviceNode& operator [](int deviceId) const { return mDeviceNodes[deviceId]; } /// @brief Returns an iterator to the first device node const_iterator begin() const { return mDeviceNodes.begin(); }; /// @brief Returns an iterator past the last device node const_iterator end() const { return mDeviceNodes.end(); }; #ifdef NANOVDB_USE_NCCL /// @brief Returns the NCCL communicator for a particular device ncclComm_t comm(int deviceId) const { return mComms[deviceId]; } #endif /// @brief Returns whether or not peer to peer access is supported between two devices. bool canAccessPeer(int deviceId, int peerId) const { return mConnectivity[deviceId][peerId] & (1 << cudaDevP2PAttrAccessSupported); } private: /// @brief Returns whether or not a device supports managed memory bool hasManagedMemory(int deviceId) const { int managedMemoryValue = 0; cudaDeviceGetAttribute(&managedMemoryValue, cudaDevAttrManagedMemory, deviceId); return static_cast(managedMemoryValue); } DeviceVecT mDeviceNodes; #ifdef NANOVDB_USE_NCCL std::vector mComms; #endif std::vector> mConnectivity; }; inline DeviceMesh::DeviceMesh() { detail::DeviceGuard deviceGuard; int deviceCount = -1; cudaGetDeviceCount(&deviceCount); for (int deviceId = 0; deviceId < deviceCount; ++deviceId) { NANOVDB_ASSERT(hasManagedMemory(deviceId)); cudaSetDevice(deviceId); cudaStream_t stream; cudaStreamCreate(&stream); mDeviceNodes.push_back({deviceId, stream}); } #ifdef NANOVDB_USE_NCCL mComms.resize(deviceCount); ncclCommInitAll(mComms.data(), deviceCount, nullptr); #endif mConnectivity.resize(deviceCount); for (const auto& deviceNode : mDeviceNodes) { mConnectivity[deviceNode.id].resize(deviceCount); for (const auto& peerNode : mDeviceNodes) { mConnectivity[deviceNode.id][peerNode.id] = 0; if (deviceNode.id != peerNode.id) { int peerAccessSupportedValue = 0; cudaDeviceGetP2PAttribute(&peerAccessSupportedValue, cudaDevP2PAttrAccessSupported, deviceNode.id, peerNode.id); if (peerAccessSupportedValue) { mConnectivity[deviceNode.id][peerNode.id] |= (1 << cudaDevP2PAttrAccessSupported); } } } } } inline DeviceMesh::DeviceMesh(DeviceMesh&& other) noexcept : mDeviceNodes(std::move(other.mDeviceNodes)), #ifdef NANOVDB_USE_NCCL mComms(std::move(other.mComms)), #endif mConnectivity(std::move(other.mConnectivity)) { } inline DeviceMesh::~DeviceMesh() { detail::DeviceGuard deviceGuard; #ifdef NANOVDB_USE_NCCL std::for_each(mComms.begin(), mComms.end(), [](ncclComm_t comm) { ncclCommFinalize(comm); ncclCommDestroy(comm); }); #endif std::for_each(mDeviceNodes.begin(), mDeviceNodes.end(), [](DeviceNode& deviceNode) { cudaSetDevice(deviceNode.id); cudaStreamDestroy(deviceNode.stream); }); } inline DeviceMesh& DeviceMesh::operator=(DeviceMesh&& other) noexcept { mDeviceNodes = std::move(other.mDeviceNodes); #ifdef NANOVDB_USE_NCCL mComms = std::move(other.mComms); #endif mConnectivity = std::move(other.mConnectivity); return *this; } namespace detail { inline void* queryAllocationGranularityEntryPoint() { void* entryPoint = nullptr; #if CUDART_VERSION >= 12500 // cudaGetDriverEntryPointByVersion was added in CUDA 12.5 with cudaGetDriverEntryPoint being potentially deprecated cudaDriverEntryPointQueryResult queryResult = cudaDriverEntryPointSymbolNotFound; cudaCheck(cudaGetDriverEntryPointByVersion("cuMemGetAllocationGranularity", &entryPoint, 12000, cudaEnableDefault, &queryResult)); NANOVDB_ASSERT(queryResult == cudaDriverEntryPointSuccess); #elif CUDART_VERSION >= 12000 // queryResult argument was added in CUDA 12 cudaDriverEntryPointQueryResult queryResult = cudaDriverEntryPointSymbolNotFound; cudaCheck(cudaGetDriverEntryPoint("cuMemGetAllocationGranularity", &entryPoint, cudaEnableDefault, &queryResult)); NANOVDB_ASSERT(queryResult == cudaDriverEntryPointSuccess); #else cudaCheck(cudaGetDriverEntryPoint("cuMemGetAllocationGranularity", &entryPoint, cudaEnableDefault)); #endif return entryPoint; }// queryAllocationGranularityEntryPoint } /// @brief Returns the minimum page size (in bytes) across all devices on the system inline size_t minDevicePageSize(const DeviceMesh& mesh) { using FuncT = CUresult(size_t*, const CUmemAllocationProp*, CUmemAllocationGranularity_flags); static FuncT* functPtr = reinterpret_cast(detail::queryAllocationGranularityEntryPoint()); NANOVDB_ASSERT(functPtr); CUmemAllocationProp prop = {}; prop.type = CU_MEM_ALLOCATION_TYPE_PINNED; prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE; size_t minGranularity = 0; for (const auto& node : mesh) { prop.location.id = node.id; size_t granularity = 0; (*functPtr)(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM); if (minGranularity < granularity) minGranularity = granularity; } return minGranularity; }// minDevicePageSize } // namespace cuda } // namespace nanovdb #endif // end of NANOVDB_CUDA_DEVICEMESH_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/DeviceResource.h000066400000000000000000000015631510223237100223030ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 // #ifndef NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED #include #include namespace nanovdb { namespace cuda { class DeviceResource { public: // cudaMalloc aligns memory to 256 bytes by default static constexpr size_t DEFAULT_ALIGNMENT = 256; static void* allocateAsync(size_t bytes, size_t, cudaStream_t stream) { void* p = nullptr; cudaCheck(util::cuda::mallocAsync(&p, bytes, stream)); return p; } static void deallocateAsync(void *p, size_t, size_t, cudaStream_t stream) { cudaCheck(util::cuda::freeAsync(p, stream)); } }; } } // namespace nanovdb::cuda #endif // end of NANOVDB_CUDA_DEVICERESOURCE_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/DeviceStreamMap.h000066400000000000000000000123731510223237100224060ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file DeviceStreamMap.h \author Ken Museth \date October 15, 2024 \brief nanovdb::cuda::DeviceStreamMap maps device IDs to CUDA streams, which is useful for multi-GPU applications. */ #ifndef NANOVDB_CUDA_DEVICESTREAMMAP_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_DEVICESTREAMMAP_H_HAS_BEEN_INCLUDED #include #include #include #include // for cudaCheck, deviceCount etc namespace nanovdb {// ================================================================ namespace cuda {// =================================================================== /// @brief map from a device ID to an associated cuda stream. Useful for multi-GPU applications. class DeviceStreamMap : public std::map { using FuncT = CUresult(size_t*, const CUmemAllocationProp*, CUmemAllocationGranularity_flags); FuncT *mFunctPtr; public: enum DeviceType { Any = 0, PeerToPeer = 1, Unified = 3 }; /// @brief Initiates a map between CUDA device IDs and corresponding streams that satisfy certain constraints. /// All devices should be able to access memory on all the other devices! /// @param t Type of device to include in map. Any means all available devices, PeerToPeer means only devices that /// access all another devices are included, and Unified means all devices support unified memory, concurrent access, /// and can be access by all other devices. /// @param exclude optional list of device IDs to exclude from the map /// @param verbose 0 means quiet, 1 means print if a device is ignores and 2 means print is a device is included DeviceStreamMap(DeviceType t = DeviceType::Unified, std::vector exclude = {}, int verbose = 0); /// @brief Destructor ~DeviceStreamMap(); /// @brief returns the minimum page size of all the devices in this map size_t getMinPageSize() const; /// @brief Print information about all the devices included in this map void printDevInfo(std::FILE* file = stdout) const {for (auto &p : *this) util::cuda::printDevInfo(p.first, nullptr, file);} /// @brief Returns the number of device associated with this map int deviceCount() const {return this->size();} };// DeviceStreamMap DeviceStreamMap::DeviceStreamMap(DeviceType t, std::vector exclude, int verbose) { std::initializer_list filter = {cudaDevAttrUnifiedAddressing, cudaDevAttrConcurrentManagedAccess}; const int devCount = util::cuda::deviceCount(), current = util::cuda::currentDevice(); for (int dev = 0; dev < devCount; ++dev) { int check = 1; for (auto it=exclude.begin(); check && it!=exclude.end(); ++it) if (dev == *it) check = 0; for (auto it=filter.begin(); (t&2) && check && it!=filter.end(); ++it) cudaCheck(cudaDeviceGetAttribute( &check, *it, dev)); for (auto it= this->begin(); (t&1) && check && it!= this->end(); ++it) cudaCheck(cudaDeviceCanAccessPeer(&check, dev, it->first)); if (check) { cudaCheck(cudaSetDevice(dev)); cudaStream_t stream; cudaCheck(cudaStreamCreate(&stream)); if (verbose>1) util::cuda::printDevInfo(dev, "Using"); (*this)[dev] = stream; } else if (verbose) util::cuda::printDevInfo(dev, "Ignoring"); } cudaCheck(cudaSetDevice(current));// reset to the previous device void* entryPoint = nullptr; #if CUDART_VERSION >= 13000 cudaDriverEntryPointQueryResult queryResult; cudaCheck(cudaGetDriverEntryPointByVersion("cuMemGetAllocationGranularity", &entryPoint, 13000, cudaEnableDefault, &queryResult)); NANOVDB_ASSERT(queryResult == cudaDriverEntryPointSuccess); #elif CUDART_VERSION >= 12000// queryResult argument was added in CUDA 12 cudaDriverEntryPointQueryResult queryResult; cudaCheck(cudaGetDriverEntryPoint("cuMemGetAllocationGranularity", &entryPoint, cudaEnableDefault, &queryResult)); NANOVDB_ASSERT(queryResult == cudaDriverEntryPointSuccess); #else cudaCheck(cudaGetDriverEntryPoint("cuMemGetAllocationGranularity", &entryPoint, cudaEnableDefault)); #endif mFunctPtr = reinterpret_cast(entryPoint); }// DeviceStreamMap::DeviceStreamMap DeviceStreamMap::~DeviceStreamMap() { const int current = util::cuda::currentDevice(); for (auto& [device, stream] : *this) { cudaCheck(cudaSetDevice(device)); cudaCheck(cudaStreamDestroy(stream)); } cudaCheck(cudaSetDevice(current));// reset to the previous device } inline size_t DeviceStreamMap::getMinPageSize() const { NANOVDB_ASSERT(mFunctPtr); CUmemAllocationProp prop = {}; prop.type = CU_MEM_ALLOCATION_TYPE_PINNED; prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE; size_t minGranularity = 0; for (auto it = this->begin(); it!=this->end(); ++it) { prop.location.id = it->first; size_t granularity = 0; (*mFunctPtr)(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM); if (minGranularity < granularity) minGranularity = granularity; } return minGranularity; }// DeviceStreamMap::getMinPageSize }// namespace cuda }// namespace nanovdb #endif // end of NANOVDB_CUDA_DEVICESTREAMMAP_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/GridHandle.cuh000066400000000000000000000161041510223237100217220ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/cuda/GridHandle.cuh \author Ken Museth, Doyub Kim \date August 3, 2023 \brief Contains cuda kernels for GridHandle \warning The header file contains cuda device code so be sure to only include it in .cu files (or other .cuh files) */ #ifndef NANOVDB_CUDA_GRIDHANDLE_CUH_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_GRIDHANDLE_CUH_HAS_BEEN_INCLUDED #include // required for instantiation of move c-tor of GridHandle #include // for cuda::updateChecksum #include namespace nanovdb { namespace cuda { namespace detail { static __global__ void cpyGridHandleMeta(const GridData *d_data, GridHandleMetaData *d_meta) { nanovdb::cpyGridHandleMeta(d_data, d_meta); } static __global__ void updateGridCount(GridData *d_data, uint32_t gridIndex, uint32_t gridCount, bool *d_dirty) { NANOVDB_ASSERT(gridIndex < gridCount); *d_dirty = (d_data->mGridIndex != gridIndex) || (d_data->mGridCount != gridCount); if (*d_dirty) { d_data->mGridIndex = gridIndex; d_data->mGridCount = gridCount; if (d_data->mChecksum.isEmpty()) *d_dirty = false;// no need to update checksum if it didn't already exist } } }// namespace detail template class VectorT = std::vector> inline typename util::enable_if::hasDeviceDual, VectorT>>::type splitGridHandles(const GridHandle &handle, const BufferT* other = nullptr, cudaStream_t stream = 0) { const void *ptr = handle.deviceData(); if (ptr == nullptr) return VectorT>(); VectorT> handles(handle.gridCount()); bool dirty, *d_dirty;// use this to check if the checksum needs to be recomputed cudaCheck(util::cuda::mallocAsync((void**)&d_dirty, sizeof(bool), stream)); int device = util::cuda::currentDevice(); for (uint32_t n=0; n(buffer.deviceData()); const GridData *src = reinterpret_cast(ptr); cudaCheck(cudaMemcpyAsync(dst, src, handle.gridSize(n), cudaMemcpyDeviceToDevice, stream)); detail::updateGridCount<<<1, 1, 0, stream>>>(dst, 0u, 1u, d_dirty); cudaCheckError(); cudaCheck(cudaMemcpyAsync(&dirty, d_dirty, sizeof(bool), cudaMemcpyDeviceToHost, stream)); cudaCheck(cudaStreamSynchronize(stream)); if (dirty) tools::cuda::updateChecksum(dst, CheckMode::Partial, stream); handles[n] = nanovdb::GridHandle(std::move(buffer)); ptr = util::PtrAdd(ptr, handle.gridSize(n)); } cudaCheck(util::cuda::freeAsync(d_dirty, stream)); return handles; }// cuda::splitGridHandles template class VectorT> inline typename util::enable_if::hasDeviceDual, GridHandle>::type mergeGridHandles(const VectorT> &handles, const BufferT* other = nullptr, cudaStream_t stream = 0) { uint64_t size = 0u; uint32_t counter = 0u, gridCount = 0u; for (auto &h : handles) { gridCount += h.gridCount(); for (uint32_t n=0; n(dst); detail::updateGridCount<<<1, 1, 0, stream>>>(data, counter++, gridCount, d_dirty); cudaCheckError(); cudaCheck(cudaMemcpyAsync(&dirty, d_dirty, sizeof(bool), cudaMemcpyDeviceToHost, stream)); cudaCheck(cudaStreamSynchronize(stream)); if (dirty) tools::cuda::updateChecksum(data, CheckMode::Partial, stream); dst = util::PtrAdd(dst, h.gridSize(n)); src = util::PtrAdd(src, h.gridSize(n)); } } cudaCheck(util::cuda::freeAsync(d_dirty, stream)); return GridHandle(std::move(buffer)); }// cuda::mergeGridHandles }// namespace cuda template class VectorT = std::vector> [[deprecated("Use nanovdb::cuda::splitGridHandles instead")]] inline typename util::enable_if::hasDeviceDual, VectorT>>::type splitDeviceGrids(const GridHandle &handle, const BufferT* other = nullptr, cudaStream_t stream = 0) { return cuda::splitGridHandles(handle, other, stream); } template class VectorT> [[deprecated("Use nanovdb::cuda::mergeGridHandles instead")]] inline typename util::enable_if::hasDeviceDual, GridHandle>::type mergeDeviceGrids(const VectorT> &handles, const BufferT* other = nullptr, cudaStream_t stream = 0) { return cuda::mergeGridHandles(handles, other, stream); } template template::hasDeviceDual, int>::type> GridHandle::GridHandle(T&& buffer) { static_assert(util::is_same::value, "Expected U==BufferT"); mBuffer = std::move(buffer); if (auto *data = reinterpret_cast(mBuffer.data())) { if (!data->isValid()) throw std::runtime_error("GridHandle was constructed with an invalid host buffer"); mMetaData.resize(data->mGridCount); cpyGridHandleMeta(data, mMetaData.data()); } else { if (auto *d_data = reinterpret_cast(mBuffer.deviceData())) { GridData tmp; cudaCheck(cudaMemcpy(&tmp, d_data, sizeof(GridData), cudaMemcpyDeviceToHost)); if (!tmp.isValid()) throw std::runtime_error("GridHandle was constructed with an invalid device buffer"); GridHandleMetaData *d_metaData; cudaMalloc((void**)&d_metaData, tmp.mGridCount*sizeof(GridHandleMetaData)); cuda::detail::cpyGridHandleMeta<<<1,1>>>(d_data, d_metaData); mMetaData.resize(tmp.mGridCount); cudaCheck(cudaMemcpy(mMetaData.data(), d_metaData,tmp.mGridCount*sizeof(GridHandleMetaData), cudaMemcpyDeviceToHost)); cudaCheck(cudaFree(d_metaData)); } } }// GridHandle(T&& buffer) // Dummy function that ensures instantiation of the move-constructor above when BufferT=cuda::DeviceBuffer namespace {auto __dummy(){return GridHandle(std::move(cuda::DeviceBuffer()));}} } // namespace nanovdb #endif // NANOVDB_CUDA_GRIDHANDLE_CUH_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/NodeManager.cuh000066400000000000000000000106671510223237100221110ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file nanovdb/cuda/NodeManager.cuh \author Ken Museth \date October 3, 2023 \brief Contains cuda kernels for NodeManager \warning The header file contains cuda device code so be sure to only include it in .cu files (or other .cuh files) */ #ifndef NANOVDB_CUDA_NODE_MANAGER_CUH_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_NODE_MANAGER_CUH_HAS_BEEN_INCLUDED #include // for cuda::lambdaKernel #include #include namespace nanovdb { namespace cuda { /// @brief Construct a NodeManager from a device grid pointer /// /// @param d_grid device grid pointer whose nodes will be accessed sequentially /// @param buffer buffer from which to allocate the output handle /// @param stream cuda stream /// @return Handle that contains a device NodeManager template inline typename util::enable_if::hasDeviceDual, NodeManagerHandle>::type createNodeManager(const NanoGrid *d_grid, const BufferT& pool = BufferT(), cudaStream_t stream = 0) { int device = 0; cudaCheck(cudaGetDevice(&device)); auto buffer = BufferT::create(sizeof(NodeManagerData), &pool, device, stream); auto *d_data = (NodeManagerData*)buffer.deviceData(); size_t size = 0u, *d_size; cudaCheck(util::cuda::mallocAsync((void**)&d_size, sizeof(size_t), stream)); util::cuda::lambdaKernel<<<1, 1, 0, stream>>>(1, [=] __device__(size_t) { *d_data = NodeManagerData((void*)d_grid); *d_size = sizeof(NodeManagerData); auto &tree = d_grid->tree(); if (NodeManager::FIXED_SIZE && d_grid->isBreadthFirst()) { d_data->mLinear = uint8_t(1u); d_data->mOff[0] = util::PtrDiff(tree.template getFirstNode<0>(), d_grid); d_data->mOff[1] = util::PtrDiff(tree.template getFirstNode<1>(), d_grid); d_data->mOff[2] = util::PtrDiff(tree.template getFirstNode<2>(), d_grid); } else { *d_size += sizeof(uint64_t)*tree.totalNodeCount(); } }); cudaCheckError(); cudaCheck(cudaMemcpyAsync(&size, d_size, sizeof(size_t), cudaMemcpyDeviceToHost, stream)); cudaCheck(util::cuda::freeAsync(d_size, stream)); if (size > sizeof(NodeManagerData)) { auto tmp = BufferT::create(size, &pool, device, stream);// only allocate buffer on the device cudaCheck(cudaMemcpyAsync(tmp.deviceData(), buffer.deviceData(), sizeof(NodeManagerData), cudaMemcpyDeviceToDevice, stream)); buffer = std::move(tmp); d_data = reinterpret_cast(buffer.deviceData()); util::cuda::lambdaKernel<<<1, 1, 0, stream>>>(1, [=] __device__ (size_t) { auto &tree = d_grid->tree(); int64_t *ptr0 = d_data->mPtr[0] = reinterpret_cast(d_data + 1); int64_t *ptr1 = d_data->mPtr[1] = d_data->mPtr[0] + tree.nodeCount(0); int64_t *ptr2 = d_data->mPtr[2] = d_data->mPtr[1] + tree.nodeCount(1); // Performs depth first traversal but breadth first insertion for (auto it2 = tree.root().cbeginChild(); it2; ++it2) { *ptr2++ = util::PtrDiff(&*it2, d_grid); for (auto it1 = it2->cbeginChild(); it1; ++it1) { *ptr1++ = util::PtrDiff(&*it1, d_grid); for (auto it0 = it1->cbeginChild(); it0; ++it0) { *ptr0++ = util::PtrDiff(&*it0, d_grid); }// loop over child nodes of the lower internal node }// loop over child nodes of the upper internal node }// loop over child nodes of the root node }); } return NodeManagerHandle(toGridType(), std::move(buffer)); }// cuda::createNodeManager }// namespace cuda template [[deprecated("Use cuda::createNodeManager instead")]] inline typename util::enable_if::hasDeviceDual, NodeManagerHandle>::type cudaCreateNodeManager(const NanoGrid *d_grid, const BufferT& pool = BufferT(), cudaStream_t stream = 0) { return cuda::createNodeManager(d_grid, pool, stream); } } // namespace nanovdb #endif // NANOVDB_CUDA_NODE_MANAGER_CUH_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/TempPool.h000066400000000000000000000045001510223237100211250ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 // /// @brief Defines a simple memory pool used to call cub functions that use dynamic temporary storage /// /// @details See nanovdb/tools/cuda/PointToGrid.cuh and nanovdb/tools/cuda/DistributedPointToGrid.cuh /// for examples. Also note that this explains the somewhat unusual API with direct access to /// protected member data. // #ifndef NANOVDB_CUDA_TEMPPOOL_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_TEMPPOOL_H_HAS_BEEN_INCLUDED #include namespace nanovdb { namespace cuda { template class TempPool { public: /// @brief Default c-tor of an empty memory pool. TempPool() : mData(nullptr), mSize(0), mRequestedSize(0) {} /// @brief Destructor ~TempPool() { mRequestedSize = 0; Resource::deallocateAsync(mData, mSize, Resource::DEFAULT_ALIGNMENT, nullptr); mData = nullptr; mSize = 0; } /// @brief Returns a non-const void pointer to the data managed by this instance. void* data() {return mData;} /// @brief Returns a non-const reference to the actual size of the data managed by this instance. size_t& size() {return mSize;} /// @brief Returns a non-const reference to the requested size of the data managed by this instance. /// @note This requested size should always be less than or smaller than the actual size(). size_t& requestedSize() {return mRequestedSize;} /// @brief Re-allocation of the data managed by this instance. Only has affect if the pool in empty or /// the requested memory is larger than the existing size. /// @param stream cuda stream used for asynchronous de-allocation and allocation. void reallocate(cudaStream_t stream) { if (!mData || mRequestedSize > mSize) { Resource::deallocateAsync(mData, mSize, Resource::DEFAULT_ALIGNMENT, stream); mData = Resource::allocateAsync(mRequestedSize, Resource::DEFAULT_ALIGNMENT, stream); mSize = mRequestedSize; } } private: void *mData; size_t mSize; size_t mRequestedSize; };// TempPool class using TempDevicePool = TempPool; } // namespace cuda } // namespace nanovdb #endif // end of NANOVDB_CUDA_TEMPPOOL_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/cuda/UnifiedBuffer.h000066400000000000000000000344071510223237100221140ustar00rootroot00000000000000// Copyright Contributors to the OpenVDB Project // SPDX-License-Identifier: Apache-2.0 /*! \file UnifiedBuffer.h \author Ken Museth \date October 15, 2024 \brief nanovdb::cuda::UnifiedBuffer that uses unified memory management \note This file has no device-only kernel functions, which explains why it's a .h and not .cuh file. */ #ifndef NANOVDB_CUDA_UNIFIEDBUFFER_H_HAS_BEEN_INCLUDED #define NANOVDB_CUDA_UNIFIEDBUFFER_H_HAS_BEEN_INCLUDED #include #include // for std::shared_ptr #include // for BufferTraits #include // for cudaCheck namespace nanovdb {// ================================================================ namespace cuda {// =================================================================== /// @brief buffer, used for instance by the GridHandle, to allocate unified memory that /// can be resized and shared between multiple devices and the host. class UnifiedBuffer { void *mPtr; size_t mSize, mCapacity; public: using PtrT = std::shared_ptr; /// @brief Default constructor of an empty buffer UnifiedBuffer() : mPtr(nullptr), mSize(0), mCapacity(0){} /// @brief Constructor that specifies both the size and capacity /// @param size size of the buffer in bytes, indication what is actually used /// @param capacity number of bytes in the virtual page table, i.e max size for growing /// @note Capacity can be over-estimated to allow for future growth. Memory is not allocated /// with this constructor, only a page table. Allocation happens on usage or when calling prefetch UnifiedBuffer(size_t size, size_t capacity) : mPtr(nullptr), mSize(size), mCapacity(capacity) { assert(mSize <= mCapacity); cudaCheck(cudaMallocManaged(&mPtr, mCapacity, cudaMemAttachGlobal)); } /// @brief Similar to the constructor above except the size and capacity are equal, so no future growth is supported UnifiedBuffer(size_t size) : UnifiedBuffer(size, size){} /// @brief Constructor that specifies the size, capacity, and device (for prefetching) /// @param size /// @param capacity /// @param device /// @param stream UnifiedBuffer(uint64_t size, uint64_t capacity, int device, cudaStream_t stream = 0) : mPtr(nullptr), mSize(size), mCapacity(size) { assert(mSize <= mCapacity); cudaCheck(cudaMallocManaged(&mPtr, mCapacity, cudaMemAttachGlobal)); cudaCheck(util::cuda::memAdvise(mPtr, size, cudaMemAdviseSetPreferredLocation, device)); cudaCheck(util::cuda::memPrefetchAsync(mPtr, size, device, stream)); } /// @brief Constructor with a specified device /// @param size /// @param device /// @param stream UnifiedBuffer(uint64_t size, int device, cudaStream_t stream = 0) : UnifiedBuffer(size, size, device, stream){} /// @brief Disallow copy-construction UnifiedBuffer(const UnifiedBuffer&) = delete; /// @brief Move copy-constructor UnifiedBuffer(UnifiedBuffer&& other) noexcept : mPtr(other.mPtr) , mSize(other.mSize) , mCapacity(other.mCapacity) { other.mPtr = nullptr; other.mSize = other.mCapacity = 0; } /// @brief Destructor ~UnifiedBuffer(){cudaCheck(cudaFree(mPtr));} /////////////////////////////////////////////////////////////////////// //@{ /// @brief Factory methods that create an UnifiedBuffer instance and returns it with move semantics static UnifiedBuffer create(size_t size, size_t capacity) {return UnifiedBuffer(size, capacity);} static UnifiedBuffer create(size_t size) {return UnifiedBuffer(size);} ///@} //@{ /// @brief Factory methods that create a shared pointer to an UnifiedBuffer instance static PtrT createPtr(size_t size, size_t capacity) {return std::make_shared(size, capacity);} static PtrT createPtr(size_t size) {return std::make_shared(size);} ///@} /// @brief Legacy factory method that mirrors DeviceBuffer. It creates a UnifiedBuffer from a size and a reference buffer. /// If a reference buffer is provided and its non-empty, it is used to defined the capacity of the new buffer /// @param size Size on bytes of the new buffer /// @param reference reference buffer optionally used to define the capacity /// @param host Ignored for now /// @param stream cuda stream /// @return An instance of a new UnifiedBuffer using move semantics static UnifiedBuffer create(size_t size, const UnifiedBuffer* reference, int device, cudaStream_t stream) { const size_t capacity = (reference && reference->capacity()) ? reference->capacity() : size; UnifiedBuffer buffer(size, capacity); cudaCheck(util::cuda::memAdvise(buffer.mPtr, size, cudaMemAdviseSetPreferredLocation, device)); cudaCheck(util::cuda::memPrefetchAsync(buffer.mPtr, size, device, stream)); return buffer; } /// @brief Factory method that created a buffer on the host of the specified size. If the /// reference buffer has a capacity it is used. Also the buffer is prefetched to the host /// @param size byte size of buffer initiated on the host /// @param reference optional reference buffer from which the capacity is derived static UnifiedBuffer create(size_t size, const UnifiedBuffer* reference){return create(size, reference, cudaCpuDeviceId, (cudaStream_t)0);} /// @brief Factory method that created a buffer on the host or device of the specified size. If the /// reference buffer has a capacity it is used. Also the buffer is prefetched to the host or (current) device /// @param size byte size of buffer initiated on the device or host /// @param reference optional reference buffer from which the capacity is derived /// @param host If true the buffer will be prefetched to the host, else to the current device /// @param stream optional cuda stream static UnifiedBuffer create(size_t size, const UnifiedBuffer* reference, bool host, void* stream = nullptr) { int device = cudaCpuDeviceId; if (!host) cudaGetDevice(&device); return create(size, reference, device, (cudaStream_t)stream); } /// @brief Free all memory and reset this instance to empty void clear() { cudaCheck(cudaFree(mPtr)); mPtr = nullptr; mSize = mCapacity = 0; } /// @brief Disallow copy assignment operation UnifiedBuffer& operator=(const UnifiedBuffer&) = delete; /// @brief Allow move assignment operation UnifiedBuffer& operator=(UnifiedBuffer&& other) { cudaCheck(cudaFree(mPtr)); mPtr = other.mPtr; mSize = other.mSize; mCapacity = other.mCapacity; other.mPtr = nullptr; other.mSize = other.mCapacity = 0; return *this; } /// @brief initialize buffer as a new with the specified size and capacity /// @param size size of memory block to be used in bytes /// @param capacity size of page table in bytes void init(size_t size, size_t capacity) { NANOVDB_ASSERT(size <= capacity); cudaCheck(cudaFree(mPtr)); mSize = size; mCapacity = capacity; cudaCheck(cudaMallocManaged(&mPtr, capacity, cudaMemAttachGlobal)); } /// @brief Resize the memory block managed by this buffer. If the current capacity is larger than the new size this method /// simply redefines size. Otherwise a new page-table is defined, with the specified advice, and the old block is copied to the new block. /// @param size size of the new memory block /// @param dev the device ID on which to apply each advice provided in list, cudaCpuDeviceId = -1, 0, 1, ... /// @param list advices to be applied to the resized range void resize(size_t size, int dev = cudaCpuDeviceId, std::initializer_list list = {cudaMemAdviseSetPreferredLocation}) { if (size <= mCapacity) { mSize = size; } else { void *ptr = 0; cudaCheck(cudaMallocManaged(&ptr, size, cudaMemAttachGlobal)); if (dev > -2) for (auto a : list) cudaCheck(util::cuda::memAdvise(ptr, size, a, dev)); if (mSize > 0) {// copy over data from the old memory block cudaCheck(cudaMemcpy(ptr, mPtr, std::min(mSize, size), cudaMemcpyDefault)); cudaCheck(cudaFree(mPtr)); } mPtr = ptr; mSize = mCapacity = size; } } /// @brief Apply a single advise to a memory block /// @param byteOffset offset in bytes marking the beginning of the memory block to be advised /// @param size size in bytes of the memory block to be advised. /// @param dev the device ID on which to apply the advice provided in adv, cudaCpuDeviceId = -1, 0, 1, ... /// @param adv advice to be applied to the resized range void advise(ptrdiff_t byteOffset, size_t size, int dev, cudaMemoryAdvise adv) const { cudaCheck(util::cuda::memAdvise(util::PtrAdd(mPtr, byteOffset), size, adv, dev)); } /// @brief Apply a list of advices to a memory block /// @param byteOffset offset in bytes marking the beginning of the memory block to be advised /// @param size size in bytes of the memory block to be advised. /// @param dev the device ID to prefetch to, cudaCpuDeviceId = -1, 0, 1, ... /// @param list list of cuda advises void advise(ptrdiff_t byteOffset, size_t size, int dev, std::initializer_list list) const { void *ptr = util::PtrAdd(mPtr, byteOffset); for (auto a : list) cudaCheck(util::cuda::memAdvise(ptr, size, a, dev)); } /// @brief Prefetches data to the specified device, i.e. ensure the device has an up-to-date copy of the memory specified /// @param byteOffset offset in bytes marking the beginning of the memory block to be prefetched /// @param size size in bytes of the memory block to be prefetched. The default value of zero means copy all @c this->size() bytes. /// @param dev the device ID to prefetch to, cudaCpuDeviceId = -1, 0, 1, ... /// @param stream cuda stream void prefetch(ptrdiff_t byteOffset = 0, size_t size = 0, int dev = cudaCpuDeviceId, cudaStream_t stream = cudaStreamPerThread) const { cudaCheck(util::cuda::memPrefetchAsync(util::PtrAdd(mPtr, byteOffset), size ? size : mSize, dev, stream)); } /////////////////////////////////////////////////////////////////////// /// @brief Prefetches all data to the specified device /// @param device device ID, cudaCpuDeviceId = -1, 0, 1, ... /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous /// @note Legacy method included for compatibility with DeviceBuffer void deviceUpload(int device = 0, cudaStream_t stream = cudaStreamPerThread, bool sync = false) const { cudaCheck(util::cuda::memPrefetchAsync(mPtr, mSize, device, stream)); if (sync) cudaCheck(cudaStreamSynchronize(stream)); } void deviceUpload(int device, void* stream, bool sync) const{this->deviceUpload(device, cudaStream_t(stream));} /// @brief Prefetches all data to the current device, as given by cudaGetDevice /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous /// @note Legacy method included for compatibility with DeviceBuffer void deviceUpload(void* stream, bool sync) const{ int device = 0; cudaCheck(cudaGetDevice(&device)); this->deviceUpload(device, cudaStream_t(stream), sync); } /////////////////////////////////////////////////////////////////////// /// @brief Prefetches all data to the host /// @param stream cuda stream /// @param sync if false the memory copy is asynchronous void deviceDownload(cudaStream_t stream = 0, bool sync = false) const { cudaCheck(util::cuda::memPrefetchAsync(mPtr, mSize, cudaCpuDeviceId, stream)); if (sync) cudaCheck(cudaStreamSynchronize(stream)); } /// @brief Legacy /// @param stream /// @param sync void deviceDownload(void* stream, bool sync) const{this->deviceDownload(cudaStream_t(stream), sync);} // used by GridHandle void deviceDownload(int dummmy, void* stream, bool sync) const{this->deviceDownload(cudaStream_t(stream), sync);} /////////////////////////////////////////////////////////////////////// /// @brief Returns a raw pointer to the unified memory managed by this instance. /// @warning Note that the pointer can be NULL! void* data() const {return mPtr;} /// @brief Returns an offset pointer of a specific type from the allocated unified memory /// @tparam T Type of the pointer returned /// @param count Numbers of elements of @c parameter type T to skip (or offset) the return pointer /// @warning assumes that this instance is not empty! template T* data(ptrdiff_t count = 0) const { NANOVDB_ASSERT(mPtr != nullptr || count == 0); return reinterpret_cast(mPtr) + count; } /// @brief Returns a byte offset void pointer from the unified memory /// @param byteOffset Number of bytes to skip (or offset) the return pointer /// @warning assumes that this instance is not empty! void* data(ptrdiff_t byteOffset) const { NANOVDB_ASSERT(mPtr != nullptr || byteOffset == 0); return util::PtrAdd(mPtr, byteOffset); } /// @brief Legacy /// @return void* deviceData() const {return mPtr;} void* deviceData(int) const {return mPtr;} /// @brief Size of the allocated pages in this instance /// @return number bytes allocated by this instance size_t size() const {return mSize;} /// @brief Capacity of this instance, i.e. room in page table /// @return number of bytes reserved, but not necessarily allocated, by this instance size_t capacity() const {return mCapacity;} //@{ /// @brief Returns true if this allocator is empty, i.e. has no allocated memory inline bool empty() const { return mPtr == nullptr; } inline bool isEmpty() const { return this->empty(); } //@} };// UnifiedBuffer }// namespace cuda template<> struct BufferTraits { static constexpr bool hasDeviceDual = true; }; }// namespace nanovdb #endif // end of NANOVDB_CUDA_UNIFIEDBUFFER_H_HAS_BEEN_INCLUDED openvdb-13.0.0/nanovdb/nanovdb/docs/000077500000000000000000000000001510223237100172325ustar00rootroot00000000000000openvdb-13.0.0/nanovdb/nanovdb/docs/CMakeLists.txt000066400000000000000000000022471510223237100217770ustar00rootroot00000000000000# Copyright Contributors to the OpenVDB Project # SPDX-License-Identifier: Apache-2.0 # find_package(doxygen REQUIRED dot ) if(WIN32) set(DOXYGEN_EXECUTABLE "C:/Program Files/doxygen/bin/doxygen.exe") else() set(DOXYGEN_EXECUTABLE "doxygen") endif() message(STATUS "DOXYGEN_EXECUTABLE = ${DOXYGEN_EXECUTABLE}") file(READ ${CMAKE_CURRENT_SOURCE_DIR}/doxygen-config DOXYGEN_CONFIG_CONTENT) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config ${DOXYGEN_CONFIG_CONTENT}) file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config "OUTPUT_DIRECTORY=\"${CMAKE_CURRENT_BINARY_DIR}/docs\"\n") add_custom_target( nanovdb_docs SOURCES doxygen-config doc.md codingstyle.txt FAQ.md SourceTree.md HowToBuild.md HelloWorld.md COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM) install( CODE "EXECUTE_PROCESS(COMMAND \"${CMAKE_COMMAND}\" --build \"${PROJECT_BINARY_DIR}\" --target nanovdb_docs)" ) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/html DESTINATION docs) openvdb-13.0.0/nanovdb/nanovdb/docs/codingstyle.txt000066400000000000000000000311031510223237100223150ustar00rootroot00000000000000/** @page codingStyle Coding Style @section Introduction NanoVDB coding practices. @section sStyleContents Contents - @ref sNamingConventions - @ref sNamespaceConventions - @ref sClassConventions - @ref sClassMethods - @ref sClassInstanceVariables - @ref sClassStaticVariables - @ref sLocalVariablesAndArguments - @ref sConstants - @ref sEnumerationNames - @ref sEnumerationValues - @ref sTypedefs - @ref sGlobalVariables - @ref sGlobalFunctions - @ref sBooleans - @ref sPractices - @ref sGeneral - @ref sFormatting - @ref sIncludeStatements - @ref sComments - @ref sPrimitiveTypes - @ref sMacros - @ref sClasses - @ref sConditionalStatements - @ref sNamespaces - @ref sExceptions - @ref sTemplates - @ref sMiscellaneous @section sNamingConventions Naming Conventions @subsection sNamespaceConventions Namespaces -# Lowercase words, keep simple and short (e.g., @c tools, @c tree). -# Use @c internal (or @c detail) or module_internal for symbols such as templates that must be defined in header files but that are implementation details not intended for public use. @subsection sClassConventions Classes and Structs -# Mixed case; first letter uppercase (e.g., @c AffineMap, @c TreeIterator) -# Do not use a prefix. @subsection sClassMethods Class Methods -# Mixed case; first letter lowercase (e.g., getAccessor(), gridType()) -# Accessor methods that return a member variable by reference or a primitive type by value are just the variable name (e.g., Grid::tree()). -# Accessor methods that involve construction of objects or other computations are @c get + the variable name (e.g., Grid::getAccessor()). -# Simple mutators are @c set + the variable name (e.g., Grid::setTree(tree);). @subsection sClassInstanceVariables Class Instance Variables -# Mixed case; always prefixed by @c m (e.g., @c mTree, @c mTransform) -# The @c m prefix may be omitted for members of structs used in the public API (e.g., struct Color { float r, g, b; }). @subsection sClassStaticVariables Class Static Variables -# Mixed case; always prefixed by @c s (e.g., @c sInitialized) @subsection sLocalVariablesAndArguments Local Variables and Arguments -# Use mixed case with an initial lower case letter (e.g., @c ijk, @c offset, @c range, @c rhsValue). @subsection sConstants Constants -# All uppercase; words separated by underscores. If not in a namespace or local to a source file, then prefixed with the library name in all caps (e.g., @c HALF_FLOAT_TYPENAME_SUFFIX, @c ZIP_COMPRESSION_LEVEL) @subsection sEnumerationNames Enumeration Names -# Mixed case; first letter uppercase (e.g., @c GridClass, @c VecType) @subsection sEnumerationValues Enumeration Values -# With @c enum, all uppercase with words separated by underscores (e.g., @c GRID_LEVEL_SET, @c VEC_INVARIANT) and with a common prefix -# With enum class, mixed case with the first letter uppercase (e.g., @c GridClass::Unknown, @c GridClass::LevelSet) @subsection sTypedefs Typedefs -# Mixed case; first letter uppercase (e.g., @c ConstPtr, @c ValueType) -# Do not use a prefix. @subsection sGlobalVariables Global Variables -# Mixed case; always prefixed by @c g (e.g., @c gRegistry) -# In general, try to use class static data instead of globals. @subsection sGlobalFunctions Global Functions -# Mixed case; always prefixed by @c g (e.g., gFunc()). -# In general, try to use class static members instead of global functions. @subsection sBooleans Booleans -# When naming boolean functions and variables, use names that read as a condition (e.g., if (grid.empty()), if (matrix.isInvertible())). @section sPractices Practices @subsection sGeneral General -# Code must compile without any warning messages at the default warning level. -# Prefer the C++ Standard Library to the C Standard Library. -# Restrict variables to the smallest scopes possible, and avoid defining local variables before giving them values. Prefer declarations inside conditionals: if (Grid::Ptr grid = createGrid()) { ... } instead of Grid::Ptr grid = createGrid(); if (grid) { ... } -# For new files, be sure to use the right license boilerplate per our license policy. @subsection sFormatting Formatting -# Indentation is 4 spaces. Do not use tabs. -# Lines are no more than 100 characters long. -# Use Unix-style carriage returns ("\n") rather than Windows/DOS ones ("\r\n"). -# Do not leave debug printfs or other debugging code lying around. -# Leave a blank line between a group of variable declarations and other code. -# Leave a space after the keywords @c if, @c switch, @c while, @c do, @c for, and @c return. -# Leave a space on each side of binary operators such as @c +, @c -, @c *, @c /, @c &&, and @c ||. For clarity in mathematical situations, you may omit the spaces on either side of @c * and @c / operators to emphasize their precedence over @c + and @c -. -# Do not leave a space between any dereferencing operator (such as @c *, @c &, @c [], @c ->, or @c .) and its operands. -# In parameter lists, leave a space after each comma. -# Do not leave a space after an opening parenthesis or before a closing parenthesis. -# Parentheses should be used to clarify operator precedence in expressions. -# Do not leave a space before an end-of-statement semicolon. -# Do not use literal tabs in strings or character constants. Rather, use spaces or "\t". -# If a parameter list is too long, break it between parameters. Group related parameters on lines if appropriate. -# Modified spacing is allowed to vertically align repetitive expressions. -# Always begin numeric constants with a digit (e.g., 0.001 not .001). -# Use K&R-style brace placement in public code. -# You may leave off braces for simple, single line flow control statements. -# The return type in a function definition should go on a line by itself. @subsection sIncludeStatements Include Statements -# Always use double quotes ("") to include header files that live in the same directory as your source code. -# Use angle brackets (<>) to include header files from outside a file’s directory. -# Do not use absolute paths in include directives. -# If there is a header corresponding to a given source file, list it first, followed by other local headers, library headers and then system headers. @subsection sHeaderFiles Header Files -# Header files have a .h extension. -# All header files should be bracketed by @c \#ifdef "guard" statements. -# In class definitions, list public, then protected, then private members. -# List methods before variables. -# Fully prototype all public functions and use descriptive naming for each argument. -# Declare every function defined in a header but outside a class definition explicitly as @c inline. -# Prefer forward declarations to @c \#include directives in headers. -# Do not take advantage of indirect inclusion of header files. -# Do not use anonymous namespaces in header files. @subsection sSourceFiles Source Files -# Source files have a .cc extension. -# Properly prototype all file static functions with usefully named arguments. -# Whenever possible, put variables and functions in an anonymous namespace. -# Avoid global variables. @subsection sComments Comments -# Use @c // style comments instead of / * * / style, even for multi-line comments. -# Use multi-line comments to describe following paragraphs of code. -# Use end-of-line comments to describe variable declarations or to clarify a single statement. -# Large blocks of code should be commented out with \#if 0 and @c \#endif. -# Do not leave obsolete code fragments within comments as an historical trail. -# Document public code with Doxygen comments, formatted as follows: @verbatim /// @brief Create a new grid of type @c GridType classified as a "Level Set", /// i.e., a narrow-band level set. /// /// @param voxelSize the size of a voxel in world units /// @param halfWidth the half width of the narrow band in voxel units /// /// @details The voxel size and the narrow band half width define the grid's /// background value as halfWidth*voxelWidth. The transform is linear /// with a uniform scaling only corresponding to the specified voxel size. /// /// @note It is generally advisable to specify a half-width of the narrow band /// that is larger than one voxel unit, otherwise zero crossings are not guaranteed. template typename GridType::Ptr createLevelSet( Real voxelSize = 1.0, Real halfWidth = LEVEL_SET_HALF_WIDTH); @endverbatim @subsection sPrimitiveTypes Primitive Types -# Avoid writing code that is dependent on the bit size of primitive values, but when specific bit sizes are required, use explicitly-sized types such as @c int32_t or @c uint64_t. @subsection sMacros Macros -# Avoid macros for constants. Use global static constants instead. (Local static constants are not guaranteed to be initialized in a thread-safe manner.) -# Avoid macro functions. Use @c inline and templates instead. @subsection sClasses Classes -# Constructors that can be called with only one argument should be prefixed with the @c explicit keyword to avoid unintended type conversions. -# Never call virtual methods from destructors. -# If you have a copy constructor, make sure you have an assignment operator. -# If you have an assignment operator, you probably need a copy constructor. -# If you have data members that are pointers to dynamically allocated memory, make sure you have a copy constructor and an assignment operator, both of which do the right thing with that memory. -# Classes which are to be subclassed always have a virtual destructor, even if it is empty. -# Check against self assignment and return *this in assignment operators. -# Declare methods as @c const wherever possible. -# Declare object-valued input arguments as const references wherever possible. Primitives may be passed by value, however. -# Arithmetic, logical, bitwise, dereference, and address of operators should only be used when their semantics are clear, obvious, and unambiguous. -# The application operator [ () ] is allowed for functors. -# Conversion operators should be avoided. -# Never return const references to stack allocated or implicitly computed objects. -# If a class does not have a copy constructor and/or assignment operator, consider creating a private unimplemented copy constructor and/or assignment operator to prevent automatically generated versions from being used. @subsection sConditionalStatements Conditional Statements -# For test expressions, use a form that indicates as clearly as possible the types of operands by avoiding implicit casts. -# Assignments that occur within conditional statements must have no effect in the enclosing scope. -# Allow for arithmetic imprecision when comparing floating point values. -# In switch statements, always comment fallthroughs and empty cases. @section sNamespaces Namespaces -# Namespaces should be used whenever possible. -# Avoid pulling in entire namespaces with @c using directives (e.g., using namespace std;). -# @c using declarations are allowed for individual symbols (e.g., using std::vector;), but they should never appear in a header file. -# Define global operators in the namespace of their arguments. -# Namespaces are not indented. @subsection sExceptions Exceptions -# Appropriate use of exceptions is encouraged. -# Methods should declare all exceptions they might throw using comments, but not exception specifications. -# Throw scope local exception instances, not pointers or references or globals. -# Catch exceptions by reference. -# Never allow an exception to escape from a destructor. @subsection sTemplates Templates -# Use @c typename rather than @c class when declaring template type parameters. @subsection sMiscellaneous Miscellaneous -# Don’t use pointers to run through arrays of non-primitive types. Use explicit array indexing, iterators or generic algorithms instead. -# Use C++ casts (static_cast<int>(x) or int(x)), not C casts ((int)x). -# Multiple variables of the same data type may be declared on the same line if closely related. -# Library code must never deliberately terminate the application in response to an error condition. -# Avoid using malloc/free when new/delete can be used instead. -# Avoid @c goto. -# Avoid \"magic numbers\". Use named constants when necessary. -# If you use typeid/typeinfo, be aware that although all runtimes support typeinfo::name(), the format of the string it returns varies between compilers and even for a given compiler the value is not guaranteed to be unique. */ openvdb-13.0.0/nanovdb/nanovdb/docs/doxygen-config000066400000000000000000003105751510223237100221100ustar00rootroot00000000000000# Doxyfile 1.8.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "NanoVDB" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = 0.1.0 ALIASES += nanovdb_namespace="nanovdb::v0_1" PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS PREDEFINED += NANOVDB_VERSION_NAME=v0_1 PREDEFINED += NANOVDB_ABI_VERSION_NUMBER=0 PREDEFINED += __declspec(x):= __attribute__(x):= PREDEFINED += NANOVDB_STATIC_SPECIALIZATION="" PREDEFINED += NANOVDB_USE_LOG4CPLUS= # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = obj/doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES += ijk="(i, j, k)" ALIASES += xyz="(x, y, z)" ALIASES += const="const" # Use this command to create a link to an NanoVDB class, function, etc. # Usage is "@vdblink:: @endlink", where is a fully # namespace-qualified symbol minus the nanovdb and version number namespaces # and is the text of the link. # Example: @vdblink::tree::RootNode root node@endlink ALIASES += vdblink="@link @nanovdb_namespace" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = YES # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = ./include/nanovdb \ ./docs/doc.md \ ./docs/codingstyle.txt \ ./docs/HowToBuild.md \ ./docs/HelloWorld.md \ ./docs/FAQ.md \ ./docs/SourceTree.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.h # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = NANOVDB_CUDA_EXPORT # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = NO # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 4 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 222 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /