pax_global_header00006660000000000000000000000064146775216420014530gustar00rootroot0000000000000052 comment=928557ed49f0940542a768e248c38032c68dde6b qtrvsim-0.9.8/000077500000000000000000000000001467752164200132535ustar00rootroot00000000000000qtrvsim-0.9.8/.clang-format000066400000000000000000000065421467752164200156350ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: WebKit AccessModifierOffset: -4 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveMacros: false AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Right AlignOperands: Align AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Inline AllowShortLambdasOnASingleLine: All AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: false BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: Never AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: false SplitEmptyRecord: false SplitEmptyNamespace: false BreakBeforeBinaryOperators: All BreakBeforeBraces: Attach BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakStringLiterals: true ColumnLimit: 100 CompactNamespaces: true ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: false DeriveLineEnding: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Regroup IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 SortPriority: 0 - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 SortPriority: 0 - Regex: '.*' Priority: 1 SortPriority: 0 IncludeIsMainRegex: '(Test)?$' IncludeIsMainSourceRegex: '' IndentCaseLabels: false IndentGotoLabels: true IndentPPDirectives: BeforeHash IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: Inner PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 100 PointerAlignment: Right ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInConditionalStatement: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false SpaceBeforeSquareBrackets: false Standard: Latest StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 4 UseCRLF: false UseTab: Neverqtrvsim-0.9.8/.dev-config.local.mk000066400000000000000000000015251467752164200167770ustar00rootroot00000000000000# This file provides local configuration to helper Makefile to speedup common development tasks # The given values are provided as defaults and changes are ignored by git. BUILD_DIR=./build ######################################################################################################################## # WASM ######################################################################################################################## # Wasm edition build directory WASM_BUILD_DIR=$(BUILD_DIR)/wasm # EMSDK_PATH=/usr/lib/emsdk # Version of the wasm compiler - must be carefully matched with QT version EMSCRIPTEN_VERSION=1.39.8 # Destination for aqt installer QT_INSTALL_DIR=/opt/qt # Version of QT used to build wasm edition QT_WASM_VERSION=5.15.2 # Path to QT installation intended for wasm build QT_WASM_PATH=/opt/qt/$(QT_WASM_VERSION)/wasm_32qtrvsim-0.9.8/.github/000077500000000000000000000000001467752164200146135ustar00rootroot00000000000000qtrvsim-0.9.8/.github/workflows/000077500000000000000000000000001467752164200166505ustar00rootroot00000000000000qtrvsim-0.9.8/.github/workflows/debug.yml000066400000000000000000000254701467752164200204710ustar00rootroot00000000000000name: Debug on: [ push, workflow_dispatch, pull_request, merge_group ] jobs: build: name: ${{ matrix.config.name }} needs: [ build-riscv-tests ] # Avoid duplicate builds on PR from the same repository if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository runs-on: ${{ matrix.config.os }} strategy: fail-fast: false matrix: config: - { name: "Ubuntu Latest GCC", os: ubuntu-latest, build_type: "Debug", cc: "gcc", cxx: "g++", build_system: "Unix Makefiles", qt_version: "native", qt_install_command: "sudo apt-get update && sudo apt-get install qtbase5-dev", # Apt is significantly faster that aqt. } - { name: "Ubuntu Latest GCC + Qt6", os: ubuntu-latest, build_type: "Debug", cc: "gcc", cxx: "g++", build_system: "Unix Makefiles", qt_version: "6.2.1" } - { name: "macOS AMD64 Clang", os: macos-13, build_type: "Debug", cc: "clang", cxx: "clang++", build_system: "Unix Makefiles", qt_version: "5.15.2", # Cached aqt is faster that brew. } - { name: "macOS ARM Clang + Qt6", os: macos-latest, build_type: "Debug", cc: "clang", cxx: "clang++", build_system: "Unix Makefiles", qt_version: "6.6.3", # Cached aqt is faster that brew. } - { name: "Windows 2019 MinGW", os: windows-2019, build_type: "Debug", cc: "gcc", cxx: "g++", build_system: "MinGW Makefiles", # Older Qt releases do not have 64bit mingw release qt_version: "5.12.9", qt_arch: "win64_mingw73" } - { name: "Windows 2022 Clang + Qt6", os: windows-2022, build_type: "Debug", # on Windows, msbuild does not support Clang with GNU-like interface # and NMake does not support parallel builds cc: "clang", cxx: "clang++", build_system: "Ninja", qt_version: "6.7.0", qt_arch: "win64_msvc2019_64" } steps: - uses: actions/checkout@v4 - run: git submodule update --recursive --init - name: Ccache uses: hendrikmuhs/ccache-action@v1.2.11 # https://github.com/hendrikmuhs/ccache-action/issues/181 with: key: ${{ github.ref_name }}-${{ matrix.config.name }} - name: Install specified Qt version if: matrix.config.qt_version != 'native' uses: jurplel/install-qt-action@v3 with: version: ${{ matrix.config.qt_version }} cache: true cache-key-prefix: ${{ runner.os }}-${{ matrix.config.qt_version }}-Qt arch: ${{ matrix.config.qt_arch }} dir: ${{ github.workspace }}/Qt - name: Install native Qt by package manager if: matrix.config.qt_version == 'native' run: ${{ matrix.config.qt_install_command }} - name: Setup Ninja if: matrix.config.build_system == 'Ninja' uses: seanmiddleditch/gha-setup-ninja@v4 - name: Create Build Environment run: cmake -E make_directory ${{ github.workspace }}/build - name: Configure CMake shell: bash working-directory: ${{github.workspace}}/build run: "cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_C_COMPILER=${{ matrix.config.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DFORCE_COLORED_OUTPUT=true -G \"${{ matrix.config.build_system }}\"" - name: Build working-directory: ${{ github.workspace }}/build run: cmake --build . -j4 - name: Deploy on Windows if: runner.os == 'Windows' working-directory: ${{ github.workspace }}/build/target shell: bash run: "windeployqt \"${{ github.workspace }}/build/target/qtrvsim_gui.exe\"" - name: Test working-directory: ${{ github.workspace }}/build shell: bash run: ctest --output-on-failure --verbose - name: Get official RISC-V tests if: ${{ steps.cache-tests.outputs.cache-hit != 'true' }} uses: alehechka/download-tartifact@v2 with: name: riscv-official-tests - name: Official RISC-V tests (single cycle) # The testing python script does not support Ubuntu 18 if: matrix.config.os != 'ubuntu-18.04' working-directory: ${{ github.workspace }}/tests/riscv-official #run: python qtrvsim_tester.py --no-64 ${{ github.workspace }}/build/target/qtrvsim_cli run: python qtrvsim_tester.py -M -A ${{ github.workspace }}/build/target/qtrvsim_cli - name: Official RISC-V tests (pipelined) # The testing python script does not support Ubuntu 18 if: matrix.config.os != 'ubuntu-18.04' working-directory: ${{ github.workspace }}/tests/riscv-official #run: python qtrvsim_tester.py --no-64 ${{ github.workspace }}/build/target/qtrvsim_cli run: python qtrvsim_tester.py -M -A --pipeline ${{ github.workspace }}/build/target/qtrvsim_cli - name: Official RISC-V tests (single cycle, cached) # The testing python script does not support Ubuntu 18 if: matrix.config.os != 'ubuntu-18.04' working-directory: ${{ github.workspace }}/tests/riscv-official #run: python qtrvsim_tester.py --no-64 ${{ github.workspace }}/build/target/qtrvsim_cli run: python qtrvsim_tester.py -M -A --cache ${{ github.workspace }}/build/target/qtrvsim_cli - name: Official RISC-V tests (pipelined, cached) # The testing python script does not support Ubuntu 18 if: matrix.config.os != 'ubuntu-18.04' working-directory: ${{ github.workspace }}/tests/riscv-official #run: python qtrvsim_tester.py --no-64 ${{ github.workspace }}/build/target/qtrvsim_cli run: python qtrvsim_tester.py -M -A --pipeline --cache ${{ github.workspace }}/build/target/qtrvsim_cli - name: Store created artifacts uses: actions/upload-artifact@v4 with: name: target-${{ runner.os }}-qt${{ matrix.config.qt_version }} path: ${{ github.workspace }}/build/target build-emscripten: name: ${{ matrix.config.name }} # Avoid duplicate builds on PR from the same repository if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository runs-on: ${{ matrix.config.os }} strategy: fail-fast: false matrix: config: - { name: "WASM Linux", os: ubuntu-latest, build_type: Release, qt_arch: wasm_32, emsdk_version: 1.39.8, qt_version: 5.15.2, } steps: - uses: actions/checkout@v4 - name: Ccache uses: hendrikmuhs/ccache-action@v1.2.11 # https://github.com/hendrikmuhs/ccache-action/issues/181 with: key: ${{ github.ref_name }}-${{ matrix.config.name }} - name: Setup EMSDK cache id: cache-system-libraries uses: actions/cache@v4 with: path: 'emsdk-cache' key: ${{ runner.os }}-${{ matrix.config.emsdk_version }}-${{ matrix.config.qt_version }}-emsdk - name: Setup emsdk uses: mymindstorm/setup-emsdk@v11 with: version: ${{ matrix.config.emsdk_version }} actions-cache-folder: 'emsdk-cache' - name: Install Qt uses: jurplel/install-qt-action@v3 with: version: ${{ matrix.config.qt_version }} cache: true cache-key-prefix: 'wasm-qt' arch: ${{ matrix.config.qt_arch }} dir: ${{ github.workspace }}/Qt - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build - name: Configure CMake working-directory: ${{github.workspace}}/build run: "emcmake cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_PREFIX_PATH=$Qt5_DIR -DCMAKE_FIND_ROOT_PATH=$Qt5_DIR -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DFORCE_COLORED_OUTPUT=true -Wno-dev" - name: Build working-directory: ${{ github.workspace }}/build run: cmake --build . -j4 - name: Store created artifacts uses: actions/upload-artifact@v4 with: name: target-wasm-${{ runner.os }}-qt${{ matrix.config.qt_version }} path: ${{ github.workspace }}/build/target build-riscv-tests: name: Build official RISC-V tests # Avoid duplicate builds on PR from the same repository if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - run: git submodule update --recursive --init - name: Get cache key uses: mathiasvr/command-output@v2.0.0 id: subtree-hash with: run: git rev-parse HEAD:tests/riscv-official/ - name: Cache id: cache-tests uses: actions/cache@v4 with: path: ${{ github.workspace }}/tests/riscv-official/isa key: riscv-tests-${{ steps.subtree-hash.outputs.stdout }} - name: Toolchain for official RISC-V tests if: ${{ steps.cache-tests.outputs.cache-hit != 'true' }} working-directory: ${{ github.workspace }}/tests/riscv-official # Version 14 is needed to correctly process newer parts of RV run: | ### Ubuntu 22 already provides those # echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main" | sudo tee -a /etc/apt/sources.list && # wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - && sudo apt-get update && sudo apt-get install clang-14 lldb-14 lld-14 - name: Build official RISC-V tests if: ${{ steps.cache-tests.outputs.cache-hit != 'true' }} working-directory: ${{ github.workspace }}/tests/riscv-official/isa env: RISCV_COMPILER: clang-14 USE_CLANG_OPTS: true RISCV_OBJDUMP_CMD: llvm-objdump-14 run: make - name: Store created artifacts # Use of tar significantly improves performance as artifact upload has significant per file penalty uses: alehechka/upload-tartifact@v2 with: name: riscv-official-tests path: tests/riscv-official/isa qtrvsim-0.9.8/.github/workflows/release.yml000066400000000000000000000024621467752164200210170ustar00rootroot00000000000000name: Release on: workflow_dispatch jobs: build: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} strategy: fail-fast: true matrix: config: - { name: "OBS bundle (Ubuntu Latest GCC)", os: ubuntu-latest, build_type: "Release", cc: "gcc", cxx: "g++" } steps: - uses: actions/checkout@v4 # CMake will not configure without Qt installed - name: Install Qt run: sudo apt-get update && sudo apt-get install qtbase5-dev - name: Create Build Environment run: cmake -E make_directory ${{ github.workspace }}/build - name: Configure CMake shell: bash working-directory: ${{ github.workspace }}/build env: CC: ${{ matrix.config.cc }} CXX: ${{ matrix.config.cxx }} run: "cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DDEV_MODE=true" - name: Create OBS bundle working-directory: ${{ github.workspace }}/build run: make open_build_service_bundle - name: Store OBS bundle uses: actions/upload-artifact@v4 with: name: obs-package-bundle path: ${{ github.workspace }}/build/target/pkg qtrvsim-0.9.8/.gitignore000066400000000000000000000003431467752164200152430ustar00rootroot00000000000000.* !.gitignore !.gitmodules !.github # Qt stuff *.pro.user* *.qbs.user* # Common test directory test_dir # Build directory build /CMakeFiles/ compile_commands.json /src/project_info.h # Local settings template .dev-config.mk qtrvsim-0.9.8/.gitmodules000066400000000000000000000002001467752164200154200ustar00rootroot00000000000000[submodule "riscv-tests"] path = tests/riscv-official/riscv-tests url = https://github.com/riscv-software-src/riscv-tests.git qtrvsim-0.9.8/CMakeLists.txt000066400000000000000000000357531467752164200160300ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10) cmake_policy(VERSION 3.10) project(QtRVSim LANGUAGES C CXX VERSION 0.9.8 DESCRIPTION "RISC-V CPU simulator for education purposes") set(KAREL_KOCI "Karel Koci ") set(PAVEL_PISA "Pavel Pisa ") set(JAKUB_DUPAK "Jakub Dupak ") set(MAX_HOLLMANN "Max Hollmann ") set(PROJECT_HOMEPAGE_URL "https://github.com/cvut/qtrvsim") set(GENERIC_NAME "RISC-V CPU simulator") set(LICENCE "GPL-3.0-or-later") set(LONG_DESCRIPTION "RISC-V CPU simulator for education purposes with pipeline and cache visualization.") string(TIMESTAMP YEAR "%Y") include(cmake/CopyrightTools.cmake) copyright( "Copyright (c) 2017-2019 ${KAREL_KOCI}" "Copyright (c) 2019-${YEAR} ${PAVEL_PISA}" "Copyright (c) 2020-${YEAR} ${JAKUB_DUPAK}" "Copyright (c) 2020-2021 ${MAX_HOLLMANN}") include(cmake/GPL-3.0-or-later.cmake) # ============================================================================= # Configurable options # ============================================================================= set(DEV_MODE false CACHE BOOL "Enable developer options in this CMake, like packaging.\ They should be ignored, when user just wants to build this project.") set(FORCE_ELFLIB_STATIC false CACHE BOOL "Use included statically linked libelf even if system one is available.") set(SANITIZERS "address,undefined" CACHE STRING "Runtime sanitizers to use in debug builds. Column separated subset of {address, memory, undefined, thread} or none. Memory and address cannot be used at the same time.") set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/target" CACHE STRING "Absolute path to place executables to.") set(PACKAGE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/pkg" CACHE STRING "Absolute path to place generated package files.") set(FORCE_COLORED_OUTPUT false CACHE BOOL "Always produce ANSI-colored output (GNU/Clang only).") set(USE_ALTERNATE_LINKER "" CACHE STRING "Use alternate linker. Leave empty for system default; alternatives are 'gold', 'lld', 'bfd', 'mold'") set(QT_VERSION_MAJOR "auto" CACHE STRING "Qt major version to use. 5|6|auto") # ============================================================================= # Generated variables # ============================================================================= if (NOT "${QT_VERSION_MAJOR}" MATCHES "5|6|auto") message(FATAL_ERROR "Invalid value for QT_VERSION_MAJOR: ${QT_VERSION_MAJOR} (expected 5, 6 or auto)") endif () if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") set(WASM true) else () set(WASM false) endif () set(CXX_TEST_PATH ${EXECUTABLE_OUTPUT_PATH}) set(C_TEST_PATH ${EXECUTABLE_OUTPUT_PATH}) macro(set_alternate_linker linker) find_program(LINKER_EXECUTABLE ld.${USE_ALTERNATE_LINKER} ${USE_ALTERNATE_LINKER}) if (LINKER_EXECUTABLE) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 12.0.0) add_link_options("-ld-path=${USE_ALTERNATE_LINKER}") else () add_link_options("-fuse-ld=${USE_ALTERNATE_LINKER}") endif () else () set(USE_ALTERNATE_LINKER "" CACHE STRING "Use alternate linker" FORCE) endif () endmacro() if (NOT "${USE_ALTERNATE_LINKER}" STREQUAL "") set_alternate_linker(${USE_ALTERNATE_LINKER}) endif () # I don't want to relly on the assumption, that this file is invoked as root # project. Therefore I propagate the information to all subprojects # MAIN_PROJECT_*. Lowercase and uppercase are used for executable names and # C defines, respectively. set(MAIN_PROJECT_NAME "${PROJECT_NAME}") set(MAIN_PROJECT_VERSION "${PROJECT_VERSION}") set(MAIN_PROJECT_APPID "cz.cvut.edu.comparch.qtrvsim") set(MAIN_PROJECT_ORGANIZATION "FEE CTU") set(MAIN_PROJECT_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") string(TOLOWER "${PROJECT_NAME}" MAIN_PROJECT_NAME_LOWER) string(TOUPPER "${PROJECT_NAME}" MAIN_PROJECT_NAME_UPPER) # ============================================================================= # CMake config and tools # ============================================================================= list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") if (CMAKE_VERSION VERSION_LESS "3.7.0") set(CMAKE_INCLUDE_CURRENT_DIR ON) endif () include(cmake/BuildType.cmake) set(CMAKE_INCLUDE_CURRENT_DIR ON) # ============================================================================= # Build options # - common to all subdirs # ============================================================================= set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # MSVC is not supported, Clang+MSVC currently does not seem to support sanitizers in with debug CRT, # MinGW does not support sanitizers at all; all together, just skip sanitizers on Windows and re-investigate # in a year or two whether Clang sanitizer support has improved if (NOT "${SANITIZERS}" MATCHES "none" AND NOT "${WASM}" AND NOT "${WIN32}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=${SANITIZERS} -g -g3 -ggdb") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=${SANITIZERS} -g -g3 -ggdb") set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=${SANITIZERS}") endif () if (NOT "${BUILD_DEBUG}") message(STATUS "Debug prints globally suppressed.") add_definitions(-DQT_NO_DEBUG_OUTPUT=1) endif () include_directories("src" "src/machine") if (${FORCE_COLORED_OUTPUT}) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_compile_options(-fdiagnostics-color=always) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_compile_options(-fcolor-diagnostics) endif () endif () ## ============================================================================ ## Warning level ## ============================================================================ if (WIN32) # otherwise CRT complains that `strerror` is deprecated add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif () if (MSVC) add_compile_options(/W4 /WX) else () add_compile_options(-Wall -Wextra -Werror=switch) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # This is currently a wont-fix and it will be OK in cpp20. add_compile_options(-Wno-c99-designator) endif () endif () # ============================================================================= # Dependencies # ============================================================================= if ("${WASM}") message(STATUS "WASM build detected") message(STATUS "Enabled WASM exception handling") add_compile_options("-fexceptions") # Extra options for WASM linking add_link_options("-fexceptions") add_link_options("-flto") # Activate Embind C/C++ bindings # https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html add_link_options("--bind") # Enable C++ exception catching # https://emscripten.org/docs/optimizing/Optimizing-Code.html#c-exceptions add_link_options("SHELL:-s DISABLE_EXCEPTION_CATCHING=0") # Enable Fetch API # https://emscripten.org/docs/api_reference/fetch.html add_link_options("SHELL:-s FETCH=1") add_link_options("SHELL:-s WASM=1") # Emulate missing OpenGL ES2/ES3 features # https://emscripten.org/docs/porting/multimedia_and_graphics/OpenGL-support.html#opengl-es-2-0-3-0-emulation add_link_options("SHELL:-s FULL_ES2=1") add_link_options("SHELL:-s FULL_ES3=1") # Activate WebGL 2 (in addition to WebGL 1) # https://emscripten.org/docs/porting/multimedia_and_graphics/OpenGL-support.html#webgl-friendly-subset-of-opengl-es-2-0-3-0 add_link_options("SHELL:-s USE_WEBGL2=1") # Run static dtors at teardown # https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run add_link_options("SHELL:-s ALLOW_MEMORY_GROWTH=1") # Export UTF16ToString,stringToUTF16 # Required by https://codereview.qt-project.org/c/qt/qtbase/+/286997 (since Qt 5.14) add_link_options("SHELL:-s EXTRA_EXPORTED_RUNTIME_METHODS=[\"UTF16ToString\",\"stringToUTF16\"]") # Enable demangling of C++ stack traces # https://emscripten.org/docs/porting/Debugging.html add_link_options("SHELL:-s DEMANGLE_SUPPORT=1") # Run static dtors at teardown # https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run add_link_options("SHELL:-s EXIT_RUNTIME=1") # Debug build if ("${BUILD_DEBUG}") message(STATUS "Enabled WASM debug") add_link_options("SHELL:-s ERROR_ON_WASM_CHANGES_AFTER_LINK") add_link_options("SHELL:-s WASM_BIGINT") add_link_options("-O1") endif () add_definitions(-DQT_NO_DEBUG_OUTPUT=1) message(STATUS "Debug output disabled") else () # Not available for WASM enable_testing() if (NOT "${FORCE_ELFLIB_STATIC}") find_package(LibElf) if ("${LibElf_FOUND}") include(CheckSymbolExists) check_symbol_exists(EM_RISCV "gelf.h" LIBELF_HAS_RISCV) if ("${LIBELF_HAS_RISCV}") # Turn non-cmake library into a cmake target add_library(libelf INTERFACE) target_link_libraries(libelf INTERFACE ${LIBELF_LIBRARY}) target_include_directories(libelf INTERFACE ${LIBELF_INCLUDE_DIR}) message(STATUS "Using system libelf") else () message(STATUS "System libelf does not support RISC-V") set(LibElf_FOUND FALSE) # Force fallback endif () endif () endif () endif () if ("${WASM}" OR "${FORCE_ELFLIB_STATIC}" OR NOT "${LibElf_FOUND}") message(STATUS "Using local libelf fallback.") add_subdirectory("external/libelf") endif () # Detect Qt used qt version # Based on article https://www.steinzone.de/wordpress/how-to-support-both-qt5-and-qt6-using-cmake/ # Cannot use version-less approach due to Qt 5.9.5 support constraint. if ("${QT_VERSION_MAJOR}" STREQUAL "auto") find_package(QT NAMES Qt5 Qt6 COMPONENTS Core REQUIRED) endif () # Normally, we would use variable Qt5 or Qt6 to reference the Qt library. Here we do that through # this variable based on detected version major of Qt. set(QtLib "Qt${QT_VERSION_MAJOR}") find_package(${QtLib} REQUIRED COMPONENTS Core Widgets Gui Test OPTIONAL_COMPONENTS PrintSupport) message(STATUS "${QtLib} version: ${${QtLib}Core_VERSION}") message(STATUS "${QtLib} print support: ${${QtLib}PrintSupport_FOUND}") if ("${WASM}") string(TIMESTAMP DATE "%Y%m%d") file(READ "${${QtLib}Core_DIR}/../../../plugins/platforms/qtloader.js" QTLOADER) string(REPLACE "applicationName + \".js\"" "applicationName + \".js?v=${DATE}\"" QTLOADER "${QTLOADER}") string(REPLACE "applicationName + \".wasm\"" "applicationName + \".wasm?v=${DATE}\"" QTLOADER "${QTLOADER}") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/target/qtloader.js" "${QTLOADER}") endif () # Qt 5.9.5 is the oldest supported add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050905) add_subdirectory("external/svgscene") # ============================================================================= # Sources # ============================================================================= add_subdirectory("src/common") add_subdirectory("src/machine") add_subdirectory("src/assembler") add_subdirectory("src/os_emulation") add_subdirectory("src/gui") if (NOT "${WASM}") add_subdirectory("src/cli") add_custom_target(all_unit_tests DEPENDS common_unit_tests machine_unit_tests) endif () # ============================================================================= # Installation # ============================================================================= # Prior to CMake version 3.13, installation must be performed in the subdirectory, # there the target was created. Therefore executable installation is to be found # in corresponding CMakeLists.txt. if (NOT "${WASM}") configure_file(data/gui.desktop.in "${EXECUTABLE_OUTPUT_PATH}/${MAIN_PROJECT_NAME_LOWER}.desktop") configure_file("data/${MAIN_PROJECT_APPID}.metainfo.xml.in" "${EXECUTABLE_OUTPUT_PATH}/${MAIN_PROJECT_APPID}.metainfo.xml") install(FILES "data/icons/gui.svg" DESTINATION "share/icons/hicolor/scalable/apps" RENAME "${MAIN_PROJECT_NAME_LOWER}_gui.svg") install(FILES "data/icons/48x48/gui.png" DESTINATION "share/icons/hicolor/48x48/apps" RENAME "${MAIN_PROJECT_NAME_LOWER}_gui.png") install(FILES "${EXECUTABLE_OUTPUT_PATH}/${MAIN_PROJECT_NAME_LOWER}.desktop" DESTINATION share/applications) install(FILES "${EXECUTABLE_OUTPUT_PATH}/${MAIN_PROJECT_APPID}.metainfo.xml" DESTINATION share/metainfo) endif () # ============================================================================= # Packages # ============================================================================= if ("${DEV_MODE}") # The condition prevents execution of this section during regular user installation. # It created files useless to normal users and requires additional tools (git, xz). message(STATUS "Packaging tools enabled.") set(PACKAGE_NAME "${MAIN_PROJECT_NAME_LOWER}") set(PACKAGE_VERSION "${PROJECT_VERSION}") set(PACKAGE_RELEASE "1") set(PACKAGE_SOURCE_ARCHIVE_FILE "${PACKAGE_NAME}_${PACKAGE_VERSION}.orig.tar.xz") set(PACKAGE_SOURCE_ARCHIVE_PATH "${PACKAGE_OUTPUT_PATH}/${PACKAGE_SOURCE_ARCHIVE_FILE}") set(PACKAGE_TOPLEVEL_DIR "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") set(PACKAGE_LONG_DESCRIPTION "${LONG_DESCRIPTION}") set(PACKAGE_MAINTAINER "${JAKUB_DUPAK}") set(PACKAGE_URL "${PROJECT_HOMEPAGE_URL}") set(PACKAGE_GIT "github.com:cvut/qtrvsim.git") set(PACKAGE_LICENCE "${LICENCE} ") include(cmake/PackageTools.cmake) # Inject up-to-date information into package config files. package_config_file(appimage appimage.yml extras/packaging/appimage/appimage.yml.in) package_config_file(archlinux PKGBUILD extras/packaging/arch/PKGBUILD.in) package_config_file(rpm ${PACKAGE_NAME}.spec extras/packaging/rpm/spec.in) # Debian uses whole directory which has to be saved to archive and shipped. package_debian_quilt(deb ${PACKAGE_NAME}_${PACKAGE_VERSION}-${PACKAGE_RELEASE}.dsc extras/packaging/deb/dsc.in extras/packaging/deb/debian ${PACKAGE_NAME}_${PACKAGE_VERSION}-${PACKAGE_RELEASE}.debian.tar.xz) # Creates bunch of files in ${CMAKE_BINARY_DIR}/target/pkg that you can just pass to # Open Build Service and it will build all packaging. # TODO: Currently changelog is not handled automatically. add_custom_target(open_build_service_bundle DEPENDS ${PACKAGE_SOURCE_ARCHIVE_FILE} appimage archlinux deb rpm WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/pkg) endif () configure_file(src/project_info.h.in ${CMAKE_CURRENT_LIST_DIR}/src/project_info.h @ONLY) qtrvsim-0.9.8/LICENSE000066400000000000000000001045051467752164200142650ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qtrvsim-0.9.8/Makefile000066400000000000000000000023051467752164200147130ustar00rootroot00000000000000include .dev-config.mk .dev-config.mk: [ ! -f .dev-config.mk ] && cp .dev-config.mk.default .dev-config.mk release: mkdir -p build/Release cd build/Release && cmake -DCMAKE_BUILD_TYPE=Release ../.. cd build/Release && cmake --build . debug: mkdir -p build/Debug cd build/Debug && cmake -DCMAKE_BUILD_TYPE=Debug ../.. cd build/Debug && cmake --build . ######################################################################################################################## # WASM ######################################################################################################################## wasm: bash extras/building/build-wasm.sh $(EMSCRIPTEN_VERSION) $(QT_WASM_PATH) $(EMSDK_PATH) wasm-clean: rm -rf $(WASM_BUILD_DIR) wasm-clean-deep: wasm-clean rm -rf $(EMSDK_PATH)/upstream/cache/* rm -rf $(EMSDK_PATH)/upstream/emscripten/cache/* wasm-serve: cp data/wasm/* $(WASM_BUILD_DIR)/target # Server is necessary due to CORS cd $(WASM_BUILD_DIR)/target/ && python -m http.server open localhost:8000 wasm-install-qt: python -m aqt install $(QT_WASM_VERSION) linux desktop wasm_32 --outputdir $(QT_INSTALL_DIR) .PHONY: release debug wasm wasm-clean wasm-clean-deep wasm-serve wasm-install-qtqtrvsim-0.9.8/README.md000066400000000000000000000623621467752164200145430ustar00rootroot00000000000000# QtRvSim–RISC-V CPU simulator for education ![QtRvSim screenshot](data/screenshots/intro.webp) Developed by the [Computer Architectures Education](http://comparch.edu.cvut.cz) project at [Czech Technical University](http://www.cvut.cz/). **Are you using QtRvSim at your organization?** [Please, let us know in the discussion!](https://github.com/cvut/qtrvsim/discussions/136) ## Table of contents - [Try it out! (WebAssembly)](#try-it-out-webassembly) - [Build and packages](#build-and-packages) - [Build Dependencies](#build-dependencies) - [General Compilation](#general-compilation) - [Building from source on macOS](#building-from-source-on-macos) - [Download Binary Packages](#download-binary-packages) - [Nix package](#nix-package) - [Tests](#tests) - [Documentation](#documentation) - [Accepted Binary Formats](#accepted-binary-formats) - [LLVM toolchain usage](#llvm-toolchain-usage) - [GNU toolchain usage](#gnu-toolchain-usage) - [GNU 64-bit toolchain use for RV32I target](#gnu-64-bit-toolchain-use-for-rv32i-target) - [Integrated Assembler](#integrated-assembler) - [Support to call external make utility](#support-to-call-external-make-utility) - [Advanced functionalities](#advanced-functionalities) - [Peripherals](#peripherals) - [Interrupts and Control and Status Registers](#interrupts-and-control-and-status-registers) - [System Calls Support](#system-calls-support) - [Limitations of the Implementation](#limitations-of-the-implementation) - [QtRvSim limitations](#qtrvsim-limitations) - [List of Currently Supported Instructions](#list-of-currently-supported-instructions) - [Links to Resources and Similar Projects](#links-to-resources-and-similar-projects) - [Copyright](#copyright) - [License](#license) ## Try it out! (WebAssembly) QtRVSim is experimentally available for [WebAssembly](https://webassembly.org/) and it can be run in most browsers without installation. **[QtRVSim online](https://comparch.edu.cvut.cz/qtrvsim/app)** **Note, that WebAssembly version is experimental.** Please, report any difficulties via [GitHub issues](https://github.com/cvut/qtrvsim/issues/new). ## Build and packages [![Packaging status](https://repology.org/badge/vertical-allrepos/qtrvsim.svg)](https://repology.org/project/qtrvsim/versions) [![build result](https://build.opensuse.org/projects/home:jdupak/packages/qtrvsim/badge.svg?type=default)](https://build.opensuse.org/package/show/home:jdupak/qtrvsim) ### Build Dependencies - Qt 5 (minimal tested version is 5.9.5), experimental support of Qt 6 - elfutils (optional; libelf works too but there can be some problems) ### Quick Compilation on Linux On Linux, you can use a wrapper Makefile and run `make` in the project root directory. It will create a build directory and run CMake in it. Available targets are: `release` (default) and `debug`. Note for packagers: This Makefile is deleted by CMake when source archive is created to avoid any ambiguity. Packages should invoke CMake directly. ### General Compilation ```shell cmake -DCMAKE_BUILD_TYPE=Release /path/to/qtrvsim make ``` Where `/path/to/qtrvsim` is path to this project root. The built binaries are to be found in the directory `target`in the build directory (the one, where cmake was called). `-DCMAKE_BUILD_TYPE=Debug` builds development version including sanitizers. If no build type is supplied, `Debug` is the default. ### Building from source on macOS Install the latest version of **Xcode** from the App Store. Then open a terminal and execute `xcode-select --install` to install Command Line Tools. Then open Xcode, accept the license agreement and wait for it to install any additional components. After you finally see the "Welcome to Xcode" screen, from the top bar choose `Xcode -> Preferences -> Locations -> Command Line Tools` and select an SDK version. Install [Homebrew](https://brew.sh/) and use it to install Qt. (macOS builds must use the bundled libelf) ```shell brew install qt ``` Now build the project the same way as in general compilation ([above](#general-compilation)). ### Download Binary Packages - [https://github.com/cvut/qtrvsim/releases](https://github.com/cvut/qtrvsim/releases) - archives with Windows and generic GNU/Linux binaries - [https://build.opensuse.org/repositories/home:jdupak/qtrvsim](https://build.opensuse.org/repositories/home:jdupak/qtrvsim) - [https://software.opensuse.org/download.html?project=home%3Ajdupak&package=qtrvsim](https://software.opensuse.org/download.html?project=home%3Ajdupak&package=qtrvsim) - Open Build Service binary packages - [https://launchpad.net/~qtrvsimteam/+archive/ubuntu/ppa](https://launchpad.net/~qtrvsimteam/+archive/ubuntu/ppa) - Ubuntu PPA archive ```bash sudo add-apt-repository ppa:qtrvsimteam/ppa sudo apt-get update sudo apt-get install qtrvsim ``` ### Nix package QtRVSim provides a Nix package as a part of the repository. You can build and install it by a command bellow. Updates have to be done manually by checking out the git. NIXPKGS package is in PR phase. ```shell nix-env -if . ``` ### Tests Tests are managed by CTest (part of CMake). To build and run all tests, use this commands: ```bash cmake -DCMAKE_BUILD_TYPE=Release /path/to/QtRVSim make ctest ``` ## Documentation Main documentation is provided in this README and in subdirectories [`docs/user`](docs/user) and [`docs/developer`](docs/developer). The project was developed and extended as theses of Karel KoÄí, Jakub Dupak and Max Hollmann. See section [Resources and Publications](#resources-and-publications) for links and references. ## Accepted Binary Formats The simulator accepts ELF statically linked executables compiled for RISC-V target (`--march=rv64g`). The simulator will automatically select endianness based on the ELF file header. Simulation will execute as XLEN=32 or XLEN=32 according to the ELF file header. - 64-bit RISC-V ISA RV64IM and 32-bit RV32IM ELF executables are supported. - Compressed instructions are not yet supported. You can use compile the code for simulation using specialized RISC-V GCC/Binutils toolchain (`riscv32-elf`) or using unified Clang/LLVM toolchain with [LLD](https://lld.llvm.org/). If you have Clang installed, you don't need any additional tools. Clang can be used on Linux, Windows, macOS and others... ### LLVM toolchain usage ```shell clang --target=riscv32 -march=rv32g -nostdlib -static -fuse-ld=lld test.S -o test llvm-objdump -S test ``` ### GNU toolchain usage ```shell riscv32-elf-as test.S -o test.o riscv32-elf-ld test.o -o test riscv32-elf-objdump -S test ``` or ```shell riscv32-elf-gcc test.S -o test riscv32-elf-objdump -S test ``` ### GNU 64-bit toolchain use for RV32I target Multilib supporting 64-bit embedded toolchain can be used for to build executable ```shell riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -o test test.c crt0local.S -lgcc ``` The global pointer and stack has to be set to setup runtime C code conformant environment. When no other C library is used then next simple `crt0local.S` can be used.
example code ```asm /* minimal replacement of crt0.o which is else provided by C library */ .globl main .globl _start .globl __start .option norelax .text __start: _start: .option push .option norelax la gp, __global_pointer$ .option pop la sp, __stack_end addi a0, zero, 0 addi a1, zero, 0 jal main quit: addi a0, zero, 0 addi a7, zero, 93 /* SYS_exit */ ecall loop: ebreak beq zero, zero, loop .bss __stack_start: .skip 4096 __stack_end: .end _start ```
## Integrated Assembler Basic integrated assembler is included in the simulator. Small subset of [GNU assembler](https://sourceware.org/binutils/docs/as/) directives is recognized as well. Next directives are recognized: `.word`, `.orig`, `.set` /`.equ`, `.ascii` and `.asciz`. Some other directives are simply ignored: `.data`, `.text`, `.globl`, `.end` and `.ent`. This allows to write code which can be compiled by both - integrated and full-featured assembler. Addresses are assigned to labels/symbols which are stored in symbol table. Addition, subtraction, multiplication, divide and bitwise and or are recognized. ## Support to call external make utility The action "Build executable by external make" call "make" program. If the action is invoked, and some source editors selected in main windows tabs then the "make" is started in the corresponding directory. Else directory of last selected editor is chosen. If no editor is open then directory of last loaded ELF executable are used as "make" start path. If even that is not an option then default directory when the emulator has been started is used. ## Advanced functionalities ### Peripherals
Emuated LCD, knobs, buttons, serial port, timer... The simulator implements emulation of two peripherals for now. The first is simple serial port (UART). It support transmission (Tx) and reception (Rx). Receiver status register (`SERP_RX_ST_REG`) implements two bits. Read-only bit 0 (`SERP_RX_ST_REG_READY`) is set to one if there is unread character available in the receiver data register (`SERP_RX_DATA_REG`). The bit 1 (`SERP_RX_ST_REG_IE`) can be written to 1 to enable interrupt request when unread character is available. The transmitter status register (`SERP_TX_ST_REG`) bit 0 (SERP_TX_ST_REG_READY) signals by value 1 that UART is ready and can accept next character to be sent. The bit 1 (`SERP_TX_ST_REG_IE`) enables generation of interrupt. The register `SERP_TX_DATA_REG` is actual Tx buffer. The LSB byte of written word is transmitted to the terminal window. Definition of peripheral base address and registers offsets (`_o`) and individual fields masks (`_m`) follows ``` #define SERIAL_PORT_BASE 0xffffc000 #define SERP_RX_ST_REG_o 0x00 #define SERP_RX_ST_REG_READY_m 0x1 #define SERP_RX_ST_REG_IE_m 0x2 #define SERP_RX_DATA_REG_o 0x04 #define SERP_TX_ST_REG_o 0x08 #define SERP_TX_ST_REG_READY_m 0x1 #define SERP_TX_ST_REG_IE_m 0x2 #define SERP_TX_DATA_REG_o 0x0c ``` The UART registers region is mirrored on the address 0xffff0000 to enable use of programs initially written for [SPIM](http://spimsimulator.sourceforge.net/) or [MARS](http://courses.missouristate.edu/KenVollmar/MARS/) emulators. The another peripheral allows to set three byte values concatenated to single word (read-only `KNOBS_8BIT` register) from user panel set by knobs and display one word in hexadecimal, decimal and binary format (`LED_LINE` register). There are two other words writable which control color of RGB LED 1 and 2 (registers `LED_RGB1` and `LED_RGB2`). ``` #define SPILED_REG_BASE 0xffffc100 #define SPILED_REG_LED_LINE_o 0x004 #define SPILED_REG_LED_RGB1_o 0x010 #define SPILED_REG_LED_RGB2_o 0x014 #define SPILED_REG_LED_KBDWR_DIRECT_o 0x018 #define SPILED_REG_KBDRD_KNOBS_DIRECT_o 0x020 #define SPILED_REG_KNOBS_8BIT_o 0x024 ``` The simple 16-bit per pixel (RGB565) framebuffer and LCD are implemented. The framebuffer is mapped into range starting at `LCD_FB_START` address. The display size is 480 x 320 pixel. Pixel format RGB565 expect red component in bits 11.. 15, green component in bits 5..10 and blue component in bits 0..4. ``` #define LCD_FB_START 0xffe00000 #define LCD_FB_END 0xffe4afff ``` The basic implementation of RISC-V Advanced Core Local Interruptor is implemented with basic support for - Machine-level Timer Device (MTIMER) - Machine-level Software Interrupt Device (MSWI) ``` #define ACLINT_MSWI 0xfffd0000 // core 0 machine SW interrupt request #define ACLINT_MTIMECMP 0xfffd4000 // core 0 compare value #define ACLINT_MTIME 0xfffdbff8 // timer base 10 MHz #define ACLINT_SSWI 0xfffd0000 // core 0 system SW interrupt request ``` More information about ACLINT can be found in [RISC-V Advanced Core Local Interruptor Specification](https://github.com/riscv/riscv-aclint/blob/main/riscv-aclint.adoc).
### Interrupts and Control and Status Registers
Implemented CSR registers and their usage List of interrupt sources: | Irq number | mie / mip Bit | Source | |-----------:|-----------------:|:---------------------------------------------| | 3 | 3 | Machine software interrupt request | | 7 | 7 | Machine timer interrupt | | 16 | 16 | There is received character ready to be read | | 17 | 17 | Serial port ready to accept character to Tx | Following Control Status registers are recognized | Number | Name | Description | |-------:|:-----------|:--------------------------------------------------------------------| | 0x300 | mstatus | Machine status register. | | 0x304 | mie | Machine interrupt-enable register. | | 0x305 | mtvec | Machine trap-handler base address. | | 0x340 | mscratch | Scratch register for machine trap handlers. | | 0x341 | mepc | Machine exception program counter. | | 0x342 | mcause | Machine trap cause. | | 0x343 | mtval | Machine bad address or instruction. | | 0x344 | mip | Machine interrupt pending. | | 0x34A | mtinsr | Machine trap instruction (transformed). | | 0x34B | mtval2 | Machine bad guest physical address. | | 0xB00 | mcycle | Machine cycle counter. | | 0xB02 | minstret | Machine instructions-retired counter. | | 0xF11 | mvendorid | Vendor ID. | | 0xF12 | marchid | Architecture ID. | | 0xF13 | mimpid | Implementation ID. | | 0xF14 | mhardid | Hardware thread ID. | `csrr`, `csrw`, `csrrs` , `csrrs` and `csrrw` are used to copy and exchange value from/to RISC-V control status registers. Sequence to enable serial port receive interrupt: Decide location of interrupt service routine the first. The address of the common trap handler is defined by `mtvec` register and then PC is set to this address when exception or interrupt is accepted. Enable bit 16 in the machine Interrupt-Enable register (`mie`). Ensure that bit 3 (`mstatus.mie` - machine global interrupt-enable) of Machine Status register is set to one. Enable interrupt in the receiver status register (bit 1 of `SERP_RX_ST_REG`). Write character to the terminal. It should be immediately consumed by the serial port receiver if interrupt is enabled in `SERP_RX_ST_REG`. CPU should report interrupt exception and when it propagates to the execution phase `PC` is set to the interrupt routine start address.
### System Calls Support
Syscall table and documentation The emulator includes support for a few Linux kernel system calls. The RV32G ilp32 ABI is used. | Register | use on input | use on output | Calling Convention | |:-----------------------------------|:----------------------|:----------------|:-------------------------------| | zero (x0) | — | - | Hard-wired zero | | ra (x1) | — | (preserved) | Return address | | sp (x2) | — | (callee saved) | Stack pointer | | gp (x3) | — | (preserved) | Global pointer | | tp (x4) | — | (preserved) | Thread pointer | | t0 .. t2 (x5 .. x7) | — | - | Temporaries | | s0/fp (x8) | — | (callee saved) | Saved register/frame pointer | | s1 (x9) | — | (callee saved) | Saved register | | a0 (x10) | 1st syscall argument | return value | Function argument/return value | | a1 (x11) | 2nd syscall argument | - | Function argument/return value | | a2 .. a5 (x12 .. x15) | syscall arguments | - | Function arguments | | a6 (x16) | - | - | Function arguments | | a7 (x17) | syscall number | - | Function arguments | | s2 .. s11 (x18 .. x27) | — | (callee saved) | Saved registers | | t3 .. t6 (x28 .. x31) | — | - | Temporaries | The all system call input arguments are passed in register. Supported syscalls: #### void [exit](http://man7.org/linux/man-pages/man2/exit.2.html)(int status) __NR_exit (93) Stop/end execution of the program. The argument is exit status code, zero means OK, other values informs about error. #### ssize_t [read](http://man7.org/linux/man-pages/man2/read.2.html)(int fd, void *buf, size_t count) __NR_read (63) Read `count` bytes from open file descriptor `fd`. The emulator maps file descriptors 0, 1 and 2 to the internal terminal/console emulator. They can be used without `open` call. If there are no more characters to read from the console, newline is appended. At most the count bytes read are stored to the memory location specified by `buf` argument. Actual number of read bytes is returned. #### ssize_t [write](http://man7.org/linux/man-pages/man2/write.2.html)(int fd, const void *buf, size_t count) __NR_write (64) Write `count` bytes from memory location `buf` to the open file descriptor `fd`. The same about console for file handles 0, 1 and 2 is valid as for `read`. #### int [close](http://man7.org/linux/man-pages/man2/close.2.html)(int fd) __NR_close (57) Close file associated to descriptor `fd` and release descriptor. #### int [openat](http://man7.org/linux/man-pages/man2/open.2.html)(int dirfd, const char *pathname, int flags, mode_t mode) __NR_openat (56) Open file and associate it with the first unused file descriptor number and return that number. If the option `OS Emulation`->`Filesystem root` is not empty then the file path `pathname` received from emulated environment is appended to the path specified by `Filesystem root`. The host filesystem is protected against attempt to traverse to random directory by use of `..` path elements. If the root is not specified then all open files are targetted to the emulated terminal. Only `TARGET_AT_FDCWD` (`dirfd` = -100) mode is supported. #### void * [brk](http://man7.org/linux/man-pages/man2/brk.2.html)(void *addr) __NR_brk (214) Set end of the area used by standard heap after end of the program data/bss. The syscall is emulated by dummy implementation. Whole address space up to 0xffff0000 is backuped by automatically attached RAM. #### int [ftruncate](http://man7.org/linux/man-pages/man2/ftruncate.2.html)(int fd, off_t length) __NR_truncate (46) Set length of the open file specified by `fd` to the new `length`. The `length` argument is 64-bit even on 32-bit system and it is passed as the lower part and the higher part in the second and third argument. #### ssize_t [readv](http://man7.org/linux/man-pages/man2/readv.2.html)(int fd, const struct iovec *iov, int iovcnt) __NR_Linux (65) The variant of `read` system call where data to read are would be stored to locations specified by `iovcnt` pairs of base address, length pairs stored in memory at address pass in `iov`. #### ssize_t [writev](http://man7.org/linux/man-pages/man2/writev.2.html)(int fd, const struct iovec *iov, int iovcnt) __NR_Linux (66) The variant of `write` system call where data to write are defined by `iovcnt` pairs of base address, length pairs stored in memory at address pass in `iov`.
## Limitations of the Implementation - See list of currently supported instructions. ### QtRvSim limitations * Only very minimal support for privileged instruction is implemented for now (mret). * Only machine mode and minimal subset of machine CSRs is implemented. * TLB and virtual memory are not implemented. * No floating point support * Memory access stall (stalling execution because of cache miss would be pretty annoying for users so difference between cache and memory is just in collected statistics) * Only limited support for interrupts and exceptions. When `ecall` instruction is recognized, small subset of the Linux kernel system calls can be emulated or simulator can be configured to continue by trap handler on `mtvec` address. ### List of Currently Supported Instructions - **RV32I**: - **LOAD**: `lw, lh, lb, lwu, lhu, lbu` - **STORE**: `sw, sh, sb, swu, shu, sbu` - **OP**: `add, sub, sll, slt, sltu, xor, srl, sra, or, and` - **MISC-MEM**: `fence, fence.i` - **OP-IMM**: `addi, sll, slti, sltiu, xori, srli, srai, ori, andi, auipc, lui` - **BRANCH**: `beq, bne, btl, bge, bltu, bgtu` - **JUMP**: `jal, jalr` - **SYSTEM**: `ecall, mret, ebreak, csrrw, csrrs, csrrc, csrrwi, csrrsi, csrrci` - **RV64I**: - **LOAD/STORE**: `lwu, ld, sd` - **OP-32**: `addw, subw, sllw, srlw, sraw, or, and` - **OP-IMM-32**: `addiw, sllw, srliw, sraiw` - **Pseudoinstructions** - **BASIC**: `nop` - **LOAD**: `la, li`, - **OP**: `mv, not, neg, negw, sext.b, sext.h, sext.w, zext.b, zext.h, zext.w, seqz, snez, sltz, slgz` - **BRANCH**: `beqz, bnez, blez, bgez, bltz, bgtz, bgt, ble, bgtu, bleu` - **JUMP**: `j, jal, jr, jalr, ret, call, tail` - **Extensions** - **RV32M/RV64M**: `mul, mulh, mulhsu, div, divu, rem, remu` - **RV64M**: `mulw, divw, divuw, remw, remuw` - **RV32A/RV64A**: `lr.w, sc.w, amoswap.w, amoadd.w, amoxor.w, amoand.w, amoor.w, amomin.w, amomax.w, amominu.w, amomaxu.w` - **RV64A**: `lr.d, sc.d, amoswap.d, amoadd.d, amoxor.d, amoand.d, amoor.d, amomin.d, amomax.d, amominu.d, amomaxu.d` - **Zicsr**: `csrrw, csrrs, csrrc, csrrwi, csrrsi, csrrci` For details about RISC-V, refer to the ISA specification: [https://riscv.org/technical/specifications/](https://riscv.org/technical/specifications/). ## Links to Resources and Similar Projects ### Resources and Publications - Computer architectures pages at Czech Technical University in Prague [https://comparch.edu.cvut.cz/](https://comparch.edu.cvut.cz/) - Dupak, J.; Pisa, P.; Stepanovsky, M.; Koci, K. [QtRVSim – RISC-V Simulator for Computer Architectures Classes](https://comparch.edu.cvut.cz/publications/ewC2022-Dupak-Pisa-Stepanovsky-QtRvSim.pdf) In: [embedded world Conference 2022](https://events.weka-fachmedien.de/embedded-world-conference). Haar: WEKA FACHMEDIEN GmbH, 2022. p. 775-778. ISBN 978-3-645-50194-1. ([Slides](https://comparch.edu.cvut.cz/slides/ewc22-qtrvsim.pdf)) Please reference above article, if you use QtRvSim in education or research related materials and publications. - [FEE CTU - B35APO - Computer Architectures](https://cw.fel.cvut.cz/wiki/courses/b35apo) - Undergraduate computer architecture class materials ( Czech) ([English](https://cw.fel.cvut.cz/wiki/courses/b35apo/en/start)) - [FEE CTU - B4M35PAP - Advanced Computer Architectures](https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start) - Graduate computer architecture class materials (Czech/English) - [Graphical RISC-V Architecture Simulator - Memory Model and Project Management](https://dspace.cvut.cz/bitstream/handle/10467/94446/F3-BP-2021-Dupak-Jakub-thesis.pdf) - Jakub Dupak's thesis - Documents 2020-2021 QtMips and QtRvSim development - [Graphical CPU Simulator with Cache Visualization](https://dspace.cvut.cz/bitstream/handle/10467/76764/F3-DP-2018-Koci-Karel-diploma.pdf) - Karel Koci's thesis - Documents initial QtMips development ### Projects - **QtMips** - MIPS predecessor of this simulator [https://github.com/cvut/QtMips/](https://github.com/cvut/QtMips/) - **RARS** - RISC-V Assembler and Runtime Simulator [https://github.com/TheThirdOne/rars](https://github.com/TheThirdOne/rars) ## Copyright - Copyright (c) 2017-2019 Karel Koci - Copyright (c) 2019-2024 Pavel Pisa - Copyright (c) 2020-2024 Jakub Dupak - Copyright (c) 2020-2021 Max Hollmann ## License This project is licensed under `GPL-3.0-or-later`. The full text of the license is in the [LICENSE](LICENSE) file. The license applies to all files except for directories named `external` and files in them. Files in external directories have a separate license compatible with the projects license. > This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. > > This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. > > You should have received a copy of the GNU General Public License along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/). ![Faculty of Electrical Engineering](./data/ctu/logo-fee.svg) ![Faculty of Information Technology](./data/ctu/logo-fit.svg) ![Czech Technical University](./data/ctu/logo-ctu.svg) qtrvsim-0.9.8/cmake/000077500000000000000000000000001467752164200143335ustar00rootroot00000000000000qtrvsim-0.9.8/cmake/AddFileHashes.cmake000066400000000000000000000012261467752164200177620ustar00rootroot00000000000000# Add file hashes to placeholder location in a template file. # Used for packaging. # # Example: # cmake -DTEMPLATE=PKGBUILD.in -DOUTPUT=PKGBUILD -DFILE=qtrvsim_0.8.0.tar.xz -P AddFileHashes.cmake # # See extras/packaging/arch/PKGBUILD.in for template examples. # Note that most files are configured (injected with information) twice: # First, during configure phase, package information is added and FILE_* # placeholders are left intact. Second, after source packing, FILE_* # placeholders are resolved. file(MD5 ${FILE} FILE_MD5) file(SHA1 ${FILE} FILE_SHA1) file(SHA256 ${FILE} FILE_SHA256) file(SIZE ${FILE} FILE_SIZE) configure_file(${TEMPLATE} ${OUTPUT})qtrvsim-0.9.8/cmake/BuildType.cmake000066400000000000000000000014031467752164200172340ustar00rootroot00000000000000# Source (BSD-3) https://github.com/openchemistry/tomviz/blob/master/cmake/BuildType.cmake # Set a default build type if none was specified set(default_build_type "Release") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() # Set variable to detect given build type if(CMAKE_BUILD_TYPE) string(TOUPPER "${CMAKE_BUILD_TYPE}" _upper_build_type) set(BUILD_${_upper_build_type} 1) endif()qtrvsim-0.9.8/cmake/BundleMacOS.cmake000066400000000000000000000000711467752164200174270ustar00rootroot00000000000000find_program(MACDEPLOYQT NAMES macdeployqt) qtrvsim-0.9.8/cmake/CopyrightTools.cmake000066400000000000000000000011521467752164200203250ustar00rootroot00000000000000function(copyright_to_html OUTPUT INPUT) string(REPLACE ";" "
" TMP1 "${INPUT}") string(REGEX REPLACE "<([^<>]+@[^<>]+)>" "\\1" TMP2 ${TMP1}) set(${OUTPUT} ${TMP2} PARENT_SCOPE) endfunction() function(copyright_to_comment OUTPUT INPUT) string(REGEX REPLACE "([^;]+)" "# \\1" ${OUTPUT} "${INPUT}") string(REPLACE ";" "\n" ${OUTPUT} "${${OUTPUT}}") set(${OUTPUT} ${${OUTPUT}} PARENT_SCOPE) endfunction() macro(copyright) set(COPYRIGHT_LIST "${ARGN}") copyright_to_html(COPYRIGHT_HTML "${COPYRIGHT_LIST}") copyright_to_comment(COPYRIGHT_HASH_COMMENT "${COPYRIGHT_LIST}") endmacro() qtrvsim-0.9.8/cmake/FindElfUtils.cmake000066400000000000000000000041021467752164200176620ustar00rootroot00000000000000# Source (GPLv2): https://github.com/SimonKagstrom/kcov/blob/master/cmake/FindElfutils.cmake # - Try to find libdwarf # Once done this will define # # LIBDWARF_FOUND - system has libdwarf # LIBDWARF_INCLUDE_DIRS - the libdwarf include directory # LIBDWARF_LIBRARIES - Link these to use libdwarf # LIBDWARF_DEFINITIONS - Compiler switches required for using libdwarf # # Locate libelf library at first if (NOT LIBELF_FOUND) find_package(LibElf) endif (NOT LIBELF_FOUND) if (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS) set(LibDwarf_FIND_QUIETLY ON) endif (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS) find_package(PkgConfig QUIET) if (PKG_CONFIG_FOUND) set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON) pkg_check_modules(PC_LIBDW QUIET libdw) endif () find_path(DWARF_INCLUDE_DIR NAMES dwarf.h HINTS ${PC_LIBDW_INCLUDE_DIRS} PATHS /usr/include /usr/local/include /opt/local/include /sw/include ENV CPATH) # PATH and INCLUDE will also work find_path(LIBDW_INCLUDE_DIR NAMES elfutils/libdw.h HINTS ${PC_LIBDW_INCLUDE_DIRS} PATHS /usr/include /usr/local/include /opt/local/include /sw/include ENV CPATH) if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR) set(LIBDWARF_INCLUDE_DIRS ${DWARF_INCLUDE_DIR} ${LIBDW_INCLUDE_DIR}) endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR) find_library(LIBDW_LIBRARY NAMES dw HINTS ${PC_LIBDW_LIBRARY_DIRS} PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ENV LIBRARY_PATH # PATH and LIB will also work ENV LD_LIBRARY_PATH) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBDWARF_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(ElfUtils DEFAULT_MSG LIBDW_LIBRARY LIBDW_INCLUDE_DIR) mark_as_advanced(LIBDW_INCLUDE_DIR LIBDW_LIBRARY) set(LIBDW_LIBRARIES ${LIBDW_LIBRARY}) set(LIBDW_INCLUDE_DIRS ${LIBDW_INCLUDE_DIR})qtrvsim-0.9.8/cmake/FindLibElf.cmake000066400000000000000000000034761467752164200173050ustar00rootroot00000000000000# Source (GPLv2): https://github.com/SimonKagstrom/kcov/blob/master/cmake/FindLibElf.cmake # - Try to find libelf # Once done this will define # # LIBELF_FOUND - system has libelf # LIBELF_INCLUDE_DIRS - the libelf include directory # LIBELF_LIBRARIES - Link these to use libelf # LIBELF_DEFINITIONS - Compiler switches required for using libelf # # Copyright (c) 2008 Bernhard Walle # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # if (LIBELF_LIBRARIES AND LIBELF_INCLUDE_DIRS) set(LibElf_FIND_QUIETLY ON) endif (LIBELF_LIBRARIES AND LIBELF_INCLUDE_DIRS) find_package(PkgConfig QUIET) if (PKG_CONFIG_FOUND) set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON) pkg_check_modules(PC_LIBELF QUIET libelf) endif () find_path(LIBELF_INCLUDE_DIR NAMES libelf.h HINTS ${PC_LIBELF_INCLUDE_DIRS} PATHS /usr/include /usr/include/libelf /usr/local/include /usr/local/include/libelf /opt/local/include /opt/local/include/libelf /sw/include /sw/include/libelf ENV CPATH) find_library(LIBELF_LIBRARY NAMES elf HINTS ${PC_LIBELF_LIBRARY_DIRS} PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBELF_FOUND to TRUE if all listed variables are TRUE find_package_handle_standard_args(LibElf DEFAULT_MSG LIBELF_LIBRARY LIBELF_INCLUDE_DIR) mark_as_advanced(LIBELF_INCLUDE_DIR LIBELF_LIBRARY) set(LIBELF_LIBRARIES ${LIBELF_LIBRARY}) set(LIBELF_INCLUDE_DIRS ${LIBELF_INCLUDE_DIR})qtrvsim-0.9.8/cmake/GPL-3.0-or-later.cmake000066400000000000000000000026461467752164200200100ustar00rootroot00000000000000# Licence related data to be included in project files set(LICENCE_IDENTIFIER "GPL-3.0-or-later") set(LICENCE_SHORT "\ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .") set(LICENCE_SHORT_HTML "\

This program is free software: you can redistribute it and/or modify it under the terms of the \ GNU General Public License as published by the Free Software Foundation, either version 3 of the \ License, or (at your option) any later version.

\

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; \ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \ GNU General Public License for more details.

\

You should have received a copy of the GNU General Public License along with this program. \ If not, see https://www.gnu.org/licenses/.

")qtrvsim-0.9.8/cmake/PackageTools.cmake000066400000000000000000000103401467752164200177070ustar00rootroot00000000000000# Support code for package handling. # Mainly intended to generate inputs for Open Build Service. # Keep file properties placeholder in configure phase, they are replaced in build phase set(FILE_NAME "\@FILE_NAME\@") set(FILE_SIZE "\@FILE_SIZE\@") set(FILE_MD5 "\@FILE_MD5\@") set(FILE_SHA1 "\@FILE_SHA1\@") set(FILE_SHA256 "\@FILE_SHA256\@") set(FILE2_NAME "\@FILE2_NAME\@") set(FILE2_SIZE "\@FILE2_SIZE\@") set(FILE2_MD5 "\@FILE2_MD5\@") set(FILE2_SHA1 "\@FILE2_SHA1\@") set(FILE2_SHA256 "\@FILE2_SHA256\@") # Source file tar generation. # Make sure that destination path exists as it wont be created automatically. file(MAKE_DIRECTORY ${PACKAGE_OUTPUT_PATH}) find_program(BASH bash REQUIRED) find_program(GIT git REQUIRED) find_program(XZ xz REQUIRED) find_program(TAR tar REQUIRED) # Command to build source archive from git HEAD. add_custom_command(OUTPUT ${PACKAGE_SOURCE_ARCHIVE_FILE} COMMAND ${BASH} ${CMAKE_SOURCE_DIR}/extras/packaging/_tools/git-archive-submodules.sh ${CMAKE_SOURCE_DIR} ${PACKAGE_OUTPUT_PATH} ${PACKAGE_SOURCE_ARCHIVE_FILE} ${PACKAGE_NAME} ${PACKAGE_VERSION} ${GIT} ${TAR} ${XZ} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") add_custom_target(source_archive DEPENDS ${PACKAGE_SOURCE_ARCHIVE_FILE}) # Procedure adding support for individual OS distributions. # # @param target_name name of created target for simple reference (recommended: OS name) # @param config_file_name name of resulting config file # @param template path to cmake template file (relative from source dir) # # NOTE: ${PACKAGE_SOURCE_ARCHIVE_FILE} is assumed to exist in scope and be unique for project # macro(package_config_file target_name config_file_name template) # The @ONLY option disable replacement of ${} which may be used by shell as well. configure_file(${template} ${config_file_name}.in @ONLY) add_custom_command(OUTPUT ${config_file_name} COMMAND ${CMAKE_COMMAND} -DFILE="${PACKAGE_SOURCE_ARCHIVE_PATH}" -DTEMPLATE="${CMAKE_BINARY_DIR}/${config_file_name}.in" -DOUTPUT=${PACKAGE_OUTPUT_PATH}/${config_file_name} -P "${CMAKE_SOURCE_DIR}/cmake/AddFileHashes.cmake" DEPENDS source_archive) add_custom_target(${target_name} DEPENDS ${config_file_name}) endmacro() macro(package_debian_quilt target_name config_file_name template debian_dir output_archive) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/debian) # The @ONLY option disable replacement of ${} which may be used by shell as well. configure_file(${debian_dir}/control.in ${CMAKE_BINARY_DIR}/debian/control @ONLY) file(COPY ${CMAKE_BINARY_DIR}/debian/control DESTINATION ${CMAKE_BINARY_DIR}/debian FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) file(COPY ${debian_dir}/compat DESTINATION ${CMAKE_BINARY_DIR}/debian FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) file(COPY ${debian_dir}/rules DESTINATION ${CMAKE_BINARY_DIR}/debian FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE GROUP_EXECUTE) file(COPY ${debian_dir}/docs DESTINATION ${CMAKE_BINARY_DIR}/debian FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) file(COPY ${debian_dir}/changelog DESTINATION ${CMAKE_BINARY_DIR}/debian FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) file(COPY ${debian_dir}/source/format DESTINATION ${CMAKE_BINARY_DIR}/debian/source FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) file(ARCHIVE_CREATE OUTPUT ${PACKAGE_OUTPUT_PATH}/${output_archive} PATHS ${CMAKE_BINARY_DIR}/debian FORMAT gnutar COMPRESSION XZ) set(DEBIAN_ARCHIVE_FILE ${output_archive}) file(MD5 ${PACKAGE_OUTPUT_PATH}/${output_archive} DEBIAN_MD5) file(SHA1 ${PACKAGE_OUTPUT_PATH}/${output_archive} DEBIAN_SHA1) file(SHA256 ${PACKAGE_OUTPUT_PATH}/${output_archive} DEBIAN_SHA256) file(SIZE ${PACKAGE_OUTPUT_PATH}/${output_archive} DEBIAN_SIZE) configure_file(${template} ${config_file_name}.in @ONLY) add_custom_command(OUTPUT ${config_file_name} COMMAND ${CMAKE_COMMAND} -DFILE="${PACKAGE_SOURCE_ARCHIVE_PATH}" -DTEMPLATE="${CMAKE_BINARY_DIR}/${config_file_name}.in" -DOUTPUT=${PACKAGE_OUTPUT_PATH}/${config_file_name} -P "${CMAKE_SOURCE_DIR}/cmake/AddFileHashes.cmake" DEPENDS source_archive) add_custom_target(${target_name} DEPENDS ${config_file_name}) message(STATUS "Debian archive created") endmacro()qtrvsim-0.9.8/cmake/TestingTools.cmake000066400000000000000000000025071467752164200177770ustar00rootroot00000000000000# Helper functions for integration testing # Creates a new CLI test. The test consists of two parts: the first runs the command and checks nonzero return value, # the second compares the stdout with provided files. Currently there diff is not displayed as cmake does not provide a # portable way to do that. # # TODO: show diff whenever available. # # NOTE: # If CLI was build in debug mode (which is recommended) the test will run with sanitizers and any memory errors # including memory leaks will fail the test. # # Usage: # add_cli_test( # NAME # ARGS # --asm "${CMAKE_SOURCE_DIR}/tests/cli//program.S" # # EXPECTED_OUTPUT "tests/cli//stdout.txt" # ) function(add_cli_test) cmake_parse_arguments( CLI_TEST "" "NAME;EXPECTED_OUTPUT" "ARGS" ${ARGN} ) add_custom_target( cli_test_${CLI_TEST_NAME} COMMAND ${CMAKE_COMMAND} -E make_directory "Testing" COMMAND cli ${CLI_TEST_ARGS} > "Testing/stall_test.out" COMMAND ${CMAKE_COMMAND} -E compare_files "Testing/stall_test.out" "${CMAKE_SOURCE_DIR}/${CLI_TEST_EXPECTED_OUTPUT}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" DEPENDS cli ) add_test( NAME "cli_${CLI_TEST_NAME}" COMMAND ${CMAKE_COMMAND} --build . --target "cli_test_${CLI_TEST_NAME}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") endfunction() qtrvsim-0.9.8/data/000077500000000000000000000000001467752164200141645ustar00rootroot00000000000000qtrvsim-0.9.8/data/ctu/000077500000000000000000000000001467752164200147575ustar00rootroot00000000000000qtrvsim-0.9.8/data/ctu/logo-ctu.svg000066400000000000000000000437211467752164200172400ustar00rootroot00000000000000 qtrvsim-0.9.8/data/ctu/logo-fee.svg000066400000000000000000000436401467752164200172040ustar00rootroot00000000000000 qtrvsim-0.9.8/data/ctu/logo-fit.svg000066400000000000000000000445251467752164200172320ustar00rootroot00000000000000 qtrvsim-0.9.8/data/cz.cvut.edu.comparch.qtrvsim.metainfo.xml.in000066400000000000000000000055111467752164200245650ustar00rootroot00000000000000 @MAIN_PROJECT_APPID@ @GENERIC_NAME@ Czech Technical University in Prague RISC-V CPU simulator for education purposes CC0-1.0 GPL-3.0-or-later @MAIN_PROJECT_NAME_LOWER@.desktop

RISC-V processor architecture simulator for education purposes with pipeline and cache visualization.

Current project release.

GUI fix crash when no tab is selected, use bundled LibElf on macOS as Homebrew misses RISC-V

RISC-V A extension, ACLINT MTIMER, IRQ support, L2 cache, GUI editor tabs

More CSR updates, fix branch range, CLI OS emulation, coreview diagrams updates, RV64IM in CI

Support for 64-bit RV64IM target and official tests in CI

Corrected peripherals, LCD endianness and memory stalls.

Initial Flatpak release.

https://raw.githubusercontent.com/cvut/qtrvsim/master/data/screenshots/0.png https://raw.githubusercontent.com/cvut/qtrvsim/master/data/screenshots/1.png https://github.com/cvut/qtrvsim https://github.com/cvut/qtrvsim/issues 768 keyboard pointing ModernToolkit david_AT_ixit.cz workstation
qtrvsim-0.9.8/data/gui.desktop.in000066400000000000000000000003741467752164200167540ustar00rootroot00000000000000[Desktop Entry] Name=@PROJECT_NAME@ GenericName=@GENERIC_NAME@ Exec=@MAIN_PROJECT_NAME_LOWER@_gui Icon=@MAIN_PROJECT_NAME_LOWER@_gui Type=Application Comment=@GENERIC_NAME@ Terminal=false Categories=System;Emulator; Keywords=emulator;RISC-V;education; qtrvsim-0.9.8/data/icons/000077500000000000000000000000001467752164200152775ustar00rootroot00000000000000qtrvsim-0.9.8/data/icons/48x48/000077500000000000000000000000001467752164200160765ustar00rootroot00000000000000qtrvsim-0.9.8/data/icons/48x48/gui.png000066400000000000000000000101071467752164200173670ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEå%4hütIDAThÞÕ™ip\Õ•Ç÷¾Þµ´ÕÚ÷ÅòŠ…w[^XŒ±l!©LÂL† ¦¨$Ã’)2|€@†"“Lj`&UP0©šJ%ìC ÁƲÁûnKÆÈ–eí[KÝ­µ÷÷î|x-aÙ-KNœ©š[Õõªß=ïžó¿çܳ]¡”Rü?–™ ôtrt×v¢á0ˆkÄYÍá`ņZ²ò‹þ²Žîú„7_~ĵ’þkJ)jÿúákÀÛ}”žŽƒHMÒ~~?‰”òÚÊo(Z?áȽ†¢dv ùÅkþ|Þîcœ<ø2½‘RÒÛ¥#ĵ!ð6Ðxê4J¿ÿ BòŠªg¼DR©z:$„· „üË?A ¥)- ôœÄß檾—S-*®µ½ÏœJ¤« ”âÿÌ»^Âæj÷-)€¼âjòŠVcq”2Pʸ¢‘ø'QJC!.›K:Ä×ë”Vn&¿dýUHzˆs V°¤úQz;!¥$ØOKýÞ„ŠÇù(ÝÍp¬¡hcñ,¢F †ÒÐD ‡6Dªµ·­ƒ4K/VJKH­…e7³zÃ&”a¿ŒYžÊ í!>«ó²é–lJŠ]3S°‚œ‚\¨£Ôž[†bEt-§/´ˆ±x61Æ¡$J‘ª€”ql2ˆÛÖEë8ùÎS8´!SS(²rª¨\xORþðQOÿì+þù™ü葊«\Û#Ö‘õ´®c,ž‰¡VÍ ']'wV+„Uï&¤rðôf0N¥78Ÿp%¶ÕT¦ÿy®:†ÒÊÐ9Éy„B:†¡†ô«3!€®Öݦ iÝíG†c…|øÞðBtC’ncme?·-aYyüY:NéG î@O¯aÄ{ˆ–h {†ÙÞ´ŽÓ]nŒĿKyôs*Ó>¥óÂgìû¬ÃÐ)]CI忝7,E^á`'ÐÙ²›S‡þ Ÿ÷4Bú{t†beœ |‡@¤)7Ìnå‡ÕÛ¸¡¢ §Ã0-+(¬p(RÒ‡ÈËègMÖNî¯Éä½强ÓC[¿“¦áMDôTʽÛh9Û„aÀ ï†’¤eÞŒaŒŒÆFFãxû#H)ðdX‘!J  ¯ë >ï—HiEJÅX<›zÿVÑRìï­ï≚sd§‚‘$“vv”!ÀPä¤zydC”Õ¥žy·„ýri]ˉÎ8×}ŒÅg8pŽ·ÞÚ˶:'‘HœÁ¡‹äwouòÇOú°Û$O?5ÚšÜiLHH"¶s¤õ6ü‘ lVƒlð7íÆ9 þ$^XÅAh±  , ¬àÛBcYºâßïÌàñïgws%G×RRäeí’!‰ë‚PØ Õ‰ÇÍ +Âó<Äb“Gr  œh\ÂéæëAܳ¢'6uà°æ€ãÓHÅ%Ë1|jš’Š›¿ŒMæ31Êf)^¸·ƒÿ3“/»3¨;t3EÈËê¡vS÷?´šxLçÕ7ZùõkøÎÖ"þ~MŸç˜@qÅFüý 4md߉µD¢6ªò»øqõ¸FÀÐP@w Èp0Š@.§›Ü²ìÒ’ØyÍ#,¦6&®`SçÇë›ù‡mߥϗÃÁú•üðÁ³çoÁí±àñXQÊ|–—^EÈ)XβµrâìI:ûr±Ytþnc”²·‚n€>‚¡ÇøÙ›uü÷Á¤iæ¸ìC¬ž·ƒ'o ±|™žØùd.Pæ¢v`Ùól;}_µ¬ÁS°÷El<›¹RV3¥ug®àl›•H´“ª’[–FÀ’jÞ]'08@ÿ(Tä¸(ÎJ¥¥×ÏÛû[ié’¼ïþ˜¢Lûe¹Ž9 H[ÓUÊÖEŸ³óÜl¼> gÓ©ZÌU)ôö…9Õ@ÉÚÊ ´ý_”°ëdlA8ö_ñPíZžøÆ"êOþžo¿6ÈÑö(û—r÷‚E`L‘ÉP£¬,n¦Ì3Èéîòñí{ ¯è÷/[fª‰ÆÆVzûưYay©‚G@bz ,î„mƒÃ*°9âTZ(Ît¢”b8jiM°HòSQ0 ²Ó",,C!8×4Êèh|z©§ÓÀ@ïaŽØG8<‡»AiV,!ø8…}¢}œkÚËç»qèBˆã-:ž´:¡÷·¦WºŒhà©A³@YN)]]^Z›ë¹~ɲ?@oÇAZ/œÄPó±[uÒœÆå¶¬Œ ×øÚ!ÞØ"ªƒ;ÅÁOîÙÀª¹àÓ!£¬žD> Àâðo7×2Rt4 ££!ü¾n`榬È&9x¥H‡K)Ø´l·­œÀŠÊî¿y6<Ëó:X=„•›t±çd#JºÀâIºw‚«¯“j@)…ÝB ƒHL0Mƒ¼U ¥€ºŒ¾vå|noáÀ™óœ8߯ÉoñÊö!"ÊÁ§Ëçû¼<ðÒ»üàf+7,ž?ÎeâûÀ˜†a¬Ö(-vU’j ·¨šyó`µDFí>+8ÊÁBÜ‘oO„úè ËŠ©YZL瓦6­XÌ™®ýøêñØ5 ä%‘[¡Ç­^†¡((È¢´üº‹§ÍÇ º¤²óWqÓÆ{ÈɶKŽé¾w ÿðïaEIº2hŒœ„¡¸wñVMðÞFŠl_bavìýˆÇNp]ñ,ªŠ\Lª.ô88ÓTUQXBQ'ïœÞÀXÄFi±“uÕ“d˜]‘ÂK¿¬âÆu™ìÙçã±'h:?YW¨ÈêH×öQRPFSk6¿9VÃÆU%”åDM-"@ø·cúuJ!„1±‹U]AdäžÜ•T•åÃÈEnL|\ŸÏ®æ9H©XXq¢! v’•)¼ô‹*{²=ûxü'§yùÅ**ÊR¦Ö@gË.N|…Žÿ¢zÑNì¶gzfñâŽùc©néK %LB˜^*m•9§¥Ùþév7×.Áå°1q*¥â«ž~µ½ˆÑ…¼ÌW~DÑ—i?ÿéeòTÎNá¥_.â†uYì;à£n÷À•M¨¯ë0>ï—aeÉ‚“,š]JðÎ!7¿ú0•°ï¨±„@º˜býfªáœcVd$¦ ÌTu‚£¢µOíøÎôfát„ÙX]G^V?f¾³I-bÎìT^~±Š}a›nɞƄÄx=N{„•eÓÖ’?ZÁì,gtènž¸+…œYa3òï0[)*nV_5\fð †Ç›]<óA%û›]!HqŽQœÛ…jÚ>lEY ßK™ô.9õE¦” ÕêåzÏÛxìmDt¯¾‰ï¿>ŸOêó ¥~2o…¬;À³åë* e -â ðJ~½#¼>Ÿ}gSÐD§eÀPïïü&½yHyõíLíÙgŸ}öÒ—‹ƒÑáNF‡:@}аÏÇq°îa,žMÛ€ÏÒ9Þ¬š±h,ŽTè<º½œÈhþø<.„yó@&?ß¾˜wN-Ç?æÄn R™^Ç|÷vB*—¶þ9t{s¹ñ†¹¬Z÷-lÏŒˆ©îȼÝÇè«Gjû>ÚÍžw¡IAÄH¥mt=­#5¶d OjŒssÒ°[L .›Æ¢7§»†hNÐ/*tã²™½U”AÉìÖo¾Ã0ÈÈœKzFÅ8.îÛj¶îŸ{¡¯7B~žƒeKfM ;)ÙùKh9BP‡RŠâ ™)6tC¡IËf™86MP™:éŒ\‰ ¯h %³7'•aDi±“§†XºØÍÚêÉiÆŒ"q_g+{ÿø.‘`pr‹+—‹™$£W`w¹XûÝä•Í`•äã'ø‘›3*úM%tEXtdate:create2021-05-17T15:37:52+00:00{Œî%tEXtdate:modify2021-05-17T15:37:52+00:00 ]4RtEXtSoftwarewww.inkscape.org›î<IEND®B`‚qtrvsim-0.9.8/data/icons/gui.src.svg000066400000000000000000000422671467752164200174050ustar00rootroot00000000000000 image/svg+xml qtrvsim-0.9.8/data/icons/gui.svg000066400000000000000000000145471467752164200166170ustar00rootroot00000000000000 image/svg+xml qtrvsim-0.9.8/data/icons/macos/000077500000000000000000000000001467752164200164015ustar00rootroot00000000000000qtrvsim-0.9.8/data/icons/macos/gui.icns000066400000000000000000005171421467752164200200550ustar00rootroot00000000000000icnsžbic10žZ jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cÿOÿQ2ÿd#Creator: JasPer Version 1.900.1ÿR ÿ\@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ ÿ“߇s $_*JRåúhyÿxÜ|µû'3F¬ÕÒ“ƒ­¶â.J×¹ ¿ÆY €‚!q ³FS„i¸±^âÀ\M’„d®^ž³´hç_GDÞ¨Ý$²ÔµáX_ŽÇÈpÊ‘ç[§4&L÷®yc†çë³Ó=)†ïcAãE‡w`ÍË(š³Æ-ìVÖx£Ì+áÙÁæô³BP ÒПDH4»ì‹¾·éyxGz 296²;ï{Ã1`cw N¢n4æ=·;V<þ˜ˆ§&ò]ÞGÄ…Ø6±Q#jŠ5‹pbÏøa*%LÌÁëLÝÑñï^„¦ˆÔDl¥èl;HH°î@y1Î ¡¨¼æI¼‰pÕã3äg1jIæ2ÄÖ£Åx•÷8`6Á²™ø—¡&a3ÿ·PEóV+@`¿kþ-&¶3A ­EÁž…ŸÍD®HêÑ… Ú«’Ï9uÍÎ]Õ$å#ÊQ¢$¹SÄIoÅž_«Jn˜æñõá£Â| ÕünÄE¾ ä,öSω\n~µ [)(k’€à2/’º]\F}øQÀ@ÈÔE2|ÿ`3䋺@$ ¿\Ø™Mèý×m’àÄAÍ/­§ÎjfŒ}~¡Rƒá}_A+éñãôr È*?NÂø¹6@by©îÍdÑçg4ôÿAI‡¢ µáš~ÝF`%͈À.!| ¨›û²)œ0ÀVô«wö©wž8_Š" 6ᦩ-m+ÝT¼,–düóІeþrÁŒz¸bjꆟ„?ãÄŸ¨pÈFƒ…ÉoÝ•¯$jïƒ×¦ñ¶ÌCVo—é­ô-j‹qŽtNÞjR8(Õ ÒÂÚr ¾¡kåú]ºX02 93ßô<7%)…¾ÕEàOâÙ-&†æ>1¨ >.VüÅšHÚ˜Pj¦’mù:ÃpÊ`>ºàÅ¥ÏpÔ ”fÏŸÒ¥%ª•ä6,/Åo*dÎ:hq(EC ²Œ­0¹ñ$+ŸY$ÍsáÎ?ÈbÝ~Ôºúò²´ë@4#xá“7kCCý7H†‘ÁgäJQ Û@ ÊŠÀÎ:M/õä§ã}»èÜ¿ŽÌE#§—<×$þÙDäty^0rô–“k©"RX)KÄür‰ÞǤ÷Ú(ÝÿC¦°‡šm=ä)Þ“¼¶LP§·?O„Åò*² àhz@°È1 JË2¯Ö˜”‡Pæ/]Ù›ŒP:e Äûšw±ßzÖe¥`Î]ô–’RãŒÃÆílÊøó‘»GœSÞIËN‰½Ôîæàµ¢ÊŠïÙbŸÅw¹iÎPF»×ï̓î­è³Èã–a/‰ñ!72žG(ñ“ìÒüî˜ø7[ç9ÎsÇȸp¬rdý°ÝMôX.,xâÁ óoEtv –d7aBŽß×ô)Y¨&Ï·øðØ-ùèoÁÏZg¾×À¿Ç5Šüö6•>Ø´7Þ¶FÀI1SU”Ñ}Ñ'æ¾K>Vÿ¹²Çò×á¡N÷ƒŽ=Z!¹ôŠE½¾&]€Ä¹ ìRŒà8+"Uê¶LËiî+wå…+ O¡ñdR2é þAV›ùDÿTõ¹}¥ É×i«ï¡óFi Í0½µøÕ£v w×ìAØÎc’Ý Û,® ­Î)’©‘•LHâ>`¤D"o—ì(ðÓ°¨#¨±H±YS®o|Ðÿa|E†r:×S‚•¹7z¶ÕÛ⟰¸¼¹±…Ù“$ÅSdJÈ¢«£Û½2»D›|\´Ü锟a^½Õ~æ®bûÃû?~¢œ{cqI.é¯ýAº§ˆ£^‰<þÇ'2ò% ¡%”¦ÑY~ç^×߇pà$_)|ÓöT´þ¨¸(p:E¨î¦‘Gh·|3ý)@¦&6}¬ªÂOëÈŸ$À!K+S>ŒVÜg%¦^ë³ÐI¨´?úšŒËg$ÌéÎÆÔ8âýÅ›øöwKƒ– $°Q²öKÆ÷CœíÚRí2íŸâ0v÷ŒŽ1å›—‚ Â×~ƒØtvã øÊ3&€tL%ªJEo»âíîþ(;¹”æÄðcAk÷T)éñšvˆ"ñÃ… C”@Uïg-ƒîÅ+™ˆð®__ý´ ù7} 0€®k{·C¯ß©ë^Pý8FMÕ ?$PуNè…„¿x^Ó²ËÞ{eˆ2ù€ß×éÛ$)Ð31k\Ð?yfÚ„ÖƒW‹:tš‘8¢€IPù¸j{K½U£Å@/óç4rHÜ4b›\Ï)¤ cÈ?¡ùŽº™ÈŽFJè—ýnJÿ_2¿o¿x5y9ÐÄ_~×yG3;LR’ÝS`1Úác“ùÀù†Û`í’•½ ä)'ßd\v—\Ø4ª`*ë×?|2´Ó§ …ª­ ”û³ºM¶ÛQÑ M:Äœ£;:4¬¦SÇ •û„À¤²¡,HÜzo³šÖÑk\,¶n9ò‚*JËXXõD7ù˜_"eÕ|5wù¥`z u<Í…ÕØ³BFÇ™ jÍóË& ôµ«ªÚ"Qå í…èÿI&ɾ/*&–ÆtRª5×PêŠlô†eì•dŠ7äó-í RÙ¸‹Mc{ݽ“™=¶aQ_H¡ãË ý{_ë°¨ÊÇr_ÒÑù6ïꋹégša3O€ì 24ô„ë:©~aØâ§uV£â¼„,Hº¡u³ ¶ÛzüÔp…‚SrË2H±Ö¡½n6ý. \¶½šä<\ôÔ¹ó¼qæRÑ‚¦ôJR€^xJ¿k­ÁOZ))Åi .òMUD"Î{½)*6ZF¹MÅö?:sXÝöùÜæímúG­k$ý£³¹Fœ  øÅóæJ€N!“'+·¡í%îHzÚv¢}…]‚8 øÊa$AäÛGJM†¼ø‡Žkm©†y+7Âе§‘hLE.%(0PÉóIÛ(Ò›Ý p_>;s ¨BÝazÿ6ô+™Æ RDî`Òt¾µZÌÔnl+Ï´ \¯ÿìçߟS³ðéÊ?”ÀÐYÐ|ö·^@%Ù;Lô…‹¼oKçØqÖe%½ÇþzÍ® ¯7™ËÅ'DÌó}Ÿ=“Œî”'*‰ŠjGm(*d˜W7U·Æ\ñÉËUCëô‘,8©é¿¾ —Žúx‰¬- ›¢¹ïÇ®u8—!ÊxR| Gç>M`Î<¹Õ­¹.ø° KG” »A‚؉ë[!V ƒ½Âχ· Æ<ŽÈ˜[pûã»YŽ¤Ð¦H¨„ˆîê]À ˜f-©¢6Ä•‰ë8¶]Ümê¹ç”LßüaŒ¤´…šø“K|¾É3TZ‘dt\‰3)êÿNG±‘Ù<³“;<Åêž6GŽ])¾£Ç²nÝ „*E‡0ùÿ-‡Ü“ Ýk¸£RŒm!ìµ'ÿi|ë>› Lÿ/UÍß½Øýý¼úOÈö´÷åV@¿¸O¾ìòÝ^ÓSº =Î>åð»¬7óh]RÖÚ J<6°¦#G\ˆ˜nî‘Î0ïDgc½Þç’Ù§?e^׆]1èYsZhPOÉTöª‚8èÙ¿Žýí® \è#ª‹ªDr IµB}L¥÷˜-ïÚ\0‹ÍâÇ”c¿òõS“¡Ý¾âž¬ÿC;â)PǤ¢x4£C¢md£‹ÛËÒ¬RôTtöW·­y’Ø&å®Úí7¥’TˆJÆg2zDؽ€º“—K}m’3åó+73Ž;:Ë*›†æ³ÇH?ítA÷KÓ†öe¡Ã÷ÖþTjAîÚÁþ¨Fu¼sDÿ0FôÑûVÔ§<¼šlú;÷Ëal/¦ÎúäÎ-Aíƒß»¢ƒüÿ`Û?÷{ÂL‰2¬ +s±M1¹™™YåZˆ9õ§Ój¹$â%4ÄŽnsøi˜ÿ›t({ÄçXE¥þ7×ùŸZCE¤¯ ûdõ¢¹u‹ Ð¡·&û³”J±/ûN‘D÷d°Ô* +㣩bÎàÓ×L¨‘ZÖáIBb«ÿ 4ä½9Cw¯Á*)Y޲;žÕ4˜††µ5p"¼Pˆ³”fªøDQóÊS*Ø3Îz®r:sAEÿ"& ÌÛmhw’açŽhçuSÖ¯ —„\Ú0ÐJ ºy;©JüsF]Õ*êQƒœd3á•?s·ëª¸ Ò¥aÏx]åhµ‰â•<ÒzDa´Ê0Ç} s¥.k—8ý7ßgزÝܾêz8wMPÀš‚rYdi®úÌÖL0ž„¿‚—îNôd˜#y‘U`Z|%wù–WWKêõÇ œeÒíŽ!:³Ý¹Lþ«Ÿÿ|¦_ýãÎÛ9['mv™“M‹k`÷,Ú 7_¯<ØÉ mÀúUõÜý’ûI…ÝXO€Š27Óc46}`$LhoÉ@¤ä¢Yay*c&N•±×Ôó‡|›„pÛ—‹¦UãŸãJÉ!þçéÊ>*v%ößy,rÄ´Q®›ÇWŠnmõ#%Ö;:v°(”è/E¿é4¹¨—ó¼RYµrÔ«ü*DaTr‘ò÷J"¥ žÇiµÂà·µ÷r;jâ»m›ßàöÏ*±ñ¡ÒWhׄf¬ ›‘‘Ià8Þ)íæ‹¡Ò‘b²ßÌg/•˜ú¸Óù0fBTHà‰àvß»¢i·:£/ â@RéŠCÛšž%p¯17D±zÛ &\X-Ü뮪¨ÓJ…´ˆº7æ/œÈÜF–á3æ ÇîÞ{GÃ|‚’o-åÃ1úFxk±­³“ê]jÄÚå÷ àåæ=/müÍoeNg÷ 4ÕšsýÒ²·ÂPvK6M꬚wöºÔN½áXBÉy0Êà íK³=Øæð»1ãö¯½ô¼Û¶äÛAÀ wz —ÛÝþ ÝZ¼¹3³iäŠ#×»€ ¤¡‘}¦(Ƽ2hÆ Šö¬Oª©m ]Ì¿Læy2¨ÇÛd#(­Èçãç>ÈöŒ óû0#¿s¡[¹Æê÷èXÀúY÷Ey}¨i¤¡%JûÕ²¤©Ï@ä­Ïêyøu‡JàÅ'tO5ô¢bUŒ¢ …{“Ÿ»š^ãëž®‚E"ˆÃãvúNgÅu–ß„: 0 „šCî뮇è9‚ $sZ„¨¸yÒz~€¥¯öuÐG#g¹«T£%§§”†Á)ìcr¶çqK%ß<éŒô(w÷Eˆ±Ü –OÒÆò®â&MîÄ h|EÌ0¼Ô2ý-Ù/G*ïžâíÂ*ýâ±¶Wçðy=ºzÛîÓ%á®sC‘=Ÿ„71íÙ¿2v†nþ~¹4Â÷ĤŸ\ t5Å- Åéè4©€îÿZhì”*4¼ºií8Œ¦¤¼‘¯ÈP v¨‡€ÛìêÖ·L/¤íïúscU8q·láýM2ÀNÝDë +‘’ýc6Òáä?º;[•`æ ±¥:ã™þ:˜‚©Ã†ö–+Šw?gödüywöùº»ž¾`c•^×~Â{„B±ÿ_i*§½& V2ÿ~ôÉ!*‹¨+ÔSR‡îÄÎË2ŠºÄüªLwüˆÍ¹¢ó0`%yù[° Õ½r> yì=‘zå…ò/Éì£ëªðŠMpÕ¤òTDe¶ØÔ|šx;<šÅyÅ”žÖV` ª›ûJ!Ì>‹IÞDÌÏ-~ªséþCÛë9ià¬w¨R‚µÕV ‚yV)@åy¥èðt_b³¾÷§#L¡ób.¥à-#2RÔqpî—"¿–·…BLv»aK×y!òåqúÞŒ¢ÂcSÞl½æiÏ" Êctj(çòêmÖ!¦Mƒhˆ ŸÏeߺ´†+φ½!)d¶ðÇPfzˆ'¨<ë)¹XÓš˜nñ–ûÓèÈgôóýœêLò\7ƒNHþÔ£6ÞšÇÕ%eïEŒ4‘@½ŒMsï[áÈéï7Ê6Ò%¤ªµµ4>› Žˆ¢}èb;ÑMH"åÁd KNˆ¥ pšØ%Æ0™%üb'q¥£Q2¢ÔòŬ9yÄUS§¢NyᜇÉO¾ ¡y¯¦‚F–5·Ý¬™,À™7ë—£ÌÍy@IîýsÄZsëlˆ9ÍÏMí€Õ; RÔs´Œ¾g>›³&1`²©¯úÇŠ¥NtJB¸ú#R6œ¸þ±uS$”N[mø†â„Èt©9xÚþš~i|ôU/ÿVœX“IkÒ‹òúÄo]…oæc½#³®ú"öâé<EÆçV³'Œñóæ½ 3¯O! ^þÿÑYˆn%Bêè¹Þ±èÙêTôDöD7 WE°ÛÊ€)»~z6þí碧›Z´EÃóÆ$ØlqŠ•ƒ7Å¡}ë<Ö.›¿Û7s[ëÆJ¬£S³t_öû€dg–#{ßÈ\¼¢ã ײýœ¹ŸsTF‰ ÁLÓ’ ÷Wsl„|xŠ0)&yz©gn¢Fl²,bëÌH |‘RjôéQé9µIÌaŸ|ø…x˜ëEðZÒžY€Ýøü®¤'ËVÇ~'Æy¡5¥ý÷»è”XW»¿ßìæŽw½+(ùr[½XÌ COeBìrÀŠɶ ͵X°eã­òÏî Bùô T&‹ngÊšÈãxf˜¹ê‹rÿ †yÀÜ$¤ªQoPFQbá¿'û,ìk•Ì@f-³ç8›Öôv<ÏÞQ .âÌqù[Œ8óêVï© ´ R.· Q÷=ÕÒ?·c|?ÉsþùÇšã # ļ§gcÈšùë¨1{ƒ.¥+ÙGU@š1Þb/,\E¸£æL'‹5„ñ%Y„lœù Ç]wƒž×‚à¸qO7 1ȯ‹ùQ޾ͣð*>âêbÕU·ªƒ{z±ÃaÉ‚2ÿT‚àC<ÞÆ¹ñ%ß§[æ'ë 1­¼ä‰á Ú}о¸ 5í)ñаªòñÀðþ˜Ó{€Þû¾;ªÓ£¬.-¬4Ž¿žŸ¡]©©ö4ª€qd×JöÝHEÜå²JkÇïwå©G HD2ô¦× a ô‡±Æ ß8تέN-‘èÞ¸­î–e^F˜UñWŽÊdèˆe¶ Ô/ïK·x‚ޏt¿X@Kû;ÃÀžØ½ÔÕ{IÊS%î!RKnðdìÛÒ¼™ ƒ‰ÿ'Æ<~ÂóˆaŠ=êZ—鉠íŽyÀhÁ¦³Ù;vc[M®¾fù2øƒ¾*¬¶…æ´ÁÚJãbdþ¹æ•9òW x3Þ³Â~RQ¿ÿn[zëµôýþ iâÜE³¢2c¤R»BiQÜ=Uy8SÀرµb7Š”3‘¤rOu‚ª ,ã˜Ë‚J7i”sS¼Ô“›jz…÷å~Œ"sÊ,@ Ø0©¾ÐÇ h™+h Tâ.Öt…GÇútò üÜ©ûf¥K‰ek+OåÜØz¢:¦fÁ ¸—óÕ(?[’0ô±]mã úKC€‡g„«Óþˆ^yæxWmšjÞ°çÅæ Ô@†¯ž]…Oî&toÏêiøu)‡M€2X¶ý-%2b°RþC+§åU$ ì+d" l” ‡?Ã'®úu1oÆ?F#œ0kœõ´%'>iS40"):‡wÉŒ êÐãï+!ì*l »gƒÞâã!øíafó䆪t¦Ê¥ÎFɹÄNJ]* Ω> ýÁ!<’óãz>]ÝRU¡¯>lÙ®µ-Íû¢DÔœ:S”’%ŽTô%h)«#L¦2ƒÖ±eE'Úæ7à×]È•§}p(I8N)˜6ZAì|.¤?Ôå±x<¼`HžÐ¦’(²†Èœ\M”í¬ä¬}y€Iör\ž@×ÅN‘5žßñ“›’<×0mÉ_·é×.ÌÚWΠ½•!Y+vÜÚ±Þû¼Ó©ÓèÑmï ^®Éò`Ù„vQn«kð @]éø"ÇÒiô(üþ”šva–—zñ g„Ñ ±éeÕ[)äæç`vä–Î饲FqRŽsþ½×”c&Bó¼V}⎻ë÷¸u¯ˆ0Àüëß–4e’‘[ݬ‘–žY®x¨0ÌMþ³ “„øÇ÷¶t+ôÖÿ.XŠE?òÔ¦çX]`Ê‘®¶Áþ½uÅ`Y‰e²\ð“5³}xý^Zñ"Yï÷ÈÜ•8u:ô$ôÇLwˆŒÜtÿN*VÉÌùÛ’øÙòÖ—éÕ¯ÍÝ|dœå¦|P¡CeQ–þhcX³îµ@ü)5'eUà-Ù. çð!™ "?CLŒ­Òúí¦S6Ž*œûÍæ«x-Z:‡W¶˜!üM 5’ˆÖ»¾ÜIÁ„¶)!ýIµáEòÓ.s-yì+Þ>AÖÝæÁƒžë4ž‰9Á~׿RÏ'VÖ9‘À$õǰ›kÝEg§;<–}m™ˆtˆ<â Á£,¤_¼ ÑÒêñ—-59âq~ ¸˜ùø§s fìÑ&]æœ,†dhe„dÖô`Z˜ir¨ÝÛjbÖü9âùÑ æ!®ÅÍzZfÿlæ ŽßX–ìò“%Âas‘Wù©H²E¨•)¶/q-P¥ ØdцšJA¸Úr¤ýÑS¬tFÍ4¥úlÈf¼k|”/^¨‰4V»–’2{îmÁy[Íùz¡2 ð…J„mß´ÅûA/{²K3Ö,œÍÉdÁ'†65 kši ˆ­S Œš‘8vwY-1þÀÞ¯{|P9Þ8w„¼˜ãBl*øåÇ=«µ¹Î$æ¿S—ÈN }³Œÿ»Í3¶+/ª!@ù’5ÅÑkŸ¾o‹Õ3ÐÓ3À$œT¢PF °—Ê':+JÿbÛþ·ŽT£oüv¬«Ä5ý 0$À4w]4>oƒkè.‘S+’ ë‰9–g–qýˆô"W3‡§|{ÞŸ—»'°ýîÙmòE·QºZT]Ê6Uõ¦ìÀC=Cª®©öµþ¾›1@K µï¡zº•8 {d¤&Ãî –ƒ¥œ¨TH±‹–VÇPÒpß/÷Ç]Ua¥ž‘€OÛÇcÜsíä5W‡H›ÑÔ™†Üû{嶼ޗ«= î:ÓÃ&Ç <É© Nó½ýD¹WFhøfƒaIÛýîÒH’C°H2¯VW·ç"`--ë¶­âN1DG!ÇߦÕ÷“‚ÀyE¬€¬wæ^\ÌaY[²AÔ<, [²xµ’–éû˜&Ã’f÷µÓä´y9žqú 唤V%vM'·½1¢Š™ð`#S ìjå”züg¿¢Ž™öÀSï†R^#„¼t˜;fÅïÓ D¼†L¾)­½ŠWw^á¡C€êM¨Lg–%2¤ïOd¡¥;ÇònöôÍYã"fŒl&®Ë—= }d‹„öƒ­â_†w$ÆVƒCž-À–A+„+‰õÝ_Ùg¢ÃXp­œÏE‡YS_ÅÌýö‚ÀѤpIˆP?¡-bEzhÆ›PĤԋIöµf»,ƒuÛâÀdÑ­á.L­oWÀ‹u3al’§ 9¥¿ú‡R¡úyn4 ³iItQÑXè=Å|;@–ɾ0DÙ-¿w­{)h¸'D§Éüqš!æ=yG%" `ÿˆUJ£Í#ab´ÉzÕT3;ƒž¿êÕOÛ‰<3 êøT-"Õ©Ðò”xÓtQñQ3­£3<ø;—6Fˆ#zÌýƒ¤/¿’XÓKJ…߯8$"häEá¸É/…„TšÿVö•!⩉¥Tººj›ÑRí¤x;7ÉqG'-ÝMIGÍ5"úý?Zߺ^Ö¥c•ã}ŒjƼfNпOµ©©ú^Š™hóÞT­/º£Wl’|p°3%I"½rXñQRZã­ÏÆâ^ô6 †¿>ÐAR‚¥Œ$KPE6ûHBoÀ[Ìò6^̈µÍò3ߚЖç²RÂ( áfd¢S\ZɆ=@€aÑ5Š´¦,“óé®Ãq# oiª~Å ^}ð}_“4øêi:a™{Rÿ|~/6¡ tL§*Î’)ÀÅÚq36"….<àwÆUÁ.²Ýc«ŠKСÜó7N¶,I@ýñÇÎl(«Ñû<.¡KQ÷`!›gXቬñmÞ–•ö×ëp×j `XÃì•»)á»ÿFÍß_²U^ > ˜ì¾H¨‚Äþü!†þó s<|‰Ž®–ږμÀgÇt!™Þ£—¢Bv/Ãè&yKþ z†ÃIùY4Iˆ$¼GRnòcg W p´£ýÒV\‘ i‹…Æ‹S,±m Çüżsô«Ö¨N_x @Ïˤ ­µë){Wî³óNÃò¡º¼Õ§½p¨0ýÉ—Ä:þ²’’‘VêN–o ê¤ÝöG% vxiŸŽ/øQ‰jpS^ÐÆî VÝÚ±ñýRl^îU° ©fµjÃ[O¿ðiy^HÚ¥³‚AÞu©v9×&ÙR DóP^©ñ‰ŽÐÞ¶¶¹rS€Ðrg ÔPŸê± ‡;_± M3Y79ȯCáå-ð É®U" ¯®Ãz}»]ãv%ÆgJìÝXDÉ““¨.kx¾5‘í^Sâ0¢ƒEýái´‚]ÖC©ëG '‘Ä–y«³éuÛ79_Ý;}¨õFÒ_ “yØ£?œ£ß$áE¯ÝÓ|¶ ôA¼éƒ'šéu¾V>·£|Ç)P§<‚s¤KkT/¬tûˆJÙ]ˆwF‚sYïdPx$(þ{ž X”³¥0ú1®¼oí¡ávø+ã&ÑòjË=5ü>d¾Í»¹Þ½èÿE !Ç©üöŠ\›cΔ•Ì±@X:®brh²y@$Lß«Ãb¾Ç¯ŠUBûY”ëü‰ cV‚?™ ¶ä ^¯ å!GnH ͵Jd>m6|xÏeW?êUz=÷""@˜Tñ!oEŸe¢3²1Ú'’­“qD3Dñ‰ûÌÜÿ9En¿< b AOyêê4÷Œ¶.¹ÑSòPÇ“/L&ÝXñHï ‰ }훉£˜™þÿ-£uéâHSHH¯XÒaì²f½Öýg¨.ƒ&ãe(À‚beÎŒxm0/v¿‚ÿ+¿ë¡ºÝs•Õ£wgÇ€cŸ“§‡ªÌ$ÛtTÛï&ƒ…µ‹¨M9kò$­Ê˯`ûMj\°útZÿB6ÿm6m–µîI$rÊ ÕÌDlúx‹¼«Õ)—Ê‚Â7©|'9|*zaçå>•ð°èzî‘Lœ}ÄJµ67lC?h:"³<&Ý3…{‰ƒ%êt.ox×¹¯ß›ÕߌgÄMîg‘Æçó³Üéqø™SùzOZC `ƒÍ4·U>ö³ùjæÉÆjó#Kº. ¦ 9zS3Dá׬’‚hõòræ-®~M –B¡øí˜b%¥ìIv=Š ¼(È'úWÂŒœ‰PZêc‚u·Ì:%­N‹Å 7-Úç¥×Ìý··ÖÂÉ/É8Ú>Ð3398ˆò"iúYFv=þ8’E´øÀëjÒÄq7b_ÿµ^£Í`æ§™JˆÅ´.óœRú¢,W¦ê³«†MêPˆ•Ò'|3kÀG407üæ®~F‡uV;ðÁåÓÚÎd*•ŒdÊÆˆ'jñÜÃÂ@gó’ŒÉÓ2£… wÍçu>ÚìÂz…µxÌ2Ú×€wÛ%¤egø+¢+-hµ5—.á³,¯kÙ:å`ž¥±ÝΊ­¡ÓÌGÈÈ×F’ø>„ò JƒIõ p*)ªß´ X#\9eÒA{ÿz²hs’ÏÇyo(Ž ´l6üx?]PÎî?²ÐÉTå!p©„R-Y—®²Jâk›z¸”1›L 4­áÈœÖ0‡0Pê'ø&k{&3˜–±èÕ0ÔU·ôXF €âüM-ÔC,æ¸öâΧ©l±|-ã@vÞ¹DPâÛ;XÕòðk=D‹8zÌ‘1”Ÿ1Múáyâ‚Úz×vÐ1œÍú^IĦzw0Må\6Ü×á6·ŒK|À‹J½@§*RÛ Èf½Åô×1DR3Ïä ¿jBç;¸çã?8þ/=+ŒK˜·Ö¦ÄìpNOg{_<¯(&à”ücj^•Väܨ›ÈœøÑõaZâ6¹HÚ°p?NÿJ+æžø#°"õ\–RðxŠmQXçxTpȰãÓøŸʲ!u. å3•ánAØ«¡½BÞ]G,Ü¡¯’&©™áÝðƒÅÙH[ œ_ºès™ x¯øî m!MEôsf uªÓy4^ B(ú oAé ©{LPvTÌoNZeƒcm^“ñ$ NÕ r¶CÁ@À%WÐÔâ×2_*…3£U&ÖpoÀ±`Í9Ù?ªƒ¦_[.ê¿›ªæbž’–`ULÑÉéP,¾8µ.ú”È_Cóä—@î—f•nùòf¼{¤9އN¼‰U¬?ät@™]]€GÉD%õ g.<òä¡g8`Ïœtß"c'Ë€xV:@2µ¤:wŠmçL‘œõìSެÂû?„ºÙ¦Ô\µ`P¥+ëê°ój#î)X—–= p‹R>¹EF]ä¼ûAЛ͎Ç,m}f¤9îÝY¡Ë¾Ôú.ÖŒ÷%m©…å:y€ª/3ÑjKl2Ö,š# ¸Ön^Ðe 6 .Xž“S„=ÛØjlÉÐøª#…íõ¯žå3D8ÖnäåN8_cGœÊ0BtD#)ÀךûÞ„·ŽŒ–øœà]Yeñ_9ÔÞþw¶ÜNOᨢ !Ï –ßO$PÅT VpÕ“]Pç˱ªÿ™^ô•#ÚSYf`Hru”öÅʽìZ÷Ãÿ1ÝÒ”;JÚÑÂ2‘KµÚ*4¼…³Û>%Ø&ÇÜ nE‹øeîq§¸\Ù   $ ÐNÞeÜ Buàz'«õ>Péˆküf:£ÒW¦ã‚û×”»ÐñsѽL‡¼çMOSj6ü|ÉIŽ aË&õ1¾eXyÜFWG»Œmq›ê°Üx•+u?·¯ªh¥XcR»ˆhÿR˜*ìëöŒdn­§Ñ¯3V²…aQÞm9þ ,¤N»ã_q“;ñ«¾»£’bO㿉âÿ8”hºÅ¼¡°.¾†òµ Uø‰¾CgŒ»k7ÜÖد\;€.ýd'Ëõ©q²ÉJDŒ…ÿåÑÙ¿[Ý„î qâ¶ÌruÒ¡O?—Ô·û¹/”P-é–×ñ/¹#•ǷVµP]¥ÊìTxÜòœÑê…*êÍ©“ÕË¥ÍDt ¦>éË‘ûà€tAª¿$íÿR¬nS •AÄ8L†¦Òô)ÔB&D§4íŇN¥R>ñÇÛì7?Z8}¾”RN…)pÝa}ß‹ËÂbŠ:FwÊí+bšíÎ{$(¦ê#ç!Óÿ”l)é”pÖW›ä«þÜb ÏÈ2¯so)^M¨I&g]·Wôôº8!Ö­­N¢¿¦L ZÖ”©¬§×ÇJ‹e¾Í 6$ð¤‚Ë„E®W”$’Ê49 ðܘÇßb†±Ù>’L×TMf²Óš•õtN@çI<®SÖo«þSJF¥Láÿt¼ÒUliZ»¬DqÇ é±±©ëøþsÿ%<èÑxÛYdGæB|›åˆ¿…Ñ"·ÓFmŸ.£Ö/)ðÅ+VAP Õ–õör™É-~Õîü™ÜàMƒ€bp˜ÚÃ7é¯ 7ÿpºÇ"Æ·3¤à³ï±œå#»›>Æè/x‹c еÕ1ÕalUŠ5…ÄYÕ“#ZZœNJÁúâÂvÓµåÂS¼òþùm—"‘ɶ×<rÑ·´R$#Ýz›ßaoŽ õœÿRNûì¹³™®ƒ¥iWÝ4qþŸYžÕ£VWŽ"a%È_A M=ȸ76™dÞŽ %ì£Þ ÉQÙSè’·iGÆúàµÊðüŠiú8cÔ:±¾þþ”œ»­Î=íÞ³¾íàÏsltÜ/¼GbáT>KÀ›¼ ì¯x·vè‘S3s+ýÜî'à¢Ð<ÏÜò;)v; Š |þa'w›pá>Þyδ*”§‡Éw^AÞd~v 8Í{Çøng@µ¦ð­òð£FMf’ìš.LP»ÈB y1Ðm8ÿ$S1þRÛV(HLå¦B7 ¶‰ØJfËB~÷†6?Îd; øl¥ÍêðÖl\ź…³€’«`ÇȼÅo CÐÈäò=Ú4Šà>¯:&Frx8|ßLƒüævç9eÏ'QÐ(U[ߪðkBQAW¶øÕ΀–]¾)eQ‘Ÿq)\ƒ Šc@4y5³!Vfô¶Êû}?£¢C¦ž#4IÁÝYBŒ` o‡:ýIo³ l*.žÖ&y œ‹:Å,Z?íÔQ`6C@³ ‡ÊeM˜2Ú‹së@â+¥ï3W±ù/¹Íõ€ö!Uæ-¸Æ2pÛæææËsºœ’ÀiÉ–”¯œÉ6+LéÔ‘árïFòaXÕºHúÀj) †¡öí-ZK^@ÔùãW   .¯00GFöKˆF›ô…3Wáâ)½«¥ôÒsÄ—¾ËtK—ü–’ׇË÷¦;^4Z‘ù¢—\3ìx:•ÒÐhmJ‰Ñ´%7l´>eØÖ=çÌa?~P–tŽû؉qP¯[3{u¿qÀW¹ð{EïÀ¬ ‚aÀ“ß0gRIìÿI¡§ò›uDB£m2m Ð4Që’\ªçLjj’¿´&+2L5y Ù*Qgt9 Ô ’Í{±„·[ÙP1ÎI™ÉžcŸ<ô7f"ŽävW«æ3–~õíÿ^#xBÜ2Î…î:cø{©P$ý~Àý×éHÿzé­Nä³KÍVkjë›ïp G±è.1°1ƒíæa*;»ÕÖjûÃÃý·ÁŒŒ &}ƒ‰ ™¸j¼Ëh½$‡l“ßKzÛðÛó¿Øò®T˧†?aWÂS…ÈèÏLƒLŒñ¨‚Dµ‰ö‡’'‘¢š‘v\r@©<i52@§¯¹ Åç¢ëõ'–ƽ…¦›n&qˆt´ @Ѝ­<î9ÝIHý^]½UÇ9ƒ€ÆÈ#Âxq‹ë­ìÅXËWt[7¯;E”M£{5ÓºŽ "6‚¯1dÝ­L+bŽ­¿ƒm;”LÛa6±g'èÈ´ýöÇ«{K{ ÖÄ„ˆ! ÊÁQ¼B‘4†¢¼â&./›àd¥zÓmud«2îË4}c™ª¤9‡2P׌ „@ÿ$ÙSškÕבNÝ8»šÑðß )&ÂDžX },æ:5Ç›ªõ:1,1j9s§­ŠÕ°þŽ@ú¦@µÖ‘wöÌ[}L"’ÊkÂydá茸c:Æ× Ô/OŠA4ƒ¡ÅI,ñø`p*5,¾°<Ýð̦mþÜ&±IAw³™Ö½ã ‰ËÅUeUß á¸UO:GÖ7âIçÄüŒþ][]-è¶MÍ æ>Ç>;G±†Dèq±ôlÁ Èr£79 Ñ9²ÜM³ÙQGµãç=¢1¾n@ ¨; e}á$cÄ%¡ ž§Zw&‰ðp]o˜sQ’£[?ËЏ-]ø„ÆC/ÕÕKÀÉŸax´ž;yÊžWe? 㲡ԥΒ8èÝ#¡Z›,ˆ×n97lÎÂÊÐÑÚJL)M¢“LˆÛ…~Òrvá•§†·„Íg^ŽÎwJý ò6&7t½ ÔèÔuz]÷6B(Åâšð™ºÇÒ;Ò-k¶#‘Wܺ2¬9,ÂÛkUFíHHÜFlÒ\²òXׄøÐ§À¯Øò× ®¢š‚ÃÛXÅê¬n=Ï—$ùu¤Î·Ýz­´&DzžƒUÂ,’»&Òtz—4yª£7(< d}97‹Íš^µ·h)@+µ¼Ðl¡ÙŽ0ðéÄÿ+íôzf/ °8t”e=RdÚ_%ižþ! jòDŠr_Bf-d`¤Íf€­–oß¿³ãx@°Q$#jU&X‰ã0Wï°ÌìæƒÌ†€ÓB:p¼3¢ƒ°Ômþ(‹I;äES!乫Ûʬ1Š›îmX<=½ÿGjIà”*ˆGÏ)QÎÆ¡ñY6zÐhÌ_»åv¦pª§ÇµæŒÂ–ìæ€#«ˆ»j”éÈÛ}ûõãq›lKsÛ3qê}%4YÐv|:ß¹AG‡®¨Ÿ³ ´Œ§ó¬¶­äŠ©k7·ÑATŒ 2Y äéIbNWBƯ&âkj͘tG•Æ*EólÎ×ý…y·*M.2n ön °ìœéòô9öኂ¢,MIÃmØ!°?õ¸’eÕM@¢¬DÒ aMÑ?Kmµ’\Ù;̛ݑS-w¡ÂÔŽJÊJÍ)â’-¢1½ .F„Ú€<'wÿvàËðȯÉ0ñ “E_¥ÇÏdn©[ XLcÙ粄iÓ2ÒÉÀÖÒ"ÒÒòbH YB&áÍF…Gøºâg½S:u»`Ö@½åLX@}ç/óöƒc|•Ò|£g‘b¤é0C㪼 U«±D­7˜£)†©pî,Kr ¹Ca4Ò¡¨ÿW€±FQh0Ú9_Í„éÕì#Òΰ‘†b”B}}êú0z¤×?*¶7èfW˜×ª¤k§*ØÂ¢±—Ñ`w/ZZìàXAá3U (ï¨j7Ô<7aØ–JÞ‰‚Ê"âßÓÇ«‚:S ë“(…èÃÚ“„³ÂÞ!P €÷9_ø’©Ðkn×ÿ Ñ÷4äg•þm•R¬eaž·¸ðl€Žkx"üC ­$MÝ(“ @c 7o |RÛ‹DAžIïî>nqFûKúæšô|ñœ”êSV£Ëø,rj‚²8«D  ù}Z0¶_Zg`_±€w>ÉØ:qËK;â(çÖÀ øBuËER¼_Sú#²‹ß[<®^®¸¿”ìÿ~¯-í¦XóQ@ -¦Žà¬"|îóÐŽ¾M‡ÂÔ%ãGYz„ô¶¶•pgûñQË4™b=°\ÿ;Æ#üÛõÒ·Eõ*IâE‹%Æ›¿ÊÓ›1Õ„{– óÑN ÃC}‚bR]ÝÝ£ƒõ@­©©Au¶©œUß'¥\ !¼–xãmÝkž¤Ø%LæLï#ELÔ•Š&‰ÜLAû ת6,΢õÛ…äL’–¨ëºÂx>&QirŸŸäº·M ÓÛöYZ™$e(°Ùü«xîŸ¯×Ø,ƒ‚•'¬¨/|¾cd†i³{îi¬üÂð+we™2Ý ÷¶âfÖ”$§þÈ\cŠ%PgE ØØÊfÊÍP+¯ÒcÄIJ2Mü?Ö |×!ouKêtÊ"²ÜÃ[ pø)Ñœæ£.Å¿=¸1OÇ=íÂ=Dª®]JÚÝ)ŠÔoÈ™bÄ…äYÁ6$‡¢gêéÝSkP ³û FA#ý_+—%Š¿Ìó™k<®´-Óóž.]NvÕfŽÞz¤½ßÇ6EÁíM†]²Cê§åâ.m)ðëª ,ËølQn¸•^Ӥĸšà##TÏx¯töž»³c­³?{øðuª#-së4â¸UÒ½)¼¨¶ ßSeÊY/"‘†sª”á1ïS²äÀ5f!ý+=ÄHa)ž«¼–’Ô³Züé< “7ÛSÙ€¥ùr¶ÃÚ\ìíq®08æð¹ñW{´ ‚è×-)kD÷ÂÄ{Ü@rZônI^@rÔWšÛb`}þÖÍÄÇŒî|;ÀŠhufw‡Y^ÁÛêÔÝÒE¹Ó{ú4ô§~é”}Ì(cS¾î¯Œ…2øÉ]ÿ6]ö&cC뿨ùDì GÌÅ,J r˜«Óß?«(º«Gæ‡ôÊ)›¦2O­ðתª Þ=kõºÄg8ÎMp ʣܡ^!_W@¢Pês×›Ÿ-,QÈJØ8¥‘ÝÇ0%¢MdacHq»ÄŒ–uÕµ¢uÒõÔáÁ’¨$ß4¾‡¥oð1x;Ô®qå\|íAmQŒ‰†VDøpwÌïâ‡ùiŠ6NYsZßý ‰ –õ¼Íï·@ã‰'9öl£J‚[£éxp l FÐKɦå­8t%=û"T/ï™î¢zœN{™:–€KuÚTu²BJ,{ÝÿZ·üZˆ×쀗ŽÈR¡*wç|ù¶áÀã£A.G ùņ(ÿjzÃ_·qº0J„ø¦D[.ä»^™lÝhÉ›î’íµÕrÑY:|'fȼ%·ê÷[£¸AUŒ¼k1 _kðµYdÈü÷yb&"p–?˜—çÅNôP¾´—PŠý€nÀö›ÑĤäÂ1V³¼n³9deûecZñz©~?Él8@î6NF9æ¶)Mš‰ž¦ HŸP¦I¬‹7ªÛ«'£#*€kY>ÂUè›ÈûMl³Q$D|í´©gHmѾ"¥Õ¾¦uM#•Oº–Ìhùˆ6™9Ë_/½ÜÀZFN}ÙÓLÜš\~$ï¶Pàƒ<GÂa'z•8þ†ëtNóäÚyĵXuÚù^|7´r´îð»/¹Wç½ ­……Ç¡r•ÙÖ *k$µYqls²#FÇD7nž7øþž¢ßEcVEWEóQr™’ÂqwÞÓA}=ᫎ(‚£Ïö™Çªöƒáùïcý·VÈå©G {—ÇÛì]?^¨}¾—ÀRN„W½­1ËØ2Û·¹F01+'Už´Sò¶!ñ§÷cá’Êh? •«hƒî‘†òÉÑü4±F¥XRïC½|ð‰ËO¬‰(¨nÊ”ÞËŽ¡?Ô`J~Ú€vtÃ ŽšöücáŸNËm.[,¨„ÖFeñÉVU¯QÓ›¼{•uºM„³Mœã´3¦gÚTºS”’Znádš±YáÚÍ7~ ¨âÅVé–Š6 üß ¿ yu½lèûnŸOŒ‡U£¹ˆX-·T±~zw`Ç·T ;±Ú_Ì̉™[êÖl‡vë¡N£^”È­ßܾñžØCNx’»&°2¥_Z0ÍÚ-âS|0(vþÐÊíв/7Ú¢€$7h«(Ì,Ìœ?`›Ùw›ô¢”󨱵x-ü²s¿àúq‘®†[´Ût!FwMWDwg?\$pó¿¨9X”Öù>!˯U]ë=É22ÇŇ^…ã€OI²/)õkµ¶Æiêf¾ï`#y|( Œ"P!w™‹ÂlT(‡C—!ø®Kr¡YM?åÑk³MªB ‘M.¥Cm"8‰<Ç4u°àÚ|™2Š?îõù[–•b‘¥Ñµ“|hñÛ;ѶèK pE-©8’퓃Ê΢\ñ֌Ɖa!kjˆ•kæÜ“¾Éö±Ý¤PðÜÃ&áêÍ æ'ÎÌ×Â{n,eˆSûÚãÉùˆËŒ-ÁzœVØòsüȳðŒÄìo3™¼œíÙXæ„ÑòÙâˆ]ò­´^$qb¡œŽ9c¢J(ÖL°¸óOаº}ñµŽ¿¤ð°™Pg¯KoZGe U«–U£ôåß=±ýo &<ˆˆ‘À¾ñ€sÉÃÙÍ'ʉ»Ç‚¡gõkw#ß\à­Pº§Ëª5 B,£àëÎ(Ÿ"0Ç@¡5½/œÖÚñ|8{‰}†û,Ø€ƒªö™ÐÏKv²FÏ軪£{`¹©ÖZ^øýøH³ìZ2¨î7VØ28'Ç¿DÚc·ç%s~Þ8®²BÝò¤gXmü2MNü;;£´$Šð2fy¶°W U\A˜Ý‚‰xø—<îkµ…[ïL $ÿ([ zѽ¼spÞ[[R†MF½›õ0deWUï!—ãE'꯰ÈÁ_õê;6cÁ¹_û[uê±øiD—ð|‘6è Œ¶(õ#–i@}E¯#_|Œ‹{p¨qa½ üÿ'D,ýqö“^ƒFšt-3²–wÇárÆë¶ÎøÛVæSÿvj­Ò€vRè§´D]-°n®-ÍïØhý‚½XO Hú=£ÈúÇQýmèBNh|Dùó,Å,Å\ˆ´/#É[ÚÏd<¶ä öG‚MÊY­¨Æ‚º)F£»žÉÔõÐX„#ˆÞ»W²´±_Sd~(qf{ˆê2—pÅøÚ•4CZ2àɿՋµÓg¿¼l?æÜÿ¿0$¨p¯`ýBí„–ˆžxÉ)n9o rð.ÄÞùm;x³¤5l/ÑÛ×õDèÿC ˆcoò8#/.ÎÜ¢„–æ ÎóÞk ‡Æ!%<0D>©À‰©"0`4¾©—&`¾Ïò¬›‘¡'`¸‡ :…»[×Ã)ˆ=¬¬þž8× 9ú‚Q|âLH_•’8çÊÄŸêÕZ¡6FðLÒÂ7("Ô÷ñáŸAšÔ›>µç:¥ÙúÉ»È÷-1Ý Ï‹éhŒëÌí@‚ž>'߬Ã]…A"=]Ÿ-ø>ˆ6„Æ 8_gqñ+÷{&É Â”Ï ®†DP̱ݗ¡£NOs+gÊ—gôU œß.«dNR^ZfÙ¶þâ9¾›E`ûˆ,û<ù«­JBô€#}tº5 ù€‚þ³ ¤û„ÆÕ£f‹i`ÇôfÏJõøBwz hY¿–Èýƒz‰^³)X`³¹È+Œ7a~/§‰â9`P\_çg!ã Þ§Ú>çŒ)qð#ÚŠ¾ŽPô³¬>ÔÛ4|^ÏÐ1×ý3ÍOåðÀ $#èÓFÓ#²çR”¹ÓòNŠ2°ùQeP#A ÁºËº£j·:OkWî]-HÛÌÓ6ÿHÜd±k–ü6cN³øÉ j ¢Ys2ë 81ü¡ç"g3•ýÂímêsŠCßÝýå«T¼åß+UÍj¯6#r#¢_:¦€¾£¤¤:8c¿ ÊÉô•$ëÚK^¢ÉýcŠ9$‹§GB´ͲÃÄÞReAQçWt ™ƒˆvP©ÚbúÇÁ÷³#v;‰¡‡kt¿"Tü:ÿ¹¦ˆEK–™Ü‰ï3…P€Va¤äŒ”}3É´Âà©›ÿ}8âKêªýÇ̱½h>%9vФ÷“üˆ?ƒ^.ż´ì /0ܲ€:)a³ fW±›¼W';$¬1”û¶‚ Xz&{2[”àú‚Û®ÇÞ­è=1HãSöºôÀè5¿F\\È:ÂV¬LÑç‹Jw»Øîi0ŒB%uŠm"k-}¹ÁEçÞX¼"™%ÕÈRŠ1'+ÛŸÝ|+i3òˆ?"/øÌŒ Ï06zû-§Õì‚•å*3@%Ù[¡°žgeãY™TSN7ÚV + ÑÆÍˆT@•R•äÓoE[òJ 8±%ýà$ØŠ9}[㦀>I¡®µñÛX=î‡dº‘àØ€¨wŠÒU¡M¯½FÊ#mf{5„qú­_8-½[?‚ DJYo(b .}jýrÑÄ6 yT+鯾Àùî¹GÎ\¨í+ÃX㧌Єc£D±=çŸÜ„•Ç`ƒÑ|»Æ+¾õäüÌç¦UŒ’[G Ò€äû!2…ò ø¤›a¢r³’¡Zø/_i”ï3¶ëÅB©-/ä À!ÂŒ¹^>X- +/cE[þ‚D¦þ% P hú­½¾gübÆ'ù¤ ‚–Ðò‘*ŠiqVºózXÙ¬`i-Í~g5Ùª)@$ÇvyŒì]ªW¥kÊ[B¹¥G²(Ñë›ê3íüQ¾Žíq2ñ6vw[Ͻr;ÛHîò=Ü%D™I²™~ý?·ç}Kidrö”wédàaÒ"ù)kac{Ö kÎ ŽÜôFú "æ¹í4Õµ$røö7S«Í»H&µ F}â'3b€ Þ/|ñ¾ßêSÚ¨Ò‡ â— àkiG=.Øg}žæUכ󉜥“)H‹Ï~æË„§Ñ²“]}%q>¹ý ½Éç¼R€J;È[šÇ¢! „O˜Áª“í¨ImYEd—ãsº»’ؤ&¯ ¥ïœÎ?›«­[é½óú”ÞОÏÍÈVWÖ³ê;˜“‡‡ß£ñ!^“„Ī’v(ƒŠÐø™iÊS;çx¾b´7ox˜™,CÇøHöA0×õÍä†YŒ|1ÑéÁ¯I4ÒÒ ¾Eˆh4hÊm¨ê"­[lÖ9ˆÂS}~娢ßäÿh[¸Ž‰¦!rš(IÙXµìó¤™á%ϧ…ˆU<)¤¦»– »ª¤&gMBû ¹ZFÖšQð™¨Ü)ÝÛwȵ=˜¶ÆÉ­œ@‡ª:U˜u5ßÒå:ÔèÎ1¨/ãX¸ñÇ‘²Z& ËߎµP¥¸\³ù›žÊ»9c 6.œ³€3Æ/ „*í?ÞùÓ ?1Ì “ùB¡ÔÜaotY…-Õh™8'B¨h­ž|v€nûÌÁ“ëÕ2O¦XÔÚæé—‚È_wxDmrrïœ/¼é9ÃåzØ VÕãu÷‡—íØ­ø]ÿE~÷äz[ ÜwµjÑïq€ßÌL@Ïâ| ì Æñ7Jåã—¿¯[Û5+¥?&Üĉÿ€ATVná>Pæš¶&|½SWkèâŽçÉqEæFiIJµ½•1kPO[¶ }4Ç;Bå°«YQ'e.0¢;æ³S´]C¢HýíŒD ·7!ò6•w΀~tȃ7wlF‰£¨äïÔ“}ލ–ŒöTeÿ@Z>óaäRÉ„msâ5ô‡§0äz$ð^pÄêCú7½Ævž€~$«ÁU$øRÞMIc‘F@úr_ê Ð2bÀƒv…dèóB{m< #ýOEs$‰ë½oîhî>Ñ&1gÓÍöoÀË<ÂÁ®'Êþ}ìÊ”5 ±zª°ü×+ÂxæCÉz¨IT,cÒ™Ø"N,“-ü•âÿu¶µŸš>ŘƒJ ƒŸÞÅ´h´AµzEB0"ÁiIR‘mxÝlH†!fR‘ãµøUäœ7)ªlM#¨åc¸Ÿø—$Õ ƒ ¼ñÙ O{³Hæ6®&´¹€7²Òc+ÏùòûÉöFÈV`§üc ^ÕiwHNVÃ#W»%“äXÕ¨\â ‚¡‹+b•"8;¬:“…UN}Ô ' Dž,?P0€ƒ1¥rk+n"óÀx½`誰ŒT¦Â甯Ø'èQÿ6ñ¾ÇAGñ¨o!eg>_«j”XèW¸çÓÁ|ðVnÖ\è¾E6 ëÝ@š‰Õ ½ÅÙ“K‚±T²Ö‚†Œqª&’B€ç8•‹ðX±;[Ǹañ›ûâ˜Ý ù[ë÷ñhSR®dh¦BoÏk¤›Iņ.ÖHj¶Ì=z0(#ÿpŽƒû®Lñ¿ðU ‚ˆ‡"ųœ”|,1¥KÝ4ŠK,pa§êLß§ˆ€Še™·X¥øÛ~n­A üƒ©aÙ#=Ø¥‰´¶å»’›*‘`ý«Lß0Z¨ï2«ÜI^'’;?Ox¦”ð¨Iœú ƒ¯ãíå¡™½˜¡@_9t°rïÎÐÆ@p‹ÉÎSÇ¢ïó!¿öËßÖžïF£i{yÖ„Å•8S£¢æ_mFb:Åäiv£;ìA'0ŽÚM2á袖½ÇîéNïusQYùAÜ(IJ• R耭È£æ?\6cW7ïTä­ÌÎ@¤àÞ’æCæH¹ûó˜qûcäÁ7½S4™¡ô0îÚÌÅx‹’b“Ÿt]‘lÅlcªÅyq-¾/6*¿ªöÍÖÑ@ÐÖIIûŠƒY[iàrß9Ý7† ˆ¶Œn²@ÈP{F÷t`:›Ú¤×!‡Š-çæ2ú®×§b3îkÙ»ó9"HÆ^½üíåg;å7¥˜DÖÜŠÕv¼i·ŸŸb€+Ž1GðB¼FôSñÓê¶cÀ)«W_îǃ<i›“] œä5§¶¿µ‰ÊÃ#°Ó6ÏјÈtN—q*$¬}7ùÁWÇí;,]ôiŒï«Ù×êó.Õ±šÄåhñµý@ˆß öÂkùYמÙkeÎ{ê|“çqà[¨nÍÍÿ1‚nwNXåW ±o`EõO´WJ(ƒ­T-©¸˜?[ãSw€ãöô¡ûzDý½£~Þý1ûzM¾­èý½{þÞØ°~­ýZµúºý]Y÷<:ª=» ¯±b÷"Q‹X¦X!(ḿUa«ÃUHžþšEen™a¥Tš#®LýÇï@sëÆ4rÙöSì9IKæ/]Öèl7fßAeÖï©]h§EµãeÍBöNÜççÌÉ`¹Í±,Yâ( ZGH¶%}×Ü‚”v›@ù|Þzh,Y£C8’ü© „:4;òØØl1: mñÀâU&Jñþ0¥Þç Ÿ»>î´79\M©Ýç‘õÑÑiü×Q¥T(.ìÚ›ãÍÃÖkáJþ'ÞE>µ6h·nñ”.(† ÀâÌâ>úpþ§õ7áÃ(\ ú‹÷?ýîE1›pË ß­lìª0;¬qô?™§“ǧ~.O¡!g²ùGÝ&ÌÀëñIS)*ƒ¯Ò΀n+Õ8i;ož}ÈU^o¦[žT!ЏÙHx°­À\Ù§¸6ø³û‚#f3¢UšÇ€aÄ;ë¤+߯ӗ§üzÔªòÚD8‡m-¨q5"q!¤Î6ñX[º敬ÑÇIAà M'EÑPèËQÊíscN26Ò{ánn'Þû‘ëî™nˆÂÛáx¤] Âl˜_g +!‘$#aàêا3i/0A¿Ò™‚›þNfÉäÛk­0T ùSÕ–`‹m)ª0¦_^K¾”S_º/“q^Ñbįsš;õ¥Ñ%‡FŠÔ EbÝÚ Q{Ü>?co%¿_è8_—‚mA8Çoïs™ì‘$È6òöòž,X,šsº¬#vI)Ü6³Z þ!°ÆbmëOø#öU¥KŠô»$uvígp©Í@$2Eù‹A¾N(„’ë¼²À“…ÎÐJ|›»Lû6>Kpz‘^\˜'ZiOª°Z°=2† Ñ’ q­Q¿b w ¥1à–ó¯ÄUó«iSD {Þ® ‘°«ehQKùÁ:98„2÷há¹±¬ðá“9€[Äã(ÿDŒÆn •Ãcÿ‹. ^«*ÙõnèPºL³±ÔÖ!3#•Û1t¥Ú±d)¥{´†²ÌþŽ×¡u•Ä"¸O}EQ})ä‚ëk…\E7!'3M‹ôÅ.Ôæ9ž"çšHXù›·‚p¡¹‹7v0ꞟÕb˜m‹Uç­ð)­¤ã<È[Ó„ÿwqðµ‚l¿u¦RŒÍœðâÊš Ñ¡ uå­éø¶EÎ1EÙ©’˲ “~–©­}÷O$Þ†rZûh£@ ým5Ìhþæ³!-Ô:ŸØÓ!TÆ=G‘ò6çòÔ ÷¤EȘÉò[¦R\”ôetKrNïYˆ&%Pt”†5*eåå9z‹/§õ ¡Z;Ô\h'Ò”Þ/>2›F]óšÎ‹7SpVU´={¸gUS"ÉÇj¥&¤CnUùÄ0·Ì9àÐâž´ TÖëÚ{|yw‹¦­Èu¥wç η‰˜œã—–Pö‚Ÿ«÷[= % LЫyÿ&2æ,…XË-Š–ì%ˆ÷lIì3À'ByÃc¥5®ßÿWÒì5ab “.‘‘³¸ƒ¸%xÌÉÙ*qkÂaÞuÒŠMO[V¾]½ðôÅd¨Ëtä;%~“­sö·zýuOl0?õÞ¹:zBxyÇÏ)È£àÉ;½¼á ä±ÿí0•ìc!À„–HÍÜ×ÐúŠëŠïŽ\‚)]U(ˆž´4w»OF‚6ÉÜeBè8eÒóðx2q*—ç`v§(¯\˜žiÉMCõ´~Ùys*eß²$‡ScGR3ÏÞ³l'åVU'Ó{Æ#‚ß0öî™—H[<-Áø€4ÒŸÁì¥V¥wF|ü;Ô™>=±"Ij©÷ÇÇ sw˜ <ª‰D±ê’hâHw Ág‰4´$îÿqÚFošópwz™Ž>¢•²€ÌÙøÚoAa×WñR¡Ä¾ÈDªZA­oé-Óýh½>*ˆï^†íV¬5âvyjÅ6E~wËx?Ó¤üj7#%#…p"àåP¢kë`Ôîíu÷NÖJÑuŠ+Ÿ×Xr)&‰çÿ.kNÔÙï*t™q#£á²£{Ρü‹ë\ST!vî¥QÐàÀ× QùE=#‚ÊÏ›vr4ç&ºÇ’Ïú¿¢;4'âUÏ×ñßšÍijл^ö—>mÒ!¡8ÙÉø@™ü)§UEW>jQD߯†´6ßl/'GÜÊ ÃEØÅcK‰iw|û_ã$Þ<Ûc犞)yUøÃD >‘­Ý R¬…tQå-Î bêÓ HªY²Û™%ÆÏ¥LöT”*ˆADÝž Räèf)§œÕ)ÍIy¯;ÏFŸ™•}HB-%l-ö"Á¸£H¹¥ï ® ,Ò`¿¶Žqƽ×S¢õKTZVåÙÏ„‘Ø'ü“µ–5û{2uÙ=ëÚèÓÐg¾¿«ön ¼,¯®8 ÉZŽ(xìçÒñ­÷zÎÓ»ÌÈO]W(ñ ß³¦8XZËöÆÁî|QiTtrž|ã_|Tºkòóž?bÃ_/ÉYñ Ñ®Åå´æä ~îG“ÕÂüsì’Ååxs/t[ú6«ßØYPgPT)#·YÜ! ÄÉ97TJ3?Í­C¤ÏvC·^Ådé£Ìp4žÍr9Ó–hX'Ìõß¼Œ|Vk B[‡ˆJS2Ÿ]Ðôx#ÛïP@Τ§Kgj b@‚=ûÆ-]ùMÜÇê²sÛÂÙ”œ F~‚Ü]Ë÷v šVÂåîf«º ÚOi^û†‡“Õ# Ч}‚[êPyEjÁˆ½ÆïJfm$ÓeÓŒÝÈš‘Ì e÷do,&­Íuw%+!T'Î^CEÀüÙÏtoow› ³Íâä‡z¤ó±„XX´±(tM¤™æÊ/ÅŒŸŠäR¯§‰WŸXqÚäŸD”ºX%RxãÞ²( O4ÜAF’Û×(O`]5®_´Ä³§ïeø×™ÖÔ  .®yÚà‚2mÎ5´À+Ò Xç ñˆ¨ÙµMI¢YT•ŠPÆÏ[csÊHÿ EqùCB™ìv((:±ÜÜÆ².À>3óÉ)¾%0µjÔ…¢ubÇÝ9ðWfãð³é·ƒè֙䰬ÆQ å¡ÿaÂgµM%'ä1¢Æ.PzùÐ~Ï Åà¼mFÄTŸ>°ÿ!Ÿ”Þ);ªh›=<Ë>‡…0„~1gü~ºö¡½ôǦ‚Êgs?ê¬Fë.„Q…Œ°DÓO@-”Uò {žÔ¿ëª¯Å•P‘cÃpQþ¬ž±Ç[ä?`4ÉP'r\FCz–O#ÐUâ­Vwg½ZJ”®ÉLÆk.Ú‰Kkÿ;ˆo8 ÙZß|˜‘wô¤7®Ÿ¾‹+#ÂkÒ}ÜS´?ØÝ"Çí”þ ·Ë®¥À~ǸÌX;×=¡«2(ŸÂmGë>¬zþIö\ÑÑ5’á96ç1]_G¶6¯»ÊŸùþ*ŽyÜVÁž®c*4œž(…DmÓfÏ™5ÑÞуåÍ›R»7,½E…ÒPÉk–L{•Ä ©*†H¢}¤I.p§€Ý}­a=ôÃùšZL24 ™‡ÌRô ÌÀZ˜íˆ³úH$g˜³ÓŠÞJ~”xDê9ðø`°ÌâDËø—öú,ŠE€<_¨¡ç~‰ÇÀäH|uVn@2%@ý¥ðÛÚéE­õSªÆ5t¬e:ªáñFs|7ÿ€)`Ü!sl¦q¾m¶·t \Ý~atc‡œU®_‰‚ ÇÆ¥@BÐ ÈN ­|‚«Ú•¡VÅow»sNÁ)TK9'ï£ôBE"Ð3ñ¾ÐL²X-ªlš³ýµRÑ¥AÊþá¬QK‡ŸgÃ)¯çl¸ÎPyWÒ,¥Îî/±öGu?¼³Ÿ,Þâ2p7¹e4òdˆS£•ÂI$„ýuô§—è£R#¿H3O“È4i,¿ÁN|xó\Í]ôëÏ'£ŒwçŽi/º Š˜ýx2ÕèúUl}AwÐŽþ¾e„F_™ŽÍ!0²yÃߥ§Û©x(ŽtS”ÓÛ³;ãß#Rãÿ!yäzЧ40P´§ãÆa‘ÎBböJgiÅW}øÍm–þ*€{R3ÍoÈ$ ÔýñÆà¼müðB®ƒäët0¨?ͪp}Æ4nWôGÌT®Ï¹çšM ap7J%^HÞN©'ðèƒ1bXBåxã´›eŸ"Ã]ÿE7ˆ® ³êái¨Ô,bâ¶°¹êNÍ·¹t]Ô¾%¨!²CxE¹cäÙpïá óêà9 ·h¡³øe£Û†¶‰9÷’ÄM"¼9ÜÈh\ìôþe„]Ýò£?RŬ²ÈÜŽÎ(ÀuêOà¦í}q'uÿ) Bq&µÞYƒ$ý2£´—®hè=có^wÁ3e~÷ÛGL'M fE[ûžÏyM%ä?s’†˜Üçöbˆ~3”ÿ~èr/Gd޳¬Æ‹ÉëÄâƒ`’êkq\œíî+Ìî]‚‹ÃQb;–›ÿq]+úX.§Š;¤E&îŽÙXÎÚØ¯H§½djxÈc³é!È ½ŠøHÒ®oÞÙ)Ê¥j| e6Óo¯Îß“­Tº}%Ûi@µ°*©J„0³þs‡«¥?Ôµßö…лêÑ€;Ô3 ©95Þh ‰8’Fß4Q(€ý×èÆ?ÊÅùDß§ aq‚ˆ é}¬¦ZÙØX ]¶ŒÅȈEÝÏ—E_ñ ¶„OðsQ)^V•våöÍ*_˜“êÝ¥–ìH.Wx øwÕ¡!6‰Çjq(Ôâw0o ã:+PcláË16µr7sàìûÞeðßExNÖPàc ‹ I ïzÐn1‰|jÉ‘Žÿ‰ÿa¾G/JaONì…RÍÛ1²Å£xÞãÈÚS¡ qÐ[ý'ªk£ÁG%ô›¡{lÄi­|b`Ñî¬V5²2NqxèG¦A=kŸ£8eÚ9«-D×”vVºñ¥71èÅ7åÕ/,ÝèBR“ènӇض?¨ßè• úzàFô`RÅpò{†¿C›I»¾iÂÏX/Ygœ'ýñð’ǯ®…¬ÓŒ Ý:ʸ%p®žÊËm,“jj›s“€1êô#DÞø3ͺÆù&½²òn+ÑnŸWŸüN9VÕn½Ö<>_"+éq”§’J©‹§„nì}%/ª·b·9«eÓ‚7’”ªRÑ]×yãôéü‡îñgQ±ºà6²f"V\ K‡þ‘ Q2y h౿ˆ+4«UÃÈŸÒ啨I-£×bó§ LP È×<ÛÁÌŒ>ÞÄ‹¼ ÃÆy}%¯;¤b~§gýÉðx#5Á»%‹|ÓEzý³•zÂðd;?F®xµ¯¯~á1’ò@–E½§¥ì/†ÂúÄîÈxBâÐ)ài„¾˜€¢-©V’½mÆÿ}‘/”$ÅKaÏ `ò|€]£¯)mLã4Ï+§@r¹Žm’ZõÜÁW€›Ð”›ƒ¸_lEo!¸å)Ïïÿ_¾—ì¸'%m䋲Ä}Á@C™^'h¾«ylÉÜñ~ø×òõkö kŠrw°,÷+xíK¸Âàè‘°óv¢œH=;‚Ëépá¡uš–BžD6¼z‘ñœ/:9V¶2NOÅ>`|s” ÕRT‘—3Ú* Œ÷zŽÐÒë GBl<­6VÎ-Ð7ÙWÐâ+h XÙ ãây)$’I$’HÁ PÓáþÏð•½ZôŸ¾õ³{Hä×߯Q…˜YÊ£ÉÊTX¡“0˜j£j‚þå&b»\ƒ¢Ôy5i¤¼ýÓ¡zÅu¼ñVŠßÈ@é¹he­8D¶q¤§Xï#B+*å\UsóžØñ¤É‚@ãŒJh‘žU9§s™® ¾Íœ³®é½ÕÃu—rLÃ{üó¬Å‡âBKT®ùýàsA¥<¾í"’ƬQ›7ílN(t=)Èë¨6mÉ$’I$’I$’IÎmÛÍÔúZ#5aHù¢C…]C}Çû„­ýö 𠜪Ã×€Ø8 I¶˜,¨ ‰7(j‘é55áà­`ÄÁkô¬¼Ù|$SA ˜À‡õ~®ps‚…žôK¤(gdRܳÞî—e`@ÍsÝBb?v¢áëkæÆ3·ïÌ‚‚\'% ¡x”´X SÂÑ»<ôãTü%÷\ôqJ>CSíÍï=¿÷£í9z‰°èÌ­õ\%öUjxYÕmãK"½ÎîÓIýeC;a’o­]øº4oG¬<ëÿi'hÝ/µ™¾Æ¯i Q_üK{ÆüøAŒÏnÐ +G^j·âQ%ŽfLX, qôñ‰úWð¡±pì–RÒXVÒo`Š@zAØo2pIê •¶íL“¦;lLœ÷$‹@§7/uãω-Ñ£=;÷8Ÿ³Øº:LlÞ@ûf+(Ó»=°…Î]1Nì3¢í„q‘®ë»ÎAÀô–+Ü4gÚúîSœðµ_a´ë#RÝ06:bl*–Î,U˜*»/VZh[79!§c³ ¶’ªeÆiSCaCˆùÙÛ =’¹[¯QÞizÄ™µÈ÷…íÍhF3ÝÜ|±PÛ[øŠaþ(IÑyc°åÍ6(B˜¶Ä¥–”ã„ÁíKÑ®+EÐŒïuÜ„·•'ÇauW@ö"ײü—6ÿJCÈ?µ©‚3+²<Ä¿UÞ$›]ˆѪvé.øJO^üôó ›=ËÌ0èªÀ^rèäï[­Ï—•{…†>n`óG‡dûK¾  1Ò¢Ú™ñ‡¾¶•·œ4_ݔۇ¯a«Dä¶£ÎBcÖ$Ǫ¤èÊ÷BÜO¹ŽÖqQ‹ZÂ^2ü’1ôòøŒ£×ýPïãè€zÝÖ=$‰:òÍ×jWâì=Ø6lÓ·kT¿ì†`œØÈ}ìÆêCÖyžRY£«û_,DÁÖ–0B¬3Œñ¢Ê ·Èœi¡þ[·`b¼}«ëÙ¡\܇án0Ta°M)c-1ê\:E…àPa¾À+Úåo DI¢¹¢¶râI« :%Dÿ ÁOv,5E×3û¹È yÒ¿k!¾(vQ_;üÞK~¨\„ŽBº‰:ýáfh@—¤m¹$’I"ÓDò°ÌòŸôeh7XddMÓ.sO¾:¡šÈ-ŒKÕõÕdDZ‘`Nþaöð«~¬ÄsNýïõõã>+ÿ -eábþ‰”ÊæPÓ8_¿ûj¦Ñ¿ã6âÍ?§–@2”b/{&=¶BðU ÒÜÝ~ûÊxE©ö£fÇBð]„šMœlNž]¡a漎ò€‹Œ¿uuY…Ó¨á¤Ù²ðv8"©‡ÂY’Æd™êž «÷# ë*åj ºsr™"#¼P®ˆâ¸qa|ýÕX=™êf¥Öb´>9*ýìù°98. b í·ª~ˆ_Ðî„ÒBü8èŸÏ›âvfN ÷Yßu>¬XÞï8p‚©ôæE§«Üá7É>ww7¬óáb¡·£uÜ#Š\»ì¥ÅÍ D%‰g&©|Òä «x[.âDwbž`ý»àM ï…Ám±>ÅÔlé+y®‡ærë}ud¾³ýƒìª%fàÔa± ·-©b Ì BŽw™^õ~ù[¦è?y^'ëýÔŒ½/¸”=òm’Ê)ïÿ$®+È“N¡=ÿqÜœÜjÑôŠ =šKGL»ÅR=sJ5‘åóç;/»LQ i¥ÑõÛ¼øÔ,ØgôMgµ)¢ðò°œ$uëâñü`ÛðúlÛ–FȯÖÅÉ(­Hx¾O0*±;NãIS‘TÐÇ >ÇóCÖ¹|±'uäÚÖê…-ÎŽ²F`”¾`·Y¶ÑQzó¿Á ¶ôs]×sFC<²;- íùÈÆÕ­ójzÕfpÓâ QèŠþŠ}óá«ÇÎ0„KF=ââféDä´‘æ ¢ç.ø:v?éñ§—t‚±ŒÅ›DAËÎWLîÓŠE±þ··M8–ûœÓâV§°H×ÅJuÖ ú¢™iW“ä\_Ktïä§_º›£gSjo›gÄ"Á¯½Óˆ—aÇ0 nÙÐKfJíÕT‰|W_‚lTüö2´ ®Aî‚úfÕ(̲Y‘ýÛô<]” knjç#paÊ«ÀGeívÈŽ­êó‹á—¢øý ŽNeîr 8fàIÇ«ß÷“ôs¬Væ”$¾VÈE äºðWI¥Ä·E~kÕ %šè.§[º†Çn¡ŠïÙã ¢GJHÚÙû½"‰YÞéÖ»SÁ—WÑ$$‘£ÇQ¡ƒx•ãK×ðô%*iK×tÞÂd¬üµ¥þþåjÕ©1a4äAÅ+xx<ç׺ÆÌl„_Áeiœ}wü¯r«Áƒ3X3h P®‹ùÂÛX W6zÛ M"=íV3_¯ƒJ?Êy¯q{3½Eþ]dB ô8´ºK:&v dDÙ­®µµª`"Tð4VêkyYyÔ­¡ƒi¯fUƒè³TóÖc„RBB-`˘ëvuW;žbmÌ™‚'áª/ÃmmWŠêïBÆ¢>”p`_„wöiT(l€ªúç’õ•ˆG‹/)ÕRËÜÙë]÷|™ÂŽM€–³¼xº¨šà+3âßÎzU>ÿ…ŒŽOrB™2ßɰß/óSø¦ÙÙ©ÏaX£H£úE˜*"„&ggC(8åø£pˆ²ô¼—‹5¸忼 ]<Éþ´±ú §È =$¥V– FEKðNnšð éWx×O»8é?¢¾æ,>`Tˆrps®¸C`Žu;Êc·ÞÎf}÷ú[àÂá‘A… ¨£l¿M±Ô±È1’q¡*¬CêM1µ‡vf ¬D ÍöáoŽÀJ@#.Xzo¾n¶^R‚˜ç_BÀRdcgBN•0Í Í‡§'8›W·íD2|—ºðëÀ”"…ͤ”6k˜fý7âÏÒæÄÞ„«#„LÛRõƒ—ƃa }g²Õü|ˆ·UŠiW‰E?þNÂ^“5lýPõÃί\z,`µà7X|†m±?Ý’F±C¦_ö•³yh+´+”G²™:¦Ô¸Å-´Tö7‚ÞHi÷ÿíª“2»”m·Â”XHÀ€E1/ŸÃZvÚ稥¾¥|T\ñýh§iG¶öeVk‡B‡ƒEI¸‚ÄøÑRñyؘ*úË£”¨ÀÅødîº%×£túA¸|p³à‚í&§véóùø…5†ƒäõÓ9¡—[ôà\à^zV4¡ù ¿å޾1pué4ðÐsÙšëoþr6„™ ± C#M=“"óx€Ê‚Q•1¢–5ÕæÐxÃ󽂒½“ï9™ÁÞøLŸõw¸€‘zhG,M·õZ…ó+p¢¾( C¬úÄl Ù]Þ ¦OæBƒ†í–Ã+Ú©.e`ð¼\¯Õ¨™b@ÊåŠfè ’YÙÇO3ˆmi’ÈÖÍ¿Uv­)?LôUM¯qÞFÝâúº¾®–¯«¸Ûè;‡êêCõtoú»ý]›à¾~Éþ­Z¾B_«¨Ðõ.+Rˆ(šg&Á_0Ónvîòå‚§]€¤äžñ*!õ$ ³mªÁ–꫞[÷‰?#»ö…ššŒv¨ÆõóçþÁ=FΙ§G“˜¬õ¥Ôyo ˆ‘PÔ·Ç™¼(²&à¤{À)yeŠlÏåpÀ=†ë)}x_9Øu¡Á=fM9ÅŽ¼!šú´¶w‡(þsä‰lÄcÓÅçÍjîù‰Lh0ßÊ$6ÕºÈÌÿ}Åß÷GfÔµyË'Õ Í}áüãôeiU¶„`â“’§ùhzád{ÕÔy˜CP¸÷@¢ò{# ÅÌ$̦$²`3˜ä>“™{Ÿr©9µØ&™u¡òÎ"O¬­oìÖ–FS [¼sËD-¥4¸pvY:áÊÎT XÔa[ÑGxù9n›ÍñüVÃ=R Ó[¨Æ^Vϱ]qW¿¾Ä0AôÙ¤·ØÃqÖB+º@;sWËp>_½…Ôç¿€‹,üi´à7–‘¯qÛ»¬=+;¯Y%˜1¿j†A­"úÖ¤=Ú4ml;;Ç_d¼~pÿe¦5`6œ(‘½ùÛ`H£4nb0¹êöBü¥ã¥<Çy4ÿFzŽ'Ö±2n»Š€ÃL+3"›ÍÂ?s?˜~uØî—«Ý«ý¼¸ÞI&MŠ  Ÿ¦ w>›§E¶ˆ#QåÌܪTÌèU™ªù~‡‚5²…u}ýcN1—c;Á¢à]Y8âŒÉó lÉ¢hΰ¬@‹¤MÇ1ŸkæÔ6*9#&¸»ºÍK'¥H&k­7Ýå¦ðèmë#Ð=ª·ŒQlÿOW˰&|‚«ØqÓÿûzLwdÔ‰ËêñrÛgX”g[”[{'EV;ÁlÇoi.@N™óÀU0b#g4s¹ææ˜=][â;+³ Ò: rÐ5ˆlx PáºécºøfP5ô«]fl!ýp«3ÍÛaW)äÕñ…»Õwì^v×w|žÿkøº°à™ Im‹ÇzŠ_•éí ÉÕÈ¡%°ø¿J­+D¸D¼†\4·è!ÂÊ7Âhž¼©"Uµ‹(®ÇQZV•æj•Sà’d!0\»xJy æÁmk"p̃ø_%»Ž­ÃÌœH¤\yä1`i˜åõ¬äK½*,¬Ýù9Ø¥¢soL¼ùE>Ç„ŠOhvÕË,ÐŽÞ2qådؘŰjØ×Üë˜Îû¹xþÓx€/4~R°q‰e—äÿLd)ÅQÑÉÔå²ÅæÑ+A¢”΢d$Ù.Q¿ío@åè Ñ#@¾ML‹QAåHÄ5½×ÕzvϽx9ùЪÿ ¨Ï&Ô0AS#Is˜‹ 0A–„ž¤#&­3R ©®ÿV/ð‰ê6I xÐz"ÓSYøçùEß.feç¢M˵žoHÌ7 ×ËSü¡oVs3Þ›ç£gi"I™ÕXyT‰V‚9wGSü eН>w¼©¦˜ ÇWhÐÀë#G”ãÚ%A‡3%z'ïzà&¦á5Žl I¨EŒ7÷6ˆMRÇ}¶–ÑsÊœ–ºzÀ¦ëµiêFN‚hÙ•äLcÁ>ã–Ï€ MB"c8ýJçW±WºÂ¯2PžEʘÉlY;[ÃWETKægUÜ…ì÷„ˆÁ wC7Fàï5‚«!|•È+k­š5§bÐ/ÌŠ0džâý#žM•¢`(õé<Ú’NcCkðÀÑwÃ3ïój …¿•fCÕµíÖÓ… Üé eeÚ_û¸ª¥‰Ê-²`e¢¦7ÒÑß{ÜàÂ;’Ú»NI¾ÊÏJþÛ­Œ›ždâ ]Ç ìÃܬ)(ûY¼×ûÔ¤½‰Á–få¶)P±t …~Byn\>ë2›¸’É—éÀÇ‹_O!a‰OEt§ãiƒ±«œ‚‚ñI—OêÔ%6hÑ$ ŒYÜ2T_ y9¦ª?Åê3"²•yì$‘ŽêX(¡C¾/t'®>ì‘:k8DŠ:çÎj'óWoë†ÍÍUç¹ñm^‹ít ßõè,\Â|{U¥bv8ŽR··¶j—Èv– ÷n÷- sÇÝú¡#’oØ?c\t|ö²"mçN6÷"÷¢¼Á©ý+ ôN8Ý]w–} ЋУ¸ü•„‰u`Äî{T8Øo4ˆ‰bÍjGý>꿲‰ÁÑfe5U½ ³ãë‘«#mßê»9CÕ{¡;K9TþzcÃóér®Dâ1X”‰9zºïzgr\bu Ý}& ¦aw[‚ˆÜn©ò"}½¤h M!]ÛÜnðÅêV0𘆈™ìXx†üœnÑ-Ö^{ð q\?7Ý£¤tµö¢ø¼<ÈLÿ~ýòoÖY×\Ö‹[§fžy¥^+ì„v¹ÆŽ0_Eëým@ÌÙÌè†kES·ö#LÁ>ût‹ÙP—bÕK°ÎS/Æ{Ž%Žàû— ˆjãg8‰uñ®®JóòkŸ´ ?Œ7Éa?¥‡w÷>Mg{³FÌ¡ÿ]§·"ÂÿJÖ?ý7æ_n¼Wi˜nê ëÄ™nã:IŒl+ôÍ®€Sc”êÄæÞHˆÎ.y!ÙàÐíº|¡=§[f®‚®ïܲ#‘fÜDƽjË›­_gÎx%Û¸v˜„™B¹{mf‰û÷$|ò*ûß,òWø¸¾:!ø…¬åÿ‹>qÎÅ =¤;•¦íá×Ý¢%åA«áwabªÙIy²‹u%¸4ìNyKô/©ÒÞ·Þ-àR™k@"\ù³žù;!ÆvO¥J>GkjÀ(aƒëùQßG3Gávq! ÐP‚pMõ&«DØÃUgÎáô^ƒ0ôP9Kú.L€g©Áp,byæ?òÓªéh3j5Ù¶|xcl}À³ËÛ9îdz _sì>#ÇO9ÿk å™Ã„­Øã5ò˜ ?ó&…ÌÞ!»Y§s‰‘ŸÏtÞHÊ©ª±Üh£’Ö+o§Ð&±Ü”`Öà‚Öy#øÙa£MîÙÂv¥ +«a~¹ßŠNúÙzçÐÞwÏÀÿOa¨|‰#|¨Šô·Ö†z‰1WUòØŠÃùÿ µ5ýIîÈñ‚D9g ÒHg4›C&ˆRŠ%„¾Öñ%“Q¸þe;FãÑâôll]ÆÒµ>²ë©DÉ)î5zù [? Uã„ßÚ"½²ÙÉ#<:¤5™¨3y³š¯Îî¤àÈ#f¾ ó#xWk\9‚•#˜mNeՀǵ°e#r;Nð=TªÕÇ1-Œ­6fœŸ°LlÔ•Š•ì%¸I3&ŒÀDmþÉñ"&ˆÌ@έøHýœTFœ–çØTB둇h}ëlOb+Ñ#„}Ž÷ÒQ<^ÈS;ÙøÚó†´`Ì2òe<Ì™cýÁg_DÎ%\˜`ù“Åãk ·¼Ö§gû'ú¬™b‘Ô‹T¶Zµ4õ(õ:”K%[ÚÇ]Ðpitœ/†•ì³3G hû¹ëY°x]ЧæÛG=¹vîœ0Ú†K’K Š,C”6504¼b=XýV²WN¬üÑš8t-¡Þ#JΤªÄ”Í¤ HÑlÀôÙÛ^ý¤ª8dÅVa‡Ö5è­iãÏŒœQç )B}ö‡,ÛCVØ ð€\ §&Ÿ_(ƽ4Äuf×Üø3HTiÇH^|óˆCe‘D.TNöì‡Î½°êe-(¬‡<Ƹý×÷Ñ”çñ(î$µm¸™+/ÿ@ ÍÜ>6Œ«¯çïÑÏϲ²'S¥MÀZà$€Ö(eE®;:³b^îͳ¨\ºJQ‚(¤É ê÷0…-?*ƧL.5·éqèËQ…‡…,ýÒm]æÃ¬·yؽgÒí°¾Ëc矱»nõžÌ2ÍÀµ™9·°5ãÊ)©‚Š‘;ááëaºªÄäsz &v‹æ.…J&…k.­ôƒ x‘_ó@ål19 ¥$ÕÙ¹Xr.1Ã0 Éx“X%&8€‰=ÎE^däU-H¶õÊ\&Ù«•ÙDÊ=è‚°Xy* Åî—ñ—„‹¥-íœCBjÎò¬Ò® ¸Å½¡…p“÷î¯q2—ÆÐá{hÐ6ügæÈn'÷ÖÙ4\÷÷ùjŠzîH‘WâÑû‚Ø2ç y®˜ð´J&‚¶ðÒÉR’u篦 ŒÏ%+PîU59¨¢šÙ(mܧ>ûTLú;“Øcîñe[1¹Þ‡:*Z þLцŒ*/h…é·q-Ì7q¡BˆòãAHzåòŒ0uĀ϶ºùÜ‘ #—S°Š\l¨Ú(>Y<—'ëÚ=±×mvB½pŽuÖ3D(Æa~ÒÔ‰ Ue÷$‹½Ë„ŒÞ˜^*®|¢&uoïæ¤ÅÜaœ BX'Á>½¦Î$I†àCU¾­Sõ3Xý ]‚lgê(ÑJ9ÙÒ[‘…@zO¯mTÉcÅ•0¸ ¾ õç»CÂe½Uê#|%}óàÈÅ5ñóÝ|€Ÿl¼ò‘ï©ÆO+µª@¡O­fóÇØ\aq\(DBhQ¤e™Ö1‹ þå]Å^Ó¥â÷Kpµ$Ä`Ý;šØ[,¥z0/é×…-¤VóS€¬$²Qm>ÊÐP€ƒvã•W§2•{çP~ãf“j0DÐc5ÙR]މ夵œÆ¢/‚•Õ0 S^&ƒ–!ó31.ñȘ-…÷c0±«’ .:£>ÏØÇQƒª^©Ñ#ÞÿC—óKGrŸ2•Þ­¬ÖÑø;ƒ1:S‡¦v¡¸Ï]Ù¯ çKIĈ|§.'¿úè®hè=có°¶"h†ý£ '…ÛHe‘Û>=fÔã/->¹L••!Nç%´Ò»E+!\¬èÚ ©¶­–7/F˜288ÛlZÿ|ƒ¢Œr€Q퓌#vz§‹x]$â4K\.©åÝñ|OÉ&ñnì.MªOhò«š4N˜eErM‘`ëŠÐÅë‹y˜Ä6 N:Q°×LŠòMç¿`? û8åæû#éT!æ—ü ÓJÁ|ÙS>®C2‚DÃD§‚þÿ3Sç¬%KÊ>`Â}èåZŠž9ˆ´pTEMÛ]„Ђn–a)mÙ å–ˆo•Û.“0àÊà3–fŠ£L¹CE–Åâ3éÌ£ø—­T×_†ƒæÇ}u/ù¸Ý}…>v!äK>Ú\ÊHâ°ÄÈÉÿFï8ü‰Ik´Jà­P¼€6EÝ×ñÇG²”$y¸¿®bþbB”¿»Ððµúçt̉(¡“ä8òûˆÅM°¢õWÖZ…§–>G ¬^æKæd.v7ò]¥؇;ðWæ¸BËj€ˆeaÎ[×—"EPR ‘ú%/ÜBÎôl2µºöù>öØ %w˜¥Ã=ö_:QTÈA¦‘Ì´ÏT-…Ñ£;ñU´•©Jd½¼ˆ™-ïNÍÐm¼58…{4ô{™ñ&+½ø¯'ª½s‚›e›G ƒïtº™rIðùmßÂwší[=ýêàƒæPÓðT®äI¤õVvZÆ[AéOzºÓ ’&ƒ»ñ•ù±ö´Ad‡ÖŠÃ™Ñ´äùãcÈuÇUƒŠëÅ¥&¾O”Z*&N¿S-GW;9ÄF–,w¡ÿ],¯âfíHƒ?½×eVáˆüäÉö`R'Ò¿|³[wôLƒåcoÄ`î`´6Ë ÏJ¬%Ó4ªØVád0OAMcøÁMÍ[•"5RÈíI9“ç»k%àþг ˜:ö›áP {$›^¬¯S-êF}Z†•šKAÔQ€<›mBvWëÒŽ¾ê¢d `O§váðÑæJO·®W&„ÝŸ~)y8-Œâ/ŠºˆûdrY´ t%„.:zãEt¨T†@`æ¸p£ºsÖÕ±œ\Ñ›½R•O„nòY†S°ZÛHRë/[ÿ9f(AUéýk ”ú‚»_È V”üsÞ½Åî§Ct4™·ÔYݧ(::Ð’Ú×#HïBí)”ì;½˜­ƒ=ö¹?Ô§¸Ò  à×Ý6}Óªµ<Ü@µÌÂåmUÀØ\ȘÖw/Ë¿¬ ûÖ ™›$Ç]"bkwXÎÕÄçÔŸn0ÃÈL1êªéPvÍl–‚'„Æmä¸ZZ¾2‹bû(ø™n¹Ä7zÐŽJÁi,Ùfnê? ujÂ*)É}hD¶jó¿0@¢txÍ4åÁðèÅ´€¯#+4n˜ß¸§åº‡j¼>l[fœÔ»Žhp[”ã—Ëz¨¾Ù+ýM¥«ã?M#0·Å`{á)вZ”=äÕœí&ðU§ñ¹Ä:nUN¼8}šsñøõA&Ùš'Òr¶§OâÕì¢;}§ÍXof‹nJäÞs#güGpßßkžd§ü½ìyFáN>töaVE±]ÉM@€âÏÐÕ¦Ù^ЖïjÙ–ÐJ xJx^x•Óê8S«r?sG/ƒú¬ø›ÚÂ%¯:Ìö÷by¨%7دr+yFÄŠbIÔhƒ–&_"ñeÁeæ-+ =H{,¹l写òsbñ¸r ÷°üCYc›Åv›\RAÎÎ`à6TëAÛÅfŸTGICY;\8ïgÜNä? vMNPx²4 µ–Ï,4“aM¿gXkòÖL@å…êÖ9 Kšâ¦ºÒcºçv:ZËFÀé}/Š Ä– @·XG‰ ›`Yñ(ч7”RYY,xR¸ÃȺDÎ:þpÁìRüðH8ɳ–™ÿ%sv©ußÚ±BƒÖ=%ø•ç2D3#3„l9i@uVi"…pÆ^O»RxLm³ª€%2AÍ´õ¤ú úþ¬™;~›Ém6ˆo.¹0,Lb/¶ÒÐY aåý‹Œè|’*Þ >EŠwóM毬LÃTWÏkOXWt=]I´{Oê›kótÌMci‰©S§¤71©ÊfᳫÀÅ"¸Þ%•ÉI¥ƒø 68å •v¶=‡šSgÞXÂ;^>°r ¡¶0k¦…ðY5=ù°2ÇüzP&!õÜ‹ÙW§J E1ãÞ%ERTê†.¾Æõŵ&R%û*Ñl°çái©º;,•ç râ€órâº%µ6Qz›’È=5¾©Tï:87Wÿ(ÉÙ/2Éh‘j³¯Â[ò“rJi¹t¦nY®h¥*yÄ7›þ¿éc&AæöP‰ïÙ³³±ŸÁKCYµšîã=(xd²†eŸÔ”;캦]¶ÂQ`Pòb\†‚IêøïeP)Êd|'ÈqN|óÜׯ/ò²yÛöÏ;!–°TÆ {–…o~#?]7ÎÝFÉ%ï·zs·‰ï»x4­ ô0v´ÞÛ‡Õ|¿é“]‘ ž§mw+ƒvQé¾Tß¡x,Z“näGcù3…’Á®0гsÝPÆöä:™‚³šfÑÊ,l™’ý5Fw@u%'ñ6A×€K’sRš(ÅÍUÒZ"a¬OÕ]ݯ݌‚n~ïÀÆ(ßåÎNLk ­¡BMj*±ÃŒÝ2¦Åè Ÿl²åaqéht3fçM†ÜéÄ”ðˆO|Fit3¯%yޱÞ<¸éŽý|â/ÚÂèÍsöFkgÂÇ6ª7ôcÒÀóš¯_ç|8ï¾Ì!mCNü"EóöSú3Lästš:Îøµö{ÅoÄ·–ݖרROsœnÔ0‘gÍtzÆN’|ÞQl/ÿ³­%Ô¨Í ÙP3›z‘ÿ2fp÷Âe9Åך)ɪh½ÉgóOÝFƒù}ƒ.ßfÿlí g~”ÎZß]·È´Ìϰ#øŒ½¿Ùø½;~‘IlFUhéHÃê4m[ÏæŠ@”Y81¸™¡t1yŸ€Ôê‰l¨«¬h¢4’a™,À¨‡‰úÒ™0)z¹.Õ¬¹O˜æç`2c_ë·o'®zwŒuZçw&GÌ©Œló‚îM<áæÀE²…Ðo:ëG@’GÊ7 }¢š‚;˜‡ŒŠÃè8nPD €¸jʶuà2!éÇ3EóÇýËd_Fs Ê °üýÕ3–âÏ@%$ %š›ò*&H¯åZ÷øàBŸk„)B¶˜f^?ÓÓRÐqµ*ê-í?Ù­<1´ëª4"ø®<&ËL½u£cé[ÐÕ—­?zEŸk}bÿ2lu‡Ö ÄZÈjã<+¡Z,!aÍX€ð€ hç2–Jæ@m±YG3€‘-‡Ïj¯Ú*(fÉ^Šß=·)ŒaΠœÒF*‹3¿j„&r—ªÿV¼DPt¶¨°ƒ/ M*¤ B xÒ`óöc½¸1÷”<¬$ÿ~ Ò«ö~•LÅKW`ýòÙ×aâERõ¢ðøë•Ò+„ˆ=º?¿É–Èüû1qݬ¨JÚ¼{Ž._à‹5„ ûÎ4òýOå*½Ë»1åÑ}&E©ÈÔw4_6š±) 6cRB:îÁh¦¢ÚnÈæŠg T\š'êêÆ`¯žQ΋á§Ù •4ÿ%•à ά4hŽ*Øã`}ç>ÁäëͦÀ† ¨òÒžIùª—mº@>¿*¯ {gD{@ì.È}×iÌmö¯  “ø¼7ªùyèU4-TúÕ2OÔ!m¢L/‹¸úËn½†TËÉ‚4y̽ôÚU®»µÝêË‚¦"’W] š%`ðŠ€ÌØ}¼;6ª%4ŸôŠÙÙ©ÏaX£H¹ "úäÏ©4„á~õã|ªTj;ׇªøúI¦•ÚÝûÕäÙ³é«âLòVv€Q+B]wÔÍCWõñBtµö¥{´1ŠŒY_J¿Xx²_©‘ïé+§©p1J"6€ïBšhÑy.¥5–ø ÉLØ1`°Ô—Àq¯cД)€×”;\ƒ£lÒãU?õ2i¼ÛºUZ†‘чv*iÇ ¯lKóus×b4‚hKGB6V›ó^a/pQõÝí¾ÑŸÆ„­Ã$9j‹ ˆKsôx¦˜lô¦tÒú=tGÊy31$6Êp:öq ÎáuÎµŽ¤i\´õ@Í+wî}*,Íø’«cK9ÔƒááÍ1ÑÈ«HMÅßdxóãOŒ`¯8Fqã¡£D°ßË2Öò™ò¶¾[÷~HŽð·Í±ôŸÞxý”WUE¶#+•å…KleKg€ºe6B¿ÚÚ~å;xZ->×Wš‘íá¨1 Î9;$ÞÛì--ó6<¾¯QÑî»oj‡ 8 ‚a_{iàÔòmw(ñŒ+2¤i‰k½þ7-ŒU‡ð!Q7Ö'LÛR¬Â›{ã/³³{ç­kì=C5® ê€Äw#©AçÑê»Ú7┼ZÚUqÕAC)ëÁ±ßç0ü˜*6pÿækþOj¯Œ1‚gºµˆ—98£vPš {º d¬ÈÀüV]Î#ô9ìRýîØ9É̶®1=H¶« cײ_²v.ìá¼Cs£lå.þ$9gkþÔh,‰ü„Å™2æ+ÀÿEMþŸò°Á‹-{žLÎç{rt»V°ÕÓÛ< 8  ÓŽÛ‰gÚ!¿.·Å¡çûKâúºÑý½-ßWv¿·½¼~Þ¸¯«§oÛÚÏíë¯óö¿óõŸóú-üþŽÑGõ'ò¦ï~ ©fr©ò®^ûo(ú×ÂAñlëò4Í=eZ#n ?B*¾] ©ŸHÎ1%téÉ›¯it -Ì“…·ÅoÝJ0àTÏbÈb;LÎ}æÏ¹e•Ïà9BŒ/H³#h„”V„–ø_ûÑ4_Yúž³’B]YS¸Ü^ú^Mr6,Ññ À§Ú‡¼ƒbdÁ5àÚmZsfíºÍ]©'4 îJ Ƶ:Nž•NmlŠÌŽ$ï{¤¡”®úeã¥êÒœMŒèô¥›€£ÓoørÐÝ™Tª[hJðE €7”‰‚HF[ÿzÌÈtºwÛ[1¢\áL¶Edù¿€ ñM©çþäÞ³~™ ›cèjT.'XCºCm†³j=hgÞÀìk/±\Γì°8u.%²ž cbm^Ø‚ÁëvŽÈÈup9Ûu'B›¯/§M&3TWñn+,õ0–¶l•À”Ÿ…_ÛׄŽÉb)óȦqJó+Šþie‹ÉBÕ»°‹°q`圧/Xäפ¼pC²AV‚¼ZäH«†` ~´ÌNð4D°Í„hº+~|2°y†7z’á'¾‘rD¸åéãc[œ.lè‘g=¦ïCë%CpòCè54nèú«‘œb‹m±¦ç{ÀßøØªÄ ítAÈ€ÁŸJD÷m9‚ùµSD½ñhn8Ö¨ÂÜn›3kæy̰×@¦Ðëà )ójuÚ ¥díNèEHôÏ)\\ð¯£M󊛣~ž¶nž€pÔºô…6§-œiøt(>¤ï.#¡ªÞWüXhkýïŠJƒâÓž Ðê k‰$ÿ„ìq‡!IÕJœ|xR“¼/¯™º7FÖx½Š÷EÞë®­ßÊå©ÒÑ®@wå|™‰’‹öÄ|‰®x›_Êön`Á7Ma&;‡Ë·ÂKcON|wGÉ`ï/À—ú=Ô,¦¤«.66û8ýÜÒâJfWaÀ¼¥‚Æãº)v(ÉË ˜._å·ð_ah*G˸Þä€È6©è–W^Î ;t¾“‹Ýp9%vâù&™ÂæªÞïŸÒ¡aÔ’uŠœ=ÎæÔ·Ÿñ0^u?ýõ.ýÁ0¼’Š_wŠS<ù]SÒ£IòlJ(jE+ÇJí¯ôž &8Tw)‚n{—Mð€è[‡É c\¬…jÓ‡»Í[@žš«`Ñ#‡ä4àä;90€RE`ÁÑdéà4Xߨ –îúÐFÕ Ü.^¿¸‘âÕÄY/Ðl22Óµ'4º\Gl33¹Ü6Ö™ÿ†òSA‚æ{뎾õ‰?ÅKFDxé©iN=üSŸå"˜û¡gvîÀ98 <œ\pOMÚÄowß™Zì˜õîøÒÙά,@N0`ø‚_Ï,Jj (EÏC«lO/%mGÄ7­y(ߎðã–þôÓæ\]A±f>Ùòãí…VrY½÷‚ Ü– áÿGµ›ºÚºjx«´69ôh”¨x˜†²,ý*d{äHã™L°‡ñ?ÏÃQ[¶¹ÓGNá3™–ÈcÜU¦®¢ÃÆwÉѯ¤¡p¢yqfwU_Î@ƒÚÜ`Iáw£»ë{߈ˆÿ§ ùj‡÷•º²ûšî]òà¶r4Pùk'çÍc-È8B"_PlE5H2ðû5¼îM¡45 9™½/¢°Ì‡Þ^_WNP÷.§:aCâÐWká[ Fa9uÁËõGhhPÑ>ñ/Ï“bt®>Ϲ¹˜I‚ÔZ8¬4Ç IÏ¡ÐÐÉ ;ë5ç,Ç‹¸.kØ0äÁQõ2Ü!]ºtº˜AŒAp˜+#Wì%«çà$¦6k•ým “¼ªü4ކ¸¯?Úyljƒ]ýÔð¿åHÏÖ6ÀÔžTˆø—Ü~ƒåÚâ$iÕ§yÏžãuRäVÆ ÖÁ2w4ϲL®‚˜_§lç¶p³Cc…åž{@y'J(î`¡E’¬à+2¾*I —ïÐÓŠoÄ»¸ ƒV„xœO$ôÈr\¿Èb!¡)í©èU(Åhœ!´fDPcy4‘$ÎË&*kQ šc^¼uy‡tKÄ‚ŒqEŠv+P&KMô^^9M“Ëèºná¸Ás²ÈI¡;èÎlO3JäGÇÅÃ3ŠIo\saL+Bz™Ðºûy¢’,)Å@| ÊáêÓSw«gnK \ðå²~xY“ØÐI~Ð{vÐð(»¾Ë2-5ˆŽc¬Œy}·6h ìü½ùƒû¼hÁ–T¹VK¬2~õo¾`˜¡.دíBJ…N.ÙÝŒ”dµ?þv&ϦÚóKF#ݬ;5]¤,R¤×¨©òèÝBG«¡ÓZ¼É›‰¡ç’N'}i>Ÿ7õŒFœæ·ÓOî:A…@`˜mdèb,jËŠrÚ±ax'¹½Î[±œi°&ÿÝHææ%õuÁQF£ž®¬ÙÃãx‰ú$àbÀ4ö>KyTêX Td•Ö wåÓ$’p"oû¾ˆ"ßAFâW”=ë=×ÿD\—¡Æ’Ž7„Oͤ$ÐGüE@ãÄ-KFûä¿Ê2uO˜3ÉdçúAŠtG!¨È>´Ô² Â1p—½L—÷4!dÊÒ$kvdZ…;$94¤Â3´×䋪Ïçãyv,쨘þÞì6iö 4 V/ìP´;Ž@†žÔDXßTòÌ#ƹà¬!M\Ř 4¸­ Èò0îùC´ãpÀ™1¥G]!1ì| ¨^L°wŽCPNGò¹@#†@’µ¾F Ç‡É^WX…Yû•¯ž ¼ £íaÏ¥J7¿†úÝm?×f•œ°ÊÎÍÌàZlU‚@¿A¡·•j š™àòåÀyh’ËåÇ}^?NGvÅîQ >Ù ·È³mxò¡öÖò>iZ¤taŠ¥A¬°º÷½Ac´Â7¿µŒ ‡dà13û÷1ð‘§ËÒ”¬H#ýç‹yx/)-Œ„U(ê>ÿ>^ó‚ ýEY÷Ú‰;ï§O G_3»&­‹ Äÿ„dw‹ýPj°—{‰ÔñÂeâÁhÏ•gZµT¾(þUà°)Ö©5qÀ|§®‡ `1Zÿ.Ì&;»K•—€Ïê’jŒ?íKs©‚|'r„71óº˜^FÁëÊÀp}úI²Êhp]hxHÇ{8mãøq_o:Püu8Ì'1/€‡`V±T¸œñdjŒgGìÐÑø»rœ"£øFò­:O’ö]¡X lúÛ«ðêKTСµ¦ ‡3‹,ª×Ãêì–bBzÍs@W>/ˆÎ5P¸`®^”¶fýs֧вW7êbÔÄëÜ0ç¯\K”€Âz¥äƒ—\•#@Œw5k—»·aëŨmâþ¶®íLí¸rÖ¤´Œþ/Ö†,_^ã¬#qõýSMgs¨n½31ÒѧŒ§ÅÈ8TTýxÆ¥z“`g¹" sof´9:<¨/×U€è¶õ¦Ûm·S´Ìx‡ HP]TôŠR·ó|ôƒ’逇‘SÏrÔMý9’nJÜH0×âï"Æ«>œt«Þd$üáÔ"\ÕÌʱÃ`JÒ œ¾ à1¹ã=vRÍ<ÐÖdúÓ(ê6_µýæ;æÏ¨Š—r^Ý쵦‡–¾þ(èºÑËš?Zèˆ=ÞYÉ€1_¥•ÑL¥j0œ ŠkYõÖuA õ 9SYd(2žD§ÿCº‰¬_m ÓR8I¼³ËéqÒjŒ·ÀuÍÐ1ôÈÂCG’F•;³UzÖ,µ±h9Ë îÆ1Q† «Å‹ ÍÍà0˜É‚‹Swim¾êD(vHG'í÷Ô¦ˆåýÂû:êª:ÚbG“¢©Æâ… /ää¸}›3SVúy›ÓR£±4…Ü;“Õ°»Ì­¬Ì/ð!3”¥(È{|–£›m¶Ûu¢«àp©‰$’I#nýRi´÷´Ãý„þ6nVc§¹f¸ûbÈ ~”5œ¾h³Ó þJ¨öݳ€z’\”÷ÈcŒãô9¶^ÛõehBgÐr÷Z ›{.f1Ájòb²c´îðQþoR¥±mb,øbA`$ÿG¨êˆ’“wtɇ‡³ê]W@ÂÌth¼2(ïç̤[Ùýb<ÜX3©Âaƒ ˜fÒ{¡sÑù„{YùÔVHô«i.ë€oÉnÁ¸8.€åuútü•Š! À;2e’›]èU¼II$’Lœ ˆW«^_ñ+ÞU€¤M¢ü‚% ùpüRL1éVL)ü”Ÿ<åj”i¸6ËE]MÆ_ÑR§¥·oÚô‚¯Mã´4°%ÓÝַÙa ¢«~Xi_IѶ`RZöýhgZ”Öµ{u!ÑìÝavi‡ä€rI$I÷F›Âñ›u+1M0¾â×Rõ©j(Uá·Ï@‡ÁÖÛ( E‡½—¥'ŸpU]•ë§ðÒpˆf›æ-Ç©ñåañe?ê3´½º*Õ’y ìu9›ï²:œ³j‘rÆÇE£è¯siç²1KFPÒîÃÍRÂJ&éCu·éQ>0…6áŠ9ˆ¸±$’I' gªÎuתÌZCx>°ÿ3íÆ=­ Âk£ÓæóŒ6ø† Z3î¸îÍ·\·‰¾%€b]È7`Á O5=¦Ä5g‘€œˆvËÙ›á&Ðýe´ð¸Ù·¿Uõ¸õôø?ÍÛm}¡1(£ J•GùJxs ¨Å<†ÈmŒ¢ŒåÚ áU“÷X‡§è*«bêI"Æ †ù #~4fü®'å‰[Ôm¶Ùh©éøëb^võ 5ÚRÇ&Qî—¸ òz æïðÖ"W8ï‘Ím9ü{ô ÇÆ8÷&„˜!2[ha¼Œ ·ÑQT0Ð ý:Ñ“c­lšK5Önð%LÜ ˆÁï Å—Šbåq3É!“”}ÉNéZœžA49_KðVšßxçšщkúJ §=»G¶Ô J·©pšÃÅg` k‚/ЬF j§/gû·À`ÐÛ“ú'r››‰5hãO°üL’7þ—[VZ£úr'¸ì=áe-}¸âdš^9Qó_Þû€ãõá‡ûS 59 tI¬µÈXຠ#Û,f(Ïìn!nx 6 É¡ä¥ÊÃ_¬A°¦-ú£XèhàÃhŸªA¾äYt#êlï‰Óƒ’½ΰ‘À­WÀoÍÝà⌡f¢»·ëxAÌ Aº’,©ŠÑ orñ¾ÙMRÓhÇ›Å" ê>ƒ Â×õ]˜.Y%~Ðì¸ðþ£+{3—v;û˜j€!<í¶)˜i÷Н«ÆÚÆÈºÒë[ Áwcy1Áë«+P’+uáÁÚ-ÔÛ”£Ýîgû†Ý'‚šD“h kT¢¯µ°„m©NZ³Äg2 I°Þ×ãU€'¾_)Ìü´…Ï>¥ÖÒŒŽnjŽ o`èsËð‡më,)ÐÂÜ‘9ýYAJ¤ž~¦®ï¶5ãEò_¯ÎóÀU–å1Ã%‘C€Û_À›=×1b½& x˵f^x°Uíñž’NâD˪ †cy?ù8‚ÓdýGXvêý”ò…JÆÁ&ÿiÝH²s°½ëŠƒ¦(¦ÄY§-J˜t#ü‰™PV¹*WÔê‡/²ŸÛ›¡ß %»¶ÖÂ"UãË{¹Hy†Îç-XóÙ¿žì6QRãJÝ`q¦ÁN†×ëò¤wI\ùùwK®šynäã;ž*$ÙY~¦Þ‚_A£„éÆÞã ºlÞO•"Âf A2ÈÙA›èô­Çï{r+FíKÆ1'íwD0*¢(ì£O° ’æaìr]cOfTˆD›³¹u†…°Â9’Û=mu þF†‚psò*>“mÿ)“à#ו‡°6@kdÔŽ_}÷ôÆŽÅ‘X¼;ÙøXù¥·U¬­Ù ’õóßþ$eù6æÉ»'…$> E`5éßi™‹4/¬mª–ãð„tÙa 뼇DŒ£œ“Ž‘™;†IŠw¦ï†Âs®@³p™ËþmpmRð,pár×ÅuƇ$Îôù}R„¢¥%‹ ÚxŸ«þê¢'fp¸[Ó«íŒ[F±\W¸ ȹ€Èúûâä”êõ@€¶¾'ü´‹ð©x¦=ÃÑîÊø9e§Æ¦Ø,d7Ë~Àòã15xŒ»=ÎYËÀ·µ£Ý›ž¼±UWÿyÂMI³uœÛ¯xãÜÓ™ûܰ%ý½˜¡ÿF‡îÝK0ÙèY*Y óŸ&ªïã.D:¦yû84îCç{ºïˆ r ïµÕ&$XãÝO^t·äδ-躛/K=üEÆg2éSC§ÎjìÔ^W¾£ôEü­›vyäïÌYÞw´Yç<ÔšPküU¹Í|š Ho œ Ëù'{8g&NÞ^“õaCè/Gœâ'¤Y;õwÌʆ‚z†gÐðý«aê´óaW¡Íu4­a‘lNýtù¶X ¿Ö€ð. UýwE÷l…oRÞ¶ÀùzCº²íš?K´:â “ 7/¤a<–áåiŠ-âS×Z@œ ¤l/x:Pþ6#¦Ò¤G\3ŒNºÑIß9~Ó)‹§r¨!¬[3nQ-ÉhäòùnÔâ”hü’I$’G­#¯ —t|û<\Ó‹ÂQW_ß º™Úú¬¼§ÏÃ; ªe½„ÃÇD|ý ïø  :’Gâî­€Þ§Ã'ˆ€97ÛâDh$«‹»°p'\u¨L²Œ—“K^;v ó–†Îpf‡X!?ŽãûZ :zõ-EÝtÿ@1ªh>—›cÝLÓŸñ )¶ÇIB†õ°0”9—mÞ•ìx-Êó&ì€p,Óñ<Údyí—Â)º Y5 à5ÛŽ2\»”šNò?€Ü¾ÄžçœË¿a±'tƒezPYXK3süuñ8éÌDcû©p¥²W±olŒåÔX0¡¯ší)ª@…§´‰papù­ÃfXŒ.*²½ä;DícçÔi—}Üá¾M†£ÞŠe+zNÿðT*ò(PwG˜Ÿ³v óïN²÷í1îRÍ :û&ô§k`F£=õ?¥´¯_5ÍÏDëÉ]Íoje¬[¢YÁ&û¹¦@Ü%Ì÷j:óÉ8Jž×·Ãg½ŸX‚Æâ§BU®›qAïMì½Xcè\Ê}ôÛ)18N+\Š|‹¾n ´ £Px9âWº˜Ú§‚ódÞó¥Ñ ·Þ¶(Òâ!ôþ=Øöò/[äžiï/Zt”oŒÐÖv;–zâîmÁ$}dñÜP e›ÂY@R¢£ˆ¼L©%hUo)[kÕYØKÑ—Æ`ã½¹ïÝJd8 ÇÇVÄY2²„aÕPf3RX¤>·dT‚}X™V·ŠIûý“r¶¤’ÿ?I4aÛª"†¶kÜ!1I5ÓíN)¼R!†cþÜçh‰„ y¶ß ÃRÐ8ûw<ÚG ÁÄUË|íOõ"Ÿ¤£?¾ÙÙæ¦p* *Rw9áIÒq_1 f,z€ïx=¥ë[¿kpJ” –ꪛ-´‹*ð2v¬‘†P%ÊÕoŽðI4žñ+‘S¨ÑøÕ—hk×Z šèÌP3Ì GF«ÊrPð\o°i6ÜAîºÌ=¹€N˜qžŠI0€¼ÖÙWÍÕÖø]'C£§´³SOdŸcú¡&»¶ï¼´âÆ5‡úª/ba4óõ…Ã`§ËÁÁ:Yäè3yø>áÅ—•#²\\£îÉ´ßöK7pð÷9øò(H=XŒK¸ên[5lk&ªÝnÁŸ¼yuŒüuÑO—‹%}Çð;*(õuŒR{<~Í0ßkö2yö'Þ}ÞÁWc³ã ©ãžÏ…‰DN¿J„ɧ Xœvº–Mn±ÈX#±ÁœH.ˆµll" USß"vC]# ÁwÉc¦÷Nl‚5¡jKÇÀòå±Õ}ÜHõ­ÖÙvoÕ€½„/È|pSˆë¼z’ËÿØ(ÚÔ¯>aF¥¦ƒŠ\× ó]ž;Ôó´t®À-R»¶eÞ ˆˆâÌ·œý¼\£0~—/*´ÑØ Q”?Ç ©˜6ôeÀÔ³õU>k»P~°ýÅfÇ^Ôß5>‚Ûr tTÞt3ê…š5¸ð•?LÆ4ìZè Ù¹_º¹–ÙÕ€¢þGÖ®"å]…Y“Ÿ‡$Pʉö¥1Nø»E³Eû¤¹Q¼”î]UåQT¸“x-bû‡;ÙÙ…1]ª[a“>(å,+Yöà3Ä‹I['‰þ妀âˆÇÀ³Ä5š0öw%’"¡Óþ3{ú¶à·aÓ¢X ÀF<~ªqä, ö†Ûa@IGGï˜é¦gżP›tN ¤²]¢¢<ü~S¤²¿Æ\iµÀB!Ȳ÷á_’E!µ¥†y|—Ä¿™:Ò—œ`° ¯Ÿ£Ó8À„ºîȺfô_©j}<&Tk¹L‰4çH»{YÔ⵫ܪ¡YéHwm?‰~ þù|»îô®ó¬œ»­Ì0k$yœ¡sû¾œT$!TÁvcæT?Q7=Fâ±WMŒ?Äu®Þyièué_‹ø""~vØ,Ó¹ú8wÎ’¶w…•¡\·°â¼·ø^ŽÖ^4zkÅÈç+2mgw@ºÊ\xÖé~…Ÿºã™Z‚È'ý½Xª>6s Þ®jfª †fñŽz®P/õüYH²ðàtl›×ê±ô{ݯhM¨]60Àê©:KÞÚ–ÑŽÙ> ž1¼ƒ&Ë€Þ,Ä Z1ð4O+NéK'ÿ2™Q>ÑÂû+ùI8”¼?㽕LrìV#âcÙ¤„#Ä’5Mü=¢×¼–m.t©i縑~¦B´§¶uu"ù«Œ-ÏÚ¿l­ªùÃm'æ›WQ‹»¹ÔéÀ'oˆ¬‰³åÖé9ÆUÄÞQa©M7] vŠ2¶¢»6e ¸Êµ¦º¦j¤cüŒÝÿJ=¬™ %ašm¹)É€ðo“JO‡nï“Vþ{/çíwçí÷çï'çéÿ|ý¨üþ†?Ïë;óõ’ù5eòwWó÷«óöƒ|—ϼ»äÜŸž‰|3üý©üý“üûÛ¾NŽ~~ÝÿOé/óôFù4Ýòz¾Nßþ~Ãp Ý>îÙÝÝnÙþÔü=ûø}ü=þáü>–‡ÚÃÖ÷u˾Œ~óü>…Úm¬‡F¾hÂ&H-eë€H›¹tg,qk^){xG߯<=Ys?ÂY·þY¸Wx飜dE»Œp8؃”~ÆCZ1ÝÕ˜´''¤ðL2ûOîÆëå‘g«€ ^ý ie.±KΓî½ùñp›©ÄÜ~ìµÞK`ë}N. -Åã9Ùmôáœ{Î }kÏøTà5rþ¯ëjDÓn&{iÄP~¡z“ÌÆiXžú“µ^déa‰j— ÜöR˜È¼c¶‚qk}°øÒÔk?§êfó;ê¡õØbš=åÞŒ&]ž¦[/ÜLürâìdVø>ÿG©H ­`fÃׯ y‰ê_¢ÝÚßò Q³1>V8Ç7e nÍÈê˜løm·oáÂÅDU̯@ÿüXôo3°âèŽÜo~Š®«:É!Eˆ&¨Ü=è&bêvzt5ï 1NÿküÆ‹ÐíùK ÁH®ÔwýG±òF+'áñ¾—Õ1§1hlP×RÔqŒôûú19Mn«·âŒêܸîk|ªu7°J;#ûÃáæìþÑ!Üx«Ë÷>jpv‘…û¿µwÒEì~…ÓŒ ÔOþÝxB‘ì+§R‡yKÏÁ¼ø²øä©aܧÄ[3Óøúó݆X±Àþœ‚ðr\ˆÞ§’_Q…0Al”-NËd3æP!ü`ÔXY|¬Ÿï´K§½³kÄ×Íi ŠûÏÈ…¹ä¾tì®áx߉D³Æ%,Rƒ}¹Úƒì ã QL±âKAéœßéºE1ãXƒv½¬ÇI¿´ …^ñàµ7Ëe›*R#20b—ˆ¯X÷—ÉÒ ÃìB <® jíÞQ¼ú"ÚÙ­Ÿ-e °€è¾ÁŒÇ)"NìrZ—ú”n`Jžâ*B4ì_•Ë&ež §Ý|Äjü}4(õö.¯Ýã,däÔëLøÔoå±ïžç j­uA¨ÔµÉÃ$ÍÔϧ1ƒ§Žóå¼ ÷Œþè6,pÆe”JdMÍÓ€_­«ÅfE)´EB‘u8ƒX,’4ØžµûQVèË]7b~n~ð Èsö7¶d#-ÍŽÀõÜ9àDÏ‰ßøq€¼áKpð±4sYub<Ê5[(‹àº|6ˆ%œ=D¥èM€i.‹Á•K…ž:©ÿ!_üí‹RÇ&„A4üÞlÒþÛÁ[Â!i£A]g÷ú×óz· 6qCQÈýÇÙ0ÚîYòPÈÉ€u„ë§a£l-V[ñƒU½\¶ 7¶Ï5\Ö-r1Qí”Æõ ©£Uäÿ"ÖSÚñ à·w^),¥YöŽïÉ•láÝ0 Lȸ2dØÀBÆ·…;£´Ò°H9÷Úc™g>cõ±Esñ¢w tÝŒ>Ýݺ%öÄ4FEõËh£§ÁF{³òPÉw4¢ ÔÕ’‚ʼnIÇÍÅ!E…\Œ÷LMŠî½1*nŸAX`§§«ÏÎw]ÅöÊhZ2ª°6¿ñ‘¨{¹üd,60øë&Ðp\2>l°Z»‚÷J3ŸHAã]Þï×h+æc-ÅJX?¬Sž»\÷3V⹘L"u’ 4vü‚Þ6²fŒK²¢|ŒD&ãiöIC¬Û}âž]ß‹Í$`ø–e,¸ú4ïèëØªx ã 9çre–×MÂø¬Õ»¼ñ.n°ê$û[6øâ®H$8•“ìj5jo'âÞð¿ñ ¶EI<çb’­Ÿ¡|½!¬¥Úç€ #;##Ì æ×d‡$ùPªõ­Ø³=0ƒÕÊ‹*mßÊl\fÁm ¬m4Ûm¦a 5y“×·ƒä¾Î%TÜþÖ6©µ ÝBÈÝ4C¹ð“ ©ÄWÞ¿qžûŠz£>.îó®AG´N$VöŒä Ò’Â;€}eLßó1ëúÖ_@òç ùÓëïŽüÿv‰¾ÞPõn¶³[oÜŠ°óF¶§…S4´©ûY¥êÙ7ês et/Gøÿ|ÜRô³Nc6:•Ÿ¨­å”™Yf¢2‚§>ㆻ‹À £=øÈWÃ!#e"ÍâW7èÿ$}Š—yù֊。~ÜòK„œÆEÐüe2RX=ć¾E÷ô}'{OÚžxîëJU‘o¾GfÍGJäk˜IûºÁk3Æ·«KM säWdýà`vEq¡¤¾fwå’t¨4I>œ*Ëyì_%„©I9ÀjRp^ûÚÜkž4µQ§( “)¤”ó‹}€‚z–ÎhÊ·\ §úe€õTÀ RSáaî ‘œÃë]º½Z2ògÌû?2Âo†{ lqq—°øó;QÆï´¢‘9qþ¼È´[!4á÷óÇï¯ãq=>éKÔs~³YŠ¥‘*?¿°]lo›&ØàO·€59@«™¼.0D‡ÿòœéÐy ^&ļW—{§ôUP<ý€¨}œ¶8{¢ô’ZTʬUçÅ M ñgŽ<•–:ß=ØõÍ·\TÆlD‘'Áövé­Aœ(!ÿ9×dÀdoÉ“3Ö±¸ô-ž»Œÿ{T¦½çÛÕöPLò=9wDHUÎ_·(©Xâ"/kMöñ÷¢Ï†D¼³àºÙ 1Sò¡u-'=0 <óC°-¹h7^¼Ñ˜ÈˆÞh†ýÑPÏêäK rÈ/¶×¦· Éb•³Ùç÷…Ì\KÝ9‡$J‰ ÙËŸw4Å^‡oÝgÕõ£ ÑÏœûR†Œï¹Ó®|ýq?\EÏï ØÔe¼åÌÈÂ_ÆîÐzl¢!óÀÙ†7P“vBo¸lÁG½ÈŠÃâx^fP4?ÙÝÃÅ)É7;hZÕ,o­KÙŽ”ߤÛÉà·af…ñŽÁY·æ•Cìápa ÖÚ•Ñ6SÖŽÜUÀ|‚&›GLJ}Ùq¼ö)†_QÕLÏKÎq*º¶,‡= L‘·„ÐÜ…ŠL²|-¶FFnüŒŒŠN/âu’–£,¸”I¹Ÿž‚rÕ@ˆ¼¿Sn\ñqÐçúýu.©k•İ®²Ð§tÓÐïR“:eÑK/èSâ™·Ž@<ôð¯ö¸• ÔgN„è¤É‘‚uF Úžh=àg¶ä·Ï_ F6[©?ï‚eáÕT³ëûù–1ZxóRpÔ-Rö*Gˆ»L8ÜÀ°âàoíÞØÄÂUÅœf‚¾<Êÿj›ÅÙ¡¢^ÍIoW`…jr½¦¤Zq‹!>Ü&GD¥½^«úî¨ò]?æ:6>ãÑäQž©­ÂwßCì†Ð8ÄÕ–*uËNÈø ±\w™Ž5Å­œfÂÔCRPg¸‘kIC´ „Ù5ÞÏŇm·_OûÜŠìñœNNKUe†xã"eZLIã”0ïÍ^BÎC`qC¥–­§³è` 5_ZE·[> %7k»®&€Ñ¢?ÛAÊ¥Z¸4(l\Á[ˆöÂæ;6Tª(üVýq€ž>Ää‹Êæ, ¿ò\šqÂ:®oü¸V9ªp¨xºÞ ', N³±Ç·Tœ¶¾Š#/Hk² k B­YžWb ˆnjiظ'á™[Þz»ø)¨ú1¢÷¯,:b7yöiN¼œýf¸Ï ‡X7À½£#ø#PÜj“äq²I]¤.X®s¢È“™­¬B®ªú÷'KÈ?BÄJ„9Üý÷x{ÎàÓ~A,4|è—ÓN÷œ•Ý#%’› sýwIŽO!‚øÝ/=ûªa— Šp–ÎÔ ÞH͒Óçη‚Yæós«¿,&AóÕ }=F},"Àmðe<€jHY†1#WÝíTž«ëN_#'Pó–üöÇ[|LЭ»\콄p˜¶\}N³ë\\> Í_á¿ê$Ajл½Nœó†©à~AYŸŠ0TÇÞ¹²µ˜V‰ís~³µ?/ùN–_¶4#sãZè¥füZr@}ßG‡ÆÑ ðq/¨§ÅK³Oá~ÈÀ =öL9$€ ßú³V“Õ7Á:ów¤¸ƒü˜éÿRvI{왚ޮ:ñ´0/Ÿ¢þ'|Û!X‡ˆ}”ö€üÕ࣠he:ÿ þóÍàÆLÛoÌA%#Ž`˜àˆGZ3Qjý¡.jìöUwÞ¦\’"ÒW#Â#¶‰9¦e¦# nèK¯À}%´uu¦Äùb<¶Ó Ç·Í©V36‘\˜ä¸M€+¦%ÿzŠU²(Ú$"T^GÃè6=‹XLóê"y³ù èDèo—Ç;ŒJ6Rî'¨ÆÞRÎ"Æ£ë{_ dd\gϺߵǕk'”hLÞÄu(£5v/Äc‡‘gdNRU’5C])¦[‡"|¯]“@|ÎUg5‘ë*Nl—ӢưˆŠh ô»˜Ÿ¯ŒBŒwV1’ppàQDó IZ ìÓh}!ÛªÀ½Í#0Qèis?Aoc;lP¡nÏgX%ˆsÖ•uLy©dùÊ€"'1v¼¢<«|ϱÿX•ž2¾K‘÷ ˆR?nùÑ$õˆ¥ÃöD/þÈ»®á¶D—oÜÀ%IKyð—P sõ7Vº†!´‹Ü‹ÕõÛåågºÆñŒù;ó›;õ²Ç{Õ ¡ÇU€/~ØoåÜyI€bã¹çbqwñØô? MG¤<Á%öçž¡ä @Ä>òu±àlºe‰6±’asÿò™³,ñ]9ÝÈ9É"OAÝýÉ9ÓIÿP9¤kâ¯<˜¤ÛW ™Ô˜®68ðûRLä;¹¯Hí5r=%gŸ1ä°ÿ(Èòέ:w\MUæÄ0aØ}¥—ê!´„BÉÚ›h‡ T€z7Aä®6#1[@Em´]aŸY‰Ä–·áæ_ô¥ µª©=ã5mÊ">þÆÞ³öÙg)†“×zUMúý\„™ZÃz"“‹ÿX ½h6¶Ä>ÕŸE/œ„õ©= 'Pzõçå°á¥Pýê¨CÂs¨¹T t5'î¶t ™‹%œúKþŸ(‚ýŠX¢&‚gÿÿçY¤JÝZßäœ+,#Y~‰¡ã;#{n\'"þ8~ 7.&Bѹ0%0¥P译ίYpÛÙo+AO‚Ä ê`ÎÀý!¯ÕAÞ‡×ê ïHCëõPw£¬Ä–xÞ_&ŸzA¶6ÂÉ\h,ñžòð9ü¼Ü€Zó³Ó‚ðÜ"®+Fo^bx—žº4¬ÖKÜjø½Oõ?ïãEû_s‘œáaéþâÁuû ±¬uc·yTºÝ”ܼ#TâˆÄ-õ|ˆðQ|'Ešª°¹iYãÛ%þ·œµÌ¿šð§p_ÛΓ‚õ„ûv%wߨ¬\ÓŠ)K5§·ü|®å› F&!0oÕkžX¶€z¡†PYx Wz ø]¬ÛÌœ¡¶yò"½}$BìysÌ„Dq—&‚ö fð&s팀D ûcdq[)F;'ÿNc÷ôö[ª/Ýú˜š á4Z’ËómïÌÀ•(ç|·-•’P^ï]4¤åÇš]°hîлàSnøÛ»òóY¨P`ºˆ•ÐhÒ²R',ñ€ºä‰¨¤ÈÕÈò&SÞÇ¥óWÚ>»åËþ¡#¹Þô½(%PB’ÙmãV¸<¤õ½€—=û¬õ®2>ôn2…©Š´Æ-Lä׫§¶Ú}¥¹Gž¼ŒÑGo{ÿOv¤xãÀ¸Œ{yÀ¥ 7\·Ûj9“SN#쇒ì ò•Ç¿¦ýºMúÓÿ EÕ#~1}=ÂIÕVþ‹—z¨— óœA óœA Ž¿»!!ô&‚ ¶@\òèQTÌ€o&åÐ Èf€¬SŒÏÿm§ i”ÿG—DÈ0)ÿuw ÷{ÏÔðÄ)u£‹ºÐ¾Õùb虂÷¿ÞS¥ÈGãñÕÿF¼€Íb„éäÛ¦;\¢ rxKõÆ®¸u…]Ï:JþÙ£Ý1PhS/@Þؤ[ߣÿ<ГïÜðÛ¥Z+Ï䬋§ÎÚïDOgŒ!xÕÍOر¶uÜ O1RßÍq—SËE"þªªG¤HlÄҸРñ  °´Ñm›E’ë†|mÝß©Ë'€cèÛœx©Í=œd7´Ô¦&@Ê@¦zB5[ÇàlŒ2T*‰$ŠÞêuŸµŠýŸ†­” ½R_£Y¹ž9ƒs†po‘þyŒÿý¯Â¶…AKÉå*QÇ0…J¼Œ*@$a’ K›&,`gûËÎaK^5à•ºï#%=}òòQZQ¤±Aö( f06˜¿¯XÕŸw¡Ü‹Yë= øHc-:îWRÁ¸Ô²áàsë‹yY:üÕ«Ï(M®(7–‹åçøù»4Sf¿d„ש%Øk™/»7eñÔǮƵºÄõ^I‰&CÊðÊÁc~ºíîrWždÃQ_=VÅîw#UºpyÁ-àíbŸ®H$Ìj!¶ƒ8?Á~ý¯Á°OtQ‘æ[Euâ,Ô –qV¹å׿ÆÕ„}ó@á)œ‘9wòýÓogn§–àTä¤\ ØÊò}1ԯª”SG½âŸg§]Œ@_ଠfÖwó;Ä$Hˆ+U,ÂP('¦ ý"šÞª.’Ÿq&vIµ§½`lÀS‰à´ (¡(O3Ùÿ}ÏP…a®<|T2W×`õ}PŸ>Ç%ý©?]ÁX<†Tp–ìDW ’ÕGJ€D¸Zïù~´E&¼î–!z?V§MúJÔ„ )™ôØ2rTÒ`†£¹G^èàÂHöMÌ%rƒWÿv´¸·?À{²5—èÿ5ëÊÝ O·[%€Ê¿¸¼rX·¤uIQ¡”÷£Íº rÏHù>Qn3f5 ®[ñ=5ÕÏ>ôïÆ:'ظ›AbáMaLùÞ«gïLcòŸ¸A‚€Ü*H,¬¢ˆ˜Œ±8E™4b×IF IùÍšà÷(‹o²hŒÖ¯Ì ÊêW³UÅZ*üã÷è1u²ŒÔmk=þ ÄšˆbÈÔc(ÄñÑx”\F°»™[g©räàì•YâÑ®–ÁÛ›cŒ]îsÛzÍ_(ÄþŸdíÛ&5úÖÌàp¦ ‰<“>›?‰|—|‚»C±Ÿ¿€;@mÉ$‡4LÙå¡'|ñSèŒÊäPD 2¢!l\ Í/REJî¤DÓ§ZvRK”åR%` 6“Ñ}ÿËÉpJ#·¬XqGu]¯Sô©šo¦ŸHÚ«AúóóU:¸×óH@CT¼-ˆñ]! ¡ÂÚV·,ÅÑ@LÎÌŒùì- ïN{… =V$p˜ý3'¹OfйPJDõ,Õf¨`ì‘uÐVÐçÁõ0±oSûp¤Où&ÅÏo…¥~ùÞŽ˜Š"‚5{6žÕ’´ìFJFaØøíÊlZ5E—œ@±cP›¿aä¨Çvýi8F–ì¡A®ÜVmÖ@­—Gý¶ºDZxE¥º ÀKlŸš(k%?( °úS©„¥ X·S>ÔjolŽÏéÚ&'t¯HdwiÍÝoêp™}­Y÷%Xõ`÷Õ(Íà c?# ö±: ì0k«Bã`?½(›»8)Ù$*zÝwŒ›Í¼Y$;€S‚Âñý#L/×" íÛùŠ]Ï€4(- Û“ :{lêäÍ=–Bu=´|ê凥L‚RÆ¿ž5ÖÜœÜNE²Hî\¥å¡­›ŽŸ·ΪÅó-ï]A£Nòdšbèdüwî®û|ZyÀù”W`eù¸PM\%½áÍžšÏ'¥ïõšOq”êJRÞ* µù.þV ‘²f‡Bbwý0å=ü|–œ{ôÄ,±CEËÇ~m£¡ EHÞÕ©(, bÌyÔ±å4´mÇS FÚlt( Gö>\2©÷=ñG/™7087‹XŽý©´ýCìøkþËRó¥GÆö™shiÖaõbh­×Š“8}¸SÅ1ïNw‚œòÉüœô¦ÏñÁgj5­4Ü})›ÎUygŸýzªN4£å»²9$H`_áw¥“0ŽžœÃPQXH(äPW³´Š²EÞ ÖœTâ“”$¨¡ÿvLiléÊÍ—èÚV"ß/«êû>ò«»bMø…‰M;À^8ãñ+fJSªîËMò̺#³jÐÕ&LÞ—Wá—jF)Y÷%울áf[®ý¡~…É8Ðq¡Õi7›äy<ËË wkÔшJ&UU8*âãp#•Éu -òâr:FÙχÀÛ…OCZë~qÒqó‹}Îw3¡„y‡[5;Ú—Ø~þ=3¥ÿa’ëO£‚èTÌrbü•Ž€Õd¦î›àP¨°¥ ʰ—}@íQ¼(]àÊଇ—à4¦ÅäUH©ê Çqï‘A.ÕØ%Ûõâg5²@Ê PµRMD3"r$ŽÛÀù7G)ƒ\›rQÄ[æQn¦Ø\¼s@¡³zìëÌZ^r(FQeWWþmUåú8/­ž‰ÇêâòKQ· ”1åò¶Ûç­0kÐ~S×çÅ «Õ,Ì‹±Y½ìT°ò}4^(Ob¡¼'M_›¨k¥†câ°·þ²x‚êw P— Nšƒø½kçD‚tØÂj4jü(îG'¦Eñcj]-#,û^Mø&¨AüÆóø…¾²B1ä0!#ùýx¸u~šLƒ8‘£"¦ž·úÙæõÈLL³{­Ò6Q ‡þôÛˆ”Ȫcßv˜ RÎÑ ðym?§Vo3p†«šæ…P‹.§Â£bÿ2(Þ`ŽšÄÎË”åiIAg^;ÇiIŸpƒ=NÌü@"ñ¾#ùCZ:nÀqgÃðlŸ2†c01h “€!èæ‰Ñ†kCÜnF$¡Ÿ\9­ ;&ŸøŽ?qãøü¥!*¿ŸoæÞ‹Å¥[[æmþ|X_¯ûã7X‘—mͰóØlÅ/Ͳ¹”eL&!ˆ‡c̤H/®¬þ¥ñU éÕÏfïÝÍêª^̓PSë‘—_?!÷È}߉P_òù„ÿ@™…øÛ+}êuFG;  `@… p{7(fffl34ìïÍkÈ>X(!øVì¿Áëvþ`%±¸í²{MáfîOá°mxžO¤ 0üMÕÖ¶öçF”:.áûC=î³#ûš8p@Ùd¨ VÐèªÆE·ªñgo%Âê+j ‘|(ˆ®¹uƒ‡ÜC\šd–qŒr8~Ï;—Xwà“0W̳ÐÑ·$›³1É„ ›¼3ÁËžÐü½TA¢fn‰ÃDâ«ct »að›÷ê÷« íe)³»K–ò­%b ›£¬'3Ó¢N‘ E)Üüñ…b 4i¦µlµ8Fø‚͘¦•²~´öÍb«¶¶à^uÚE •ݸ®)Ô¡ZNGÏýsÍ0~ضocÊ,ª$Ñþ;‡&w÷÷9@¯ÛÀQ{H¯yG@ÎÉw]Y`É……Êšæ‚îW–ßLæ c¯T ä>ç`;…¹Gçùd&)É¢õŽúò¥3 ä¶.ì{êOô HC¯8I·ÿÿÿÿÿÿÿÿÿÿ€p㢅‡5®öϾÚ†4"Ùµo^Ö“]3­µÂ–pð Ï*^i}WÝÁï³Ñ^®l±4":Ü:mÌïwp)S¡{.\Ûλ# •,GŠù2 Ë‘ì™Ç¿t®îl.šŒ–¦ð"üƒâÐ×cPSJ¢¬à¡ã wWV²€¨Ê†–L¾¥iI)Õ0.;{iD‚¼é™©_ÆDÒ"T ¬ Ö¯eÝ0Bšcꔼ‡["ƒÁ¶ú[GßÿeÁnrb(Ê!ZóæSvÿ ÏÔCâµ—ToÑÉÍ1bö/OªöøÉ¿!‰X*í'Ù@“¡Ó3if'&÷®òK¶Ûm¶Ûm¶Ûm¶ÛmŽ ýFaíré‰Kú=[ò7±úòEð§×ðã++q0ãUüà _! H8ï9wúãO²ÒW©3ø $’I$’I$’IGÔ-­6c˜atj»™-l„Ýœöâ©&ÒZHæ"o .ö_Ÿ²·%=®àÛ}BU,ز;u;n„7o‰˜’×îõcßïOê$©å«2ùÝMÉ?ò$H9mÝÌÓ&©ÔÂߺc¿®ž8žRÌ* qò®]Ng”P'äWÿA›’»^Rž:`zÄßC’.dëG4Áð^|â̵<(¶×'1&t¤8ž_çç–u#õ’,÷¥ÒÎXa‰…ûŒxo59>mâ¾§­^†5ó[9rf:Z„Çâøpx(^Y26O©³}L©•\‡†®?ÔŠ[ãyGS®(¤Æ2;å•7·ÝoXø«p >7Xmè—fã3±rJ²›‚}‚&W~!e*pG»ÕSéò‡AÖiŽ;LPF‚Àœÿ/^SͦAD+;”æû›úrrܹH¥õ³Un90wYçˆO´„4v)Q¥«èÚu9Q#´!¼ˆzû@"lU’00iükÆß…ìûYZq9~øû¶âñªNå, $àßÚH‘Ÿ©|m"_ ë$4œ™‚:Ä¢G²Ë}’ëV?¿Läy¼ªympÊÑHÉiO×”‚Î ÖèÐyÖ&¾òÖºÿXŸæ4ºo_\ˆ® `öQs—'Ê)ç2œXë@°Ñë-‚õ)ÝþGª¾Oý“®cí"’k%âÕРsÃ©Æ ÕᙾÊ1'f“*Q,Þ !¯‚¦ÆÁ<”ÉÖ¾˜D|Š›>Þn¤™už²,¤{ô ñ¦Ð¡P‡¡Æ¦ü¼fâQsãÖ7Åi£ÈæCñvâ7ð„wêKò¿04¯ÙŽÚžïò×z ÷et¯õ² ý†²§—Gaþúî˜ANTÀ¶£JÏf"þvy ³%_-á»ø®<ôj[B›–q‚# ¦ñ²=ýæbjc3%ÔïÍñtŸö@¯$ëaß/_œœÛF‹ùÃÄÊó"Ëò!ŒüühmáéÒ“ÏIžœ¶Y´ìïïß´òd”Е(Q¶ÉÁQ-9‡®žÇÕŽÉ *ÖÀd•¡‚mžH²4l‰«…¾0Qh%Sf$B‹·&4@'€³ÊÕ¸®´ÆKjŒ‰;˜GM=`.þIÚMf¨¯~ö§§Y6i£ó#wHIJá*€U+í|Í­qÍ ª&˜C¶Ð±6(eãÒ²¡ü §ØÛE¨°^Ö¼ÐYgòq=ÜÇäàü}7nÿ Ž 'AŠ×™E®Ú½$«8ꤠ&£ –x#¾ä7÷¸ÖšÇ5öÈ3ÉT²}ϱdd³¤I hÑ×cÖð4±žpŒ•ê°¡¡ò¼¢~þRlsÈá‰ê_ˆ:…ߨ×Ü‹È/y¸îÈoY¸ÜˆÖÞ‚y0èñ0Úb±3¨fÖABSÚ\9¾`ÐA™öA<òH[ò(h,G¨,]q½K­\A„=T·L÷0ã°³ºâjŸ…›Y>´®G£Ûw]‹™ Ñ&5a Á‰l©ÌÞ‡û“C¤+—áï –ÈísÒo·ÿKº»ŒLÅ‹(þ4zÁ…fîàªõàü‡§Ÿñâ©HIR’ Ò_}!ù¿á-$YÇØ¡KÂ4§õ"OÞJ¸="ÐâuO¯¼;ð\WËÎŒÖI÷j~·µq»èMŒ!{W—‘Ýמ¯ÍŒ ž%^]ü[ƒ2Õ0˜*?e6c ¹Q9õw¶zÖýk_|7ÛEÞ˜ïLröF2Áo¥ ×+' Š®ZëÑ‹ÓÓò!ôîQEæJ÷ÔÌw àXzW"…ïb“PVµPñ ¾ Z3í«¸sÔ1ä굛ϛ| t0>æÿe3Ua”ዳ¿‡ /F–z ”7TÃOÈõ·Ðn·ô» "$r¡z;2c×oƒ:M¨²¯GsK—áäCæL×ônfV)œàݳs­¶:Ìü×(WíWÛ$&™I—[cL_%jߨ6KRçõÏJ•“i¶¾ž¤î¤^ºa©ú”<ÝLÐg™ðE˜ƒ®SÞÔH ¼ØàáâðàÝþ)ἑ½‘$êžú£Y§R“yÅØM]\æÝ—çÄ|ƒ]}¿]]Ïþ[ý/û©·N(ú©É·M, ›ìÉxËÅåjœ:Xµ¹wvDÚ&¼½(ÄBVߤÑËu%t²,œŠíbù"ÜrБ³âBÌQ-ìl)è\Y-«ÀÖ°##™¼kúóà Ü­7¢ñÍ y`yì Ê|§øŠÚe«ð]Ë ›Éi•~".‘Ï/&ò´k~ì‘䵃“{ÊbÏÊ —Îw±˜R  N+˜µ9KJHºšÙ>"} ú g¦±žà o%¥½„X#‡IïŒáª}ùÿNÌóšW½0 ~Â?ë/ý\ 1 ¿Áÿ¢×ÏN¾Ìµxˆþ 3Y4铨Y:WœŸ1™ÕJ¬ô…¼MŠWðÜ€Iò'–¹ÈR‚Ãaï̽Ï-äµcgªÂøàÞd¸Fo v^Ó˜FÂYOݽ· >ÇŸÒcôÐMyCÐÅpn!geòÜ­Üg»Egý†¦îIZM¾ïœ–×Do\g¸Ë ®\ƒä¶/dŠŽÖÑô :¥@8¦]}÷±#‹òû Z÷TÙ–ÅäøaikW…¨–tŠ¢g25÷8r ÜŸ²†›ùµdŒ3®Mćÿ»2#;û»1x˜ñî‰ß#)%¿lJ™Ó®ÑàÀ{S¹ ý²¬›‚ÔÛÖ"êÄ(̸Lq(˸ÎôØýq¶¨QB¼Ò+¶<.΋> N h—8Pâ«Ó~›ÔT|ø¶½óÿ~@«:«ÍÉV`ýÚñ»bÀ­»²S3¦yv×î)T9E¡ÈAalÍ»rƒV×äýâ‡e|¸éRS™œ)9%{¼¥Ûÿ‘ _±Š‘Xΰ¸ïP§­wˆjA—ÎÏ'俎Tá¯QyZD› „Æ•{aVÕ«YX«Ep7åU¿¶ÙȲWKW¼Æ.u½‚RòÛiºüÂËg¯.‘¨:oéûíŸÒi£ªCšGÝ#qJ½u¼gË  ŸÞqË?s–dT2ûOh+`ý)áôJÿNš48]òêÙ¿åÆêÔŒ©+;œÆGÐeväï!Ô¯çoM5<Õu©ó _†´lªñœÑ°³«dí1)ÅÆYÚ*Ô¹#7?ÐÚD3è:%‡ùÌÀn·ö¥ »×@é`]nÖÓ7ŽK`•[#(Œý•>MûAÌ ”!ÙGN ÇÉ€³gˆÚªã´t“¾63ls‰hŸ dõ<¨`¡ƒÐ`ÕÉò°¦óyÄw²ÚGÃ¥ù7?*ϲJ/yŠÌWGˆôüÙ7kße¿y‚"!_4çùݪœ[´–)Ý–Îd'Êb¹»áºÎ?QñÀ¾ *xÅ%áxT>GÜR ¸lUë)Q3Ú’ø±ZM@¡PÚK(rhå{3ü¡Aè„´|ÈÃmä7't­ŒúuT¥Øþ~4 èΦ¶}êFè’€uõÌØÓÂ"ü·†“ÿ9ÙOÝßHĽ–(}¯¸aÆéÕr`¶uk”ª^8Y’yøWdAÄä“·E´÷ø°µá©Xú’ACõý]ÝKs<á·¾þÃ%®äÑ4M µ¨ŠO%¡¢T`ZÐ0¶žâ}­â iˆã¹ÓšLS=qŒÅJMa‹{ó8„Qˆ!¸ ª|ùE´‚E Òc.ü›¦fhFTÊsÏW·j«dnW£¤b©u]EÞ+ÓÇnóâ(9L?4{FÅAòk[¼£ØiÓ,=^°]"þÚ‚%Jð ö™Ãʲ¯Ý/ðlš¾IL¦ßfW׉Û0˜·;ü'¬²T'M«!™€‘»t2ZÝ“¶,ÃÈö¾^h¤~«˜Ç% 7¯Çt!$½þ@ÛÓôOic-¶5ÁÖ(ÉØrC‘²ugôŸ$¡ÀxžÖ¸^H4¬…´ŒØ±·ÚgÚý°ýk†! PgÕ¦õí;[éiu…ÌŽî" ¯ƒnÞ30ŠA ·ý«¯ûá%u0çnÚkÕ!¶9ÅI®‚Ô颼oÚ;É¥cØB€‰Vààtn·ºOÈ+'ƒZØx´‘GδȇíL3#ò®ßÌ—ë{ãü¿~p:Qb®\l[/°Õ´ç³²á[㣢t¢ÊË£ë×ß¹5k¸[Ò%a0ÃÛ¡gy»tö¾o M¤îñJÏÏæ!•ƒˆ ï}¾ßÑ¥\ÚwÙðU!p,cš<6‘1ƳHO .ê¯n¦qàóMµÝ~äšàoõÞ¤‚økŸýNMŠ ¾éÚ1 Óì9% ¢Û%¬åâ⵬HaIkûL©ß=· —bÈ«ç3¾YÊÑdoýu°ö[ óƒlÛ~-÷!Shz>^êY:ßk‰aàXñs½é K…"R Yîò™“ü"ìë±ø’צN~‡í” ’X7ûOârE¼ÚÇREýðGù]¶ø“Ÿ³°þtË0ñ'èÔ=Z‚ÌVð>®Žê½òjÏiüý«üþ‘?ÿ©_çíOçõ{þa_Ÿ­Ÿeχ×ïÏÛÏØ^ç¾ß&Ýï“lþz=òt¦ù=_'>ï¿ŸÑçùýþ~‡~}?ùû)ùûùú÷À7u+»øvëµ÷{‡ðúoø}%ü;Æ÷µ}õk»ëÿpõÇ»½÷ø{‹ðú âÃe<c0àÞ6í±d>ÕÚBÁÒ2ü- L|h~^i¦ñ3/j_ªY3” N? CŽb§¾M‰K=ªgÌ$r«¸!\š¿Ý·_7Íó|ß7ÍìJE—xÝ<‹•Ge@Å,œLd‰H}û|Ù[ãî^zHÑèÿ2nûH•ÑùuW-úù«êü(†„âxjOuFLÑŽÅ*>ÅÈšÝa2äk' %Y8a1QCK UâÂ×öŠÁrÄ£]k àE|+9y3L§P0ÛúáB3FVjr/—¯—-“}BÈñûFÑC÷kHb[c .G¼g:ÃàЫõ,L¤INLñ7aÛ ?½«×Ä |<§Õù]µ ¦Æ.GQÈ»ÍÅöÎ~ ;ËÈå‹ZÄŠˆ’†òP8I8Qrxª|\ì#§^0 §ýsœ-p‹ül(¬CIÀfØxóæ1¾0D>£•ž6ÞZ¹g_y¢ piŽŽ{çůw®'W|ÒfD-4\†Dío#´£Õºc¯„r˜Ù³À‚·¶ÖŒËk80¯P¦¶´ä`¿ú;GúþEâŸ÷>jpv’­'¤–Ýc DŽkgÜü6¼ì˰f²Ïy‰(*êè›:áWxº °Ÿ jßVãí³OZп »”¶üEç¡û­»VçÒl4Ï|ÓÀ'PJaÇ)GŒŒág¬ýÐ1f ƪ»KèG y~¿ÿ²\Dˆq¸ LxuÞ¸ë% ûîÔE:Õ®Œ“ÖL÷T}¡hò®ÐëøFè IÒ 5³9œ’]o™!e…öUmÛ5Ý®õ¡µÂ²˜š²IÖ+¿L K¿ª×à–†ˆYXΖrkî_:Ì{Õ‹*ŠI~ÿae~“lUõ8õò7à6~¶Rg«­1ÏV¨w!·ct…š(DCýy#k hÖ{@‹ ø`åYHØÓé•O‚Iœ£·&mq$?%›È³$K%fiž}N‚U)P,%É/~å&[5ßéqT¥í&ª„r ôH¢¥¬DaÝ ½fdÎ_Y¶Ë^w‚ZëÞ¿ø ÇU±fâŠ;!D8_ö®¯˜÷‹þf¼½1A lÑ•€œb™x½ÐÝnÁ€G–P9†hŒn¾Æ}TQkÓ¸sþ›³å±”lp^Ÿ¼´ø¤&üǨג8 Ô ¶}{5G[&œ2Ð6µJèï`0àÐk€(¹¢Ì•»¦*çêðc´±qïž uéÆõ¯nNGó"™…ξù΃ãt3ÇIw‚âýŬâXÊñƒ4û$ëóy’¹¸¼^—=ù¸Ž÷Ó?›#}$U85¶<õà„Ý7E­™ÜÝñ•e­³)šy^Šó3ÄÇÐy*T¤OOhõê!TQíhC>ŽÜsG¸°¶*¬9¿¹»oiZðÓÀŸeûaœ¬NfÅSï¨TÕxÁÍÆŽa9ÿ-í´=@öSµc±ôä]”‹ciÈó„Iï2t‰¬¤)§4ùIù®a0nZ|°Î*t;x¼Âõè§^$ Ù *ýB2œÎPnvœË”Q]ÛM[R…Å¿Ñ{ %’[À:41÷põ,Þà'wmž6å©© h[Teh/H³Þ×ÎB&ލ]!ˆJ‹€ó:Ã!£òËÝ/ä÷¾¾ñIæÁXa.ûí<Þ}6ŽÝh݈؉‰"º( *ÖÓ™ª´ÒàvÂôù‡ù°&D”i$ð†õ}¯cX“v쇜ݩ怣‹Œ$ú2 K„Z?©fòRó ÆÓ´ýúIÆy Yž¨^GÎ-¤€µzKÛS{Œ­ÉŒ¬ƒ—Χ2Ö:áýÓ=Ÿ¢ï:¦ ¿½˜ íæ“€ß»íûh_òIÉUÏý¥ 9•„ÝÿxäÄÒ€a^ðŒ ,ˆ`‡MÌn·žóίŸxå@-öÝ7er¼ÇgL£ -u´û)飳¢xL§»¶Â¹ü¹¼pBxäúÀù$Žx`¨‰ŽAÂó°2ŸVÜ Ê-ó³äSúS+ïÙ‰µÈ’ÿ„W¯¶-ú÷¹¤5`³}$*0Ï/òAäÈ—¶OÖ@ãx)œ–ì•‘APN‹Âˆ§¾Èºk±ËÃç8¯¶2³òÐzu$ë‹‚–\aÈÃe¾'áÂu`±@'°{>Ζ-Ï¡Sj"vbêf³˜%Ÿ*êmâÂIp¯ (kÈíÿz>lïL] bcÔõëGÕDÅìåÑ ´À² (J´ÜA§%Í?âÇ¥ ¬ íŒù-*ÕswüYcwb$èX I6$jü´C.}2_ÄóbâÔ4[çýGŸ­ZÉ%µÆu»#oú×Ek-æIù+[ä£&“B)EIý´Í뀇¶Mƒ^œæî»öݨK­âiõÖRC¤ˆ‹’­x‘ôZ.Ü=NPËqúá"‚eT¦ïW”ëH¯Ï)¸ò ò2F.kêesZÃÃæN4w­†I ¤³yu0`|¶ŒY`Š=ؕȄÁv ¯¥’ŽbëÚ}m{ h“®v°Ä5‰ž«iî ­!Ìí7 |vùp yáˆñÚ÷®JÚU|%t«3Ü Ð m€ÉBSƒ$½ÈBž™Ü¼-O(™˜lšç¡Y±(éV©èŠ(o†ç/"§ªAß¾©ž«ëÕ(ÎŒÕRÕEoì :¦3½\ž@Ž<ˆÄá8á[­Ü¥CDµK…qùBs~³YЦÀOç:EÓ+ÙÂèì“e7«‡Œ oÍ)×åpa¢Ã)Œ&ÿà<¸Ü˜÷¸5¹Ó@<­³nxýzÈj4÷Ê:é$>¢s¥é û 49·Ïx·‹tþ Þ-ІWÿ)}O­Ò¤Ü”3·(9ƒÃÍMË«•lɹž&+l5g¯Vœ™–P60¿ÆÏ¿þßÐeåÇÙ®Pïpžréå)u‹»¥§fW*)y OŸft¡Ç@s¡Ç>}õt޲ÝàÃÕªVepiÀ’=RsÑÏñqÇåM8Øž»PP«W!I¹fD,>¢„8ù!`Xï}Yçr6"ýÎtÄŒ§ MNΊ¢I42¹ž0Á²Ë¥à‰,b8tX‰±)erƯŽcÙÍ–sDå›np¬ÀU¢|è,"h¬Ïeڑدæz‡Ê¦¢¿ê'ÕNûCp†pêØ|]/¾2„û· e=pÿ9¬$XÐåªænu42¹¬‰srµã,Šþ.¶ls÷ô-‹ J¾{5s*lj`–‹íŠéZ—ƒ«æPÌ»H£ä¯%\…¬euXMÆö±Ù°ÏÅT 8hñÝ~TºB]ö ê++Æ’Îûf&š2::ªŒ^;[ ÿXÎÆëÄÁ°—¨NššåøG£\{ïÕŸÕ=9*š7çcÌÒ·ÇGEI‘“5«ÔÎ9 …¦ gÆÇg‰³i¦_—t׿Lù§úíÈkÃQÝÐ\ åI½‚F·0 gˆ™ ò]Á²eW>ع‹1÷™Çk©ÓŸ!Ôã#£þh:dú3»ÖvgŠnDæ5ž­­Ó^‰>ㇵ-Vê9¤ ¢ê€÷,F†8÷½FÅ­¶X;xµf”I·@Ò´ R1äö[„¹PYè ÙtŸÐctk…)FÍ]!©êLð-Ë7m:n4ñk°†öÒ-nÿ5 rêõˆ{“á¸êÿšjoãŽEŒLvwL><¿dŠ0Hð¹Ã–@ÞRGkz :Âà b‡à©Ó³½ ‰l´ÐÞh·žÛ3%<3…„3î U_5ï®M¶êÙò»eB#Fg†.®\ìÇ–»Ã%7 u¦ ‚=6-«.ç`õ&/›-L³¤{Öè¾M ‹xÞpH VÀ÷nIÑ8 E詯ê¯1+ÍÂX¥ä—Åû“؇y±E®q0á/Yå ±lÞïŒ/ÒEDºø ?&üh *µ˜òµ—s5·Êþè/pV}©F&ÇfuÄáý^5xű>JðÇÈ}Ûhø†tÉ>tXób ¢Ï‹)æŸ •ƒH&½BŒ˜µï¤w)e¦9H$,PpHDçùRX>¡žwñ,ùkål#èE/©ºÓË–6ë0_`¼Eœmù,ÔEGµžC`+¯é³ïÜÆÃl= w?;âç¶£»býÆ]Ìqdº÷9a1áÍ-?޶U‹vB=¯¯zD¾ªIsêëÂê#èócòF8ÏðAL:G¶9JA™«!»@g—ÞCže=hœ.[ûpl¨yeìÐ8k j\KeI)yQ³>Þ*ƒJ™]âæ0T-œ³o³ùʼrS£Dß3û°i5{žL©é@yP6ýÕ^ nî ýƒBŽè3Iyß´Ga•ß§ª1—sØrŽŽ ŠEXœzÀ†ãÉ¢cHLèß$Úæñ«ñÀøÉD†1ày +ùb.ƒŸ®N*«ÎàºÇæÇ'N¸ÑÞ¹~ný•wa=M0Àj¬Çè-Gh°¼:…($A\†á—3-DŒæ€Î/” • õÊÁ’ò"K)¢´S/…ÂkÂ5Dl=Óo_þO¥ÎÝ´’eÞ1¶ê½?­°4@ؘæµs.]ƒ$›/¡ÌŠ+Ÿ M$+ä(уÀ€itª=9¤ä6£ÈT”îÎ@\ ˆ‹±é-‡=s7%ýBŽDûøšÆ÷h@§^ÕmÖ&/;v’³ þûS 8ìHMž yؾòÙ÷S;üXJ(èߢ+hwŸRMé&¢Ö¶ážÕÿ_ØjêÑ¿°¨9®i®÷*r.i»Ld{çÆbÒ:¡À<º"K8]øFÐ|1Z•ÒÇ×?â\‹ô}ítÂ2Ù(¦±”\±ô€ŒßGf‡¾ž0¯Ô3¤âÿ:o­oWjæ«W- ÔYA.KB:ÏAs¸FÁôP˜ÛÊ/óiªŽGŒ‚E–¼w*l|äBšh„º)g„ûw: ëÕ¥"Ëúê©¡êr -Ïί?û-²Ye}ÝÔéÁ>1âÖ3s‰ŠÂk§:Lçtì4wÑêùV•›r¥ëŽ;èG&PL^Ü×ùÿ_äAæÀЫk‹<ˆ«¯‹æÂÐ<ËÝ‹‚»¼¨ÛÖÃú‹Y,:Ø.{¢gSe.¢ÕÌÀ„q¾¡of@þœN“=’ `cL¾h?Ãö*‘¶ÆàZUO¸µ®’“Ä€ÒxÝKÀ†úGq?+{¶ù\/Àf†Qá2.ñœ¹¢†q6€ÝSŒwúk/]»pëí8ÍëÎú[çmW·—R«ØqTãDâS#ÁO)­ÄQ=·I0vËQµ9è¼øj˜ü¶Shiâ3ø^u.‚­5+KËØp.oú-²\® ¢qÁƒÝÿi¬…)e-f¦'Þj_NÌUr†ŠsÒµV%]÷½Ä^âz‡¼s™—^À$7Ç‚†xw?É/«- sòŒGޱ†1Ck.ÄXHÒÞ€Ðnýrþž\¬&©öH ÅG"…Oÿ~÷*„°7†ñ‚NœŒ²•¥8ÄC|8ÈË—,Äþ$ê[ÈÊù –¯~0/hýÒã]eºÀò…á3ã“*«ØÎž@‚p¬1’ƒ›¨øȱwž«S ÐÏ&Wÿgé ÚòwÆ&Ú!ÆjÛj£`°ñYéÆÅ. ýv~MøT€º!$ Ô t†J2°*)†¥9sôAÏF,G.¼OnåÖC6÷ü"«T‰:ÉØ¤C#<‰«]äöÇH€‹€mÝ*Oó÷rG:‚þˆ|Yö Ü ð"ûÿžqÆkfœñ¤)ººâTTÊè1Ž·Ó¬~·`Ká¶û0*JN4hÚ¢WËL,Ø!Â$3Ú£íâ{h6~˜Ó"'˜Ê=3P­±5ãÓk0±ÚE&CA%C({X©ÿ$ŸìWÛ!lð q» #ýÇ]¦¥T ç+|Á" ªickŽá)?Z¬Hp_<{éÂ"¾«2õ#µ1šž #uŽ6ü ó1~‘ªjÁkGV¶s-‰© Ð$aæ ;@p1ð&lHXÏVZ¦ aÀw‚°‡3óisd°²ÏS'æù[µTÕ¼ò 29È”•¾»ŠŸš fá¬ìR&fÞðD/«i³£ã"WAÄ:ˆß P±Óà NqÇÄä,fC<´ŽšLOݶÔfä©Á¸+<5ìQ˜}ݯb-Ñ*ûˆBŠSô+lüŒÃ¹¨A.ßi53‚^A("È%ëÂÁü‚]øèTÀ„«÷¸'äp7X¨)tï“¿ËÒ6šÎzcÜRR|>! > Óʲv–˜w‡ðÄ)u£‹ºÐ¾Õùbéõñê_x8þ°á€uØ™AÜü°«ùi€Ù˜±Swï(êð *O(m(fpfv߳·כTgö¼ŒsÞ9BæbÛàÎPO)RÜYÊ3<½¦ø‘¼LŠ£ž Ùkí~;@êþcR5@ƒÛny·D½³LYEKG«·°ªœFø)2ué¾SKØÄœÈ]”~Bä»UAt[´Ÿ+§çÔ\¯%É„%yTdRÃ0hÍ)È÷àRn×{¢>&‘jþæuj5ìTî,ùÉ<}ÎϘÕ',Þ;¬ÝÄÿL¬ x›wiª˜ÏP³â½%¾ J¿ÒM$Ö'JºO 5”ÑøõÞíº¥u¾†‹Ñ „ rog R)$ýUd’Ë~.ž./#Ÿ•Z,ºù=&¥£ª¹Ÿ‚Çn¹"›6£´{¶äÍÀAt K?¾ý}à)ƒ:ME<&oÚÎï»qÆ*ôûÂd~~.]-üñTk)[vYªTÅ_l9ßÉЮ’Ì»Z¶,m¥þ“dš¼Ïô7DR%·Hn û.M^íoo ç;›iB ÜN7Jý~¿d­&·ªôJLÙT¯¬"¯¥Ýc ¶$q¸6¤iàà8´cK˜¤sjëÃ@ÎpŽ•¹9ÿ%*‹I™¯o•¶ÇLì-Õ2øÛ>XDΈW$CØÙKFø¬*¬œžRÏ å ¤Ñã§ÃlH'Ov¸mÛ»Šr–ðOMfþA«´›O݆È#Ø0œ$s¢ çzlnÇr°*MDÐÁˆ(wSä,Žº³]G…Òˆ£%“ÏŸÏœmL•ÖµŽ#„ø9ÕÔ<¬“vÊø‚¬ë”íiÆj6ŒGQz$½(sˤþ '‚§‹È.N”íV·š9XÀdCÈv”ÒxP4c’ÃjpÖG›,ºàY­Ò s$ºJo’óñõKôŠó[úª€#i÷¯ÛRùŽŸ ÊšoXNš>u¶Øn©Å »ó«­th@Üj½Ä.¼¿ü”Éš—V^}ÈË⽸Ø4JbYÏ6ÜW¶0•Ý¡w 'ãf, V!5‡Brû}CP@§^c™Wù$بÁé•§‚Ï€agg ä}õzâTJVÀÔ”’FéàSHíaψF@- @êM³çíÍÿ–„¦²æþ2ŸRXÜ„=¦Ûo1iX¡‹|¼²(^¼>Å”.ÉÚ]‚ž·À=±³<.˜çÚ„0ý×Á9MFöø-Eÿ5ïZÿý>°\ëÌ#ó|öÑ–x‹‡F!¢ÚNsû‚@ÚQ¼d-¬, }÷f€–ô_å¢öVduDäÂÖ±mc?(]ÕôÈÈ „À«Ø ‡¨Ü?L`´ÛŽÃ¯+¢¾zT”ÆÑ-(o—¬KœÛ5Ä¥õ€¯ˆ’3ìziGBׂ 6F*@׃™‰>aiZãK\àÄ4Pmw\ý1MÛ/b^ž›®q"3.”ÔD“fí—¬ÕÔݦ‚ÊZW¥öZ“gPô½*+ÜP¦zµÁnxòér¬¤_Û¨A®¾"ƒK¨¸°é(§Ñ‚¢ùÕŸdgT—àÿl¤ÿ8ösn÷zÄž<g—ÕkGNË~Æ3à0Ù\¤bþr'ßêí?´*SÚ ‡Ö†iŠ¥L½0*UkT_ßÌh¼$ÃkA4¯Z¦Ò÷Èó«¨UD_n1ãZò»aç¿ÿJ×”®‚_»Êû/þٲà 37-¼nÝÿJå+u¶ÝJPåʲÎvÙf+^ìFxÞi=@>ÝÞRòÚ±°“z$G=üM(DE›@Íßœ’Å£ÛKõ¥‹ŸÔO£•÷Ÿé®óhËrÂâ®NÉÑ÷GZ”8¯S¨ï¹œÄ#K AΘТoœi;™íôš“ýAl¡R­ûwmB^ÔæÎþ°ï›Ó|ï ÏÖõÿ}Œ`o@8ou²È/˜·níƒ%Ø™)·õ?•Œƒío!ÏY»)_ÿ|ôÌ¥ˆ–ýO••ˆõÿE¡ÿWèÂ"NWU« ®#ñæʉóª¼@ÿR¸¸èOŽ)ÌD êˆÞľ2»Û\ÝR_{ÑD€fRºáûåšÍiJ€êý–/,“ö͉úä„aH„j¾¼›²û£À{rÕrJ®ÙâPÛ8õs‹÷êêtžüh’‰ŸM?ÞîP#—ΪôñÞz7´Á3¤L>…1i€ñ]Ý’RXS¯øJ˜ïÓ÷l7a•2(Eåð#ìGm{‡Î¬|T9YgÅ8&S+=É—œ*&Á3Õ$¦Nþ¢³±! 6 ä” ìSf¶‹§@D¹½±M[ëâr£¶à^ tͶÙõ¨ €ÄóNËyÐâK£Í†ëÿ88¦½–J(E–Ä€Ž,>ËL—µÞ¯<<5‘1ú< Ù0]G>(?)‚äã|ˆ9œË]£òpI<Šì½§#–uU÷‚w­Ì(Þ@³ïŠnª–ŽXîLäv‘°Ò`_¯ágbªÝx%AõÒ6{"(…°>Iô–6vA8ìŒßÔȦt@'ê_np~¿´GMc}ö•âÒ, Ÿ&ÔÀlj¤Ð@@ài iö z®±Õ·¹æí˜òxm<ÃØŠ?,¹),Q…K‰fw¯Áe$M¾ãÒêÈgB;B?BPÿuÂÓER­Å„œ®¹í÷Þ ½B)©Ú]Ï´? ¸H Çß] ±óf1¼'ø§Eˆ¯2Åj”@²³èÕÙI¡>>Á\°É7ÕçÙ]š†2¬"a­’TOr±*º€¯e'Áý"uöW¯ÃŸ³‘h…Zô#Â4ÐI3ªæºÎãªJ»Ž6†]%ÒÕç;„8¤<õš|€ª‚wcq~nn¨Åoð$þ±„ qYòGÐV›B¶ÀÀùkÁò˜ns$<Š$¿ ÞwÍýäÆf¾¢îÓŒÇã• m³_”9˜À²”BJ×ß×â÷a¢z”ð [ i\.¤Š-¾–ˆàóI‘T#<a¶31yìYžÍYá³{µ%à u"†|³9œâ÷¿lZødY&à~/-Aò¿ò1''öbPd•èŸ @V×QYÍ\­¾1cåîõ(ÃÅõ„Ï—wlÜØ¾Ø}$A'(ÅN>“ɾLxS s¯ Ù¾ býu2it¶É×C–3`ŒÝF‹ÍMîå”i=pToifT²Î¿„ꩬh¬0œØá¼5%òÂBðÉOŽ”óšp¡6w³^A¹ÜŸ w‰¬îN[µX¢qmnÅqôç$\ûö#eØ:-ò}Y;väÛÓ‚ѺR¸©þ H™l]ï¸ýÏ}úöÕÒ%•Tw~! Ì¡¾(êcÐ@øÁzgÛ1ºƒ$p[àc ~üD_ÉXTD¤OÂ'‰vŒ;~€¶L)e Ë™ï“à°1û›ñ(`zð'I›S5[.…³.ã½YƒzU÷á­¨IÜÉ\bštQ‰ÔÒ~*Š‚Éh ›ÄÊÈyŠ¥iÔÚð» £ñ¯6 F’^¾’É‚@¡Öž@ˆœÁ+q6¸£í¢OçT Œ¿ÉŒ0´dˆ)yOªòäÊrù«qÖâÛ̼ÛVµŠù›8`]bX8rçé_qËß½gFZcûÝ¡VÅáßÚ^Y,gfY1‹’Êãþ¶”±æö(Tݬ“×ðÇáXòÐ#÷ùNž& ­Æ@hå?û‘ϼýíP%c?š¦7™­ÄAÿKt›Ï\†æQ{Âô¢@N„5 -þÉ=Ú¼íÏpËuŠ.0¦'Ÿ:}#Ì=Ö4`H7úQœÓÝÆ6É0œ¨]lú¡cNúË•HÕ®¿ä)¢Vß’TÙ”ê6/úç}s 9³®½[ˆYeªJŽ!ʲ÷Èé”Ï4®Ùþðž‹·þ§«Tž´BÕ‹}öÿ+ñmAq‰ RJfŽº’nQðã¸À}˜€r¯ƒ²Løý"¹HøgdŽ…Hw•ªp´Ø n‘é˃*YŠ-0Ž“BÆ ` xŽP1V˜ÙKÕ[Ô×ëL Ó•ùîù{{ŸÀ,»çoPãJ ¡’³|¡œ¤Û¬dŸ³ZæÓÝÒ!â_xÇà϶ªTxµ]#¿¦ìñJ£\±ÍØ8àËžÎæâ…Xnÿ.â @r:=„ÞC¢¨”Jšïm%Yi•a˜øOôé£t é[üå¦~W—¬Ñ¬bÃ\§>T$JsžíØ}”~µL̘wÖݲÅ×M¹<>pïôñi¨»Sfƒê2„ŸnÑNLƒe,9 åóö*°ß75ŽõÀ­ÛÜ“ˆ¦.3! ‘d!òÄ3U>Jd^ ¥?'dxˆ' 6,gòQo¾î@EUwé=£–6(>©,°»‹MXª†}Ï« £ ¼e˜™#èŸMj¼œ³OLI@âœK+¼ag÷ñ*Õ ÉAÆÓu€…¸¤â ðï5‡ÉKŽýs… ‘ý6¼ü)êlâ¾s¨v¤’–/“€{®sðÙÇÓ£®‰÷]ñ£ì±¿4W˜åǵVZ veðK§èÄDÅ ÔzÐ^ÓJÀÜ=0ÙÝT;ö†ä™g _›3TV¯6F²—Ãâ´Sª{Õoj˜ó¹u÷0úo'ßÓd¦-þI×»?a“¹ç´áBÔtža¬J@­Ym?ìÚÞ @f·>}—[aÄøOôéjÇØÒù >”m+ÕqEKTó¬ ÜÙ?b‡nDÜïó߃¬¼„\!kÞë¶ %éÚ™?güuÂEŒß•,rÔk¯œm’¦X!8¸—ü§ŸÃY¶“j£µ‹£Í›Ûð‰ýÏGvV5Çp›Wñ6â7C5ë]#-ЯïIV®‰ºwGQa @ú´€%ÿ9Ò®£•ˆd5{¢1öþ×#~‘Ë)BAZ‘Fªý‹ë{º:»7 2vóGWq!‰†é™æKÇn¯:F³øâ¡ñè B4çæNc Ïø „‹ÄÞû~ó Š,%‚zÆ Ê  ú¸§G;kƒ9Á(ÝvÛmߨ{ƒ´Ï°9—ÿg_ø(¿Þ£Ç5N–ÎÿJæHœdÚ²ìz -l„ݼ¼x¦–zŽ/þgfÅb-ûý[’·P·g•C¹ê ±û ò7 :g§ÅõlÿI“ Ç";ë=@;.ÒïÌ–§³ÕÔyZ´ÇŒÓïS”Î]0$œ³w ,:áÉäß9lª5~\DuËJP;ê)Q6Ú@"¸ßZyø¶LÌKL}aÁ±n¦vhŲ-á]î.4hiZñ4âí.Aí¬/³-j§oÅÕ:Úá‘^ƒž9Þ^äT8¯&À3eòrTRèòŸO6^Ñÿq€ïHI-ðŠUÍH ŒY&€jp´£ÈX¸Û\(&vš„üH†Ô µ%x6¨WQŸR}Û¥^«c–È MwS^u´[ÊÿQŠÛ< ‚ ÞBý4åðîíì·h07¤í³ý½”ýaÜÁÛüŽ+ž±CÓg|5–Æï–n?}«Üšìà±kIôUáÅfŒpPµ"Ö%8m.¿ÈÕG‹OÔ+¼Þ/gÉŠè¸=’ôÞFÙ:É7½NbÀœªýIyo®]û)|œºlnäa)sº®’æìVr0àåÔðœosMVfôÊäî­…Ô@Ƶ׳ÜG9T9ùOöMˆê„A·³c‰£;ÖéaFŒ©O\&ÞoÈM÷zÎ~»Õ?#b®y|ªª|¹}ñvÊãnLdÏ>I“Cf)ƒét´7)“۔Šg(<Óß—dQr¡ÅîøSÔØ„EZ~ÓØí9 ô¯%¥´'ô£—³Ú3X“q7zmwh©p$ý›m×.ag¦2ñöê°óMs·*_û¢ºÔ»ó‡hƒlvâ4®ØµþZËÒ­Ç™ š>ô=äú¡µÕʱ„ïE˜ûkªJ·pƒýó‰Â1˜ÿúŠã.uË@bò[åàí™±¹žõz=¸èS«6,g›®³o¡·?¬–$að^u&K}¡ïa5£ÌÚ‘s=GÖ(ÿf~î0¨"Ê­ÿjèP«œ¤âpP8 ÆW—g]?£+±Ô‰™Ï6@Y†<€ÁL…‚.×oSÕøìÀz6Ld±'Ÿè"r,4¬ “»Ð]RÑ7zҢƦ†Ö;˜ÿ: !\3F|$«Ø²!¬ŒB;©Z•löÜ`¿ú÷ƒ’&#[ÊÔϹpºÊ˜›áœöÇÏz_=ôMOŸÄ+Ö>feó ¿£øŒ«.~¬ÊãFwÛq¾Js£h"msZ€êW²ó¬|uÄ…N–¡`ev5¦~¾” ÒnõkÑNG![VgÜnp³^ “+B¤¤®+îEî—¡Öìë ßÑbƒÁ¶¾ÅÅgc±.yÚ$‰a̸ü9ë*|ÑïØ6KRó£Awwà™ÒdéñãΔ‚øt[á_CIRMÐn˜mÕ¯½Ò}ºª§Jš JŒgÑ耕BE›>wJ D¶î¦•SI¡ÚÁˆå‹å»þÞE @¶_ÙT—ÆMM*µ3!Š ªòÊ©K·wÁšòŸ¨M?ŽÆêpš$~õfIÆ/‹¨nò±ˆÎ낸rC¸ˆ1RÃÞΡFàx÷6-„•&§¤À@§ù ˉ¨Ií»zEúQ¾Þå‚­uÔ‡±6D»'&Ý7áFðji#çU"'Ûð­‘41†žI+nTécT.f÷œ˜zÏÁ[Uc¿tk‰Çš¼ÎáëÎg}v{‡×•°·°Üâf¸ÊˆÎ®ã¢8Є(¿]ì\óð–FÜ×&ÛX`i\ ü-Û¹¿rNÍ¢?Ó‡sp%aÒ­@Ÿ¯Ð uú𿎘LÊZìSÛCÝ˽.("l¬zGŠ¡íÆ4‘eE¤"ưK¿à8ã a»Ÿ:ð ºþ•ÖYãüv¡^#Sò†ÏìHmhü 1&ªc¨î´yA9"‰&声¡[B΀ÔuÒ©à‚üõïe¹”CžDÑu±”±Ö8pf3A/ósîQCƒ2¦’;Sœõ8‰Õ¹JAifAòÔ‹sÃ3'ÆÌ.ËŸnuÔ°üWêI5¶¿D9*iàLK:/°ÔÅeñ“¯-°©œ™ï<î :š¤¡ž|ôòçÙͲµ®- *H¦2u¸”_ö©Gs #r{©MÊ|÷y »PSßµ ðž1Aäÿ˜¸’\rBå¬Xön\Ó}â‚u‰8F²iíuË3{¬\=ùŽŸŠ[(N|´7Sf胞LFÅOÝî…;>œë逢€l«JÏ?ò+æ¥ ¼’;2|l¢‡±{Þ¼ QëŠ×²öTÚc»Wee¡‘IÑÞGyÁ¿ñÊÁö ÕŒ)ç E12šÄ«»¢axô駎ڰɹBòëwh±Ñ¦É{àÆ’^1†ÜkÌΔ«û+%ºt·¬˜â4ú*_ÇÊõSkvö“³‹=&¹ˆ •æð×â†HA®˜8ÿL6Š `„´¹).#Caœºñî™lo€ ë’…øqíøìý !Ÿ„¥µ!{ôÞ#«‚äØËŠ¥—yI;MÜ¿ºZú?寬XPûFÔè%áOÞ<È»fï|ÄFÜù÷ÈÕƒÈMÊõÖiÉ‹þoÜ÷ƒtÛk33@Ô4£8¨“èI+›D?–˜[e;rƒ·•-("d“õȇ̋(Ѩ,CÜeç—£K6DÁÚÚ×V•— }Úÿqí€Sßšÿ{Ià¾ëT‡,®˜À¸ø%¬دxKmÒC¡Œ‰c„²XMÜÃnI±#U÷Ðç <†”U3S¨AÁz7:D¨ÌŽ:,­ŒÏWò#ÜNoV Ô 2Bƒÿl˜v½¸çô„ûäuø«$dâ.lÚÑ <º=¸–Òq¥ÓgÖ6(;­(àŒ1J9Øcá=-Ö*kûDŸln ¾0¬€G‡»¼™ ÑqgŒžÇóŽöÙëJ;ET§edÍËÛ *E¶]¡×(•ö©àÛÛ¡aBP¬ l ™ «—¤ßd9àwž\úñ-X}oˆyC©þålu滕_ÂàSá÷øatꟅõ*v@ò­Æ[Ý”4ì>03Ñ(¯v—ô4ëÁ9@oýø·ñôØ3H2››¶jù‰âÖ"åˆHþ&~òéULΑVç›\†q›ò a¥vzPˆú%†ðàŽf ë‰ý*?¹qÕPŠçþȼT°JñÖÕÕ`«ïÖ&˜®š„ÑI7ù¦¢9 <[—…ß8À ×ë’ÂÄVŸç!]öx‘±ZÏe—xð¬*õu暉¹(½[¬ÜXÉà±Uq/r¡„îCØGWG?í[ÝѪ¡»>ë¦&)¿À™,Ùî˜iN–£-ô ë.& ® ·`ÂF!‹r—\‹²)&7õP.\¾eÊfÓvÿV}3ª8ÿ3‚å+hØœ•”‘[œW8¯_áÏE0ä'c«Ø¶ÃÇ]¿ðÛG¿n+Ì"kÛ¦E«u事ôÓvRzET‚HÊh#2[ç66–bVrŸÂ£øÈ­.†‡¨f+ŒÊ(%}òÏBñ¼`¡Bôú'3¯5R˜p±®‚º ì©?CC²x1©C?,ÒŸFœ(ã•„¢‘>tu]¯2t§Øì ±Û¹·M5&{׎­.9A)~«”Ë3Œ»àz¯+ÞA§©“åý 1þí¢bOä—ÁãKhL=놵²¼³rhê=ôŸˆñƒ!s XµqˆmØHÆó€ñfÆs18ô–|ÚD¨Ûecyò”ÆSßj¥tFÀ Õ§öΗVB^XÓØIGWÓ*—O„K˾ÑÔ¾Û†ž}*$e[Û¸©} èoY¿ |TËzÀãªKÜŸp;lËPž?ž;ô“º5¥ð>¶¾Mþ}¡|–ÏÜ‹äô÷ùý.þ}Ûþ~ß~bÿsûvüý üû*ù:ÏùûùúÁüúvù:þ~‘_#ïÏÕ¯Ïéóúˆ¾MEþ~·þK?çô'ùöWçØ¿Ÿµ_Ÿµ¿Ÿ üøuË»ïøz.íoáï+¾ŽÝôÒîÕþë»êø}z»Ñvk½Õw»nöâÃe<bý¸j©w¾÷³öp2pD’Î7Ï™ô1;!…ÑPçìÛ“¤0fTÒ¦¯Ð‡ùöb¹6í VóþE§pjՂܪ¶äýèÊsƒMâÜ®"´bö>´„# ·Ï³ŠÅµ÷y-QöfÇ0\d>;3õªpL "õƒËUT´ÿm´ÃK¨}ëòÓ­ön‚ÒÞDÃ%Îqìt-`á9ðFh¦Ú$È#’«×A*:êÛs¯ ¸À¬+ˆmöç…(È…`Ø›©‚ãol ÷£U¯Ðö.7ñ’ &‘=Ãþrýkû‚>ïDE y€ê!œßÃúîÁ¥·HïìyŠýî@»6Ĺ\œ^Ïæ .Èq,È%*A¥9E³à ˜—` D®¡>̬ЭÊR’Ñ1ÛH _ ¥qÜ(œ%Lo86ðÊP¥<®lµÙ£DlxfÃO$XÉv÷¤äŸÕ×,‰,¯WƒˆÎ*÷¬fH2G¬5ËrÖëÔŽõ~ð8•Ê äž KÚYã¥Î2hLÍ“nü|cô~u^S1’¬Æ{„‚Ù¹Ù&@»(ëœ ˜<Çc&w¥ÄÚVìu"hÝé:1d¥nJ“+3?= …Ø*™¿™V#›–S`duþ­Md÷îÊ>Êô`¢p„g*±Knˆà­IuGÙ&C‹J¯p F*¶Qv©ß'­í˜W†L÷‘TÑûZų áѰD‡•ØÊZóT­¤2 ßJ=G$éѦƒ'PËSŸmû-ÕToPÜ! Ysƒ81ØöÃUÔDÀO2VÌFu M…ñV3Á¼ûß©YÐjÉäYf-$†³V©IÈ®¿üÊæØÚbæFP¬%VoÆ]yFüO(ªO”ãpµt¹$Ñ:Ú¬ç2EÂw›QI âa\S ýo€t›èO¼ ³ý(tÊjê“æbFæ¡ã*¾Î=ÇÞ¯ ¿wºÑJFOg&va3z«ËÁ –¬cزj¥]Ù±¨LÚó›Ç\ýûƒ7ƒt>Þ*RøY®å¤J*¢ÛÁrzçQÝl‡ç¬…‡H–›M¯,)“‘ÖfÓX pMBr ˜oý¶÷†%ÆS]£Š¹éVÞ[o ,Ò·qWÄîAÜYd×c¸¿ï}HÏN&ŸTgê{^pŒ…IyÍ—Ý*&ÉC”³Öõ}:ƒ²Î³{]F}Èéc;'rN‚E×iÁ^œm×o9$Be=›ïˆÖ5å°_Î{¬ æXÉ)vÒJUÔOpt{;™ bôÒêµìô:›2bßXç3ë†|:’²H(í‘X­T,]ŸÃZÍ=‘4§NŸˆšíq$ð‡”à´å*tíM™iTË’ýɉˆ7@#ªÈd´‰ÃMÚ”Q”eWcäŪðœs¢jú wÛZ©·ÔÝÖ&T²±SgÇØp,çºä¥“¢ žSM×ïq|ŠñrÆ#•·®`—Ö Ê‡ °è7 [Vu«K+ÓéáZ’E‘NŒØÿÏ\9g‘TÆ«Pj‘Qœ](K4LدÙSºëåjQ(å4j&úŸŽš«’oîô@ C¿²åBÇÇ•ù1üĘoìφ:Ÿ¼÷O¨xI~‰C”ˆMÅ<Á§ûÖ•âVá¦âP<NgÙó¿ç¡e§ó#® ?™ÀP}"b?õáPÒuë‰ðÔqˆlÄ; £…£q’IÉ­IGÅê?ªŸ£ñ÷è>–-«©ß•=Ec˜ ]qg_ØðÈ×—/09܃ò0´é=w&@Ê‚Ú}¸áÎB<ƒËº•rc•¢ñÔñçœÇÄxÑ9Pç#²]ÛÐæqï~—ùûº”ccOÜ~æ òt' l%ééŸ> '135ÒÈËŒÛä¦TjÄMÁ†ï9mÚxhR‹u«Æœžï›n<œæ?G×luž¥á¨‚U+¼ùUp,ëßg¹[’­VzÉ͵¡¥$O— ´ó=ª’lK§&– Š…‘¯ì¿›ïç!¢º²ŽÖ‚Årå„<+r;äQ"$pñÜÎ öõ&-äB“¯®]uÔ0¯o0ÿ~?Îâ ‡'C†oœ™„¹Ã‰ªøý¨¹ýAtŒ^ß~P© º™ÀÔm«"»f$ðåº3ΨêÛ¾ñºÊý ¹­¹eÍäÂõ¤å>ÒkÐ9côL+qç5 ­GŸåÈfÈã 1Þ<Пç:€G¡ó¦?³Ì_I² û4Ãh>æs³Í¯º°%Ⱥì!q(b®©Ì¹$ÅÆÆ§9ÌPe!eЛ¡9S ­‹h6ð'¿øP‚ê=eoËkƒÆ¾+Ýôz]·¡V¤Fäá&Ä4Á[¬¹xO(/y['…<¶ríÃÓ—ÿ»_XwgÑvØ¡“|™3ó"Éd²`Yqnƒ:6öº~&Dí‘WN»‘¤TÂü/Âü/Ã#3 Ð:Z›°e¦Æ»1°|A’pVúÛk}†²ã¶5F —hä¿¥…ä)Ô„¿»‚Ôé×#ô¯„Q8ÿ|ÊhÜs'_¼Oo³Â[R˜­ˆ#La:`V£”ª {ϰ¾}…óì/Ÿa|û ™˜ øhÝxsw8q¥>µôx¿@å¹UµææÉ¥pšðmB×ö‚Ó^ލ†8#5í)üÈŸ—oîY³xùJÕ8ÆSˆ§•ýŸèB€Ò-EbjÑ"¹vrçÄÙPeÉYÚ¾O¾ƒqÏÐ'Ñǹàõ—Ì4â»×g•Çêm”Â’Fcô¹§¢À/pû¢\xÅKe¤«RÅ 扒Y `íXR™âä°t}'š)À!P‰Ëh!äסµÔzZÚ|X Áí6ÿb‘žË‚åíÕÅ™…ýüLI^ÆMeXñD`dÍZ­f³{Ì6=ËœÑϘ‡d! 7ôl/@\oL?ç¢Ýˆð®‰Dø¦„€¦k~#âØ>•À!¨IÉoH€Ï6ä=¿pBŸ€ Ø7z̳¾³ù?C‡ßÚUt ¿ÛÇñ÷Q 0v™1Í•'±X(†–*±É_ `–…hª?¡"2«•þ` ÿ\³]ÀuÁN7‹Xþßs¿øÙQôˆ3üIG ç„€­÷3¦oä-}fJôu³VÔ •PŒ¦r›8–‚ÔÞ•k¥µÍ¹Mˆ8ÀM—s€Å ›°¥p’>?±¶Hÿï½Àï‰cøÃî¼{ä×—@ßu»¢ZnIS¶au}ÍÔ§bc°ÂB]÷óXÌ;}.3±ã5?ššp†ëËv9;¨t;Ù¨4“£,ê D!r¿Æ9Ö"áõ‰ 7VÛ„â+i‘ËJ¨‰ä»tµ„×1Ù”à¢kª¹EÄ„ö÷É’½‰¢ßÄr˜ dÆ÷ಗ%]»š0t±bøsþÛѺþ•MQ‰Ž1Š0jŒÉÕ<¯Ä9‘„Á Ï•àËt5!#›Er\9¡oþñ® ‰°Ë„Ð8K¸d2hdo‹nù)¼&K+šê¦oïÝ muz&ƒ¦YVð‰SñA#fð8ƒŒºˆ»a±køÃÑÀ;袙’$*#úO™)~Õ"43Ùª }hѸXÿfd–`¯kRcÒE wܨÁ€hûÖ £nÊЦš~c14ŽtqfVæ ‚Ä¿yÉ;Ƶæöó&ß|O ˆCó#—)@Ò¬&£¾ýjˆ®7æ¹ËêÕñƒ ƒ¯,ñIÖÚÚh£ù„$G uÒK®B¿ÚZ©û»+{Ôš!ýùZ:;g9{æPP¥wgnÞØ¢/Œ_¦3»¹¤çy[QYçûÊ1iÆ"Û†ˆc%v­ÁUú㔲é–e¼ö¢qõ,ÿ'È`’Cí·œŽæcV[·>@Š6ÞÉ…Õcx½{Lø Mà· æõã•=yЦ£ZëqÊ ¨Ô¡zþØËœ| úo»+ÔÙàå•„ý¶„Ç’Äœ©â¨4…‰ ~5aˆUíƒWVÁJo[ÍÚÏ®€R²£;àf´-gˆ‡JîÙás¥uEí÷R7Çß|ð*Y²žY §Pc÷ÛrDÎ>æÝ¬~ïqRoºê>¾ï[»qÜ¢9ßJ¨oæÆ©½÷‘x¯k—ɦ«ìˆû˜7Š®bǨ'Ñz¯Nä¦ö”¡Ù‹›" [ Wg€ëŠ>FÌBÄU±ü½Çq£•‘/Øýzա¶¦$’pà$V ­0 p}ýÕ'ÑWVÙì™.þÔŸsæ29wc`hÝ –”x=‰àñbFuq˜¡¡÷ÈðÛ ¹ñŽš~P5¹8÷fv[¼K&àYœ€÷$BodÃAhc­kýsFg„™¥Ÿ€OSD\¶°¯_&‰†˜yþô57Ö8o;·°œAA~k¼¿qI\ðQ4rùˆLzågžTJúM²ÒžÄ ©Jí㣚Nt$•„ …‹œ{‹;­É%Cµ˜mXœû½Õÿ[& u?Ä"½ZÊΘ:ûfßè3w+SÕ÷µkN•ÝÑ–Tñ`ÒSÜjMS@s>&SØciÛ[OTß‚\ËLÙh²ÐÅïíጾMH¯vp©) ÀZVÐ7Ò_˜ãð‚l>‚ÏT¤íËwk’ÁÚºA(ƒ8ýUéâ3?en¶Ãa/$©TÜè$ë³8›œÿAŒ[(‚¶ßã/Šâ*/÷mê–µ¦z ¬ ´Pð.nÒJ4 [h­V% %||a¸Y6î}ªpbQóâ=ùu7gúI$Á[Ÿ¸1'K<6+†M"; nna£òX8òdfº÷ÞdŸÅ%ç'¾†#&‹ZÆ ­nÚa7÷ççíoèroi|Ø«Q^Ón@Ø¯è—æðµ G>ÌQ¡œÙ ÜÄ̹…s¸hš›§Ä³º,RdƧ² —Ž`.“êáq˜¤œÁPZ6U>|ktüsÞÌfhc1ÿ+hCÌqæ°cIÓó/ck„ÇH~ °\¦Ž²VT`6½lä©P¹E¯u6ºëU5x5‘ßD°ù+5^¿ä@ ôfºè¢íˆ”ÂÞê‰>º1xׯÐ4¾Ä1ÜXˆ8²·ÉÉÅߪbo–h9aû€Xšw²-²Ù`ßËÂ¥(xµÖªMÊ¿gØÏO¢lFàÚ­Ûu\@¯¬Éú'yžãâVéoŽ“eìÜY† 6çâ*ª26) âÆ÷+g;Å ”)Æ-`DÁ‚“…D–¬ÙzÛöó€úíÆÏ›hë15#Í18×¹R] x­—º½ˆKæ©—AP³3b#Û³€O. ´õòäQ„ä3£n¨Çäì§¼2Ђ™$UG¦&ÁâìšÃm»ßXÈ*§EzöàÒ‚bI‡rˆÇ–G —àú¡6/;gÒDÒ¹íþ›Ë lñ[mþê*˜ „ +ÜÂÔêeÑÆ*ð¥,Ë'u¶ƒ´(¢Ç© E¯ÂQ'Zåê(]àqÀ>;gC­&íâ“LÑÚZogbÁË~KDxÒ(8#)WÞ¸m_‰*…ß5§¹:­Må¤u¹yݶíïZ õ³erèSïÅGK<ÍšÅaPÄäEzÜžGBi?¼»¹ªýÖñã)†ÔIòÅÆØöÀ"R3LúɃ÷áa³šÊÒ*X<+d j_¾r¸ûÉÑZè2ÌJ ’jÛdIŸëïm¢‰YØv¨'ZÈå'íô6ï¾+æw±J¸N·Ò‘jô?É/«2b’âv-ææbÌ¥íÁÃûP"–׃¡ÈõVHÁ‘ ¾À¤qú{½*ðüðY9!u|› áøX†„”å£~ÇÚCÏ•äð(5æ[·§çsrgë÷\ð!Ÿ'à"äŸí¯˜E Õánî‘`·™æˆ{Å+ñi,šNä×<nÆêò¢Rô0ÕÏ $ÆÁáF¨ä}žëÂ%¦Üé+ËÝðD@0»¶¥` ×ÆZlO.n~ ­»®g¢H¸²o¿ªÇ‘éÿzl?¡Ä^ǰH~q$Ø»xõ, ÙÁéSf[‘´•€k°Å$ Z÷ëîT™€öéq;`<ÿtGlÿÂþâ…>Ó±ÄßmX¢ òÒ¼–S;ЧËzDL«â«ž)ð¥+xþ:7Bx)xʲ¤¿[×µgžˆ’í7éxä°Þ0=%ÖòíŸ mô<ý³‡Ì0~¼ÇCË!@lDpÒ-9yzÜÅ“Óî{åiÒ™ ð·(‹c™8WšbëÀVH‹mÂg¼‡<”Ÿò  õ^Y:tdxFÃá{‹â€õ” ä—ÑÂî$nÑIþÖ˜:¸±ziêÐAõOÙ¬úã¢}øKJy»ÊÏd_ÉMhÎ0GRÂ[˯”ˆõ:rvôqC¤Ÿ>·%Ì]¯(º:UR_&`Û]„±©×Û¤”:JW×?Z”ÝL1㞖î·kÀ5›Åß—¶œÀú/㊕JLüž³›ŒÕã݂視ÿytØÙ =ãÜQ]@$/¶¹fa&¾Ä+yfT£™U“…#sêá|jhëÊL9 òlûÁû'v%ƒÌú·^L=1¶}ŠÆï¼Âôˆ9`.¿ÇÕÌ„šKVsv¤K$_kâëÆ³òV6Û@Y&ßžé€I–éstK\aª#_[\ˆ”;{ä¸NR펊«Ší—ÒFœ®º† 1Ŭ–TËüÄç‡ Í„já…Wzi„[ÊôÍÅ8FE€aˆ~[W«¡2~¢km7¸…2ÏØëך#,vX7Yá <ÉŒ„Dà8BXWeǵæh¹FÆï €Är-Fd¥ÓÇÜå }öD9…Døwq‚±2ðŹcåœÑf½j r-Ælͼ“ÿT‘9\lä"ØcûÏŒEâ XÜûˆJÖu¥¦õ+Jy_¿¤–l&ô´[ùAvM´µ¢àþýµÊâàó±#Û èÀ‰àNŸè+D¬}>Z¯!Ñ/¾p¸ýFö5GÄ  ÿºšº÷ RÔbáY÷¬–žšÎaŽ5¾ö '’²[7í»Ã!zóI~jÙ›ª·@“Ï]Ý“CÞ–ðAòVNxšhwó#Ç;ÿ#±›r“¤Ù. XhÒUjf2Œ8yõ½*È“«Í†¨{H?&A+qUco(>]c7º@Äú”d),±‡0&9hSÂÊ’v î#gaÙ‡·»W×€ÉЗ@e µŠ.‰_ÌÁ¼˜.Ÿ$8BKIÊÔòZõ+£ –\¯9$Py½¡ØŒèŸ'“Aí=ql¶NKž”ñízÙæÚWy¿±·²(ƒ‚PìiqrÈ |Í-jÊÐõùàtüMûaE{7žfT‘B;À]™n/ënYÂiT¹8ì´ª 6ëÕ9|RŸÈUA¬;®-# O@ÅVÌ“!üŽøße=3ìzñæfHô6f¤?{á[œåœ_Oâú9,`ô¡Òèû,UÈÒQßɬT"1ã@™É–Ø“$Kƒ…éN²ÿÿ œåBwä®Üœ%Ê‚@ܰÖA9%ØíVõ/ý1{–Óü á*âÁ&\ºÐsà¦ËÿK2¹Ð„!cα/Ž!ŸÔdJSvr÷Ãä´€Ú'JŸ†TéyL¦+º–„Â@ØÅ~åã"êÁÌØ\BÉ£dP¢Õ+ä—ƒÜL•«kcÕUUUUUUUUUUUc4 ÷WÄ‘€Å½KE² ÀÎÒØ~ýÜ=heÆW:ñ½A¼>ìÆáìÅ‚“¾~÷6ù¨$ðãäÓÏ©ö„}õïA6Õpÿt³"ºØû9(Š'¬œJ+è…èG¹·¾6 _Jºû?Ú–ôhÆXó}¶ÎûžU1s~SR©~ °{äÿ}/Žk¯N=YÚÌZiŒ9ñˆ³@I‡ŒYНhcŽ}šMJQ“Á!*™ûµg¤XtSì;ÐR>¸2ò[«¢·§Ï(¢y~z^B°Z‘‡|½ÁVÃMÁÜ‘B²&gÐÊ´˜²¤º<¦¼e,…Ž£¡ñïÉP5ð"‰ä¤’I$’I$’I$EX ŽÜÝêæ{üUÜøÑ>ÿ¸žå' Pç>é E³¦LüjæpD,?çÁ4¯ S{=<‚RTwÇ+¼²Á9X"ØöÌέfšh[@l/ëA¥(¾fÇé¯)ŠžNYîõXÝ(OTSFU̹DOˆfðtùÀu)º5Ëw›x˜ô®Øu&”*5º®Ðû2í`“º*ð»»Á(_ ˆôføû3ô†³ÔmC¡ÒSæ+_VÌg*ïî_sè¾ñöjéŠlÖåØtR¾ðÃMça4z0&_@µö§ãÒ|•®85'›Ãö }lÓ½ÉA0YWæ+Ði}'™mØ Áƒ/x,÷j™ 6 \´Î0'Ä›ØxμúÁD µlgPÒ ¥ø<—Fa{uh»å‚eïD}2š³XofÃJ× +›8×ëÏË0Ú)ñ´¦ss•‰‡“4_« âß›ÀÙ$"<Ùq…ÔÚ÷´‰ý¯Ÿt´+ ¥.—ZáF¦`Žgw¥TC̤ŒËB6ËýÅÁܵ“‹ühÛ<‰Œ†|t2ãL¶1 EÆë¦Òö°xìÁ>ÈžV+>8Ð'[ñQ @Œˆ ‰Ÿá ·(ÒÓæÎûéÇX£V&XzЄ‚Ùš«tУ$©Ù]Áx$†©Q©­u]*cœd4!‘ ¸JøÍ2B|Ê8ü·çô€/úýˆ™·€z¶Üj¿d ‚Ï‹-°†¡Ž>hEχ¡4 :¦°Lí=Žšé[DÿuúC[•9{î.è.Ca*îš`hVM¸ NeŒ¡’øÝ€8víNF%÷âý==^hãaéýè+Œ'}sô81¥3γ hÈ!ºý \XÍ'‚°áÕ_KíŨh(!<f²À.ç9Îsœç9Îsœç9Îsœç9Î{^·Í,/ õªúúÓmoÿÿÿÿ€¬Žq#žÀ¾L,nø .õŠg¤7ä2RyÂ!1—¥Ýkà}“˜û&@<8è}më0ÐLÆ7'’‹²t¦]tÖ%òD|EÎvŽ)ê½ÂÒ»Òð,¦¦ÏÑ/|ëò7ýö÷’dÿB¨IÖâ&/÷m[GYÉg7µe›é¦^ñÔÓÚwéë¢ÜÈhÆ;2[4Í9ÐwSt*‰ˆì,ý;°ê°w ÓçþPé4k¡Ç¡k~Gè§üHûÉîù‰SÇ+ Ûª8B‹Š(̱ÕÕ@¼¨$’þMþNý&ýyvq%wèÎó+¾CŸhîù!‚ÑW»Í‡ŠÄ [-aï1šØŠ‚ævQ”Ôc<ŽÄÇ{ÆÂ“ø7%£/0¾§–¿že¸¾aÙ즻n€‰í^>Ö­ÒÜ"5¤£Šÿf.ë­.d»@ü%~’Ä#èä~ô÷ KîóÆQ±¿†‡ “DהǞ—ßíÛÐÞ J0–2Å úå‡G\T/‚R]Ñ'üc. ^`ÕwƒÔ*0Æ@}ÒŒ•Ièà–¾ÉÍQŒ(+Ð@™<£™C"Å9—'þi:MðÑ89%˨ó±Ùj\kb¥ç]ôÈäcÚâ™§¤RÀ‡|y_ªxãÂÔ¨â­Õ¥"”&ÎÍî.D#œa‘ã˜Î]Æð.s:q¡ìH« ˆùÖÂqè c^ÈÿWàéOü.øà|F£ýkoFA‡2è=õ݃Š,·¹tWÇå=ßÓ„“j‹ Á𠼂•4SæØ.wç‡&Wëò_³éœ92ÇuŒêCk8†qlYþg)¯¤’I$’I-]ýªd mþJêrÉ=‹û~ôåÅ{ª³[}Óî` 4ï.*Gvøc8ˆ ðžíÕ :¥`›.½þhË0@Cࢤ,”©èæeˆ-EA}ç#ÎÕâëïNlzægÙ’Ge¨®,Ÿð³A„ºX¾•Ä"¨ZÞ¨¦ßàü •åé)—/˜æ°íO¨. ÿX•t­>§SôäÙ0ÑË¡áËg )#\Â>Aq+;F „ (fó"ºÝE78¾l2¦JÜœh(rÑößêæ¬…#æÄ÷a8u‹–Ò%_p.¼~bê¼äšÖ £óÛ3czUº4Jâ}†$zS–$~;O'÷!ˆ‹L••Ÿáwùæ t<ÄŒ+ò:Ô®¹Vò‚/ X‰Æ5Q¢ÍU÷Ø›â3V¶O–ÝIýu¯>ojkvø_qß»|ùÞ¿ ¯rù£ ¶ñÖÎÔ8ä˜ìVuÒß RblÇ8›$‡{ê‘jþ‹P+¥ÉÏá܉K/,ÄÚXyÄ¡‡„êêÌöÿ7pópô»ø­ý4-\²Ê]žÁ{‘:„×0tÕÚ+~J_Þfö-bHIÂéŒÂÛ™±g7™ ÎèéÅ@ÆjrRi[X®‡1+§ž¬õÔòäÒª¥b8Åg2—w߈ƒð áǯ¨³;®Äën1Xí2Ž(þBﹿNU²3-J┡‰q1J1+•K:I vVš…ä6C,$Ø*ÒI(^eAK‹Ç‰É>§÷³nõ_~¹-^±Þº€ÂXmŠ"Ö}Lû[Ýä]t«PC@wú7}Ôa"ò¢ªiMÙuÄ?í%( Sº'=7üŠ|À®Çžh{Uü´Œu*^V*ÈÉîŽDKÞ¬ï]ñq3;ÍìHÈ÷(®¢šÅkq_§t 9ÇÄžßËŽ ÷¼v£Œ? ¶É·G V»XÕñ¸[hSNdOžþ]D@»U¨ Y¹x:Ä1¤ézrïbçŸEØ-’Dàï{Öþ/úI–!‰3D^‚uµV¨ŽàùåËÌ"nµdð-u«$ ¦ ò{Ï/a¤ÖÌE­Ù!è·±Œƒý{vRë ãawcFâ]ÖÄ—Ø(ô»êS3ÈãTÑêÜ$•ÈòN–¾õç‰Ö0ðºÁSr)ʾ8“ŒpŠ"{o% èÚf»¨’ÓÜ ¸Yu€€sº‚pBó âç{fPßµ³Ó)©±Ÿ¿%Ú§w@eîÑ´€Ö·D ÑéVyœs0ýD1,¨0åð+Û1bî!ì$ÎF™µ+ë½/¥¦¶è}ÔÍô<á¾çôvÐ^Äta:÷7—k´qÕ‘ˆˆµ“C•pߪŸ¡$Ü– Üh=*k`ŸwuÔ§êý¶—|F8áÓ㬩‰ú¡ÌŽóÈÄ÷×þLÐHØæx@Í;ЬåMI>ä T0Ð%PùŒ“Ž1O÷ÈåŽOJÈCô¡Q.ºßÛúŽÐBa…¤Þ·P16ëha?Ö‘¢bÒ“œç9Îs›*Øê³€ŒÆ?N'’’-4p~õuåÜ¥¹Ï¯8$زÒ_—i"°²R§£‹<­Ø¢*ÕhÈæM–‰Mô$¢Ø½ŠŽú,Ñ7xÓfC¦!ò<Ú0Ï úµï¾guL7а‚§oK$/í©’›ÅëÕ uQ6@؀ѶC=Ž»qO;wKª4z'õ\œ<º¡Ö{£ˆá$´ª®D³Û,Ž0ŽÐ}µcD4îÑôí:[™ÍyÍgz…µ³¸uß=ua†ð¸×©ÉΑ v~Š˜´ œd ƒõäûûý“›ŒÿVéÓ«Êò\Á;)œP¼D.C¨Ö‹3x•˜$.ã Ñî…éUµúvT8¼Oñ‘nÙºní°e Û4;Ú y‘) Á#ß2œÊp(f¸ ¬Q¡‡LbQͤrö|AÓ:‚`6 õ4 ÅvV¼2þJ½j)~ký›‡º‹Å{nŽ^fÀ&Õv~-’Ôƒª…Èzšþê´¶.Oף߸-ú4Ü¢¸|‹ ¥oFV?Ó†¹ù{z)÷¯eˆ¢Ü¼9 Ç<°ÍÚËñ¾Ã¥ oúÆ@€Ê÷þ‘ä-ÂC&Ý—^û3;X\tmS›ÜO«Ö%?I’µ×FV¥x÷vð¨'h·Ã¼êÔ È~ýštÜ¿¥vÄ,}Jý {ó˜lݧ¡?“ÛƒH¸Ã0ª9OARì€ÙÙ̃2_ÍT&ƒX«M½tžî³¹¤æ —“Á¬ùµ±ØÒÄ”:ï3´Ä*Ø£z${i’R~›%£¢Ž£ß!¶p¾[BßO’;Õ¿ x'¿•€nZòW¤à¶ÿx±Ô˜•zg÷OUÎ(N\íR>zû[Ïž”» þ¥²e„ïe=Q§;:¸‡°5;6Xj“¦ØÃí”÷ŒfgwƒÃØS΋â5JˆçCã4psï1l¾HÈôï,¢‡Tî&`'Cn®q'8,ˆ#üîìJ$Ô§#µÄHròGtüe•THà ,q¥Ü<Éòó£K&HÑ«Ï'û»Å2ú†ƒê¼(œU@& ”J÷ÈlŽ6½ÂYbßøŽ4ñ$ãZþu mïÚî¶­‹ÆúY! w©&<ó– ® F§#“2Õ‰ƒ6-Å4\]A•™Ø‹a’éÓý2®—í1çkóò´=%Ïœù"L¥€Ä£ŠZNË$’-v=Xض?w‚Š˜ß¹2Vî¼h¦,cnnS6í©n°òìaÍ*†Y#4ÏÚ¤…$±ç#(šyÃîÿDk!9{ ÇMúBƒQCÆ@N’jj6H/|ƪÆ!àºäQ˜X®oËÈU1øOÏ¿ÿä ‚“Çü1)îžû©"94 ³L¢QÄ{BÇ1Æ?ÍÎ ùqt³,²m;ß2£k§ON}‘¦LœyÇShÛ½L¹U¸NXŠ6ä÷µ&Èzk«°…(ht¢-$óë_åú–m„>^Z§œ“{ƒ¿Ý ½æ‰^’UDî뀀åV¦°uÛ~e?™£ ý×iJªªªªªªªªª¨Ü!ư³ç¦i(8oÎ˻ϴ’3È#t%%2©yլϘtæÆ¨@afY£.é¹iñÌm›iÜ¿ ¹?‹<ñ·kéÿ#èÁ­ÜV õhTÜÑGÏ^@6å|-=3-ÎRËtƒONe–ªÏþƒ6‰àÞ[6a]10·~+îf4ôl21 ^H¤é”ö)œwŠ–6ºÖV$´kî–§K&rŠÞ·Åˆm-B¶[ôÐ"µUSÓFÑ|yK¬¨\uŠÂwy„…úÖN)ã@  ÖƒàÂBW-ƒ°|ïuê³Þã°ÂI$’I$’I$’I$’ôÓBÈ&úE´ÄüÒ0rqvá-ZuS„Æ欽V°áÿR“íÇJ¡(Zw9cÁvO”ÄbÄ[j=¹5Þ÷N÷ûg€íTö u”Ú!ÁVS¬T·¨*^¹fÐÚùþø†raåµáŠrZYEHÿ^*ý><8·¸o߃hJá´ô·çꨜÉA!Œ€€ÿxvÃÔ¸zÛ¢iöŽÎšC¦@Âí ô+³™Bˆ”m âºMŽŽå¬!]Ô0ýÇE¢f¯NÃëþðU=u­z–hؽ='ú ·D€wËÔ¿ØCãåží)UUUUV™Àãi¼ !Ë’£7…[³jçÀ‰®+Ų{;î =ù *¸•«"œ,6Š2»C#ReÌ×=iPÕ¾c(¼µ›Ç:ýKßOm™!ã{8â°´-«ƒ.±¿ÄÖQqJg9/n~uVÄUkÂáë/æ¤_W êhu™è¹ é+E’µ[sjû^Õë!Wö‚%¶…eÂHŸ¨BõÅ|ÛQëÊxX7CˆZ¾SˆÈƒšönÓ#Œ½˜@·2UwŒ‘ÞÝ˽{ÇÌ‚ƒî‡swÉwz;Aì‡éñ§ í ›ï_ÒͰBÀë ÆçPmÓAA+%°bî@†×F‡oãÛv„ |`‡‘éƒ Š£]&Æ™„¸4ßÅU‚\idazÊ M4Ë*»•î =^Áö\V©×ëøƒþ½'9g• ò’œÚ"ô”‡æ\f€˜ªT+Z¨`Ávýá5Æ}}óbòÅÝ0ùYÉ Yz¶—'Œ:ל[zåoÁZò/F²åxèÊ–Ž>™3®2y&C~ˆÃ‘+U^pƒ‡·º.*WNa/õ»ì·˜ä€…Ëòi¢«ú ¡0y/”g/ö‚3Ôè“/DhP§VÞ,ŸZá”8ÛVœBA7rgÑ|«aSjKPö¡í1yš) ûˆßYÖ‰xåaNrx‘n»ùíÄrq?y±vÏÃï3‹•CžPw5 ú ÷q’î7ÑÁ(ŸÐ•L‰•Ú?çìÎë&|uÉSàfd³Z*±:7h_ãVá·:ÔiŸD¼|ž¬­w¯¼Ût×C˜  },íq cýÆÐ©ÅD>'¥Ü(–«ù™¼ÓÌJ£,šBãí8ö¸9ݨŸûˆ"£îTMcpóü'å@ôiÀŒ¼Ü V jj€ZˆcnÊ3…‰°ùÀô¿05Ô:«ü~ÃwÃBìÈ”RS£ºËéâšK¶º×އÌ(UÁ:Ÿˆ¬ä÷T½× LÙ!é£zù~gÔ]¬&…_:R/]!'ø…0ðÜå[©>Œrž·¥’·†sÝÏioUZsJ§ Éêƒæ1V]ÁÅF/F'H¨'ã{n= 3{ßâMœ”!"²à÷㬋!„” ÍŠb#øÈ%5=µ¹+†P‹…ÒöÔÆˆBÛ$Ô;3B¿¤¶d4«6ÝÝ#q^4R¿¤Â“„“ljš,q¬9§‚.¿¾ÞèÌL'qéY¶j§06 դƗÑkNZ ')àÛ¥Œ4£Ì¸ªF šÞgsƒ%Õàׇ¥ g!çr@~µÍ=|-³Òi|T:À5hèøµu2ÐHVÀ1S›Ð\2ÀyÀ¿j`ºë³ÒõU>ËÎ4 ^oˆ‹ŒR?c†%År39µê¿ÍÙô¤_J7–¨VíÜ·E…¸É4zÁÓ€öPH³¼fI°-¦s‰dÂZ¹-%ÉšR^‹$¢¬1E 7ÀACï_ü‡žÅ N† _| v~óëäûÃÃ’ŒŽ\3x#t"›J‰™^xßöªQC|à‹<&_”ú¡æ¼ïìKèjtvõ·ŽgûàÜ û]?d0°Lò‚ݽÁÿBk *6_N1j·1Ÿc#N8}:Α÷ºËÇ5ÜàýÃì"íç$h}ÄÙJ.­“D±ÈÀv•£M$èf‘U‹cNë>ÓÆ¤Ÿ_QA"1$ê#‘[ÈŸš€3 Ðx±|i~ÜH#â"â/_’ø©&3å£(kÏþ¨›‘^>D*wØ³Ò 5Mw}l`žêåf2‡|¶¼Àëçu‹õ:¤1=†çgh ™äã¦3m„Øž»5»HÌèç;ü‰èF³·LÁ_ÍÓÛtšqd3‚ðÈnð'?ž”Z DF'’«GpT°õå°I‡ås¢ý-.áú¤‹‰Ôùò†1æçÆ4-㫤^¬Í÷Aä©&£y×<-êôãcîŒÓ^˜ü`žëj8ù4~%êšxK6¯EñÆÉwÑ&÷ÍìÆv´¼ÚŽÑ”þÞxO2^ÈV«s# çKÎ¥äéæÌ±#µÚK'dÑWøn¶ŸpëÁü´•kŒ_ !ÒÃ̅ɧ}²‚Û-?iY†Á´bw6þüõ¢žu!ï×B3¢ûn»né:†s„w¨šÜËôªÍf <Ïárcˉ)hzÀ†òÿ%lu_# ÊŠ}o´¿9ôÞ-9Œ–ÜÄÆMÝ °˜ÖqM …íÄŽ}ÇÇT³ŒWãOµ{ÒÕlSç:GU3&!ò7Š*Çc |ÛÒngAÒ|~DYOÉX1?&† *ì~foÆûyq†‡½4bGl å`vd3ó#q>T\a ®òÅþ`xqÆî”ÖÏÀÉp/Z­º!ÃüîK9Ó盚Æ%P¼ÌsW×}€‘†/ž<L´©=ðÇVU¹P®â ±>N&hÇa(cwtuE‘}zT\Ü(’/SÓÎ(ñ>˜-JÏ _8>jx¤f´)½ž;P†{þI'ž·¯–3ÏC…dËB±šTë)ƒ»g,¨ÕÊ›B7‡=GóÔVm”4õ m}Éú°[«åÆ 2±'Ê1ô$j©”Ð`&CŸÛ½Òïdœ]í…z•Â'¿Œ˜fO/ï|\k×›KLÙ?À¢ˆß˜ÊˆèÔ½¹†Ç„0@K¬aF¦á®µGÀÛ ýÿ5vcY×ÊW3‘æ;¹@ÌC#‚w!”3×…0Âd­ d­€Ïw²å@,ã0qºÀˤwÞõr^ÕiÚqGc+Û~ÁšWÒ3gÈ4€ÃåÎÈÅ?xÜe(ôûöZ­Cï yÏ£jWĉaJ¡Þ½èª-x ÕPû~ñ@©§¥"ì£ îBéêí{ˆ™™V$éEÞ»Ûµ£:JK&*÷«[D‘v& á@€ÖÅIŠ/y*"í¦U5cʈWÝ(×øO~Iը̗ßéˆ^Ú_di‡Ôc:!X©‚ŸòÌDÅ5@4=«KǶíê ­-õY¢1NóÌf¡qýë¯.@žZ‘Ho»Uý!µ z(¶ïÃê7áÕç\ü¾˜üS~N§~§|íäëï|=Où=äëäê¦ü>ƒ~žvâø}8¾ľ«áì[áö¯ðè_‡±5Ö?M羊{è»ÚÿCè^ü>~k´¿‡¦=ì?t˽…øwÿaí¯ÃÖÞºáßõÚ[´¾»KøwMuWáFî‘wü=w¤®é?‡hk´?‡Ðîø}ü•¿òl»áôï~B?HÝKð÷ä¥~N 'zêë¯]Bïl’«ù:ëÿI¹gzÇ~›ü;}Ú¿ÃÞ×ÃÝ×çþMë|>¯~OÃךê·v½wÑïÃ黨÷z÷~E¿ mÕ¿C]î[»5ÞÝü;ÿpöwáêuezÌÝz×ZJ»Û {¯½YïDWî¨ë¥÷¾?z»ÛŸÞ‹÷Ñn¾©÷E­?{“Û?{uï^VóêÏ{OöÓßG¿ÞÅ÷¬ÿ;·ºUt¾÷—½S]w½9ï¦5Ó{ÐÝkW°~÷ÿ^áýê?z·÷³k^´ý×kèÏk+èÏu_zsÝüöȆ\=Ý@“}yñpn›ÓÛîêuŽ;† )6¬ßù°‹ì‘ø£³oïåë2ó¶#ýŸwYÎm¡Ñ.»(Òf ÇÓyÞO•òÞú´uW,cˆU"’zÅ\å¶kY«ÿüM:•ÌfJƒ±Äº}–àD(f`_Øfn°ó»hÀ` QBDó£#‹x3‡¡ny†ô³ÿàÆ06z$mÓ²µ POÆ)>÷T½kÎ }ÏMÓü`ø¸ÎOq*|¹ îËïè€#Ìãöä±…ó˜æ`½$l’š!éI1˜[KD‰ãÃ{ 1 «l’îŒÒ&:XG7Âç½ b„÷«'ánëWõämÐ"RÅXÜ éß­M3 Mµë¨¹Hòüðë}Hö©YË ³Ñ†gæÀ¢JÏéÚJcòüP´H_Ë@ÖI¼gáìô_XÍë'´Úã7œƒfs*½4*‡n€€LŠa9ÀIe|UZŠq’˜Ô«‘V¬M KqšæHèIò”(rÈÜ‹ðBœ> Ùz¶õD÷³¸ h]Ð[ªÐ™1wnî½ <¶ó9§˜Aô6“ôë!ãÿd‡œJ Î1òä×1ÌÏéÊžɈÏéw˜}ßúÊ~ÂöêVB/çdŲ›üž­y×u†ïV õæ ̃Lp£7¶ë׌^ð‹1I&0v‹#ôKkâK̼™\ÁƒwÎÖGÂÞ¡,§iΨ›Ê«`3p-'b¨o5© ûÔ6€¿¹ú|0E/ˆ`à>-{³‰½=X‹¿µyýú!¦ÝƒÅÍž|z(ß5ÝÀnuE[R4Ø2XjÏšm=ÄþA˜ñÆJÇT[ýƯ]³ÃÃö·<ï‹»°k+D«“S&Ò/`L[WóX!ÙÛ<%ÂS.&3½†ôÙoùn:ÒŽ©É©`—æ°ÚæØ-éÖ<»–iÆ“"•¬?dã“þÇÛÖþ84v:Â̈աHGQºäûHú4¨ö´è¿ïÚaÔ¨Q‘=~ÐÈë®ïýùíµŒèÒ+6\ŠP¢õ•†;yèãÿó°.–÷j,á[vp#¾úÙƒK‰Ù”{¹âK<Ìò*Ò˜÷ãóוo¬žÚ4Ðe;ñæ-Þoô&ò 俚>j‹#äÔ?â쳤²X9XÑG-çU®§PÚf)#”¼•€5JÿiO"Ⱥ¿ü£ Ã2Ì¥›B•ˆ¶‚è»Ép8þ+ºóÐïëŒ/§¢.DԺ̰)›û¼‚ÀÉC3´Çýþ!|ܲ´ãñ~„ù†z2QŽ’:^‹”*ÞÕ&¡»çÑ—ƒ@¼kE™æ×,ò~Ë ì ¨Lã€>8þáøGÕ}”O­?àÝiªÄ|Í #fš[^âK‰²P…[¿(d0RÀ¬Z—_µ%Àê–ƒòãér„L—-mïi$Ù<ìà”M–h#^7¥TÊžúîã/¦­Y†,ÀÓ€X¹×Mö«¯;± &KHÈ"s¢rñ3j ÖŠú2ÜÏÉ¢´PŸväd=g¹¤ÆÚˆ±o¿ç¹çòÍ`˜ô‹KmeÛ#(úElƒ"J?(¢W[*˜´_Ÿ™+ŠLŒòã«^ÐÏk2~h Òvï†?Í]†~­qÚ+D»Ãa…Oñ[)¹OèàôŒŸ‰p—ÈÞç÷³ßÎöZ¥”Q>‹\KÖ1{G6g¥é\ž}©±AºÀá’ÁSO;uxÿojy ùù ÷‹)™›Üdžô,ŽÞö)ŒHÙ®¿âšG3™B¦‹ ã Õ33Û®1QÄ~OvWfÊ×zÿ9—g: ÍH%kò\øg}‡ }¸»!s¤1O£c¼ØcU‚‚´2¾¥ðNÂVvÔÂÏ_ܾgìºÍ'ɾÔÒ¶K¿ÔÁÝÍC%žm:ÿ;šÜh¸A{ÀÖGÓê´ëLôÈ€„z¡¯U>5“Ÿ!ùZ’,­jËò}tD´?Àå&f¹æŸ»áæÀtCŤ cìs&5I2Àô­ü‘cPí¹L%Î6*½#6¤¸¬ë¢ôèîà﯌7nÚÒ6L9î 03|³Š‚¿H»L¿É‘C´](“ˆb‚ÅH`SOVÇ´9ZÎQ›làÍ|Û¢õøIqn õfÒx¸-šdž_Eùš§=cä•ý½öö|Z¸ÝúÔŽãï2 Rg a¼ÌÕb-:ÄhLAa‹”¯©ØJÛ"¶7®$åoâ[Rg“"KVùúÀk½’fiA ’ÛÏD³fŽ×– ì«i©æâzѰ¼²ˆ;ØÁäehÀZpyÙrVÀ¼™oVlã dº¬®Y®ž–ÙáLÜ\t²â'p»Š^ƒ’#a€Ÿ¡vÌ×À¯ÇÆ„˜‘õˆc.„ #Lä±¶J!ª€È—¤ÇPµâîÛ@‰«äkæ›N×`'>¯vJêˆW‹\¨6« Á·C9 Zö5Œ¥äÔOCæùÓ)yKÉŒÇzGÛ²0ö“eÚÔ&$èP;nA*Ì- ñá®øz8ÚÕÉ"sáÕ_Ú{¢ÿA]‹“*(°Y°‡8|&Aå‰?/†°3ø½ñ€kŽþú;V µŽùý#âF!¹ö±±Â°Ò 5„»'}RÜc›ÚîŸXj9n È?þV ËVmlïm„’Y+ 詺 ”±2 ýÅÅÕ°Å¡AEòÖû»% øÐ޽nÉ$Ùߟ˜ ³É¥xM\"á€ôyÙÎŒ¥LÞ:g¦Yï:k§Öµ3Ÿ„þ=öU9)ÁØ9툀qul±§Ëh—’ج 8ã6ðÌÌLÖu\{ö3õc*r: ¶ü_̆»†±n¿È°šÙ=Fl÷€í å7¿º+ãoð$ì¢[ú8òÀæxð‹‚‘€XgöÈÍÁÕFQvWƒŒ‹WžÀKBB¹{dÿäKA"R!ȪҒüŒCÉ™Oä£CíPˆÉü\:Þñ°¶ˆgÊ~6ÞÌ0‡áÝ|¤ßÀ^õ±“‚p~ç’Y˜¼7ÒÝœP¨!à” h‹;ûÃõGdÈWJmÄ‹@;$OªLÛÃÃmº;DhÎÆÑEá#J«Ì³‰:Z·æ4bèªÓ@C_q~!óìv¯ÛSê?½ºKü¶L¨‰/Í6Ìõ÷ºB®Âò{ÀîÚ´ûãÜ TÞÂ7[¾É/»˜9çe™Ÿ¿ÎŒ‡Ú?®do¶qÛt·Ü0ð1­+ QGF$û®0ŸÈ ¯1Ôˆ€Ð†:t²Öè®Ì–;jÜD½q_ô€V©œm±N^^ĵq{ ð¿ ð—&…jZ\‰l‹ IUëá5,•$ nKŠff ŸiOމåVj¨¨ßZ_1YÏ2XÈÍbÉ·áÏ„4@®UÌʹW0( å\ÀL +xÝ%p™Ž;ÏXg0”¿ô?ï8žÛB>y œ¾1àX E®þ¾4i8Åu¡ žI=¹s·ûPO1éGøæíwž-1èo_–lðÐCú«#VmÈßpú\v9ÙbŠûÉ$ð=©¦¤ˆéÿgù0{y¼pÕz}Lï)‹lKh ÌS*«°·;¦ü¦&50;Ý¢. øå:'9¸èÊi3{m2ÈŒ.zÈO!þ÷ý>še˜>ü§Câñ®xñç8Ž{B ðRb™1K£2 ½Õ¬’œ ,ÎúïgZ˜ú.…|7(‡öûaqJqß/8ŒÝɺô ºf‡Ãb´µJ¨‰dÖJ@©ƒ*cpö£sç4Ba¡/u{®ukãb$´ñAŽõS¸(s)§úµlmÅ‚SØMX£«UºÔÑøFú¼¤Š«( H{19¥sê;\oyõE–¸[«Ûܬ’Èë¬vGŒ³¼Ž(€û‚q~,ç µ‹FEùoþ≇§‰‹{Ø_oatº²çI±žA´¹£œòÄR¿Ñû"Ø,tAÅÉ ÷¹ß’—2Árs–1RÜrX¨ÖpޤžÑ|TÂêÎóPê3-îNHêNöd Œ«êò§S)]°Ù8Ñ*q”mgBMæQEþºÅ Ô/x7}Luªû<`V»ýŸÄ)‘óbéDÂu´‘ZÞ×ΓÝ0 Më¾$×l¨|[£Á¿ËDioà$ Þ”?þÊaÿnW'Öqv¥Ô-FGßïã\ž3àF—!N7µ¿×Xœ4ÃÓEÔCëAÙZŠ£ÿ0©2ë½4fŠ¡7]?˜:*ßÚ÷ï öÓöF·Zj÷0GESK0×;%y ØŽodš/Œ1Ÿ}õÖs:üv‡Þ6²î6aþ=¡vÌ×À¯ÿ÷”–òE˱¬e/)yKÊ^Rò—”¼¥å/)yKÊ^Rò^“] sèIóº`´k©f‡{àÄ›šæïâ4F4Ö@1šß=öþå¸;é´²ANËõ§Ñ‰†çÚÄG ÄG ÄG ÄG ÄG ÄG ćšÄßa#ñÕÚÓ†íf=Öÿ+kgë–º^ˆ„‹Ó»ü!## ŸgÜ2ßë¤F*b—$xÎöf#¶câwL\)2S 7Í¿”åø= -ËOaž ­"‰äÖ>y¸ª³{ÕæRô,à$ ó_£• ù´¾·dPœº°Ÿ¨ØK,×8~%'ù&™,´\ôÈ[§´N0;Ò×(*¥¶þÍÛó»ð×OŸ±£YþУ©¶ê—bÔ—ÛY"3 ÑÊŽÄŒ¦™m+$ ¶ºÈ’Ñ%çˆ[©ïYî‡~‹¬)¤Ñ4Z¬½z üyÇ]a¼ÆkÎK–¡‹ãn¼5á¢àfëÊÍdÀ\ÇJ¢Ž!«@¢>Ø4d‹hGˆ5Ø bÒ-tCd$Gj+Ï3ìÀŒñ:}AØ7Ki n3ö¢î’%ž¥ª¿óåËÉhÛ—Ä‚Ã1KgÛ·S¼%oðc#rrÖ„*¥W8 ó4, b÷&r^ÉÍsx†³/Þ̪1e¢ß n>Àð¯“Ï0öÎÄ@Í7’p±›C¶7a:Z=%\0iúÑNµ" #’Ø7_áUÔ‡¬ 'Kô‡•Z•¼Ø¥_Ž‘à¯ä—ÆÉ²ƒûýÛ´±IRÉ•¨ø*“èÀd—ÿ[û ‘WYsœ-¨¨n¦Ùs%п ð¿ ð¿ ð¹ñ˜ueC"ülŒÐI´qéíÄIýáïƒqÙÙût4ÝúŒÑE$YV¶š=;€fã5‹&߇>ѹW0( å\ÀL +•s2€®UÌʹW0( å\ÀL™Yq÷|ÍÛÛzâm.ƹpL¢oðDÎ(/Kºd=(†¸Z!Fñ&›ÄâûNõTžj-Nfx¥ôloÿLÏYxd(M0VÅžTa8ë%nW׉R)àü UŽú©KŸè;ÌØÔSàâ3\¬Jêÿ_’Ë ñ?Î>V¢¤ÌÛeœF™o½Ý¯Æ„š@’]ƒiª\z_U\x«žüÚÉ/Ý•ü^X×»Œþssƒ7ßÖ™Þ:zw5 ó§XOFr,sUâ‰pfÚÑñDeÊj€J&„}2¥ž®çLdkËñ’ãmzžê"<$÷ Å…Š&“èê0B ËÌÿ)&èMngªqf>MŽWÁ½¨»‘/ÍvÙ›^•Ö^á $oRéÍWÙcÆvÍo¦}{]@?mžL C6¥v4ØŽÔ nå ÒL4Uô¥x¾ål]FÆí?ý‹ƒ¤øû ¹Šúvz˜º³‘‡G!-?ÃM׃ #Á8¥ƒ|Xœã`%lŠ) }Íìýj`¹”wŸE¤%íÆ4Þɾ¤Àó?˜\•÷4QŒ¬B’ !õ¾ŽÕpë q²Î~óPüˆõ ¬8>{Ê:âoÔî:Œ1j!% ØÄÝýÆ)z+Z» Æ“×2¸üH¥§<«æ”#âgY¬€@Ñx(µ‘*®íØÀ%èæv³­l!å¤T×+~«ô$†.–"CÈkÍý_è¯ôyo/¨3 ‰Yho]¡Ø¡vÌ×À¯ÿgs!m´d‡Ò¸M ÄK!$’‚ f "Öo:/4!D\o€MVd⩇¹r½c)yKÊ^Rò—”¼¥äöØcgËä1'¬¥0Ûsæ½Ý a;¡â–"‡û0"Å]C«†Í›« ó½³m›^=8–yÙôC“ [q£<«ç,UMÏz•¯XõQaka¹–Ð\Óu³Ç‚cF ›å¡þÒN1ü™šùÏ©Iâ°_%+}õ%0£mc+u–î>ÀHµ ø>!ä"[µô~WˆÞ4j´á_lƒô !Ø+’UL×—Ô—ªõ=}Tú(Kðhg E¹ûþ6Ï8—Š–Ý›*8êñiÁCj H™=eüý;JÍ£ÀÓ¢M­˜ ¨ÃKyZý=À%Ô\6cFUÉúËŸ[";C½e”†šÍîešQNÛxÚŠ#=Ñ3´€Îãˆ{Tw!Å)›¸ÚÚîu”VtŸ.2Ž®ûÏ\ÕŸE:9$•&}ñSi都ÿ1èê`šÂÑ/=Î(Ïž}`¸1hÈ{!f¤«ˆ9\΄Œ'"P$œZÒA¿«¼uåCiðúaÛÁA°3R¢Œ<,>X¹*¢Ž|(e1²ÿ§ÔâR.0S÷˜:é:XÿqJ¸õ—¹‘¨Ö÷•›ånòÅ&òÉ´[ùBý—ÿÿdŒ¥ ‘à[‡âb|*Ü8 5%KÖjïA †.u¹®ûü‰¦Õ)‹£oêm¥vSÉ2oéVõ¦#4¢cªîí Ú4#÷ö£)/èv~kaÓTõÕ‰ìµê‰>˜z¹¡ü¤| =„1bÝÕ8Kk'EoÓĶбÇL‹Ù̆͞÷²£¥àËyÎ×,j.|é*'ðÑ5MªHÊ"_?–d=¿ýMÝ‹6{·ÕÂqO€™ Aå©E¡~öBFÑ^¯ey¿¹ÛbY”—ö¸B³sB“åÑçn+ÑÑ©ÙßJÅ'ÂAFjfÆÞ—$•b¿ƒýQHp½®gL‘´M‹5ì4gÓ~Íá:üžPtx}ÈÁeÿzq•Œi3Ì*åüÏ!«è3×ÚÝú.n×"³ƒ››OæË‚giŒÿ¥¥5¢ /Ägû(Ÿð.*é‹Á`£¹›½ò·$*~Äæw;‡¬Ìqr&èö|g§Ì'þË@eÿÞöœršÜÿ èîq_æhk³%!qÚåÙ£ˆÒ¿\WÿU°É³ÍsT`›!Î.½S?/Ü ’–v¢NY ^:¨[g_7ò»ÿ(ÀR·#.pºÝAz…ª‹1¹eÍ:+¾ÀeŹW4r „¡èˆ 䊞±P©kÀ Ž[Ù•(‘¬¥Q(¨ªF¹H÷¥„dŽÐp³Aó|ßN¢SäÍN *hÂrì6g†ªòW7]þ™8Cb ìp–eµÌ?ž¡P2­büÙú™ƒéy_ç÷fìqnhyWrûõßg¤½ÇÇÝYÝ Òš˜VÊ–˜Ùè °ß#í¥Gº›ý—=_,f­ñÿ_ÌM Þ⇋lÿ\‡%/—´!çZ±¹ÉÑõ0OñA›px,_ÁWšÜ,¤ÁÞ¿Ç,¯¯#…©Ë­lMÑçÿ}°n¡Æ¦÷óCÈ{AjÿC.)Ä"œ>O%vG™ð=SÊ!»¨N³¤¼xßÿfÊI_²¥[§TÌÄLñÃÅf"‹ÉQºh\YíRîvZ¯Šs Ë%©7NyùõlÈ(|þ™ë÷¾Âæúp:Ïeý_é×!}æW0:’Xzy{\—wñV…Y%;!2 ê¯@4²rUÕñ³óêx6FxŽI2ðMGƒj¤£õÊÓ×CÁx£îñ@“á¡ þ>pŠ~œïÇPÈœAÜ­•‚ i~Õ!:Ý^ ÜKõÿ«²Y§P°Š·Åªx(#üaô+,aâOÅÙê¸6);Hˆ l|° 4¿ÿÿý¹qÀ¡¨ÂH™?6$¬@Vâ®(åe$¢ËY ÉŽw@]Ȭu®8Ðx#s(þ‰¯‡«V䤜Œí™N>ñTž™Ñƒ bí['êò·¸¤ïþøW›´X5ÐÓIO4:íGišŒ—ú‰eE{ è­¯[Ëžê·H<¼ÃÎY¨Q.p Q·áâTЊ·±lCWqGlã¾"·“?n”¨ü ¡:µ†ÒÄAG-®©½޾ à`£*yæÞÁMïÏp½ÕÚ’ÉiÛ„ºc¸ b¡M7'áìš#oê?µoÌQ“(ƒÂY^ëAð¾d,%Ì+Är[æ‘ ^Ç|åpêÃ<;]Ò“Óïz5ï´y¡d T<…Xm]g>nhE)=<‘±’Šòû/³#+S¥Ò>×^)¥& >5û#¶i:u¶wôéÒc^âÞ? iFì5ÆBG K7Ud¹•·‰^ư×Mû¼j¬á.ÞνO®Qú[HõW\‰€.É&•DÝs7Pë]rwŠÁy)7 =°¼KиwÈSçÿLÑŒñûгñPaù ¶™Í<‹i|펨wý“!ñ°q;Xº·c@ù«OÆ+`1'"èÿ-'~{Ge®’¨:~°V:?Uò7Á¯ýèÿL€.ül¾g¯­Èb‚ ‡p'ËÚÂè%Ö&$š/Å„_Ÿß¹ÙOÌ[:[Î+Bl â5Ю™Ts²ä¾M•Ë''!æè¿¼s¸ÅÜÃ1j¡··Â›<‘ÇøYFH<•f'lŽ(6A:G¨Á½h1É0K·ØCî<'9@t*ms£Ü±Ì8lù¥œDΟ«O mqÀÍç‹àÆ)[,3º}ÿcì òúH È’lH hÙ‰ò}Ü¿UX«9˜æ]“`ûªNJÔÕDÝþ;zêÁyT5ØkQzÄìât Ú@¬HñõÐ3˜H£"£ËGò r¬·³X(³Hù^ ®S–Äù±ÿNœ´ŠŠY ’̨™™¹'§Š÷’1£a»ÿxXªß4Deª Ò¾G8Ìõ'ÒF:¶FL{ßèŸ_¿; Ù9çÿAì ¤xÖ€³á›«›bøôÍ\;Ä-¦Ä¬YoJ r÷…fÄì~1ȽI)ìƒE×KÚy‰ÁuË2•RA¢J>×áägÊ&š—ºµfÖÈ!­Î#ºÝÏæ«poÚ»~i¾F¬ª"•à5Ü×™&®L]´^^^^^^^_ ̾~ tž*Šý.w¸IÝE.Òôväh䯠åC9à{x¯•ŒÚÛ™µóØá$ØÞ°mT žv)íþÍÍUéŠ2õ©-ÀoQ8ä©Sÿ~÷¿W°Á;nÞWúœ.[ÿGé2úP´“ßÐäIúÚ—1Ÿ€À/ÿ~§@sO’îñ›d{mÓ xë‚u+1"U7ÿFxUÙGÍ+#CŸ¤ ƒ˜H̶A»[qãÙB,ŒÈ`yÞTê•ñ¤pkþn'Ó÷9 ¤]KñVßá„h0`îÞóo Aü²·“EnÿC³{ïÀ9s…åõ®™¯­H`â+¿_8H°ãA(Yýu%%“ÿÿÿ}î¶.SNF³•o\‹lD“À&‚MG¥\—áCÅäľ±¼urEÊzä¸ÛÅ+ ]¹èWû£0•6…¦Ÿu9²`¿Æ»èÅ0ýƒ Óï×"o²ãAzOy0á©Øõ&õ‡>æòˆ¬±Œ X6ß‹%ù³Näè'$g2y»Râ‚×ãHµGóš›ùD³ðr²çǨDA%(_ûx€íKþŸ|µ„sD<2;^’úÚeÄç§ÔÆxÄŪ¯L(ÃøO ^].>H‹L+F$¾šù§ô€Èÿ?ƒéj¾ÍžÿGU˜AÐW”µvvèÚÁžªƒŠ†)ò%bׂA'Áû"rKF0©ƒ– ÉÕ¶1 ;~¡mZ—äShÜ¿0ieó$1¾ìùrÖ°Ýö øy;\„ÙQ¸Ž4üÙœû 39· "9ºG"A``pò‡ÎWÇë7ok?æŠ?e«~¾ÚUc?Ö-D°4 MP,„õØÏÀ <â¢1¬?y(ÞbumÛ)˜h$P8…Ù‹»¹¸­ãåðÃå·ô]âOÈk/…ÌE ücOÿYwÙÞà*ÌOçJá.K”˯õ­ÙÝÎÂø<ŠMÒQ\DâD‚¯ËU²‰\×G¬$ÍB×î(¸mÄG «¹ÖŽ=/œÜÛÄ’ÄÑ󙸘˜ndw—9/¿ößjD~¾ðÄÏþËõàŸSü»¡p­‹RèÄN2"𠑆Z@,˜<×{>ÕIš)Vr×å"J0EßßYÍK®¢š³pÝÁñ: _ÿ|ºÄgy–…4Ìvx# •GÿÝÁñ: _ÿ|ºÄgy–…4Ìvx# •GÿÝÁñ: _ÿ|ºÄgy–…4Ìvx# •GÿàÅͤa9ñûž8Œ/-µ×´.Mè’¦m6È1YèZ_–ÍïMA §X¦A ý=µeòÒšfsåÓ¨«û4)[‘)¾ûÈ‘ï²0Éxe\m–¾ |UÏL§p˜Hú²´#rÎâÍÌÐ’·zäúIó‰°çu®¬°PûgiŠ~Pý6Œ/ïødS’êYGJ]>Π¸à3Ÿë룙ËJ)ÙV<¬ÎcrZÿa´¯B·p±šT J¦BÏÑw ¥õK†ï(¬ËFG) tè YÝt DÅÄMg4_08T3?óA`«³”\¨ƒ1ÈÓßXê‡AÁÕÓÝÃ,&©Hä+@às5TÿAâqã kSW‚©ÚVÚ;•q'âŠw‡:¿#ýaÖ‡ aº}WõÜþ´—ªû×@" …D®SN~M·.sNQTž­µ~„üQ’+Ê}>Çñóÿ½ bÈ;ç“ôYÿIGÚa±¬Ô¶±»çWpqMo=˜Lñü¿ dq€ý>ŒX"^qì ™S2’zs×1ÈòÞö6pZí gï!­$Ī„òõÿ"Z$F…q`§xÑŽ$ÞÀ'4{ð.vTJb.î61n_5j 2‡SeAúÁ{ˆC¸~ž÷ps˜J?ܽFÿu0s wg¶Dã· S[Ú >ÌRô!Љ‘öÑD ìâÝ¥¸bövîú82}’íußSŠóº_`óŹ ›Æ!ÔÿE]ÆD{þeâ=_„|n »Œö-ÐŹÜ\oA ÎQH<*IPÅ3NÖõ×) Þ$mºœ)—ëÚu‚ÄeÅü|œ÷UJ¿Á‹é•{ËuÕ:¥ÌIA:ÉOX°9SB?¨¯%ª·uT†QØBNxÃdÈ ‘î×úƒÔ¨roÔ“ bS¬ÌF‚ù"„,n†ºÀ_OþUiRYRIjC Kî{#à;:ˆÛ–Üáª`×¶gÍÆëï¿IHÅ6:áU_{ó_ÊÕ 9ݧÂﳿÂ2z0#8ºÖsü¾IH¼mç±1kP´~_Š}/ëy'¢èô‘t>÷)'<9%·üXë4M×ÿmGNÌ¡“Å»E‡Ö§ôŒU3kî8Á¼ÎºÚë°%tœàá( +¦«HíWJÊ}mtn,4#?ÿw?uüß¶m98¼§ÛH¤¥!¤‰4ƒòÝ¡ª€: €4,«›€ú}0ãï­ž;èu{ËuäcA•Y6¼Š:,­‹Ž0Vþ³ ¥æ–ü=j׸F æå‰´,( ¶þê‰Õ«0¦3ªUøÝ'S.¢¢h]ÝøÇ-‘Œ‰¯&©}Š0¾çÏrjC"Ew„Üüp¶–•΃××€s@+X÷ÜÅœHíÊg*Ô šÒ–¨iQM¶D-âzt‡œ;ß±;f?ÌùÛbãsǶe?¸/³®E±5·êC^„B;<»ÐÏÈc6ݾ–í®ÎÝžDMêvúHk”»"/SÊÌ}B+¹åŽùõ)LÀŒïÅ7 `÷y¼©¾Dóã5µpàó¨ü§ð‡‡¢ô{†¹{-Lû„úP§AÍœþeëKfŸ^èaª©;ô+tÜ„'í,æ¾Z¾m/Fbyšµ=LQ#=ÒR?ùé)í´œÆHÝÅ ª”›·BÒüøÙwÇl7Ϩcoi¦(Jn(2cÚŸÍʱ…¹6I‚ º–,- ?ÍèRaA¼?0R¿§Ï^ É‘íM´Î‰K Q hEÄ/ (a:5ÌŽ"é>uñ9ŸŠÞc '|Ïßh¡ªy7’äÑ,·4ÇtÜ¥uK\‡b¨¦8ؽ1 $Í­C“ú-‡`ƒè´uÒШ5/C½nrÇ{ß("·¯ u¾§×pamÙç,ÚáÝ•¤íð·O,#A‘7ÊìjßM수›·ë„ÁòåÓÏI¿”éž?¾Å R†ŒÑ è5R9ß¹yã:øîëÞÀÚÒ˜9j¦ÐÝô›Ó6áNÓî<d½–VÁ®ë)ûª›‹ÿZ¸—üE]ã¤Ä%ÞþfCUÝBqôîØM.xüZ]ëöñÿ\¹ú\>63]¹ûÅ‘´ÊÚàçnKz©Q^?žÌ¬]ð×Àƒ<Œ2ýþ•%äξÝ|pN'Ù̉0¹Y'žt¥úå­ËгhZ8Onš˜6ë#-6†_ äŠB¨“ÍwÐâ­z_¥w‰zajÙŸ©HR¥O>·…Dw s'ö8‰›K/¬u@÷[/Rzôìg°"Pò“m¶ÛqöÅÑ —uì±»”ÄrKsƒ£ÓX>1Za:ÀS)MøŸ5ÒÃÇ]¶KfdB‘£GÁtÚëðÆslAÚìñe«™.GÓ¹øÿ{4ò”¯·'¢þqpY”HiýõlØ~8ŽÛÞìÈKC´ÎF×6ˆ5C˜¥o\|U’I$””0ì ˆ B¿[ßgŽ}3#fz':ôòðY†@ñop‰ä©8}€·"çü‘_/]DÿBÝ.¨&‚å›;ÎópÉ&ï7ØšR$¬Ÿã¡b|c‹WÌâ†y¢… ¿a§³=C‡ÿ`ËÆž B¬ÿ ÖNòqÞpû’*DV=ùI¶ä„,;úZÖ~Ñ•€6µ3>I†Ç‚"óÿg‹û”7žӗu—txxìºdð9èhY¬ φLaEãüy#Íp'=ü)ÑÚÉ$’Jøâ³ ¬á„öb-«Mê+ïܾõ°ûÆeŽ_çà¨Öö±xgÏâsÅ͵RPà qr¹‰ N.;aÒBœ˜Ë;}·â†@„lÒÏMPW¬ß¶aª¤HÁ&ä¸ ?@`æãIàM˜ñY¥OcùMRäIù »zqÂ…Óñ‚±ˆ*5yýŸ»Žœ=÷C@ªë«Y´4á!´¶ Ç©€ •¤Ì%Y ÅBâAdMùa!çNe(íU®:H_ò¢( ïc3…¶²ü™n,o¼²µ˜ Kz†r êväoRH¯eFù®í¿m-ŽË¦ˆþV“Ë« XµqUø†tu²R×< öàᨾ=Ylã“pOnêŸ$r·©‘¥˜u& ML)µrf"»ìry‹é·i’X—¸Šq÷ƒýo®êâˆTAUˆ ©ЍܔÍ*óe&×TªwË­ßûž/èx°ÎΞm«—‡¼¤Sè—2 LVZU²X74í×^ÒŠËè}™q™kä^å⟶ši”Eìeö­\C,.EŒR¢d–ÄÃßxvæ)ßT>¶&ø_îAõsäìÁ²ó‚'b È‹±¹˜iÛ/)ù&à#HÕ†Á££æêˆu_žÒ„d¤õ—“Ø(ÿ þ¹4=·Û+]¶ ®¼ôKB*#OevµLGÝ)ýËÿ;¥/KÎ3ѤÎ9¾&:u®5©±%~ð9ïCØZåÊÁçËÉe²ÞOƒZuðcP`AîLØ,$à¢![MvÊÊñÕ-õŠj9||±P*÷;õä|PHˆÅOët™L±5î½Ò”•ÝV üˆ'Ö… <Ï¡ÄëOljD+(žÍSj‡®5-ˆÚÁÊg€ë?soŒm¢ÿGr<³û&6ÈW. &1ëÞ0"m’À……õì7n÷Z ÅP…„mp‰´§äKºñ,ÕÊÖ¾:®?ô’•—Dþ™Xj å×ÀIõml> £“l5Ü(—*}æú`î§Írc»Tÿu#Ô.žÛô,GëF‡J¯ím(V?çIé6Å~8åI[WiwU•–»ÀÊôl"‘λp·é\Ÿ3c ßÔÄlè7»@9çˆ\)E§ô¨”*¹ L ®¤*½¤UR£œOž ZgyY•×›ï˺{á?ââ»>70/嵚q±ÔkP9Ør åíï*.o¸HŒbðÔ«Ä™L²ŠR%n >a)szm¡q<ðŸÏn‘ Ï׷õ`tn&EØì™xj÷Q$ã2][@µ/ר÷–0 À" „tÏÆb&€!qsàzçÁ=Kßtм²/,e¦…˜´„abôÎ(ø>¥¯ST½(û +Æ¡ïZ(w0è¸qcT×ÕÊ”ˆ¢HTÊ.0˜0»r¯ßL¸†¨èO~Ä9yÈ.­Ðd_E/Ü}wÌiGü9òÃŒ 0ìÖ8‘²Æ½Á¶‹ ر(ïªo5$â$½zoÁÚW::ž*Ï&¹"˜ÑR8‰üŘI3Ö²Öuº@Ö_èk*Ö3íÃ%€cöÁàèTxy¤³¬pá³îü† ›ö.ÍÁ×ô[èñy [ÌyòWONBnºýHwf`ÖÃUÑìœéÔ€QïZÒŒt4[$ň~Õ„,Êpk¯QZMý÷GeÚZ8¼«â›gTññ"½Ãmt¸•9/´õq]ÂúàÓŸ³Š˜!|¦NÈàcöð¿Åô6Y×-9ëV—F¶&xé¬˹6=]èo˜5 ¼È 6L}ãÂ|˜Dý„wÞ°ÉÄ)©Þ§§â¿¿®€Ù$¤ñxáy¡À”»Ù›°‡ÎRü£#0l˜ž{¨fM¥0LÜ@òtX¦÷3`ϧn¾ŠÂ¿,ûR\D“3]žØÑÕ©‘ã ïšú,ÝÖúŒÇ,Ø&œ48†>·¾«¥rÔ–ËŽ¸Î wÁÕ¼Ä[3Æ!†"Ö‰Ä*i‘fn7;"^°&%#p瑱hu†v£‹/“t_ ‚å¢ÑS‡¥rD¼ªrä ÎÃuqòeÒH—“Ÿ‡–ž P¶ÁoÞ@w97Ëš•äLeô2á÷'ãmÚ¡/ô52z2]ës[Œ!ã} î¹Õ1Ôbb¼v§;|öp½b"õ#tó—ž 9ðÇ™¢ëÇËŠ6«ã9‚X73°bpeúµvhZ¸ú}Êÿ 4?I·AYmį<½9̰Ÿ–¨— šv$‰­êsumˆÖtz ¤¼å|j2’Ñ2 /óWrv9Sš"]zw²‡Þ˜×¼‚ÍycÝòHPêzˆf]¸ÖRiEm­¹•̇Z²×Ë™Wñïê¯ÐªIÏ-\[€~KÓÌ{5I¿­á0ÆèËåóX)}ct*äQ¬bõ©ç\MA‘uÛTizŽ´ü‹C¥¬N…ÓÚö70nÜXÇñœæÕ烿›Ë¡·vß)[m_. ÁþtÔ§v8ï‰0D°'í àé)lEòWrºÚ¢ìN˜Kbž¥ø&÷aõ°ÿ$­mY]7}þª [T¿hK2JGG¢™ntŸ„“X{·lâ+î X§2Á‹j<õM™Y>BЉ³€Ýý·‡´…êøÜ›ë¶Æ'–u¤>Ÿã„ö™£b‰êFì<®»ž˜,!ӜҌP1³íô'~¥P•©«£Æ OãKã¢bzpDç苵r ³ ›\ê³”Aãã¿“Ý…LŽƒ%HϸÄNÈæ†}¥¤ƒ>cñíuŽÿprf¬£¼þ¹DífJr¥¸µÓ¿ãYHïs²´Áé¤vxé·T“T…ø„F_LO2EÑÚÌÒp—ƒépjº ®K¤m=}šÿ;F¸k½ÁôEî g¿8Nò’©KJõñù5'¥ûáÙXQ #ƒSª™¸“´ø>ïøÙ~_ÓÑÖYPÎÈR±7Æ»akdÀ¼ç)>™1P3‹Õ:ën·/‰Oô!ÉI#N™ŸâÖb#ÖñŽÆÜýèºÿñ†Ôㇰü¼M«yp™ 1濎/m;¤}ntœ&‚.\:ÆÙøÒ…ûP9Hb¿(ÞcbÕ(¨´£vŠ1©! ë½n+œ¶¯øyÓ¼Iþ—t¬›¶Ût°ûæÐ„ü÷qGéB;[Ó‡Bð)˜0óŒRôR¢*sï™ßEª¾1¾¸A6 -Å2·K æ›eñ«MwŠ2R–1;p¨Ùy˜Í:ž©hsS¯ÿG°æ¿u^lDŽ ì´yã1µÕÃé§WÞr µû¦Ý¿L•+¹ÎøÊbN×£¿­½lÍ,ÏÕí¿ØMWÆsq ]ô Üßãý[ÐAšçaÝ¿»û©¯Mýö;·[Ç:h#ñØ­‚¼é`êP»T}^Åù&C‹ó¬m‡Ôßb3¬ECMýÛG˜a>¾â™Bø`ª#ŽAW½(Îs䳋î„"˜­iFAØoö³AóOÇ "}.’§ðê~¸„™¸#Åš× ªál4»„!lÄp<¬Ķ6 âá)ÍÐPGÍ`$Þ(Ê ïôõ`™`â ‹¨‡á›í‘ =è¹î›NR­ ˆ¼aºZ±–ow/L¼QÓ7~³ór3ŒÂ¾•2_9W²ÿy‚¼c€ñ{ön놷!ؼ£*9¬ Î?.ôz÷vœT¸ÍpŸÕÅ[ª¤‰ÆXQûkŠ ‹Ü1JQú¸d«õÁËì—‚u¦ä|Mw9Qíõ÷:…íø§q˜DyéÞ¦62;§UFØ)¹»Aø0,ÇX•î«Ö!/¨-°¾§H|ï ´0æŸiPOÒ¤·š›«ÊN²Ef¹70ÚÈ´¤JšÛayàEo¡©Æ¦Òêœäe%/¶Uy&Ñîÿy|“i~[àeÂŒäŸH<ëÜ÷ÿ&¹™›Í=BmR÷’j3’¤ÁGÑî#§9”úûðÒ?È@äEõ?Vvþï™w{÷EþmÃ_òêÐ ûª¡©Wɤz ™ ß® hACZ;?¹8ÒÄ9Ò çhÀÆÊ@ë%Ÿˆâ'G Tyá ŒÐ2>ò±@ŒŸ"]¶çºL'óãüÄ®ñ l -êêJ €Üx­P¼Ø<½—‘»> ö€J•r݇ÓÉ^ËÔ®\E]l˜f« 5 ÁG(î^6\<Ž Úí.0Ppçë1Vtmµ7SvK†e›4îY ÉOÃë(Ð<¼ÈO%ÁxàR†««ÓÅ4H ä$=µHt80 AQ`Ø2&ù]^ƒÖ»²0ÉP¡ÿ~ûËNdÞ²•“ U‚\”=Ø`ùε¤¼;^½ñ1Ä«”èö,¢l³½i¾q¾YÖa=K LÄÒ–ÅLÚ°'*¯r2ìZʬ-<ØwxqMëžÓ9ÖÝÚlÃUš[€–›Mýñï>MðêΑË8­nÉšw&#¼´ªÀÄÇHi¿€åkéõj\bdÄwÓ|tÖ¤S'ÚÝ^[˜fà~r&4¶’ް‰ù¥ ÕÎìÉg½»Û 5V¯éÑuk7 ýÕè|ó?rì룘ŒÝRUŸ}Ò£Z“‰SK÷´Þ}¶¨Mès@¾¡zí™65¡Œ¤¼©y&Öå¢{Ò ,>h#˜†É¾æ;*°Š˜¼´í´*°Î}Ò+{Q°3¯=Ü}í/xS_!;îïˆ ÎjPm»ƒYÞ*z¤î5ñ»Õ"|v(U/0)õjNÜeѱ‘h°ðz]Iß ŠµÚY0n¬\]I¼’¨ô(xËW—ÿ Y®2ëÐ,ÔBw "ÍC6…8Å…ì8 }ÔVñ$fï@‚Ù¤ÎÊ\æÖµNW¾ÈcÍ…>æP X‹z Qe£ÂœЉKR™¦²ÃÛÀdç‹ü¾õ]ÿ5‡›åQÊÛ¢Ø ;´Û_ð³=Éox#1`iQ²ßR´îÝ1t/J=\_ûDi‰ÙZ¨TõˆKˆˆ›¿!‘åumT© íŸ´V䕟ü7nl"?âþ¶.I¿e-p‰ñ i+5Aær!†ä½JÅ^t£«${Цµr²afÖ“·¥˜;‹eéJ§-ÄI®âMÖ 9¬—õ9>,åèC3«&îÄЬ©»íì²Ì`/>á–k³‹&,]Ã÷/™C+·Cí7p¬Ï]6ùÛùj@VûÑ­J2f‘¡­ '¢Œ)_8>u a»­‡Rò‡Eú`éã<3ÓŸM2._aÇ4â?ÄöŸGrD8kˆX¬vëgSú×Ïh~$Ç!˜B®žŸ…UšmgÊo¨Êu{†Î ø`ùŠ~Ãe ¹·®«Ðú¿ÓÖð¦8Yì©1¹á—Šô@!¡‘ ‹BùÁÍ [÷j.Î UË'£b “E2²¦ê¶XXu.¶ÕîòVž  ÚOæPÇv.>dD"Ó­òÞ܈ƒˆ…ý…à£l]¹•«6Ψ(aP»9À©¤²ðT^Ò¶fqÀÛkUÿa·WþfD ÄâÎÕsÿz¹÷@»Hxû8V#¨ÅÏ×êsR `.›b`D9 ¡L.£Ž¯÷#\¡ú˜® Û”ëC‰†aé+t†„hå¼b÷ÞmÞµ)9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9ÎsÐBúVG]DŸ=tj NO·ç‘¥ë¹¾uæŸó®Ì=¶ôÅz÷€tâÿO‡~ŽúMòR»âÊ@´3 bÒöKº†÷…¼# 슩Üý<$"$]BŸ5)9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç=.ÍÅ <38³¢þДffW°K«¶LÒsl[胇T÷°ÈíÎþ(€^ u¦Ü”d„´PS_ª‘±µ/FÇø2}ÃFAz*b 4a3ÿÿUj/Á†Ò F|¢ˆ–¸m›Á¨^çœI)#;ŸÝ:Š˜¤©C-ûz‹™Ú<‚3R4rÐÜE‰ 1?ö׬ٜ`œé¦Ê“{=3æV1¡—lÑ{ï6ïZ”œç9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9Îsœç9è!};1åÁ(]Úƒy 8¢û2°Ñòtì+(·7ÕÚÓ3wÌQºk„·øp,ük…NUw\´v}#• Y½°Ó`,f®ˆA9ÿ§p•šÇñ=§¦Ž½I©æÏvx !üÚ’ªÅÏÕ-JôàJ›Û‚ÿ5›ãÑúÔ¿›%@k¢Rsœç9Îc 8‚KvÄŸ™·ð®PII‘uû÷ˆ—bø~À¿F$òŸ{Ò×Ë6€}D&„¯’Gø<“¶Yþ§jáuߢ֊ -Ð\Ô™| lÉšj«*8™‹^a”¸È OÂÒKÿ¨·hf§8•s¡mn=‡IÊ©ÂÎõÂ1§Ÿmï¶1Lklü¶Žøl¤xªþè¤õN°ÂËú¦%êTñ?bò›óf˜ÑðwÍ@•Û/­GÄžÒHFtÓ×ÖŽ©íÁl¬{®" Ë7Ë’›ö_±y DzD—Sshhb: /“O8¤æ§À[DGŒ$8?&¦ *§ dè:S»`ŸüKœ&È+-Oÿ•«>¹»7ü†XPØø5T–«qDêÐÇ?Àá‘+(+^öÁ¸#ÀA1Wúöp»r ×ÞÝûS5Ä3ïô®ûG¹Pš)®L¸ÁÎ’[e´˜Î‡à•©Y±ô™±üÕ(†¾?é@þņßÏÈ'fg*Gß6qÚ_¾HãÒ!0ÿJ`õ&HVË@««zn‚;'õ›˜4j$ÚG\oâ#Ƀé 9¡•*ªd¾Z Nñù>[½-XM,à=PcDެÎã ê GðŠäC3l PóJw …¢¸[]ÔF÷fÓXZÛ1èO%1h?{ÓÑfz“],½àDN¬5b÷w©Ñ^bæ=ӛόšWÈÝ5=aý˜¸5߀zß‘$ó"/Ø´ÜÍéÈ /­Ï´2¸HüíÅΖ`t3ëù‚0´‘ììº6–ý4j.YR ó… Âçl‚õäF”ƒ6%F¢cëk­@T¬_»Z%ß{ó6­Î]Q T°J:…ÀílÍnŒ}–ž¯ i³ÜûCY›[‰Œ%ã×=æßòAÔ`ÀåÌ”=ÁYx»*=Q¯ËU•HCqÑnÀÎÅê¤RHìšÏ†]í{vsÇz_o]ù*jãtz®nŸ„S´@Hþx·v­la”Ù5ÂËTÞé.r‡öf"jâŒ}Õ×Q¬TщÏÕù³rWwˆU’•ãâßø%|¨Œ ÓõÒ"Îꆡx[¼GŒT”*Ò«Ixá)ãÝYU—cì\ˆ E­­Aù†è°¿³²ýnÍØéÁ.Ëé-ûdc*¸¼Êh'é’é U‡:K€œšéŠB½SKYH.J&Ŭñ9Ë`äôFX ×T(tCtzßVPvA 'Xߣ…=ªŽ3œcå÷mÅf†¨PÎmŸ›jobDœw®b§IB;CUÄtÇòxó3 Rÿ:ìµåON‹OÄd¢‹ÂjÚÚo¹£ –7µ7:è E×s¼ †ûÇCCR@jêH¹=Ú ÎòÏH8Âü`)µÑÜsÚmÅUC˜Hx¡ÜY,cë.[\F}&×É¿0 <Ï/+ìä8rô  â9YGiM¦ÀTîåCçv_T•þµXZ@ô¿ÁªÅúg‡.ò›Ë/nš"+¨º ¶n¿·ûŸÎ…f”^[C›€“9H›ƒ?c_òºëairg{êO“Uœ­ K8hQ°I‰’n±\Íž~ÇO¨„xñ{1š½H’CGd÷Øê Bº/B÷&_ò÷./›èTüsp½ ÕUÜyX±,âÅvNòvÈÆäöõ}a%Z΢ÑX2Dtã^¤S3°ÿ(Z*j0ÿ2 Ó¶iºŒ“ºdÙÔ€ÊÇ\ÌÇPú+;¶ø»(WÿEt…•ÝuQk«‘јÄ"ÜèÈëGaìU~J2­-«OŒ X™Ý$ù™È·j÷2ëCn•äQ(^ÏTZÈ ]rÍ–º‚øP•ÿ€›«hE•ѽ“ÖVîÂ9©ßqâÃ?Ô)¡ý£Wø«F9t—”øm~ƒo ä‚-j;?æÁëR†íšN[‘ßÅËž3…d˜yÊ\¹ŠZE%c"ÿDo†åjûìöxåÄs0ÔÞ/­`'|Hþ‚œM6V5³ï­Û»šÿPO  ReòmÐØÌº®ßÜŒö›‹nËwa&йòHúåtádD¤ÎOØ0ûEUûЬ"ý®P|¸žÌ‹!ÿTˆŒ­Ã¨ûœpMn“.ª]uì0ù>‹»¦¡˜‰IþE§ƒ@P]˜°GIû·C“ðÔé{ÞÊÄ´åKÛwsÊÁ'åå«ywisäþ.êc`dÌ)·–èh?Ê?» n³ölYO’Ñ‘Tºz-ª‚#zðÛØÂHÿÚ(X9ÊÑn¯ÿÁ”§N3C˜æáŒˆ¡bÛyN/?Ó`”ÍS”¨X„D”1„[3L?¡SGgoÄ<` bYE®!̈KÝÐY¾ééºIUU¿Žc8Zk±¥×0Ÿ¶`|“b'ŸX¼ñÈ$ÑÆZìÄ->塌’ …:µÇlgnYW¾«Ê½h¸[Û*Lh4µ¿wÓv)xcDš”XÈ¡i,C×_ΧËnèSÆÁÓÀªṡ=RÞ ¸ML©­¿m÷= ºíƒyÓs# õ—GX£‰XXb¹.Q]ÃúprMQ«Ê'ÎTýX}´F%CĤÅM¯0ƒ¢ >²Ü\‘b5ÌèÀîÕ{ž"iON¢dª^A&-5“òB8º+Reª4.5A–mÞç3íÖ5¼pÒQ[`Ûàǃ›I1šˆ©˜±]ÿxý°d(Û Ëšâ q£i’HZ/Ùœ«`eÉ™íÖ ßm?§Á6êOc>nQ6¡‡—#tOm,—OÙRDNn‹”¦ßž 3ÂnM‰£ÕŽBR°v¤õ³¶à†ÏiÐ+]$ÒÜãéEÍÎ茪â;wx§ö ™ë pQ2‰Õ14'fîÏYüm0¼Š§H­y|óE:$=¥†ƒò!{xGâ8Ö÷4ÔsYÕ„l:‹§ð÷×»ƒ­ô+rÉH£¦®ÐÝÉIËðšë§Jò>#öØÜ¹Ó±Åí Ï¶ûÓp ÉÐÛhPðwÏfôdÄô´ÉÈvÙˆÙ1Á²n N­ý,sGóàt¹Í6?Ö6º×xÇwénVü›×ý_òÅ7r'¢Ó‡.CD¼7éK™`sFôå T¢Mdù:=åÖ{óô‰1j´°/Q­£C–hH‰0óŸûAþä¤âáog¬GkÖaÂ>½ØÒˆñ@ÝiÏýÔ´þø–”+ðyðŒ<÷0w C§lŒ Iðõ¢˜vàÙ4ŽÅüZÔÿ3sÀ&Áôt¶B8´Lû¬-ÂCÌò–ud š­DâÚdXOªªâ<Ó-¬X°95±e5R`q+xUôàú›“cJ|Çz7&6N V¶—&Þµ€ º6u£û‰MîÜ:§y*"›ÍcÃè&¼ŽÐm‘:±¯SÇï "ùÍŽlZÉwïWrôdºªu‰kr˜+Nð^Îùu|û û#QëÌ?‘z><›*)nn·òK?Ïôÿ`ÔÝ·^â´ —ï÷÷:<¿¢pôƳx±åW»éÒ–_Ž æoÚ,‡À†D\˜MŠÂ jK•‰zîõÒŒ±ì ÒøÔ¦àÎìJ€“saV›[ÏŽWÐٔĨ9??å3ÙŽrÊIeboy¦)õ˯AEY3ãû‹'1 0 qÍŠ¡æáÒBgÒBðsÐÌùº—ëGPmê»ÛŠÈßÈÕ79´%#̲{|^dƒ@@¤w{õHðì¾ï2å—•7Œf4û6@š¿‹7¼U­í@ý6ãÇ®k§Q×›ëçôuòŸ%zçGÇMOŸèÖ"@•_¯ 1¢YWßBÁç©$Ø}âKwÁ‹ÚÄ"m§2Qmj–_¢kV±¾H)±$ÿ_UoBm™„eKÄtÏíHáQ<íQô_ʵ%ï}à’œ°akRäFëÔɺ>Ë•)ŸÐ8CñK\›ÒÎɲ…($^v·Áw<AÖF «|ÿ¨{åÓ°õìÊ*æÏà­ù&s5½â|X„q3³\åÙzõ„·Ú:¢£ïÿ$É~Ö7ߌ\d­TÞ²íþ¹¥^5 5#~‘€tÊ«{ ñ4¥&scjÑ:Þ¯®¯ø‘ø·^x÷¦[_¬¾Së ‰è÷•Þÿ`rXñX¤öÛLqï ¼V•Ðù—ø© y©î%ømJEš5âTÐÄ8‡„ŒÜºˆ‰ ú)¬fVŠVðÆÌHY¸±—³ÇB~âÑ¿Œ_3䳨þŒ¶ DŽ\)1í>ƶ¼?x8ݘ{-bLc•èe)4ï¨B•¼ÙÔœ1©!þàh³1¨n_*(ª‘‚y+„KÓï”P‰0Öù„:Ì!–’J’3ýRb+¦ôŒ·bÆ„—.òDÑÊ q½1@r¨Ëút\;pì# ÙÆ?9n=.¬C0€¤÷ܶ!°=ï.PˆÄ&hŽ‘86âm!5ƒã+qL´mZšjÍÚ?ït4øÛ¶Ûô‡juØN3d¯¡C¨ÛûWËzzÞ‹†®$]öÝ/öÚiôÂüGæª4ìM>¸pV|‡añkÍmý9­Àý‹ýU)è¿?¹§ oÆ:UŸÕ‰3 ‹»X[8b•¨»A±#ÌÙG}-®â´€tÚÒ™0”i¢Çœ8¥hî ï2.†Ú«”Ä¢vJ_EFˆ‰ú)X˜ÿ”#HtM;¯Ë´¯%8ºrÙé¿jqù /c÷æë¦Â½ÂÁybØã„×d0,ÁiP±û|VaÿEA1Væ°#a (”Ñy 6AQhÖä6ªHš\ÅGÖ‘+ÞÀe8_ÃË’@­$>îŠ"\ ®º …3ç†Ä`. "š….O¶H2†,§Å–¥û·ñ˜Âü§Ê˜;£(»,…¡Ø¶’mi2³D/#lOÑèp³ô ËÀNûsÚˆ´Íu÷šУ[®Räp£ÖÙ§×Yò4>å±8vÖÿ{Ø üDe­ `–© t’…ôSƒÖêó”ñä‘“ ¤×•|ÿOêâñçH-+Sö¡É—bý§’Ÿƒ± Ó ¶Üi˜§¬^„\"€Èãá`ë~5ͱ^¤äëdaØáâùÛŽö¬-[‰ ÍPqòÓ0ñ’ï÷ô‚ ýÅc&±Œ’Ê+Lêiýá=ìµ/G3Eص6qlÒ^"À¼4WÒ–vçÁˆ_ü.vaç9Ž´vf¤‰ž L¢‰¼|^2`r ¢—Ê"Û¡­KœxºœÔ¨bzc±R`ŸËêÌ‚K {½2Ìù #u†]"¢àà<¥‡L>õcr4Õý?¨!¨¯K µÇD×ë=ꇃ…1Sœ–Ó`¿ÛèN½Þ'5—à »Y_·J×—ž¼{FÇãï“û ª®u«*W™Ä¨­Ëq(ç­4ùFȼÚ/&èRkÒ ’ɓӧg,‡Ìs‹šÚ>†"Õ⟨;À±ókBvXŠ+9Á\à1U±y{õ°!UÂt Ë`Òi6aè‹`üd>¢ø @ñ‹¡Üæ^d ýÌôŒµßüåL0Ôc­Ý.·¢\’sKøƒjNåK8=¥[EæßÕ@º{•Û W½Ôµép½QíØç¨ÃŸtºzšOWzL0üÎ{ׯ<öjÞï”Qr¶ˆAº;…í‚òÏ÷æðb±öé;0Þ†ÙQ¡;qÒœÝup|¦Ùñ˜ëÆéMå&‹Ï¸p³†P­@úÈV†À/èy^g_Œ£ÖIs¬ºú{æfË#ÿ€]3˜MW…éôF°ŠŒ/Ÿ}Í.Wœ òà ߮ºº|ãH°Æmêpõ(¯ÿb}„kW à–­ÁÛiqëùΆ“Èðy{||BÅb+–Kqöûàô€éØkl¡¬~Ìi£òÀAªÚ\öH«¯ \ìáý¦Ÿ‚^ù‡öŠ:Óy«'7ÊʰjO×Ô?w“Óq:Üyü»í£3/©;Š—ÏðØ–gçùÒ¨…<”„v†‡„ºñú?t‹¹U•;æàXÖ¾MâA´GKxH9mPâµí$øc+2 aÌ4%;*Oìð7äñ5:@b䜢æ†È¢êŸ."0b=ÈS615¨og<"‰¿¤ªyÍüOœ+O²Vì”Ð?};¬”™ŸôDšÈ› ×èÒ«ò±Ö…ß­3¶4%—-‡Kü¹kè«T óûÜá(ƒ¨ QÏÉ-Ó]²!DøÑº4Šì 9™èÒ˜£É?_Õm]F2Á–§ÃÓ¯Ò,òœ†MÌìÌíÆ5 Î ÝÃÚ5wÏ6Ã=ÕÔAB=ÄeÚÿzèðÿj‡õ½‚‹‘¹üq˜­lsJßF0iªÃƒ ÷qu¤ÐÙäñðnÊÜõD$F‰ÉµE6S›ñ¥ý¸ Äè¶]‡d6–³ò˜2óY6{•‘¨ÿIKâ¦Ôy;PGíR§ €Šhi0F{tð¾>ïí÷§ýäâGí#(&׆Êö›'|Âúk>¹¬yöAôvrÿÙfßé~ÔcþRcñÖpº@c‘à±Èá@ðxÛù6¯¸¡‘À§~U¨V×ÊÛ üúÐz 3; £èÁ”6êœnš„Ã5ß+¼¾SB‚×fl{ó6…×ܬù€‚+?KôûÐdzJ0\lHw¢T¯«§o$û +ñî[ >­màzÄXÃŽOböÒÓÈv<‰èq€"äŽbä"Å:Ì”Ñ%*g ßâ‹Ô-Û8áHp(3RŠQú¶õÍ¥ùS¼ M¦á’Ü~ùoK¥›°‚UsA‹êw]‚¦Tï¿cˆ&¨ÅÖeüäd±ÝU¤õŒ;SS~9ç÷±è`B/ÏKÏÆ3ºt\WÿeTÌu¤Ó] smÒã4{M2ýdKGJ.ÑÊ™,]_+[Ú¤ QJõ|=» &¹Q2ºã–šÛ'±¼”\o5¸1–ò³í8Ü^Yó4ŒŒò£QÝÂYxÏ=ë­èSd8‹ÃÛÕg7©ý{¢2H15ÅüFgQ21œE1¦eqõôª±S–Ü«ÊóÞ!ë ªmËì{®äïÿsÇbuç\î'›ta°X©ï&Úfb‘Õ1ZE úô5“Â4‰ÌÙPÝP7—æX!9yòt¨åG(*®ã—£—²õðìÛ-u,$ˆ¦aQ:‹ì·W¯†A¿ëX}¸È‘ÆجAcA›?ô(ûèÕñÂó‹ž6>þ2èºsÕ+{ñ¤-ûß9üx;ù.%ÄðrT&éŠÆHlZî|º± Ïøa§‚Có@ã„ö¾ÏÑenÆã°Pn>-2Ò!úL÷Ì"þP‹±s“ÎæK¾ém‡xçJ£@ñB}šÎymz¸ú‹\[ê3š¿‰:cÁ[o:u‚ú3E´¶Yè^"Ö îoå~¿°«'Ÿš¯óíêº^ œ ?…,ÜàŸ=øH`ûrC‡úà†We(oIeÊ‘~¹iЫè-ÄÏF - F÷Þµ›TÓ\ä„ny¾èý¡ÀM‹*L’•¹T¿ñ‹ÄܹÚù¦ôºd€+ äúb”•y;ÏV+_Nƒxgb­66ûgTAÊ´iïçÚ3Ý¿£g/ü*sœ<ˆÐ‹•‘ç^ˆç0Ž,’ù4ŒOª¯Ö6Õ#Á/òŒ‚š‰‚I}À×oý7 †½È²>h“ኊ]½NjÚÛ¼lˆv%çÁ <€¾]c v+$ÝfÂw4Ù+#Ÿ©‘d"ïNvV/C…Ò§Y೉–mK9C¶®Ã'¬§ÿñ«€Q}®%°î² tø+幜6µ¯;ðÿMpªŸ·?w1òìZ2Òú9@_”þ¸èÚïe»õèzÄ®UûþÔmÃt:wœõmWp¹v¼¯Vì˜á-X«ºNƒkX«Y;˜È!1l°|@¤ó‰ÎÉÕ!¤W"ÃWÚƒoGœ[…êÈ¢0)fJæÄðQS²ô„8 Ó›Æ~š–uÿn² µg¶?Âf‘påÊJƒÜ^J¼ßÐJPkÖ¼žúìNƒJâQ<äRÕ°ù0ÏB‡óWŸ[5„k 5ry+n˜õÜà!}ÒJy+ågM3ò·Pw[/Y-`søÝnÂl,”"{[ÝéMœÔ»PŸ€;F;E8R¢„”ŠÙ=T½¦»+‰ëÍ ÉeŸ"ºò€ƒsÔ)ÿo[(/åÇxle„,9}ik`â_[à3Òòa{ÎÈeÓ/ªüŒjY-Åö° p-r¯E¤+^¥ˆkfSÕøë‡¡¦ß‡ÒÖ]¡ü;d÷[÷o»­~£ðôË·¾HµÞûÖÜïh_¨»ðúaøu‰×?'b¿c~[çTüü=<íÚ/Ãë§ø{Ÿðýýðû5ù:«¿z~–íŸáôjï|~½¾ó¾bÿûðõÿ:ÏáéÝïvûÝïNþA·áô'ðÓ] ü=IïRû¡]ê?ÃÐ_‡³ÿ­<u?þ÷SºŸÝOðïýÕT»§]×?N]Ü.ê‡dok=ôü>‹~Çÿ½¥¿áïŸÃÐ~±ïz~’ü>­Ë¦ü=Év÷Vü>„ÿCÕ_‡×ïü=×w¬¿ÃÒ¿‡g»Ow¹ÿÐÏÃÓ‡·núYøl^wU»»÷{¢ï{wzðöø} ü5Sü=ø{/ð뿇´ÿ¢?a~§ðVû«Íû­u¦­ í~íUô{]zºËö›ÞÞýíz÷¬ýô'÷ª}ÒkGÞô÷z÷ÐJÐ÷¸«yõ£ïxþï¾ú½þ÷ǽoû¹{¥ûIïqûÛUîþõç¾›{YïDõ©^·ûÜ^öŸ_EûÔ¿½‹ëuw»G½]/½^¯ïHû¿öÎvr2nèüýYz~waêc>Do)êïs`•w¬è ŒÅ|C~Ðé$¼0û܃¼Í‚6AIpYI,0¦L‚ˆ”0¯iE×}1–eKÀèæ¶ÏïµxKëKóBõª}C‹5[çÄKœÀË:8`‹_’Ö"z¯úIEMl“;kA,ªQeüÄ6®~S$l’QçùßéFksùô§n;%mØŠÏû »šÑ®Úµ«£ˆºB|H9üíÒ p©OêÈÒ8 þ q…*÷6Æi1[Éq3ZhA!¨×¿f}AXZ×åD¦<ÈÓ‘ sƒ ª¼þÒVŒ¬’’߀[À1*í6ÒðxUDCü$vø‰ó‰¶Ö3sÏm؈ SÝó¨óH.É›ÿª±M:Gè)¢u0Í’½ö5÷]+¦Cùм>Á?òü¶X³Ef”R!)”_W¿¹øá>r–é)Òy1™¾*ëÛ¿‘DçFA†ªê’¬0ðpD&a Õ.‹&È–ß»NC­=ü–6+ðÊÜê´Î‘ÐÈUÛ[ Å^3ñkÁŒ—Vë«ÓéUs×õ6–ÍÅ$ƒííbAíˆ˜Šˆ/ˆfôü08ŠÇ¿€ïÄFLr2¶Cˆþ·ÀM…ÆÙÁz´Úîí¼ñX jõïvàË’Õ§n 2„È$Ïn‡š%M¸WŒÑéeñƼsvMVsËé²ePã‡mwÇÓLõ±êž- s™è¦RçîácÄpµÛÿ-0PMwy7u*V×ø”Šè*‘?™¯µö,’ë©$3wíÛ)gN¯;ãBÇ X&¥máVŠwÛ_jLÿjR’7Yõ9Ä,ÈRéõ])M¶I£rÐÛúªIÎÓÜy—dV#þؼþ?G›!vgCPyÛp4jª,Ïs-Úê×?"`óeïÓUäãô_Ж<9*úÜ•òÜ`wˆd A>üåàÞ”j“Vü3¸-ñ.fX"ä[§¥@F¸M;»©ÿ|LòŽ3ÒÐ)£`Ó$º?€{‚)”.üwulß"ªÏ·gUcŠ˜/džÓÛ€¥°W?½T8Ý5Ÿô³&é ¾Ï£èǪܓÿCép;¨Ï*Q:ùÕª¹?™p¹¦×)yKÊ0Z`¹¼¯7„;˜Ø@å –¢_XâÒ7>жwvœ;!ˆ1TL–ͪ¢Ï…’ulŽ3ö“®KÈ'9¤Œòdž:¾Œ*^â Œi£¾-QËyˆZíÁàqèH»åúéZÑÙ’û¶ØOb/ç÷IJ²·&1,.·ì´ÿI/­R%i‘vÚ5­WÆ}ÔÓÝÝo!é=UÔ\O4…€^°€V—]{û=ÉÔΞtÀ)ÎxEÂöÞm37í1ާ[»œH%Ùƒdô4­;ÝIi}ªâØdFILÿAß‹ÿ ЭGFƨˆ-¿aãÄM Äm” 5àÃûjuU±-Z:Á¿Á.¶‚%Þ÷g=4Š4î)µã3ÙîDÅ.¿ãýŒhÌ+uÎ'A|5 i̦Ϥà“ÇÛ"Þã."@y—Zƒ¹jb/53ôt%¹HšLuýTC‹e¨ÀºˆWxHpöžóD¦w;ØK~C–PàYƒ@¾.E}Ì‘ÉJiÉ·³ú%¼ ó‹?Ÿ1B¬Ã!L{öÁç¬x-ª„9Ç­&øaûÿ>Ëç×áÊum¯b¬pžÏÀ{<Þü?Ùj­ÉŽná˜]¿6àˆ“EÔqNt©,¶L_­gi¡…@ɺ Q‰¹ºu_M!yÚÁ %ÜÇòðªHµIÞ‘Ä@1…e% ÄOk{˜> CµüxS¦ô3!]zjëœ1Ædm^Q½À:ˆ.öØjH}Jµ N9ÓÌÊ€h%~„ÌUk”q”Y•jÌ<«Ú‰†>lÌdùŽl\xo’[ xj’¼8¤×â´8fPnÅ”v;¨,wóS¦t’Mû`ïÑ¢šè\MÈ(æµîìò*ÿ âÄN i“É ÝßÚÝùѦ—Ó"\þTÔ¨¹1¿ÚEŸ"åƧ~¹Êÿòy5š ‰—f¿¡vÌ×À¯ÇƇgw€ =*Zø Öª®ö¹?þð‘§›0ñÒÚ… 6Ø»¡D°j„‹œjî¶šw/2*(d&}Oû¬^?ìkKÊ^R[ƹÊ^Ròc2xY˜Êè¿"eíûJ¤€°‹Œ­ò`¤ŒÁl?̹= à¾a5ç%ëµ ”jÝ+½Is!ÆFvz]^o¹ªâ|÷û\‰]^œLö@ê¼”©ÇòX$Põ)Ý{Ž‹Û*W˜¨ÂbÈÀFž™øƒˆ’á à6E¶£™¡ô@Ju79šeƒ‹Èár¿ˆŽQ#8ì…ñ-q´T!9¯uIJ‹œî¯6Pë©€[:~˜}Ç»j*'òúO®›¦` +@=A;§?‘!LÖÇ^²@åíˆ×àЪRHVq}»¿ÛV¿)KÂ8V˜¿ße¤Ö®2¥="n'_M»õŠv»r§¡áÁÊù›=L X|†ûB z·T\Š[‚lmS•Þ$ñß³öÈÍ­Î;¦Ã ?÷²D?$Au,Y#äKIÝ;u/×v™ìë‰×, ÖîylÁƒ…$¤ò׃+ºÓƒ^ï7…8¶w "ÜánaKtïp. ôøÒ%ebüá*W¿ÞONÇòBZöBO„‘XeöÁ3É"ÁŽš^Lwm#Óˆ > &ʘYå,óò³ö±øÅWÚ_«öH Õ΃†Nù{òݽñW¹M\Ô«Ý—2L0kÙ?²)øý9sjÏ3lSbrè_†À8‹p4½·Š7¸JdÍfƒüÊ ˆƒíÍVLœ¥ †Š¸™üæXgY´,ÍìÔ„ñÞÕˆ’íkœÓ‚„†É¶nããÄKDÁaO9ÀŽ=*7°ÚSypP{ÖWŠÇP‚4ÉG„¿—¶:Úi»HK°C<‘ÉßE ï,1HAÏïÃ1 ÐíÊûrv» %’ »zï&ñN‡ñF5£õÃN’6<óÙ^äE£âƞʗ¬J\üón9GV0OcÕGÐè›Ó·k?À%QŽŽ0»[÷®iÁöjiáz;g,\P¥>E .ÀH°'í”Iúvb!rø¬¢ÑÍ鳎G1àÌ,Q\‡§Äà¼òG©æêhWGUš2¦Ð®]κà|ýyôVewe²ŒE½ô%ØÝ/|3c§s9´è Oñ€Óì:bn1Uxkùò[,ôd¾ý”²mÙïD‰ãqvúYU3¯o]6RŠ“& •¯‡2\”ÒNÔŒ§ ÞÊÁº–¦×€ ¢9ÚCTãŒQ†1›˜Âª ÊÆÔ<#¾néà‰‰-R1U ³Š8vZÚ¶vŸ™ÏH¿<14‘¸m»#­Q8hµ®sc 5ÐÞHõk¦Cö¼H¢­ýò{ný_%@"¢\ ”š ;¢>žÃ8zk\&¥g³Æ+„?ý³ÂY w’Ðaº_8ËöcÃÅ‚LÑу“˜ßÆþÚ\@ÀžƒÃÈÝ~[ÈìôD(WÂQâ¨þ%[”XzçUdä‡Hhç[ø0IrÓîy´Ùïg#ç­dBž’ß.´±¶çvýLâ‚ ã{D‡«D¤GfÜáª*R/žƒ†c _;°Ð ÙZ†AC^ÿ€%Âí²ø;Zëä3V-fú„è­jW“묂½ Lû"áäbgxº.Є*ašO†°ÊsóøpÆ•’1ëk±­gÜ Ê亠¿ ©íKÓmät9ÞÊê³"«Ãy{<½!W§‡(yð韛k€,>üKm;GN§Ú»C.Ã÷ÎÎàþ‹'»Ÿ V,iò€ivAM> ºÒßzzäq/L‡æ×›¿3 æiÅ=R'•…lŒð Þzâ3©Œ—7ÐÓ=lõއ°Zµ¡Aœ„Ý NÚª³0Naœß…ÝÝ#ŠâŽ‹ì[Í"®¸{›û*:Êí&äÍEï\ª@æû¸áœUºw*Ø'¥ô>ۇäü†J&'uú)ÀˆiõhÝÌ£ç/M9 ÊàJ· »<ŽÆP9¬¥œÅ—™6è^7º,Ó ÈýgIðü_«p@ñ™ë‘«XHÎ7Ý]¿T=H†ŒCqó$W+ŸqG¯êY|¬X¬v1‰«ÞKÍ×ìg0Å6¸Í/·ÝL @â#ëØ+?¡vÌ×À¯ÿ÷”–òE˱¬e/)yKÊ^Rò—”¼¥å/)yKÊ^Rò^œa¯\ôÃVj3ëó?Ø»ãÓKUaÏ/,YÓñã±S®s† [eG¶qU-[hÙr™œAB¡®b£ ˆc#hÀFš0¦Œi£hÀFœ¯â'í¨‰ÔÌÁ ‹¹ÏŒÀ˜v±ªh¸E=JH^`»Êþ&=ª±FáÈ<Ô~ cë¾æI yƒo;(nÅÿ|ëBq9ŸãìŸ0ìíÒ¶o¢’)IçþdZêKG¸Z.]1[i£=ò° ÑÎaÿMÄ#·}í²íýsÛWvœóN«›Á8%”úpï`àmíy-{:_‰r"ø¦odį–ÔZ¬mS,ÓM%$¿5¢#ê•sÿ÷|Ïù„•s›¯Þó)gÔí>0s¦4”Äî!j>cò¶Ô'ï>Qéûj1Nx)uçõÒ©@Ú¡=b5L 7ŸV9|¸'ð~M‹æq†m½Ë’¿¡7ðÐ.¤Ã‘Y‡ œ>u‘uk'ãvŒÜáF…ý§½ö朇iž•™qM$˜µüÏq†Ü‘mX&‰a_¸–fj½„ô`0—Fr¡-å&Ê~Eåâ]h4*„nmƒ*»2á)™[‹Ó„µ ƽï‰T’4xƒ˜6ïÿN3éWÿr=DɧSú•c^¢«7ùÇ:Íëç¯ÑÁl{È-3 •ßdj3È(&=høÒmò=¥àÊ HE…\1¹DöOE‰‰±Â¤&›Wx™,[+´‰“v<Ÿô îlEš›±’&!:ûZFá¾ÝŠ¿¦½…áÐû>M©8è£Öƒ“Vê Ý9)síÿjËÆtº§.ǧ—V,®°jpÿ–Ÿ´<ÿ4&‡+bæ16и¸dÚzöÿXÔr‰)½<Ó”1܈mů‰ñŸ¸-…QÙ=äw®Ë3ŒüTRC¹ŽžžIÔå|/ÌRp²±/4ØŠò”ÈåIO’ò¸o)'âv£V Ó°ÂVn«sl £n uÿ8m|ñðÿP™xȘðØ«Õ.€?#4šÝE“·_š/ñØãåšÉ¨{P âoèlž…ª]•Šª\äuISþÊU¾>T¼a³bšrÉŒ’«ú<ù„¼ï²D(jûišÑë«/RŸËÑÇu\‚#ˆlÇC–,9޳_œl'k\;™•|8'¨Ù{›«Ñº·Ó²Ðy U¹4Ði˜ÆÄ9ñ©›µg@ï5HV>‘SÙÞš&õ~ˆB—ÞËDî"Ç`QKBž 0‰ vÓ¯·ö^Ix>È­)8LR¡  ×¢ÎÒ»’f`Š6? <5vA|ý­bºÒÊ3Â]aBü˜¿>¦sÁižg5ªXÝŸ›ï3,7̉XshÊjVPEU/ïæ¤4ÛΠ8~±#K'}?j¼͉·ÓBÃn\•Ú„дÉ.ú“ÑÚ)ÅtoÇ69óÃcdÉ}ÔDé¥Ôbšna¡I±oÆÙp<†›€Rq`¼7çfÉ{4êe©áSP±Ë‚ÝžÃ_›´Ì:ÌKÔ—Å|LmŒDŠ ¬zóhêP©Xï¢êl°¬ çE¦­ëŒG‚N`!õ¬‚&ŸùJýö{ñÂç:DªØ†Pm´y|æåÅ—ÇA·ÓnÁzݼU—²¿n~Íp«ê»ÔPî*±Leeeq\èùº¹FxĈîå©UðýEYš|<=/·,²§:ζGø½ô™Ï?‡ŽÏÒWè–Y˃‰5©7%X†—Öé?t‹k†Ôøx“ì Ô}Ây/µ«­4`Â,ý £9Š„sÄñÒy±ô%ÝËøï6[hÚȼsÆZ¿÷ RÝ Áz‘~kA¸ß¿kEP\Üœ,¾Húï[²ÌcâÉr$Zö«¼…‚ÆL<. …2Ea{Öwr¾ÜH•î’A4«r&w„ÉÓÚE8°4ñ/›å#Is€˜·ú¹pzfŠNÃp£b‚få¢ÌjÒS¼¥(äËÍÔqâUô ï4Y^HMiªg9›7o krÙ2}Š9P•rìÕ¶æJËöàŸñc#^ª1!Àá½6.ÍË`¢Ÿ§¦ÒÀN\«],» ¤±§Gr&EuGù±=+šQ®Ëÿ%º gëk? µê y)€|üâ/›5O¶™Éñ›Ê¿Cc_M4?¡vÌ×À¯ÿkÉë¡:qLN!Z{‡Ï+ GÊÚj .Bþ­KÝ 7ØÖ2—”¼¥å/)yKÊUR$zžð1Ir°¹Oò2 +7©‡ŒuZ™Ü R”äÛ¢ǼIñŠRèfêM=|ò?Çž*}™Ög5"Kq ȃ$2U¤äG(‘¦Œi£r¿ˆŽQ"¡7z÷ý-ªŽ<w¬•"T ³x_HcÂIüQpìÕU½æ¾=ÁQø>²nºK ¥É«·÷VôŠgÓŸw꘮ãÞxÉõåEVî.,÷æY× ôÞ£¬>.u›ý!sè‰é0)XxcßXB}ç>ÉÃ{t:¸&õ§EoKDÑA6‘$‰z„Ç!.äâG¤ÃÔBl…F”kèrz?¿ç÷IJÁå·s£Ü8kulúÃ&´ìÿû±Æ+ ú}ˆåâ/Ó﯇†€è®D$ã·ŽkErÑ䟪>B’žs¦#[x©©Ä¢1s©>žcØL$*Zú­Ÿr–svÂëL£ îkí|]gbC™°VmN}â5 >- Nñ±ŽÖƒ¯g|³M¯Î{›Ë­2š‰~¨9M¥Ht°*RÖÒƒU$Ö{-™EšPi±10WÏì æOD½8ñs$è`ý’=Ø›…Ø88Ç0`ë4ÍsxÓ-æ±K&o%Û1y9ë†_ üþ.ZÉ‚[‘nø¥nj •$ ¦^ð ‘"m•0lOuIñ€Vnù Do2O4žÈa²©xÙ“›W‡…ù½ÓN³È1}û<€ö«N†-sîÿP"x2ì' [EÊÏp»ŸdŸb†WÆ8ùÎÚ~`Î[èod.0õDæLÏû4øïŽ#¾gh*Ïò$î´öàªå| *‡ì¿ó Ã=é(‚Ptï˜.Z¤fëˆ{UÆRPëH•V0J ¦‰ýM€;ºï ŸúëÝÝü<ÿløàNºÜ q[Hâ\²3ƒû½^;YŸÃ†È]mv¥?{0‘ªÿ$.PÛUhíœËFÈ¥«”ŒVꮹRNy¯ð,#yÙ5˜D‰¯Û¦òU21¿Ë¡Ó@f’äêq\¡`ÊTåM¼€HyZ¬\kÔc'·‘Qþlº¸±T-ãjÿ­šò9ü'ùOFuzSI 7¢Bm™ì ý:íG|ØêßgC+2á³Ñî$ðRÛb\Û9ºà~uWþ’§Mý7#(¿ÿ|hy­÷…vÞô¸Ï´‚÷G¥f©Ñ3ô2h:Žê0'ö~CCôCãÃâp§¾x §#JÏlL/DÈ™Ç÷ÈrŠ›åÒ3È­ŽçòAxªI…á}ü=â l5× >¼òYCŒzv‰@a†…` XãȆ½ׯÄLIš¿îùRp1pB%Š]Ší¦¸VVâs­ª9zʱUwdfs%{}jQk¥G¡)\Èa»»ÿ¿·£ÿ•ºc:ä¥ LÇç¡Uzyõ Ôþÿd„• ÐÃñyÓ8{ }i&=o‡mІ·{·:ÔÕg}XÃpà?â¬Â½G‹&öHº*ÑIc\Ú‹—?ÿB1¶?ÿ~' Íz(X¨fiáÁßÂZd¡n°ÝØYg‡•(qƒ–åËHÿÔ†Wà4ãSàQ] šÉb™xäý$ˆ‚?t½Ó•÷F¤B YÝËü¨C 8Õ7ÆysK# Ht º¶§Ã>– AøD¥eû5bÞ{#4ÔÕ) Dߎqg¾,óâB0aøü*…Hì$Â!Bì–Õ‡ñÄúdi­[@úJ øV†W¨™ÐÏLŠƒè¦/fTЪû¨þ_Û†‹*CÄ·h¯˜XYmBDBþ÷Ĭ°íÁÚ zWrºr’¤Ý0Z#i`8¸‰ñW®Pø@X*{»;3ú! #™~„’D9šQãLG±>ÕG]%FWÅ\LûÈÕýÜx”v=–>Ü›i,ž)óB{LîÒÁÐÊüFCõËü ì²Ç£)$¾ßã¶9é“§6F,_”«wüÑã+- B$\dË{Rß¿ãP^Ëlc>vš‚«ãªuë—¼M‚G ;SgUâ·VyE–2½±šÁÒØUñ{ Œ°Âù0] Ò<2 ³ÿgål”“ WÉ Dt³)Âj:콚ׂÎe^”àú¦\ &)½†qvåTó;v¾ü§Ñbm“ \Ý,®~Æ%ˆÏ™ëÿggU”è[û–—Óäf/Ð<ûM !-ž6ƒö¹“i ŸÙ¹´´"¯}« œ¦Õó¿P€?Å%êbÊ~¼É{÷»Œ'Sò¨¬¡:¾Ùqh¨ Þ]úW/´3Ÿúǯå>v½¼«nmá¸íµgšHÉáC.oéX3óÃã%x½10jgª±rÝVÔ'ÜÉy¯ö¯ñÌ~UL`Úu«­]iÝžó`N.¯Ë<9˜äëëE7|ÇNËC«àU0íG̉ˆ—yO®°I|ÂÏã}¶h¾àIBùŸÀ7Èê+~Ph¸¶t´†:kWDžŸÂ€Œ”d`쬲1Hrj‹ˆ÷ûUóùßKl¿œœâÆàô–Ža`2:«¸¥£ókZ*7äKÿ8ý•‚žº1… ¹mxÏÆ¯f8Ûj³ñ’bUÕ1óÉ¡ñfðqÄŽ2­ís.ÃûÙdÖH N»T¦³sÔ|mq&N‘ ؉£è;œü¼j3SΠLÃáŠ/ÔAõy1â‚ôMwå'Ý™{µ¶:Âu:4ÒꂹÞóÀÉâYNÇz5‚¢>-ò|å¶ë;üÑ&·éQþu×–fœòxêj]%µ0ú˜"#­ŒØ'Oþæø_Ý[ |jàQgúÑÊ ~Ÿ3@+¼ ,¹È|pÏDNù‚¶{v¢búT«º2ÃóðF­Ž€¬Çœ~Œ5Al¸(qz¥¨Æ™×¼PbÈX¾â¤Å¶ÿÿÿí;‚㓼Ep[•3oôó¢”õÕ«ÍÆP$ÈÏ‘MÙƒº½âcçþþ8uHu®1› Ã\à;EhòxìRü×&‚îr¦V®–—àdÒ¥D.ó„Á gÈfšÇxn•Ë.\ ê`Äøjk†žn9MÞ¦3ÎPÔpù±. ÂÌãdÇ/?µˆ‹$ÿï0žˆÿÿÿÿÃqM(H•‚,h DiLnërðKYí0Ùõ^P ½tày9›žTåïNG‡$ù¹R5þâõÌPü²‚—8¢Ýs¯ƒ…›Û8¢”©š§ª šè.^šµ¢ùÑÜò¥þ*»_Lb+B œö¿ìÍ Ñ›ÙŠÎoÑÚa± Pß6 'çFàu.>+¶²‹§æ…~ßÔ%¡Ìž½Û‡"ß¶%g[Ï(Hí¥[£˜dûáÑuO«1pE}ÂE4èyɪ¾X š¶ÜܺǃÙýW q|âùU·ØçìFXläªw¹ê#s1î_! ÂG4¨Xb30yUt×@EÔ}s[imνÇÒcf]P7“”Üõ8í„÷9NÃäËWû0δÆöw,®òú®T^¤F:j†Vº¢Êaùå*£š²•ØŽ5¾}'@ñ‘˜™µ½W·§†0h¢ý› IÒé ìE?ößHýúšÆE•75…ú“ðòÅÑα(7 ÙYW(¨à°ˆxäARÿm¸h½‰uá?³ñì>¥83:¤|Ê*žEB&—:+i,ý«bß #9ɉ®¦g£Oà;m e}ŸÞÄ~7-…̆µ½]¸ø?˜v ¬öæ,RããF¤P› 4zk¡{2 dSí€zž9ÙÜgç…ë~?£Ü±Ì8lù¥šµ\–|\ÑS>›§€(èM\1Q–¨¿òüô̘î£ÏÞú#Jlâ‘G¸(X ®Ê«À?ýÍ1ƒl´HŠÛzùóRÔ<`Î'Ž˜üœ pIjý†ƒš‹‚Ì‘'2K!\4C„þ„ßšNeê“QñyþNM¤ýÅæ/Ζ:ÿ^ v K@l¹ÿ7žbI&3‚½•DµÁÿÖtý¬ÒGÀ¢ÊáôD'f›¹_8{;.0ôØeT ×ü4J¿;‹ç&wú$ëò•ÒðŸuÑé*Ñá<±,݇äbôãÀ73EˈY(à$ú­ìZð%4Ÿ`Ì0Ç:IÏ„$ø:OÅM¦ ·ÿ`Ü*ø²6yÓ™ÿR d7‡ÀWb05¨€*Aƒ‰¹±àBçÓã[¸«â<¹FŸ(ÔMÕJõêÍù@™× {K<žÃÐð£y/MØ&>ÍY,\êÓ]ξ-fó¸?Œq±Ïk:%H?ýv=Ù>|‹ÐýB|% “5ÿÿô5„rÇóer©swðÎZâ½6¬7›òϘ‘ïHC`Öômï/êQÃã5NÛåMZ³œ·÷¦z EþqGQ‡Ù“¢Ìß‘ÁßåP;̳âÜY&À2I|ä=BjVIîïTy ¾Wã‹öGåíy‘~UzÊ´?ïÚ }¤ÅûÍ»¨)ê[ò|~”"k®³„¯)Ô¿å.ƪŒaXüÍÁ‘€:S!A±`Œ±ÄÑî‚ÀËŠ·=x±%µëÎëåßÇì áßlµâsð‰ ;±Š ó‰‘Úím™,ÚþEAªm<˜W:j@TxÁ˜^*æý¡¡“¡È³uòKØÜاKË3‚å§G #°\çI?p.H·]ª½¿\EAA8?éª!N\|Ÿø×@ý&ñãâÜiªcöÔÁ"Ç»ŒC­¦ ]¶ÓÞ#R,êR}„—ù]³öÝÌ!3f©+2È_öbŒCÌ9 Ý5•B X›´ñŸwÐÑYz°Æu£@^aÌyaË–#TXœköºy"Â~VÙèÉ_‰ÊehŠjñ:):­€ÁÞÏ%Íé9t6§X¹çšâÒÌy) 7m]Ÿ’ˆâ vÞL[sqQÞ°èNƒ{Wõ­¡ðr`ú@šÉ‹ßË$/Ÿâ3È:c&s£-W>e§pšeÂÓü/-~Èj¦ã]¾ÃUº;¬µÁðAm€»ñ*uú»ë œHdèáí“)PYhÉÐÍQyŒL$$Å10±˜³Ví²ü•øÐš *k+3”Û!ï«Õà|·:R 2T€›NIÝÂ!8_H1ù$’×e’ÿÝÂ!8_H1ù$’×e’ÿÝÂ!8_H1ù$’×e’ÿàµ9”iÁúNÞ;‡˜·Ä(©]*ŲvÛ佞¶o)ºú\|V@›âk_ÜSy“‰ð¥Ìƒè°FJÓɤQ·ÜU‡ùT1fŸ ¦]Í_ÈÁO-ؘ÷×E ‚ ”Ð;×–DB¢. ÕhÑzè«MË!QUD9oó{þ-I<§eˆÅë&ò»™XñõïÉ6ùÑߕ٠O ÆÅ­«%âžëêì-zÔ_ì­…×ñ¿ÿ|ß\ªücñ|K`*Ëqû¥Î6&pag[P•׺š´´Ï7"àb{³ÕZlüþ ¶þ‘Û;Tæ[çr7óS§Si¶^˜%³ïÜ€ÓõËW±m…šÝ²| ŸýèCrÚ~ Âg0’àaà°±ú°Ò9×FÂÞÕlÞøyÎ+ŽuÈÚv0æ™ô)¡´ÏG¾ã® µÅ<\Òžø^ža®†Òþß@ëD¸;œÁ€(5üðp½³Ïê^ýrt¨ñDÕáE8(¦FíK©`–Ü´að3Vßζ ö7 rÊEàüáüåö“µ“|p;)hHF6Úv-NÜ! Ð*À§$€åÅcPpEç›°,Ù.%Ø…eоËm/¹)†lT' %:þ Ä‘0©¾¿aúm¿òÁE´bÜA±!e¬÷ºõ ßÛà ¨.9‚æ=¬ |dÒʽ`_~Ù«ÁîŽ^Lã´ŽØž”ˆv :Xdápà©úòëï™Ú6ÚM0ÛÎ૯€EBÍ´´-ìÁC Áö.*XòöòQsõªr˜ô¿ïçcsl ¢‹U´kÑΩê}Ãß,ÓŽÙÝ›aåÏ­êÓá/þ¦ŒPî[ù’¢­¾,j7U˺rÿ?}\ˆc÷¸r·Q&Ÿû,ä¸R?ñü½™P›—%G칑¹´È+ù!:àôIžó9üBxð+Ô \ÔÒfŸW4]e\ãcí´Ê),bk×¢¥Sãàö…7{‰¤0ì}²ÙŠîMëGWzz‹¡#ñ’Ž®È÷Ü»¸Gí,ÿÜx³ï²¶Š¾jiãÐ"sÐhìÖ`Å•Gd$;p­»ý3­c:?)Z¿erÿtwmÅk‚\F¡²—îvODZT¬àâ“ñA¨d…m>'wÛ}[*¿Y%¯ÂŸ°PÄÉ™ï84Áàß Y×0ÿH‰O)@cë„Ò!Í _ éÉþ·³·;ÖÎå[pÒ)Ûø¦æKX[ãö·þŽ ¡Óÿ|°¦[Ÿ ‰q]™¸é:` 2p”úvÞ¡Ù³!tÈË^ ]³P^1…`T öv×8¼Ýv:˜€  ñ —",1Bÿ%XC¾WÇZ­m;Bïî ­¯#/–ùñ  H‹ÉO°ÂÂë4¬6ëmdÉ,c?"D€2î¢àÒ™ù6”¨± ¦²‹våÙˆZ!Bo$Ô07êÈY!ðAXuƒ½Cá%°‰WÞî~˜öÉ®dðØÅ.uœË<„ºõKahÕøÅìí&0‘U_ü3E.bÕe??ÿ(Üú¾‚Š ‚ËoÈ\dD”ë½óþ—xö—€&¸¢÷ Âűìm’°²<!ªÿ‚x‰À¥9šmü7örÅ-aLÝùIÎ1ý²’ÂvñÊÔ½¡Æ ´¨6Ó¼£_ùø×"HÜCŒÛhM—èê]£¿M›öWý—z^<¨LÅæ³Wh_·_’Y}æG‚¤™Î}3BœÕÚ\L‘^ôB©e;8RM ‡T1F§È+„fÏz^ggžUãf]Ć ›Š‡ 9cÎÓW¹í3@©p2cK_AØ[Ù:ö0šáR7W²Ëå¶|Çï9gªÄÛ7U: :ì™e š)%+^G ôÈ÷®Ð£><¥ßbGù|,µgB±Cm ]Å¿â~l xðy‚sæb9›IS+zó[p _6Yˇj9OµƒR„Ê‚ 8@o¤êÙ–<`S,%ÅVòM``‰…Ç 9[7øþZû¥p™~/]¿ÙtÅŸ^Ëh`©b$f`tøßš-ê ì§½dÔVî sZíý|wsnˆÆ±uÆXþ¤Ctçhk»X‰Ÿ'y;™¹žqÄÃmI-Õ<Ÿáù•raºç(]°®ù”´r®£²á(GŽª‹+ñ´ÏÏlÞmQŠy_Gêú©fG®ì§ñ„­—Ð)Î)eM䃟“fÛ2ßxÖhɼëE ƒ´Òñ{­µtDÊÎ…æz[Ôæ ká` ¼¡ŽÂÎV(6í Ð…¢)Ø#2lIj!I­a« ÇÕZdD陈½Ž÷½ï·v°,IQ8ªhTÞ“ØhÜS’·}{}gòÎ,ÿ\¯¡BõWÿ~$7çyhδóˆ‰`¨«Ò%éW#Oˆ§¬ÕÊN”e…a¬KRøûS`Ï]¥ú3=Ö;©q2]N®ìuµnK´Š?†Êª4>ЗEû@l7.=d9ÞÏ«pÖ~F§×¿vêªt=Õu¥ŒX@T!üåÁCCÇ’­Ã`5ýâc±XÂé,ÜG uÔ l³ä·ZâÃdœ,`Õ9œRŸ9Š$Ù«Ï›®Wh/jtRÏî¦åµ]7°2£‘·gÈü$[iÿaÇzö"bdÂøPQ‘D~€&k·,ç<é¥;µÍzu,k‹ÿUžDäýב~Æ(#ï=ãë\µ²‘T!^·­ó…23ª/‰ÿ(´ûaï] Oí]º]ñZUvœëÓ¡4_¨E§¶ ²Ÿ»ç«©g4ð…z,“uömEïQ ¦|j´¥õ€éˆÛ¤$•¸Åóx¼fkMõÿ<¿¦ãm+7ÁòE"Åb"ÔäB- ^0¿ÙØvo•<^&O«¨²RW®‹Ó3½s¼s¯e´6½¿Q–Ì•Éú8}‰}ÊSû@uµ dRn­‰žÃ¯{ð3\„ŒL\JO¡Úv¤R0{þÛ—ÏlA)§ è¬Â'ó!Arÿtª#^qÙÓò=çx_q-Òê~¸Àp:<Ûßþ‡åª@™î-úý£ „Áo³© ‡|í¬‚8Ž",èÖzÔj`¹[<òÎåc¹Îž0xê":OÛäнÉO}Š€lߪ‘qÍËûÈ Ýkíx=è öH~ ­3«ÕQ?¯B|k­À~øÇ§ˆºfóL6¤ér97ÅÈá³Uf=«íx+@.¸ØZ¬«I4œù…}é ¸ ˆ©+êʶe—’Å׫º÷<¿í«¶çÅøo-Ÿö…u'ZÔßËgw@•¤¶ÂÄÔ)Pö…¢·ø AÆ™tòËö&ÓÇ¡†õ÷áÙd÷à"_cëߊ˜¡ß#ùç@WãS±ú’¢[[TÐßÆÊ«>PÏ…ð|§ƒiæ¥Äö)É(ÐUÒCÅçd™®ÊÖ·Õ °šnÚ×¹%éb8N¥éó‚Bàm§”©+;;‡D";=Ø.<³L >¿ÆÜt÷&Of6ÑÕ¨è;&ò¡Œ3,¸J84Þ£D_ëùÖt'ò×dÌÄ-ÎÙS×1K-·d£þ‰ÈòÀÑî± ÒàÚ.@Ìz6‡ƒü¿ä¦Hy´‹6@Àôl0>j•ݵó®"ÎÏçue#]Êû d›èûž¯C8hæàú¤ø,å0hd¬lM˜? ‰Q<·ïj·õ­ë‚YȹH© ?Ë ¬Ãˆ’Óý¿gy–u©yw†0š2éûR?½ý&`ñü1ÆÔL0Ú:è*¾]²‡(˜‰‡¥]@.2™±s>ø…NŠhÝSÅø™×kž[%)ÆÙ«(>ùT<ǵNG›75÷Á¯¡‰wh­“¤üL°ÒÙþŸNÍlçÕZÅY‹6ó¡Púõ( ý'Cë…øtV~ž_ëD88§x¾`¤¤£WßãšUôꟵenÝ$m-ºàÈJlËj«]H†BžÁÏ!z>Þ|EÏ©‰w¡øÔçRaK¥w«JqÏÑðJaót8ÓT›!Ÿ,Kҗм¸§”.Fá…¾ƒ`Ež“ÉþHAxÛl¢3ˆœ‰5´W0¯1Dñ52W¥0Y=fþò™uW1>á<ú~kó•{ÛÄ‘¢­É ü{4òüøÌõ貿ƒÿáȱþ97YxpfCÇÍ©5HZÓèfîÉ~Š %,çÆ·Ìò®ôS§E¥´É¦éØimfvv´F!­¸‚N]vCÉÃP!WÈUùîwÏBYІ~z¢œ®Úaù·N5Rò»iöhä+:Ec–þ›2Â(»x_îNžä§NlzùsºÚôï@CufV¸Æ¿›·áf#ü3ÒHBU ²PSpœCô‰üi§Â™¶Ë#T?q™oõKe~ËÉ/(A‹Ã(ü°jfŸ®ð_¬d¥•[«H”<ªºÃ‚ÍÍó?D;\\—ýýab’Þr¤£R X ¬X”‚ùÅõÂí3WB„ZâAÆÚÌB®x…º¯°ë# ÆzÝñn‡^ª ErFeUñaŽQ~>ÔfÚÀãÕìœ> }˜õvw{÷Tu“~ãq^FòWV-$¹‚ñ¹~@eÛܱµ”¬;[¨‚#Dd¹F2û³J©¯3¡ÆPl˲–œÝÉj¾úâ›°f?3„Üz¥/ñî‰+ã¡I’ÄXš'ý«¶Ü§˜(€Þ·øMññù6¢½3lª8J4Ýmfl™)® BKV¾$¶zÀ|ëÓ(¸Bäa—Q%CR ¿×UÄ̤Nµó%«Á>éøÉº*UŸÞ?ù)ÈÁÙÅDÿ¼J [e¶g§s‚Aº;C)ßCâþ¯"“ÖôHŒïó¥EayóÇÈæ’\ÚY»«™ðŠпh²Ä*îÞœê=HmȶLŽ›ð]¨,¬è\«rA—†Ñ0`Dk9¶°ïP*³Oÿ)!«VÝJ> sÞ»}yf ñdc€” L}ë»BŸ%ä)–ýëýœ+9òŸF8Ö’h}¶Ý¥5Bøä',ÈwŽ^qΑMcU›DHIJóN¯óäFqd©T!§j­N]Ÿ`…P&ѼvÞ+ûÒwª(õIªÐüãfŸ²ÐrD¬ó1ân€>S%Jÿ^Y>Q€mÏ;±YØ­¡ß<:é‰s‡²½³ÆEx0¯U¿žðéìF¹93åk~¯–~…E¸õÄ'ÕÍ‹áb½>žµ‘S ±R]‘¨É|r_"çÀ©P¤„9=1 L äÚëS;ê~x`[-çµ¼&ÿ_"šÓ?ÞžNèøüZ¡3¼Ø™;çŒê° 1¸ÅdkÞñæ+ƒÞ–áÕ¤‚ÖSAƒ[U->Åâ{Óê\Lݸ?ã¥÷ ˆ6S7²œ#0‡zu²?¢_Kß̈3åN~VD#åÍê)Ä 6HÌÁE ±5°X$8sãÎÑã4ÄØ‡>¡Ý…yo„>¦¢¸ GEýÁû•dAkãmQK_Þ¨Ô'ìCv昕t8x·ðý¨¤í6ŒKôð4§BñnD™ØpkõBêvD¥UG¶š÷?U¦ÍÀ&þþáל@&Ôâ± l¼ \äO2MÀYW½]œ·qîX¬²îÅT †l#A§†ßÌYMÓW>¦Fe4ù>Ð7¼øÄG2R´ã°tÑäœ"mKÒ" ‘*o©œ@í¹0ƒ Œóí¥«×ÂÍcwýWìªÓ|ø“4Èø¨URÍœžp˱!õ`•.¿zÝý|N.±[šÇ\C)…v=”Ò¿/UEÀ÷*ìÀª”¶wÊLvªyõ×Èïsñ°S›J˜†{ßÚu)PâM¹–šûß2_ÞjÁ5Ï_M÷€ë­ÞVêå<@9°äÑÕ‹<³gkÄfxíì£Ð•Î%²ÿR®\lÜ=RY}²9Ɔ>áÔ þ–°Åvà^‰\Oà’ñûbãv oÛ°ÃÝç¨kq©‡…+Øm‚¸,…c¡ùghäž ωðòhkT€©à…zä쮑vRõ|=ÒÓâÎÓ%&š£`›U¸Ü{ê;;@…‘?XH?†µÙ9þå#%@HÉ.&›AÅé h_“¸ƒd¶¡PÀ,¢ŒÎÂÝÏ ¯ò­.Ö·~¯ÿ}¬0$·ï`Fê~ÞqåÑŸ³Ä³}1Õ©O¸ö/ב¨XÂÿ‡Kz—¹<ÐjqÜ+Óà j©J½0š=%K+°Ü4Eí‰X¼ï¨&Î/¸/êOjôÕûk:kÏÿ>ôõA9n:ç” qÛá^Ø2òÒÃ~Yä¹Žë ®âGÆ7ÖþS²8;“†ó¶Áål—ì àž$`Åñ¤‰ÁczÝfŸóí_“¨_WO<Š<õi.Nh·Â?°·×·¹[ö347‚ƒßÄ©ÌçB ôT¼“Ât²R\½UQÝóswújY7X1Ùbè0äðqdÀ§ Ô ^"ÔK«0CÌÿ)<%¹2Ü "ê~]³µÏ&Nˆúaä”îΓ€Š–¬­@›1ÆBuMx~â%C$ÂGÜ´Ñ×õ±4»Z”*®Áõ¯šÜŽ`áÁ ß¶'æ7z¸[11QÞq9Ëo÷p—I‘J×T•ê&Ëæ«J}–WóêսXò颉PŒäõ:{µè ÆjÕ]%kI\+2I¼½É£9ôúßIñƒÿ/Á6,¼; ‡øKâ7Y>åÙèõã %=¢EÎ{8'w„ôÊ_º×ÒYÖ• ZŽ¥ê0ubY΄‘Üíïãî®1ï¸lÄ0í/å3Z ƒZLœˆ-•L°¬|€  ÿ_+iS(BîDÈWq7Üm¡§FûÐWôàö ËRó`å? `%;hæ x3`…,†+»k9Lœ×àLeBâ819ÈUãǘQ³t%<¬-ÖBúÎSèz!vÌè~€$Ìõ”â¶ O´Œ*qÙLKT¢¿èTÁ £–¶mX6]Z_ñ!àGðÂCºqs–I§¥ÞdµCÀ½HòÂI›ÿ7 z„34zÇ æ«Ï?ó˜¦ÉîK˜ˆá—–Ÿö±'ß5†b#€ƒ ÏranLšZ׿1¾"ÓõÏîÝ'­î‘‡ÍâÆ¤®}Y y˜uj²µm[v­ê›®­tí¹µ”;JO|Lztdx5ÚuÌ1uäË%¿oó€`Zžf¼-¾Qaµê;Vëªø ˜As¢†‹wÌ4«ØSëÿ¡’9°¶(tAi"²½ÃÞÒþí››ŒÉ¸l—zë‚áÚk6ŒLõŒ S#ä±ÀJBÄ‚w ͈ºLxE¥ðØ).BÆûWø¼ÙF ª./ñ„ebZŽJkwħìrlbÚºš U=ô+Å.{~âiM›¬øÚ}¾‰ÑÆ‹-'ÅR*AY€Ãœ6¸ ©Ø³AË‚yMœÜ¡ èšq˜?¶ër[cfÀ)¥ú­HˆŸX©ËE&Pv5È‚¬7ÿOu±è–ËêiªwuNÿÃ`´ž©¥ò‘ï|­ž$}ÎgÇ"H¢4Ä/ç‚2Ô²4çèʆPCwÈÕ`µn#*1$¡>!Ø`›ܒѺŠ)rRëÞS˜ƒÒ½[+ñ‘H O6il›öºøšpz˜ ±¥GªOÀ^r¹$v`µ™Dئ!èX½|¥\Hщùç®¤Ææ‚‡ÿ.¶!*“?“⦧çý»(¿YÃè;³ÉsÈ'ýÐrí[?.•CXßÊ0àáïšYæðñ®›ÿbn~L-¦RÔ+‡™ÊFn>ˆ(o#ñ3…JèöÚeû×ÓøËzý;´ž'òù£…Ôt°;eí(ZÏ}r~üY¢EïÙ"™ôÿLÌØ'£Öé<´Ññ‰÷œ÷Y8á†Õ:T¶DA¢½sG<õ˜mü¸¤À/?ÎæF­BÇ\û̹´J¦ràã#è+Ä8ŸOs¤›ò­/¼>T±‡hBÇÙCÀ\¥HÁ”½:LQe$QŸ &”̸0cox[ëýãÓÿQ8a0ƒ¹r-ßÇ#ïür ò”öñÝ«ZìYí*©72ý4n—çì>ì¾eãn&A"‘‹$ÝòØ£ê4ßKn¶sÿP÷”ÞÜ\$?öëæ-$¹u>‡“'‡˜£(ªp¹:‘Gº>ÐP‡C7êÓÑæáÿ9ñ¯MJRȘ÷×­\ب'ø6Ð-tH]R¤!àüVrê‰ ›<ÐZwùõ{'[PÏkÇŸ:†liü4VãÆk„!ù‚'Å»èªW†šöÓŽW¶êȲHŸ"mA÷Cç/ú;Ò°€éˆ•Ã(>Dz°`››iù•yÙ°À¨þþ\MœÛ+õ¸àΉ«t¯rÔDrö9gñ„? øä:à?ÿ hÞ“³jUGËÀf´æŠµa èaåIþ¯ºSÌN’pdPN“OG)’¾ô£ª¤Ê¢¹†æÍŠX2¤?+ÍþþJ›ëù~Þ:¿ÿ„/zËF€9"NÓ;åe`ÁDDDDDDDDDDDDDDDDDDDDDFw{zj®åCבe?K໚OÎ9ÐÎÈ›\”<Ô…·Bóý7Á³ì{¹ZÙWêú×7ú?MÏ }ÏÂ*b!Þ¤¸oÕú+}lAóCøä:à?ÿ hÞ“´J:å1F66 hÒ 4ÎùAÙX0QÖm³W  ̈½LjÑÎ˥·Æ_Hûjÿqj …Jÿøä:à?ÿ hÞ“³‚%•‘£4nÌ5*­qÀCOàþa§ÕZmÚø€'Õ/ƒ!Wè®’ðBÀU”ìUCÍ|ÿò5ÓÛˆ6 hÒ 4ÎùAÙX0Qß ÖÔ¯f=b@“P¦"Úôd`(ø8{™ÁÊ1ž ;…ò^Óòª}QßÊu,L3ÅB½Žë¬¢¿†«ÿ[Ö €ÎßlÚ;à¿>©éò_« Hȳn€,Ý0r],Š ×b‡MÕR/.IŽ-;EðdÕàÔ© AJ,ÀýRÖl%?¯0سQíô:áÿsLGþs`Ž’…mã¾%š±¡_ŠMx6ô’\éûò4¶ÃE{‹ƒü3ÍÒj'õl¿›–¯Ùd¨?œ€›2Ö MÈZz(ãGiD¢Ð:4š…]÷d‚)w<ìˈëÆ0lF47¥H¯\3Ÿ„,™×Áš urs¢^÷æL<ÑÐ1Náã¬J‡YÕ¢íˆ1†N|W§-­¤ïw ¨„LÒßTqs. õufyä×öÇN€ÂVËlüIþÔJK.ÏíP!uö6šá×µ¦üØ;ž:@È€tb2¿ã> # \Ç·!˜þ„©ˆ­ŽAÏn °–Î]Xµ ¬úwÜ2Ép¹sãÈo l þ”Á˜5‡J“ßúÓ┞/sÀ[De2îNÜÃd³ªµ˜²¬ïB´°B7þše}{eN ›âïL'õ+ˆŽnè…ìâþO\íÑTþy¿šR ¼ìÌ¡¿§8Ùyâóõcê4 Š|0ãžÃ’„’³dlßQU]yëÉr"^í]‰Ö=ÑÝU¬È¦F{%4<ý)+.VžÉ-Ñ$y*~7´Àô!|N ¢]öVLœõA4 =+ôu |¼?ß5>œW…y»_†‚ùÎ#»ozçhW„ö/†‹±vP‰N¥½ÐWië»v½Äƒ©ÃÆùþ޽5ÌJ™›ŒÜï.IÏý³µ]ïa \cpà6×ðY\×-ÛAÄAQ‚¦K¥½2†ÈØ×HÕ@±ØYÍYFm°:]Ka'(þ‡³ó| a™7vöKYö­Ž£;®@q]¶)ìšÝl‡ØÃdN®ìv}¡M¿N~öŠQ$öã"6”ΑçᦦiŒíFÌÝ8wñʬ.Z„÷|Sñ4üak‡«úÜ:êõïþ˜î´X ëôq{¢¥B/ß]¶›†ˆÜ§ÆíʤîÉCdÕÅzÇyÃÝ‹GbxÏfk–ùj=FëW3ˆV­ba¾Õ\ѯJÚ8›²’3Ô´¿ë_}i4cd’mò…Ž…¼viÞf©ç4B™u‹(IÙÙÓ$Ëmà­™mbû!¦¦Ê_Np þ}z¨u`óRp$ïË„–ˆ2upX3GÐá¼-­_gÓú¡ê¤dУˆ/Ò,Ì»ö‰ýÀ·-{¼íæz4Ç&õ#$bùšnr_ÈyîÈe}Ø‚É ™íònÌEu³ìÿøK¤sÖpk*ºÂ]îÈLÚ( h- ¨>P]šîÉ´CÎñ~G×;ºÑŒÓÙ½(B» †|3€13ÈÊpÀkh¤1ëÀƒÍ‚­›|ikõg x¡É)žÜÇžL¢ðJþ§z¥êG5ÝB¦l\‡ÎeÇòÆÏÓ$z +?¶K‘Tö¢­>§:ÿ(Wø]cÏŒ‹ù¿›­+FUXËä(ê=,¾CΗ2¶lMë“èúÒXÚ!-‰0üs®dî|ÓøGcK¦ÙÝ«ŒôÆ…äÌÕºvP6…Å{}ùB]"à¿XjBGºPɇIÙþj–>¹:2½i°ê¼ Zµvw€"ïêôa¸×Ë/Õý·›lgLiR7øx—’öiîN:Œ:!UIÅ@q.ø²„¨6  ÛTXXyXŸÓºtÓŠj ¦`?.&R=u3G_$ƒ_)öÿ y+ú*šÍèš·(yÍoîbãÞ@[qŃüO‰4/õ<àŸ'JV{~=¸†WºaªÌç—ô²†Ù9 Þÿ=8ãeX¯>k1‰Ÿ£ g¿ìÓ5äuÍ^в ¾YÍ^‘¦ôñ{7x,ðP˜äí‡7 BÄ~i†¡¼Ä)Ǹc&Qâã¡Ñ·fÑeÛØBÃëÅœNšG"™ëô»³JèIU]i º&h_ˆI—æùã³Ü ÞÄ]ÓI*ª†|ÿ tŒ‘%ÌZù䘳’½#Fzèˆ2m!Å5©uUæ"¥@V3‘bèe­ÒBÀNÙ-äŒR»9PŠV™p–ôÏϳ4€Ù§ñ Ð8-¼‹UztúkB‘ò@·=úºåKÊúKñy³çŽú bÄÿ=âi€»:\B“Jà"s«‹cT”Aõ—úu䃡ëòVN-Fô¼²"æye-ð3•Áað úÚ lúÿ%}ÃqÊ ä·v5u͹A†PàvÈæ²XÆáne¦î„L7‰´Cé `XYï'eÍ8’o•—ÝÓ.”öF:øXÊ"ÒÌ”Ÿsk5ŸµLÜž,è97j¸O5K'±DtNËÜ_€.p€m?ÎYä<H"b[ƒÄ ÷È3Ž€j(úla㜧ƒA¨»µ-_y@BAJù»rBI )ËÉ‹|¤öKÆ uWÄÞÎnÝ9áœ4%Ãÿ_^‹¹M6¯°r™ ”e¶ ‘fH?{›ŠØ>VABÎla[Iöä¥Å ®Ÿ¨lò:MS²²Ú‡üÃ3¼°¼Ìκß-Bú `OíTi×/9ÙâÉÔ:²RÐ-° ×ýDš¶± ?&^m'©®"HÖï« òÚè´ÇÁس<îÇìïßdƒµ¦ç&)"Z+Eïx0/n&ÊøJ÷‹Àãâ!‰Ã‡q"gÅrY‚ÿ.Z˜½ºÔàê:ùQå’Oׯ.9Ýmí·4ùnJñ™LCÿI¯Bi Д4°6ij§+£5rNqÃÅjŠa›Ž¶WÑ=ž±“d’!ðúžkbß7ÿ$¹Õ¾Ù7³Z‡2&Y®IoÉ…wyN™¢I“bù}ILw®bÕ·.†'Ñ0årÊ3¬-ºõ ¿’Pš¸*•éK^ íXòñ„ÉI 8êe0$¤¥P-*Ìf/˜Ú±|_¢.C¬mNJ‰RTÔ®$Ým»™2ù%žS¯4@ÿ)!tÛ;Ò®gô›nACÙg‚:I ¿ð«Úÿ!®£ž¨cbüù#.kÛžÒrkg%¿Pûg é`—]!Ù c•{a¼)Ìn·Pll9±H^µÞÿ9ÅY1IJ(üõÙ¨šžÑáÈÍ„¨žôÉgý;Y¿~‹´rCQÓúý^UŽKá®Äw–PÌÙ¦¢Ná‚-Êm˜ôxGš%?ªïsƒ§“{òöö>éüUû÷úÄѪÀÛš_3"hUxïàíá‹xC´Ó)«\uBHFŸaWPËÒbù ׯŒ+ÃÚ‡vdú{%4¬vÚ_ÚŒ ¾aÓLœÔØ,ä¤Í GfÓ½@ì»’_Þþv7•Í•£èæ1ob˜ xúƒ0jM‚ÔÁ"¦Ó>n då÷onkœSŒÓøMÖ%‹¢’ÃV&þÁ¶³ ÐnàußÒÕ^[¨ÑøYOQXž¾,o鼆9ðEP~T‘l/zoœËX‰k`ˆÂÍZ%â Yð0^pÂfdkŒÿ€kÛÐë‘NAÒäú/-¶¬ƒ;yÞÑÏ_Þ%Ê ³ÈCb§b5Š1ei~fšzXuÉ$90åȽUÓƒ`ñÑ\òLÚ“^䜮L)Ó×Ò»MÐx>ž&X[#ÞB\·­]C©P<ŸËàÞ,ñîfJÞ\㱺q8%Ê×öI- WûèJ7"‹ÝºæT"ãÆóª±=!=}’d¸¨VëÑFoÏÍ‹Wè»$Èÿzà!þ‡ö²H¾stCl>€2Þ99jª¯K%LÚˆÙï2§d¡´ö ·/ ®*šµQxgGé¿ñ4H¡ý¼8ï,ˆ;ùÅPVC,”z-Dff¥Sèuª¶çeΧbLrî€Ô*µõÖ??éöÍ §Q G/„FAöbHTÊÓÏBob"½VÀ%².Þ²„×äEò˜®‹?*‡fòÏ ãó+w¯åÿj?Ù\jˆAB¥P²rßöOŒÖô8o±‚K”1ßþ˜7#>Þ±§/ ^‹Çûz&þ;ômîÔUïÇcoïäŸMª¦92 MfhÒÙÝÕÁº8úùªDbé,9Š ð0·ËëÃJ­&íðóªdL-_¤¨Ç­ßÄ}%žÁ¥êÿ\®Òðó1ò‘–¤ìÏ­Xsâ^˜»”¶ÛnÙÂ6 ÉM—çö¡D÷ÔZ± |A(ÿ+ögiCŸÀ_sZÌìpÎε¢âWMvœ° “?RäºJAù@M[φÕL89 †U¤ëç Çm!$ŸSâȽ§mÂü>ùÉ«ûÝóº7:®cÈ·Þ7š?­õ>ìÜd0«r¶ *ìøNHß)M0¥%a$Å9+vÁ|äú`—æb—SÊÝØ»Ò¢2ÉÈ-ûeëÞøD”I• oNHsÞ'-™;¥Á‰¯|ýεoàMÕ¹Xã˜*i!ztžêHX>7V ªi%÷Ï#`”!ƪPLò¼È÷bƒ{̘\að²g,ÿ _¹…nÍýE×UÐ5Óìù½ “/åƒ"³-}®:À}?z¯P,{3Dnh,Ý…azý“+¸–íhsbMÞð`„OŽñÏ(ëåЄ˜Ót,­ŽS¢qötÃMOôo”UZê…UIÙL–©Ùb|<Ðt~|,ÕÓ! jæŒ ÖV œ&̬ÌIÅ·¶p–ñ…ѤÜ( ཚsŸp‡˜ñ(\ ÁùJl=žú™ívÈh଒ÿ1:Þ— ¸ê‹÷Så•v¸Ì¿‡ÝÛ2{¨›ÿd­i$hîw'ðÎ7Æê2hf "T„¤±ð§çÁ UÀ¥îw[Ÿ†#Mì¾E«ïÃÕ;¢’Q-²Õßf- `¨ë3rÙ=Øÿ—õÓüŸ5?Ù;¬‡wB`ÀE8–èáàÛ6¿íó Bñˆ5¯P±³O,SÕ$!.œgØÝ¡ã'“Ø£‹¬iëaSšúZú ‘oè6î"g‘Ï6 lûƒY„èâÇ.°AÏ<ExpŽÖÚ¬h°&¨ -Ùi\™\ h3Ÿ’š7}¶$ ©ÑNbék ¿Pk‘o9Ê©;×äûîç°Usé†Y÷¢XË]©A™fȦ/1ö;RÍ$ò«Ã†ƒ/e¼€¶`¬¦^DÂzi|ʺ³’ƒ=glÍ¿4ºÂ31ŠýÞØR¹ˆjÁúó™‘!¼‚uvg¸þ¡MÀ`¼ifêÈH²ó;æ8¢’½Tšm˵ÄNm/u¬ÙÉ+¸’£{Zp^àÔUeSP”‹´å,üæ”R¼@™4ð¯¤x³cÔˆF [~,“›–;ñ yò1Žk0yÿSKú@ †ŽŒø´·r¿ónÅ-³mgÀxÅâNOGÓDj ³Ú¾Ê3)›Á¡8uh'Þó÷¾[jýëLt“L r6½{¦R‘›Åfjß•ísñ9q O»$,YÜîœ$õ•‚ . w¸žø÷ñÿ+¢0´=„©òÅ ÛóäEÄãߟ~·Èc?$lqqØ¢F«ºTv¹Uãž¹F¡×Pu,Ž—ç'§}rH&ò‘â3„˜4Díúç¾Üi ©nŠIù|°:{Š Z;1=:›-½§Õ í­¹,ú[. P V!.wIôQ“ç y®UÖ\b?«;ÿ•ˆ- Õ›¾Î´Ò1ïàbºkËS«âŽ™GB07Ÿ|vú#œ„T#õªåcõòS ¼“ð-Òeã@‹ãâ‚/#±[¨‘Ñ(ë4¾8y^Ô¤øc¹N ^±®’Ì{dB¼Bsj-·ˆ’DL”•ËÃGÐÁe*å ¯Ûø¢ä¤*È"¸Å?@™xúkÎoLʽËoçóa*Õ@3vž"ŒÊ¼ŸÈc! "/ü¶ø¨‚˜"°þ *‘ˬñƒ½”‰µßÆ;>2€É7Jº¥Ém÷uc¾¼ú› nlææ3 ÇHIgFot R…+òjöÕ×4æØ!ô›©÷µÚÇs"áâ3ñ>^_¡ZÙ˜ýû¨Ì´[,$fÎWý®I5ó©X“*Lr.x;²jvÊ©u~cPÉå=Ê« ³¿|^™qqÿBE‰žÏ ±©«™Ô#S„nytAJjú%  ‘>|iˆ>]úüɆ¾>O§]>w<ûÏXõ´»ÇS8# 7­˜ÍãQz.ÂÝPx Üí]QÂ5ñ~!¹Ýº(9ê/" òë‚§ÿI£è‡ÑDR†zKìÂ#Z›éëáu•}}5™± À² ù¥S ´µI àñÖb°™£_fs÷­À”p‰BñÈó ÙžÙqobqxÑ)±ŒS»¡8Xæ5ì¿„ØÜÅGñíA”tQâöXíi¿îAÚU>VL­Ñª ­àI³ûä-„Ž?ÊÂa´NipïnPj"‹/P„D8¤œ%Íʧ“‹ùÞ ½ruüi˜ös]äõæÀå,Óf÷hÚíhɫ󺎗¯j @((6„€n&‹qð§:þÀy3­ µ°¼¸÷Œo"ë™ùú1®ˆ´æˆAǽiÿ&ḓy5âdĬ4û„’±ê0 ó»_£¹ŠýZÕÛwÅ(Ü|6WÆ_14Ð:ú6Ýx€M´­žý£áApºÍgÛDßÚû•Ÿ:‡æ©ØR é Ì_lÄrüŦ®ãÎ8ªóÀÒØ2õâZÁRÁDØü× N»+µ¸`Ÿ«²a§%p´ÞƒQ¼ëßõŠ>&'m`sx`_Ö,@Þž£o›’Qd(â.•ctß­^ÿu°Ç“Åx}xÊR>îšÔ#u=”øŽôÂü¹­dv bï;£aÍ6~øðê«5Æ?7"ÏM< ¢¿ë8±ÄÀ]ìiÎÒ×1ZX¦0æŽ#Oº®ÌÜ2µä‡î—0­¦F¹sJŽqzo±%‘$DÎ4T³3á3r8TC_ó-ŸôyûWô‰1lx.¹¡áሿŽÕ{#7‰%Æy²—Íi^…l­¼EŽ×¢oèâ±Á>äseŸ«hXêô„¥LT‡¯Ò^«ŸÔ£—ppÕ”ÆxíÝ x)ù`“;Xn‰î¶Á¡ÛܱtËÂi-dH˜¿ÀÙZĶËW‘w"×"Côš³nÜ‘ÿvŠäPtF²Ûøà¸•o…èÿs7Ò#XÝ„ÝÝGªÅ4Éh2+z’¥^ŒÌ}RZ†Ã½CYÉX%?7'#5Ð3§iþVåñzK‹C×ÖGæÒɺØXtïå²´'#þú\ïÊÀl7t>3S±TM› H:_M°vŸÌò,´ØT°²,qŒjžý†È±÷F”•sGÝ-ŒÖÆY¯è¸ÄþŒ¼ ;3·w„Ý, SOØÒšìË ¥“[~̼&Êÿm«òGÿ""LÀàïoµåµƒ[I¾àÖPÀ¹HYÃvÛ‡¯e‚#¾D3"TóÛ "!EŸB9+&d‡à‚ ލ4¡è×íUºF‘DCõ$Ó#Sƒ°‡÷At}.°ð¬A™6”lÕÌ–{p!ä¯;¥@CÂW1† àì® "{"«HPÔà)gQë$àò¨¥VÎ߯UÙÿñ·ÃS®[߬ŠfÇõàáΚ ýYÙ›‰ «™ò ’AèB!ãú&êÏ£ ³l‰S÷#¿BùäÅ¤ï ©ýò¥T4±C/ïv›³‰Ï;K»S à%UîÖÄc[¨´œW†` yò„ö\˜Öz§q´ {;œ{¢e¡Ñ8.nƒÓÝÚ¢XrˆŸŠè$D#d(düɽp¸hó^¿M3ÑmäPë(ðâʪTa¢jW_0M¢±½#(×µ\™ã–të¸ç)ÊŽ0v{E–ô;3S´1BÛ×í ×îê20?Ù“2&¹®Ü‘jiç`o®¬h¬Ñ}íS–í ü=Ž`NG­Ž§Ôž#Åyª§™á“.lT$-!ô³8 %-%\ö.·;ÃòÜŒY~÷¡ca‘é»ùS‰‘¯Ô´h„h˜`ľ–^ Q&÷(cÀãÿQî*/D¤F5”õ¡™ø¼ÿMú›cOÉaøT‹˜Hu£óòêEoëýëÅÏX:5ÎA#™ñßgÍØ¾«Q¬öÈ<·¾Ëw6Cl¡u¨Gñ3¿#™¬Þø×aÔ(ê=Z¨´¿¦H Ê È⣶ãÉyƒšŽ2çéSJ –Ïyì\Ù¹ÆÛ…Ó\n=L@MjjâwÌÓÀÝ7ÁéðÜÌÅN¤ïsKß;ÑM[1é?ê(#w¹¨jœ²ëù¦PàòIY}];ðÂ- Ӯīeù´éä®)]—0„ HÁõo-‹Œ)XQ„-A±?Ô4ßjQ®Õô¸ÉÊ&—¿SîËài]:¶š$²yùgRÿ5½$M¯Ò9Sž7ø}vëàÍWϧº cu2¬%`s¬m|À; y sY]õZmägtBÿ ìâ×°2É^RžfÄ_)©>ÔFò >2Ý>Y¦ÌŒ`ÆVE¤MàÓik‘ž¿õå¢Ï ¼k <Ìã2糃$ô¾ßQÐ,yW:¬@â8q]ÿH¢"”‡&×RRXØoù!¡«Ð,° oåzFj¾oUg•âlöÕiG0Ø¥Yd@ÉyS?ë[Âç‚T[Æ"DpnJš*ü ±ÆÕ°}9Æ+§þéd½·¥£ivŽ5óð½råîò?1q3žóÄ¡9PBœš,š"î#¬GIK‡ ‰MÎ…kÊ™ÃB–¾-ýTˆ)Üt•e[Rðóò<·ØÖµ. ¼  „á¤Ê³‹ÒpYcú&îhYn‹['ó)dˆ9tÜ/úùÆÉ´æDÛœÀaj9µq:æÈKßÎÃePKÓØ1Ðm3MqÇù:W€ã½æêCøÉ†¦D"òu{HtsÏÒߨ²!¥ÁF]Æe‘aê!j7}òκ9‡´9riî õD×Ð:¼$C•as Ѩ&“ëâ½á°Wu GlöR½ŠÜkÕl ~=½#ÏY] ÒÐFƒÛú¢•¿,Ðò¦‡ÂRûï¼å„;´‹Ò¶ûYDèA/‹þôbý 0Ï›)¦¸? ‹z Ʊ7–õg ”­„-‡øðÑþîmøz=¢~Oö^ï¾ôýÞü;o»Óü:áô÷ü=…ø}'a7áìëºá£ü>¶þøü>¤ß ÿI×Ïê;ølÿÖOð÷×áö{ï‡×;áö~´»¤þ ðúIø}Gü>žß¤?“µ_‡F»Ð_á¦ü=/½î¯{Ëë»áí½øzÊ놫ðô»ÏºïBþMøzjïAxð¯ù4†ºÍÖ{uŸÃÔ[ÖWÂÅðí?‡ª¿tþºü;?ºs~?Ãênü>™þðÿ¾ÿÖßðõ…ÝGðµø{ÓðôÏáôðê_‡¼ K¿…¯ÃéŸø{‡ðúi÷ÃÙ³½3¿åwAü6‡Ñ¿ÃéÇáì¯É¸o‡ÖÃswrî·øzKü>Šþ@7áíÏÃ×úïRÝgðµøz‹ðõ/áÒ¿Sþ¡ü=wpðV{®Mû°í¨­o>ô½_ïIû§oJuÓ{èïZ{ÒŸ½mï¤?½íߪûÝ5ï¾öÇ«ûÚ5¸úÐ÷¼?z?ßA?Þ·÷©:özï=¨÷·=îzOÞº÷Óºê½Ý:Ø÷]ýï{{÷©=éßÞ¢­ZÔ÷j¯p­ïvïu:÷êõðöÒõýëú HY÷‚J¦¸}ŠÃ±9øý"•¤Ó´Þéµ›êïs²0îÆ<²zlÕB}¯úº‡ìƒ£03êa»(Ä ×õ}êè†Û˜µ滹1î(èˆÚAX³4+º"„áÂz ºMUï» Ù[q‰Xéw)W¹a«jŠ3Pu܆îTÐýå<‘¯MQÞù(Фƒ¼!rYé<¸Í+Åܸ¡ùIÛJ›ƒ[ÙëWŸ&º±v™ulÍzô¥†1F>€Øå8âÕ××W¤O,…?'‡x.–¢U7rpTÛ±¸h”Ôkhc!×’ãÑÅi~嘘%{?¢ŒÞkrh¢¨{¬Ž.а˜‘sQ!jr;°²’âQë"íƒô¤;H΃aèc—õq» Œ´U1eÝv÷³8qµÕÂw¤ïª±Nû7HšbI*>ìÉáë¤aGUTh˜üµÙ˜èRí¤*ƒÍÍE T6_üòü@À£9RSò1“ Þ fcäáK\;¹Qܳ}ˆe”k¶î;öÎ\|‹3‚"í}ÄòÔ4ËK'¿ÿDÿ-š©ägìX´ék8§íRdÑ‹äÜþ ¥n¬Ê £¥IZC¯ hþýÍÖ·?õyªªß5»#ÿ[a^½R{–YÏ(ý„|4ÁÛëÇ\iá o®êÞ½`Ap'úQܧëɵ Ö ´t»ª%\ò2×åÇŒª¸ÆkÀX¾å=0å«WRKW*AÉ…E•'É5}¯·Sê%oÞ=h)zŸ õµ­ÓP?òjEÅFœç[šÅPÇ3Ï ze‚sn/T†« ÉeôšÅ”Ñz¥ÌâY„ËÔ¹çeCc²É?.®v¨“ñ¹\,þbݰª–Ì8ësÕˆ\Ž:›ª0_¿ñJÄ Nå©4Ê«l±7RН–Ï/†SØŠuL‹¥ A+½Á{)ŠŠU]mÜ]ÈX.¶ŠEC·a‹&ãØšuB¿óØsV‹(ú=p²ßét0Y5Âa`&5º{f‹!qJAQEˆÊv1z‚¨Ø¥uäBdìÈq{<¬Êš4§s±8–êu]‚ϪoÕOpf“âå¸lŽ)ÌØ©¤Ì=Iƒ`~R[^îÛø‡Ec)ø¶Ì9W]Ÿ»`RYä=TÏ.Eoe_ñ õ@kŸúÂi9®Ïo0P–l}=ÄbøÐ¾:°[S,us¯„§XôËáÃ4ñw •„*ëÂçRÕþ)µ¥,Œêÿ±š‰­ÆîwÞÓ“Whž¶)¾Ì.AÀ‰5äÒW,ÄÀ4¥Ûa¦¥årF#%Ù:7Á õk"ÌŒËáÙö‰ø¥Q0÷²N±ÛlœfP"vaY•…V½*q›ÍhÎnrg¨27,eYx(nÇyýå¿ÿÜVÁúÚ][K«iultûÚl±ÁZÿr¥»}b­B †¤”rQ8;¤”Ç͈Å6Ôã1>š7‡kåÿç¨ êÊÃô-¹>+ÓøÁ±ÃñX wãq–QA¬ÿ…š³€ Àã¾Ý.KÇӓ578-jAÊÕ‚ô›ñ/ˆ1?[‚èwÖ—Ü/„ÉýMFâï<ÁaFúF1wËÓ4r‰Ì]â½("– £>¾t†ôØH‡:'jívÝÛÏ%!,Ùjû?®|.¯îƒªM+ „çtSK·^|ÝTu*…j «>#g¾…î»Y`‡e DŸêMsY7¢¬%íg%1ÖnbçÝHnbÓñJZ¨Æê3o£tiØNðƒº×ÎI]n¥Oño= ;ªµº×ýÅ¥×JkýmC"n>C~R º„®~£+u3J¾ªÔ+½ÅÂ)#!"5HgÞZZäUa7YÁä`ûÚ'aõtþÿJ[3_ºå¯˜Œòƒ4ÿº’ OMðàSZ¼LsF šÆLu ÷ rÔÏÍy€I^¯ôààC·gâPµÛ 'õ½Áãç›Â(;Bs‹&Ñm{åV±‚š;š„V fŸ•ãàëãõ¡zСÇü©z®TzöÏ1•ÊUÇm7 |Cˆu(IªˆVÖE÷b17?ÙfÜGjepIø bÓa`Ašóí¶Æk ½§gNÈFÝ ¦ +z‹œÛÉñúy~ó¿U.zdľcFÉоa)ó÷²ls ”ñ‚9ó>›Â+µñ?²š!ó.a×ËFI|[l7¨Áܬåòê@óöpB…(’ŒZ=™Ýò ØY6ZõŸÒ§\lTfÈ©qÉÊkuФâ§+BºøìFnJø.“P½¹µ¡¦¯cÁ,çj]pàV˜µn¶Â0Å«z“ëÑœÙðmšmì+h Q¾S™‡Ë+èCDmV5>&å )¸Næs‘?ÌȳçýÂ08ÑÔ“ÌA )ïäÿHäY¶s^ûî­#áäß S–= Í9¨ßµ¢.¯x+‹†Ý>Ü?bÌ)Z*êÅn×{óFŸðáùŽ¡yž†ÈR»>%t¥Õó¸)—˜ÎjGzm:²æÑìµõ¿Þ¢6Ç7o ô€\Œsœfñ)Qˆ,z\tŠxiô,ü9àó±mß°÷§¶ŒLqdcƒhêE ‚Á¨%«;¡ý•*fu@D„Ëp±!¤,9íìý"zÍÂ{‚˜éQHW]ÒJ›ÏÎu-®Äø€„!Ù|–­ó½}¾¡à³|ѰqŠË®‹X…¶ÎаÉ%î+ïƒ9hRL6;”(ÓD)Ƴübp´®Sø’ìúÒÄî—uo.–¼9è,l5ï•f™¦D êæ!p—o‹ fÖnÝhñz@ø§À;Ê,Écê³C+¶égŽmºQÝ«¡¼henÈüÄo“‡é!²“2“gôè³ï°çÊ—ÎØŒà-ÄùôS(òÌs²ä´±{©¨ %· ¢uú æõBóù8žîÊy*)sµ æA˜5ÏõÆÊ@œD]ßvãÚÍ<Õ¿*-TÈ…ðèûxrŽ:j^ ÷‰__ß@eç“p¬óEù¨9¯ôΛM lãh5Ñ%V–±ãvr/h3ø2ãHÄÔ52±pjÔ†´É3“ñuätP³¬ëè,†Àß°ù¶Xp'KÓD=ú{ØÅYqŽ¿ùŠw$,mÐùårŒ7*2Ísåì$³E?ýáQ¯Ð-——‹,ï,À_˜6 Ñž¸Ì×#`£!R4ð¸á{±¬º&¯ß­aÕúž"0ûc$à‡lÕªÅqº—2LÑï~ý—%#ù²™pí%‚³<ƒÊ"»ú¼…v³´4^Há_Ò蜽q"j]ˆk@'ŠT'FN™¨y+/Ù¼zq¬{™-óÂ-¸¾š¹¨™„÷ II>#yl6ó >57/ÍÙòæá”~ï½ÆÛHä¬kï,ͬ¢25d ’ê_]s15(ñ.? fVQŠ"þ[ìšå¸ Áù%¼}XC7.–õ°ó¹±ó •a}Õ‡Ù§ðŽû+˜eUñÃ5Ï£3û¡ä—Síù¬e DTF›UØÌxÏ–ã†W‰Z+s=L_²ç(O~dzü\•tö×)¯Ã7œ\Ÿþ Ö#ÌÝŸY®ÜFy´ 7€W{=Rè†ÝI§ÅÚ ÝîÍ:€ŽP¼uI?ñ{l™•®·…}S±åÆFôø!LP¿ùØ=Lß7{a­> „á¯E¡¯¼HÐDs-ë™2ùº¶dÅ-MÓê Úÿ†ßH¯ï­#Ë“XÕž˜žäqwÔìñçÛøsĤÖ;a Ø#QQ7£/«:2ÂÕ; hcIîE‘ šn’¡ãE/|±ÜC‘‡³_ݺ-Gß8ǹì>_§N ;j—š oÜp’eŽÝaFqn¦¹pÓÿ.: tX/6¹ ¿K¡ã׿ æü%¸ù}¯§Õz\]í®nc‚%<œâS¥ 6ñÀrHQ× 3qRޤˆ ±ÔÍñ{çòñPK›Œa,=JÈ<`øô|ƒ8ÜsÈ|%I´Z—Æè cŦûR®BÀ{[‡»Æûófª„ù¢“j­ˆÿƒ³™òÆ=^¹_?i$EGµ¦Që!ÎγÖÐ…’ ¨Ð¾’iItÞ9æA€7ô&Ù‚7ZmѸ8‰TðM®l/^ãÔ=ÐáF–ΫÛÖlå6*1év£3Œæ3­¿ÿju‰2ìY9«Ô†ÿ~±Ô[ï‘*Õî VÏùY«÷Mfx!]ß—íÊ l^û6w£yª\:IÝ?¿ÿwÐàfC×@Ÿ"'Í£÷qþÑ+J5áQÌðÿ~MMª¹CøËQ¡Ä·Qâ÷î8È—0;0; Ézõ~Fš@àèÆ;¾Q’ï”d»i(¤+IÎ-?õ'…/Ô2uN+˜Àg!D³Ý´ÛNÉœ¨GÛ"¶Ñˆ«A›:táp;*+üM2À +R½<¦)ïÐaÓ¢Õì~-~S:3 ÇQCjrA¦ÛõÓA¥FIUö¨õ°ë‚éýÕЄ°…ìG_|^¥éÿ@¦àÉbµç>ÌÜíÝ¿õ )oåŒq!Ô#mËôb›â„,ð1‘ÕÊ+¹“ ¬Mþe›ãiÕ(w¡ÏÙiD)Ÿ=ÕàÐzz5 –¾FDrHWFnÓ׈ËÞŽ$:0óD/…D‚²aœ¶Õº†Ôô;[Oñ>@«ùâÖ¯{ ¦ìPùuI‡UË/,õíChç¼f´Šeè'Sïã:tŒ$¨ŸýQ1Ï·vµïè“*íŠ >GG¨ˆ³„j‰^€˜ß»äçŸE Võ×øLJYù˜ „¼×Á«ÍznrÔ{ùŠ+YA¬ZÝa©õà¸Ä¨ôôüªÞme_W¼k§ö]¡Ïøî|Í'B@ÄÄò›¦ÿR,³æSP€¤´ÃÅ4É‘óx;]¬¸oÆJ@çÇÁvŒÐÆp±Ʀ± žw¹1ÎO 5§ü“^Óxì½Ñ¸ÊÞ2ÖJRœYïf3 ‚‡^–÷zê3ÐS0u¡Z븀xp&‰?µ‘Ϥm2n20 ,óM2ÍCíI p;kPè †ƒD„|(™ˆöÎð¨aìœ){-ÃÍÿc¥`¡*CÓ]ìÈž§Csý†T  q)WÔænÄ9z4{}y¹-¡N a<‚Ö]˜òCxS¼§#󿉲´úüoÛ £xùv<‘¿âOÊÁÍé&^©ç÷\-½UJiæѤÀYCªó¬Àµ[;U˜…¢â±­n£ñ›€ôв§zA^öybœÈ¡Z¾@é:£¯Y«¬ ^ Œ˜S«æÙUÜ•ƒ ²4†lñY>‰¬åëÍó*†2,¾/÷SõDzP±8ÚUš¯ûJï]ÿv%}ÙÑÇÊÖ`Œf 7qÌúÿny— ¹ÆiÔ/|{=I;¶±^ç.î& c6ƒº×'ŸÿÚœ)ö**+×ÿª±N {÷‘Nk|‰a5` 2J¹5 îÁW–­[¶.Ö…û,´ÙŠ Š \˜ó?µŸ©u$ðÿ?7†¯@äYÆF“áŒý©ÎÓJl¢g4Óß·0¡þø~™3΃*Éù:VL"©ýàɇRÝJÄ\úuáèøaSMßPMÈâ(TR©³±Õßë qÕ¦7§ì6ZõI"»(¦ûŸ ƒ -C‡c°+þâ/MÃ5£°ƒ5·¤ÒÙ[[·_lîË$‘¸ãÀ´h§ …Ö£¦w6Ô_3¹ôO{¤Z=q§‡À?CKMåýcˆ§1Eí–¨‰tÊ®Îá}#1¯=«gZDºÒ›uѯƒó¸Œ+w£þº ÞIßù{.mŠ›ÉãF»ax£aòsç¾l¥DQ‘~¿}\Ññ{ôÏÓ‘ñ‡¶p8Ÿ™ È…T' Ä>ËE²;¸Û:‹ŽÎÿNQT5(Àµe¬Ñ/Ô|‰<Âó¸ip¾a„À/ÿ¼DÞ#®7ŸEýKÝvÈÂòøÍ˜a1„!í~õVI‚*Dfý-GNˆ\–¡ú<¶†MÖ„Y;7d) â ë¨›xŸ |®aÞsÎ' zT¥`¸å¶È¡U¬ö³Wò,taÜ÷>¹óq> O€ù1ÀþÕç‰ô‘›Í|Ÿ÷×Éÿ8æ¾0|nîLjDÍ$ì‘áãÞ!̈1€§¡Ñ?àŒÞ“›œ…½¡ê.y•:CRû˜_H’ÊßûŽõËNÕ6<þtY;¶XöS@ß§/+éLdU/+ãZ+©†4‘3¨ÄÊ“¤G»½Ö¡ÐQ¶œ±N8߇¯?ÿ 7Ƨۣp£8vAž?Cæ­wÓRI`ejïªu\Q)¢ä%ü…ŠaŒg–‚ªín¼‘ïM°y&ç¿3t½u„2ƒ?æ²gÏ<€öîiš7(¯´£/ð¬ έ li>»înú[ɦÐ<’=†º‘Aó)0]Hú‘B Æå­|Pˆ¦g..t¶ž©*žY¡œ7a«ýŠÇ U¤d{‹ ÐvTàæˆVVžÛEó<Â~jÖv ¯·Ê¾>…8 ¡)‹²°)$2­7ÌZ$¯Ï‚gouH2È!Cëû7˜Ëö·xHÍëè¼-Ýk …M8åµmIgóªQµÙÁ@žõ7LC¢Pð¸x£ø{©úTöÃÛN½BœÊí–jé¡€Ÿ|ÌÃ~jáö¿5‡}‡˜bâ§§Ð ±[:” ¿Ó_ŠFž_½0ëË*wkòÑÓ"T&¤)·Šnнà'89ì§à²˜»´‘¡ÇQèÀ.Ô%0\Õ›®ƒÑ2veªHâÝìxxŽ;LªN›'eéZˆE3E-·ô â+ç±µÔѬ\Eð§/Z&Þ`àíÇpÜ>*ì8v& Dãúµ“ñù|¼é.-*}Ó°Ó~ó1ê”gÝ‘Üo e韞GàÙ„&Ì¡ï 1鄨 þü¹—A5yˉn޾³}KÔnƒ,¾ô¸Xúw,Cë²²m`t,­`U™†Äº_˜0·L¨šjÍ´Ï©ß!E-ká',4÷V¢f¦xÌÚNàÇ` SŸïë—NšQû vB˜)^¾tpjR<Ú‡84—ÆNéî9C¼‡J[I ÿR¸ÎËkWèÔR™C:Qæ gb­MäØËælP*Õ06_rhè¬,m§þ¸áè”ë£ÍÄ"RqŠè`ˆ1øÝäEïTÃÛñìø1 2›f=ÜH9l(6 r–¬ ªXí­qÉ»g3eù{pŽÆ}#¯ò ú»Þ(Ì® !Âô𸿠·Š7CcÞá«-©qïýR–¥°K¿f‘ø“ùOµ±ˆ!;Ξçb¸ ˆèbUÚ¥óµ=ÍG‹P]DЛˆøÉÞƒ…¸b"F¤XŽƒqåÚx¡Î¨´©ä‹<¾„>× d?µÂ3†öZ–ÀÛ¿ÁÒ eI3=øfðºšÃÖ†mÀI¡¸ÛoûöM 5ë\­¯ƒ‰„šxUúOü[v¬‚Γõ§^™&§±¬íG Ífù°è%^ÁLÒ–¯k­ÝÂq6Ë ‡0×eÛE‡ü¶,ƒ>óñŒ%²#¾H¾ DâJXwܘo+ÚDß<¥®|œ L΄ï)ÄÛ,×‹ÈØP Îk/ŒÑcbPïmzm cÿ±g?Â^×z %ÿR4Žó€.)´£u÷ð¢T†NǹX¿{kZíyûŒÁâ‘ù¬Ü^?”/Ÿx‰&¬{Ï.qõR0.*®:%Ú„ÊØ!†?A°#›%mOäêJÜÿnS=q¢Óî•mµ•÷C—Ø{Âð#À`ÅÔ-P‘ÝCžÀN÷QÜÛÒD›Ý•ÝÕ¸W·#¸Æ+TIr?Ä@gÔ9w7YG½€{´Bîñ4 ’Ãå4X?Èû@/ oÒaìw ¬gŠ.¬òwùÔpNƒ÷¬óòö^,4K<ÓïŒrÄ~®ðÛY5h‚øF»u•ïè€m†?ç%ë½ïiv()ÉFâ‘¹Š²j?›ÏødB`+èêž SÈÍ´ÿ}øM'ßá¤*ÁQÈ;’@© @°—oÚ[+±7R”Šè(üÒœaÚ¯ØXßXÓáL—&öœ¦;µ^¼Ÿ)h?nD%fY…D‹¡·à5Ú¿¼ï~Ämt.˜?1M2'qzH²v4 §¡Õi¬Fdî8Œ š¡õVN}ÎÛKý1ó—á zD¨Ñ) ÃK;ªqñå÷ß“:O=ÝÞ c³]ƒ%xP²ÇÂÐcXâT°)]ç5ZºœÃ×Wµ3i@gZ†ÔZæCÛ„Ž¥QÙâd‘ÈYåö@<ƒÔWzˆƒ¡2i"DϪæÌѨ@F>HøÖÝÕÜå 0-çI"*èa„SMÚ²ÿIz÷­ F¦,DÙJ£ZžâsEe“üG}8\w[Ä—À¥„Ô¢ïÏváœenCä)ÎÄÍ–SRÔÕO ß;¹¯2,«9g¹‘XöºðGÑØTˆÌ¥†Ëd¨Y$ʱTšqÇ`X»¦wÿ$.y@e-xJ\¶,#ÄpßmÃÊÓÇ|Â᜘r¼‰Gz…pDªr€R^,×Ìh+s‘´ü[>DµM¨ï±-̸SդߑEä!Ùh|•KjØJ1(8ߥÇôõ¢ýHòг’ßýçÚ·|§TèL÷à)çuð³Ë®œ—\"—†N°?ÃĈ¸[–ÌUNÑ =YTËäʃÂLÁH¥'A©nœqÍ÷º4r蹺 BFœ[ÓD/žY¸Ùa`CîóeRµÊåøB–×.ÝTŸèð}’%s(ª¬sê’Š!âc%x}¾K}Êz급.5J2£d‘PHmÖ¸ÄR~>S@”/E Ê’BŽû@TRªð[ UÊ}hV]APâ¯ÆXNÌœVô˜#ûžì…a³Ü…´ã¬JÈžéc‹B™jôÈQBW­J¢à¬—™•´íßËEzªy{†ÿ¥á«ŸøG6Œš¿sÄ`Ñ䢽¬Ñõ)ì |) ¸e-vœŒÞ꯭úÚî®´áóû“!8.Ÿ ýùkïé“̉2¼éº‰¬£¦W7|tÿ\´ÐBþàh #èO´î¼Ñp<ú*ÌV»ß­b§÷™‰ú¶$K¯F€ ŒÐ™ú±a4๻ÒeGíš4wÿýÖ„Ô˓旺MÆs%é°i˜I‹&I‚rÖèÓ?‡þjb‰C¾3¡‚ë¢ÙJtû„ú9DvÔI:»’+2†cƒû†,6yJUˆ,‹8¶*O2r|†fèfýϰY£öøÑw% «!¬ÿ-Jþz‹Ü½1;=Úq«”-+.2-pþ0ä•:ÒU©þ+–ù&ålºV¼×´Éœ+¯öºÝÐ c_ŒT I€"ÅñüQ£5ãÔ'$÷ý€ÀL¸Í EFŸèƒihÀœÚýà Wª±«‹ÿ]m߉¹\C€‡ cvçîfzc8‡ÕÿU‘þzî7BÍñùN)–,õÞKÿu °VÔÆò—iuì|¼Ë›>°–ö%fЛ²´Ðœ':5¸œÝ]™÷ Lš6]üô–‚2´à9”ûÔ²ç¢6Ð4˜´Ÿ™åº¯d1„·,èßæ?4»í|ø´!TmAU—à. et6Óè›…-gw„¼ûØ{Ü[)¾n,u&Cã¯ý+±U#1M¾T®c †å{à£3:ŨmA% oÇÉæ F~Z]×~ôÅ”Mí€XáiÁ­4Bˇ`ZÚ½ºâÒ]¦U¥%n®=J»©8σyõ–ï!ýxüÀµtÈÆ&Cw.ðo/E¦Ë°Áè%RY'q§1”),,$$@>js±U™ë÷Žž¬ÎQW®<7)Vý“1PÅ™ÄDNHòžŸÄ‚콺¸É*ßÕjTbtˀȴ§ý…nŸf°<ì`®®Ê¯¬n¸3ÛŒxò°gªpMMLÔG_ãh)=Ч<ÔVZPÔ—™¦1ndˆƒú¾¼‘æë ÔV¢±ŒÂš7g-jàY¦%Áñ´í€¹!{Ó»wÎ]ÅBΉxG´lvé—HB°tÑk´À’õ•Îñy ö„8²¬hgÖŒ¥åbŽÄó?Sò _:R—C ½Ëü®IUpÉá}† çvliç Õó9+’š,jú×;9©pfòXùž”oÐf8•„‘]Jjæ‹ÈõòPÜþÑŸ¿Â¼4KÎ^oß:ƒ'Ì­6U~;nøÑzϬ¨&ÅkçxQC>eÿP *ˆc¾¹žj”}¹–ÝÇ÷×ñÒ¼íbtÀ–áT/–¢Ë<²^…j©s»[ñÒ¡ŸN÷Æa%$ÀÀ‹ä–‘ [Ñ eoa4ª³S Î0¥oˆ0>Qp" à7Ü€S»cD Ôæiik6`Å~…šYc«@úŽDç¼áÈ-ÀáÜé‹SkÂÖ¥ö\–),ÖçÜpúNaçÍõ°çÞŸhì俼Aƒÿ¦íñÍt¢(Òƒaiðû"t£­p–«Øpâš·XÜn/§Bîxâ>wÏ¡tCÄö^ÛŠ?.D¨ ˜QÒ.´õÅPue}qm‘ºä˼ֲ!"œ_C {+k9¼MîMJNýgV¸¢Å¾Ô>~Ñ/©UæQÆ.Ëp‹ ˺Ӣ«/Ãì qgªJLûA¥X‘o ×ï¡¥ØÅÆ“¡âsžëc2aÁn[5Ao,øE¶³²žrR/”µ! m…‡~œ¶SfVÞj#nØÞÅ5¥ë.ÿq¥çøX%9uŒí¿š¼±:é¥rå¢Ò_ æã­Û>ìJÓýž|,Œ#«„“gc\Ä?ßÚ…ûÐ˳má:DЩĬ³_†$†_¨ÚUŒv>.\`Á1/?Ç>a—Y{»7ËÏ%™ËDÝHZ°¢²ÿ"GN&NZ¿1‰FpgÓEfÏ?n›QVÑ9ªV A©ú¥ëÂÃ$M‘àE6Èuœž%èFíƒqyˆg½ÆD–5Òj öç9­»–ñˆl˜´ú©\T¢˜È9Oë "}²PÜœýf?Á.aØ,|•¯ÌUUsŠöVø­òN²J24hÇ´/Š:ç‰Ä9$?êb›¤ÆË#.Óž8I‚'\¯öoѧÞÎ"#‡ÏYTÝ›³É@ÿyŠSíмJ˜gVµH‹ñ.y@øÑhiî)¿Á8_†èxͤÆlc­¬>ÍäBXï±íˆz¡Þ2Uxl  pÍ¢bÁ‡vZ×Ù \ñ$PäOBƒ‰§#t'€©Ü!I?íe?Cèÿq«ÿW‰» ž® 8‚ó;hHIö8Ú¬Âþ Ö9Er†kuÅß"ëÖìÁ™5BrœüEŽ_碤©ù'ÙÝ3 ({¾÷+1_·ñ¡TÄÊÍmÇvoré€aü—Ìm&’üøÐ ‰ë@ÏS}Š„ò‘;¸fo”Ñ×ñ™øz©jcÓ£ó èSGýâØµb96¿¡êN¬7d0Dm”™ãˆMeä  /Ä¡·S1?ï×${m:ž_Ëóðs6vTG¤>.0N»Wy»«Œ,.xf& d¬tù+.çÿg.Û¢¡ƒ¹ðo¨Cßu44# ÁdÃ6!8×›˜•¼B-¤6ó'$7úèŽÊ©–}_RpgMX þùãrB‰Š ÿ'þèR›é[²~MKu^~x´Iž…mÁ$3:¬O6žµ·Š™ýÕþ°÷P1“Û³‡çv³(βÛ4CXM¦¾¤¬âRÁÊ5á‚FS¡dP˜Îºƒ¾IniâÝ qñÕ™õ=¤…ß|TÜý®ÔL®/dÏuµÎ^·°åùJ݉|p”PV¼«ªo£Ñþ¿óTé“GCËÌŒrnæ3P•r¯£y“d‚M¡êm(_úXrꑜñÿÀa@²Ýð»ÚmCÙÊÌK8:4wêž–0O¶ü¦ qM žˆ V‡"ÙwWÇ[Œè#¹ðì,ÝÅóNÅ, [ÌR¥û´ç°×Ób@o/(P;RZ(ŽEÝÅ„-á»ÿ%W¨1áPzÌ8úP/z‡Dp®<4oå]‹õ­Ùݬ´ѽúö—Kx’(¦kÀô¥L¨ªŒë­*¾¼ÉXi~r§CÉ K æ™+ÖÕÈÐbGi‹‰T$ÌGܼôÆŸFZ}Í›Õho[:9m°)¾Bdz@œ‹_Ù ¸Ap⎇“ÝÑQ;z5-p‚'ÈŠ§$Q¼€DV­…ÈŽ‡_#‘P6£þ¶A£®ì¿ÝÁ@ò¾‚¾þ½—‘­èfà $%ÿÝÁ@ò¾‚¾þ½—‘­èfà $%ÿÝÁ@ò¾‚¾þ½—‘­èfà $%ÿà“ö>Pš[Óõ¶áëd$fü¸ž(ôënÀ‰Äðvêò|ÈJTz0—Û2ï¨xCgìÌ?·tí™Ø’ìß­íò`5‰jgÕ™ {ÎfáH˳›%š¥@Ùú9 –^ù6ÎA$L5›˜Ûäq¾,4OíÅâsÖF{ˆ #âÚó—´~‚,¨³è ˆõÕnC¿‚ôŠÀúíýóæØàó|2S¸"œpÆ¿o;om«Sˆ$¤oÔðïÅä(êµzœXHb0јIã±Ôøsëêì9ë´›Fîl`\Ë™èðSиÿk êöÂ2þi¶â`Ϻ ä<ñôí¤7é7ñg!¿ûÞMï’ÀVNóN'’’I$Ž;ÿ`Í%ê&/ºF¼Œ:]»íz-H/ã8âÞ4ßô~ Gü9@þ/í£MÚ&í«Âñ0Etef«á@ñùa¹hꉦVLì:fyMœB­…™;庂»©ù¢ÙMÙ‡ˆXê‘õ¶ÊøAÓ‘3$8ƽôµAÁ­ÔËyÞÞÜíV‰CÏM»d;Ƈi䣽µËB]œ¿WÌý5ëØãsPf$¬ÆITlH")fùåþ_¹èNŸå‰úÇæ)ñ•´ç¢[w—á÷? Û/¶Ö™Ø_¹ódrÀòwÁ®âg{#¯üðyò‡áãÝ/Z¦ýz|•¨E­ÿxŸa¥Udö«Â‘Æ©fÜYÈÜ[åœv.­¡,ÿ7®;Ñ16Ðyèª~C…µÞf+µÖÝiƒša™îÆôfáØ. H¦Ršd6\=ûÙCQ4³±Ì¶ÿjx$¤ˆm:Ø?@¬>#óñ·Ô‚ •½ænȨ‘µuÜ1ªÅ;B F®+¤NËKÞ^Wžs­Gx\qQ ¦ÉùÔe¦…™²±ýD7-KŠ$ËïÖÙ—ó¡ Ëa6Zr×K£Á팮Åü’#GÓõ€ˆðÃZ½B‚c~ùÁæÄ½Ö4¸|XŽÏxÿP³ ÄSè–d…šæ™PÉ>Ò¢Þæl¯½ÆCâ/5@3꺎é çæŠ!êniŒÓÈ'c²® $íœóÜbßI% R@Sóú’¸Å¡Ð„ lò³)ØJâÕ;îÓŒ\ *bâü±óèÓFI!Ñ£ Ø᫯¼FLMBîÄÌ6C‡_¢£45…¿C²‚þ¬%ëW,i„yÿ-ÜìkqË$YCÜõ›ÈÛ‘^l—µ—_¸U+}ÑÎ{œ|ȨкKeÆö5˜9Þ{Þ Û’I$’I$’HÙÞÎ<ÜQ—ŽÈÙ;;6¼[õš¸ „8ë¾`ÂÈñÏ|j „ŸÔÙÉ SÂvk†öF0´ª*K–c„]\jûîX,yÎòªÖbXâUÿ~í£#ÿ+$Y(¼}o@‘²¯2 }M[¿¸qáŠI/w£ARÅõ"¢´_FÅ×¹êøŒ=>} Ð<Ô1-G.*¨ÔüðMNrym€ë•+ÉTïGÇúæ¬S Íb\î 2øfõ#¯ýF…Ù¾%ìu¨ãNbdñ`Qt4Î ¬Õ’Ú/î®…|·cLÞEzÎ ·"ŸŽÄ?A¾Ão8([DÚ ˆ½ß@BÅÔ4ºh4á^÷x# •ˆ{Ð"c +÷ô3ZÚ×&kÔ~•´ÛR½-~S7Ü,cõ{êQX«Ë2—´åŠbé2Òä\b14J2$$9ì¢Ú03¾Þ½k®6âš?žÓ™´©bú—$™Oœ©•D$LïÔ³DƒEegðhÊWµ~­DFe­½ê±i˜MpSŽœ,½õçy láG•ÈÊ”ÌÀt‘±w÷^¿ç(ªÃÐéðª¿SåvsuÉØ¿mTKœÁÛJæ=¬‰Þ¼ïÏbÖN~ß³‰'Áš7_ ÷hÌoarú hzC–¾Sר JN 8có".»ËÔ<1Õ|.j¼àΓ Â…õ¸Ç2˜ãäÞW¥z4ØûEtJ2(.µ+?We?¦! ¤Ô¢ÿq«¹©â9µWFΓœIlí$¶­^|úÒpy÷â†ÕDïPb;WühÍIÄ myU…‰÷ _ÊòÁ#ÜÊ£B²wþVº_¢ESЇ“”¢JëQ&¸ŒqPªgQ£ Ú¦éø!ù@íÌÜ‘ãeýŸÿG,ÜŒ¹Ù̾Dó¾±áž‹„s  µ¸£Îs6²'#Û\‹Å¼Ô*íùÔ½å~Ë E½o 2Vt³å–H]„ÎA)Oi!¨ŒÄµm©¯äö*ú|:b—»|ߪñëJ×·Mfÿ1›Ý‡Cô¡„^ ŒS€óª°Fy® B8"mÔºÀ›½[\0SB®Ž ¦âüöÈÜgp¤pN-kžqéÞºw™ê{}/)ß÷uOä«W<£Ö[fß\{ï•f`·æ" Ñm‚¤±7!I™é™ñ¢åSÈ^ ¯¼Tìù2æNSŽéá‚fóE±XlŽ{¾rWùt­eÝðõ²gýšá—Ë%ÑûÈ“°<ÉÄ |ÒÞ×磂ÿ'JNìvç´¬–)¶"­p2èèJ<+•cþ¨èø^»}Õ»†ÊTÕÒO¡¡ë cvÊÔ:îLq c WÒPëTà–¢“ú"Š ÝyNÎW/UÁÖÏ®"KÖÍÙ§¼OõT¶ü´¶"ñˆd iP«P‰&\§µª  š^%ßîý|´ÀØKÃpo|réyà R‰^TÅ-PRi%9jbåú3xfGÈ]‰¬®ÂoÖúèã£M©Å$$¥ðT…) óðU1Û²îÛZU53rf–Ç*‰¨ªd¤´¯¸B>Ž•&²‚Pòá(n_T|Ö Êiî|œb lÚƒiUçª3ëU=ȇj¯ÛVµîÏëIù3 ¦~§´Rð–ìŽ;©Uá¡1Ð:$z¯4¤wZ¨f"4}À®w;-c÷²Xçï•}^–k,ÝБû‡U„ãÅ ƒ»0I†W"x˜j<5.ÃôQ0¹™.(ð£ZË’ÒLâùûSŒÿiD< ‘/¥®„Þ8uÏâÓE6#Ã$võ9lIOì`%.²C[×'QRá þ:¦«.8kH$wƒZ/èð}#JÎrkŸ² 'ãvŽuŒáÍÝ.‘}t‡?2 cR5}DLªø›t›gh3eÚòÌ‚£6V§³g„Rzn]è OTmñ~Âêqw‹`P/ý·XÌË{AŸ¢éYTN„AEBû WV6hÛé5ÌD™jûpnÀ_Мª†ë ÿk}Tm“á*4'2šÔöŠË"@þ‰@çqŠh#W+µ6”½bd|EÇCí…(A»±& —ƒYÚ\Ì»n/‚É—m†å³"Loúß3¡€DÖ{(nÿÊíš·iðˆƒï[1Ögá8HnÕaö"ó¦mfÂÍËÕ Ün>0³*†rgß&™œbÕT€HKö±!B $%ô,§iшÐüq(iœ@c žÜÜ{±ê/a"~þ*˜4p²ƒÑaí6=Ä §c¯¿…°(ÝṘ)­b#ƒ¡Þ>‹­ªìœÂÆMš{ã™ãÊø²%;5èÅ`¼Ê‡ç|9Þ½h ó íó¦)'‹=+~jÑâIõ.Sˆ&yœOa™QY¼ÅNÀ €ú’*ÚüjbO¹ü0u ö€õ°È‹$ˆºØ­Ä­ÕÊÚ’l'×¾=n,Ä”£G2Kz‡•ñ ~9î‘!þ|Äg–$B¢7n3 k¸ƒ3Rý‹–ö¡Âðò;†|1øâµæš|%¡d+7ó…mèxEe“@Ê2,—|R³ìSfíͨ¨ð:SÅ›šZÚÉ?@ï˺{áQ´ùg„ ÁέÕÒÔ -ß?â{åòŒ­#+hr7V²îž‘rÛ—’—%¥±áE›éûΨR#X‡g¯é 9.Ôå v*+—PÛâ…¯hþÿvÈï®kR—e[?V…Þ¦ÌF¤ù•Üwd©ûÖ5²ÂáƒMkDž<³L¯Š( šg_mgdSû$Ö4û‹Ù 1>Q­” ·ï €w?½ð#ȼŸ{$Ç~„*gõëd(½+ð¤“AÔ4ï¨"ñ—4Œ€蹃mðÖíÓ–‘§Ámz’j8Éx3*òaÀé#¤§£VNb²$¸²`ÛŒ×Ð"TÉ(CÀUqºµÐ¡¢árÐWœ'1GlìE?­Sxη¤%6‹{D·5êB£EÜÒ#ö›†b®30¦y8žT¡™ p]Q­ö¡¯—Ë2À\æ>õM  )ÿRÀÓG„òL¡iP¹a2éV³‚õ+!r¯l+?È:¤íi%û˜;Ïv7x-wÏ('øUÎ=>ÔDýÉ©ä†Ö åZžýî%–·!’ñ4p#z)ñÓž»»M‡Â§É!âxýiE A/âįŽ5ŒÊ×ÿÕ)ÎÒQˆSª÷ÐQ¦¾’ä9Éå<§ã0Ã?+®vj°%[# • ·T\ÁL¡@ç pD2SËêÂ0‡–ÐՌ̙£\ÄÀß7$Q^®I ?P|Zˆ3r>  ×;ælu¶Ç ²±$Á°Å•1U:ËÌ”TÕÎɸ57|ÓFâ6‰öÜHDóý¼WhŠßH¿ãVè Ë몺ìt ÉÖ¯"N÷ú-KæáÖÖꪆWý¡3£Óë²æ¡œ¶J¬åÖxœ†Ùi¿Ìû…B²zPá½Vˆžf…Õ?v{3P02]³‹‡i+¯åÎm¢Óš\î®¶ð …ãòé‘.E4'IV‘£%Yøna\RÆú¼¸fž&ɬĵýe ÙEÔMÞ™…ãÅóZ}/ÐÑù”<Ǧ%šIó‰íÇDüù)h/ˆ‰¨ž[í8s©uZ1h†úì:C-‹=5šÅ›½éëê"àhÓîþÖ¶¥fÓüªèÎOvKdéÚu‚Óâ-+ƒBu ·‚wÔáàD#x´lH䉶\xõ@§ïÁóßq¶q¢>aÀåJ2]ÆZÆL,¡7’Ï}ü–1fº¨ØÀF1!ÿ>uõ?(A0YýÍîGeû¦­©‰ uâ 'IŠŒ7KAÍã«4ó£oþðß1í‹áÀ|¸Ü_²(],Þ¹ÏôoÚf;’BnQÔ0F  $9MøM†žÿ9ÿ3ŒkÂKŒ¼´Òøà;+`7øà€‰ª%y`Ó}"p84²¯«™Ã±µtA?µßA7 Kô÷ð‡šÖ›sÝY&W=ÅÆ˯£Ô{Í„ˆ¨G8ÿ"Âà„K¹ø Þp_åÒüp§·5ï¦ÿ#Í|uýw56úPÍ®½A ‘z}< hφЦyÖ·2òÁýUÿÃ# ¸S_òjø$.ô…®/ȉÂêbÒ¼_‡7 ¸9Ñ»´½OóÌ2±Â´ÈØT.×ÎÅë—xHøSx¢í»9‹ ò½*ø”Wz ?D±#sßþpC\J`ËSj1ÒCIþk߃-Ù$“üEj­Æ˜5³,{ º/am ßæ¢¥ðœfÏsä \“‘]"­–ñOD8ÎTþ„=o3ã¬XpŠ6 ùç‹ÿ¶—‚üm ‡Z7?GÅÆCõSE´3æ•»ýÚkÌà?…'èúì2åùÚùØŸ'\̤ñ4dÔ4ÔO†´C£2宎Sç­Ió¶éÑvðfŽÝdÇ<ÐWÍ?îcÙÚ(< øáf¡†…?æÿ6%ÎÑ}èxgÚÒðÀ Û7ÏëNÇ’^2#‘iùöWÝtTqokai÷YÒLÚŽÀ|¢xb›åß?Då ÙôCžÞrƒÊàÏ3¥Çaõ¹=Yß $^IN4bçúo²(Ñ+Q¯¡Wê¹²P‘ëðï³TCõRÞjë“ñý&Ç. VG‘‘Q¦fCìà]Hf`8KmÞ‹ö’«RéÑ07ÿuÜøl.4â„Ê ñm²õšŸ—A | K)3”’Déu“ìðq·bûñè…ÞE¯.V{MõÂMùáj“Ì 57ЮÊQ¢§œfÕDÛ]­»‰®¨»OgÌTÿSÊw¦Ê¡ÏòB½T§ÏèÌ)Š¡!>D×läZ8êDn[<)Øé„EΫÄü¼†Ö›®ÅbqÔƒ¾‡j¿F¢œÖ3ENvnŽJFHJ@À‡Ã{„y`ÐóÓm¶ÛrGj9v±ªÚ'•Ui§½As¿³ŠÔâùA‡Ž"–è½xeé^¼ä[YÂ*áQ'Én{a¯Â¥1¦÷vÖg÷R‰£lT¹iÌt˰E ^–ŒÍ• ÜÈZ<„”ˆ¥A›4œÐ$9¬¦*†D„g|ž²ÿ[å€]¬<]¢¡Ç¾Ò8<ØÂ'MQ­8£×צbÄ3âNõj•vÙ qªZ!‘ª«ÜÔ[’Ùˆy:ÅY1 ¼æ-Ê%¯êfX¦‹d Z£b›ºœ³Ùìˆ0½`ˆè…Ô “…A d©ÒP[¦TaYWþŽ›;³»m »d–#âÁŽbàûcf4ßÐ[yÐ&³á1Xj‚’ƒ%çC³¶Ap|¼,ŽÛ±ö7˜í »£Ð~´aµ¨YºuûrHë,9Ë¡mÓY4}¯½°K§¾Ó‹8°OÏ?%]d¾ŸWå“‚\+?­lðÍ9QÂ)ï”s¢C÷ÖÝÕ¢Þº)U‰;o¡H±W†žo¶©"ްU`ßbúâa‡·±ÎÌ)?ØÙŠž¾ƒ#–DÙ§ƒûJÀCjÀ²^Ó×êÛürçÝDÿ”ésº*i´~›jUl¾r- #SÔšÖfÛUGvÜ-;3‰È0Í?WÇ—ð{&ÌÀ:Ü`í8 ÌêZ_ ɸƧÃäÿ2±^µ#Ô<˜Úçðî(™=šþ„PEvÏŒ,e5QõáŸ[Àë–La…Ëäj6½ûàÈ<-Õ8ø{É0‹zŸ•nixéâŠI¡>Áøl”d¹#²,9÷¤‘Æ•ÿcõ Ä—Õ’ðܦˉØTÏR*M*]ª•¿×m$TâYô̾ ¹üûÈ'NIµòO}–vÙö*;?E׌¾ê¨K—¯×–WBõOžÅ­˜Í¯®óØYõ“7-]Lºö‹’Yã䢩â³^û¼¿&AåMG•'@¦-þÇì´ø²ÁÚyö .Ôõ±Õª–=CÚG–Ì0c°»\壆ðqTÏ/ã9'.8¶h®ŽjÔ‚Ið¨MV„k·–úXÝwoL{´Â-Ü!ùn1ó®õ¨TJêY`.'šqoŒ.$S‰ã0 ‡rò}†¬x=^A_?Ã\óSÜÛC¶m3WFwÝ)[Ǥ~g™Où86åKlÁ ´¯âÛ'KõG2i¶ ÞR„û¥ÿ€#B¼:—˜z}<\¥x2æI‰_8¨!uYÉüýúëÈ雩—M!²0ÉP'èI6Ûm¶Ûm¨ºID†°j‰q«Á©äŸ 7Ô%(çŠà‚¿á·E(GN¦/͗˵±Í¾„<*¿àrèn=Ù¢¬¦®/ñ>N¾¡¶ó]8†ŸÔ]#Hé¤a5ÿ$tz¹’"EHr½¢¯à ™§¶ÿ@ ù¹#q™.'¡+u8¾ û ô{˜xoSÖpŽÝ;ÐúkµyÖrÙ ÅY"VÛG@ÎK _ì}PíÕéPäéûñ»¤ŸÌÞÂ9(Ç–d³cŒ7Z³ôa0D)j-M0ÊB­øºZöôà-k:"‡ð0Tº!D›¢ãÓgažgÿy ïý¢‚¤Ðr ¶Ï€d€e“íBhTÊç{«Ö±Ñý#©³œLiåýMà…älø‚°>ÎÑG3<³Öaì1ÆV÷R×®¨Kü>B9Ó$p¸ž|ÑYc$ñË|[ªÁ_Yéׯ%Fùîû¡á1Í6Ÿ‘hµû§ÇTè½\’Ó8X È<é7ÏÖO‚鈼”2â'h§ 2TM½¸=Aˆæã•»äѦú׏0XäÒì a›¯7’Mi És N™T½Á¶,:~¾„(h¹ô¼Ê§}Œì¤®‡·U’ZÀSwzOŽÏ‹úC8xk Ç«îäýt_ÀÚaå ÿ¨¶ÕGt¢šÝ=£± QDT`WÒ)\Ôõ-ÇôóÒÁæµF--—ŸFñR˜•NòÝù?IáÇòð¤µ)„å&\€7(‘±åBäWI‡áù*Ù$BR ꂇD&‰p‚©<ÒØ/›ÿuiiýkŸ¢ÂÔ†ƒ­Ã>ÍÂ7DFÈ^1Év”H[b•oúVv Zúòï :OÐS*Á>5Ló»Î‹TÌCIP›f:tL!_Y7_J'O3·™ÇêZH7É`~WÓ‘jØœÀÉ£0’½ïâ?~j”2±ÌŸºJÈf><%-"I†šN¿\. È(›È=$9›Â6¤ÒÏ»ˆˆZ÷1ûJ?,‹ÿ‡sHÔ"v3XñuI¢Ù †Æ>ç>¸Ä^ŧ¹¯g›pƒè€]CœÄA¶˜wÕ£c¬ #£BÀ2R_/í{,ÑK¾Æ”ˉékcŠËì¨øL #ˆÐZ±÷/¼YœàsŸAû–Â5UÔܪ¹zÌí¾.ä5²VÿV¦wž›þX* ý›zöWqŠ…vMjæM§D9 ²8+ujbDâ§Ç¬öÉ\-»4Ö´‹ë{²ñDo2âB“T/gËϷؘ8&í0£ÜYÙýÒ†ë’פÆDžhši lt÷Š%Ï þh2Ö‘µÜ”ÇTJÃ,œ"ËrÌ:¿ÏË•Ôe¦u½)¸„k‰™„3‰Ÿæ'%0ÓæQ?q¹D¿ Ì žïAôëÜâÝêãèØ5õbâ ÑúqgÁ/a·%v#—¯¤*#Ê)×@¸œ['"mÁ¼$sñJ­/䢮iäõCú[îÃVöçÔfg-¯ZP‘øCˆÛòK9G1O¥ñ%ÎN@õ*ïø5«jcË[ƒD´IvÇðyàÀu\ÝF˜Rùd0·zÿì‰u²ûµ]+¶E¹ h>uIi»E}3¡›Òxu¤Ðfë¶¿衤u\ÐæŒ!Òέ•ÚAÍDè_whЛÓ˜þ­‘^ŸÊÒÚ®ãøh¶Àÿ 'g’eNOµ  Á„~9q…\â8Wf¢ÖéâpNˆ|Ëm\ø2l´ÏœÚöCGSÿ6ÍÕÿÌCOtÌ®«LLS†ú•UUUUUUUUUX%™kêY¨ôuÝŽ2ÏùŽ,û9ÑYz‚¾ä<€">",ù£-5<"+’£(6¡7YªÎwCP(ä “0Åmú?ÊV1…‘ÿëÁI6ˆÊÚ!p «B©½áÏfÈVä!§e½£ÔÑh–ràêú¦êgY\F µWã~·MìˆhÅ™ ûÍ\z&µµñ§é1È1GÑûÇS7|7S‡"Ú›7[ßay5ÈÑJ‹²Õz¤T²ç3²k–ɇ3<Cö 5¹ÆS`0 O ºåõ樬xܳé;¿„À¬üÇž¯E? N/ÃçË+±ÿ|ð@ŸòÏ&s`$ÈÛz}ònáñ¸>³[^H™E¢-™¢aÏ †dÉïb$p¥ÃxrV‡6º[ÇcÜÏ!pÀ• @m¯ÇåYàå=ÑjêqxLs9Úž±ïóˆf?iÁÅŠL!&Œ<`…ïö+"W‚èµw”¡¨òéªÀÔŒÂ,áž?Ǿ» ;/s‰âЛø¬úÏ{æýwqJžö&JÒÌÄÇÌrùG+CC1åE‡D‹KÕoRT?€sÐ!¤”È¢¬*;u—¹ì8ç¢gp¢0^ •,]tqÿnŒIbýeèõ›èo8ùÂjA+OgñËMiRØÍò÷­ž¾ízpšX£pvpè‡{YþkÖeî„35tÛ›v3&ÂS⪗ó…òSqKp BÃTË»±2Â;ÕŸÝwýßö82ÙóŽn€“ŸàÉ‚Ãà!.lÕ³fáèìÍÎçsfu92ûÅ˲gªªô™e휴´É";©ñÏ8°\„¨Ö`éî‡F¼£‚Nµèc_Dkk¾%¥=ºS~·‚­á“¥©ü´×ƒºAó|Ã4ŸDÆ[£ø Ê'Ë÷¯åë~ÄëÉyfÛÉ€ÍíyòüúÐ$3 öçSã)ÅÀºn¥¹ý8lƒ†.a¿ýftÉ ®LRPèé4ëuoš]§Ø$?6ÓÝYý‚í&õøZÔ0ôù+39üPO{’D]¯ø§¥0DÖ|&®²þZ-ß´Bw‡¥Æ„< ÚG‰8ÂNè`{-ܧE¥pJ‚÷K»,¹-õ²£í~ô°CùÊñjŒÌ¥¯Õ¢¥j2¡N)’·L[ÿYGˆŠD- =ižY¢¢ÙövŠ,¿øW_Xôƒ¯iû#ó‰;2l= 笯5„=t„˜Aý€‚53%·³<õ ÿ}å_Šÿoà¢ýþP}£]¸G%#z¡2 ä¼Ú3mëI&ºÏá$-RTjF#qå ;x3Zsí¢€ˆºoù– ·?®â œeÑ~Q"TvdéòrËì |³T²:”8úû«tõ²I—Éo¯ÿI=Qþ¸b×¼©C°P =€ÇwÚ'œpò·âÒ‡}8B+h2Ùþ„F6ÔáCô²ál{øÃGÑHl'|0z sÏL…C³èPòØfÕ5m_¦í>ø}ö™ÂmRôGëa7û«ËðßÚ½<%’_ÍþÔñZnÔœ¹sœz?ËÀ.ç} «c¥iöt %)å&„‘£‰CîÔYÄæ¼0c²›š¾kõiÎNïÆ‰r¢3Reøœ %À˜@žÝ•+ü͇ð^Ëtù^Ô°ˆW¯¶5 [Í….Ÿñí¬nïž9¼‚ÃQ_P§¶|eºä#î° Ò‡iéYcÓã  :ëÍÜÒxΪ_!]Wb'-TöÐJwCì®Ë€.¯‹ à?åôÿ.çCÚsy§®_½^7êMuRϰýﮣy 5è¡~_Ûh ÃÕWÅÕÀ,ƒvÄ1èhþzyhÈKa´ˆ2€p3aMÅM¿ÅSêáÊþÜμժó½ôc]þêXVp h =nÕ$4©4ø^£3Ê%bÍ8²œ„±ñÈ›M±ÚE¢i7TùtMëŠö .d)È“ó€.âhO^̸–J¤CüéYï¡qˆÿ;AqjEh_¬u®û+¹sÄÙ{;£#7/â»N–BâNÈ}üÁe sÖe*Ú°"`µj–€ß©@KD½6ŠÄ¹¨("ü…u Ê:#ž¼Z¡³þn˜˜Æl³o¨"¸ç]´ã&Yv ¸Œt„•%óÿËÀXç6UsÖ÷W/øäufï½¶õðwL®,=\çƒë`Þ‡_á¬ÉùM^5'®ÞÁw¯Àj‹š¸=i°è·¯þœ ¤¾×Îÿè1ÌøscªÐÔR•Î+ä9×4®ÝãÜŸ vÔ/Võ`ceæu£“ì›×;Ò€düw©efø¸-Ù1«8×ÿB˜ÛYOñãÚõ­ŒªŠö÷×ç°ç’ãQa­ÿØù{Ž*–/ZwÅ—ÁÛòJµóYŸ{,;ä†a!mדŸzÔgk,ŸriŸöÛÖåp9Ìm"Õó )…d^SÓeO[›¼qåã4©žÃ ë²òÌÁÑ#+mŸ$l©½Ì8òvòLˆIÆÊƒÊúÙh>ÕšîSgû•2¤JÃOˆC«Q­4\îeò;ûUÙ`ôú»N@ (Rw"¦±Ì8vZï/§G/Ú,:rCN—¬°±[E8öo² J§T¥OF¦uMB†©g ’…+ u_žÞ/¸LžüsUîÇ<r}Ôsx% ’Ñ_è];$´ØÈ)”4¡*NŒÎºq˜æjËP¨,Úôí’zÆ ö` G­ÇÑ7c»ÀB‡]ÿ~s®ÃÔ‘¯} ÊíÿW··ŒñX}þw4K& ¶b¸@ô}t¢½Ð”òyuZò´¬å ù¨ Éba%­…ó`œˆÊ5mË8Þv~Ù×|l[NŠ›Ëñšý#Ч:7DA8†˜u/° C.]–ïýVDáñßr«š4µ™JU&ýG#Û²o#\í”Ð9(õºæÐÉA|ßS¼ÐrIRuÏp’bX*luÌEÎôÀ|ý•;Oõ«z_®jÕ‰ù™0?>b«zøîÍ'ÿ8죊Fú. ÔNxQÕ°›dy¢(ýî˵›1í FIÐXjo”Ïû ïìná‘M¬¢]ÌPÌ?Ã6ú"‚Þ+¤HŠCí’Å3çýß`vÀF(ÜwÑ.a±Œ¹Ä¥19à3óúŽpòèâÍØÚk‹dÙHŘ¯éf/âí‡%¿ù‡ý¡ñéž[Ù¼ç]D¼PÀÆ;T¸ÑŸ¿Ïf¦&K“*«ü6³Y¸¬ß q{ï+¿‰ U­k{ij <ÉÇt{YR¡óNÙ$-î ­­Öøay£F•·£“®]--W£¨bæŠÀ´9‹Õ‘öÂÍ¡O܃˜3]£ý%ÚJìÿb²CùÌž)CpÖ]²1¢ŒV… IÖñ6eK1]auÊ ¹Í­þ¡²¡^ãˆ?ó2‹±“Öji~ЧÀCû^„š~ib8ˆ´þ‹¦:ü(…8É#2 NÈ%¹KFVI ²è´¿<e›YS󸑨û^Àì. œGh¿mÏO_µÖ9O¼ÇÃÔ.ß(•-Fær‚E•ƒB³ =J“W=—G¾ÏcÉ7r‰ëµT÷¬~áp*‚òÓÿWâHã™°¯„á密nÍ»‡Åšqž?®Š¥ÊûÐ¥¢Ï°Ƽ{}Š;Pz ÉÕµNv*Ûôßhàx~Äó®ª uXçòÇøJ×8ÔØBáÉ,ø\§ÏÀµTݽ÷£’må/+…ÊHÿAªËŒX•¨Ø0ÊË`AEWb/G¸™-9ˉª´A$øLàê¤B‡¢}WD„pMÖ×-:ò_Šcu Ú Üiÿ<]ÀÖFkz:ýò8-nsÓàù›ÔÑÀ&€·ðYG4þS¶°=BË;^ØÒÃÖ5Ib8÷Ø+BÞ)ŸŒ!_ é·¹ôYñÓ÷F>ÀÿQ<}'•l÷UEq××jWÍÖè³ø$á &aœu«ñ{v`ñ>¶ýµï×îéB’p–+ÐüsW΋A$‚lŠ.L¿ás‡ÿ7aعï_*ùzǦ^Q,>ôY˜l©üaœlAF Q—¨%…éßý9j³ÄàiU‰€ñUæB»çO_óäþ4Ü|ý¼BýÐ&k DÔÚ\`r¼WÀÜœkª˜aŽ¢(ê¿tEŒª¤„Пѧ±ÌxÉ©”žjWèsrŸ9kr*µŠõ²ÚÐåŸÊ­9E• îoƒv‹XðYn€3h³'&N1×ñ ótÖ6…ÃÏÙ•ùcWanx/)ÆÕe¼¸&lâ P)ÎkϬm07à„’n;£üÅÐé 3ŽŠeˆIx—ßw8[¯ ±¸q³gpTÍ$qM]ý¦ºAèó>üLsSÐ1Ô ‰EÔïdk¦xü÷± b®è½>âe²ÝØpPmʈÔü!¢Ò\wôiIöŸ–½Ÿ_å^Ÿ­‹IBÀîJòTÊÊTNq]j“'c®jXŽ/ö2+´rì ³—¹µqcyz?®©s±£™¦0;†¹+¦ˆôb³æEá¸Ròe“óD¯æ®ŸK@cXWëä,gôœôå8~cbûþYølƒÓ˜SÓªJèû•ÿp¡ 7¼ØÀŸû“C­²êBk%³RJŽÃ{jè;c~ñÛõv°;²Ìƒ œ5 s1ÎÛ“ŠÚºÓwY•À‰ic?KcB˜ß€+ál)öïH¡XðÎk¼IzRD‘qFáÄï7 i‚{¥×Ÿÿi $´h­'V5Ñ^Ä·â—à﫽ÚÙú°Ê…•Èd|¯›?Çhývt¢ÂsÀ»-¬…Ó=‹­O:¿]pÃòUäI~Rå½ïšÕB×€H—‡/8I­aé4coÉ!Äêýr^†”¢YÿE…‚ý5(åúwv‡¨¼ŒÐ?çM6DÅRÖT1dfÀ­>Ò^ó 'L­¨õí ¢5g { X’óà2!øQFW´SÒlÝ#2äèƒJÙ: Ü_qÐuôj2ŒÀÓ¤Z-¡JÖ¢E¸¨ ½! æ±SkŽ,£š(õÇéó×åL ÌH)W†ãëÔÞ¡!;€{Êk¹´†he¥åÃæë0oޱÒd’Yç,’)_@n«zhNR„_9/ÿ«\ßóž}‰¯iÙt˜_ ýF¡s|q˜æ3£—™ÖÚÒ€$ç÷lxsz'ÕêÌ÷]• ;íQ´¨Ët…zBfÍÕ6rŠÁe”E‘Â4uŧ˜îÀŒ¾ò&|²è›EY8Ìv¯ˆû¿° úJ‡|Ⱥ:òfÙÜ?ËOŒL¦ËãÉ–YA¬® ¥Ý9†X¦ËüíïÒ](z)Ÿ И'FÒ/‚É!\«>ù¶pÕÁÐ’RnþÚÝŒ`¢m… M'¨¦œz‰ó˜›z¨e‡ E¦/X±¥¦$Òm½Žz:Î-:¹8Aþ늴íèòx&,7b"ºõò8´Œ¼FeS&c(DþqÌü•kï™&<à^bŸ_p³Š:JšâìáÇ&x¥ÖÞAnæjì8…&Öyí Œ«è,mÇOìÀ–ÉõÐú#â°î½­a¶(töý;ÿM©¢ÂŠb  DÛkг¶ñ>ö?ÏñħÁ)ûq0Õ¼é‰&‰p×[óÇ‚kR4цã^ÀìW8}õ¯ÀÒÔ4m¸a—žSÆ÷«Ýš#®-¡6W'u^é«”Ö²½ù‡ʦÁˆ@§Y\ _扊ŒÄL¸W÷s5‘× –ÃõAh3­¨íibŸ€þ§cqŠ×é §Õh0 *Qˆ»IËž†©h…òt¯úW\€ƒføR^¼*+ËqîövAVÂ5ª …c{^jã, ß¾"å0<Û`¢)¶¨å#ï,ÔÊ ãÁéaÁÒ†˜!î²–|Öú^1Zÿå¤M$¡pHnT^~©žƒ€--J…) ˜4ĦÑH倓Æü +ÄP© ªdŠ:ßv5ëX¨XQŸ"€Ã’5°Ü¦½çvwÚØ+°·øY´J¨Ò¡í;Äê:I] ¿¯©Ízá$´Ò“…YÝŒåªØ}+ö‘Å.Ç7-N¼~SÚžµÕ€_ج¯!×=ÿZ3:7Lˆ€týù›ÑÙ*Ž‘ ÄXpÙh9ŒëÿOBðõ¢²œØUö-o'ÊÆø¨zsÄ;‹JOÛnæ-ÅÜrj3‰Ü³”‡r*KPO¸(?Ffbk䯙yrÀâlÎ×â(øŒz¥&­È{„׬ kmA|©bÒìA#Ý×X_kOŠ"&ýÕlG:ZÂÆr sVŒ{ó]™¥˜É9ò/›«¾¨hOo["s—obçÀUã«D ¯cç`ðª<ù;³{ûõÁê.Ÿý%‡ôÎåÄ—aê¹²æ8=èWI«¨#w=c 4‚ ¾ÍŸû[â ß³è°ÖöyYö“n J6QMuÂ’ÞcMN¢( 0ð]žˆˆÂald}’RÿŒ¸Úfw½9|§JÆ(:J§ÜžÑó-cÌØI$o ¯!Z³ÊNÔŠdáŠîŸR¹tNdKë*Þë¡ômú]Pîq|W&Ýãº÷¼gì¾™LØLeÝ#cºçY ÍýnSåø6œIjvŸ”\!€—¢µz2Ä$˜Æ4îr† Äètæ=£tCÃ?²¸,^›ù|ž‚{ú/!N¨¡P@vŸdOMºy/û’ÏÃdxÑ™u&\âÒàyµÏî~Ö à¿šÚÄ$–¿“G|3ÿ ¤îm/[7þDéÈÂÌ<èXK¼¸=;< ¤–ä ^“:­ûõá%Æ _«_ðáæaƲ«Ç–ÅoìÔú;î•1;LJ|Ä÷p’x\ÔôY@í¶¯k×Po4`åÃRþg&k)Dž:¸ÞX›%™Æç¦¨6 òÖ<Á@ö q»ƒ¡¸ÙmWÒ^bÌ8¨©[5™úÓ#Ñz[6 7sylVy;W¢¤jï™ UPb'sûrDgHÕ WFùìó¶Ã½å¾nØ38%ôgI9Å]6Ȭ=—gÒþøQSÑYûÞ~߇îjdZ»™Çü‹’F~3“è\Ĉ¾ŸR FÇ€E /Þ¼çÌ9;™-ì"ÒAêZF@5šR¦¿oBÎ~f[mGpÌù*¦+–ÈÎ\ˆ $oßAýGm½ñc©ÐÙ…†Öµh ¶pRi&:vdàÁ cÚûöEÇ(ÌÙjáÙDHæá‘±Ê÷˜§Íöç$PAs\Êì×nDSdKT'>¿çe¿©_…»¶¢Ÿ& v01Ê ðþ0µU9´$EÆìÐC¿Î3­ÛYè—†;Á[¯2Kf´Ò Š' ÉÑHÓ.¬z9Àj%³B¹=û]·23·|8(ŒqÓÚœ'ùënÊHÛªôwòÆ•/‹=ë2êgöÛÿ֮nè^§„v”wä½å̈́چ<àÄu›J!tïxJõí¼@9—ô»+N<òOç£ÄŽW¨´LIVSæÛ…Ÿ¤IúîÈ·86*Hû ;ÇÁÊ9õGt*¹§þ•y}iQB=mè OÚrÎ_æÿW?ïÆWöñâSž®j—ôê×Q¬bø¢=ð µç\›¹{*k¦ -T2…îR%¯•¡æ}ŠL6ËQ'3}zqâ2øÖ1fÑr„…g jï\Ýã¼JÉ‹gâ³\ÃÝínb !SŠÉ<(U4§¶lè¹Þb²jH]yë£á—”$0òÚZ …y*ÇdÜòª/Æ ²!HÝY‹ÈÒëà¾vÕ­>,o"ž™G:ÇÇ8›ãá|ûÁXаu«™Œyÿ Ý&l ==S½zÇŠŸ+kÍ[RŸB_,˜`ã]—Á»N¾:dÏèö;ÎøWÇþù‘YÉêÊÒ`¤k*”eœ›­)à•ê©€bÊRN'·u#|Náú¯Fr~C¹™œñ°(¯IÛB]©G±€¹C bÊwô§f[GDœ*coo’æÂ?­ax6'@±-P¬Þ(αJŠ×C>ûd…æÃ1?òvø—Uë*¯×GÌNùßBï 6èþ˜Ð-Ø¥n‰GQg¯^H¢»m«®îW€žÇB.Å{0ÊNc±G“îaÐ^¶N'€ÿÙqtrvsim-0.9.8/data/screenshots/000077500000000000000000000000001467752164200165245ustar00rootroot00000000000000qtrvsim-0.9.8/data/screenshots/0.png000066400000000000000000005106301467752164200173760ustar00rootroot00000000000000‰PNG  IHDRöx¹¿sBIT|dˆtEXtSoftwaregnome-screenshotï¿>*tEXtCreation TimeThu 20 Jan 2022 23:58:33 CETɨ+ IDATxœìÝw|TUþÿñ×IB€ (u)"`D)ŠÊé¨ÈªwźúWW]×um(ʪ`[¬Š +@Qª,ÒBï!$¦“Ìdfîïp¯“d¤Âûùxä‘É­çÞ —Éûžû9'˜¦éHOO¿Ã0Œ;€N@0"""""""""""RUò-¦i¾]¯^½· Ãð)))MNçLàÊ*l ˆˆˆˆˆˆˆˆˆˆˆ¶ÌëõŽ‰ŽŽ>ì0MÓát:?F¡¾ˆˆˆˆˆˆˆˆˆˆHuu¥Óéœiš¦ÃHKK»Ë0Œ7ªºE"""""""""""R:Ã0î2ÒÓÓ×]«º1"""""""""""rRŒôôt7(WDDDDDDDDDD¤&Èw P_DDDDDDDDDD¤¦vTu DDDDDDDDDDD¤ì싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A‚ªº"""""RómÛ¶ÄÄDBBB¸üòË«º9"""""g5û""""rÎÚµk .$>>ž””|> 6¤S§NôïߟöíÛ—ëþŽ=Ê‚ Î #**ŠvíÚѲeË€ËÌœ9“üü|ÂÂÂ9rä)í;11‘… жm[zõêUl™-[¶°`Á¶lÙBZZ^¯—ºuëÒ¼ysºtéBïÞ½iÖ¬YÀí¿þúëÌž=›˜˜vîÜyJm‘S£`_DDDDÎ9{öìáñÇgÑ¢EçÏ›7§žzо}ûòì³ÏÒ¶mÛ·µlÙ2>úè#^xᢣ£KÝïƒ>xÒöµlÙ’ûî»[o½Ã0ìé ,àÛo¿ sçÎtìØñ¤Û²¼ýöÛL:€3fš—””Äý÷ßÏwß}wÒí4oÞœM›6•y¿"""""Rþ싈ˆˆÈ9eùòåŒ=šcÇŽP»vmúõëÇùçŸÃáàÀ|ÿý÷dff²dÉ®¾új>øàúöíp{û÷ïçóÏ?àÉ'Ÿ,s;êׯOƒ ìŸÓÓÓIII`ß¾}L˜0_~ù…×^{Í^f̘1v°ÿñÇóì³Ï–i_^¯—O>ù€¨¨(lÏKKKcðàÁìÝ»€ÈÈH®¾újZµjEXXééélß¾µk×’““áC‡î#22’˜˜˜RolˆˆˆˆˆTg‡fÓ¦M 4è´Öÿúë¯éÖ­±±±åܲâ싈ˆˆÈ9cëÖ­üñÄårp×]wñøãS«V­BËåååñâ‹/òÊ+¯““èQ£X¸p!]»v-·¶Œ?ž‰'š–••Åo¼ÁË/¿ŒÛífæÌ™ :”k®¹€~ýúCrr2Ÿ}öO=õÁÁÁ'Ý×?üÀÑ£G1b¡¡¡ö¼gžyÆõ‡ÎÔ©S©S§N±mäåå±dÉ’b½ý-Ï?ÿ<Ï?ÿ|Ù^DDDD¤š9|ø0C† á×_å­·Þbøðá§´þܹs¹ûî»iÞ¼9_}õU…‡ûŽ ÝºˆˆˆˆH5‘ŸŸÏŸþô';Ôâ‰'xî¹çŠ…úPPïþ‰'ž`òäɸÝnÆO^^^…¶122’Gy„'žxž6kÖ,ûuPP7Ýt)))e*½û-cÆŒ±_{½^æÍ›@ll,Ó§OêCÁ9ø€Ž;2~üø m¯ˆˆˆˆœ¬ð¾¬á~i¡þµ×^[áíU°/""""g½ 6ØAy·nÝN¹—w·nÝØ¿?¦i²~ýzúöíK»ví˜1cï½÷žìOž<™æÍ›Ÿq{?øàûu÷î݋Ϳá†xôÑGÉËËcÖ¬Y%ûÛ¶mcÓ¦M 0€úõëšÌõ×_ÏÇŒÛífðàÁŒ;–AƒÑ­[·€ãœ©Ï?ÿœ&MšðÓO?Ѿ}{{úO<Á5×\ÃîÝ»™6m_|ñÍš5cîܹ…Îé#<ÂUW]ERRÿþ÷¿¹ýöÛÕk_DDD¤šIOO/—íTviŸ²†ûUêƒÏ‘s@rr²ýºE‹§¼¾ÿ:þÛ*O¦i’À¤I“xá…ˆˆˆà/ùK±eëԩðaÃØºuk±:ü–’Íõ÷Ïþ“6mÚpüøqÞ|óM† FóæÍéÑ£ÿïÿý?æÎKvvöŸ¿·ß~»P¨Ń>@ff&;vìàý÷ß/v£¤I“&Ü}÷Ý@Á g;vì(·v‰ˆˆˆˆ >œ·Þz‹  ßûÄû¨[B}P°/""""瀌Œ ûu:uNyýºuëگ˫÷Ñk¯½F»víì¯&MšÐ¹sg¦OŸŽ×ë%&&†y󿕸€Pïà[¬2=7æê«¯¸úõë³dÉî¹ç"""ìé>Ÿ;vðá‡2~üxÚ¶mËÓO?m×ë?]íÛ·§wïÞç]vÙeöëž={Ò¡C‡€ËõèÑÃ~m ˆ,""""R^J ÷ï¸ãŽB½ù¡jB}P°/""""ç€àà`ûµÿ‡ð²ÊÏÏ·_;ÎriÓñãÇINN¶¿üó6mÚ°|ùòBAwQ½{÷¶Ÿ$˜;w.n·»Ðüï¾ûŽ””n¾ùæRÛ]§NžyævïÞÍûï¿Ïøñ㉋‹+ôçææòòË/síµ×’——wZÇ Ðµk×ç5lØÐ~ݹsç—ó,8++ë´Û"""""R’@á¾×ëÅçóÙ?WU¨ öEDDDäà_›ótzÜû¯U.m4hÓ¦McÚ´i¼úê«Lš4‰K.¹€Ý»w3tèP~ûí·×7 ƒQ£F––Æ¢E‹ Í÷ïÅ?zôè2µ)""‚k¯½–É“'³xñb<È·ß~ËM7Ýd×±ÿùçŸíRA§#22²Äyþ7J[®hÏ)‘Š`…û:É8Î* õAÁ¾ˆˆˆˆœZ¶li¿Þ¶mÛ)¯ï¿N«V­Ê¥M^x!£FbÔ¨QÜrË-<ôÐC|÷ÝwLž<((1s×]wašf‰Û5jGÁGzÿ ÿ·ß~cñâÅ@Ay›Ö­[ŸVƒ‚‚èÑ£o¾ù&/¿ü²=ý½÷Þ+ÔSIDDDDälåóùJüLîõz+¹5¿S°/""""g½öíÛÛ=Àããã ÕÜ?™¼¼<Ö­[@xx8:uª6ZÆψ#Xºt)_|ñE‰ËžwÞy\qÅ,Y²ÄØwΜ9vOö²öÖ?™qãÆÙ75233Ù¿¹lWDDDD¤º²Ê Ô©ÅëõÚêVû""""rÖs8 8·ÛͧŸ~Zæu¿øâ Ž;ÀÿýßÿV!mô÷ÔSO ÀÓO?]¨ÆQÖ ºÇ>.«÷~DD×_}¹µ«mÛ¶ö뜜œrÛ®ˆˆˆˆHuc…úþ¥Ng¡²<§ÊÂ}û""""rN¸çž{ìד'O¶–-ͱcÇxúé§nÃb¿.-€?±±±Œ7€0{öì—!;;Û^&77—Ï?ÿœ^½z±|ùr à¦À”)Sn³k×®ö‡úçž{ŽŸþ™£G’œœLrr2.—ë´ÚÚ¨Q#»×þ¡C‡˜5kV‰Ëúøk×®  îÑ£G©ûÈÏÏç©§ž¢cÇŽ<øàƒüðÃ…ÎÀÑ£Gyùå— Õê¿ÿþûOõpDDDDDª½“…ú–êî|‘³CXXóçÏç¶ÛncñâÅ>|˜»ï¾›¿üå/4l؇ÃArrr¡ò×\s o½õ–=ønQÑÑÑÜzë­Ì˜1ƒuëÖ1`À€BógΜÉàÁƒO«½&Làý÷ßÇår1eÊFEppp±åºvíJ‡ضm›=íTÍÍÌÌä½÷Þã½÷ÞÃápРAêÔ©CVVV±’E·Þz«ý䃈ˆˆˆTœzõê•ëöÒÓÓËu{g›²†ú–áÇpçwÚëXá¾ÿüŠ¢û""""rN©U«sæÌáÃ?$..Ã0ðz½=z”#GŽØÊ Ã`ÆŒ|úé§DEE•ºÍÉ“'óÒK/q饗Uh@­3ѨQ#;DOHH`æÌ™%.ëä;FŽyÒíGFF2wî\n¹åš5k€Ïçã·ß~cß¾}…BýîÝ»óÑG1uêT Ã8ÝC‘s@½zõÊ嫲|ýõ×§ê[J빿`Á‚ m³‘žžnVèDDDDDª±ääd¶lÙBJJ n·›E‹ñõ×_Ó~ðÁåÔWwGeçÎ$%%‘——GDD5¢cÇŽÔ¯_¿ª›'"""rN©©=ö+"¯è¶9r„¡C‡²oß> l¡¾¿Ï?ÿ¼PÏý6mÚ0þ|7n\amV°/""""âÇív3räH–.] À¸qãxå•Wª¸U""""r®©©Á~Me…û §ê[¬pÿ‚ .¨ðP싈ˆˆˆsüøq®½öZÖ­[ÀÃ?Ìc=VÅ­‘ŠtäÈâããéß¿ÿi­¿`ÁºvíZá¡>(Ø (##ƒ§žz —Ë…a<ðÀ´iÓ¦ª›%"""""¢`_DDDDDDDDDD¤&qTuDDDDDDDDDDD¤ì싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©AjD°¿f͆ Â!Cp»Ý…æåääØó~ùå—*j¡”fêÔ© 2„'Ÿ|ò´Ö×ï¸j¼óÎ; 2„¿þõ¯UÖ†/¿ü’!C†pË-·TY¤âÝÿý 2„÷ß¿ª›""""""""R#Tz°¿uëV7n\¦¯Ûn» €ÔÔTV®\ÉÊ•+ñù|…¶çñxìy•}8¢]»vö9hÖ¬iii']ç(tî>üðÃJhiÙìÚµ‹•+W²uëÖÓZÿlüŸ®¼¼Ÿ—ËU¦¯¢½óÏyyyö9ÈÎÎfîܹ¥.Ÿ››Ë¼yó ;¯×[I­•ÊFÇŽq¹\üøã%.çõzY±b…ý~øé§ŸJ\öðáÃìÞ½—ËE÷îÝ+¢ÙRÍø_‡Ër­ðz½öòEo®ŠˆˆˆˆˆˆˆHå ªÊ?ôÐCôïß¿ÄùQQQôêÕ‹Å‹Z)m«4h@jj*³fÍâŽ;î(q¹/¿ü’ììl{ù³MíÚµíßÛ¶m«¸5U¯wïÞ¬^½š;w’’’Bttt±e6mÚıcǨ]»6ÙÙÙ¬X±¢ÄíùÏëÝ»·ýúž{îá†n víÚå{"""""""""rFª4Ø¿à‚ ˆ‹‹;érQQQeZîl3lØ0f͚ŦM›Ø¶m:t¸Ü¬Y³¸ñÆyã7*³‰•Âétž“¿ÿ’ôîÝ›_|Ó4YµjÆ +¶ÌÊ•+}úvÒõW¯^ÍÏ?ÿLff&7¦_¿~´lÙ2à²^¯— 6=ö### Íß¼y3n·›óÎ;Æãv»Y´hÛ¶mÃårѺukH½zõNÚ.ÇÚ5kX¿~=iiiÔªU‹N:qå•W^†3SñºwïNhh(.—‹•+W–ì÷ìÙÇüyóX±bE©Áþe—]Fpp°==!!¤¤$j×®Íþð‡B뤤¤pàÀ Ãàâ‹/`ïÞ½,^¼˜£GR·n]zõêU¦Ò>yyy,Z´Èƒ¡U«V 4ˆ:uê”ñŒ@ZZK—.eÏž=¸\.bbbèÝ»7^xaÀ勾gŠÚ±cÙÙÙ@àkNnn®ÝÞN:{ÏïÝ»—åË—“€×ë¥^½zÄÄÄн{÷€¿ƒ³Iy_g÷ïßOjj*uëÖ¥M›6x<–.]J||<ÙÙÙ´hÑ‚AƒSÎG""""""""R}Õˆ`åÊ•Œ3(ÊûËÊÊâÑGå“O> Xzذa¼úê«Ô­[·\Ú[žFÅçŸÎgŸ}Æ?þñ‚‚ ÿÊfÏžiš\uÕU4iÒ¤Ôm­X±‚‡zˆ;wœ_·n]ž|òI{Ðâ@²²²xì±Çøä“OÖæŽˆˆ`úôé\{íµ×OJJâ¶ÛncõêÕ…¦Oš4‰|Ç{¬Ø:ÙÙÙôë×€¹sçÒ·oßBóÇŒCBBO>ù$½zõâ¶ÛnãðáÃ…–‰ŒŒä7Þ`РA%ÛÂ… ™8qbÀHPP·ÜrK±õÓÒÒ8p »víàÒK/åÊ+¯¤~ýú¤¦¦²víZ~úé'Ž9pÿÙÙÙ\ýõìÛ·áÇӦMŽ=Ê¢E‹8zô(/¾ø"­Zµâ¦›n:¥sdÙ¶m/½ôŒ7ŽF±wï^¾úê+²²²øÓŸþÄÊ•+ö˜þðÃyà0M“óÏ?Ÿ¡C‡Ò´iSÒÒÒøïÿË®]»¸í¶Ûxçw¸á†N«}åɪ³¿}ûvÒÒÒ¨_¿¾=/>>žÌÌL5jD«V­ðx<Àï=óýùO+ì—Õ„ ˜5k—_~9Ý»w'//ü‘-[¶°hÑ"yä‘€!ýæÍ›¹á†8~ü8‘‘‘Üxã´jÕŠÄÄDæÌ™ÃŸÿügXê¾|ðAÞÿ}:tèÀµ×^KíÚµÙ°a_|ñ+V¬àšk®aÉ’%4mÚÔ^ïŠ+®`É’% Þ¼y³ê,[¶¬X°o­wÙe—ºfÜ{ï½|ùå—8®¾újââ∊Š"99™„„–,YBFFÆÉOj S×ÙôôtþøÇ?’’’˜1cèØ±#)))Ì›70qâD Ã(u<‘³E•ûû÷ïgݺuç…„„йsç3ÞÇ„ ؾ};‘‘‘|ùå—…jˆÜyç :”øøx¦L™Â¤I“ÎxŸåÉáppóÍ7óÊ+¯0kÖ¬BÁþªU«Ø¿?QQQ 4ˆÌÌÌR·ÕµkWV¯^]¬¬ ÀÓO?Í<À§Ÿ~ÊSO=ÅÿøÇbáÛý÷ßÏ®]» á7Þ`øðáŶsðàA»„IQ?ÿü3M›6eùòå…Êr¤¦¦2lØ0¶mÛÆ+¯¼rÚÁþgŸ}Æ•W^ÉG}T¨¤Ð¦M›8p ¹¹¹¼ñƼôÒK…ÖÛ¶m?ü0¦i2zôh¦NZèɈ¿ýíoÜ}÷Ý|öÙgL˜0¾}ûÚ;W•¢uö‡ bϳzñ÷êÕ €víÚMbbb±:ûÖ²tíÚõ”Ûár¹øì³Ï˜5kV¡Þãñpï½÷2gÎfÏžÍã?N£F ­{ß}÷qüøqÎ;ï<¾ýöÛBõüÿú׿2|øp¾þúë÷½hÑ";Ô¿õÖ[™2e N§Óž?vìXþøÇ?’””Äý÷ßϼyóìy}úôàðáÃÅΉÚ7mڔÇóã?rß}÷Ú·µŒµ(xeþüù¼ôÒKŸ|ÉÏÏ·KøT¿þú+ñññ¥.è)•q]¿~=uëÖeñâÅ…n´<ôÐCŒ3†%K–ðä“O2pà@ !"""""""g=GUîü¥—^¢_¿~¿¬Ò;gb×®]vIŒÉ“' ›  ìž8q"3fÌX^¦ªY½ñ-ZDZZš=Ý4wĈ„††žt;]ºt êCAy——_~™Zµj‘ššZ¬ww||<ß|ó Pt õZ´hAÇŽKlÃk¯½V¬Övƒ øë_ÿ ÀÎ;INN>é±R»vmf̘Qlœ€‹.ºˆ›o¾((«RÔ”)Sp»Ý´mÛ–—^z©X¹#§ÓÉ«¯¾JÆ 9vì˜}Þ«’UgŠ÷Ä·~¶‚}€=z”ºìe—]Vì¸Ëê¾ûî+Ö³>((ˆþóŸ†×ë-¶ß+V°yóf à:P4ˆµJ'9%_¢^}õUÎ?ÿ|&Ož\(Ô¸üòËyðÁXºt)[¶l±ç]xá…ö˜ EßÖÏ?ü0†a°jÕ*Ün·=ÿàÁƒvÐ}ÅWØÓ0M ÐÁÁÁ¯CUé¹çžãŠ+®(õ«´ ¾7” IDAT2¯³“&M*öôDXXÓ§O'<<œ¼¼¼€%¡DDDDDDDDÎ6U쇅…ðëTÎ,Éüùó1M“Úµk3bĈ—»þúë‚RÕ­7-@ëÖ­éÞ½;n·›¹sçƒw~ùå—@ÙÊð”EDD:t(‚|õÕW„††žv©‹ÆsÕUWœ×­[7ûõÉz—¤ÿþ…JÒÚ¾=t(èAýí·ß籤!aaaôïß `]ûÊfZëš›¦i_àì÷ìÙ(Üöääd»Vùå—_~Úm9rdÀé5"66(þ;µjö7jÔˆk®¹&àúmÚ´±oH•m#0fÌBBB.7nÜ8{àÛï¿ÿÞžîp8ìcö/Çãv»Y½z5‡ƒk¯½–N:‘››Ëÿþ÷?{kùÈÈÈB!¶u¬@©5ö«›   BCCKýòT¹¨ÊºÎ—ø^‹‰‰±o.BDDDDDDDälT¥¥x¦L™Rn¡t ëׯ ÂÃO?ý´Ôe ÃÀ4M:T.%€ÊÛèÑ£Y»v-³fÍâŽ;îàË/¿$;;›öíÛŸR •œœ>þøc¾ûî;víÚEFFF¡ÞÈÖkÿã7n z:ŸîM—Ö­[—8Ï¿´Í±cÇNkûEŸ´ýüü|Ün·oß¾Ýt5--­ÔÞøÖ99tèÐiµ¯¼õîÝ›U«V±uëV222ˆŠŠbË–-dddРAÚ¶mk/(Ø÷}ºõõ-[¶,q~TT‡.ö;µ‚Ý.]ºØÁ{ ݺu 86ÀŽ;ìZ­ÄÄÄТE 8PìfUŸ>}˜?>Ë—/Ççóáp8X»v-¹¹¹tíÚ•¨¨(úôéC||<Ë–-³o”XÁ~ïÞ½ =%KïÞ½Y±b<òŸ~ú)ƒ¦wïÞtíÚµÔp¼*ýûßÿ>éuø›o¾)ñ)ªÊºÎ¶nݺØÓ8þºvíÊçŸn¿7J{ÚCDDDDDDD¤¦;«Ïýí·ßØ»w/÷Þ{o™Ö9ÝP¹¢ >œ‰'²iÓ&¶mÛfЧrcdûöíŒ1ÂÜÖápMÆ í€2!!¼¼<\.W¡u­P»qãÆ§} ¥• òw­r&µ}+†ßß#ð{i—“©.ï‘Þ½{3yòd|>«W¯fàÀvÞ³gÏBÇÜ©S'"##ILLdß¾}´lÙÒökÕªuÚåa‚ƒƒK P­6ýZÈ6lذÔíGGGœî?mLLL©Ûhذ!(6h­UF'--øøx.ºè¢bµóûôéÃ믿βe˘4i¦i²|ùòBËø{ûí·¹í¶ÛøùçŸY¿~½z‡‡‡sõÕWsûí·så•W–ÚÞš¦²®³'{¯Xó½^/YYYU>†ˆˆˆˆˆˆˆHE:«ƒ}Ë…^Xb ‡¢üKÂT'µk×fèС̙3‡^x+VÄ7ÞX¦õ=cÇŽåÈ‘#´nÝšgžy†+®¸¢Xé™Ú%NüYámuƒ ¼<ðÀ' ‰r)U.¹äBCCq¹\¬\¹²P°ï_† ~—^z)‹/fÅŠ´lÙ²\êëŸ.+ð?Ùû©¤ùþ7-N¶ ëFNÑ­[·&66–#GŽðã? ö{öìIpp06làØ±c:tȲûMš4aáÂ…¬]»– °jÕ*6nÜHnn.ß|ó ß|ó ÷ÜsÏ<óL©m®‰*ú:{²ß³Çã±_oADDDDDDDälsVûVHÆÝwß]Å­9s£GfΜ9ÌŸ?€~ýú•)ˆX½zµ]O}æÌ™´k×.àr)))§[ûIHH8ÕfWkþçïòË/çꫯ®ÂÖœ«ÎþªU«X±b¦i²jÕ*à÷Ò;þzõêeûd×®]Àé—á9Vïê£G–º\bbbÀéþ=ù‹ ¨êïðáÃÅÖ±ôéÓ‡Ù³góÓO?ñ§?ý‰ 6Êe—]Œ;ÇêÕ«Y±bû÷ï Þ7%ý‚‚Á»w±dÉ^xá¶lÙÂôéÓ¹îºë¸ä’KJ=ö𢲮³'{¯XóCCCK-Ù#"""""""r68«‹[ÁÙ† HMM­âÖœ¹Ë/¿œfÍšÙ?ŸJ+Ô¯[·n‰äÑ£GÙ»woÀyqqq@A9Ÿ’ÂÖš¨}ûövè?¸jMa…òñññüüóϤ¥¥Q·n]:vìXlY«ÿÊ•+ Õ­¯Š`ÿ¢‹.à—_~)VöÉŸ5pQíÛ··K/Y73Ù³gø*7dõº_µj?üð‡îÝ»z’ÅZfÙ²eÅzô—Exx8C† á‹/¾°{’[å|ΕuÝ·oIII%ηÞ+;w.uÜ‘³ÁYì1‚àà`<Ï>ûlU7猆Á»ï¾ËŒ3˜1cýû÷/óºÖÀYYYdff\fÊ”)%Ö·>|8AAAx½^žþùSo|5Ĉ#øðÃ9pà@Õ6èY¡¼ÏçãÅ_ GëÞwéÒ…ˆˆŽ9ÂG}œY}ý31dÈ àýXÒ€Å+W®,6à­%$$„k®¹(x¥hý|Ë믿”f8p`±ùV@Ÿ››ËË/¿\hZÑe–.]jßD8•`ßÒ A"""€Âã<Ôt•u5M“7ß|3à¼;v°lÙ2à÷÷–ˆˆˆˆˆˆˆÈÙì¬öÏ;ï<{0Çwß}—I“&´1''‡Ï>ûŒûï¿¿²›xÊâââ>|8Ç·Ãú²°zÕš¦É£>ŠÛí¶çy½^¦NÊŒ3JµY³fÜ~ûí@AþÄO››[hŸÏÇÒ¥K퀭¦xøá‡©_¿>999\{íµ%öߺu+>ú(?üðC%·°dV}(ž!p(¸‰a½¬e«¢¾>@ÇŽí`þñÇç§Ÿ~*4ÇŽŒ?¾Ôž×&LÀét’ššÊ-·ÜR¨·¸išL›6>ø€‘#GzÚÅÒ¸qcÚ´iÀÆâ¡ýÅ_L­ZµØ³gÙÙÙÀïïúûî»ïxâ‰'ؽ{w±yV{¬ëU¦çlPY×YÃ0xíµ×˜;wn¡é Œ;¯×Ktt4cÇŽ=­í‹ˆˆˆˆˆˆˆÔ$gu}( ýõWæÎËôéÓyÿý÷‰‹‹£Q£F¸\.:ĶmÛp»ÝtêÔ©ª›[aÚµkÇõ×_Ï_|ÁìÙ³Y±b—\r ‡ƒ5kÖð믿ү_?²³³K ¶Ÿzê)öîÝËâÅ‹yýõ×ùðùä’K¨_¿>iiilÚ´‰””ž}öY®¼òÊÊ=À3ˬY³9r$‡bРA´nÝš:Bzz:[·nµKºTEéš’ø×Ù·8×_Ïž=ír2PµÇ2uêTúõëÇáǹîºë¸ôÒKiÕª‰‰‰,_¾œððpþüç?óŸÿü'àú]»vå™gžaâĉ¬X±‚Î;Ó«W/êÔ©ÃÆÙ·oŸ½ÜsÏ=Wb;úôéc‡ñuêÔ¡k×®…æÓ³gO/^ @Ë–-Þ$ÈÎÎæõ×_çõ×_§E‹têÔ‰úõë“••ÅÆ9xð Æ xc &«ŒëlïÞ½ÉÉÉaüøñL›6:ššÊ²eËp¹\3}út¢¢¢ÊùèDDDDDDDDªŸ³>Øw:¼óÎ;\}õÕ¼òÊ+ìÞ½»XïàÐÐP ÀM7ÝTE­¬Ó¦M#<<œO>ù„„„{ \kÐË'Ÿ|’n¸¡ÄõCBB˜={6o¾ù&¯¾ú*ÉÉÉ,Y²ÄžoqqqłњàÒK/åÇäÙgŸå‹/¾`Ïž=ö¸–V­Z1xð`.¾øâ*je`—_~¹ìתUË®_HÑп*ƒý&Mš°`Áî¿ÿ~–-[Æš5kX³f PPƒÿ7Þ8éÓwÞy'Íš5ãÉ'ŸdÏž=vøÿ®ÇÇO}웽{÷¶ëà]ÆÚvI¡üþðÈÊ•+9xð ä[êׯÏwÞɃ>Xê1ÕD•q áÃ?d„ ÌŸ?ß~ÂàüóÏgêÔ©§U"IDDDDDDD¤&2ÒÓÓU?Kíß¿Ÿ]»v‘™™IXXM›6¥C‡„‡‡WuÓ*ÍÑ£GY¿~=¹¹¹4lØnݺÙÈ–•ÏçcË–-Ÿ¯Â$"""""""""""§G5öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ•4Ã4ÍÊl‡ˆˆˆˆˆˆˆˆˆˆˆ”z싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDj€| ÈÀ ƒ40³€<ÀWµM)GË—/çºë®c̘1dddTusD¤š2ÒÓÓÍ@3ÂÂÂ*»-"""""""…™¹F˜™FàÓ†Æ4ÃÀ¨iF‚QpVqƒÏŒÏô‘éÊàHÖ¯$d"#7‡aP7,Šóê6'¶ÎyÔ ‹Âaî§wÜÃS?¤æ3MÓ41 £LË—u9Ó,gfýlš&‡Ó4q:«÷¿‰´´4.jß–;Zgg&l‹hÇÌ?¦C‡UÝ4©"yyy§•´B  äéòz½äå呟ŸÏW½zR8‚ƒƒ «ð‹»ÎÙñù|äççãõzËõýY ÃÀétŒÃQ±Âè<Ðy(YVV»wï&##£Ä‹MFTTmÚ´!22²ª›#"""‡A˜É`¦cp Ì0]€0ÀÆ Ó¬A¦Ù“h0«ºñ§,/?—owÍgáî¯Øö[<ÙFÎΠ‚Ï“>¯Û¤uésÚ e`»a;‚ímäæçÑï&°>ógœ® îw=LTX½ m·ËåbÕªU$&&bù;7;'‡üüü Ý¿%$$„Z4hЀþ”9 –Šåóùðù|„‡‡üœÊ4ÿ¿ýüCû¢ß}¸Ýîjß‘ÕápàózèÑРO#Xzt'ú^Åko¾Í°aêºy"R”Øc?44´\vàr¹HKKcãÆlܸ‘#GŽ”ËvËKll,]ºt¡K—.Ô¯_¿ÜŽ»(‡3ãñxÈÉÉ)öaÀápàõz1 £ØkŸÏgÿîÿ³õ¡Âº¹b¯Ö÷¢ó¬u­Ÿ­×AAAø|>‚‚‚ÈÏÏÇårL­Zµ *ñž™ÎƒÎC…:tè[¶l©v7;*ŠatêÔ‰æÍ›WuSDDDÎIGŽaãÆög,ë³—õ¹Ëÿ³VI_þËÙ6La¡Y„‡gžMXH¡¡¹„»q:=€Ÿ¼^—;ˆüü0Ú¶»”f-.Æ4b±@íª>=e’çÉeÞÖOøÏ/ÓÈr¦S+:Œ°º!8œ…;ˆ8 'AŽ Ÿ“ÜL™ÉYÔöDq×%÷3´ý x¼ù<²èÿ±-w#í;üíëv1ï¦EÔ ¯_amÏÍÍe⤿³2§ÙµÏ¿0ÖðyiûëÅÞ's®ž‡„„Ú¶m œ‡Óáv»ÉÌ̤~ýú¸\.|>ŸÝ;88—Ëe­V/i+Àu8ö ŸÏ‡Ç㱃]+Ѕ½´­^ØÖ|«'¶âz<‚‚‚¶ãs¹\x½^BCCÉÌÌ$$$¤ÜïÓy8·ÏCYþ=íÞ½Ó4iÖ¬ÑÑÑUR¨2†App0ÑÑÑ@ÁS »wïæâ‹/®â–‰ˆˆœ{òó󉊊âøñãvÉÓ4 )Öq¢¬½tÆ1œŽ£F"ÇQF2# ‡‘ÃÈÆ0\€IA°ïjY»Q‘9`&t7‚À Ç$–êZscâzþºà.rëeÝ&ÃQBú<¾‚*C£à ÃAáÄi8q:N|ú£ê…Q?ª‰ É9vœ /êDHpÞ|PñáþÁC‡ÈŠê >wžâî‹…úÖÏe-cküþ=?¬»<Á?Ìfô˜1g]g—š®èM½@AÑïÖ=ÖÿàÞ?è÷ßV ›Å4M–.]ÊܹsY¹r%©©©téÒ…›o¾™þýûc/›ÍªU«˜?>_õÍ|¿1°©ƒ;ãà—Tx>ÞdsºÉ±ü‚«Ó€M ž¸ÈÁÇÛrÕUW1kÖ,Ú·o_¡Ç$"Õ[…û‡””’’’*r7å"))‰””š6mZîÛÖy83>Ÿììl¢££ñz½áv»í× W­^Ù.— §Ó‰Óé´{kv kõöµ-½bmËápØû‚‚šþõø<=Íê%Fvv6 4ÐyÐy¨ÐóHFFõêÕ XJèlaÝpq8Ô«WC‡ÙÇ."""•Ë Ê¼^¯ý™ÊzÂÑú¹¤-p‰ †#Ìß0Œd ’qŒÃHÁiÃpƒ > 3È_õ¢r1Hœ`†µ€HLêVØñŸ®ÍI¸÷›[qÆú %óHy.ÂÍÚÔ®ƒiúÈÈOÇê¡vý¢¢#qôØ2‚p:‚rœønѲÕ¿O3‚ÀðR9¶Ïë-ÖSßvû7M³P o½.3¿}zB"Y÷/Þ^úOòóßSYžjÂÿŽõ·•Õ ®VÉ «dŽõ·Óé,à}o½¾ø˜[ýòË/ :”±oP¯lJû‘Y_ÆÄû!¢~cêÖ«GNv6éI‡iUËËe ^lgp七ÅGL¦l-8¦àÿ¬‚àöׄ¯59˜mòTkSv1ðÿ®bê´7¹îºë*üØD¤zªðR<§ÛK»*äææëURtÎŒUÏê)íõz #//ÐÐPrssí?¬^Û^¯×.Ëb­S4àôïÍìß#Û p}>yyyvïï¼¼<""" •u±zk[ûòz½…Âc‡Š:XåZ=XÎÆP(4Æu¬gë Á"""Õ] `Í? +:ïd¯FNã# ‡#§#‡# §ã†#Œh £ x1Íã`¦ãp¤P72ƒ4LÂ1¨ƒI ԪϓŒi¹©<´ð^Ìò2=Ô΋à†6#èÛkÍ£Î'4( L“lw6Û’ãùfçYµýGê4Ž a“¿÷ØÔ‹ÿÄÏ•ÐY¿°3ØŸõ²k¡é­ʽ¬‹„û›»LâýŸþILÌ7 2äô*g¤hÍûÌÌLöîÝK~~>qqqvÇ+·ÛM||<ùùùtèÐzõ 6 Ãþì_´Ž¾Å¿s“ÇãÁ0 {»%•+OÖ>–'›ü_¬Áyµ zÆ@ϯÏ$ÝÄqo¡õ¡^HÍsðÝ“¿­ó‘™u‚ ahA¡1—·àËW¤¹ñ0÷ É¸ÖšÕÊæowÜÂæÍ«î¾È9ªBÿÕ½ÈVwÕ^‡3gµÇ꥛ŸŸOxx8¹¹¹öw(¸ƒo…ªPðh°Õ[~ïId•`"HœØ¾ÕsÀúÑívÛí.4ÐŽ Ù7C*òÜé<è<”…u gc¨o±ž¢P¯+‘ªå_£,Á}é¡¿‰aäâ0rp8² ¾ÇN”ß©Fc £õOÔÎ÷b˜Y`†aú <<ÃÈ¢ —~Ù@&n |ËCSÆÏ|^ÓNj˟&ÕHÂL5Ôb8ôz„èˆâ5èë„FÒ¤N,}[õgÓÑõ<÷ã“ÚµŸÖZÔÛ?Ñ[ßi}9~]©÷1 û§ð1ÍW$ô-îŸH÷tÛâ«GÂy8p`sÙ$.##ƒØØXÈs¹ˆ/Ãú+**Šôôt;؇ÂåvŠNóm•í±zøW¶<±ÁÇ“9èÖ `ÿN‡Aô‰ËÐÎL“7wùX›aˆ †&á>³ g¾Çg|7‹ûNÚFl³M¤Á+›<ÿÎ ª»/rŽÒí<©1¬ ÏçóŠËå²C\ëgÀ.ÉbÕV·Vkÿ°³hˆ á¯ÕÀãñ؃¢ºÝnÂÃÃ1MÓŠ­ÇŒ+“Îö>uDDDDª–'†¢¡ý©‡û&#чÃÈÃaäbÇ1 8¢0Œàh‚a49QŽÇ f*¦ ‡ ‡³¦ï8޹¿™n0*&ØÏÏÍ`ãï"?· eWM“'ßß‹3ÈÉ—>Æ-ý¹LÁãE»ñÞðOùû’¿±vû þбM±ÞúA'~²{ìWb yšÁ¾Üûù>«ωi¾S-Ű-Õç‰s™Ï4É÷šx|&µ£¢Ù±s˜8CÈË71  )ø[ëØ±ctîܹØ6…úE§U‡Î?¹^øûF“:;èÑð÷öÌ9àãÝÝ&¡N¨ AFA }—·àVA°_ðå5ÁúkÕ:FÁímtˆú}{uC þÕÞݶ>W\ÁìO>¡C‡•y¨"R…JL Ê£—©u—ôT”gÙ ÿ2˺ïŠè­~:ç¡*Uäy8Ýõ¬÷„æBA½=«üŠÜæçç*‡â?ø©Ûí.ÔÓ»è>¬ÛÖ<—Ëe¿‡<vikEÛeÕc¯¨ó§ó óàßF)LçDDD¤ò•ôÿïÉ‚üÀó}†0ò1Œ| #ƒ00jƒQŒÆàhfΉ dF¸0M7¢·~~=™íe×O“ip^KÚôz®Lëìúi*lÞŨη3êÂq'¶S¶¶……3©ÏÓ úð ÒR z;ê­ï×cßç(+åiì’2Ô“d«EK³Øáþ‰Ÿý_Ÿq[üöY•œ?Ì è«ÿàØ´üŒ¶ç»èr&^hpy£‚¿+¿ýÕ+Ì÷ׇqâß+=ô=¾‚uó}5ö/‹†ëš;èeØcgøL“Tdº!2¤ ð_–´—Aý®fÊ«Ó>|x…£ˆT/Õ¦k©iš4iÒ„›o¾™ .¸ XÐvª|>ûöíãÓO?%11±Zܱ-OÖ Ã0ìï†aœñyg4S“ IDAT«Î¬@Ö?Ì ³Õó/¹bÕ`÷øÔê­m…ºþõÇ‹ž·üüüBuÊ­²+áááÅÂ\ÿïÖþut*ë<ˆˆˆˆT¥¢¡”ä—a˜`˜':_›Ô•qN ‚ zß‘'‚Ót`àø½/`bRпbB¼£ÛþKvòZº×ñ•eZç† ;PûÐzºGµ+¨… Ž»sxzÙc„Ô "¦aÃëë;N|tÌ%:Å?·íP¿È÷€á~¹ôØ?µöIÅH;îeO–\/'Rl^wA-üºáNBœ¡A‚ ³ ì.’ã”v#Ñ?´w:öÓÕþËT…|ž‹7qû|ômâàæ ^ÙfÚõóýƒ}ŸY°|¾š„C¿Xƒkb ¢C }¯Ïdc,O2Y—Zì{Í‚õ{4„ í4‹ÈæÑ»Ç±yófþþ÷¿ŸÕ‘ˆTB°_Öÿ„óóóéׯ±±±v 3Õ´iSúõëÇþóŸBu°KR5ÁÏ„Ïçãÿ³wÞñQÔùÿÎlɦ‘„"5ÒBè €HÑóh¢¢pÊY8±+bá§€"Þ}EAÅÃ;‘ÃC¤ˆõÄñ¤ŠiRH'Ò7Ù6Ÿß³3Ìn6•l²Ñ}>0»3Ÿùìg>;;™y}ÞŸ×;%%…®]»’œœLRR‰‰‰Øív233¹pá‡fË–-zâÏšjkU#„xL²,ëb®¡­ ¾Æ×n·»˜·qfˆQÖÊj­ÕjÕE\—Ëå#—&“I6 ÷C¸ª£„ &L˜0ajš’f[WNÜ—QQÍhB¾À 8§º .¨þ¢D.‚"À‰ðFæ É„Ð$­®ª%?óégÐá7b¶„RP®ýl¸¡ÿ`v}ó&1ñ͈NlQ®ýò\vž_3™ƒÎ½tèÜ‹Éâë³/ûFí{¤j̵TA1]·ßñòãkƒ¸o±XˆŠŒÄ@ ŒŠŽ.÷çÖ$Z¤¾uÖ#H ¼>è½RÔ¥¬5ZòYè¿^ãuSVºº»·^§·T¨FîŸ/ðp0[¡À (Ó…ârc’d’㬲L£X3Ñ&& ›SEQðx<Å’èº\.Ý.UÃßs?eOuâðúã0¸±L”YáßEê#³ WDA÷$‰>Émë¨íW„ =OðÝÁ÷gnˆðºmYdðx6dÀ¯ù Ó»ÊÌì&xõý×Ùµkï½÷žOž‚0aÂü¶zòÜòÚêѶm[ݲ¦°°¢¢¢J}®Íf#Ò›x¥mÛ¶8Žr ûÁá*Ò%aµZ¹ûî»i×®O;N'f³™ РA:vìÈ AƒX¾|9?ÿüs¥FgCMŒÔnúŒâªæe® °V«5 Ðk$2z«kýHÀ5®×ÄY›Íæ#âjIYµ¥¶O°lWÂýî‡0a„ &L˜PÄÿ9çò"÷M Y á]B>ˆ|Y¢@ÊÜ‘ ÊUàWòAJBM”Àê]Ví,J»ˆýßý•]Û“`FÙÚ?&ÎD‹.mØ÷íSÈ&k™åóÝnÞqe‘S?’Ô´¶˜M¯åŽ)`Ô¾*~ò4TcTuI‰rý£ø6lÈk3f|¦Žöö+i &ø!ÈÈ÷p(GM.ë*rs1¥ÐIRR.ÉŠŒB»DgîCx\¤¦¦úˆÒ§˜ÆQ–~aŒæ¯Iàû.Eá¦&2½ê Ž@®¢-Ð bÍ—¬vr‚ïÏ)¬<¥–‹1C´¢ÍNEPä)žX÷¤þu@áÅÎ&þ¯³Ì¼ýßrÝ€,\´ˆöíÛWû1‡ &ø„”Ñ‹~Ú´i8p RuµiÓ†_|ѧîÚŠ¢(\}õÕÜxãz¤pih–#wÞy';wfáÂ…U–³ Ð"®K ³Ùìó^Q=zzóæÍзo_}›Ö/š¬Õ©¡%[µÙl¸Ýn×è¥Õ³PÙ~0¶Uëƒp?Ôþ~|2228pàÄÅÅ‘ššJ\\\M7+L-Çáp°wï^233©[·.©©©ØlÁIî¦t}ôQŽ9Ÿþô'ÆŒã³mΜ9|þùç´mÛ–7ß|³ÚÛ–ŸŸÏˆjäåÔ©SéÞ½{µ·¡¼¤§§óØc0wî\š4iRÃ- SïŠ'à ü¾tq? !E!ˆVÿ‰‘,e# 5XK`( ò€ q—«A,ƒ$Å D4 ”-žWÓŽ=û8Rú‚È©T®¬Oý¦ñ”uËèVƯß@¶9’Öm[a1[½â½I_ʘ‘‘%õŸ K* ¨ë‘ùF ?O}£X+Ë2ñññåoGŠøš§¾ÔØ{õbÕ¥Õ;›Ää}nñ Ü×~K÷9%B•t$“ïç„jÄ~F¾›Ãy& ]‡ÝžHv…l\DEšp¹ábB‚ÍFlT'Ož$..Žäädl6V«zÓêñxhݺ5Ï<ó Ó¦M«Pä~(”4ëÁ(æj‘×þØ&“‰Ý»w#„àĉôêÕ‹FóT7úµ[­VŸÈo£­‹Ö-:Ûb±è‘ÚöPí§Ó0Â!ܵ³‚…‚ôôtvíÚÅîݻٵk‡ÂãñÁöíÛkº‰ÕÂŽ;Xºt)_ý5ééé>Û$I¢OŸ>L™2…Þ½{×P «‡={ö胢¥Ñ´iS~þùçjhQÍáp8صkÛ¶mÓÿýúë¯!¸þúëùøãËUËåbÚ´iÌ™3‡œœK‚P:uxà˜/xe·‚jt¾UV]šœ5gˆ"T[·7Á®1bÿŠ("Ó¯ïuv@‰fÑ<ûàÝüüóx&Ožìcq&L˜ÚMHýšµh}“ÉTéÄ“&“ɧ®ÚJBBƒ ò±ÉËËcÅŠlÙ²…¬¬,=i§Õj¥I“&ÜvÛm´nÝZ-###9r$Ë–-ÃdªzoÉšÂ?:Û¸N‹ªÖ(((Ð}ø<k×®%99™=zø¾f³“É„ÕjÕ-^Œç“fÿ¢ÍŽôÄÅÕ=(RÞ~ø÷¿ÿMff¦O¹øøx† æ³î›o¾!??¿X¹‘#GÖº~8tè1114lذØùà8{ö,±±±z}þçÃÇÌÅ‹HLLô雚âèÑ£ <¸¦›Qã\ýõ>×ßèèh¢££9þúˆ¿ýío¥ ‹-ò¬¨©žP¤4ŒŠ'ÏÕ:'Eä#aGEHx-•,.‚Èö†( n@FñdgÒD$”„D„¨4QWÙA׋­¼Ü³9®ò½9n~ú&žwþ(KÖrXý\6%zìËìnÿϽûu”.­%‡TþúžkŠã—´G ^õ¡…¼Sô¤uåýoõ>Ãt½]]¦¯V—…~¹‘Þ¨õ”ëÔåö¥êÒìÝß;@^³® []õ8Ü‚,ÈnP\ Ün7¸e·"(t ÍtìØ›Y*öŒç?°¯å`Ð^ðþúÕµ/ãMˆëMŠ+!T!^{BüðˆÀ©À_®ÙÛ®oN)8<!« tÀd¨CñFé;u;@Z<ÜÒT¦w=5J?-c%ÞìöÝæ·HP…}clyðãѳ¥2Â~EÛÌz].£FB’$ýXöïßÏüùó),,$&&†ÆëÁ‡¬¬,fΜI¿~ý¸õÖ[õ?piiiìÚµ‹ƒ–ëY°ú¡²£€Œ^êFQ×øÚßÎÀ½™™É7ß|Cjj*M›6Õ˘Íf=Aªñ³´zµœÚ{³ÙŒÛíÖo´ï#˜Þò•é‡ÜÜ\=Ýn÷‰Lô¤°¥•«-ý°`Á<]»veøðá>çC^^žOÔÿš5kðx<4mÚ”Î;ëåƾÌÍÍõ±ªÎ~¨¢££IMM%--Ý»w³uëÖšnRµÓ¾}{þò—¿0pà@RRÔäfv»>úˆ)S¦““ÃÓO?MÏž=IKK«áÖŸ>øÀçši¤ª#¨C™äädºtéB—.]xÿý÷9wî\¹÷1c†.ê¿ôÒK<ñĺ¥×¬Y³˜4ik×®eÚ´iL™2%X‡¦Œ;–#F胿ÕMLL ßÿ= æŽ Sµ$%%‘‘‘Á·ß~Ë!CJ,÷ÑGéå/\(;jú÷„1Z?++‹èèèb“å³àÑ^K %"(DÁ$Ü^!Ì„ I IE ‚zêä{o[•¨ †ç+¡ÿW¥DHQN}Þ©(Äñqj –˜¸úÉKhÃæ>o€òó¥$SêNhêýaŒ£<~?%ÿè{EQô™ÑÆØ@b¾¢(ºmjuJH¨ÉmeIø5UÞ(Ì{¼Q÷KŽ©âþƒ­UqxS™Ÿ.(8u>’Yø û.\BõÛØHbpc‰1¾×Ñ‹Áºs‚-™‚#ùêgvK’¸¯•Äÿu–™à[ú÷ïÏG}öÝæ7@‰Â~UQÆl÷å)kç„äçç3zôh–/_^¡hó@uU¤­U-ÂU´^!ýúõ#11Qõ³²²xï½÷0™L$&&ìÐ"Š­V+6lÀb±póÍ7ê ÇСC9xð`…ÚŒ~¨ì~šHj—ý£´EHÛl6dYÖ#¨µr þ±ß³g'Ož¤[·nDDD`6›õ?üÆÏÓ[-z[ûlmvca6›ƒ~U¦ŒÇ¯á/†—V®6öƒ½ñóÏ?“žžÎ-·Ü¢ÏfQ…¼¼<ÝÞJ’$"""8}ú4tîÜ™úõë<ŒÞý5ÝÁ¢aÆ|ûí·4oÞ\¿I|á…B^دê>ùðÃ2dˆÏÔ^PgBÝwß}´jÕŠ!C†àñx˜;wnxoWÆ~íС­[·.WÙß"C‡eÈ!4lØP_·|ùr]Ø/ëøsss™9s&·ÝvO=õ”¾Ÿ$I<þøãìÙ³‡E‹1kÖ,{ì1ƒt4¡Cy®‘ÆíÁ0õ¯»I“&º=dMœã²,ûX•Ö†šþ Vç÷TUÜ~ûíÌž=› ”8[mÆ 9r„¸¸8 Ä¢E‹€šïïPÁP•““Clll©~ûå‹â@Œ@AA,‰L,v$ŠPe/ !,@MæÅ#(¢1BJFˆâ†Ð.„?+G¡àÇÖ?5‹É–Àæèï=nõR†Òz@gõ”*œK—Làk˜ÿÝjžúz¤þ(uyÃDuÙíÏêòÓ‡|÷»õu™ØÜ»Â»ÿöÅêÒíÛ¿5~œ~”ØžRš((±´ÙAþÛüÿi¯ƒù÷I,©_¯IòFíkÛðö]Š*îz\M„ûx;è”(1½«Ì?ö)/·w_Y‚¤èš$qM=‰®I`1Dç{„`çEXqR°ù¼Ð'®hQÿßl½ ˜ÜQæþV2kÎaÈðÆ[³¹í¶Û‚Òa„©‚nÅS‘ f ˆýÔÔTn»í6–/_^!°ÊDìWçCbi¸Ýn’““uÑQÁüùó‘$‰¨¨¨R£î­V+ ¬]»–öíÛÓ¢E @¤lÞ¼9G-sD¨Ý€o› Ù¥­×Ä}ÿãÖÖðý÷ß“ššJ§NŠy²kášÏº–„U‹â6Ök2™ªí<ªH?”vüåYWûA¤e»Ý΂ hÓ¦ wÜq‡žô477—ËåSVQ¶lÙBƒ 0`@±óÁ8ø¡M=¯©~‘‘‘úµ£¢ê‰ÏëׯO£F–óx<ìÞ½€¸¸¸J^0:th©ÛûöíKJJ éééÅ¼å Ø»w/ ”””3Æívë9 hÕªU´û¶nÝ:`Âɼ¼<¾ÿþ{öíÛG^^IIIôìÙ“ž={–9»SÁ† ظq#4nܘÁƒ×ÚD¹wÝu³gÏæ›o¾áâÅ‹Ó.\ÀÈ‘#ËõwÝáp°qãFÒÓÓ9sæ Š¢Ð°aCz÷î]â쮳gÏrüøqÚ´iSb‚ö¬¬,:¨¹M.÷ºTû¤Y³fDFFêVE%Eê—/r?A#&$EƒˆÉ®úì{…}°€ˆÄ£D‘™…š D=„T]ü $%GØÏ»1õºÑiГÁûÌJrþèVNî߼фµaBŸ@×TÛÍÞ=®":uêDttt±}ŒÑüF«P@‹ØW…}I¿ ©Âþ%Ÿ|³tÉRçëS—O¥B‡‰wzÉχ µ®‘ª°/û£Ý-øþ¬à‹‚3vˆ±@’Mõä/ò€Ñ(2Û Sv(|ØG¦‰&Ñ…L~ì^víÚÅ /¼öݦ–R¿Ü@ÓZmÛ¶å¶Ûnã“O>)÷Ŧ6{ì+ŠB“&MtaÿôéÓœ8q‚ÄÄÄrý±2›ÍDGGóÕW_ñÈ#èëãããõ©kµcdv Oõ²TÞ(ÐîÝ»—3gÎ0`ÀÝjEK^¨Ea#±Ý»ÿrl£*Jeú¡4_–eŸd¯ÊÕÆ~0‹6]óðáüöÚk <˜N:!„ ;;;`Ù .ðÙgŸÑ½{wÝ‚EÔ0–ŠŠªÑ~5"""˜9s&7n¤nݺ|ùå—Ô«W¯X¹7Þxƒ¹sç"Ë2|ðAH ûåAó¦t¹\>ë###ù¿ÿû?Ö¬YCýúõÙ´iÉÉÉÅöÿÛßþÆÌ™3‘e™¯¾ú*díÊî_þ÷¿ÿª•G×®]–iß¾=5âôéÓ|÷Ýw>ÂþÊ•+yå•We™/¿ü’þýûÛÿÛo¿å¶ÛnCÁóÏ?ÿ»ö¿ùæ~øa"""8sæ Ï>û,ï¾ûn±rƒfþüùÅ‚²˜5k³gϦGº%N Ï>qâcÇŽeÙ²e>e&NœÈË/¿Ìc=À´iÓxíµ×|®/½ô£FbΜ9Åf©æççsÝuª§ògŸ}Æ 7ÜàÓ.>ø€>øÀgßÅ‹ûäÓB0sæL^{íµb9u:vìÈܹsKœšúôiFͦM›|Ö?žñãÇ3|øð€û…2­[·æª«®bË–-,[¶Œ‡~Øg»Ýnç³Ï>ÔA€ ”Z߃>È_|AAAAÀíýû÷gîܹ>3@½g5jçΣoß¾|õÕWÅî#Ün7#GŽdóæÍ$''ûj -ÐA’$L&“žs¤¼¢~Iâ¾åÂÈDq(ä‚°$@B`FØ·‘‘š!D4Aõµv Ç%a?ËD„-OáÁûÜJ’}êbêöÞÔa?TÚgòž—ZHõž•ê²³×c¿ž÷žø6¿¿c ÞÁÓóG}÷Óê1ÕŽçŽb2~€±Ò"‡‹ÅB\|,çÎóyNÐfãú,n¸$î½ôÍfs1Ñ¿:‚®$oľY’T;ù§É+ì ÜÞm²’¢FÕ»Á3i2Y¢E,´(Á0Ç)øì¸Ðâ-Ð0ÜB©}V€ÿÑF™Áâ=URb%fvLÿàïìÚµ‹yóæ &Lhta¿,¯vÍ'M’$ž{î9}}RR’n©ãt:iÓ¦ ·Þz+Ÿ~úi¹ÄýÊxÄÓW¾¼u !hÚ´©.¶‚yY!‘0""‚ÌÌLÝï ^½zåjG(ùëkhçB >(É[Þ(®¬h­ÝnçË/¿¤cÇŽtëÖM±M&“OT·±~íÆAÛìHõËé‡@o†J*g³Ùj]?ø{/ºèþÅ_°mÛ6î¸ãâããK-»iÓ&ÒÓÓ8p >ûC+«( QQQúk¨Þ~EdYfÆŒÜtÓMdff2~üxæÏŸïó]­[·NÝÆŽ[é(ÚšÆn·³oß>€bö4²,óÞ{ïÑ«W/2223f ÿùÏ|úá»ï¾Óí{&NœHß¾}«¯ñ•dË–-¬\¹’œœâââhß¾=={öÔþüVû¡²hçK‡J-×±cGNŸ>­—ט8q"6l`íÚµŒ3¦Ø@É™3gxàBп&L˜PõâŒ7Ž… Ò·o_zöìIaa!kÖ¬a÷îÝü÷¿ÿå™gžñë’Ç{ŒåË—3hÐ ºtéÂùóçY±bgΜa„ ¤¦¦²aæOŸN·nÝèß¿?.—‹U«V±oß>/^LÛ¶m?~|¹>¯W¯^8–/_NNN]ºt)6`Ô¼ysŸ÷>ø ‹«¶ W_}5×_=‰‰‰=z”%K–°k×.n¸áÖ®][l€-??Ÿ¡C‡rèÐ!dYføðáôèуüü|¾üòKf̘Azzzå;°¹óÎ;Ù²e .,&ìþùçäççÓ¦Mºwï^¦°ÿÝwß!Ë27ß|3iii$$$pþüyvìØÁ·ß~Ëš5k2dëׯ÷dª_¿>ï¿ÿ>Æ ã‡~`úôé>ÏFS§NeóæÍȲÌûï¿Oýúõ«®.ƒÒž./b_C³åI@¢(DÂÀƒ`F’£P„•Ì‹Ñ[-"®ÀUöE‰¤æ‘ 4«irÏgШkÉ3½Â„©„ 4 á÷{XÌfŠì\…ù>‹4±¾Xø öšo,[]ýñññ˜-€«)€î¯/y…}á#þ¯9Eáù2VSñöºKŽ ¾8.$ˆ³€Å"!„ê½ïVnå’Ý‘.‰ðTªL¤Y­×­v\d9[W­bûöíz A˜0aj5±ŸŸŸÏßÿþ÷·ge©Ùà=­Zµbøðá|öÙgeŠûµ)b¿¨¨ˆ›o¾YŸúkL˜ Ю];}Ú®ÛíÖ#ÁJûÃ$Ë2‡ƒììl}Êvƒ p»Ýµ>ÁaE8Œ‘Õeý!7™L˜L&Ìf3;wîääÉ“Üzë­ÄÄÄŒ7¢Í®¨N*ÚŽ!11Q(«S§N‰åJÛf$”ú¡¤ÁM˜ÏÈÈàŸÿü'}úô)µlLL ¹¹¹,]º”^½z‹Ø×¢øÔD?„õêÕã7ÞàÞ{ïeÓ¦M¼ýöÛ<þøãœ?žgžy!½zõÒ#Xk#ï¾û®þûùÓŸþTl{rr2ï¿ÿ>7Ýtk×®õiΞ=« °ýúõcâĉÕÚöÊâ/x:kaüøñŒ7.àïè·Ø•娱ceZ–\qÅ>å541/Ð@‰ÇãáÞ{ïåÂ… º@ø{›5äp8Xºt)K—.õ±Òr»Ý<üðÃ,Y²„E‹1eÊ”*·/q8|ùå—|ñÅ>ÅÏ?ÿ<×]wGeܸq?~œ×^{G}T/óâ‹/rÇw°jÕ*fÍšÅOøÛò×ׄ5OJJ ³çÌ᱇"Êì$B–Ôä·Ú$£Ç¾fÕ# ŸÜ›ÎÃßv*LîxI„pzã·*͇h³:+À#@QÔp{}ûÝa¿U¸»¥ÌUuÕÏsxß|ú«àL᥇P±2 &LŪ°ïŸÄ6Š¢™™Y®ú<W^y%7Ýt_~ùe©=•öýoJ«Š²úÁãñðý÷ß3fÌý!ÜØþºuëê¯W­ZEvvv¹¦HY, õh -ñiY«*‹öǺ¤ˆôÒ0FoWDàˆŽŽ¦  €%K–èÉ %›5FÃk¯ƒ•Œçrú!ÐÀ†,ËÔ¯_EQÈÉÉ¡nݺ%–3FãÖ–~(k0GKŠûÃ?`µZËUvÓ¦M>eµA‚šè‡P§wïÞ<úè£Ìš5‹Y³fÑ£G®ºê*ž~úi.\¸@ݺuyã7j­ðøË/¿ðòË/ªSRÂE-jzÚ´iLŸ>>}úЧOÆŒÃùóçk•MÛ¶miܸ1&“‰C‡±gϲ²²˜‰-a^µm{aa!ÇǚŠäÕW_eÒ¤IL›6õëׇ\$ouóä“OËa6›™:u*K—.Åãñ°~ýzFŒQåŸýôÓO‹t«W¯=ô'NäèÑ£ :ÔGÔu–å„ XµjçÏŸç—_~¡cÇŽUÚ6—ËÅk¯½À=÷ÜSLÔõ~sΜ9\{íµlÚ´‰;wÒ©S'@Í—1þ|@à3Šú þÝ{íµ×øî»ïŠ HÕêԩðaÃX¶l .dÚ´i€šÇ`ݺu˜L&FU®ºJKBسgOÆÇË/¿ÌçŸ^LØU´_¿~=?üðƒ>3GÁý÷ß‚¾}û†Ü ¨ñÞ°¤„¹ÚëÊÛòøÔŠf³#¼Ñ¾jYOÝs¹œàöDi‚ö]EN°Ø‚h±áoÅ#’OdÁÙà}f)F7ä\Óþ ý¶ï+~s X­ØÌê* ¿´r ùªƒ‘#Gât:yâ±Gh«a’¼Â¹¯°¯EóË’„„*Π￟.À‹?+üµ³L”WÜÏpÀá}šM›6•jIqúôi6lØPn¯}›ÍFRR’>HpìØ±r‰&¡(BjþyÕi±$IIIIÅêðqýëöyT™~d5ãñxÈÈÈ 33“¦M›–hIcdªMýPÞÁœˆˆˆr‹‰þem¨‰~uÆŽËO?ýÄ?þÈÓO?ÍàÁƒu 7Þx# ÷~m 33“Ûo¿‚‚êÖ­[f„ª&Ò¬[·Ž1cÆè¶šMM ÏùP¢~ýú,X°€AƒéùG4vïÞ̓>ÈîÝ»ùä“OèÓ§<ð@Àzj{?\..—K\×ò–”„1Ò·¨¨¨˜'|ÿþýyöÙg™>}:Ó¦MC’$]´0aB@ïýß wÞygÀõ 4 qãÆœ‰ÙNž>¾\ís»ÝtèÐÁ§N:U®džÁê‡ÊÖ§Y™h‘ŽþZ_·;NÜn·þº¼Â¾Ûí&66–Ò¢E‹bB¹†ÿ:ã{­½Áè¿Êöƒ–ÌÕˆ$IX­VòòòuFHIåJ"”û!бh¸Ýn¢££éÚµ+’$qàÀRË&$$0pà@6lȶmÛŠ%®©~¨ Ô«W'žx‚)S¦j’YÍo¿ª vŸäççsóÍ7³sçN¢¢¢X¾|9]»v-×ç&''óüóÏóä“OššÊĉkÍ÷X Üwß}L›6ãÇsäÈ‘Îßr?@Ùç`tt4¹¹¹äåå•ZVvm6[‰÷;²,óæ›oÒ½{w@cß}÷ÝZ™´»<÷þÛ•×ÚKªK»f{<%Ûu”v½.m›&†—uV«µÌöù÷‡ÿëÊ´/##C¯{ìØ±¥¶Q#77W¯ïâEÕºnݺ¥£Ñ>2”­èõ©$IŒ5Š×_… R§NŽ=Jbb"ƒ Ò÷)MDB0iÒ$Þ~ûm}]TTõêÕÓé 9yò$ âE(# `øðá|òÉ'€*õïß?$û4ˆïÿ¾ªÅ}ãgòÛ®„A5ÎÍ’¨“l 9}€¼ ù$¶m´~Ñë5~Ukž;gýí¤½.Ey‡¿£.“šªËŒ_}ËÕ÷zîß=O]~öºÌ lk\SÇ)Iw\4ÇÛ¦ +Ò%!PöÛ]˜LNüŸ°›Ž;°]mâ@®‚d`ɘd„G¢žE¡iûúœ8¹›žm }ÁGŽášk®aãÆ\sÍ58NÎ;GëÖ­9|ø0íÚµÓ?«:σ‡~˜¢¢"f¼4…kë "LŠ¼Â¾À8Æ¡PL!¼ vUKƒ¹0q›Â+]e#$®o(q]ÃÛ‰VYµóÑ8œ'XvLðS¦ }œÌmML˜$p(ê`ŒP½ýQ“÷š<&)8Ϭa„ >5nÅÁ‘#GPÅ'Êoîܹ>¢êÎ;Y½z5 åŠ:¯MV<6›sçαeËzô衯?}ú4[¶l!!!¡\£ÌBÒÒÒhÑ¢…±ït:9þ|‰mku£ ¹ZÛ$IÒ£¨]ÄW—Ë…ÇãAQ}YšÈ —"²»téBß¾}ußôŠXÏ=ÕƒEeûJN2«EŽj¢ÊÕÆ~4˜£õMZZÉÉÉäååéÉoK*Û§Oºuë¦Ûîø'Ï­É~¨ äççûXÕ¤§§³cÇ]Œ¬-0|øp¶nÝŠÍfcÉ’%úƒCyÈËËãÿø‡þþÀüøãµvæ‚?:tÐ_Ÿ>}ºDaÿ·ÞeѬY3vïÞ­[¢”„&ú5kÖ¬ÔrZžPgš-^¼˜ñãÇ_~C«c”raaa™å5“ÉTê «0¥Í /¼P®²mÛ¶Õ_š½ˆÚ4c6wÝu¯¿þ:ß|ó~Oñ§?ý©Lû,Å‹ë¢þ¸qãxàhÞ¼¹O™5kÖ0lذ2ëÚ¹s'_}õ•þþ믿fòäÉeÎZ® ´Á²²žS*+îû¿÷HÐ>»ºE)I’TÛ äeK\‘!fÃãq+äÒ<¹}Ù…/‡":\PN'kÖ¬ñ™M^•X, €ÅbñhGìW;]ZÆð§lYgϳ?¡>²~2^Q9ЯT›`árƒdò^O¼þñ&lÁ•3ik³`-(¼T/ê ùéÓ§‹Y5+Š‚Ãá¨qû²'Ÿ|‡ÃÁì×_æºd5r_õØ÷zë{Ñ"õ=& ·X…:“AŽäÃÿÛªðj7™z65_‰íR &!Ø“ ËŽ)숫’L<ÚJÆ"«Ér ÈŒú¹²GT0y$¯Ð_íÝ&L˜*"èÉs˺¹²ÙlØl6rrrˆ‰¹äû§‰g‡ƒ²bÅ Ê}c]™‹`Ý –·^Y–©S§ëÖ­£E‹$$$àr¹X±bE…,x’““éÙ³'EEEúºï¾û®X¾Ëmoua¼!t»Ýºh èµÑÖ@·á’`_ZľÛíÆf³Ñ»wo7n¬¯/¯õL Oõ`žG•釒,vŒvE¥•Ó¨Mýà,n·›ÄÄD:tè@AAyyyȲPØw»Ý$%%ѯ_?’““}|a¿¦ú¡¶0yòdŽ?Ntt4-[¶d÷îÝ<õÔSüç?ÿ)WðPÀn·së­·²yóf¬V+ .¬°uÌã?®Û÷´nÝšíÛ·3fÌ6nÜÐ~­¶a|P/íoÕo½Ê¢]»vìÞ½›={ö”ZNÛnVýy÷Ýwùì³Ï5óÚµk™:u*}úôáꫯ®ºF £8yòäɃ4´ÁP5kZ2åÂÂBÆŒÐþ¥4´œ(¥ÞOž9sæòZôlÙ’Þ½{³qãF¾þúk@ûË‹f97|øpŸ7#çÏŸ/³žüü|î¹çiiiœ9s†Ó§OóÐCññÇ׈_tig=hAå_WVÜ¡_ý! ÿ»œPd—‰‰·j‰sÝÎ"‘qM«÷ƒý„ýsçÎ1÷ßÿšM¥,ˤ¦¦Ò¸qãÀ3½¯)´Ç­/š{“‘'5W—玨Ëúåd·X]&·ôÝoçbßzC€]`G6ÿ>›Á¾„d$Qùî—%°"¸±¹…á-›Â™}´ê”æã,ÕºukNœ8áhA›6mÈÊÊ¢}{u`«&ŸÉž}öY ùðí¿ódž‹,ymxTç}UÐGÔwËàVÀ%«ÉpNÚá™­ ÓºÊ4ŒòÎB‚-çaÙ¯ gípu]c[˘½J½l&ÕnGFRíheµ×5Ý¡ÌâÅ‹Y±bS§N¥{÷îÜxãœ={– &ðÎ;ïÔp ËÆn·3bÄ6n܈ÅbáÃ?dàÀªã½÷ÞÓ­Þzë-zõêE¯^½8uê?ü0Ë–- FÓ«•-[¶è¯›4i°Ìï¡ÊbÀ€,[¶ŒŒŒ öìÙCZZZ±2‡âĉ\wÝuëÙ½{7“&Mà¾ûîcÆŒ 4ˆü‘{ï½—7†üÀ™1YìæÍ›¹öÚkK,ër¹tøÎ;½mµ íoRis´ÁEQX½z5C‡­Ðghý^TTTꬫ7V¨ÞPä®»îÒ#--Íç\-‹Ã‡гgÏˬ_¿¾ÌzüqŽ9BLL .äðáÃŒ9’•+WòÖ[o1nܸr·©:0>wÑîÚë@å´úŒËš¦¬~Ðfü$''ÓªU+ìv;¹¹¹ºøo¼¦he“’’h׮Т`·Û1›ÍÅ·²"öèìß¿_V¼ãŽ;¸ñÆxõÕWyøá‡Y½z5óæÍãÞ{ï­Éf–Jaa!·ß~;ëÖ­Ãd2ñþûïWX Û³gžÌôÞ{ïeĈÌ™3‡Ûo¿ÿþ÷¿Ìš5«Üž×¡Hzz:óçÏ }ûö4jÔ¨X™ßC?”‡¡C‡…Ýnçí·ßÖÑl³Ù̼yóèÝ»7'Nœàá‡fÉ’%A?žË!--æÍ›sìØ1æÏŸÏc=FTTTÀ²}ôÙÙÙþ þЂ?23û,ƒšÔ¶uëÖ¼ýöÛÌ›7¯X™¬¬,/^\ñ1n»í6}FC«V­*´¯–káøñã·?~¼Ìßæ¼yóX¾|9ÿüç?III!%%…±cÇòÖ[oñ׿þ•k®¹†nݺU¨mÁÄ(¤6lØzõêé³HKôÂ}e¼ö¢~iÿÁEõϹ(›h 9€Ü vbëõ©ž dÅÃ¥ï'ØÎ>y0´†mªqôˆ}ï‹M Ôež:ÛžÝ+Õe¤Ýw¿w¼I¼;xLöxój~,!›7¸‹¹?÷Ì9$Ô/¡Tà/Æ,KD™`h +ïŒPE}‹Tæà^Yëj2ˆQ’$¦M›FQQ+¿Ç "d E€[³ß‘Á%À"«ÿÌ ˜%uƹ"xp“B³h‰kê™I‰‘|“c&­ý³Á‚„l½oúCæ&L˜ŠR¾¿`h³Ùˆˆˆ¨”—j¨ˆ•A³ä9xð 111%ÚhÂuLL ‡Ãgj¯B$é7áG« Öx<ŸÄ©FK@³7wš`­Y¸\yå•zô¶–DV‹`7&¯SE€¢¹£à]ç]eú!99¹ØÔïääd½.m¿† rîÜ9ŸrM›6Ån·×º~èÖ­›þ½ !ôo­Z$¢$Iäçç—z>hBPÌ7×XguõC°8uꔞwГ, !8räˆOÙ&Mšè} ª >nÜ8mÚ´aòäÉú¶ë¯¿žÑ£GóÁðúë¯Ó½{wŸi³¡‚ÛífÔ¨Q¬Y³€gžy†ÔÔT<°¼Éd"%%ÅgÝnרöíÛóÚk¯éÛ† £>ÊìÙ³yñÅéÝ»7]»v Úñ\ýúõã`ðàÁ>3¿Ün7ÿùÏxöÙguÿóçž{®Øþ¿•~õü?tèÏ:M¼*((ð9?Ìf3-[¶ô)›À£>ÊŒ3X´hW]u•ÏàÖÂ… yÿý÷xàtû#O>ù$‡&**Š?üP¿67iÒ„Ù³góç?ÿ™+Vð¯ý‹Gy¤j<Ȳ̄ xä‘G8~ü8#FŒ`Ö¬Y>}æñxX¼x1Ï<ó  æ5jTIUþnéÔ©?þø#+V¬àî»ï¦S§NÅîeYæ•W^aäÈ‘ìÚµ‹#FðöÛoÓ´©¯=‡ÇãaݺuÌ;—9sæè~Å‹…qãÆ1yòd–/_NçÎyâ‰'ôý²³³¹ûî»õ˜ÚLTT”>øXQzôèÁÉ“'™?>wÜq‡Ï “ôôtî¸ãÝ*3{÷îe„ Œ=š‘#GêÛþö·¿±qãF¶mÛÆèÑ£Ù¸qc±¨øšB»ß”$‰øøxŸY`•%ÝvÇ%ƒÅ+æ›e ³,0Ëàò‹[2Áè––bu ¸Ô§¢¸¸o’ RÒ¢÷ tC£k„ S BÚŠçrÄèÚjÅ£a±XHLL,3"ØétúøªkëvíÚŶmÛˆŽŽ&:::¨m­.4ÿô@IJµhs‡Ã$Iz$·¢(X,¬V«>Ò«W/²³³uKc½ZàëA¯ ½ÚçÕ¤åJeú¡U«VtëÖÍçA¿°°³gÏúÔ›––¦'n–$ ³ÙŒ,Ëäçç׺~°X,<Œ‰pµDÃÚƒFTTT©çÃõ×_¯GîkvO¿E ž'žx‚;w[ïr¹ŠYѬ\¹ÒGŒ›2e G%22’þóŸÅ®å&L`Û¶mìÙ³‡'žx‚/¿üÒ'ÇJ(páÂþ÷¿ÿéï§OŸÎôéÓK,_§Nb QŸ|òI:TL€Õx饗شi;vìÐEÿ¤_¡ÀöíÛu¸qãÆÔ­[ÇÑ#GôÙN“&M⦛n*¶ÿo¥@M2^R”ì¦M›|¶Õ¯_Ÿôôôbå&MšÄ† Ø´iãÆãí·ßæÊ+¯$==ýû÷Э[7¦L™Rlß?üPö}óÍ7‹E6Œ‡zˆwÞy‡É“'Ó«W¯¶®¹ë®»Ø±cÿþ÷¿Y·n:u¢U«V4jÔ‡ÃÁ¾}ûôYSuëÖeÑ¢Eö†ÿ=pß}÷1þ|Ξ=Kÿþýõ€€ 0xð`È믿΄ X³f ;v¤sçδhÑ!gÏže×®]ú@îìÙ³}>gìØ±¬^½šÕ«W3yòd>üðCzôèA~~>ßÿ=¹¹¹ü¿ÿ÷ÿ˜1cFõv@1~üx¾þúk èß¿?×^{-7æÔ©SlذP@§NZl_m´°°ÔÔT^ýuŸí‹…ùóçÓ»wo~ýõW{ì1,XP-ÇUò •å±_¢ùm7&Í­nŒíÊÍ’¨ßÂD¨ùë ¹‚†‰WÖp;yyylÚ¼9hÉs­ C‡%222×ðtTgN˜3Oª+{æ,Þç}-ßê}å§…Øó}Ëiûi‘ÿ™ù>ŸJ êT!åòαLØJ·¶˜ Ú$èSÏEŸø|ê+b¬ P‡ÓÓ)((àÔ©SôêÕ Pϯ½{÷Ò¨Q#vïÞM‡Bàr¹Ø¹s'111!¸âŠ+ªãPË…Édâÿø;¬þj)}“Uÿ’ ¯þ3yß›$Q“èê”p)5 ùڃί[óØd “7i®ì {ì‡ S›©ñä¹FŒb|÷îÝùå—_*õ¹Ý»w¯•Ésý)o¢Û¢¢"\.œ;wŽƒrñâE*58jÉ>µöT#š«Ý(E\“É„,ËtéÒˆŸåf IDATEQˆ'''‡¢¢"=ºÈét{µþ4Fíkb.”µìó¨2ýPTTäc»cô×7öC^^žy«YÎhy~ ý FŒâ|m:B•O>ù„Ï?ÿ€¿þõ¯Å"–A'Þ|óMn¾ùfNœ8ÁäÉ“yóÍ7«»©AeáÂ…º%ÅßÿþwZ·n]¬ŒÕjeþüù\sÍ5;vŒÇ\·´ %† ƦM›ÈÌÌäÔ©SÅ0®¾új&NœÈþð‡bûþ–ú¡ª°Z­|þùç¼ð |ðÁ8p€j@ÃwÞÉ+¯¼Rldß¾}zäúwÞYbäúË/¿Ì¦M›Øµk£GfÆ !7pfä7Þ gÏž¼þúëìÛ·C‡ùÌŠˆˆˆ`ĈLž<9¤ÊC‰ÔÔTV®\Éßÿþw¶nÝJff¦>(í?üÐCѱcG¦NʺuëØ¶m›ž¿T±òª«®bذaÅCL&K–,áùçŸgÞ¼yçêz`òFè›UÌ×D}íŸâ×|£`ï¿Þ_Ü÷_/IxøªÑúrø÷&L­EÊÊÊ xu« ?öS§N±jÕ*vìØQfÙœœF¥GÅÇÇW:b///OŸ ìt:Y¼xq™Égºté 7Ü@ãÆ+õ¹%Q‘~¨Š¢——‡Åb!''§ÓIDDÑÑÑDEEUú;¬ª~8sæ €.äh`%++‹}ûöaµZFgk–DÚ{£ k2™ô¨scY»Ý®×e6›‰ŽŽö|eYÆl6c6›‰‰‰ÑÅm-ú_«Kû£̾}ûh×®žÀ§ª÷Ãï»Êó{Z¹RõäÔ’kºs¨ Í@Ùºu+@…“Ú†©GŽáÔ©Sœ?EQHJJ¢cÇŽåN̦8999lß¾ .˜˜H·nÝÊu¿ò[åäÉ“ìÛ·ììl, 6¤S§Nγ¦|\¸p;wrñâE$I"99™víÚ•ë7}áÂ~úé' ¸âŠ+èÞ½{­ÏåT•¸Ýn¶mÛÆ‰'ˆŒŒ¤eË–´kW v(5Ä”)SxöÙg±X,ú=˜‚ˆˆ=ßUIžúe½´4Ú+_Ûív&L˜À?þñ ³Û‘ËOÝJמÇÙ³ÕÆ5C‘B,õRV†‹_v4¢ËíË‚jA2ûí·y³¨;gS. ðË'ÝWŒeéŒç©W¯^Ð>;ÜñÌ4¶} ÅdÕ×78¼Š§£wðp ÙÔ™×|€m®šüZJ©ëm˜WóДU}éwBiÏ=šº«-Ïzí2ÓÕ<+EüwÿÛª°õ—¢(¸=VtòÖ^7‡… O‘¥ÀRP„%ÂL¬ÍÄàV‘ O"2÷8¸ìtìгٌÇã!;;›M›6Ѹqc:uꤟ×ÇŽãàÁƒôíۛ͆$I(ŠÂöíÛ),,¤k×®º¶¤( ¹¹¹!cUìp8=z4¿¬ýšÎ‰…°»¡ÀûO}-(pƒÃðèm†gÚ]:¿K²Þ× ¡ÎX|ÌÅ›}΀ªæÀ„ Så”À^-V<剦e™½{÷Ò±cG@}`ÐFV/‡½{÷–{Êg°­xªú34«EQHLLÄd2a2™.ëÆ­¦#_JBá#âj¯5; £ˆkü§•Ñ¢¯ ÂF!WQÔijš fÏ…Ûíè7¯-ƒ}…û!ÜaÂÔ-[¶ 8#L剋‹ ?@¸âŠ+ÂQùÕHRR×]w]¥÷4hP·è·ƒÙlæê«¯æê«¯®é¦T •± ,+"ß½d¿v¥½®vïl¡þËÏ‘ˆ®cB’C/˜"?ÛETR›êé›’<öÅ¥Hë·gÍÂ$+‹ÅÂccÇŽØa$`p‡Xòxs§tÉ ˜MÑf‰AWÚÞ.ŠÉVb›´ñÉk2™HJJâÆoÔ×ißuóæÍiÞ¼¹Ï¹.˲n1ÊDDD0oÞ<þüç?óóæÿÑ6NBBßñÿç‰jؽv-ôߦ¡xô¾5røq5L˜ZMЭxÊ‹ÕjeÇŽ8Z¶lyÙQ?‡ôôtöíÛW¡)èÁ² ’$UØ?¿¼„¢é/˜úVù?Th¶+N§SìÕlWŒ¸ÝnÝ®Å_ô-**"""‚‚‚}JtDD„ž€Õ?amuô[¸TÂý&L˜0a„ Só\ŽOI”dÑõk’œ‹2u$„'ô„ýœ .b§Öh4a_| Ö ƒ÷\(Õ³†…}-‚^KŸmùê=LŸ¯¿¬z5O}×S|>'T‘%‰Ái± ð÷­…œ4˘ÌCZG2¼miõ-D›%„P¢|ƒw¥åâÐ¥ä¹þDFFòÑG1bÄ~Ù¾ŽæÑ !écSš°현¨°5Î;«3¾Ä~˜@,I IA6›˜üß³ h#;ÆÒ®®™«„É$süøqŠŠŠhÓ¦ pé¹ï矦I“&Ô­[W¯3++‹ôôtÝŽTãôéÓdeeѾ}ûê;ÀJÉ’%K1bGvn¢aä¥D·Ú©ì•ï+Ø—½ï/îç¹?dx8eNbü Ïò—¿ü%dì‰Â„ S1‚.ì—÷FO’$bbbt‹‹ª¸QÓ<µËK0oJk↷²„b[…x<Ÿèj­þ¢®,Ë>#òþ–-%ù²û—5 ÀZ€>P¤‰Âf³“ɤGy[Ð÷C¸„ &L˜0aB…`<;øG×z_“h³Šì’Rzc‹­\ BñP¸n¶¸ªÍW"eXñT'B_%Ô¯M5Qê‘õÁD,Ëtˆ¾ÈGÃm=q†+ë4$ÆjA’$òóóÉÎÎ&""‚_ý•fÍš°{÷n’’’Ø¿?}úôÑëÛ·o]»veóæÍôìÙP½ë8@£FHOO'%%¥Æ¯eËÒ¥K¹å–[8¹o;‰VÃÌ%¼ÁùèVDÜw)‚Í™ Ûó­üåÇxê©§ª<'^˜0aª—  ûEâ„ñGlÂ-öQ×¢x´„]pIxÕ|Øu¸Ýn]ÕÊz<] u:Øl6‡z_T„¢(X,Ün7V«UÏwî‡p?Tg?„ &L˜0aÂÔ$•o+b‹áŸ«,PòÜš@f“Ày~îËO W¥Ú=X¢[`ލS£íB …ÿÏÞÇ×t­ÿœ“QI ! QSÑ⚪¨©´ZŠÒÕAõv@[C)Õ™¶Z-í­ú©ÛQ'E©Y•Æ ÆK„"jNˆ È sr~äž}3œD"s|߯—W’³ö^kíHöyö³ŸuáÂÞ:•Ô´’)YäààÀÛ#wÍšÙ3ö¥Üʼ9îŽPÝ9çÿæcÚúm}-%%OOONŸ>] 1Ìf3^^^\¹r¥¸§_b<==Y¶lýúõ#2,7kñ‰|~ž³•àÉQšÇz&3,B¯f°%ÚD²uÊüýýKâD¤”•›ÅsËZE\<·$”×9Zk˜'&&eOrfPg]ð4ë›…¬åV2220™LFÀÖú1g`غ¯5l±XHLL¤J•*$$$O–¤¤¤àêêJbb"NNN¥’©®ó ó """R^¤§§êzÇVP?çµZÎÏmúòûºäeŽç^­îu[”òØ×sü,.^õ±³/¥' ®“±ïêæF‡J4°ïæêš;(¬à~¹’õ{c±X¨W¯GŽ¡ŽŸîîîÆÓØîîîxzz’˜˜H½zõŒýš7oÎÖ­[©_¿~¶ß 6dûöítëÖÍxÝÁÁoooNœ8AÛ¶mmΡ¼òòòbéÒ¥ôïߟsÇáhÆöʸ9ØÌÞ·À‰ø 6\È Q»Î,ùqJ®’E"R±•›ûåjìg*¯sMMMÅÑÑ‘””ã£5pk-b ÈÚÙÙ\kI&[Çeýß3ÛÛú9`”T1™L$&&âââBBB‚±xj\\®®®Ù^ÓyÐy(­ó """RÒÒÒHII1‚qù½‡È/C¿ A}[exr~´²®‡TÒO›0áìp‰k[Jtœq%" 7ŸÞ¥;hÎÀ¾é¿ 5 ÎÎÎ }üñŸBF~5öä/wÒÒÒhذ!&“‰ÔÔÔl¯ûúúb2™²•^utt¤G¹~Gx{{ãíí­o“ÉDÓ¦M¯ ó”PyàííÍÒ¥KéÛ·/‘§ŽÙ,­cKÖí.$[ø32 j7bæ7SéÓ§ªcˆTByö‹#¸k­æàà@RRÒõw(CÖ‹¿’x¤Sç!Óögý#œ’’‚ŽŽŽ$%%eËÔÎZöÄl6‹ëd ÆZß|ä\ÕÚžµt ü¯Ô‹q¡‘5KÜú¦ÁÁÁØØXªV­ÊÅ‹7 %qþtt²ž‡ë#[ WYŸÆ°*¯7%EDD*›ÄÄDâããIHH0oYŸT´~´Ò²Ô¬õéó“3¨_пñ\ºt WWW\]]±·/™<6kÉ Ïº-pö­]"cÜ8 ×î¡NÍÛJñÚÈb3p^f5ö­²ÍÉRæå›nf9Ï{Ö÷(9_d}ÝÖn^¯¿¬íáçÀÇLJ•+WÒ§OΞ9EÎ)g+Á“E\ª…ÍQiœµ¯Á+ïd.Œ›u]8©\J4cßÑÑ‘ªU«âääDZZZ¡Ó, Ö2NNNT­ZGGÇbãf=µkg^䯯Æ©{{{ªT©Â¥K—ðöö6‚¸Ö€‘µ ÿ ÀBæCÖ»üyÝ¡¶¾nÍú¶··7‚ÃÉÉÉ8::Ÿ;99‘’’bì›––F•*Uˆ‹‹ãÂ… xzz–È›‡›û<äÿ“³³3III¤¥¥eËT«lÁýœ7\ óØEDD¤ä¥¦¦’˜˜HBBqqqX,âââpww7®y¬‰MY¯µlßleÝßhVm||<éééÄÇÇc2™Œõ’J"K×ÎÁ•jþù;d3ÇC/{ÿEe1UíÖí¥2–··7.‡#È /þ÷\—‡ÄèA}—˜p¼›×*«ÙÈ•eæ|y‹Á„ŸŸË—/§_¿~„‡‡ÛÜÆš¥ŸœnaÇ¥tö]sbøs/2nÜ8<==Ku¾"RúJ4°ïââ‚¿¿?G%&&'''ã—¸õ"Ïš±‘׿¼¶…ÿ] ZA[ƒWY_·õ/ç¶Öàœ¿¿?...:%tn”££#ÕªU#22’ˆˆªU«FFF®®®¤§§AלÙÚÖ²+ÖúçYÿÙb-Ýÿ [ÿ%%%aooo,˜êàà€½½=)))¸¸¸põêU.]º„Éd¢Aƒ%vƒHçAç!?U«V%))‰+W®P£F\OT6ÆbXU«–íâp"""7#“ÉD›6møè£ŠõýCaÖ÷5ÉÉÉ´hÑ"×Ó%Ád2Óøî7HMM®4ÚrÀΡ f{§R«ç=÷°zã;¤í¯B|õFXL&Ì驨¥&pàÀªW¯^*ó°ºtév© xÛG†Ù“%÷èc´ŽÚFϱSKu.b[A2ñ ³maú«ˆêׯÏÒ¥KéׯçÏŸÿ_Ã#úX¹œAà% ½|„ 7ßÔ¸"7Ó•+Wl^‰G Èb±páÂŽ9Bhh(gΜ)rövq«Zµ*þþþ´lÙ’¦M›âíí]ì¿üuŠÆštþüy"""¸|ù2‰‰‰e=­lªT©BµjÕ¨S§µkׯÝݽD~ŽttòÇŽ;0™LÔ©S///ìííËÍÿåâb±XHKKãÊ•+DDD`±XèСîîîe=5‘›BRR×®]#!!„„âããINNÆÎÎŽäääR‹5‘£J•*¸¹¹áââb|´³³+չܬ¢/]bÍš5DFFf»Ñb«äei°>‰™7w|}}éóÀ¥~“AþÇšH˜5Y1/}ïr#7ñ¬õüK+ñª8>|˜~ýúqñâE\íáÕÛ9oáÏÈtßÑ™÷Þ{V­Z•õ4E¤„ä•”Z¢}ëÀW¯^%**ŠØØØl‹¢”T­Z•ZµjáééYb™­:Ec±XHHH 66–¤¤¤2»HÌ‹ÎÎÎT­Z— ¤ê‘Â+óÀ¾ˆˆˆˆˆˆˆˆˆˆˆ\^}EïEDDDDDDDDDD*<ë®”·R1"""""""""""¢Œ}‘ E}‘ D}‘ D}‘ D}‘ D}‘ D}‘ Ä>¯‹ÅRšó‘È3°¿cÇŽÒœ‡ˆˆˆˆˆˆˆˆˆˆˆüW‡òlS)‘ ÄtåÊ›5wK{."""""""""""¤¤¤äÙ¦Œ}‘ $ÏûùÝ ‘²‘g`_DDD¤¢Š‹‹ãäÉ“ÄÄÄœœ\ÖÓœœœððð ~ýú¸»»—õtDDDDDD*”ÊþóÜÜÜŠsX©´P®ˆ†~gˆˆˆÈͬXûõë×ÇßßßøºE‹ôïߟѣGóóÏ?sáÂ,XÀsÏ=WœÃŠˆˆÜô¬5îóÊx·fÆnÝj³½[çÎÜÓ»/o½1¹Pãn`íú?xoÚt›ûYûíÝëÞB'"""""""ÿS*‹çNž<™Ÿþ€mÛ¶ý“'O‡‡7Æb±Ìž={¸|ù2­[·fÀ€Ùúº|ù27n䨱c$''ãííMçÎiÑ¢Åu瑞žÎ–-[سg×®]£N:Üÿýøùù‘˜˜È_ý@óæÍqvv6öKNNæÀ4kÖ WWW.^¼Èºuë8sæ éééŒ5Š5jû\¹r…àà`ÂÃÃ‰ŠŠÂÑÑ‘[n¹…îÝ»ããã“ç/]ºÄ©S§0™L´mÛ€C‡±iÓ&.]º„÷ß¶(.\`Íš5„‡‡ãââB×®]iß¾ýuωˆˆˆˆˆˆˆˆˆˆT,¥Ø÷óóÃÅÅ…„„.^¼h¼>cÆ ,X@Ïž=ùøã>|¸@èÓ§Ø·X,Ìœ9“O?ý”¤¤¤\ctîÜ™9sæä x[?~œþ󟄆†f{}Ò¤IŒ7Ž|{ïÍÌܵk76¶‰ŠŠ2ÚþüóO¶nÝÊ´iÓHKK3¶0`5jÔàÂ… <ýôÓìܹ“ôôô\ó°··gøðáL›6 GGÇ\íëׯçÅ_ÄÉɉ“'O2fÌ–,Y’m›7Þxƒwß}—Q£FðñÇ3sæÌl‹FM›6!C†0gÎcQ)¹yY3õ¯—IoÍ /,k¦~Îþ¬ãåÌÈ·nß©[ÏODDDDDDäfV*ýÄÄD¨R¥J®ö¸¸8yäNŸ>ÍÝwßM“&M¸víZ¶¬ùñãÇóý÷ßpÛm·ñàƒâææÆ¾}ûX¶l[·n¥W¯^lذ¿ÿ.äguñâEúõëGdd$ööö 8V­Z‘ÀüÁ§Ÿ~ÊñãÇ t,ß|ó ‹-Â××—»ï¾›ªU«rôèQìí3OeLL ÁÁÁøùùÑ­[77nL•*U8{ö,„††òÍ7ßË—_~™ïX£GféÒ¥ôêÕ‹V­ZqñâEÖ®]Ëùóçyýõ×iÖ¬ÁÁÁ̘1ƒ6mÚеkWÒÒÒàÈ‘#,Z´ˆ¦M›2nܸ›ˆˆˆˆˆˆˆˆˆˆ”¥Øÿý÷ß±X,4mÚ4Wû®]»¨V­ëׯ7ÊÏdµnÝ:#¨ÿÔSOñÉ'ŸdËB6lƒ "**Š1cÆðÛo¿eÛÿwÞ!22’*Uª°lÙ2î¼óN£m„ ¼ûî»|öÙg:–E‹ñä“O2cÆ œœœrµ{zz²dÉzôè‘k1'‹Å·ß~Ëĉùõ×_5j­Zµ²9Nrr2«W¯æ·ß~ãî»ï6^íµ×¸ï¾û8yò$ãÇçÌ™3|øá‡Œ9ÒØæÍ7ßäñÇgÆ |ñżôÒKƹ9äUSßš9Ÿ³¦~Qå•™ŸWíü¼ž¨ Nœ8Add$W¯^¥jÕªÔ¯_Ÿ:uê”õ´DDDDDD¤1—ôëׯçÕW_5¾~ä‘Gln÷á‡Ú ê|þùçÜrË-|üñǹJËtéÒ…ñãǰqãF}:‹…€€š7od.Ö›’’ÀСCmîk6›2dS§N½î1>öØcEÎ~o×®[¶lÉv–!C†Ø|=ëBÁymÓ²eKãóÓ§Ohqa©†k×®ñÄOðöÛoÓºuëRŸCePÞÎãéÓ§‰ˆˆ ))‰êÕ«ãííM­Zµ´Æ—ˆˆˆH)(ÖÀ~pp°Í×ë×¯Ïøñã‹Ðœš6mŠƒƒƒÍ¶#GŽ‘‘gF?€··7õêÕãÔ©SÙæGÀËË+ßÇà³Âóc½a‹ÅÂÊ•+Y±bäâÅ‹ÙÞì[ݽråJž}˜Ífêׯo³ÍÃÃÃø¼aÆ6·qvvÆÑÑ‘””âãã¯;g‘ÊÄZ°¤Í™3‡1cÆP­Z5&OžÌСCñõõ5¶‰‰‰á?þ`ÆŒìÛ·ÐÐÐ<¤|:yò$Û·o'99¹¬§rÃÊúÒÒÒØ¾};ÿ5°ä¯<œÇ””ŽÏŠ IDATæÌ™Ã?þHddd®vwww:tè@Ïž=>|xéOPDDDä&Q¬ýwß}—êÕ«gvloOÕªUiÔ¨ 6´YšÆ*k :§«W¯Ÿ{{{ç;~Íš59uêT¶}bccÌÀ~~®×n•ß\­ã :4ÛM///j×®m½þú뤦¦âèèȯ¿þj3¨Ÿ•Édb̘1ù^“?~œ€€ÂÃÃ1›ÍÔ«W^½zQ·nÝ<÷Ù·oÉÉÉøûûãëëKbb"k×®åðáÃF®]»vÙö‰eÆ :tˆØØXjÔ¨AÇŽ¹ë®»®{­s31b ÀÍÍ­¬§"79777Ö¬YdÞP,mo½õ–ÔòÉ'=zt¶÷©©©ìÛ·•+W²iÓ¦RŸŸˆˆˆÈͤXû%¡FÆç‘‘‘ùÖŠ?{öl®}¬ÂGEE‘””„³³³Í}O:Uä¹&%%±dɦL™ÂÓO?ms»K—.y,‘âP\™ó׫©Ÿ³½¢gî9r„ 60xðà—ôÛOÛÅÄÄ0jÔ(-Z”«Íl6óÌ3Ïð¯ýËXË(«‡~˜Ó§OóÁЪU+† –íZÃ×××ì[,f̘Á|@\\\®¾ZµjÅ÷߯µyr¨S§N¾%EJ‹]¾åIKRll,K—.ࡇbÆŒ¹¶qpp }ûö´oß¾À‰S""""rcÊ}`¿Y³f899‘œœLpp0½zõ²¹Ý±cÇ8þ<@¶z­odÓÒÒ ä¾ûî³¹@@@‘çndáÝyçyn·mÛ¶"%"""eÇÔxì±ÇŠÔWbb"=zô $$€û￟=zžžÎÚµk â믿æèÑ£¬_¿{{Û—oûöícêÔ©888ðÈ#P§NÎ;‡»»»±ÍðáÃùùçŸèر#½zõ¢Zµjœ8q‚ùóçB·nÝØ¾};Mš4)Òq•gW®\aÓ¦Mœ8q‚„„ªV­JµjÕhÑ¢-[¶ÌµðgDDQQQ¸¹¹å:/ÑÑÑœ:u ³Ùl,dzøða¹té>>>6Ÿº¸páüñT©R…Î;sÇwØœoJJ 2צruuåìÙ³¬_¿žsçÎáêêJûöíéСC¶'WoDZZ»ví"$$„èèh\]]¹ýöÛéÚµ«ÍKEeëØ²²X,ìÝ»Àæù‡ÌsŽ££ã ß”:qâÛ¶m#""‚´´4ªU«FÍš5i×® 4ȶíHIIÁÏÏÚµkçê+,,Ì(¹Õ¦M›\OÁ$&&rèÐ! sý®üJk攞žnü®hܸ1U«V͵Åb!44”ÇI||<Õ«W§U«VÜyç7¼°mXX©©©ôéÓçºÛ[Ÿœ‘’QîûŽŽŽôêÕ‹U«VñóÏ?3nÜ8<==sm÷ÿ÷@fKïÞ½×[¶lI“&M cúôétïÞ=×Åshh(Ë—//ò\³.|æÌ› í®X±‚¿ÿþ»Èc‰ˆˆä§[çÎ@Þ™ôÖöâÒ»×½¬]ÿ';?gæ¾uûŠjÏž=Æçyc êí·ß&$$“ÉļyóxòÉ'¶I“&ñÑGñúë¯ÈÌ™3™<Ùö÷tñâÅ´k׎•+WR«V­\í_}õ•Ôÿꫯxæ™g²µ¿öÚkÜ{ï½8p€çŸžÀÀÀ"WyõÙgŸñé§Ÿæ™MìááAXXX¶×¾üòK¾þúkÚ´iÃï¿ÿž­- €±cÇâèèHXX&L0²š­ÞyçÞ~ûmžþy>ùä>ûì3#H ðÑG1hÐ >ûì³\ר¨(xàV¯^Íúõë™={v®E¢ÛµkÇ—_~‰ŸŸ_!ÎÈÿ¬_¿ž7ß|“3gÎäjóööæƒ> oß¾7Ôw^Ìf3ƒæÚµk|þùç <8[û_ýe»§§'‡ÊuóbæÌ™üøãtêÔ)×¹¿žk×®ñòË/³råÊ<·éÝ»7óæÍ3¾þàƒØ´iC† aÖ¬YÙ¶ÍÈÈàÁ4Öü Èõž`ݺuŒ9'''Ž=Z¨ùÆÇÇçã—_~¡GÙÚ¿ùæ>ÿüs.\¸`sÿúõë3kÖ,Ú·o_¨ql?¯¶žø‘ÒU´”žRòòË/cggGtt4O>ù$ÑÑÑF›ÅbaΜ9üðà :4WFÔ»ï¾ @HHƒ "$$„ŒŒ X²d <òÕªU+ò<ëÕ«g,ðûÁä*¹ÀèÑ£‹œI%"""eË4svv.Ò5D\\_}õ™ùŸ5¨oõꫯҽ{wfÍš•-¸–•½½= .´ÔOMMeÚ´i<ýôÓ¹‚ú5kÖäÛo¿`ëÖ­ì۷©<›7oÓ§O'%%…-Z0vìXÞ{ï=&NœÈOþøcf̘Áí·ßÎèÑ£5j”‘…¾xñb¾øâ‹|ǘ;w.Ÿþ9Íš5câĉL:•|³ÙÌž={xøá‡oèæÏŸÏSO=Å™3g¨W¯/¼ðï¿ÿ>&L qãÆ\¸pçž{ŽeË–Ýйɋ½½=:t`Ë–-¹Ú³¾võêU#»ßÖ6]ºt)ôøcÇŽeåÊ•˜ÍfzôèÁ+¯¼Âûï¿Ïرcyøá‡ñòò2‚ôVÖqlÍ÷àÁƒÙ¶ Ês¾íÛ·/T¶~AìÞ½›Ë—/Ó¥KFÍ{ï½ÇäÉ“4hNNNœðàCÜÓ»pÙµkWg믰ãuêÖ3ßýrfòt¼òÆZf£¨‹©nݺÕèkĈyn7räH6oÞÌ… øÏþcB³êÑ£G¶À[V;wî$""ÀÈ·¥mÛ¶4hЀ'Nh”–©,¾ùæÈܹsmn“õiŒÂHIIaÍš5,\¸nݺ¯Oœ8‘¾}ûrêÔ)&MšDxx8ï½÷Ï=÷œ±Ík¯½ÆðáÃÙ¸q#_~ù%£FÊóztÍš5 :”™3gfËìôÑG6l§NâÃ?dúô‚¯_qøða&OžŒÅbáÑGeæÌ™ÙÆ?~ø€êÕ«çj{ã7xì±Ç8tèÓ¦Mã§Ÿ~*Tß>>>tïÞÍ›7sàÀ:uêÄСCéÚµ+-[¶ÄÅÅ¥¸CDDDD  Â¤Ž1‚ùóçÓ¨Q#øóÏ?Yºt)'NœÀÉɉ#F°jÕª<ß`?ž+VpÏ=÷àåå…ƒƒ 6dôèÑáååelk«VeAýóŸÿä½÷ÞÃÕÕ•ØØXÖ®]Ë‚  ¥W¯^üùçŸÙ÷‘ŠÇZüÚµkEê'44È,%h]È–¬|[Ë@¶`gNÖ`µÙlæÀüðÃyþ³ÖÅ>uêTa§Ü ÈV¶1§ü¾×3zôèlA}€5jðôÓO™çôž{îÉÔ‡ÌÒ“/¿ü2—.]Ê7›ÚÇLJéÓ§ç*×s÷Ýwóì³Ï°`Á‚Beí[Ë5nܘ>ú(×M;;;>ùäjÔ¨A\\ .,pßa pŸ?žcÇŽ¯§¦¦²sçNL&“q~rÿ­_»¹¹e[g« """ŒrFyÕŒwppȵ8öí·ßn”Ík>ãÇÇd2±cÇŽlOÙœ9sÆ(uTý=zØ êÔ®]›>ø€7’Pèþÿõ¯Ѹqc"##ùôÓO0`5¢[·n¼öÚkìØ±ãÆ@DDDD ¬Èû£FbÔ¨Q7´ï_|qÝdzêÓ§}úôáÈ‘#;vŒääd¼½½i×®]óêÚµ+]»vµÙfÍÄñððÈõH½¿¿?W®\)ð<_zé%†ή]»ˆŽŽÆËË‹Ûo¿&Ožœg}ÜÇ{캋ðµhÑ¢@ó±.&,""•ßðg3³½¿ÿæK ïÚú×cÍœ·öW^Æ+ojÖ¬ d.‚sÃÙËÖ¿çù–äÈZ^çòåË6·±µ‘•µtPFFF¾ûYÅÆÆh»ŠÄ××—S§N±zõjúôésÃOiæå‘G±ùzÖëƒ ²¹MÖE_óZ« àá‡ÎógåñÇgîܹ$''³mÛ¶-pšššÊºuë€Ì¬ÿ¼úvvvæÞ{ïeÁ‚çû„IaÝvÛmT¯^èèh¶lÙB£FØ»w/×®]£E‹ôïߟW_}•;w’œœlÌÓHïØ±c¡¿Ÿ¾¾¾Æç+V¬°Y¢Ê³ÙLçÎY½z5[¶lá©§žþw#Âl6Ó¯_?¾ÿþ{<Èž={èØ±c¶ùV­Z5× ƒÒжm[ sÞ°°°B?•ãããÃúõë™7oóçÏçøñã@æï–°°0˜7owÞy'³gÏÆßß¿ØADDDD2UˆR<95mÚ”¦M›[ÌŸ?€N:a2™ŠÜ§››[®Å¬DDD¤rhÓ¦±íž={èÙ3ÿDy±®»“žžžïvYÛsfj[äúÅÍÍÍX{èzn»í¶mW‘<òÈ#Ìœ9“•+W²wï^ú÷ïÏ]wÝEûöíqww/Rßf³™[n¹Åf[Ö§Aó*—äì쌃ƒ©©©Fy&[òËJoÔ¨nnnÄÇÇsøðáö9BRRÑÑÑ,Z´(Ïm­µã­O>X_˹®”•··wž„5™LÜu×]¬\¹’   ã ‡¬%k<<QS¯^=ðññ¡S§NóÆo°xñbz÷îM§NhÕªyÎÙØß¶m˜ÍfvïÞMbb"ÿøÇ?ððð K—.>>DFF²eË–l}ë€:ààà@HHqqq„‡‡7Rrö‹ã<ž}øõ×_ì~[?ÖqwìØA`` iiiÜqÇÙ‚ØÖm‚‚‚lSq²–ØÉo}ë9+iÖñíììptt,•1EDDDn67MÆ>d^¤[3hDDDDŠjòäɸ¸¸0iÒ$Ξ=ËóÏ?Ï /¼@ãÆñôô$&&†Ó§OÁ|GGÇ\%CFͶmÛXºt)Ÿ}ö‹-¢cÇŽddd°eË£dàsÏ=ÇOΟ?ÏÙ³gÌ›>®®®FÛÅ‹ILLÄßß?ß>¢££E›6mš­ˆˆˆˆ]e‰ˆˆˆÁ˜1c å‰'žÀÃô´4>ÌöíÛ9tè×®]ÃÓÓ“#F°ÿ~œm³ÙÌ‚ ˜6m^^^DFF²téR–/_Ntt4µjÕböìÙ….-bË‹/¾ÈÆéÞ½;ìÞ½›E‹åDâââèС~øaž ùVTÑÑÑ<ÿüóìØ±ÃfvûöíF0ÒZ’¥<Šç™gžÉµ8î_|ÁòåË9rd¡J-?///®]»Æ#<ÂŽ;lnwèÐ!Þzë­\e-‹‹u‘ܤ¤$Ž=Š«««±…•µ~}hh(¹xëõÍy `êÔ©;v,W›Åbáßÿþ·±P°­Ÿ‰ÚµkÓ¨Q£lóɹÐn›6mpuuåøñãÄÇÇg;ÎâÖ¶m[ ó ¢Ÿ~ú)[[ll,£F⯿þÊ·Å‹óÀðÀpäÈ‘lmgΜ¡S§N¼ð lÚ´Éæâ»{÷îeðàÁÆy{òÉ'‹rH""""’›*c_DDD¤$Üzë­|ÿý÷¤¥¥Jdd$111¸»»Ó Aš5k–oÖª¯¾ú*&L`Ïž=„‡‡c2™¸å–[hÓ¦M¾ûZËoÔ]wÝE@@—.]bß¾}DGGc6›©]»6·Ýv›ÍLðÊ ==•+W²råJªU«FË–-©U«©©©?~œýû÷™µÞGŒQƳÍÛ /¼Àœ9shß¾=ݺuÃÅÅ…½{÷ÁéN:ñâ‹/ªO~øá† Fxx8  aÆ4kÖ GGG®\¹ÂáÇ,úN:ûqAfíù&Mš@ÇŽ±·Ïþv¥U«V¸»»ãœôˆgîܹÌ;n¿ýv¼¼¼ˆ%44”3gÎзoß<ƒñ]ºt1ν»»;ÿøÇ?²µ;88СC6lØ@ýúõ©S§Î Ï9?ƒæ‹/¾àÌ™3Lœ8‘ü‘fÍšǶmÛˆåÍ7ßäý÷ß¿á1ÒÒÒXºt)K—.ÅÁÁFQ­Z5ÒÓÓ9uêT¶5 ú÷ïϰaÊãÐDDDDÄöEDDDЉ½½}® ãÂîß¡C:tèPŒ³²­FÜ{ï½%>NyáææÆàÁƒÙ²e ‘‘‘lÞ¼9[»££# àí·ßÆÃãl&Y}úô¡M›6¼þúë¬^½ÚxÝÞÞž¡C‡2uêÔ<ë«ç§}ûöðñdz|ùrŽ?žë¦Qƒ ¸ÿþûiݺu‘#/]ºt1û¶JÖØÙÙѱcGÖ¯_-û½I“&Üwß}lß¾3gÎ|+///ž}öYÆŽ›ï|çÍ›dÞð°ÖäϹ5°_RÙú¹Xï’%KxñÅÙ½{7àÀ@æÿ÷O>ù„Çü†û·Ýv3gÎä?þ`çÎÄÅÅqøðá\Û5k֌矞G}Tk˜‰ˆˆˆ” Ó•+W,e= ‘âÀÀËx&RË–- {÷î@fv}I:}ú4çÎãâÅ‹dddP«V-Z´hQnË…‡‡¥`Ö¬YCÛ¶mIOOgïÞ½œ;wÚ´iCõêÕ‹e¼¤¤$BBB¸xñ"©©©xzzÒ¸qcêÖ­[,ý—7éééüý÷ßDEE££#uëÖå¶Ûn»¡›$åÁÑ£G$¾¾¾´jÕÊæM‡•žžÎÉ“'9uê111ØÛÛãééIÓ¦M©U«V±“ëñXŸ¶±–"¹Y(c_DDDDn*õêÕ+³b‹‹]‰­àìì\*O”vvv4mÚ4×ÂÖÙ­·ÞÊ­·ÞZbýÛÙÙѨQ#c)}Zîîîe=›:t°gÒ$<øúÛ>ùä“üüóÏ 4ˆñãÇÌ„ ðööæìÙ³ØÛÛÓ½{wY°`>ú(­Zµbÿþý¬]»–û￟eË–ñÐCqçw²cÇ£ïƒòǰiÓ&Ö®]‹Åb1ú˜2e S§NåÑGeÁ‚üõ×_4oÞGGG’’’0™L%uŠŠÄ:÷wÞy‡)S¦”»±‹zÞ,Ë ïk» }v{…¬°l IDAT«ví2?îÙS>ú)©þ K¿‡³+ëï‡ÌcÁÑ£0>4iRôþî¼ÒÓaǰ¯„)¾úžiÜ8غ>ýºv-ëÙT4oÞœZµj?/‹%×ÏNÖ¶ë}Ìkߎ;²}ûöBͯTþ;GDDVéþȈˆ$''sáÂ.^¼H“&M¨S§NYOé†ÅÅűtéR/^ÌâÅ‹¶ .ðÇзoß\û9::À±cDzµŸ?'''š7oNóæÍyå•W¸ï¾ûX¿~=gϞͶ­‡‡‡ñ¹··7)))DFFâëë[ GYr¦NÊÔ©SËzy*ìµhy½‘"""""’“.]K_aúÖ9_+Ê{ŽìÇÅņ­ZµÂÏÏûÊx{PDDä&•––ÆÙ³g !,, r›¹=K–,!!!† òÊ+¯¯ÿþûï¬ZµŠüÑf`¿Q£FìÞ½›>úˆ£G2sæÌlí;vìàñǧwïÞ4mÚ”˜˜6oÞ @;kêœ 5kÖäž{î! €~ýú1bÄbbbpvvfôèÑÅsÐ7¡ 6°zõjÍ£>Êܹsö ЦMV¬XÁo¿ý€»»;S¦L¡[·nùÎûçŸf̘1üöÛoŒ1 ÔËÝ\Ï”)SÊÝœò³{÷nªT©ÀÑ£GËx6""""""…Wâý˜˜€rÿ踈ˆˆõo½õoysâ¼û.,_ÿ÷àâ’{k}NwÜqG¶Ä„œÛµhÑ‚ððp"""ðññÁÑÑ‘/¾øÂhoÙ²%[¶l!55•¨¨(Ìf3µkׯœåC^ÁñZµj±hÑ"RSS9{ö,xyyêØ%»É“'0nÜ8’’’Êx6"""""ÅGùÔ7ì[ʵ³³S¦¾ˆˆH%fggüïoy3t(;»wÃûïôiÅ[‡ÒÎÎŽzõê廃ƒÃ ¯AàààÀ-·ÜrCûŠˆˆˆHÅ£šéR*ÅsóÉãAt‘Ê¥n]˜5 ¼½aýzøûﲞ‘ˆˆˆˆHéQÀ·rS`ÿæ£UlEDDä¦áèwÞ «VÁc•õl¤¢Èg}ãJ5¦ÈÍ((Èvi6‘ÊD™ÿ7}Ÿo>¥ØW)þ»fj…”‘‘DZÚyL&üÊz:"""""RN(c¿|X¹r%ýúõ+ñ±”±/"""7•I“2ÿå塇âòå˘L&jÔ¨Aûöí9r$îîîyîwìØ1ž}öÙ<Ûk×®ÍÂ… ¯;¿ÀÀ@ÞyçzõêÅ믿n´mÞ¼ƒ»ï¾›&Mš°ÿ‘ëö%™Šš½´gOé]”1Eäú:w†¤$e7ŠˆHå£À~ÙY¹r¥ØèÛ·o‰ŽWê}eˆT>¦J &**Š5jàììLPPK–,á·ß~cëÖ­ØÛÛ¾|JHH`ÇŽdddšš €““ÀuÖµú÷¿ÿM`` ¡¡¡L˜0ÁèCŠÇ”)S˜:uªñõ—_~É«¯¾ÊôéÓËpV"""""7®½%«rõW®\‰Åb)ÑÌ}-ž+"""bÃìÙ³ gÆ ìܹ“ýû÷píÚ5>ýôSž|òIyä¦L™B³fÍHJJ"))ɸ srr2^ # €_|‘‡~˜‰'òwŽ|cbbX±bf³™&MšpåÊV¯^ç7nãÆ#11€eË–1nܸ|÷»ÙM™2‹Å’ퟂú""""R(§ºôå ê[­ZµŠU«V•ظ 싈ˆˆä£nݺÆç‰‰‰ÄÆÆÒªU+&L˜ÀêÕ« ãÃ?äÚµkùö3sæLî½÷^¾ûî;>ÌÌ™3iÞ¼9ÁÁÁÆ6¿þú+‰‰‰tïÞ‘#Gðã?æÙgrr2³fÍbÖ¬Y¤¤¤™¥|fÍšÅÖ­[‹rØ"""""R¨Æ~ÙÈ+¨oU’ÁýR_<·¼–â9r$ÇgÈ!¹êãÎ;—¥K—Ò¬Y3>ÿüó2š¡ˆˆˆ”¦Ï?ÿœ¥K—wÚ´iÃ'Ÿ|±cÇhݺ5AAA¸¹¹‰««kž}%''óæ›o°nÝ:ºvíÊ[o½Åûï¿Ïo¼Á¦M›øá‡xì±ÇèÝ»7&L`íÚµ\¼x‘š5kæ;ß¼J•E-×T^¯!EDDDDÊ•â)}+W®dÅŠ×ÝÎØ/îšûå.cîܹT­Zµ@ÿæÎ[lãþç?ÿ!((ˆ“'Oæj;vìAAAìÛ·¯ØÆ“Š%%%…   ‚‚‚¸zõjYOGDDJÁž={Xµj&“‰‡~˜õë×ãââBhh(?ü0nnnøøøàààg_ÇŽ#99'''ºví @Ïž=8xð ÇgÛ¶m˜L&üüü8sæ Mš4!55• \w¾vvv€à"""""7#eì—®+V(¨oU™ûå.c?55•äääõ™ššZ"o^óêÓZƒUn>—/_æÞ{ï`ýúõFPFDD*¯ü‘G}4×ëÖÌùÓ§O¸¯5j™7Н^½Š§§'.\ÈÖŸ5[ßb±Ð»wï\s3fL®~³ÞLˆÇÙÙ™cÇŽx^e¡°×RŹ0seZäYDDDDÄ….KÞŠ+ò-¿“ë:hÅ•¹_®ŸÙ^´h>>>y¶×«W¯g#"""C‡åË/¿dÞ¼yxyyѤI¶lÙ¬Y³¨ZµªÍ}jÕªE×®] âñÇgÀ€̘1€Áƒc±Xøé§Ÿ;v,M›6 ==qãÆñŸÿü‡C‡åê×ÕÕ"##=z4>>>üñÇ%täÅ+99™W_}•U«VáååÅ믿ÎC=TÖÓ©”±_z|ðA|ðÁ\‰ìùXœIãå:°ßªU+ïEDD¤X|ü1DGÃsÏAQÊÑwéÒ…Ÿþ™I“&ññÇàîî~Ýux~ùåFŒÁÚµkùý÷ßqrrbܸq¼þúërêÔ)ÜÜÜøðéR¥Š±ßï¿ÿÎï¿ÿÎ?þÈý÷ߟ«ß3fðÌ3ϰpáBZ¶lIÿþýY¾|ù`)™äÛo¿-‘À¾ˆˆˆˆÈÍB9-7r±_X111Œ=šÅ‹çj3›Í<ýôÓ̘1#Wз¨, Ó§OgÆŒ$&&æjïÚµ+_}õU®§–.]Ê[o½E½zõ8räH®ýÆo,ª0cÆ ^zé¥líQQQÜu×]@fÝ÷Âöcbb˜8q"óçÏ'###Wû€˜;wn¶à½ÙlfðàÁDEEÑ­[7~ÿýwÌæìk0§¥¥ñðó}ûvjժŮ]»Šd&7ÄÆÆrÇw¯µk׎… –á¬DDDDD*.…˜n>å.c?k{a2öéÕ«—€íÕ«Ý»w'==uëÖ±uëV¾ýö[Ž=Êš5k²eÕÙ· m/½ôß}÷·ß~;ÄÝݽ{÷²dÉ‚‚‚èÞ½;AAAٲŻwïd.¾wâÄ êׯo´¥§§h|½aÃ^|ñÅlãnܸÚ·o_¨§bccéÑ£‡ÂÎÎŽþýûÓ¾}{ añâÅ,_¾œ'N°yófœÌþæÍ›Gß¾} äƒ>à7ÞÈÖ÷»ï¾ËöíÛ1›ÍÌ›7š5ks»Ñq­._¾Ì=÷ÜcÜ騱#=zô ZµjDGG³cÇ6oÞLDDD¾‹ _ïõ¬?{¤E‹ÌŸ?€>}úäZûÁÑÑÑØ~ß¾}ôéÓ‡˜˜ªV­ÊC=Äm·ÝFJJ 6l`Ó¦M|øá‡\¸pÙ³g_ÿ›%"rƒV­ZeÜ .¬~ýúѯ_¿bžQÙ1›¡AƒÌr<< ÂÈ‘àâRÖ3»9ÅÄÄ`gg‡»»»ñš§§'111e8+‘ÊM™Ü•›jìß|ÊuÆþþýû‰ŠŠ²ÙV£F 4h`|ýî»ïŠÉd⫯¾âñÿgï¾Ãš:ß>€ÃÞàb‰(Tª¸÷ªZëhµjÝ«Zg­Vk—µíÛÚÚÖ ¢­?ÅUm±­{Vqáª7 ¢ lA@VÈûÇiŽ I Ìòý\×¹’œñœç$!$÷¹ÏýŒ#.[°`~üñG,Y²§OŸÆÏ?ÿŒ… –K:$õ'Mš¥’,'NÄСCñôéSÌœ9SiÄä6mÚÀÞÞiii8yò¤R`ÿÚµkHOOGݺu‡3gÎ ??_é„ÄÉ“';w†™™Y‰ú=gÎܹsvvv8tèÚ´i£´|æÌ™xýõ×qãÆ ,_¾K–,—õìÙü1¾ùæ,[¶ ]ºtOR;v ?þø#àã?ç—Ç~`ÆŒ ƒ™™Ö¯_áÇ«[tt4222Jô|å£>B||¼ØŸ;w.ºwï®vÝ/^`ìØ±HKKCëÖ­±wï^¥LÎùóçcýúõ˜;w.1tèP¼úê«åÖW""EòÀ|IƒûÕ-¨>>ªó4|”S%°´´„T*Evv¶x?33³È«*Õ½†Õ™¡¯6BBx2Žˆˆ¨4˜ÉmXØ7FůR>äÐÚLr£FBÏž=ÕNË–-×þü9#GŽÄèÑ£UÚ\°`Œ @nn®Ú}ÕuËþùg€‡‡V¬X###¥åÝ»wLJ~Æ7Äe‰DìÓ‰'”¶;qâa”e///dddàâÅ‹jב×åÕv Ãßÿ X±bZ·n­²N›6mÄLüµk×"??_iùâŋѽ{w`Ò¤IˆÇÓ§O1eÊñ¸/^\®û½~ýºœúøãñÖ[o©=¾úõëã•W^Ñúõ-÷|Úºu+¢¢¢`aaM›6¡V­Z*ëL™2ýû÷üòË/%zí8qâÄ©¤Ó Aƒ0hР [¿ðD¤† ÂÄÄ÷ïßç…‡‡ÃÓÓS‡½"""""ªº˜±oxô:c߯ÆF¥~»œ•BºÎÙ³gÅ í©S§jloêÔ© Abb"®]»__ß2õ/##çÎŒ?^cÖü”)SðÍ7ß@&“áÈ‘#hÙ²¥¸¬gϞطoNž< ™L&Ö\W ÚáöíÛ8qâ:uêxðà=z$®S»wï†L&ƒ FŒ¡q½aÆáã?Fjj*nݺ…V­Z‰Ëäev:vìˆøøxLž<2™ ¨S§6mÚ¤òÚ•u¿{öì Ô&ž1cF‰Ž¹²ìÚµ €0®B“&M4®÷Ö[oáСC8}ú´ÒëNDT´Íܝޙúr—/ ·YYB)žÌLàäIfÿV&ÅuVVV8p üüüˆ¤¤$lß¾«W¯Ö¸½ü5¬jJû/¾ªoEèÚÈÎf¶!QQø]©ò•%ž'ß¶, rzØ¿xñ¢Ê€³êܺu `llŒ¶mÛj\¯C‡JÛ”5°çÎqðWÅÁß sttDƒ %öU®W¯^€¤¤$ܺu -[¶Dvv6þý÷_£[·n022B@@Nœ8O>ùÀËÀ¿ƒƒƒRÀ]W®\8;;ã?þ(r]‰D™L†‡ªìÇÙÙ6lÀàÁƒÅþÈþNNNå¾ßk×®¼½½•jòêù1š˜˜`ëÖ­דg(¦§§#--Mã@ÁDD奸à~uê@AÁËÁsŸ?FfP_×0hÐ 4hÐiii˜8q"¬ënUiÌØ/_R©T×]ÐHïÏ-¼6맦¦ììì”1-¬N:âý””랯øXñ¾|¿ò¶‹ê«££#¢¢¢Töëéé ]«mÒÓÓÕî£W¯^:t(vìØ˜~ýú!$$DiÒðööVd¸(íÚµS;ÿúõëJ¢ƒâóÏ?G­ZµÊ}¿Ú¾Îº¢ø‡9dȱlRqÈ ¢Ê$ÏÊ—v4¨Zgê6uª0™T‹o@Õƒ»»»®»@DDDDT屯¾áÑ»Œý¢²å5‘‘Ÿ?.f´«+Þ¯]»¶Æ³&EeQ\¦¼Ž‹‹Sª¯ißêöÛ³gOáÌ™3ÈÍͳñ{ôè!®Û³gO\¸p'Ož„³³³˜½®¸Ž¶äW.XXX`æÌ™ZoWx?7nrrrТE @î‰'ÄŒ~WW×"hÕDÞîÕ«W‘œœ\âíåæÌ™ƒÈÈHØØØ`ëÖ­X»v-$ þùç¬ZµªÜ÷+áÎ;ˆ‹‹+ѶòR7Š'w »yó¦ÆeŠWZÈÇUPG~ŒG-Qÿˆˆ*›¼üU}ÌØ¯8‘‘‘ˆŽŽFtt4>|ˆ˜˜ÄÄÄàÑ£Gxôè?~ŒÇ#66±±±ˆ‹‹C\\ž|8LMM‘ŸŸÿû¿ÿ+U7nûáïïF¡_¿~˜={6`éÒ¥â@²åµßaÆÁÄÄR©ß~ûm‰¶õôôœ;w999*Ësrr°qãFÛÛÚÚŠYÿIII×{çw7nÜÀÎ;KÔG"""C ‘HJ4QñدX–––2•E¥öå—hšJ²®|255Åüùóí‹/K®Èd2dffbÚ´i |ôÑG*í·_MË,Xccc$''côèÑHJJ—`ÕªUØ´i`ôèѨW¯žÚöåAúk×®€8­â1vêÔ 2™ ¡¡¡^–á)éäææ&àׯ_Å‹‹ƒÔ*Nؾ};fÍš¥4ÿÖ­[âs8a >\\¶téR´mÛyyy˜0aÒÒÒÊm¿õêÕÃ»ï¾ Ø¼y3>ùädee)­#•JqìØ1?~\i¾üL||<þïÿþâ²äädL˜0QQQ_g3334mÚ°aÃ<|øP© ù4lØ01kÿ½÷ÞÃæÍ›‘ŸŸ¯²^ll,üüüàççWª×'Nœôm"""""""ÝaNŒá©6Cǽ÷Þ{8þ<öìÙƒÕ«WcÇŽèС pöìY±&ý¤I“0jÔ¨rÛo›6m°lÙ2,Z´§OŸÆ+¯¼‚®]»ÂÖÖ×®]Cdd¤¸Þ÷߯±=z 00P|¬.¿gÏž8vì˜ø¸{÷î¥î÷’%Kðøñcüõ×_X½z56n܈öíÛÃÉÉ 999xøð!îܹƒÜÜ\¥±²²²0a¼xñ^^^X¾|¹R»¦¦¦Ø´iºt邇böìÙØ²eK™÷+÷õ×_ãÁƒ8räV­Z…Í›7Ã××5kÖDJJ BCC‘””„ï¾ûNi`á=z W¯^8qâV®\‰={ö eË–HKKÃÅ‹‘——‡%K–à‹/¾ÐøœÍ˜1sçÎEHHZ´hccc˜ü7úâƒ`gg###lݺC‡Å­[·0{öl|õÕWhÛ¶-ìííñüùs„‡‡#""2™ 3fÌ(õkHDDT•ðé~$QU§×ƒç–$ P"‘`ãÆð÷÷ÇÊ•+ñôéSìÙ³G\îèèˆ>úS§NUÛ¦bÿŠÚ§ºeÓ§O‡››–,Y‚ˆˆ9rD\faa‰'bÉ’%°¶¶ÖØv·nÝ ‘H “Éàààooo•uåµø qãÆJ7””‘‘Ö¯_W_}+V¬@xx8N:¥´Ž……ú÷ïQ£F‰ûùàƒpÿþ}XZZbÓ¦M°°°PéCýúõ±jÕ*Lœ8»wïÆúõë1eÊ”2íWÎÔÔAAAøå—_àç燄„‹Ë% |||кuk•m·lÙ‚™3gbß¾}ˆŠŠ3ô6lˆ€€˜™™‰ëª{L˜0–––ؼy3nß¾´´4±¬<{ÞkGÅÏ?ÿŒõë×#!!‡Vj«V­Zèß¿?FŒÁ@U ü,#¢ŠÂªHÌn$"¢ê‚¥x $55µB_nyÐõõ×_PôÀ£å%??W¯^Ell,$ ÜÝÝѺuk±FzEº{÷."""““'''øøø”¹^ReˆŠŠÂ½{÷––KKKÔ­[^^^Þ÷²ì·  ·nÝBtt4òóóáì쌆 ÂÙÙ¹Èíbbb ©TŠúõë£M›6VÃWÞLJ"++ ¶¶¶ððð€§§§Ò€¼DDUü¬üDfŸ>}tÒàà` 2D||ìØ1ôîÝ;š`Ñ"`Ät‹ ˜ü;FI’UJ²¾!èÒÈÉΜ,,tݪ.ªãûÊÇG¸½|Y?Ú©¨öJŠŸÃÊtýzvÞy~ÿøoÈÀ2éÔ ÈËÎr« þ ¾ýعX¼>\×½©‚ƒƒÑ¼ysdggÃÊʪ\Û–'gee‰ã¬Þ½{½{÷ìÞ½@Ñ¿­«M)E&&&ðõõÕɾ›7oŽæÍ›ëdßeááá*µ_###x{{ÃÛÛ»DÛ¹»»ÃÝݽTû,©Òö‘ˆˆˆˆˆˆˆˆH[ÌØ7•YUøÿ¾|9œ ¼û.`R-‹i¯¤ÿ»µÍô¯¨vIU\œpëì T‚D¤çøqjxøÑODDD#0˜>ÈÈÐuOˆˆˆôCNNæÍ›‡FÁÇÇ;wîÔëv+ÛºuÀ´iÂ4}:°p!°z5ðô©®{¼ù¦0¥¦êº'D¤Oª@Εæ«QµwåŠ1,,š¡^½ŸqýúkhÞüg<~<_×Ý"Ò¨ºd°V…«yˆ ÝâÅ‹qáÂ#,, #GŽDƒ жm[½l·²EEW¯5k®®À… À‰À¡C½ò¬Ã IDATÀž=€±±®{HD¤Œ_¿ KñQ™éÿÿ÷dgßAdäp´lGǹxòä H¥ÏuÝ1"""ÉÏÏdž °k×.xxxÀÃÃC‡E```™ðÕ®.õì |ò ðè0t¨± ¸»çÎçÏ­ZyyÀñãÀÛoùùÀÉ“@JŠPÐÝ>ptÚTÜ® j×&MêÔÖ‘É€#G€Ë—…vêÖFÊïÈ%%6·=zTö³CDú€ƒçfì‘ÁJŸ#3óììúÁ¢23ÏëºKDDD:‰ôôt´oß^œçãム  ½lW—>öí®\;:¾ ®ßºüñpô¨\—H€îÝ… }D„°ÞÓ§Bà~ß>àï¿kë—Û:¼x!´•“„… zøøca;33áÄÀåË@Û¶ÊýÙ³©HOŽjÕ:t¨¼ç†ˆôû†§Òûâ%ÅúŸÕGDDDÚ’H$ÉdüÿNDDTŤ¥¥ÁØØ¶¶¶â<¤¥¥ée»ºtåÊË >ôï/Ûee[·Mšúž=ss 1ÈÌ>û ˆŒ®]ºv}¹™°s'œ,dú߸!øïÜ‚ú––À¶mB`?'GØ¢qã€ñã…“G/2°OdˆªI%G* ì›››#''ùùù055epŸˆˆ¨‘H$âÿöüü|Âÿ~}ell këɤÈξ¥ëî‘ø³¨âXZZB*•";;€ÌÌLXZZêe»ºÔ»70e ,] lÞ 4kôíûr®]…y`cüú+ðÛoB0^QB‚òc__ÀÎNØF.#î·l)õáDAá¯Z}ú·õë ·ÏYiÈ 1°ox*<°ooo„„$&&ÂÅÅE T—ÁˆˆˆH8aŸ˜˜@øß¯ŒÄÁsÿ3ëëU1üù@Tþ6lÜ¿ÞÞÞ€ððpxzzêe»ºdoxz S£FBö~x¸r`_10¬_XXAAB`þ½÷„lüÂ',å™ÿFFÊókÔxÙ–L¦ùsPè/¼=&&EŽ ì{xx 11÷î݃L&ƒ££#ŒØ'""ªd2¤R)pÿþ}ÁÃÃC×ÝRÑ®T¼ßªàç÷ll>ÐaÈP”ö;oU»º•ß퉪&+++ 8~~~ DRR¶oߎիWëe»ºtë°j•mõª0ÏËKóúRéËÛˆ¡6þ­^,Ø¡P³¦Pßñb K &èØðñ)ÝqQõWžFRTx`ßÖÖM›6Ž{÷p÷î]ܽ{·¢wIDDD: ‘HдiS¥zºúfêTa2©´Q†ˆˆˆô[@@ „  -- 'NÄàÁƒõ¶]]¹_˜,,à­·„úš¸ºcÆ¿ÿ.ÔÖoÛhÑBÈØ×–àç|÷0(î±cÂw_ß2UC<×ðTÊÏZ777ØÛÛ#** iiiÈ)\`Žˆˆˆª,sssØÛÛÃÃÃC¯ƒú‹#FèºDDDúÅÍÍ ¡¡¡ˆ‰‰­­-jÈë¿èi»•íÛo…©(Ó¦ Sa| ÔåÏεÛîòeåÇÍ› õü_¼RS… þÿ†-PYWS?¨êa`–Jƒ}ÃSiùj¶¶¶bm="""""""ÒîòÑY«H»U…0••¥¥0‘a)ïJw øVo¬Œhx8´ QÆŒ}ÃÃÀ>Q¡㈈ˆˆˆˆˆ Œ¤‚j6TT»U]n.”$ ~«®Þ>Qyaƾá`Æ>‘rsߦÜ\í·»yxóM`ÆŒŠë6–â1<ÌØ'""""""2²b">>>ÂíåËåÓniÛÓW99ÀŠÂý7ÞÌÌtÛ""9ö ûDDDDDDDDÅÈÊ^>û£G/^{öOŸùù€“0hà奾­ìl`Ãa»>}€V­€«Wà`¡dOƒÀ¨Q@ÍšÂúçÎçÏ ëëÕ® LšÔ©Sá‡NDU+¡ö‰ˆˆˆˆHïñÇ*•'f3Ridg‡¿||ø°ðÙÔ¿?p÷®l¯_J³g¿ÿ6n^yE¹/€÷ßù#GÞÞ@Pðã@@“&À–-ÀŽÀ5ùoÝî:$lW„… 'ˆˆ˜±oxØ'""""""ƒÄFT5kû÷½z ÷ïlm…ûõëƒ))@Z°m›°<8X9°Ÿ“Ì \»L ¼÷žP«Õ*áý¸y3àê*œX½ZÚ/^ür{33`çN 9xûmàÆ ¡MsóÊ{ˆH¿1°o8Ø'"""""""*ƒK—€eË„€»¢„åÇOŸ SÛ¶BP?‚ó€0À®¢û÷•ûúvv€ÍËy ìOV"ö‰ˆˆˆˆˆˆˆ´`d¤~þÏ? Aý¥K…šùëÖ Ù÷…3gëÔ¬­…2<«VsæÂ2ccáä€â>øÀËÁz5õƒˆˆû†ƒÿ ˆˆˆˆˆˆˆˆ´`m XY ÷W¬þ÷?¡¦¾T*Ì‹‰ºÝ·OýöVVB‰gg!ð¿v­PâÇ×Wh#$Dæçç uúïÜ©œã"¢ª5ö O…gì_¸p¡¢wADDDz¤C‡ºîQ…™7øõ×—Áû‰…Áp¿üR¨‰ïì,êÚUää¬Y#ÔØ_·05¾þøþ{ààA¡6?¸¸üZEDÚb)ÃS)¥xøŸˆˆ¨úãÉ|"""2Æ “¢¾}îÝ…r<ÎÎB©œÿû¿—ËÛµ._~ùØÝ8rD¹åË…Lý„!kßÎîå²iÓ„I‘b{DÚ`&wõÆŒ}ÃSi5öm †«îÝ»ðôô„„§Å¨Šàû–ÈpÈd2œ:u -Z´€““dÿ}ÓÉdâ}Åuµ½Õ´m§Npþüù :""""ýfn¸º–­ “²·ATúö G¥ö ª2y0Tñ˜ªÓñQõÄ÷-©S’€¾ü¶ð<ž$$"""""Ò-þ,3<<—ˆˆˆˆˆˆˆˆˆ¨`§á`Æ~ÎX$ª ø¾%""¢ª„_YˆˆˆˆŠÇû†‡ûDDDDDDDDDDUKñžJËØ'""""""""õ||33Àΰ·š4¼½®]9 .û†‡¥xÊ€%M¨*âû–ˆˆˆˆˆH?åæIIÂôàpø0ðÃ@·nÀ{ïžžºî!Uþ\§²àûÇp0cŸˆˆˆˆˆˆˆHOii@x8pã†Ü ÎfÏÆŒaÉ CÁ×™J‚û†‡5ö‰ˆˆHÉÞ½{±oß>]wƒˆˆˆÈ 98õë}úóç ˜˜+W›7뺇D¤x"Èð°OjI“ýû÷Ãßß_iÞ/¿ü‚F•¸­‘#G"55U|ܹsg,]º´¬]¤"êû–ôÃŒ3ðàÁŒ9S¦LÑuwH½{÷bïÞ½âãAƒé°7DDDDdb¼õ–PoÊ hÞèÐA×=#"}ÄpáÐëR>>?~<ºu릃꟯¿þ?ýô“Êü·ß~ëÖ­+—}¬Y³£GÖqáááxòä àíí­ëî”ÙåË—‘••…úõë£~ýú×»zõ*nܸ__ßJìi«pPïÞ½Édxã7tØ+"""ªºvU§)øTš Ty²Jòuµ<£(MšK—‹«V }d†.ÉñóÀðèu)ž¼¼<äää¨LÙÙÙxöì°uëV¼öÚk˜={6 tÝe’Édøí·ßÔ>g;wîÄóçÏuÝE¢J'“ÉÄ¿©Tªëîˆüýýѯ_?|øá‡ºîJ¹˜2e úõë‡ß~ûM×]¡R*Ô—Û·oËò"#«WK¿}v¶ê”“£~ÊÍ-ù”—§~*­‚í'™LýTzõš6€+W*fDT5±Æ¾áÑëR<òm\\\pðàA¥ù‰‰‰ E@@=z„ÀÀ@´lÙÓ¦M+·>kÛ?})iròäIkðÊ+Úm"ÜjÊ$-¯ùš˜›—l}¹ Êgÿ%9íÚë׸w8^»mˆÈ°ð§¶áÐëRŒÑ¼ysôïß–––%îÛµk×pòäI¤¤¤ÀÑÑ}úôAóæÍµÚV*•âJ¡ë ëÕ«äççãèÑ£¸qãÒÒÒðÆo S§N*m¤¦¦âÌ™3¸wïRSSaee…zõê¡gÏžpww/¶ò1"##ñüùs˜™™¡F¨S§Z¶l‰fÍšÁÄDýŸ’T*ÅùóçqóæMÄÇÇ#77ööö¨Y³&<<<кukÔ®][«ç‚*Fdd$’’’`oo/ž@<{ö,þý÷_<{ö ...èׯ_±ƒC§¤¤àèÑ£ˆˆˆ@ff&ìííQ»vm´jÕ mÚ´ñ¿ ž={†û÷ï‹›ééé¸xñ¢R[ÎÎÎâ{3)) ‘‘‘022‚Ïé8÷îÝñcÇðäÉØÛÛ‹å|îÞ½‹çÏŸÃÕÕnnnjû™‘‘;wîZµjs )LR©/^Ä¥K—˜˜KKK¸ºº¢S§NJ'ZcbbðôéSdggbccUŽÇÓÓS?ãöíÛbƾ¦>Âërüøq<~üFFFpwwGŸ>}ŠÝ¦<^KC²gÏ­‚úròÌ}÷‰¨2ñÇ)‘þ17N²ñûõ¦OêÕÓu¯*NA°~}ñëååqqÂtö,°r¥ÜŸ5 (âkl‰¹¸· ?÷‰ŠÄÚ놯³áÑëR<%ݾV­Z*ë=yò={ö?~ÄO?ý¤²^‡°yófÔ+Å·}('±{÷n•lýýý1fÌqì™L†ßÿüq‘mýõ×_˜7ož={¦4ßÉÉ ÿûßÿÔ¯º'©©©˜:u*>¬²þ¨Q£àçç§vÿŠí<þ\|ýä¾úê+ôíÛcÆŒQ:™S£F tìØQ|œœœŒÏ>û AAAÈÍÍU»¯7Þx?üðƒÚ×=-- sçÎÅŽ;Š|-,,°téRÌ™3GiþîÝ»ñá‡âÉ“'·777ܼyfffE®WÞôá}[ gáÇË–-ömÛЧO¬]»ãÇÇÙ³g•Öù裰páB|þùçj÷±|ùr|÷ÝwÈÉÉQ»ÜÁÁ±±±€Œ5J\výúu•÷ø¬Y³°|ùrÀ¡C‡0}út˜››#&&³gÏÆ_ý%®kgg‡ Þ{ï=\ºt óçÏÇ×_­¶/·oßF¯^½wîÜQ;Ðí°xñbµ'KÀÇǧN¬Zµ «W¯—mÚ´ ›6mRZ?((H,á2yòdܼyScÓÓÓ1wî\¥c”322Âĉ±|ùrµ'Ëãµ4${öì)²üŽ&û÷ïÀÌ}"ª|ü±J¤:u¾øذع8|8r<˜:µb2ÔuÍÈhÙ¸ySø,26öí²óI¥@Bpû6pæ pèpô¨pä½÷€qãÊç³ÌÎN¸}ú´øR<—/—}DTµH¸‡P 2ö³C}‹¶ÞÏÏ{öìA‹-0dÈØØØàòåËØ¹s'.\¸€àÌ™3°··¯Œ®—«­[·*=nРÞ|óMtéÒ§OŸçØÿ믿0iÒ$µAßøøx >,¶?/^¼À AƒªvyPPŸŸ_l[…ÅÄÄ`àÀHIIQš¯8xrxx8(S5Ù·oΟ?ýû÷£eË–JËFŽ©ôÜi’„„¥y§NÂØ±cµ ž?~üØà~Ö™™™xã7ðàÁ >žžžxòä >Œ'Ožà»ï¾CãÆñÎ;ï(m·víZ|ùå—„ ø×^{ uêÔAzz:bccqæÌ„‡‡‹ë7hÐS¦LÁÙ³gggg•¿)ÅTŠfΜ‰;vÀÛÛ;v„D"AXXX¹>k׮ł “Éààà€¡C‡¢iÓ¦ÉdˆˆˆÀpÿþ}¥¾fggãï¿ÿFZZÚ´iƒ¶mÛ*µ©ÍUB€ð¹Ñ¯_?ܸqðÚk¯¡gÏžJ¥øçŸpæÌlذáááØ¿¿Æ+eJûZšÁƒcðàÁ*ãnhsk('‰ˆˆH½ÚµE‹€±c…Löýû]»„Û¡C…uìí)S _Ùªœ €  !`–Ÿ/ìGV^ÇØXȦwqúôÞ}Wx~üý…o—.*9§‹ˆ “ O•ø›ŸŸ‡Še2’’’Š•+W"==µk×.6}Ïž=?~<IJ0nÜ8 >‘‘‘øâ‹/°råÊ ;–ŠðèÑ#•ô[o½>|¸Ò²ÈÈHœ;w;wVi'!!sçÎU ØØÛÛ£Y³fxüø1bccUJþ¨³lÙ2µAýfÍšÁÊÊ 7oÞÄñãǵ:¾ÂÕ•äÁñììl >\%¨ß·o_´iÓOŸ>ÅŸþ)–IJJÂÈ‘#qéÒ%X[[®^½ªòœöéÓíÚµƒ™™’““q÷î]\ºt *}ñ÷÷W꣓“ ggg¼xñ111¸víšR€”tëüùópssÃ… ФIq~rr2ú÷ïÛ·oãÇT ÿòË/€#F`ãÆjÛ¾ 0òVË–-áïï¹sç",, Mš4¿¿±ýËÉÉÁÎ;±zõjLœ8±GX¼k×®aÑ¢EÉdèÖ­þøãÔ¨QCi+VàØ±câãaÆaذa AZZú÷ïO?ý´TûÿꫯpãÆ H$üïÿÃh…_JóçÏÇO?ý„%K–àôéÓX¹r¥X‚¨°Ò¾–DDDDô’6ƒ²ººK–ãÇk× Áî?ÿjÍÀºuÛÇŠTÜñ9¢Ø/¬n]áê†7ÞæÍ¶)(¾ýV¸  ´ÒÓ…[ggádŠ:T—Èð°Æ¾á©¥xâââàåå¥v™©©)fΜ‰Ù³gÃÝݽȲuëÖÅŠ+`dd¤4¿wïÞ˜1cüýýñÛo¿á‹/¾ëA¥p£®lÛ¶M¥Ç‡L&Ã!C°`Á¥ÌømÛ¶©­E¿nÝ:¤Ë¿!üçÍ7ßÄúõëaee™L†eË–áÛo¿UÙV1ƒ333k×®UZnaa;v G€èèh 8Pé„b[êî+γµµÅ§Ÿ~Š×^{ &&&¸}û6,,, “ɰnÝ:DDD(mó믿bìØ±âãéÓ§£W¯^b‰ž‡bíÚµøàƒ@¬A.7`ÀüùçŸ*}ÉÍÍÅñãÇ‘ŸŸ¯Ô×»wï*­·cÇ´–p¤ &&üñ‡Ê{²"éËû¶²~?uÜkÖ¬AãÆ•Ö©Y³&.\ˆ‰'",, OŸ>…“ÂõÅ111„²$šÚöõõÕ¸¬¸>).?~<&L˜ ÕkWÔþ4íû»ï¾C~~>êÔ©ƒßÿ*íãµ×^ÓºÏÚö1##„«eÞyç•væÏŸàà`„„„ sçÎ…©üWc!¥y-©ú3=""*f7–Cû?{÷.›«]ö}Û¶ÀêÕÀœ9@p0àîÌœYú}Ë«½.DDÞç±!«´À¾T*-ñ6ò€ŒD"­­­Ò²ÜÜ\dgg#//Û·o‡½½=-Z¤2®b‰“·ß~¦¦¦jû2nÜ8øûû#;;'OžëA«#߇¼Ò[yúý÷ß•{zzÂËË R©èÑ£‡R†íŽ;ðÝwߩԨ>pà€ÒcSSS|ÿý÷077qáÂ…øã?¥´nAA¸Î‰'T²ØÇŒƒ®]»ŠëÔ«W‹/ÆŒ3”Ö“ÉdJϧ¦çvãÆèÛ·¯øX^'\*•ªà[·nwÞyG©­-Z _¿~Ø·oŸÒó2wî\PyݸqgÏž…Rùccc±Ší+^%ŽœQ§Ð7¯ºuëŠYÇý>Ò·÷meQü P|ŸÊÉ?g\\\УGµÏK›6mÄû‘‘‘J»ºº"** »víÂÀ5–‡)ª_E½Šë7®ÈuåÇ¢î8Õµ§¸^vv6Ž9"îÇÎήTï‘¢ö]TOŸ>-Ž2iÒ$mLž<!!!HLLÄ•+Wо}{•¶KûZ‘æšìçÎÿý\ÅÅ Yù™èffÀ!Â2})ÅSÚ“7ꞇˆ`Ô(ÀÒxñBx¬!QEË–B9ž)S€M›€.]€V­J×7ùÅñ…*`‘cƾá)ÃÅ_•ÇÍÍ =RšâããqïÞ=|õÕWxþü9–-[†É“'ÙN»ví4.óôô„ Õlm}vñâEi%w×®]hݺ5>ÿüs9rÏŸ?/÷>¶hÑ¢ÜÛ”»sçŽxK×®]+l?šÈ?Œ•‚ï…)Ž¥Rø3K®´¯%i') øþ{`Ø0aY@¸¿k—P{Ñ"`útÝõËÛùdçÊ$&–l{oo¡,OA°reé‚o2ðÏ?Â}5â‘c`ßðèu)žâJ²899aîܹ(((ÀÒ¥K±k×.Œ1B)ð¬¸]íÚµ‹ìGíÚµ‘‘‘””­ÊLèCI“ÂÙú€PóZ±Oƒ ¼yó““£´Ý°aÃÄÇiii*Ùºººª=¶ÂÁ~@¹¤Grr²Êr•¶lmmamm-fénGþ¸°Ö­[k|Γ““U¢ŽŽFtt´Úõ )) NNNhԨƎ«2(qnn."""C‡aùòåhÒ¤ ~ýõW¥`þ‚ pèÐ!•Àabb"qñâElÙ²&&&˜:u*¾ùæ•,ÿò¦OïÛÊTTy.ÅÇæææZ='R©Ti½ùóçãñãÇØºu+=zøûûÃØØ>>>7nF¥1“_ÛHÍÌÌÄrSÚ(i)Å¿[''§2½?JÓÇÔÔT€ÌÌÌ4¶¡˜a_ø³º¬¯%ïüy`ð` 'G"õïL›Ô«§ëžU« *çåå©Ý¯¦ùrêž¿Â' äJSêÃÅÅEã²²ÇO~øùùáûï¿/2ûÂÃÃ1räH¥ ífÍšáøñã2dÌÍÍ5n›ŸŸ_ý~~~eê7鎩©)V­Z…«W¯âË/¿Dß¾}Å26.\ÀìÙ³1hÐ ¼û/%Iÿ‡VüÛÑE™¦Â¥¢4QÂŒR©IIIPej.}:¦OŸŽèèhܺu ‘‘‘¸wïNœ8¡ô^KJJÂÑ£G•®‚ðôôĦM›ÐÐPÜ¿QQQ¸víNŸ>­À Âüùóµê#é'¼ÿþûxÿý÷QPP€‹/" û÷ïÇ¿ÿþ‹_~ù¥Â_cùßFáyНQ¤}  IDATøwûèÑ#x{{—oçŠ!ÿÜ}þü9233amm­v½ØØX•m¨lÊrÒH¾-¯| ""2:¿¾òŠ®{Rùòò€¬,ÀÜ\8¹agWò6V¯n½½À@åà¼úmòóÝ»…ò=ÙÙÀìÙÂë@D¤ˆ¥x ^—âÑvû‡ŠËmmm5–r9wîœJ½y¹«W¯ŠAæV­ZiUŠG›¾U$uexJºýœ9sÄÇmÚ´ÁùóçÅÇ7oÞÄ;wмysq^vv6öìÙ£Ò–bIuõ±·oß®R›?((Hm¿Š+ÅSÔ|‰D___œ>}ZœwíÚ5Ô«Wj·„«ž>} µmׯ__ ž‡V­Z)ÕÈŽŽV»­¹¹9:tè€ ß¼V¯^Ï>û¬ØmË“¾¼o+›¦Ò3Å­[Ôüâž;‰D‚:À××Ý»wÇ­[·púôi|ðÁâ:ò õ‚‚­ûTÜ~僌ÇÅÅi\Wq Åç£iÓ¦°±±AFF‚ƒƒ1`À€"÷U˜bÆ}iJñ´úoä0™L†sçΡOŸ>j· QÚ¦¤Ÿ†úw`(ƒeQÅqqþ÷?ðõáCáV~‘z:%ÛþÆ aL##`Þ<Í÷©©@Zš¡ó&pø0’"ŒY0o0fL鈪?ù™K¨&ûkÖ¬ï+¬XØßÿ?þuÔü÷ýå—_ß;w.ÿN–³„„?~\i^“&M0pà@Ûœ>}W®\‡……!44­[· :T)°3fÌÀÚµkÑ´iS$&&â£>R[C_Q§Nàä䄸øxqÞÞ½{±fÍLž<æææ8rä~øá­·$Ư؉‰ÁÌ™3ñã?¢fÍšJëFGGc×®] ÄÔ©S1oÞ<ÀÝ»w±lÙ2Œ==zô€¥¥¥ÒvÉÉÉ*õ󭬬Äû‹/†““ „&Mš¨ô±ðUŠÛRõ!‘HP·n]ܺuKeì{{{¯*žžžƹsç““£R*''›7oV»­±±1† †-[¶ ((³fÍ*¶ •¢²Oûöíáè舄„¬^½Zm`?//¿þú+a€\œޤYff&Š=X’“$šÖ-jàc"¢ÒâS"ýàá!L%¥) ]ßÕï/cc qcíÛ»qC(Ÿ#““& ûšôí«üX"zô$öôÔ~ŸDdX˜±oxªD`_*•*eFB©‰¨¨(lß¾Û¶m ”’;v¬Æv2220aÂlݺU)Àëïï/ÖªŸ5kV‘™ÝúâÏ?ÿTÉÀœ1c&Mš¤q›àà`¥ñà?þûcÆŒA@@€R žëׯ£cÇŽ*ezŠbjjŠ?ü .çÉd2|úé§X²d Œ‹,RVòà¤bp×®]øçŸðÊ+¯ÀÙÙééé¸wïžÒ8Šòóó±oß>ìÛ·¦¦¦hÔ¨ÜÜÜ`ee…ÔÔT\ºtIåùèÚµ«xÿÑ£GX»v-¾úê+Ô®]žžž¨Y³&¤R)îß¿(mÛ­[·r|¨²$%%aÑ¢E˜:u*:vì¨2¾ÄÙ³gÅ óÂ'å¥n"""°cÇ 8°ÌŸ=ýúõÚ5k€eË–á‹/¾K¥¤¤¤`Μ9ˆŠŠÒ¸ý‡~ˆÝ»w#==Æ C`` | ý¢IHH@PPXÆKñx.^¼ˆƒb̘1hÕª•ƃÕ133üyóðÉ'ŸàäÉ“øôÓO±téR˜šš²²²0gÎÜ»w°pá w€ˆˆô ?ö‰HŸ4o˜™i·îÕ«B¦}V–´ï=Íëš™ööB™OO eK kWÀÕµ|úMDÕû†§J”≋‹CÓ¦M‹\§nݺضmììì4–®˜3güýýѺukôìÙ666¸|ù2ÂÃÃÙ9sæÛWùò·•©pSSS¼ùæ›Eö¥G¨]»¶RFíŽ;ðõ×_ÃÔÔ–––X·n†Ь¬,¥måAìš5kbĈbÖ¬\á'“'OFHHöíÛ§´žT*OHL™2{÷îEbb¢J[êîkÚWa‰[¶lÁرcqöìYq~VV.]º¤q;ÅvÛÏËËCXXÂÂÂ4n;uêTxyy©íWRRR‘YÌ5jÔÀçŸ^i¥xtù¾ÕmKñ·LÝzR©»ví®]»P«V-x{{ÃÅŹ¹¹xðà®]»@¨¿?sæL¥vúõë‡  ::S§N1ÃþÝwßÅW_}¥vßEéÖ­zôèS§NÁÏÏ{÷îE‹-––†K—.!//Ÿ}ö¾üòKµÇìææ† 6`üøñˆ‰‰Aß¾}ñÊ+¯ÀÓÓ2™ QQQ¸yó&lll”ÊxÀ¤I“°eËÄÇÇ£OŸ>H$0ûï—ÎÆñúë¯û|O›6 çϟǾ}û°fÍìØ±¾¾¾byž””À„ 0bĈr}-«3kkk4kÖ ®®®Jÿš>´¹5ÔÏ"""*½Ë—u³ßÒž,Üßäd !`&“¯½V|±±ÀºuÀÁƒ@A°ÍÒ¥/Kù·O¢òƯíÕ“ O•ÈØWÇÔÔðòòÂë¯¿Ž±cÇjlQnРAh×®-Z¤p611Á˜1cðÍ7߈١úìÆ¸}û¶Ò¼^½z©”™)ÌÄăF`` 8/99GŽKø´oßû÷ïÇ|€ëׯ+mß¹sgøùù)Õ¸ÖD"‘`ýúõøþûï±fÍ¥ìv;;;,\¸3gÎÄÞ½{‹m«4ìíí±gÏüöÛoX»v­Æ ¼¹¹9Úµk‡×_#FŒç;;;côèѸxñ"ççç—ºO›7oÆìÙ³±ÿ~DEE‰ú 6„¿¿¿l×äÕW_Epp0¾øâ ;v ·oßVú¼©Q£†ª²]óæÍqàÀøùùáòåËHNNGÛúîFFFذaV­ZÄÇÇ+}VשS‹-”)S´j”EFF–ûUò ¿L&S)ýDDDDTlÞ,ç%¡Ö}ár9 •ññÀíÛÀÙ³À¡CÂ<33!KÜ8ÞH;å€çûÎ0ðu6<’ÔÔÔ =_wáÂtèÐAgÙ|111b©™#GŽÀÇÇR©W®\All,¬¬¬Ð®];Ô®][ë6åå6ä%!ÔÕP¯îܹƒˆˆ¡yóæ%ª·­(##—.]BJJ Ѿ}ûJ/w»wï"%%°³³ƒ»»;6lXl óÙ³gˆŠŠBjj*RSS!‘Hààà€&Mš ^½zEn[PP€¨¨($$$ %%™™™°´´„››š7o^©Ïƒ¡¼ou%::±±±HLLDAAœœœÐªU+ØØØè¤?111¸~ý:¤R)êׯ֭[—8¨›’’‚ëׯ#%%vvvpqqAÓ¦M+åh~~>®]»†ØØXH$¸»»£U«V*厨xW®\AóæÍ‘]îãyȃúYYYb`ÿîÝ»Jƒ…W¶àà` 2D||ìØ1ôîÝ;š`áB`äHu ”ü³WÛïÂ%]_ݶ¥U–ïëšö]¿:tcÿþ+ÓˆÊCçÎ@n.pîœöåTô¼‚¢¾e}ëº_åñ9\PL™" d[FF@Ÿ>ÀÌ™€›[ɶ-+MÏ»®_ÒΈ@d$°};PÊPŒ’nÝ„±!BB€ê8Ä_e~ßÒg;wß~  |ú©®{S=WúïéÞ½{vïÞ jÇ ”3È¯ÆÆÆÆE²K///xyy•¹ôêÕ«zTzNNNprr*Õ¶¥ÒÈÈ5*õIª:4h€ èº"www¸»»—©š5kêìo×ÄÄíÛ·Gûöíu²"""""9##`êTàý÷‹^ÏÌ ¨]hØðõz÷Jù3”ˆ¨ÔªÙù *B•¨±_^û-¯zʬ-LUß·DDD†¡¤ÿã99Qñºta–;é7žkxXÓ€ˆˆˆˆˆˆˆˆˆ¨ c`ßð0°ODDDDDDDDDT…ñ"LÃSíKñÔ¨Q?þø# ~ýú,ÅC‹ï["""""""¢ê‰}ÃSíûÖÖÖ˜0aB¹öƒRªŠø¾%""""""Ò=mÇ·iÜXýü¿çµmÏÚZ»ö¨jãËi8*-°/•J+kW•¦  @õ<6ª¾ø¾%""¢ª„?N‰ˆˆˆ´ÇïN†£Òû§OŸ®¬]U:œ;wN×Ý *¾o‰ª¿Î;ëº DD冗—W>m3@5a(QÑJú9YÜçry·GU Ï5<<·È3 ‰ª¾o‰ª?þ鿜œÌ›75‚vîÜ©WíQÕÀÀ¾á©´ŒýŽ;VÖ®t¢ºUO|ßQq˜J¤=]÷€ª¢Å‹ãÂ… FXXFމ  mÛ¶zÑU ü÷kx*-°ïææVY»ªTÿþû/:vìˆ6?×uWˆ´öK ƒúDÕœüÿSXX˜®»BDDDDDäççcÆ صk<<<àáá¡C‡"00°TøònªfìžJ ìé=¨¢]¾¬ëPU‰ôôt´oß^œçãム  ½hˆôkìé@ZZŒakk+Îspp@ZZš^´GUO^ö‰ˆˆˆˆˆˆˆˆtÀÒÒR©ÙÙÙâ¼ÌÌLXZZêE{Tu°áa`ŸˆˆˆˆˆˆˆˆH6lÜ¿_œOOO½hªö ûDDDDDDDDD:`ee…ÂÏÏ””„íÛ·cĈzÑUòÀ>ö‰ˆˆˆˆˆˆˆˆt$ W®\Aƒ ФI¼ýöÛÆù¸²ò¤ˆHÌB^ k[ÁÁÒ³»ºÃËÉ öÞS»ý$ߺ˜ÛMh§½Èǃä,Ôs°@3Ìéꎺvæøúh¤Úm$ÀŠÁMÑÅמƒ§é9hêh 7 ¬Ò Ÿ ÇÁ»Ij·ß:¦¥ÊÉAÉŸ§iÝàlgŽ´ùXòáIYÈÿïŒÄ£Ôì"·­mm†ëŽÜKÆŽñâ•Y¹åB¦¬ÏQuÀ¬3"""¢â1cßð0°_IL%øf@˜IðøY6¦ÿuqé9€×›ÕÆ7š ©£5fvqÇŠ“ÑåºïæNÖbPÿêãt,Üw)YyKS#|Þ·ú7¯W›ÔDï&µp,?Üüò?£¨<ž7""""""""2 ìž[IzÕ³­PÂæë£‘bP‡%aÏAæ·½`gQ¾ç[úzÖïÿßÑH1¨/ò ðMp$^üw•@ï&5U¶Ÿèë # ‘#Ň#Ä+ ¤2ütê!¢S„ÚðS:ÔUÙV`²¯0ÿêãtþœ„2>Ÿ G~ ¦FÓÎEmÿ?Øs]W]ÄøßoaÅÉhD¥h®E_œÚ6¦„R6%Þö¿D ¹Ô/爈ˆˆˆˆˆˆ 3ö 3ö+‰<`þ8-cÒT–︡-aaj„.8¤P^ågI$H}‘§1 -ÐÂÅ€)Y¹ˆM{yâ ŽÎÎ+PÏÌ•âaê 4s´†£­™Ò2c# z4úž¬2ȯ´@†Ý·0¯{}´t±…£2rÅå^Î6b=û7U3äãÒsðïÃgèêQ½›Ô‚ÿé•u´ÐV“Fµ¬`eö²v¾©‘p.«®½ZºØ*­™œ…L…’:6æÆð¨i%>v³ŽÃÄH¢²mfn¾ÆÁoM%èÜÀÍl`$Â³Š­_Ï[yxòä âããaii‰¦M›ª]'44РA888ˆóe2.\¸hÚ´)jÔ¨ˆˆìß¿ÿÏÞÇEU¯ÿ ‹8,‚Џ±¤âŠ$…šš¡¸tS Ë2®Ka‹÷VjÚEKÊ¥"[n©iêO+)õ’Tj.¨™¹€ˆâŠ"ÈÃüþÀ920¸#ð¼_¯yÅœíûœá`ðœç<ßôôt:t(îîîw_VVIII8::âè訬KLL$77—Ö­[óÀ••źuëHII¡qãÆôíÛ—>}úÜrŒ‚‚6oÞÌáÇÉËË£eË–<úè£ôìÙ³Ò¶ûöí£´´š5«|“̤¤$²²²hÑ¢nnnÕ»B!„B!é±ßðHb¿¨(ë¯{þªÁmŽ]ÌãïâRÔæ&ôtl¢—ØïíbǤGœÈ¿¦!he©9•“ûÏû´áµGàZI)Ï}{¸‘Ø¿”[–h77Uaf¢RzÊ—ginª·­Žg +¬¯O*[Uìq©7–{;éÇ^¾eNljUûçÒÛ¥)íš6®tcà^…=áFçÖÖ•–¿ìçÄË~NzËÆG&r Ü9vimÃÿèPißÖM,X쥷,6õ*ÿ\“Xi[·æ–|8Ôçfj½åg¯2{ÓÉ*ã6ö禳páBæÍ›G×®]•~EÝ»wà»ï¾#((HY^TTÄÃ? ÀúõëÙ»w/óæÍC[îÖñ´iÓøì³Ï˜4iÒÇ–ššJ¿~ýHNNÆÛÛ›M›6é­ aïÞ½¼öÚkôéӇ矞üü7‰ÂÂÂ;v,ß|ó &&†^Ú°a&L ##£ÒºÇ{ŒÕ«WÓ¶í'UÆÇÑ£G™;w.S§N½­ó5j‡â½÷ÞcæÌ™Õ»B!„B!©Øo8$±_ l)‰óªÚÈ”jáLÖßthiU) ¼äÏTz86á¡v¶|0ÄqßÑKÎwjeMèõøó·Ÿ!é/ý ÷m'³׫-¦&*ü\ì*U‹»6WãhWVs*KoK¹XªŠ½|¥ºK…Øuï ‹KÉ(×~HÿåkçfêjMPoK¾Ì‰rŸÇS0Q©Ø{6‡ónüUaÜŒÜ"~L¸¨¼÷laEçÖÖä•°é„þ<ç |6vj3¾Ù{«Fä_ÓðÓ‘K¤æáÖ\M`'æT]©nìÏ­º-Z´ˆM›6H÷îÝIMMeÍš5äååñꫯҿÚ·oÛÇ;}ú4ýúõãÌ™3øùùñË/¿Ð¤‰áyøòË/éÒ¥ O<ñ¹¹¹üôÓOœ9s†•+WÒ¯_?žþùJûmÙ²…§žzŠ’’œœœxî¹çpppàСC¬ZµŠ;vàïïÏÁƒ±¶.»yäççÇÑ£GÙ·oßmGAA‰‰e7„z÷î]m± !„uê6JÌLM«^§•¿`…BÑÀIÅ~Ã#‰ýZÐÒÆBùº|ò¸½½%—ó‹¹òwYÏûÌük€­›Xèí_ª…·IfÍØ®xµ²frïv|²ó,VL™;¸lRÞMÇ3Y[.­“˜‘ÇŠýxÁ§ ³žhOÄŽ3ì;—Cq©–έmø×c`¢R±5ù2¿UHX·lr£5.v3î-,I¹ü7E%¥ä_ÓPP¬ÁÒÜ”V6ú±·¼ÞÚç¯üçmmaJ[ÛÆ$]ÊG ü•w£ç« ­€îÕòýôÞíÔ‚F¦*ֹĦã™UìU&åòß„ÿ–¢¼÷P[:·¶ær~±Þòª¼ôˆöV(,.eÜ÷GHþëF"~Ó‰Ë|ùtå§tŒý¹U·7²fÍF¥,›æ‚ëÏN|Ø‘žïJôøîx:Xé­ÓU÷—w9¿˜·N¦T c}Úàû@Y’ñíþ®8Ú5æÜ•BÞ»I²yáγLÿ9™ŒÜ"fjϯ¼Ù2©'Ã7<’دW‹”V).Í*O  âFû–3YU·%Ú©C;µ X£ekr* <ÀÝ`ï| 3lÕef¤fWü=Ÿ}#aÜÖ¶±òõ™¬Ë«ŠÝ¥Ùàc×½·47ÅÁ@ÿŠÇ=s¥Ðà6uMNáj|;µácšª«n%s¿|nº›UU…_¾\õÀÕ) €9sæàààÀòåËQ©TÄÄÄ^#ãéªñÿúë¯*·)¿®|õ~·nݰ²²"??ŸÄÄD¥ O@@ƒ&!!ŒŒŒ[¶áB!îÖüùóñõõeøðá4iÒ333Ôj5ÞÞÞdffmìo*''SSSlll”evvvzOÈ !„B}ÒŠ§á‘Ä~-ÐñieÕRÝÛÚÜÆÃÁJ©zK½jp›öö–LÜ€OweZt‰yة͘7ÄS“Ê·æÊWŽ—¯Ä¯¨i¹u%å*‘_ÊSÚ¼tw4ÜÇ»»ãsªûÁ´«å¶«bÿëŸIúÕ"2®ÖÊó“™Ê×î-¬ nãéPyRTûåsÓMÜZU‚ûÌ™352nEåÿ°4h¯¾ú*³gÏf÷îÝÕ>ž®_~RRùù†ç¯8xð`¥íÌÌÌèÕ«PV•¿iÓ&\]]ñôôdðàÁhµZ6mÚtˉs…Bˆ»eaaADDYYYœ8q‚={öpøðarrrˆŠŠªr—û…Z­F£ÑPXx£p!??µÚp‘‰BQßHbVÜ ¹~Iì×’í'³pn¦¦k›ÊÉýá^k´ü~:»Òzµ¹ =hlnÂ璘°:6’R-Ó¢“É¿¦¡k^éÝ®Ò~Å¥=ŽS™þ–?ìl @I©–s媿‹5ZvŸ.›Üw€{såæƒŽ‰ªì)€¤¿ò¹P!Áœp!ËÅzçX^ ëF<âRÖJH÷Õg²þV’íOx67¸M@‡Uî¿|nºÇô/^¼Hzzz¥õ+W®¬±±ofÞ¼ytéÒFCpp0W®\©Öã8€k×®ip›U«Vàææ†«««Þ:]~LL »ví" ___š7oÎ/¿üÂô¶B!ª›™™øøøàåå¥Ü°¿ß¹ººbff¦LfœœŒ‡‡‡£B!„¸¿IÅ~Ã#‰ýZ•x‰¬ë‰ÚwºêUÏû¹Øñt×–•¶+oæ7œ›©ÉÌ¿Æ~=…îg45§÷6Ÿ`¬OskZißè£eÕÖ­šXðÎW½IWMTÒ«->Ne‰ýí'³ôúþ,ß[µ3ú»bvýÉ0é'<®W¤/Ûw¡ÒØ¥Z-+¯ïïû€-£»µRÖ567áÝAíidjB±FËÿÅVNCÙ“ÎÍÔÊËÆÂìúø*½åŽv îo Z òú¤Æ=í+%÷ŸónMO'ÕøP=Ÿ[uÐMêZZZÊôéÓÑhn\[·nå믿®±±oÆÂ‚o¿ýµZ͹sç?~|µßÇÇ___Þzë-eò^?þ˜Í›7ðÊ+¯TÚ_—¬ŒŒ¤°°PI웘˜0hÐ Ö¯_Onn.­[·®tS@!„¨qqq„††âç燗—>>>Œ3†¨¨(c‡vK––– <˜… ™™Éš5k5j”‘#kØêò5%„B4’Øox 7ÿÕ®°¸”°§X8âAÜš[òSHwâR¯bÛØŒ.×+øÏ])äÓç*íû.- è`O©für’+ë'þ7¸L¯.1¢³ïjOÐÿ%^®r~ÙÞ4q¶£CK+†tlŸ‹Ç.æS¬ÑâÑÂ’ÖM,€²¹l?SiüÄŒ<¾Ù—Ƹ‡Úòd{º;6áøÅ<%¡ð[Òe6Ï4xî߯¥ãß¾ÝÛÚ0íqžêâ@úÕktnm­Üàø0æL•ídBzµ%¸GëJËÍMU¬×MyŸ~µˆ€%qa «b/ð¸{3:µ²fîÆxç’–S„[sKÜ[XrèB®Á§7tîõs«îîî 4ˆ7²bÅ bbbèÚµ+/^dß¾}¼òÊ+|úé§56þÍtêÔ‰ 0yòdÖ®]Ë¢E‹˜8qbµÿ믿¦OŸ>dffâííÍc=F‹-HHHàèÑ£ôë×É“'WÚ×××SSSJJJP«ÕôíÛWY7xð`V¯^ Hµ¾Bˆš±víZÆLj# ÂÎÎŽüü|’““ %&&†ˆˆc‡ySŸþ9C† ÁÙÙ™œœ^xᆠfì°¬úpM !„õLžÛðHb¿ý~ú ¯¬;ÆŒ®´ibAײêz-°óÔÞÛ|ŠÜ¢½}vQI)ñi¹÷´UO ÜŽËÅü~ºz':­ Ò¯éµGºSÆþÜT*ÞÞÞx{{-crqqÁÅÅÅØa!„·%00àà`ÂÃÃñññÁÆÆ†ÂÂB’’’X¸p!vvv899;LQ‡È5%„BÔ’Øo8dò\!„B!ê‘ùóçãëëËðáÃiÒ¤ fff¨Õj¼½½ÉÌÌ$::ÚØ!Š:F®)!„âþ'û Tì !„BQXXXÁ‚ HII!''µZ««+–––Æï¦T2ëÛ}©._SB!DC!‰ý†GûB!„BÔ3qqq,]º”øøx% ëááÁ¨Q£6l˜±Ãu”™™ÆC!„H}DÃ#­x„B!„¨GÖ®]‹¿¿?yyy1uêTBBBhÕª¡¡¡L™2ÅØ!V¢Õj«|y{—½n¶M]5kÖ,T*•Q_³fͺ­Xãââ ÅÏÏ///|||3f QQQ5û! !„â¶Hb¿á‘Š}!„B!ê‘ððp"##4hP¥uÓ§OÇÝݰ°0ìì쌨‹Ö®]˸qã1bAAAØÙÙ‘ŸŸOrr2¡¡¡ÄÄÄaì0…BÜB¾.î€|ŸIì !„BQdggãééip½½=¶¶¶äææJbÿ>vÛ•óÕeÖ¬YÌž=û¶¶•›EBQ·I%wÃ"‰ý†CZñ!„BQ̶mÛÈÍÍ °°„„BBB°³³ÃÉÉÉÈQŠ»UTTÄë¯¿Ž››={ödݺu5>æíÞ,B!„ñÈä¹ Tì !„BQÌŸ?ŸiÓ¦1|øprss155E£Ñ`ffF@@ÑÑÑÆQ܃iÓ¦±wï^¶lÙÂñãÇ=z4ÎÎÎôèÑ£ÆÆÔÝ, ÇÇÇ IJJbáÂ…r³¨¨ª±œönu¯óUÜênW]ž/C!î’Øox$±/„BˆA~Á ………,X°€””rrrP«Õ¸ººbiiiìðÄ=())aÙ²e¬_¿\\\1bK—.­ÑľÜ,B!îÒr©á‘ľB!„õ™™Æ£JGŽaòäÉtíÚ•É“'ãîînìî{)))\½zeYÏž=ùþûïkt\¹YT{ŒQµ^O ÀŸCu/„ •üsÚðH}!„B!ꙸ¸8BCCñóóÃËË ÆŒCTT”±CS¼öÚkìØ±ƒO?ýظq#¥¥¥Æí¾•““ƒ©©)666Ê2;;;rrrj|츸8^{í5Ƨ¼Æ_]Sw¢><ŵsçNüüüpvvæùçŸ';;ÛØ!éÙºu+S¦LaÀ€|üñÇÆG!Œúðÿ8q{$±/„B!D=²víZüýýÉËË#((ˆ©S§B«V­ eÊ”)ÆsssÚ´iƒ……¿þú+O>ù$:tàóÏ?—ÉX P«Õh4 •eùùù¨Õê·®\Sw£®V7^¸p!C†ðÏþ“ßÿ‚‚^|ñEc‡¥gÿþýʵ™””däh„¢áÄ~Ã!­x„B!„¨GÂÃÉŒŒdРA•ÖMŸ>www°³³3Bt•-]º”ž={²dÉþûßÿ’””Ä+¯¼ÂÛo¿Í‹/¾HQÑd,,Ú;Ìû‚««+fff$%%Ñ¥K’““k¼åR]»¦‚U«VÑ­[7Æ”ÍƒàææÆÅ‹iÙ²¥‘£+3mÚ4^ýu½›QB!j†LžÛðHžB!„õHvv6žžž×ÙÛÛckk{ßUÃÛÛÛ3}útNŸ>Í?ü@Ÿ>}ÈÍÍeáÂ…$&z`i9„M›65ø6=––– <˜… ™™Éš5k5jTŽ[¯©ú.>>^o®š6mJBB‚£BaL’Øox$±/„B!D=Hpp0Û¶mS’­………$$$‚NNNFŽÒ0333ž~úivîÜI\\ãÆ£Q£FìÚõ3ƒ ¢cÇŽ|ñÅ :‰üù矋³³3îîîŒ9’aÆÕè˜uùšª¯rrrhÚ´©Þ²ÚšoA!Äý©®¶—wOûB!„BÔ#óçÏÇ××—áÇӤIÌÌÌP«Õx{{“™™Itt´±C¼-Ý»wgÙ²eœ?žððpÚ¶mˉ'˜k×®eܸqŒ1‚   ìììÈÏÏ'99™ÐÐPbbbj¥/{mppp`ÆŒtéÒ…¡C‡RPP`ìîÊìÙ³™={¶±Ã¨RCº¦ê’7ÞxƒI“&‘™™I»ví01¹¿êöf͚ŬY³ŒFw§mƤZ_ˆ†Kû O­%öÿüóÏÚªÖýùçŸ|é'ÿóuK}þ™B!²ððp"##4hP¥uÓ§OÇÝݰ°0ìììŒ]Í0777võZC¼¦ê kkk¬­­†Bˆû€Ü×kxj-±ïëë[[CÕª?ÿü³Þž›¨¿äº¢þ“›wB4\ÙÙÙxzz\goo­­-¹¹¹’„½Ô•Šf¹¦„BˆûŸTì7<÷׳zB!„Bˆ{Hpp0Û¶m#77€ÂÂB ÁÎÎ'''#G)깦„BˆºCû ‡$ö…B!„¨GæÏŸ¯¯/ǧI“&˜™™¡V«ñöö&33“èèhc‡(깦jJ¥ªõ—±ÏA!DõR™ýôS,--Q©T¼ûî»”””;$QA\\¡¡¡øùùáåå…cÆŒ!**ÊØ¡ !„iÅÓIžB!„õHxx8‘‘‘ 4¨ÒºéÓ§ãîîNXXvvvFˆîÖ àóÏ?çå—_n0}¸¯\¹Â믿NVV&LàÉ'ŸÄÌÌø²­]»–qãÆ1bÄ‚‚‚°³³#??ŸäädBCC‰‰‰!""ÂØa !„ šTì7<Æÿ-Q!„BQm²³³ñôô4¸ÎÞÞ[[[rssïÛÄ~y“'OVÚù|ÿý÷Œ=ÚÈÕ¬+V°råJ¢££qtt$$$„œœœŒW]¿Y$„B4$’Øo8¤B!„õH`` ÁÁÁlÛ¶ÜÜ\ IHH $$;;;£&‰ïVPP*• +++~ûí7c‡Sã<<|8¹¹¹˜šš¢Ñh033# €èèèj3((SSSLMM111Q¾.ÿ*¿<11ñ®ã(((`àÀ899ñã?Vç©Ü^{í5"""رc‹/fíÚµDGG­Š_w³(<<lll(,,$))‰… ÖÙ›E5iÈ!¸>[쯿þjði!„¢&HÅ~Ã!‰}!„B!ê """X°`)))äää V«quuÅÒÒ²FÆüî»ïîxŸAƒ±iÓ&ž}öYV­ZuWãž?ž^½z)ïóóóïê8÷#•J…¿¿?þþþüõ×_¬X±‚Å‹“œœÌìÙ³yï½÷¨•^üƸYT×¹ºº*‰ýáÇó¿ÿýO’ûB!j”ôØox¤B!„õ™™øøøàååUcIý{5fÌ´Z-ùùù¼òÊ+÷t¬ßÿ•JÅþó¢¢¢HMM­¦(«E‹¼ñÆœ8q‚mÛ¶)OHDGG3tèP\\\˜5kçÏŸ¯‘ñu7‹²²²8qâ{öìáðáÃäää…££cŒ[—é&|nÖ¬EEE >\Úò!ŒFZ´4 ò}nx$±/„B!D=Ghh(~~~xyyáããØ1cˆŠŠ2vhU²´´äÓO?E«Õ’••Eppð]ë½÷Þcøðá899Ѻuk† BXX?ýôiiiÕuíR©TôíÛ—ï¾ûŽ´´4,X€»»{­ôâ‹‹ãµ×^cܸqÊküøñ÷õ5u?øüóÏyùå—%¹/„¢ÆIÅ~Ã#‰}!„B!ꑵk×âïïO^^AAAL:•ZµjEhh(S¦L1vˆ·Ô´iSV¯^V«%55•'žx⮕‘‘ÁÏ?ÿÌ»ï¾Ë°aÃptt¤uëÖ2kÖ,6lØÀ… ª1úÚQ±ŠôèÑ•ªøÃÃÃÑVÃ_÷õᚪ¨¶’*•J’ûB!j•$öé±/„B!D=Ndd¤Á~ÞÓ§OÇÝݰ°0ìììŒÝkÛ¶­’=qâcÆŒ!66öžŽ™‘‘¡LF«Óºuk¼½½éÙ³'ÞÞÞx{{Óºuë{§6èªøûöíË¥K—”^ü'OždæÌ™xxx0räÈ{£¾]SåÕFÛ]rà¿ÿý¯ôÜBqOT·ñ?¯›mR7ýÅýA*ö…B!„¨G²³³ñôô4¸ÎÞÞ[[[rssk9ªêáééÉÐjµìß¿ggçj;vzz:ÑÑÑÌš5‹ÀÀ@Ú´iCÛ¶m:t(³gÏæçŸ&##£ÚÆ« ¼ù曜8q‚Î;TKë¡ú|MÕ©ÜB!Du“ľB!„õH`` ÁÁÁlÛ¶MI¶’@HHvvv8999Ê{׳gONŸ>V«åý÷߯‘1.\¸À† ˜5kC† ¡M›68::2lØ0Þ}÷Ýû6ÙobbB¿~ýªíx 嚪i’ÜBÜ.)¨·C«ÕÞÑKÔ?ÒŠÇH’““9}ú4–––tìØ‘fÍšÕʸZ­–¤¤$Î;Gii)mÚ´¡cÇŽ˜ššÞÖþ†„„.^¼HóæÍéÒ¥ ·=~^^‡æêÕ«8::Ò±cÇÛz„¨:]¹r…¥K—²gÏ®\¹Bii)Ÿ|ò ݺu»åþÛ·o'22’Ó§OSXX@·nÝøä“Oî(ެ¬,žzê) ì‘ÜŽ;Þá™Ô¯¿þ:ñññôë×ÿüç?ÆG!„¨æÏŸÏ´iÓ>|8¹¹¹˜šš¢Ñh033# @¯ýL}ѽ{w|}};v,±±±ÄÆÆ’˜˜Hqqqµ£ÕjIKK#--Ÿ~ú (KÖ¶mÛViߣ{µlÙ²ÚÆ5¶†xMÕiË#„¸µœ.uTQQS§NeÆ 4mÚ”·ß~[É7‰úMûµlÏž=¼ôÒK:tHYÖ¨Q#žyæ.\ˆ­­mýõ×_3gÎΞ=«·ÜÞÞž)S¦ðÖ[oafVõ%±lÙ2fΜIzzº²¬iÓ¦¼ùæ›L:“ª)**âí·ßfÑ¢Eäçç+ËÝÜ܈ˆˆ 00°Ê}/]ºÄü¡¼:Dqq17&;;ûvN]‘‘‘A¯^½8wî\¥u·s¬÷ߟ3fÜјU¹ví;vìàêÕ«·µOaa!=zô %%€%K–ðÜsÏUK<÷£øøxvìØA«V­ŒŠBQgXXXÁ‚ HII!''µZ««+–––5:öâÅ‹Ñh4h4JKK ¾tëN:UíãÛÚÚòÒK/)ï 9tè’èåèÑ£ÕžìOMM%55•¨¨(àF²¿|¿~oooªmÜÚdÌkª>’ä¾Bˆê4mÚ4öîÝË–-[8~ü8£GÆÙÙ™=z;4QÃ$±_‹vîÜIÿþý)..ÆÂÂooo®\¹Â±cÇX±b‡b÷iÜߨ IDATîÝ5òËño¼ÁG}€µµ5;w¦Q£F>|˜ÌÌLf̘ÁX·nÁýçÎËôéÓhÞ¼9:uâäÉ“\¸p·ß~›Ó§O³xñbƒû–––2bÄ~ýõWœqrr">>žS§N1tèPV­ZŘ1c îÿÐCUºq·Þ{ï=Î;GóæÍ™?>;wÆÜÜ€öíÛßtßôôtÂÂÂ5j'NTž´°¶¶®–øneöìÙ;vLy¯Ñhje\!„BÔ=fffxxxÔê˜'N¬Õñn¥qãÆôêÕ‹^½z)ËþþûoƒÉþ’’’j·|²ÿÿûP–Ìutt¬4Ao‹-ªmÜšfŒkª¾’ä¾BˆêPRR²eËX¿~=...¸¸¸0bÄ–.]*‰ý@ûµäÚµk<ûì³ãææÆ–-[”ɾ¾ûî;ž}öYâããyçw”|u‰UŽÙ§O~üñG¥Z(??Ÿ &ðí·ß²~ýzÖ®]Ë?þñ½ý9¢T©:”ï¾ûKKKJJJø÷¿ÿͧŸ~Ê’%K 4Xy¿hÑ"%©ÎôéÓQ©T\¹r…ÀÀ@vïÞÍ„ èß¿•,7jÔˆ=zðÈ#«Tºß©ß~û €W_}•_|ñŽöݾ};%%%¨ÕjV¬XAãÆï*†»uøða>úè#œœœ8þ|­Ž-„u]l¬Šà`®¾cJŸJq?‹‹‹céÒ¥ÄÇÇ+ÕÕŒ5ŠaÆ;<£R«Õøúúâëë«,+Ÿì?pà±±±;v¬Ú“ýçÏŸçüùózÉ~'''%É?ÿŽ'×Tõ“ä¾Bˆ{•’’ÂÕ«WñññQ–õìÙ“ï¿ÿÞˆQ‰Ú"“çÖ’ÿû¿ÿS~Q_¼x±’Ôxæ™g”$óW_}Å•+WªuìüQùzÑ¢Ez[YYñÕW_aee`°bÞ¼y”––bkkË7ß|£`pÒ2­VËܹs²› o¿ý¶ÒS¿iÓ¦¬Zµ sss ªìQÿ¿ÿý«W¯²gϽñ››Û]ïÛ¶mÛZOê—––2~üxJKKY°`A­Ž-„BˆºeíÚµøûû“——GPPS§N%$$„V­ZÊ”)SŒâ}G—ì å›o¾!!!œœþøã>ûì3^xá¼¼¼nÚ¶ònhµZÎ;Çúõë™9s&‹-P&¨½_È5UsdB]!„÷"''SSSlll”evvväää1*Q[¤b¿–èæ®®®ôëׯÒú &ðõ×_SPPÀ¯¿þJp¹’Âýû÷£ÑhhÑ¢E• i­V˾}ûÐjµ´lÙeÝ… °´´¤C‡•öµ±±ÁÃÃ’––¦·®¤¤„ 6ðü£Ò$¿fff¼øâ‹¼õÖ[üù矤¥¥Ñ¶m[eý”~öãǯ4¶³³3 à—_~aíÚµ|ðÁ•¶¹ m«’˜˜¨÷‡Ñµk×8}ú4þù§Þ¶;v¤I“&Êûœœ½¶7º¾öÅÅÅ•ömÒ¤I•“ß^»v7‡F£¡K—. :ôŽÎã‹/¾`ïÞ½¼òÊ+tíÚõŽö½ééé\¼xµZ§§§Ámâãã²ï¥²\«Õ²wï^<==iÚ´)'Ož$::šôôt:t(îîîw_VVIII8::âè訬Ó}ï[·nÍ<@VVëÖ­#%%…ÆÓ·o_úôésË1 ؼy3‡&//–-[òè£Ò³gÏJÛîÛ·ÒÒR<<–ªb/_©^1vÝ{KKKÚµkwËýOœ8Q­‰ý§žzJ¯âÿ믿F£ÑпÿJO?´iÓFï}»víô&€‹gïÞ½ØÙÙ1zôh½m ýƒ™™™É€HOOÇÆÆ†qãÆáêêJbb"+V¬¸í ¬ÐÐPrssùì³Ï°³³«ÕÄ~uY´h›6m"00îÝ»“ššÊš5kÈËËãÕW_¥ÿþ·œ¼¸¼Ó§OÓ¯_?Μ9ƒŸŸ¿üò‹ÞÓå%$$ðå—_Ò¥Kžxâ rssùé§Ÿ8sæ +W®¤_¿~<ÿüó•öÛ²e O=õ%%%899ñÜsÏáààÀ¡C‡Xµj;vìÀßߟƒ*“'ûùùqôèQöíÛw[çQPP@bb"½{÷®¶Ø…B4lŽ666’””ÄÂ… ±³³ÃÉÉ©Vcú÷¿ÿ‰‰‰ò255å»ï¾ãÔ©SµGM°²²ÂÏÏ???e™.Ù¯ë×ˉ'î8Ù¿mÛ6T*999Uþ®SîÇkª>’ä¾¢¦ÉQõ¥¥%ƒfáÂ…,]º”ÌÌLÖ¬YÃ_|aìÐê…üü|Ž?Nii)¦¦¦Õzl]á«F£¹ë¢MIìׂò“`•O9r„–-[Ò¢E Z·n  ´®Ñ111aõêÕtëÖ}ûö1cÆ æÏŸ”õß|æ™g(..&((ˆ &TßÇLJ7ß|“ùóç‚ xüñÇ177gïÞ½¼ñÆh4þñ0räÈ[Æ^\\ÌáÇéСjµ¬­­ÉËË«»nÿòç““ÃéÓ§éÚµ+*•J9oCç~¯Þzë-½÷Ë—/G£Ñ¢W]nHÇŽùꫯ”÷sçÎeïÞ½´lÙRoyUÂÂÂHOOÇÒÒ’ßÿ]¹s ÄÀoyŒü‘Ÿ~ú‰Gy„±cÇÞrûûÕÆY³f £FR–Mž<oooŠ‹‹Y¹r%ï¾ûîm+))‰ÇœÔÔTüq¢¢¢”9" Ù¾};/¿ü2Ÿþ¹Ò>cöìÙx{{“’’ÂÒ¥K+%ÇKKK™8q"%%%têԉݻwckk«¬î¹ç8p 'Ož$<<\i!Õ»wo–,Ybð)Cbcc)))ÁÜÜœ^½zUKìB!Äüùó™6mÇ'77SSS4 fff]ë1}øá‡•–íß¿¿^$ö 1”ìÏËËS*ûu ÿ¤¤¤ÛJöÛÚÚ²sçN£µâ»¯©úJ—Ü×jµ|ùå—’ÜBqKŸþ9C† ÁÙÙ™œœ^xá™Ø¾šØÛÛ+_߬½kUë -¯¸¬üNwZ"‰ýZ «Ö”ÊÞÙ³g3kÖ,¬­­ÙµkݺuSÖ•ß^§U«V|ûí· 0€?ü0`À^zé%N:…»»;‹/®2†yóæÑ­[7,XÀ¸qãôÖ¹ºº²páB&Ož\©o°¡ØHLL žžžÄÆÆbee…••yyy•b×½×í{ñâEºvíÊÅ‹3f «V­RÖUuîuQQQ«V­Êæ(ŸÔèׯ#G޼é,å999¼ú꫘ššê%vë¢è%õ¡lî„°iÓ&öïß[ÇILL¤ÿþddd0dÈ~üñG,,,nº­­- ,Ðûüììì?~<Ó§O'66­V«·~ëÖ­ÊS,~ø¡^R oß¾³råJ–-[Æœ9s055UþxOKKÓk+¥Ñh”?‚ËOh£»УGƒýïî&v!„‚ˆˆ,X@JJ 999¨Õj\]]±´´4vx –µµ5½{÷Ö{J///ƒêµ¶¬Ê£>Ê¿þõ/>ú裚 Ó ¹¦j—J¥R*-%¹/„âV‰çܹsØØØÐ´iSc‡T¯èZ0êòZ­¶Rr¾üº[ý·ª}KKKÙ³gÏÅ&Í™kAaa¡òu£Føá‡€²_æþùg½uÿý·Áãôë×™3g¢Õj;v,~ø!«W¯ÆÂ‚ÈÈH½„aE¹¹¹ìß¿ŸÔÔÔJë.]ºÄÁƒ•Ivo{ff¦ÒKþĉJßõªb×í¯[¿k×..^¼@dd$Z­VYw³s¯k:ÄÕ«W2dˆÁm†~Óc¼õÖ[¤§§3iÒ$¥}]eh¢5¸ÑÂHwMÜÌÁƒñ÷÷'##ƒ‘#G²nݺ[&õ¡ì`CpêÆ.((Л`nÌ ammMÿþý wĈ@ÙϮ唛››òJùªý~ø¦M›Ò¶m[Š‹‹•åºmªª¾»›Ø…B333<<<ðññÁËËK°÷!kkkúôéCiii¥BC>þøcÌÍÍ«}²ÞÛ%×TíÑ%÷_zé%ŠŠŠ6lX¥9¥„BˆòÚµk'IýFûµ |òñÚµk<óÌ3@Yõ­®ç½nÝÍf® £oß¾dddðæ›o¡×G¾¢Ë—/Ó»wo"""°±±aݺudddpùòe6oÞLûöíY¾|9=ôÇŽ»iìöööJ¢³sçÎJ¹ªØuûëÖ÷éÓG©b;v,*•JYw«s¯K’’’”¯ogn‚Š~ÿýw–,YB‹-xï½÷ª=¾Úæèèhpy³fÍ€[ßÐ9vìýúõ#33(ûù14 ôÝŒmh|Ý÷ÏÓÓSò*Î ¡£«Ú/ŸØ×ý–››ËîÝ»•åºm õ×¿ÛØ…BQ÷¨T*:ÄSO=uËmumüNž{Ïw6«¢›éüfÇ/¿®üÌèºêû Ñh8rä.\àÅ_¤k×®ÊÏ«.ñÿàƒêMÆ"„BˆÛwéÒ%æÌ™£<[_ZüòÊ+·µÝøñ㕾¯5)<<œÈÈHV¬XÁ+¯¼ÂsÏ=ǤI“øè£ˆgùòåJa„¨~’ÜBaˆJ¥º£—¨$±_ Úµk§´˜Ñõâ®H«Õêµÿ¨ÊòåËY¾|95â©§žB«ÕòÜsÏìe•Ç—/_ÐK¦WÔ¾}{åkݤ¡c©*öòí{*Æ®{Ÿ——We…õÍö¯«Ê·Jѵ©è¯¿þ2¸\w# ¸¸˜Å‹³hÑ"½×š5k”mcbbX´h+V¬¨ÆèoÐýÃ_ÕÍ ÝµUÓ˜3g,_¾•JELL ááá52ž®¿ªïQÅuå«÷»u놕•ùùù$&&*t0xð`ÈÈȸe!„BT-66–^x'''Þyç ¬ýáìÙ³Yõ011A«ÕÞòÉ\€={ö R©¸råJÅ“]åïéöööØÚÚʼ?5L’ûB!„¨Hûµ@¥R)­6víÚep›ò“­>ú裷9rä¡¡¡Ì;—ï¿ÿ233=z´ÁI´ÊWŽ—¯Ä¯¨üºòí?zôè¡´Ç©*ößÿ]ùºbìå'¾Õþ<ðíÚµ«2ƺD×vÊÚÈ¢›x¸¢víÚñÁTùú׿þ¥lûôÓOóÁ0sæÌê=ëtUoU%¸Ïœ9S#ãVTþÉ–Aƒñꫯ0{öl½žõÕ¥S§N@Y¯}]©Š À?þX©§´´”åË—еkWœõÖûúúÒ²eK–-[ViÜ .(­ItŸQ}ðàƒ*7)ÊWØ—·zõjƒËÛ´iôiÓª|?^ÙvðàÁL›6É“'WÿI€òÚÅ‹õZ&é¬\¹²Fƽ•yóæÑ¥K4 ÁÁÁÕ^¡6pà@ l¾]+«ŠV­Z€››[¥§atUø111ìÚµKù™öõõ¥yóæüòË/8p@o[!„Bö×_Ž‹‹ £Gf÷îÝ4iÒ„)S¦œœÌO?ýDÿþýëí—Çœ¬¬¬ÛÚ¶ÿþ·Uå§æÏŸ¯¯/ǧI“&˜™™¡V«ñöö&33“èèèjS&Éý†Gæ¸BÜ.ݯB’»o8$±_KƇƒƒ&LЫÿõ×_Y´hQ¥íÊ›8q"ǧuëÖJ+(k¯³xñb>üðC6lØPiß±cÇpîÜ9&Nœ¨W\ZZÊûï¿ÏöíÛ²äzùêh€·Þz (k»2iÒ$er2­VKXX‡`Ú´i•Æ655å7Þà·ß~ã‹/¾PÖð /PTTD£Fô*ÑË»téÇW^ºþZ­Voù©S§ îo *•J™ˆxÍš5•’ûü1111FˆìÎèž4)--eúôéh4eÝÖ­[km¶Š,,,øöÛoQ«Õœ;wNïfGuðññÁ××(»þ+>uññÇ+7à õÀÕ%ë###),,Tû&&& 4ˆõëד››KëÖ­oÚ"KQ?ݬzF^÷ïKÔ¾ƒ2nÜ8œœœ˜9s&iii<øàƒ|ñŤ¥¥ññÇãææfì0kEÓ¦MÑjµ<üð÷Üö«¯¾B¥RUë\DDDD••ʼn'سg‡&''‡¨¨¨z3OV]!Éý†Eæ¸BÜ®zZã nBûµÄÒÒ’o¾ùiß¾=C† á‘G! €ââbÜÝÝ™;wn¥}/^ÌêÕ«111aÕªU´hÑBoýèÑ£ùç?ÿ‰V«åùçŸçìÙ³zë§OŸŽ··7PVaíââ“O>ɰaÃpuueÆŒ@Y ˜O>ù¤Òø>>>Êä¬ß~û-nnn >œ:0gÎFŽIPPÁsíµ×”DçäÉ“éÖ­C‡ÅÅÅ…ß~û €ˆˆˆ*Ûð¼ÿþûtèÐAyé’ä×®]Ó[þøãÜßX¦L™‚¥¥¥ñðÃL×®]ù÷¿ÿ]+Ý+www ”MÔëææÆ°aÃðõõeÀ€üóŸÿ4Zl:ubÁ‚@Y‹îæXuùúë¯iÚ´)™™™x{{Ó¿žyæ:uêÄ¿ÿýoúõëgði ___LMM)))A­VÓ·o_eÝàÁƒ•›cR­/„¨);wîÄÏÏgggžþy½?ø‹ŠŠxýõ×qss£gÏž¬[·NoßóçÏ3bÄœ0`GŽÑ[ÿÕW_áåå…§§'ï¾û®^ÒûVǾY\·:ö­âõCqq1?üð}úô¡G,_¾œk×®1dÈ6mÚDbb"/¿ü2ÖÖÖÆÕ(þøã¥¨çV>ûì³jßÌÌ |||ðòòª7“×E†’ûW¯Jr¿>’9.„øöî<.ª²}üøgXYÅ}ÁSr Q™{úJj¹æ^jâ’Ïc¹d_4ÅL3Å25—Ô²£rÉÝÜÅ·wQIAÙfæ÷Ïœ‡aq†åz¿^ó‚™ûœû\‡`æ:÷}Ý¢°$±_þHb߀|||øóÏ?©W¯ üùçŸÊbW¾¾¾:t½}Ξ=ËøñãÌñ:uʵïE‹Ѹqc?~L¿~ý”Ä!d–ãÙ¿?ãǧbÅŠ<|ø;v°yófnݺ…¹¹9ääɓԨQ#×þ¿øâ æÎ‹wîÜaÓ¦M\¾|™ *0qâD¥,InÌÍÍÙ¶mC† ÁÌÌŒ³gϲeËbbb”ÅPu£ÛË vìØAïÞ½Q©T;vŒ_~ù…ˆˆz÷î­”0*éÖ¬Y£Œ^¿uë›7oæÌ™3L˜0ùóç56ºwïd^H¹páB±õݸqc:DÛ¶mÉÈÈ`ïÞ½¬_¿ž‹/biiɸqãØºu+¦¦¦9öµµµ¥I“&tìØ‘ *(mÞÞÞÊ>’ØB¼÷îÝ£{÷î¼ÿþû>|˜ääd† ¦´Ož<™ãdzgÏfΜÉ!C 2gôìÙ“5jpôèQÞxã ¼½½INN`Ó¦ML›6åË—óǰnÝ:½äa~}W~}—(ý>|ÈìÙ³qqq¡oß¾>|;;;>úè#®\¹Â–-[èÚµ+&&òñåƒ> 22²ÐÛçµÎ•Ètü8ãäƒÊžÜ¿v­t&÷eí“üÉBˆg%“MËÕãÇ_èÓ}üøqZµj•#a]V;vLIz–F£áäɓܺu +++š6mj°EcŸ>}JXXQQQhµZœñôôÄÎήÐû‡††òàÁ*W®LË–-Ÿé¹}ðà§OŸæÉ“'Ô¬Y“Ö­[cnn^ÔÓ)5nݺEXX†¦M›òÒK/5žg}ÝjµZˆŒŒÄÎÎ//¯3Gʲ7nARRU«V¥uëÖåv¤ (=t¿ç{öìáå—_&%%¥ØGVêJ”$''cii À¥K—”¤aÏž=zk¶ìÝ»—Î;ë-&ÿ¼tI„®]»booöööy~¯ûZ½zu€^Öeîܹlݺ•ƒ™Ã4h@tt4•+W¦råÊüþûïÊ`ÁƒcccÃâÅ‹9qâíÛ·'66–Š+P¯^=æÍ›GŸ>}ðññ¡E‹|þùçüðÃ|õÕW\¸pŒŒŒ|ûÎ/.ggç|û.(.CÐ=ïÏúü=ë~E=Îóìû<ÇÌ«¯ìrëÛÛÛ›;wR½zu=zDjj*îîîŒ;–Aƒå(YÖ-\¸ &0~üø\gÒf•‘‘µµµÞ€ž¼4iÒ„ðððgN‚–„×Ô‹Ò²åÿú^^•*_ÿ~~~lذ_~ù%Ï™ÍÅE«ÕâïïÏ’%K01±dûöÍÊšQ%A‹™_ÿ»ÄTÏ›œ/èufÈ¿ÃPðùÔž=Ž””&OžÌÊ•+IHHÀÔÔµZ™™>>>,^¼X¯Vqüþ¥¦¦bbb‚©©i¹¹€RÒ¼óèŠ1L™o¿ý|£±;u‚'O uk7ÜÜŠ'Î’Âпç%Ur2´k*ÀáÃÆŽ¦l8räˆRqC÷zÉZª³(vA* IDAT_³?¦{=j4BCC•Š$üñ¹†R^ŠïS®(4Zµje”ć•••R7½¨ûç5k 0tÜË›ºuëR·n]c‡Qd*• OOO¥¤SyS¿~}êׯoì0„%Œn­’&<<///å~ýúõqtt$""‚ºuëòäɽö-Z°~ýzeßF)ÉsOOOÂÃÃéÓ§áááz s¶hÑ‚¿ÿþ›ÔÔTnݺU`ßyÅÕ¥K—|û.(.Q:éÒÑÑÑ@æìÖqãÆÑ¥K—b™_“Rfff¤¥¥ñŸÿü‡¯¿þ:ßm#""011¡B… ¨T*LLLônÙÓÝ^¯½öZ¾ÇÉïØÏ²MQöy饎h4–ÄÄ4àäIgÞyçºtY…™™¶XŽ}çÎçþù–nä>À’%Kx뭷ؼ¹d%÷ £¨Ê:ÝóæÍãúõëÄÇÇcee…‹‹Ë +‡U¹re½µùt¯mSSSLMM•ï úZÜÛóØ†Ž³B,-MIM…/¾€sç4L›¦ÅÔÔä¹^ûÇŽAXL›å05SæÉâ¹å$ö…B!Êøøx5j¤÷˜ƒƒñññÄÇÇcjjª7 ZצÛ×ÑÑ1×}skwpp@£ÑP¨¾óŠ«0}ç—(‚‚‚”õ—üýýquu5vH¥ÒüùóéÑ£íÛ·/pÛ””Dô?¡¡¡=Þ³™ €JeŠ‹K0ð6AA÷ˆ‰É¦DI¥R©øöÛoÒÜyÓ­qa FCFF†QŽ_~©°¶~•úõbëÖ†,ZÔ›ÇC” ŠÏrÁÀܼ¦¦17oü›ÿû?3>ý´7*Õí2q¡¤¨.\¸ðÜ1”¤Y-’Ø/$±/„BQ†XYY‘˜˜¨÷XRRVVVXYY¡V«IIIQÖÿеå·o¥ÿÖ§ÈÞ®Í÷<}çÕž½ïüâ2$C}p3ÆDCÓÃÃýû÷ô˜eU»víˆÇÞÞÞØ¡”:Z­šû÷çààð6ÝKmb2GUKr¿l cåÊ•„‡‡+#öÝÜÜèÛ·/=zô0vxâ…Ñ’œ|š›7‡Ð°á1œ'ñøqZ­µZZ­~†¾þ[ׇm89Ý nÝåÄÇ÷ãÆþ/"ðRÃÃãXúÑ%ùÓÒÒŠ¥¿¢*!ׄÉêSB!„eˆ››W®\QîÇÅÅ‹››...˜™™éµGFF*#ÝÜܸvíš,+IfoϾo5¨X±b¡úÎ+®‚ú.(.!ØÙÙ¡ÕjŸ«lfy•––Y6ÇÒÒ¸ë`]r_· î[o½UbKlj ¡C‡$&&âççǤI“>|8ÕªUÃßߟ &û1ËZÝñÒ.)éZm*ÖÖMP©ž|n\ÜïT¬h¼u±ÊFS¨5o^4Iì—?’ØB!„(Cúôéî]»¸|ù29jÓÃÃWWW¬­­éÖ­AAAÄÆÆ²aÃúöí dŽú555eݺu=z”K—.áëë @ß¾}Y±bÉÉÉh4¾ûî;eß‚úÎ/®‚ú.(.!ÄÿìÝ»—5kÖ;ŒRÅ¢6©©WIñä~ÙHpp0kÖ¬aìØ± 8Q£F1þ|ÂÃÃY½z5qqqÆS¼@*• `‚V›V«)pû‚h4™eÙLMË×õå‰\›+?¤B!DÒ¼ys¦OŸNË–-©Zµ*jµš?þøCiÿöÛoéÞ½;õêÕ#>>ž!C†(Óø+T¨Àºuë0`³fÍâáǬX±‚jÕªàïïOhh(uêÔÁ‚† 2cÆŒBõ]P\ùõ]P\B}ƒ âÀ¬ZµJ)±$#ps§R™R­Údââ¶9šâ#eyÊŽ¸¸8ÜÝÝsmsrrÂÞÞž„„ ™0[ÛN¨Tæ$&ž?±_±bk’“ß»/Q2É¿üòCûB!„Eðøñce±,“¿ž…½žÕĉ5j±±±Ô©S“ÿMÒ¬U«áááܾ}[[Û‹ÒvîÜ™;wîEµjÕ”øææælذ‡’žžN5ôö-¨ïüâ*¨ïü⢨JZ²{áÂ…ÅVVC·õ×_ÍG}„V«UÀÔh49îçöØó^<;~üxžÇ*l /jÛK—^'#ܘ˜TÖÔÑh4¹~ͯíY¶) ÛóØZ­5Z­––­¨^}÷ïþÜÏa… ©Sg111AÏÝŸ(YdñÜòGûB!„EPÒGÆÙØØ`cc“g{:uòl377§~ýúy¶W©R%ßcç×wAqå×wAq !ò¦»ÀhÈ‹Œ-[¶4رžUË– [¶£eK˜5« •*Í,¶þýüüŒžØIî—sçÎeòäÉôìÙ“„„LMMQ«Õ˜™™áããÃÖ­Å?Ó$¯‹žVVVT¬X±Ø'rzç¸uë÷GŒ€#ö¢Õj•ÅsŸåBÁäÉ5xüØ”G2Ó€mÛ>fÅŠY¨Õ3JíŬßoÚ´©H?ç—_~¹HÇNII)ާ¹ØIb¿ü‘ľB!„…ô¬#¼UE\Ŭ(#É‹z¬ç9¦¥Ý¢Eк5˜”áÕç$¹_ºYZZ²`ÁæÍ›Çõë׉ÇÊÊ ¬­­ ËóþŸÏ®R%˜>^{-ó~ÖY¡Ï"6âã3ÿÖýç?з¯#*•cÁ;–E}m^¼xÑ Ç{çÏŸg̘14mÚ”1cÆ(ëTéÇeð°„‘Ib_!„B!D¹TÖ“ú:’Ü/ÝÂÂÂX¹r%áááJbßÍ;}û*kÙˆ²éûï¡^½âëoÇŽÌ‹¢ô?~<àÀ,Z´ˆ7ß|“qãÆÑµkWåBŒØ/ÊÁ[!„Bˆ’C7ÒJn¥ë&„¥.¹ÿᇒššÊ[o½Å®]»Œ–(@HH:t 11???&MšÄðáéV­þþþŶ.‡(ÊÅ̲ÊÜÜ€5j`iiÉöíÛyóÍ7yùå—ùöÛoIHH0r„ÂdľB!„BQÈÈýÒ'00àà`¼½½s´M™2WWWŠuí)Í&DɵråJZ´hÁòåËùî»ï¸rå cÇŽeêÔ© :ŒÔÔ1XZ¾dì0…ȵ:!„BÐ-v&·Ò}BˆÒNFî—.qqq¸»»çÚæä䄽½½ÁFêÊ 6!J'''¦L™Â7ظq#mÛ¶%!!E‹‚¸pÁ +«îìܹn•xQfIb_!„B!„(G$¹_zøúúÒ¿þúë/%Ÿ’’BDDÇÇÁÁÚµk9J!„1˜™™Ñ»wo}8tè§OŸfÈ!˜››³uëVºvíJãÆ9wÃÏIûB!„Bñ lll”[ÅŠ±¶¶ÆÚÚ+++¬¬¬¨P¡–––XZZbaa……æææ˜™™aff†©©)¦¦¦˜˜˜`bb‚J¥B¥R1aÂcŸš(§$¹_²………áïïO›6mðððÀËË‹°iÓ&c‡&„(^}õU~øáîܹìY³¸téFŽL>+++\\\°¶¶~!Ç” ÅBÍòåËÑjµhµZ4ò}Ö[Q¿zõª±OO”@’ØB!„Bˆbð¢’lB“$÷K333ÜÜÜŒƒÔ;"#FŒxáÇxóÍ77nsæÌÁÊÊê…O”l&Æ@!„B!„%—.¹?jÔ(RRRèÑ£»ví2vXåFXXþþþ´iÓ¼¼¼0`›6m2vhB#X´hÖÖÖ¨T*>ÿüs222Œ’0Iì !„B!„"_’Ü7Ž:tè@bb"~~~Lš4‰áÇS­Z5üýý¥|—å\@@æææ¨T*/^,¥´Ê)Å#„B!„BˆåV–gÏž=´iÓÆÈ‘•]ãíí£mÊ”)¸ºº€ƒƒƒ¢B”$cÆŒa̘1¬_¿ž~ýú9"ñ¢Éˆ}!„B!ÊݬE½‰²C£Ñ°wïÞbëO^K"+]r¿I“&¤¤¤°lÙ2c‡T¦ÅÅÅáîîžk›““ööö$$$ë1eį¥ŸŸŸ*•ŠŠ+²{÷nc‡#^±/„B!„e@LL «W¯fùòå\½z€š5k9ª’Iò–ÏÇÄĄɓ'Ó¿ÒÒÒŒN™æëëKÿþý ÄËË [[[RRR¸rå AAA888P»vmƒÄ"î„ÈôÞ{ïé]Ð611É÷þó>~öìY¶lÙR¤X“““•ÅÎk׮ͯ¿þZœ? ad’ØB!„¢ yÖ‘–’¨)Ý4 û÷ïgÙ²eüþû蠟§P«V-FEïÞ½‹Ü·ŒÚù‘¿†1wî\&OžLÏž=IHHÀÔÔµZ™™>>>lÝºÕØ! Qîüøã?¦··7;wîä½÷Þã§Ÿ~*RwîÜ¡U«VÊý¤¤¤â O‰$ö…B!„¢”‰‰‰aÍš5|ÿý÷Êè|ºwïÎÈ‘#ñööÆÌL>î QÚYZZ²`ÁæÍ›Çõë׉ÇÊÊ ¬­­žÂÀ À?þHrr2“'Oæ›o¾)r_‡Ö»H«û>ki½Ü¾¦ 11±È±‰Â‘wzB!„BQ hµZöíÛÇ÷ßÏo¿ý¦7:ÿý÷ßgذa+É!„0œ°°0V®\Ixx¸’Øwss£oß¾ôèÑ£Ø'³u„(ù¬­­Y´h‹-âñãÇŒ3†Ÿþù¹úÔýîË߀ÒCûB!„"e Êù°# íáÇJíüÈÈH@Fç Q^„„„0tèPzõê…ŸŸ$%%‰¿¿?û÷ïgÁ‚‰EÞÇQ29::²nÝ:Ö­[ÇÝ»w>|8;wî4vXÂäÝŸB!„B”0Z­–ýû÷+£óu ”Êè|ðûïq8ãñ©S«Sµª j¾ûî!ááO±¶6ÁÇÇŽwÞqàêÕT¾ý6ggs:u²å›obðô´fÂgâãÕ,^üˆˆd¬¬LhÛÖ†!Cœ011ÌyzdziHpp0ÞÞÞ9Ú¦L™‚««+888!:!DIS³fMvìØÀåË—0`§OŸ6rTâE‘ľB!„ɈïÒIF* C bÛ¶mz£ó}}}1bo¾ù&¦¦¦FŽPÛ‰I¬^ýZ’’4Œ]KKÍ›_âÆT^{͆˜˜tV­ŠeÒ¤jÌ™S“¨¨4‚‚bpp0eæÌhRR4˜™©xüXMÓ¦¹s'zõ,xòDÃêÕÿðûïqlÙòÒ ?§’42½$‰‹‹ÃÝÝ=×6'''ìííIHHľ"wwwN:À©S§èÓ§7oÞ4nP¢X躻B!„0¤ƒÒ¦MêÕ«ÇàÁƒ‰‹‹SÚRSSùè£hР-Z´à·ß~ÓÛ÷Î;ôêÕ‹zõêÑ¥KΟ?¯×¾téR<<}:7oÞdóæÍtïÞ]’ú€/¾¨I\\3îÝk‚§gæª~X7· ,Zé R™#G܉ˆh„ƒƒ)óæÝ'::]é#.NÍâÅuHO•¯¿®Å¢E1ܹ“ÆoØqíÚ+\¹ÒS¶nÏuv@qÓL_³f cÇŽeàÀŒ5ŠùóçÎêÕ«süÏ(|}}éß¿?ýõ ™ÏCJJ  >‡bŸ½#„({Z´hÁ7ÐjµÌž=ÛØáˆb"‰}!„Bˆ2æÞ½{tïÞ÷ߟÇ“œœÌ°aÔöÉ“'süøqöìÙÃÌ™32daaa@æ‡ùž={R£F Ž=Êo¼··7ÉÉÉlÚ´‰iÓ¦±|ùrþøãÖ­[Ç7ß|S¨¾ Š+¿¾ ŠKˆ²`ðàÁ 4___¶lÙÂÍ›7 ’;¥Ø† ^Xß©©Zzö¼ÆÁƒ‰ \™Å‹ëñ€Õ«ÿA¥:µõââÔh4pþüSeÿjÕÌ:´2¦¦**U2SÚ:w¶ÅÄ*W6£iÓÌ‹çϧ¼°óÐ)ìÈôòfîܹ´nÝšž={bgg‡™™VVVxzzËÖ­[ ‹Ì\¢lhÞ¼9ÿú׿Ðh4h4Ôj5jµšŒŒ ÒÓÓIOO'--´´4RSSIMM%%%…§OŸòôéS’““INN&))ÉÈgS¾I)!„Bˆ2æ§Ÿ~¢Y³f :ÈL 4hЀP¹reV­ZÅï¿ÿNýúõ©_¿>½zõbåÊ•¼úꫜ~bb"çÎãÉ“'ÔªU‹FüÇãÇY¹r%¡¡¡<~ü&³åÂ… iÖ¬YûïÛ·àà`nܸAJJæ›âfÍš±páÂgŠãÑ£G¼ýöÛ|÷Ýw4jÔ(Ïm£££ùûï¿yúô©òs·²²z¦ã•F}ôááátêÔ‰ÿû¿ÿ3v8BQj„‡‡ãåå¥Ü¯_¿>ŽŽŽDDDP·n]ž}çÃ?ÔÛ÷ï¿ÿ&55•[·nØw^quéÒ%ß¾ ŠK!J’ÅÔ©Syÿý÷Q©TÊEÍâðÑGwغ5kk^zÉ’™3£3¦*~~•Xºô!ûö%н»=ÎÎf\¸Â?ÄÞHIìg×·¯#K—>dÅŠXj×¶àöí4.]J¡re3:u²Í3–ãÇaÈç?§¹sç2yòdzöìIBB¦¦¦¨ÕjÌÌÌðññ1èÈô’ÈÌÌ 777c‡Q¦ddd°lÙ2~ýõWnܸ Í›7gâĉ4mÚô¹ú^¸p!3fÌ`äÈ‘,]º´˜"%ÍèÑ£‚(ç$±o`¡¡¡|øá‡œ={VyÌ‚wß}—   ìíí_رW¬XÁ¬Y³¸uë–ÞãNNNL˜0O>ù3³¼_«V­bÚ´iDGG+9::òñÇ3iÒ$LLò®ì”ššÊÔ©SY¶l™Þ4 °`Á|}}óÜ7&&†£G*·³gÏ’žžN… ž¹Æâýû÷iÕª·oßÎÑV˜¾fϞͧŸ~úLÇÌKZZàÉ“'¹nsèÐ!>þøcŽ?®÷¸¥¥% àË/¿ÄÉÉ©Xâ)‰ÂÃÃ9pàÕªU3v(B‘CI՟ケƒƒñññÄÇÇcjjŠ­­mŽ6Ý¾ŽŽŽ¹î›[»ƒƒ†„„„BõW\…é;¿¸ ÉϽ1^_%ù5]©-J¢)S¦0uêT†PlÉýk×RHNÖ0{ö}åq?¿J´kgÃÚµõ™<9Š÷Þ»€……Š×_·É·ÏŽmY±¢.S¦Üå?ÿ‰2Gø/[VGÍŸ{{ÐýiW©ôoºÇòù¨¨‘éy cåÊ•„‡‡+?777úöíK=ŠýxåáojZZ>>>ìÝ»<<<°°° $$„š5k>wb_! AûtðàAÞxã ÒÓÓ±´´ÄÓÓ“ÇséÒ%Ö¬YÃÙ³g9räÈ yÓ2qâDæÏŸ€ ¯¼ò œ;wŽØØX>ýôSN:•c;9sæ(oL+W®LãÆ¹zõ*÷îÝcêԩܸqƒï¿ÿ>×}5 ½zõbûöíÔ«WÚµkεk×xë­·øé§Ÿ0`@®û·lÙ2Çň¢š9s&·oߦråÊÌ;—W^ysss^zé¥|÷ŽŽ& €¾}û2räHe¦…Mþo’‹â?þ wïÞ¨ÕjLMMñðð J•*ÊŒ‹U«VqèÐ!BCCejŸB=VVV$&&ê=–””„••VVV¨ÕjRRR¨P¡‚^[~ûêþçeo×]°ž¾ójÏÞw~q !DI”=¹¯R©R ÃÛwìpÍ·ý½÷*ñÞ{•xø0ƒÔT ÎÎæ˜›gfÚ;t°E«õÌu¿áÃ>܉èèt¬¬Lpp(xfw«V°ví³ŸC^ddº¾†J¯^½ðóóÃÁÁ¤¤$"##ñ÷÷gÿþý,X°À ±”æ ÀÙ}óÍ7ìÝ»sssvíÚE‡ˆ%22€íÛ·³iÓ&ûì³b?öéÓ§•¤~Û¶m¹víGeÿþýܾ}›þýûðûï¿’cÿóçÏ+£Ôßzë-n߾͸uëãÆ`ùòålÙ²%×ã/[¶LIêrýúu<È­[·hÓ¦ #FŒàÁƒyžƒ……­[·æßÿþ7íÛ·/âOvïÞ À¸qã6l^^^4kÖŒfÍš˜œß·oXYY±fÍ:uê¤ì[ÐEgõôéSFމZ­ÆÙÙ™S§NÎîÝ»¹yó¦Rö'22’éÓ§ë±…B”~nnn\¹rE¹Gll,nnn¸¸¸`ff¦×©$QÜÜܸvíšRª.·öìûÖ¨QƒŠ+ªï¼â*¨ï‚âBˆ’jÊ”)Ìž=­V˰aÃX½zµÁŽ]¥ŠµjY(Iýª^ݼPIý↿¿?mÚ´ÁÃÃ/// À¦M› KIHpp0kÖ¬aìØ± 8Q£F1þ|ÂÃÃY½zõ3Ïdð믿àçç§$õ!³¢n­Ÿµk×røðaRRR¸ví³gϦeË–ÊŒûS§NáîîÎìÙ³9vì§OŸÎQ¢7$$„aƱ}ûv/^¬W>°OŸ> <˜#GŽpóæM&L˜@ÇŽQ«Õ/øì…e…$ö äÇäÎ;|ÿý÷Ô«WOi{÷Ýw•Å”–.]ÊãÇ‹õغX™d¯Zµªr¿bÅŠ,]ºT©W›Ûˆý/¿üFƒ½½=?üðƒ2£ÀÌÌŒùóçÓ°aC ³LMvZ­–9s晦Nª\åwttä§Ÿ~ÂÜÜœäääåСCüöÛo¸ººrþüyBCCéÚµ+GÍuÀ¥BäFJñˆ.ùêââB§Nr´1Bù »}ûve=ÀÉ“'Q«ÕT©R%Ï„´V«åĉhµZœ©_¿¾ÒvïÞ= óÃvnÿ´lmmqssãÌ™3Ê?7ŒŒ e$þ;3cº»™™Æ ã“O>áØ±cܽ{WoZÚ©S§”zö|ðAŽc׫W.]º°mÛ6BBBøâ‹/rlS˜mórá½79iiiܸqƒcÇŽémÛ¨Q#ììì”ûñññ\ºtI¹ýúuÒÓÓsìkgg—çâ·iiiìØ±ƒ°°0Ôj5Mš4á­·ÞÊ7nÝs™ æ¦E‹:tˆèèh4M¾kUtt4<ÀÊÊ*Ï7“ááá@æséàà <®Õj•µÜÝÝqttäêÕ«lݺ•èèhªV­Ê[o½¥$sŠâÑ£GÊÈÎZµjQ«V-¥M÷ÜW¯^ºuëòèÑ#~ûí7®_¿N… èØ±£rq$?ÉÉÉìÚµ‹sçΑ˜˜ˆ³³3íÚµËõy9qâ77·B—†¸rå =Òûý.®Ø…åWóæÍ™>}:-[¶¤jÕª¨Õjþøã¥ýÛo¿¥{÷îÔ«Wøøx† ¢Ôè­P¡ëÖ­cÀ€Ìš5‹‡²bÅ e½BCC©S§4lØ3fªï‚âʯï‚âBˆì S6Ä4ŸAéÅ]gs”¾¾¾ôïߟÀÀ@¼¼¼°µµ%%%…+W®„ƒƒµk×.Öc–‡ûöööܹs'ßÊ_ý5_}õOŸ>Õ{\—7‰ˆˆ`РAÊß›:uêèmÛ¹sg*Uª¤÷ºWöŒŒTÊëœ={VØ J§qãÆ)¯ •J¥w+êcëÖ­ãÚµkÆ9!QbIbß´Z-ȳŒŒ§§'+V$))‰ýû÷ë%ö·mÛÆôéÓ±µµ%<<—ûÏ›7I“&Q¡B…Ig]¢=--ôôôÿ4¥fmÖ¤< ,Γ_ìíÚµS¾?pà€^ìºÅa ÚÛ¶mDFFæ¸0𼆞cáY€Ï>û,GÙ£}ûöéMÁ åÍ7ß̱ï­[·”©y:íÛ·gÿþý9¶½pá½{÷æï¿ÿÖ{ÜÍÍ•+WæwÖŸAözÂÙ¯^½ú Iêñå—_Ò´iS%Ÿ]óæÍøå—_ðóóSOMMU~N¿ÿþ;ÇçË/¿Ô{“8yòd¾ùæFõ̱EEEÑ©S'"##ñôôdçÎzíºç^7»aðàÁz 70hÐ ~øá‡<~[¶laĈÜ¿?G[ûöíY·nÞs5tèP.^¼Èœ9s˜4iR¡Î£oß¾œ={–™3g2mÚ´b‹]!&NœÈ¨Q£ˆ¥N:z/jÕªExx8·o߯ÖÖ6Ç¢´;wæÎ;DEEQ­Z5¥>€¹¹96làáǤ§§+ub Ûw~qÔw~q !Di5¹¯[HW’û™ ;2½¼%öçÎËäÉ“éÙ³' ˜šš¢V«133ÃÇLJ­[·,–²Tc¿K—.œ?žŸþ™iÓ¦áä䤴ůÆòôéSfΜ‰µµ5¸ººÒ©S'BCC•²€UªT!66V¯ÌpvºÙþÙ?·U©RfΜ©×V” ¢dÑÍ^-NÇ—ľÈAûp÷î]% ›×4/ÜÝÝ Ë‘þì³Ï8xð ýõï¾û.‡ÖKΟýôSæÎ @BBï¾û.éééøùù1bĈÇ÷òòâã?fîܹ >œyóæÑ¹sgÌÍÍ9~ü8'ND­VóÎ;ïè-ä’Wìéééœ;wŽ—_~+++lmm±±±!111Gìºý³žw||<7nÜ iÓ¦¨T*å¼s;÷çõÉ'ŸèÝ_½z5jµšáÇë.ÏM£FXºt©rΜ9?~ggg½Çó@tt4ÖÖÖ>|˜&Mš(m~~~tíÚ5Ï}mllXºt)ýúõcÑ¢EØØØðÞ{ïáääÄåË— àÆ4lذT,ž»cǽËcÆŒÁÓÓ“ôôtÖ®]ËçŸ^¨¾®\¹BçÎ‰ŠŠ¢sçÎlÚ´IY#"7ûöícôèÑ|ûí·Ê‡´3fàééÉõë×Y¹reŽR†‘#G’‘‘AãÆ9räöööJûÀéÚµ+W¯^%00P)!õú믳|ùò\g‰äæôéÓddd`nnN«V­Š%v!„B‘»ÔÔT&MšÄ–-[pttdêÔ©¼ýöÛF‰%{r_¥R1hÐ £ÄRR”¤‘é%‘™™™,_Œœ åßÿþ7[¶lQ’ñ5jÔÀÓÓ“úõëóïÿ› 0`ÀÚµkG«V­ Uú˜eáÂ…Lœ8@¯ @~*W®ÌÖ­[ùðÕ¼…J¥¢iÓ¦zë" !D~¤†ƒd-¥¢6cÆ ^yå\\\”'º¶ÜJ¯T«VŸþ¾úê+vïÞ À‡~ȵk×puuåûï¿Ï3†/¿ü’Ÿþ™Úµk3tèPêÔ©CõêÕéÙ³'†   ‚ƒƒsŒNÉ-ö®]»âééIóæÍ•ò ºÄjöØu÷uû>xðwwwš7o®ŒXÏ:b/¯²3¥Mjj*?ýô¹¶@Ö¤>@§Nr\DÉ®gÏž:tˆnݺ1sæLÜÝÝ©\¹2¯½ö'Nœà?ÿùG-ÿô»té’£F`³fÍèÒ¥ 9ë¤0.\¸@ûöí‰ŠŠ¢{÷îüùçŸù&õ!³vâ¼yóô^ÛÊš§OŸÎ1ŠkïÞ½Ê,–¯¾úJ/©бcG¥äÔªU«P«ÕÊôË»wïê­W¡V«‰‹‹Ë±¨•îÀ«¯¾šk9‰¢Ä.„B!r7yòdŽ?Ξ={˜9s&C† !,,Ìhñd]PwÈ!¬]»Öh±”º‘é=âòåË„††rîÜ9âããÙ´i“ÞzZåMXXþþþ´iÓ¼¼¼0`@Ž…Zų©]»67n$>>žëׯÃÝ»w•ÏêóçÏçŸþ!**ŠpôèQ´Z­RJÖÔÔ”Y³f‘À;w¸wïûöí`úôéhµZ½AZ­­V«¬äååÅ©S§HHHàÆ$&&ræÌ6lhàŸ„¢´’ľ¤¤¤(ß[XX°qãF 3‘ýçŸêµe_˜E§S§NL›6 ­VË Aƒøê«¯X·n–––ckk›g œ°ÛXð¿Fù-X¤sæÌ:tèÀýû÷éÓ§¿ýö–––î×®]»\§¨êŽœœœ#á®[ÂÆÆ†7Þx#×~{õêdþþèJN5hÐ@™’uÔþÆqtt¤fÍš¤§§+ë¶Ék!Ü¢Ä.„(²/Ž%·ÒqB”^¬ZµŠÀÀ@êׯϛo¾I¯^½ò]÷Êž'¹õêUüüü”[^³Š?ûì3e›«W¯æºn¸ŸŸ_®3 ¤´g}?[ÜÂÂÂ?~œjÕªáïïÏ„  KYý_hiiIýúõs-¨û—•JE­Zµôª< êÕ«'¥•„Á¼È¿ã°$±oY“iii¼ûî»@æè[]Í{][~ ÁбcGîß¿ÏÇ À‚ ôêÈg÷Ï?ÿðú믳`Álmmùí·ß¸ÿ>ÿüó»ví⥗^bõêÕ´lÙ’K—.廓““’è|å•W”…SóŠ]·¿®½mÛ¶Ê?EÝÊñº¶‚ν4ÉšŒ/ÌÚÙiµZȸq㈊ŠbáÂ…\¿~ÄÄDNŸ>M¯^½Ø±c;v$88¸Øã/ny®©T©PðK—.Ñ©S'bccÌߟÜ.ʱs;¾îùswwÇÌ,÷ŠeÙ׆ÐÑÚÏšØ×-ì›À‘#G”ÇuÛäV_¿¨± !„¢ä›>}ºÑ/T•†rŽÅéúõë>>zI};;;† Àþýû‰‰‰É7v^zé%%©Ÿ””¤”É»î~Öó¶¶¶V’úÙÛÊJÝĬ£¼óJâh4š<÷ß°aùF-kR?«ñãÇðäÉ“_eÁ§Ÿ~Ê™3gpvvæŸþá½÷ÞË÷gøm£°²²B­Vë•MJJ*Q3†³ŽÜ|ø0Ïýuo˜r»£“×sVœt5óº8¡{m½h>>>Ìš5‹ªU«²zõjT*û÷ï'00ð…O7?¿ç(k[ÖÑûÍš5£bÅŠ$%%qáÂ¥ ݺu#""‚û÷ïX†G!„"«ÔÔT>úè#4h@‹-øí·ßŒR©âââ‚™™™^ÉÌÈÈHeí¢’"krРAy&÷³&ðg̘¡$g6oÞÌãÇ kq3t»´˜;w.­[·¦gÏžØÙÙaff†••žžžÄÆÆ²uëÖb9ŽF£aúôéù–Œ}ùå—™>}ú `%„x~>TÖ“éׯGŽÁÎÎŽ &ÉæÍ›yã7Êìšå$ö @¥R)¥6:”ë6Y[m×®]®Ûœ?æÌ™Ãúõëñòò"66–~ýúåZO1ëÈñ¬#ñ³ËÚ–µüÇ«¯¾ª”ÇÉ+öÇ+ßg=뢠í_·n]êÔ©“gŒ¥‰‡‡‡ò½®ŒLvùÕóÔ=oEyΊ“®ÞZ^ î›7o¾ãf—uf‹··7ãÆ2?Äd­Y_\7n dÖÚו‘ÊîÌ™39¶‡Ìç®U«V@æ¨ü;wâââ‚»»;ݺuC«Õ²sçÎÎB!„ÈjòäÉ?~œ={ö0sæL† BXX˜±Ã*5¬­­éÖ­AAA@æà› 6зo_#G–SA#÷• ;®®®4oÞ\™å›ššªÌþ-m •À6”òoÿïÇÿYZZ²`Á=zÄåË— åܹsÄÇdziÓ¦b™õ®ÑhðóócÆŒù.ª™žžÎŒ3ðóó“ä¾(²°°0üýýiÓ¦ xyy1`À€r½Hvq8sæ C‡¥víÚL›6»wïÒ°aC/^ÌÝ»wùúë¯iР±ÃÅLûÒ³gO s‘Í£Gæh_¹r%™ õññÉÑž””DŸ>}HNNÆÇLJ>ússsÖ¯_GeêÔ©9ö³±±QþÑïÛ·OoêiV»víÀÜÜWWWåq Þ|óM~ýõ×S5 «W¯ iÓ¦Ô«WO¯½uëÖ8;;™‹;ewïÞ=¥4‰îgT4lØP¹H‘×k] ýÜèܽ}û6.\ÈuÝsù/Äûçµ8±îVƒ r̆ÑÂß¿?‡R~§[·nMåʕٶm§NÒÛV!„"/¬ZµJ÷æ›oÒ«W/å3„(œo¿ý–Ó§OS¯^=\]]éÓ§=zô0vX¹Ò%÷5MŽä~HHˆ2øÄÏÏOï+ï=úó2DÛºuƒ¯¾‚¼òä]ºÀ’%PØü¸™™nnnxyyáááQ¬‹^~þùçlܸ±ÐÛoܸ‘™3gÛñEù!‹d¯ôôt6nÜHÛ¶myõÕWY½z5iiitïÞ;wráÂF±C/ˆ,žk C‡åóÏ?'&&†#Fð×_QµjU¶oßβeË”ítg5räHþþûoªW¯®”"Ì)¥ßÿ=~~~|õÕW´mÛV¯Æ"À Aƒ˜={6·oßfäÈ‘|÷ÝwÊ(|FÜ9s”s{öì©7:à“O>á×_åŸþaÔ¨Q¬^½sss¥FçÙ³gÌQDÙ™šš2qâD>þøcvïÞÍâÅ‹•YÉÉÉ 2„ÔÔT,,,ø÷¿ÿëÏ.&&†G)÷u ›jµZ½ò@æææ%æê£J¥bôèÑLž<™ 6УG½Zù_ý5û÷ïÏsÝ´[Ý(êÖ­«´ïرƒ/¿üÈL¾wìØñ…œ‡n¦‰F£aÊ”)¬\¹R©'¿wï^V¬XñBŽ[KKK~þùg¼¼¼¸}û6|ð¿þúk±õïååEëÖ­9vìŸ|ò žžž4iÒDiÿú믕 +cǎͱ¿.YLFF†’Ø711ÁÛÛ›àà`ÒÓÓ©^½z¾%²„B! ³ìâ“'OðòòRkÑ¢ëׯ7bT¥O­ZµçöíÛØÚÚê•S,‰².¨;pà@:tè@­ZµôÊðT®\Y(U»vmîܹChh(W®\y¦2CYgzgdd ÕjõÊrfžu[Èfccƒ‰‰‰r355ÍõûÜîç˳ÄþöÛoç{¬¢š5kV‘ÎÉÍ­=æÜ½[•õëÍ9qâ>~~¡˜ššüw½ºÖdd˜eÏÊ•&œ<àA—”v]_Ï+...ß8u®^½ÊìÙ³Ÿ¹ÿÀÀ@  W"V”?ÏZÎ¥¨‹d¿¨²1¥µÍÇY¾|9K–,QJsÛÙÙ1lØ0üýýå÷²‘ľX[[óÃ?àëëË… x饗h×®="44ÈœF9gΜû~ÿý÷¬[·~úé'ªT©¢×Þ¯_?öìÙÊ+}úèÉjüøñlÚ´‰Ã‡3fÌ–/_N:u8~ü¸RNfÁ‚y–á™={¶2e6«´´4ed;d–ò1Ti˜Â˜0a!!!œ}šFáé鉳³3‘‘‘ÊÅ ~øá,--_È9¸ººâííÍŽ;X³f û÷ï§iÓ¦>ÞˆQ•^¥¹üçíÛ·õ}ôÑG¹n·víZfÍšUè~ÍÌÌpttäñãǨÕj¢¢¢”Ù»QQQ¨Õj s-±ì‰}µZgùÊgÆÊ•+ '>>+++ÜÜÜèÛ·ož³+~ÿý÷b9vvŸ}öÙsíojꀫëN®_oÉûï¯çñcý™ÀææÕpuÝEDÄ+ôìù>ññ[žëxÙåwáJ¥R) ~F£<¿Ï"==WWWLLLP©T9nB䦰‹dgOì‹ÿ6l="55È\«rìØ± 4(Ç@]QöI)òññáÏ?ÿ¤^½z$$$ð矊J¥Â××—C‡åøãuöìYÆdŽˆïÔ©S®}/Z´ˆÆóøñcúõë§WÏÆÆ†ýû÷3~üx*V¬ÈÇÙ±c›7oæÖ­[˜››3pà@NžwïfÎzwrbÈÐÐjµ¨ÕjÒÓÓ‹”ÔÏJwa ##ƒôôtÒÒÒ”„£ÙÉ"ÙE§ËóEGG“ššŠ;vìàâÅ‹øûûKR¿œR=~ü8çûbtüøqZµjUf¯¶;vLIz–F£áäɓܢÞñ IDATºu +++š6mj°Q#OŸ>%,,Œ¨¨(´Z-ÎÎÎxzzbggWèýCCCyðà•+W¦eË–ÏôÜ>xð€Ó§OóäÉjÖ¬IëÖ­177/êé”·nÝ",, FCÓ¦MŸiZ”F£áܹs\»v§OŸâèèH³fÍò¼SÏúºÕjµ„……‰^^^9fŽ”e7nÜ ""‚¤¤$ªV­JëÖ­¥F(ñt¿ç{öìáå—_&%%¥Xk±Bæß­VKrr²2sèÒ¥KÊÒÆ°gÏÿgïÎ㢮·Ç¿ ÄÜsÍ=Â(Sqë‰b¹ ¦…ävq-ÍíöEï•RÌ«[š¨T–™¨˜–f"ŠŠ¦"‹¦‚ËÕ47B‘%a~ð›O Ã>0ÌpžÇëùà0 çsÞçýK9[öïßOÿþý UVDþÖB”¤¬¯—м¾Ê»¯1½¦‹J—{y÷«¬ã-^¼˜%K–àççÇâÅ‹KÜ>##ƒzõêqêÔ)¥xàwÞáÖ­[ÅÎÛTÞsW49_]^KÆü3‘?©Â믿äUf&$$ R©¸|ùr¡9Î^zé%öíÛ@xx8}ûöÅÕÕ•ãÇy.íkáäÉ“ôìÙ“¬¬,ÛÕ®]›£Gâìì ÀæÍ›=z´®6O÷îÝyÿý÷u¶èHJJÂÁÁ+W®(–õuZÖ÷a}¨]»%;_ãáËœ9ã c}+:w¾Êljœ9£»ýPy_¿ÕEuy?úUÞ×Yff&óçÏ'88˜ÔÔTjÕªENNjµwww>ýôÓóiÃÏyEâ(‹3gÎ0mÚ4ºu놯¯où1 Mߟ³ª“#GŽð /_öïàÇ—•ößÇ—i¿¹¹¹ xwìØÀ€ŠŒOZñ€™™Ï=÷œAVVVJßôòî_Ô¨ÒhÒ¤‰ÎÉM¶‚¦<ÌÌÌèÚµ+]»vÕsT¥§R©pvvV>Ä×4mÛ¶¥mÛ¶†C!„5T:uxå•W "88˜¤¤$¾ûî;>ýôÓJ=¯±'µªk\E)*©¯íðüóÏJêC^›Vmb?$$¤Lsq=ûì³üòË/Ì™3‡_ýµÀº=zðá‡VêߦآC­n@VÖuëkÕÊ»–ìì[U“†¤${ÅŠ\¾|Yi¹egg§÷"$SÓ©S§bçj5“$ö…BatNž<  TOU](„¦â“O>aðàÁ´iÓ†””Þ|óÍ"{Ž ã¥Mê«TªI}ÈKæ—t³ÅÇÇŸËŽ;Vêó÷êÕ‹ãÇóçŸríÚ5T*-[¶¤Aƒe»rжèð÷÷ÇÅÅkkk233IHH ((È([t4l8 €ÔÔpë4xãÿ¯?Te1=N¥R™DU­0.e$[¡›$ö…B!„¢škÑ¢111\»v kkëb'ÆyŠKV>ûlÞ¿'N@u)èÏŸÔÿòË/ $õ«Zƒ JÌ9r$_}õ•Òk=77Wyä^Ô×Ú*ý€€æÏŸ§§§Î»víÒyþ;w{ÞñãÇ—ë{àççW¦ëÐ>¿wÏ…œœÚKfæK˜™ÝÇÑñ} ¯,7dt©_¿~±ñj>ÌÌÌÊÝg_;§CþÖ¢f)Oë›òL’]Þ–{%‘×­0v’ØB!„ÑÑVê !DMSUss‰ªU\¥~u§R©¨]»v…SÞÅ·¼‰ýÒÌ¡‹ö¦@›6Ð;»M:×7kË—ÛòôÓ?:NE[H%''»^›àOLL¤k×®ÊÄœ¥ennιsç°··þNîkoèã5!LOhh(ÞÞÞ 6 ///lmmIOO'11___""" 4t˜B Iì !„BabÊS '„0ŒÇ“úãÆ3tHe*-:æÎ(êžÄÔ©0|8Ô«Wµqi™™™affF‡X¸p!K–,)Óþ‹-R’úw#B¥R)UüBèâïïÏ–-[tN’½`Áðóó3ª¹4„0$Iì !„ÂèHO}!Š&ÕpBüIý7Öø¤¾)Ý”5ªøõM…`Pÿ÷ÿÇo¿ýÆ÷ß_ªíGŽÉ{ï½WÉQ SdŠ“d aH’ØB!LXzz:çÏŸ'77—ZµjéõØÚž”999R%D5"ÕpÆcÉ’%e®’¦ãñ¤~y[Ƙ ¹)i8ffflÞ¼™Ž;âïï_d[sss-ZÄ{ï½'ŸýD¹˜â$ÙB’$ö…BÖ°aCåëâ&‡*j®å/S«ÿþ8QÞÉ×ÊêäÉ“Àß½ö¥‚_ˆ¿I5œÕŸ$õ “›’†eff†ŸŸþþþEn“¿§¾åQÞI²…ºIb_!„0qÚä·6!¯Ü,¿üëJú·¨}sss‰ŠŠªŒKB”TÃU‹/.÷ÄœÂøåOêoذA’úÿŸÜ”¬rss‹\gggW…‘ö¿ÿý€–-[ê}$ª¨å$[¡›ŒB!„Ñyá…”Bˆ‚puuÅÓÓÔj5VVV8;;“””$ÕpBÐãIý7ÞxÃÐ!UÚ›’ááᤦ¦™™I\\>>>rS²Š—0/nôgE¼ú꫸¹¹®,;|ø0nnn øànܸ@pp0xxxпþïÿþ0{ölZ·n­óX7nÜ`ݺu„‡‡ÓªU+úôéáC‡X·nÓ§O¯š‹ªad. !ôKûB!„B˜˜èèh‚ƒƒ‰‰‰Q’cŽŽŽŒ9’¡C‡:Û·o'99ÈKÌGFFÒ¦Mú÷ïÏÚµk¹}û6^^^E&ö£££ÉÎΦI“&´jÕ WWW:ÄñãÇ%±_Id. !ôKûB!„0:'OžþžX*ø…ø› s¢ô*»›\þ¤~pp°$õ‹!ï]ÕƒZ]tš¨²+öƒƒƒ .Õ¶¿þú+ݺu#66–M›6áé马ëׯÉÉÉÅ&‡¯_¿€µµµ²ÌÆÆ¦À:¡Ú¹4üýýqqqÁÚÚšÌÌL ’¹4„(#Iì !„BaBd˜»ñºwï³fÍ"99™I“&ñòË/›dÕÛãI}oooC‡T­É{Wõ`ÈV<óçϧOŸ>DEEñïÿ»\Çùæ›oJÜFÛÖ'33SY–‘‘Q`Ð?™KCý’O‰B!„0:ÚJ}!Da2ÌÝx…„„ðå—_°k×.Z´h>>>RÁhd¾úê+%©¿nÝ:Iê—‚¼wU†LìwíÚU¹±“?á^333Ë8ÀÇyþùç L¾ûø¹nݺEZZO<ñ‰‰‰téÒ¥<á‹R¹4„Ð/Ýï‚B!„B£¤æNjj*— ‰‹‹ÃÇÇG†¹ GGG®_¿Î’%KhÓ¦ üðùy'DÍUÚj¸š’Ø×Õ9ÿº²N’¨ïãU”¶Š¿o߾ܹsGéÅñâEþõ¯áèèȈ#ª4&!ÊCnJV2_‡¨LÌŸ?OOORSS©U«999¨ÕjÜÝÝe’l!ÊHZñ!„Âèdeex!þ¦­† W†³gff‡O©†‹ŒŒdÀ€tèСÈm:tèÀ€ˆŒŒ¬òãU†Æ3wî\.\¸@çθqã†Ab¢¬¤EGõ û¢2i'ÉNNNæÂ… DEEOJJ aaa´hÑÂÐ! aT$±/„B!„ ÀÕÕOOOlllP«ÕXYYáììLRR’ÉWÃ=|øÙ³gÓ»woöïß_âöû÷ï§wïÞ¼ýöÛ<|ø°ÒWÌÌÌèׯŸAÎ-j}'yå¦dõ ‰}Q´“d»¸¸Ð©S'êÔ©cè„0J2ÆJ!„FçäÉ“Àß½ö¥j_ˆ¿i«áV¬XÁåË—IIIÁÊÊ ;;;“ÿÃù¯¿þbðàÁ„‡‡—yßÀÀ@bccÙµkVVV•rûì3ìíí±··gË–-9r„ÄÄDiµVF¥$[ûB”ŽŒB!„ÑÉÊÊ*ðBüM[ ÂôéÓ7nS¦LaåÊ•ÄÄİqãFîß¿oè0õ*,,Œ{÷îZ^«V-:Tä~‡ÒYúðáCß–÷xÉÉÉJ{ŸÒÐN*DuQIýÐÐPÜÜÜHKKÃËË‹yóæáããCÓ¦MñõõeöìÙz=ŸÐÍ­x,--Y³f ÙÙÙ¤¥¥±qãÆB‰s333,--±°°P–EDD0qâD†ʸqãX¶lééé%®;zô(³fÍbÍš5EÆtãÆ Ö­[äµWûå—_èÝ»wå¢ôd’l!ôKûB!„B˜ÒVÙ’±cÇê\>wî\zõêUä~½zõbîܹ¥>OEŽ7fÌT*U±mârýúõ|õÕW¥ŽKüíÌ™3¸¹¹1sæL ŽI¨Š¤>ÔÌ›’Õ‘!û£GæÖ­[|ÿý÷„„„ðàÁF]`›ëׯDHHgÏžeÀ€lݺ•ììl.\¸Àÿýßÿq÷îÝb×ÄÅÅÄöíÛ‹Œ)::šììlš4iB«V­puuàøñã•ñm0i¸ººâéé‰ jµ+++œIJJ’I²…(#Iì !„ÂèœýôS¢¢¢¸}û6Íš5+väõíÿÇ?þÁ³Ï>[äñ¯_¿€µµµ²ÌÆÆ¦À:QzÚI²“““¹páQQQÄÇÇ“’’BXX-Z´0tˆBIì !„BaB¤îoE% ókß¾½ÁŽW’ððpT*<ÐÛ1M¹¹9ׇÛ‚Ÿ~ú‰—_~™:ðÉ'ŸHb¸ ª2©rS²º(®Ç~e³°°`âĉ?~œóçÏóÏþ3³âÓV}úô¡uëÖlÛ¶ ;;;¬­­yë­·ÈÌÌ,v Üø[ºti‘Ç·´´PöÈÈÈ(°N”Mtt43gÎÄÛÛ[yLœ8‘°°0C‡&„ёľB!ŒÎ /¼À /¼`è0„¨–¤îo 6ÔË6•u¼ÒªW¯‘‘‘z?®) æúõë¼ÿþû´hÑ‚„„¦OŸNóæÍ™5k–¡Ã«öª:©rS²º0dÅ>ÀÔ©S•ÿ{Ÿ·oذ!çÏŸgÏž=,_¾œvíÚ±mÛ6Ö¬YSì:€ßÿ={öpêÔ©"ßµkWnݺEZZ€Òæ«K—.½ÜGæÒB¿ w+V!„BQiÔj5ŽŽŽ†CèIïÞ½yûí·Y¹re•ž7::šàà`bbbHIIÁÊÊ GGGFŽÉСC«4–²jذ! ,`îÜ¹ìØ±ƒÕ«WIPPÖÖѸºº²woXbUpMbˆ¤>ü}SrÅŠ\¾|Yy½ÙÙÙQ§NJ?¿ÈcèÄ~‹-øùçŸ177§~ýú%nìØ1¶lÙB¯^½puu娱cÄÇÇ“››[ì:€Ý»w3uêTþñ°gÏÇæ™gpqqáĉŒ?žgžy†;v`nn΄ ôzí5v.AƒZ·`ÁðóóÃÖÖÖÑ a|$±/„B£“••e脨֌9+ŠöÑG±zõjþúë¯*i—Š··7Æ ÃËË [[[ÒÓÓILLÄ××—ˆˆ+=ŽŠR«Õ >œáÇsúôi>þøc¾ùæöí‹dß¾8991}útÆ_ vMd¨¤~~rSÒ°Š{o©ŠÄ>@ß¾}Ë´ýW_}Uà½ÈÍÍI“&‘P亲غu+cÇŽeûöílß¾¦M›òßÿþW¯­×jŠÒÎ¥!‰}!JGûB!„B˜SIÆêRYI%}·¼Ç{íµ×ضm[±Û}:ãÆcÊ”)¬\¹’˜˜6nÜÈýû÷ ¦Ð¡W¯^¥ÞÖÁÁuëÖUb4¥¯¬4F5báÂ…\¹r…-[¶ðâ‹/òàÁV­Z…££#ìÛ·¯Ê*” M’úB«¸Ä~uÖ¸qcìíí $îK³®,5jD›6m$©_2—†ú%ïFB!„B˜SNÆVçÏŸ/׺²˜>}z©¶›8qb¥N$®­¬ W^3™™™ÄÅÅáããc••æææŒ1‚ÈÈHN:Å›o¾‰¹¹9»ví⥗^¢cÇŽÄÇÇ:ÌJ%I}‘_uhÅ#L—v.ääd.\¸@TTñññ¤¤¤F‹- ¢(•JUàQÚíJÚ^”$ö $11‘Ÿþ™Ã‡“œœ\eçÕh4\¸p}ûö±wï^âããÉÉÉ)õþ999œ>}š={öpâÄ >|X¦ó§¥¥ÅÞ½{9{ö¬A>Ü»w?ü×^{~ýúáææ†››111¥ÚÿÀL:•Aƒ)ûΚ5«Ìq$''+ûÿöÛoeÞ¿&˜5knnnüûßÿ6t(B!„Ѩ ÉXCˆŒŒdÀ€tèСÈm:tèÀ€ˆŒŒ¬Ð¹ÌÌÌÐh4L:µÄm£¢¢P©TÜ»w¯BçÔ¥¦UV>óÌ3lذßÿ¥K—pîÜ9üüü Y呤¾xœ¡'Ï5ƒv. :uê$d QNÒc¿ŠEEE1uêTbcc•eµk×fôèÑQ¯^½J;÷ºuëXºt)W¯^-°¼aÆ̞=›wß}·Ø»óëׯç_ÿú7oÞT–Õ¯_Ÿ¹sç2oÞ¼b‡£=|ø… ²fÍÒÓÓ•åöööâááQä¾wîÜáèÑ£Ê#66–ììl,--Ë<ŒüÖ­[<÷Üs\»v­ÐºÒëý÷ßgÑ¢Ee:gQ²²²8xð <ÐË1MMLL ¤iÓ¦†E!„0ÌŸ?OOORSS©U«999¨ÕjÜÝÝM.[Ù>|ÈüùóYµjU©¶ß¿?û÷ïgöìÙ|ðÁXXX”ûÜÿýïyíµ×0`@‰Û>ùä“üòË/ôïß¿Üç{œ¶²rÅŠ\¾|Y™ˆÙÎÎΤ“07fÑ¢EtéÒ…!C†‘‘aè*Enn.Ó¦MãóÏ?ÇÂÂB’úľ¨|ÑÑÑ£ü^qttdäÈ‘ :ÔÐá‰2(ë{‚TëëŸ$ö«Ð¡C‡0`ÙÙÙXXXàìì̽{÷8wî!!!ÄÆÆräÈ‘JùÂ;wJR_ÒŠGT®ÐÐP¼½½6l^^^ØÚÚ’žžNbb"¾¾¾DDDhè0…0ÒŠ§Šdeeñú믓½½=çÏŸçÈ‘#üöÛo|óÍ7˜™™Ã{ï½§÷sŸ:uJIê÷êÕ‹K—.qôèQ"""¸vícÆŒ`ûö턆†ÚÿÌ™3J•ú!C¸víäêի̘1€/¾ø‚~øAçù׬Y£$õýýý¹|ù2‡âêÕ«ôìÙ€I“&qûöí"¯¡víÚ¸ººòöÛoÓ§OŸr~'`ß¾}̘1ƒ &àââB·nÝèÖ­[‰ÉùðèÑ#¬¬¬ ¡_¿~ʾ%ÝB!„¨JÑÑÑÌœ9oooå1qâD šÑÈÍÍeĈåJêk…‡‡3bÄrss+KýúõÑh4<ÿüó%nûù矣R©*|N­èèh|}}éÙ³':uÂÅÅ…±cÇÊkɈIR_ÇX'ÏÆÁßߟ-[¶ÂôéÓ7nS¦LaåÊ•ÄÄİqãÆ2wf¢&“Ä~ùꫯøý÷ßX»v-mÚ´QÖ=š &yÄõÝsëÖ­Ê×kÖ¬¡qãÆÊóºuëòùçŸS·n]ûË—/'77—zõê±aÃ¥ÒK­V³råJÚ·o䵩yœF£aÙ²e@ÞM…… *CoêׯÏ×_¹¹9EoÞ±c< **ªÀùÊCÛFÈÞÞ¾Üû6oÞKKËrÇ „BQ™BCCqss#-- ///æÍ›‡M›6Å××—Ù³g:D£°~ýzvïÞ]áãìÞ½› 6è!"8zôh‘£d÷ñÇWø|òZ2=’Ô%‘V<¢2Ý¿'''¾ð IDATë6lH½zõ”ù„%“V/^d×®]ܼy“Æ3dÈÊ_rr2 ´hÑ‚-Z(ë´ÿ÷Íš5£uëÖ$''³mÛ6._¾Œ¥¥%}ûö¥W¯^%ž###ƒŸþ™øøxÒÒÒhÒ¤ ½{÷æÙgŸ-´í¯¿þJnn.ŽŽŽ¥.@rrrŸo}Å.„¢fÒVà 4¨Ðº ààà€ŸŸ_ßÛ¢ ôôtÞ}÷]½ïÝwßÅËËK)¦©ˆ‰'Ò·oßR†ŠŒŒdÖ¬Yå:—¼–L‹$õEiH+Q™<<<3f þþþ¸¸¸`mmMff& akkKË–- ¦FCûU@£ÑpèÐ!€"ÛÈ8;;S·n]ÒÓÓ‰ˆˆ(ØÿñÇY¼x1ÖÖÖÄÄÄ`ggWhÿ+V0oÞ<,-- %µ‰ö¬¬,²³³uöŠLKK+°­–v2“âbïÝ»·òõÁƒ Ä®¶¤ýüñG ݨ(%¹œß{ï½W¨íÑpssSžGEEñòË/Ú÷êÕ«…†A÷éÓ‡ˆˆˆBÛž={–áÇsþüùË .Õ5ÄÄÄ0uêÔBÿ¯Zžžžlß¾½TÇ*«   –/_N×®]•þãºwïÀ·ß~‹———²üáÇÊ÷iûöí?~œåË—ø08þ|>þøc¦L™RæØ®_¿N¿~ýHLLÄÙÙ™½{÷X¯ý¿Ÿ9s&½zõâ7Þ(0q³ŸŸãÇgÆ ENüüÃ?0iÒ$nݺUh]Ÿ>}Ø´iS׫··7¿ýöË–-cÞ¼y¥ºŽ‘#GËþóþõ¯é-v!„5Wi«á$[´°°0£hkժŠ|þÍïСCôíÛ—œœœË“““Ù¹s'£GÖK|íÚµ#;;›:uê]ì¶Û¶m£K—.œ8qFCnn®ÎGNNŽòµVy_K‡*ò<%=òÇQžÇ¥K—*þ 6A’Ô¥%û¢20þ|<==IMM¥V­Zäää V«qwwg×®]†Q£"‰ý*pãÆ %q®«bÀÌÌ '''¢££ %ß{ï=:Dxx8£GæðáÃ’ó'NœP‚AAAtíÚµÀþÆ cÙ²eyþXŠŠ=¥úã±kŸ×©S‡V­Z•¸ÿ… ôšØõÕW Tü¯[·Žœœ PhôÃSO=Uày«V­˜ûŒ.]ºðüƒÔÔTvîÜÉÿþ÷?¾üòKúõëÇo¼Qh¿_~ù…W_}•GѲeKÆGãÆ‰å믿æàÁƒ¸¹¹qúôie~†ž={òÛo¿ñ믿–ê:2228{ö,/¾ø¢ÞbBQ³I5\éi[D–Öܹs‹5׫W/æÎ«´¢Ìo̘1 `*J­V“••Å;ï¼ÃG}Tì¶ñññåj%YÞ×REæÄÒ——_~™3f°lÙ² M^l $©/ÊBû¢2YXXÈŠ+¸|ù2)))XYYagg§´}B”ž$ö«€¶·>LŸ9s†&MšÐ¨Q#š5k ´®Ñ233cÓ¦MtëÖ_ý•E‹@jj*£G&;;///&MšTèü...Ì;—€€|||X±býû÷ÇÜÜœãÇ3gÎrrrxíµ×1bD‰±gggO‡°²²ÂÚÚš'žx‚´´´B±k÷ÏÝ)))\¹r…®]»¢R©”ëÖuíõøê7’““ƒOêr]ž~úi>ÿüsåù²eË8~ü8Mš4)°¼(~~~ܼy“:uêpøðaºt颬óòò*ñÃtZZ£F"=={{{~þùçB£5V®\ÉÂ… KŒÅÐöìÙÃwß}ÇÈ‘#•eÓ¦MÃÙÙ™ììl¾üòKþýï—êX ôïߟëׯӿŠÖ~àÀþùÏòÉ'Ÿ(¼/Y²ggg._¾Lppp¡äxnn.“'OæÑ£GtìØ‘#GŽP¯^=eý¸qãx饗¸xñ"þþþJ ©_|‘/¾øBç(]N:Å£G077ç¹çžÓKìB!„TÃUžÁƒ—¸Í+¯¼¢3±_YV®\ÉСC+%™n쯥իW³zõj ï3ÔÂ… ‹m3bŠ$©/ʪ¦ýŒÃP«Õ: $…e#=ª€¶ZP*{—,YBçα³³SZœh×åß^«iÓ¦|óÍ7˜™™ñᇲoß>¦NÊ¥K—ppp(v"­åË—óÍ7ßвeK¼½½iժ͚5ÃÓÓ“ÜÜ\‚‚‚زeK¡ª%]±¿ôÒK8;;Ó½{w¥=ˆ6±úxìÚçÚ}oß¾““Ý»wW*ֵ늺vcôðáC¾þúk ¯jþ¤>@¿~ý ÝDyÜúõë•ù6oÞ¬³S½zõøôÓOõuå8p`¤>äÍ0pà@ oÔIiœ={–>}úpýúuÌîÝ»KìU[¯^=V¬XQàµmkk«ÌùpêÔ©B•'û÷ïWF±|øá‡’ú}ûöU*îÖ¯_¯ ·ïÙ³'7J'ÿ|999Ü¿¿Ð$@ÚÏ<óŒÎJ²òÄ.„Bh«á’““¹páQQQÄÇÇ“’’BXXX9iDÙÕ–&¿öíÛWA$õîÝ[iŸ©O¦ôZòóóÃÜÜ•JŧŸ~Z#>CIR_”‡Tì‹Ê¯¯/={ö¤S§N¸¸¸0vìX šFGûU 33SùºvíÚ|ÿý÷@^"{÷îÝÖýõ×_:Ó¯_?þõ¯¡Ñh?~<~ø!›6m‚-[¶`mm]d ©©©œ8q‚ëׯZwçÎNŸ>­$‘‹‹=))Ié%áÂå¦DQ±k÷×®ŒŒäöíÛlÙ²F£¬+îÚMll,<Š®ìòôô,öÚ_jÏ?ÿ¼Î‰Z‰® ×àïFÚ×DqNŸ>››·nÝbĈlÛ¶ ‹÷ëÝ»·Î!}ÚsgddJ¸kç†xâ‰'0`€Îã6 ÈûùѶœ²··WF ä¯Úÿþûï©_¿>Í›7/ÐW»MQCúË»B¡¥­†sqq¡S§N2Ä]6l¨—m*ƒ †~ýúéõ¸ÑÑÑÌœ9oooå1qâD£NÀL›6 333T*ß}÷¡Ã©’Ôå%‰}Q™BCCqss#-- ///æÍ›‡M›6Å××—Ù³g:D!ŒŠ$ö«@þäcVV€2q–­­­Òó^»®¸~~~ôíÛ—[·n1wî\ ô‘ÜŸþÉ‹/¾H`` ÖÖÖlÛ¶[·nñçŸòóÏ?Ó®];6nÜH=8wî\±±7lØPItvîÜY™8µ¨Øµûk×÷êÕKé¡?~üxT*•²®¤k7& Ê×¥™›@—Ó§Oš¨×UÍõä“O%ßÐ9wîýúõ#)) ÈûùÑ5 tyέëüÚÿ?''§"‡¢>>7„–¶j?b_;±ojj*GŽQ–k·ÑÕ_¿¼± !„ Õp5Ùþýû Ñ˱jBÆËË •JEݺu•QÑÆN’ú¢"ŠkÅ#‰}QQþþþlÙ²…¦OŸÎ¸qã˜2e +W®$&&†7rÿþ}C‡)„ÑæiU «mëšE‹1nÜ8êׯ¯TÚgddÚþqfff|ñÅ888 ÑhèÑ£S§N-öüï½÷qqqXYYñË/¿Ð¶m[eÝÀ9xð NNNܼy“þóŸ8p ÈØëÕ«ÇÞ½{¹|ù2­[·V’«EÅ®}®½î&MšÀ­[·”Ö2Ú}Kºvc’(ôãm\´lmm‹Ü?77WùeÖ´iSýgùGeèRÒĸ¸8 o®†?þøƒ‰'Ò£GRM´\Ò¹u_û½/îÿ¨~ýúÊ×ùÿ¿{öìÉÖ­[ $öþùg:uêÄ™3gسgnnnܼyS™ƒB{3@± !„¡¡¡x{{3lØ0¼¼¼°µµ%==ÄÄD|}}‰ˆˆ 00ÐÐaŠJ4~üx<ÈúõëQ«Õ˜››cffVªG­Zµøßÿþü€Ñ5úrÁ‚888àççWè3Sÿþýuû‡~ÐïØ±cuÆQÚ˜µØØØrß¼ÊÈÈP’ß-[¶dëÖ­å:Ž¡IR_T”Tì‹Êtÿþý"ÛÚ5lØzõꑚšZìßâBˆ¿Ib¿ 䯺½yó¦òu«V­ l§]WR¯Ê¥K—*¿POœ8Áž={Šluy-oÜÝÝ $õµlllðööæƒ> ""‚;wîиqc±?õÔS˜™™Ñ®];eyzzºÒäñصÏó_w:u ô‹Ï¿Î˜út'•CQ~rss‹Ü_¥RaffFNNŽÒ¿½¦[´h3fÌ K—.ܾ}›×_ýû÷cf¦ÿGÚ³Åýå_—ÿï¶úþäÉ“äääpîÜ9þøãæÌ™CHH{öìQ&b†¼>¼†²/„Â4•7[åääTÊg‰ò&¿V­Z¥·*xmñЊ+˜5kV™öÕÎïSÞÌ/¿üRìq§›J ÄÞ½{yýõ×Ë}Üßÿçž{Nyž––FFFYYYdee‘­óëüÏóÏ·TU$©/ô¡¸Ä¾åááÁ˜1cð÷÷ÇÅÅkkk233IHH (([[[Z¶liè0…0ÒŠ§ ´jÕJi1£íÅý8FS ýGQ6nÜÈÆ©]»6¯¾ú*†qãÆéìyÆÿüóO“¯jåOÔk' }<–¢bÏß¾çñصÏÓÒÒŠüp[ÜþÆ*«mû˜Çݽ{·ÈýU*•’ìÕVu‚ö¯¢þ8Õ¾¶*›»»;K—.¥qãÆlܸ•JEDDþþþ•r>m5~qÿGù×å¯ÞïÖ­uëÖ%==³gÏ*mxÜÝÝyå•Wˆ‹‹ãÖ­[%¶áB!Ê«´ÉØš¤¨„²TŸO›€ W^3™™™ÄÅÅáããS­0cÇŽE£ÑžžÎôéÓ+t¬#GŽP·n]êׯO“&MhÑ¢vvv´oßžÎ;ãììÌóÏ?OŸ>}0`îîî>|XOWR:F’úB/¤¨L¸ººâéé‰ jµ+++œIJJb×®]†Q£"‰ý* R©”V‘‘‘:·É?ÙjïÞ½unsæÌ|}}X¶l›7oÆÅÅ…¤¤$FÅ£G í“ÿ—ò;wŠŒ1ÿºüí?žyæ¥=NQ±çÿÐúxìù'-iÿÖ­[Å`¬:uê¤|­m#ó8íÄÃEéÑ£áááú ¬Œ´“ì•àÖÓ®lù'†4h3fÌ`É’%zÖëKÇŽ¼^ûÚ6RÓÎ{Èû™ÓVx?~œ½{÷bgg‡““¯¼ò †½{÷–8q®BQ^ÆœŒ­,’Ø/SHÀÔ©S‡Õ«W£ÑhHNNf̘1†Iï4 ¾¾¾’Ôz!­xDe²°° 00ääd.\¸@TTñññ¤¤¤f2]„¨*’د"žžž@Þ$›G-´>88ÈKª»»»ZŸžžÎˆ#ÈÈÈÀÝÝY³fannÎæÍ›±±±áèÑ£,\¸°Ð~O<ñ„òÆxàÀ233uÆ÷óÏ?`nnŽƒƒƒ²¼víÚ¼üòËlݺµPuWnn.7n k×®´iÓ¦ÀzWWWš4iÀúõë ÷?þ`Ïž=Àßß#Sо}{å&Åwß}§s›M›6{ /// o¤Dq=>+³UöþÛ·oh™¤õå—_VÚ¹‹³|ùrºtéBNNcÆŒáÞ½{z=¾ö¡¬¬,¥•Õã´C»ííí †ÑVáGDD©üL»ººÒ A~üñGNž|HíÚµyûí·u~ïîܹÃùó畇vbSFS`ù¥K—tîo*•ŠþóŸ@^bÿñäþG}DDDD±Ç9r$ݺu`„ ìØ±£Ð6gÏž-v~…ŠÒŽ4ÉÍÍeÁ‚n"ìß¿ŸuëÖUÚ¹‹caaÁ7ß|ƒ••×®]câĉz=¾‹‹ ®®®@ÞëÿñQ}ô‘r3L×Ðnm²~Ë–-dff*‰}333 ÄöíÛIMM¥Y³fŶÈB!ÊÃÔ’±ú ûcŠ ˜æÍ›³gÏåo gggC‡Tf'õÃÂÂ$©/*LZñ!„ñÄ~©S§6lÀÌÌŒ³gÏÒ®];Ì /¼€»»;ÙÙÙ888°lÙ²Bû®]»–M›6affÆ×_M£F ¬5jo½õ†7Þxƒ«W¯X¿`Áåƒê—_~IÛ¶myùå—:t(vvv,Z´È› `ÕªU…Îïââ¼yóøæ›o°··ÇÓÓ“:°téRFŒ¡T˜?næÌ™J¢sÚ´itëÖ!C†Ð¶m[öíÛ@```‘mxÞÿ}:tè <´Iò¬¬¬Ëû÷ï¯sC™={6...äææâååÅóÏ?Ϙ1cèÚµ+ï¼ó/¼ðB±û«Õj¶nÝJëÖ­IMMeذa8991räH%éß¹sç"[郃ƒƒrã $${{{†Š««+ä­·Þª´s—¤cÇŽ¬X±€ÐÐPåæ˜¾¬[·Žúõë“””„³³3 `ôèÑtìØ‘wÞy€~ýú1mÚ´BûºººR«V-=z„••}ûöUÖ½òÊ+ÊÍ1©ÖBQ™L1[^’Ø/¿èèh|}}éÙ³':uÂÅÅ…±cÇfèÐôÆÉɉ“'O¢Ñh8qâD¡QÈÕ‘®¤¾)Œ@†'“ç !„ñÄ~rwwg÷îÝ´iÓ†ÔÔTvïÞMTT*• "##±µµ-°Oll,3gÎò*âûõë§óØ«W¯¦cÇŽÜ»wQ£F)‰CÈkÇÁÌ™3©[·.wïÞeÏž=ìܹ“«W¯bnnθqã8qâO=õ”ÎãðÁ`ccÃï¿ÿNXX.\ÀÒÒ’9sæ(mIt177çÇäÍ7ßD­VË?üÀ;w”ÉPµÕí¦¤víÚìÙ³‡áÇ£R©8vìß~û-qqq >\iaT{{{~ýõW&Mš„¥¥% |ÿý÷|ÿý÷ÄÆÆÒ¢E /^\©×¢T¯_½z•;wrúôifÏžÍÊ•++õÜ%ñõõeðàÁ@Þ”³gÏêíØ;v$22’^½zñèÑ#öïßÏæÍ›ùí·ß°°°`ÆŒìÚµKç_kkkºté@ß¾}±´´TÖ 4HÙGû¢:P©Tå~˜™™ÙÞBaX5![’Ø/ŸÐÐPÜÜÜHKKÃËË‹yóæáããCÓ¦MñõõeöìÙ†Qïž}öY®\¹‚F£áý÷ßòF]ÚØØÐ Aš5kF«V­h×®:t k×®<ûì³¼ð ôéÓ‡âîîNóæÍ+-FIê‹Ê¤ïV<ù¬)êûBTE±•bРA\ºt‰'NpõêU¬¬¬èÚµk‘Õê]»v寿þ*ñ¸VVVœ9s¦ÈõO<ñ«V­âƒ> ::šëׯ£ÑhhÒ¤ ÎÎÎØØØ{|•JÅܹs™6mQQQܾ}› УGB7#t±¶¶fÆ ,[¶ŒS§NñàÁš7oŽ««+æææÅî»jÕ*# Ê£¨9Jcþüù:Û çÉ'Ÿäûï¿çêÕ«DGG“››K×®]i×®PºF7fÍš5qâÄ þøã /éß½{÷J¯¨hܸ1G%::šÄÄDlllpqqQFŽu –––%^ßâÅ‹‹½1QR»"@gû)€cÇŽ»Ÿ››[‰ñuìØ‘C‡qåÊâââHOO§qãÆ¸ººòÄO»ott´Îåõë××9ѵ¾cBQs…††âííͰaÃðòòÂÖÖ–ôôtñõõ%""‚ÀÀ@C‡Y¥¤Ç~ùøûû³eË­,X€ƒƒ~~~¥ú{ÀuïÞ€*ó‚•–——W‘smU„$õEe“VŒ3†ððpå5“™™I\\>>>ØÚÚÒ²eKGY3HR_T}'ö…BT©ØB!LXݺuiß¾=™™™zŸ8S£Ñ ÑhÈÈÈÀ€sçÎéõBˆ²Ó&cýýýqqqÁÚÚšÌÌL ª‘ÉØªJì›Zc@@óçÏÇÓÓ“ÔÔTjÕªENNjµwwwvíÚeèkIꋪ$“ç !„ñŠ}!„B!LH@@®®®xzzbccƒZ­ÆÊÊ ggg’’’jd2Vzì—……$''sᢢ¢ˆ'%%…°°0Z´haèMž$õEU“ûBa<¤b_!„B¢MÆ®X±‚Ë—/“’’‚••vvvz¹c,¤OŨÕj F#I}aÒŠG!Œ‡$ö…B!„0A’Œý›$öË/::šàà`bbb”›DŽŽŽŒ9’¡C‡:<“%I}a(’ØBã!­x„B!„&Mû力›iiixyy1oÞ<|||hÚ´)¾¾¾Ìž=Û ñiçzÉÿ0…äwMMê«Tª2=DåV1é÷Ï/¿ü’¿þú‹Ã‡óôÓOsãÆ FŒ¡ŒòúôÓOyã72dãÆcÕªUdddðÁpãÆ ‚ƒƒ™5kû÷ï'%%…Å‹3zôh† Â[o½Å÷ßoÒßG!Då“ľB!„¤Iýò±°° 00ääd.\¸@TTñññ¤¤¤F‹- b¥ÊÎήôsèJêëšÓ@ˆªRRý‡2}út^ýu“~­]»6={ödíÚµœ?žS§Ny#Ο?Ï£G8rä³gÏfÔ¨Qlß¾äädÂÃÃÙ¸q#ñññܼy“U«VqãÆ ²³³ eäÈ‘|ôÑG†¹@!„IûB!„B“VU=öMQtt4ÁÁÁÄÄÄ’’‚••ŽŽŽŒ9’¡C‡:¼JÁˆ®n IDATqçÎÖ®]Ë{ï½@:u*å<’ÔÕQi'Ïýæ›o°°°`ýúõ•‘auïÞ]ùú÷ßÇÅÅ…¸¸8T*7oÞ$99™^½z±k×.ÒÒÒøõ×_éÖ­±±±lÚ´ OOO ï†È­[·HIIáîÝ»DDD0}út6oÞÌ;ï¼c¨ËB9Iì !„B!Lš´â)ŸÐÐP¼½½6l^^^ØÚÚ’žžNbb"¾¾¾DDDhè0õæÔ©S|üñÇ|ûí·deeСC–,Y¢÷sIR_TW¥MìlذOOO† R‰Öõëו¯Ÿ|òIþúë/Þxã ~øá‡B¿CþøãuçÚµk¼úê«…zõkÛö!DyHb_!„BaÒjZb?77—ýû÷Wø8þþþlÙ²EgÂyÁ‚888àç燭­m…Ïe(ÙÙÙlß¾Õ«WsäÈ ïõâááÁŒ3èß¿‘¯Ÿò’¤¾¨ÎÊ’Øxë­·¸yóf™÷3iiiÌ›7ÈKê?÷Üslݺ•;wâììÌ?ü@:uxòÉ'ÉÍÍUFéjÿ¶lÙ2Μ9ÃäÉ“ àðáüòÊ+2rL½š8²¯:‘ûB!„B“VSzìß¹s‡€€œœœ”ªÐæÍ›—ûx÷ïßÇÉÉI纆 R¯^=RSSË}|Cº{÷.þþþ´mÛ–Q£FqäÈlll˜={6‰‰‰ìܹ“HR_Ô8vvvh44 ¹¹¹\¼x‘uëÖÑ®];Ûß½{—­[·Vq”•kÙ²e¼øâ‹´lÙ’;v V«ùüóϱ²²âÑ£G¤¦¦Íœ9s %çŸzê)V¯^ÍâÅ‹¹xñ¢²ßÍ›7‰ŠŠbéÒ¥U{QBT‚ÐÐPÜÜÜHKKÃËË‹yóæáããCÓ¦MñõõeöìÙ†ÑäIžB!„¤™rýÜÜ\"""X³f Û·oW&|mÑ¢S¦Laøðáå>¶‡‡cÆŒÁß߬­­ÉÌÌ$!!   lmmiÙ²¥¾.¥Jœ>}šÕ«Wóí·ßòðáCÚ·oÏôéÓ?~c&‰}!„B!„I3Æû†ˆˆ¥:?++ ¨¼êü¢DGGLLLŒR±ïèèÈÈ‘#:th¥Ÿ¿¬´£nÞ¼ €»»;3fÌ`àÀ•ÞnG—iÓ¦‘œœ,I}Qfí‰o,7.…ÆËØGö™‚*Kì;v¬ªNUåLùÚ„é’×­B!j ckÅÄ?þX :ßÃÃI“&ñòË/S«V­*‰#44ooo† †——¶¶¶¤§§“˜˜ˆ¯¯/VI,¥Ä´iÓèÖ­¾¾¾888$íkK’úB!L1Žì3U–Øwuu­ªSU©cÇŽ™ìµ Ó%¯[!LŸÜ¼+¨¢UoBãfl‰}€ÄÄÄ*¯Îœ¿¿?[¶lÑ™^°`øùùU«Iñ:uêDDD„¡ÃàòåËÊ×’ÔQÖ÷©²~æ)îø†K—.qðàA–/_®Ül|ÜæÍ›5jT…⨠׮]cüøñ4mڔ͛7+ë¶nÝÊ'Ÿ|À!Cxûí· £ÆÎØFö™iÅ#„B!„0iÆÒcÿ7ÞàôéÓÜ»w¯Ê«óu¹ÿ>NNN:×5lØzõꑚšZ­ûÕÅ®]»æ™gž‘¤¾0*ñññtéÒ¥ÔÛ7jÔˆáÇWbDå—‘‘ÁÁƒ•çS¦LÁÍÍ €¥K— @ûöí žFÏGö™Iì !„ÂäU·ä¢jKýúõëbè0Œ3\\\°¶¶&33“„„‚‚‚°µµ5ÈHcФI.\hè0„(³²¾/®]»Ö 7 KËÒÒ’?þ777:Dll,VVVüõ×_¶»rå Ÿþ9—.]¢Y³f¼ùÿØ»ó¸¨êýñã/d•%LAr)5B)s½š†b}%ÔÌÔҌԬ\p¹¶Q byK“Ò.yCóŠKj n¸"à.†@*¢\YDÙ~ð›〢,ãûùxÌÙó9Ÿù¼çGxŸÏy^777Ο?Ï×_Ï=÷ÿú׿xì±Ç˜;w.,^¼###¦NÊÓO?­¼çŽ;X¿~=W®\ÁÉɉ &(e¶nÝÊÖ­[éÑ£·oß&22’gŸ}–K—.ñì³Ï*wB;vŒU«VáêêʤI“jè¨ qwõñÎ>C#‰}!„B!„A«¥xê‚   fÍš…¹¹¹SRR‚J¥bРADEEÕvˆB=»Ÿóâ˜1cðññyˆÑèψ#øñÇIKK㫯¾ÂÌÌŒaƱzõjeŸC‡Ñ»woÊÊÊèÙ³'ÑÑÑ|óÍ7üú민øâ‹\¼x‘ÐÐP7nLYYFFFäååÍÅ‹Q©TdggEJJ Mš4á‹/¾`úôé4lØGGGÖ­[Ç’%KصkÏ=÷ 44”ˆˆÒÓÓ122¢{÷î,Y²„ˆˆ^~ùeT*K—.%,,ŒÅ‹×âQB›ÜÙWû*¿'U!„B! „$öŒ™™!!!\¿~³gÏËñãÇÉÉÉaÆ ØÛÛ×vˆB=«îyñ•W^á‡~xÈÑèÏäÉ“)))aΜ9üúë¯øùùѬY3­}(,,dÙ²elß¾7RRRÂŒ3´ö+((ààÁƒ>|€3gÎ̵k×°··çúõëÄÅÅqëÖ-æÎ Ào¿ýÆ©S§˜;w.·oßfΜ9Zï™——ÇÑ£G¹}û6o½õ ==M›6QTTÄúõë155åÕW_}ˆGéá322º¯‡¨Û4wöíܹ“ÜÜ\ ILLdüøñrg_ ľB!„ ՗ûu•J¥ÂÅÅwww:uꄹ¹ym‡$„xHîu^455eÉ’%üç?ÿ©W‰×®]»òÜsÏNqq1ï¼óŽÎ>‰‰‰¼þúëñÜsÏpöìYnݺ¥ìתU+:vìH«V­”m/¼ð*• [[[²²²8þ<·nÝÂÌÌŒ^½zàååÀ‰'´Æÿüs>ûì3.]º„‰‰ Íš5SþéÓ§Öû5lØPçýãããµ^·lÙ’¨¨( ¹ví-Z´ÐJÐøá‡|øá‡•ÆgaaAÛ¶mILL¬×ex„á’ µOJñ!„B! šÔØ0ÞÞÞŒ9’;w’›› @aa!‰‰‰Œ?+++j9J!„>RbÿAaoo]•†ïWÆ qpp¨ö¬ûÅ‹ãêêJBB¯¾ú*íÚµÓKBèSu'ˆ‡GûB!„Bƒ&¥xLPPøøø`aaJ¥B­VãææFff&QQQµ¢¢É9³æ´lÙ///BCCY¾|ym‡#D¥d@í“R|8ǯí0„¸«   fÍš…¹¹¹SRR‚J¥bРA2 Hb_!„BaФÆþߣR©pqq©í0„µLΙBˆŠd@퓾B!„¤ªÙé2©±/„Õ#5ö…÷K&ÔIì !„B! š”âBˆê‘ľâ~ÄÅÅF||¼2cßÅÅ___†ZÛáIIIøûûMHHHm‡iÐ$±_K’’’¸páææætèÐÇ{¬FÆ-++ãܹs¤¥¥QZZJ‹-èСÆÆÆÕê_RRBbb"4mÚ”§žz 33³jŸ——ÇñãǹqãööötèСÆoÏÊÊ",,ŒØØX²²²”[°/^L—.]îÙ×®]DDDpá èÒ¥ ‹/~h1×…ãVÞ}÷]âããñôôäŸÿügm‡#„BˆzJjì !DõÈŒ}!DuÁÀuÚpvvfþüùXYYÕBtIì×°ØØX&MšDBB‚²ÍÔÔ”#FŠ¥¥åC{ÅŠ|ú駤¦¦jm·±±aÚ´i̘1•ªêo‰ï¿ÿž¹sç’žž®l³¶¶fúôéÌœ9³Ê?˜nݺÅìÙ³Y¶lùùùÊö¶mÛ‚··w•}¯^½Êþýû•GBBEEE4lØìììê|tÅ•+WèÞ½;iii:mÕy¯Ï>ûŒ9sæÜטÇß9n† >>ž˜˜š7o^Û¡!„¢“ûBñ÷Ib_QQvv6®®®•¶ÙØØ`iiInn®$ö"Iì× Ý»wÓ¯_?ŠŠŠ033ÃÍͬ¬,NŸ>ͪU«HHH`ß¾}eåè>ø€E‹иqcž|òILMM9~ü8™™™Ì™3‡#GްnݺJû/X°€€€š6mJÇŽ9þ<—/_föìÙ\¸påË—WÚ·´´”aƱeËÚ´iƒƒƒñññüñÇ 2„ððpFUiÿnݺé\ŒxPŸ|ò iii4mÚ”   ž|òILLLh×®Ý]û¦§§3þ||}}™8q¢r§EãÆõ_E÷¸ !„BˆrRŠG!ªGfì !ªËÛÛ›‘#Gˆ»»;Mš4¡°°sçΊ••µ¦A«zŠµÐ«Û·oóꫯRTTDÛ¶m9sæ ûöíãÔ©S¬^½š ϼyóô>öÑ£G•¤~Ïž=ùã?Ø¿?ÑÑѤ¥¥1räHÖ¯_Odd¤Nÿ'N(³Ô‡ BZZ111¤¦¦2eʾûî;6nÜXéøË–-S’Ó$''³{÷nRSSéÑ£&L ##£ÊÏ`jjЇ‡ï½÷½{÷~À#Û·o`Ê”)Œ7wwwºtéB—.]ߵkÅÅŨÕjV­Z…§§§Ò÷^„>Ž›B!„ľBT—$ö…Õ„‡‡>>>XXX R©P«Õ¸¹¹‘™™ITTTm‡hð$±_Cþýïó矰|ùrÚ´i£´1‚qãÆðí·ß’••¥×±ùååù²e˰µµU^7jÔˆo¿ý–FT:cáÂ…”––biiÉ?ü ÜQ R©X´hO<ñP^¦æNeee,X°(¿¨0{ölå+kkkÂÃÃ111¡   Êõ¿þú+7nÜ 66Vk¼¡)#Ô¶mÛîÛ²eK6løÀ1T‡>Ž›B!„('5ö…B!ôËÌÌŒ®_¿ÎÙ³g‰åøñãäää°aÃìíík;Dƒ'¥xjˆ&aîää„§§§Nû„ X±blÙ²E™EpøðaJJJhÖ¬Y• é²²2:DYYvvv8::*m—/_ÀÜÜœöíÛëômÒ¤ ...;vŒK—.iµ+3ñ_~ùeE~U*ãÆcÆŒ8p€K—.ѲeK¥ýÈ‘#J=û7ß|Sgì6mÚп6oÞLdd$Ÿþ¹Î>ÕYж*'Ož$77Wy}ûöm.\¸À´öíСÊ뜜NŸ>­¼NNN ¨¨H§¯……:t¨2Žììl¶mÛÆ™3g(((ÀÞÞžàìì\éþú8núžžNFFjµºÊºiñññJL릕••qðàA\]]±¶¶æüùóDEE‘žžŽ­­-C† ©òTÇõë×9wîöööZÿih¾ö?þ8­[·æúõë¬[·Žääd6lHß¾}éÙ³ç=Ç(((`Û¶m?~œ¼¼<ìììèÕ«Ï<óŒÎ¾‡¢´´—j/ˆ}îÜ9®_¿®õ󭝨…BQNjì !DõÈŒ}!ÄýR©T¸¸¸Ôv$Iì×€²²2vïÞ Pe7775jD~~>ÑÑÑZ‰ýÍ›7óá‡Ò¤IâããqrrÒéÌÌ™3iذ¡NÒY“h¿}û6EEEJMùŠòòò´öÕˆ'''ç®±÷êÕKy£{LLŒòüný7oÞLRR’Î…¿küøñJr¹¢yóæé”=Úµk}úôQ^ÇÆÆò /èôMMMåÙgŸÕÚÖ»wo¢££+!88˜?þX9ÆFFFŒ7Ž¥K—bff¦ÕVÛÇM#44”… Ò¹sg%§®]»ðŸÿü???eû­[·”ã´~ýz<ÈÂ… µ~œ5k_}õo½õÖ}ÇvñâE<==IJJÂÍÍß~ûM«]óµŸ:u*={öd̘1Z ÏŸ?Ÿ×^{~ø¡ÊY|7nd„ \¹rE§­wïÞüôÓOZÇ}ìØ±œ:uŠ 0sæÌj}___øä“O˜;w®ÞbB!Ä_¤Bü}rÎBÜ)..ް°0%¨V«qqqÁ××—¡C‡ÖvxOû5àÒ¥KJR·²óP~{°««+qqqœ9sF«mÞ¼yìÞ½›;w2bÄöîÝ«•œ?|ø°’ ¥sçÎZý‡ Æ‚ (..fË–- 2D«ýÔ©SÊlô;è*ÆRUìgªß»æµ¹¹9­Zµºgÿ³gÏê5AýÒK/iÍø_±b%%%ôë×Oçî‡-Zh½nÕª'NT^ÇÇÇsðàA¬¬¬xå•W´ö­êÊä¤I“øöÛoèÑ£ƒF­VsäÈÖ¬YCXXYYY:kÔöqÓ·eË–ñÛo¿áííM×®]¹xñ"kÖ¬!//)S¦Ð¯_¿ûZ§àÂ… xzz’’’B=ؼy³ÖÝ%&&òÍ7ßðÔSO1`ÀrssùïÿKJJ ?þø#žžžŒ3F§ßŽ;x饗(..ÆÁÁÑ£GckkKBBáááÄÄÄЧOŽ;¦¬ÏУGN:Å¡C‡ªõ9 8yò$Ï?ÿ¼ÞbB!„6Iì !DõÈŒ}!DuEFF2vìX† †ŸŸVVVäçç“””„¿¿?ÑÑÑ„„„Ôv˜Mû5@S[´“Ç'NœÀÎÎŽfÍšðøã(%X44hÀO?ýD—.]8tèsæÌ!((€ÜÜ\FŒAQQ~~~L˜0Ag|www¦OŸNPPãÇ'88///LLL8xð |ð%%%¼üòË >üž±qüøqÚ·oZ­¦I“&4nܘ¼¼<Ø5ý+~.\¸@çÎ122R>weŸýïš1c†Öë•+WRRRÂøñãµf—W¦C‡JR`Á‚>>J[m7}Ûºu+kÖ¬Á××WÙöÎ;ïàææFQQ?þø#üqµÞëܹsxyyqñâE¼¼¼Ø°aƒ²FDevíÚÅÛo¿Í×_­üQÿÑGáææFrr2aaa:ÉñÒÒR&NœHqq1;vdß¾}XZZ*í£GæÿøçÏŸ'00P)…ôüóÏóÝwßUz—HeŽ=Jqq1&&&tïÞ]/± !„B—ÔØBˆê‘󢢺‰ˆˆ`àÀ:m8;;3þ|­²ÍB¿¤†C ¨X‚E3³÷£>âÉ'ŸÄÉÉI)q¢i»³d @óæÍY½z5 4à‹/¾`ûöí@ùŒð?þøggg–/_^e .dõêÕ8880vìXZµjÅã?Ž¥¥¥„††¡3›©²ØÿñàææF×®]•ò šÄê±k^kúfddàêêJ×®]=z´V[UŸ½¾Ò$ªûöí«“Ôðòòâå—_Êg´WdhÇ­ÿþZI}(_;¡ÿþ@ù]'ÕqòäIz÷îÍÅ‹yñÅÙ´iÓ]“ú–––k}o[YY)k=zTç—×ßÿ]¹‹å‹/¾ÐJêCù×TSrêûï¿§¤¤(Ÿ±åwéT\¯¢¤¤„ììl­õåÀÓO?Z­ÖKìB!„Ð%5ö…âï“¿=„eggW¹£ –––:y¡_’د………ÊsSSS |67”'d7mÚ¤ÕvóæÍJßÇÓÓ“¹sçRVVÆk¯½Æ_|ÁO?ý„™™4iÒ¤Êrss9|ø0/^Ôi»zõ*ÇŽSÙ½[ì™™™J-ù³gÏ*%ªŠ]Ó_Ó¾gÏ222ˆˆˆ ¬¬Li»Ûg¯oþøãNœ8”×K¯Ê€Ø·oŸÖ/I†vÜ*»z •0Ò|¶»9vì}úôáÊ•+ >œuëÖé¬MP™^½zann^åØ:ÿÑhÖ8hܸ1ýúõ«ô}‡ ”ÿühJ'µmÛV¹“¢â¬ýµk×bmmMË–-)**R¶kö©j!܉]!„º¤BT”âBT—··7#GŽdçÎJn¢°°ÄÄDÆ••µ¥a“Ä~ ¨˜|¼}û6#FŒÊgßjjÞkÚ*›¹«1þ|úöíË•+W˜>}:!!!Zuäïô¿ÿý矞š4iºuë¸rå ÿûßÿضmíÚµcåÊ•tëÖÓ§Oß5v%Ñùä“O* §V»¦¿¦½gÏžJ-ø×^{ ###¥í^Ÿ½>‰‹‹Sž§¦¦²råÊJçÎÊ/¼dgg+} í¸ÙÛÛWºý±Çî}aâôéÓxzz’™™ ”ÿüT¶ôƒŒ]Ùøš¯‹««+*UåËî\ã@C3k¿bb_³°onn.ûöíS¶kö©¬¾þƒÆ.„B]’ØBˆ¿OΙBˆŠ‚‚‚ðððÀÇÇ T*jµ777233‰ŠŠªí žÔدK…hJ×Ì™3‡Ñ£Gcmm­Ì´/((ÐÙÿN 4à»ï¾ÃÙÙ™²²2ºuëÆ¤I“î:þ¼yóHLLD­V³cÇ•¶þýûƒ««+ééé¼ýöÛìÚµ«ÊØ---ùí·ßHNN¦uëÖJrµªØ5¯5ŸÛÎÎŽsçÎqåÊœœœ´úÞë³×'ÿûßÿ”çsæÌ©VŸ7n`mm Þq«xwAeîõ bbb"P¾æÀåË—yóÍ7éÖ­[µ ¾Åó]² IDATר•¯¹Èr·:p𝔝 Ñ£G~ùå­Äþ¶mÛèÔ©'Nœ`ëÖ­ôéÓ‡ôôte-ÍÅ}Ä.„B]Rc_!ªG΋Bˆê233#$$„àà`’““ÉÉÉA­VãääTiõ¡’دgݦ§§+Ï[µj¥µŸ¦­ªYºŸ~ú©òŸíáÇٺuk•¥N ¼t À Aƒ´’úŒ;–Ï?ÿœèèh®^½Š­­m¥±·hÑ‚ Ю];e{~~¾rËͱk^WüÜæææJrúζ{}öú¢â_~ùe•³Ä*ª˜(~TÛÝÌ™3‡)S¦ðÔSO‘‘‘Á«¯¾Êï¿ÿ^åꇱ±1p÷º»Û4ûÃ_³ï9BII §OŸæòåË|ðÁ¬ZµŠ­[·* 1<ñÄØØØèý3!„â/Rc_!ªGJñ!îG\\aaaÄÇÇ+‰}|}}:thm‡gð$±_Zµj…Z­ææÍ›J-î;•••i•ÿ¨Š¦„‹©©)/¾ø"ëÖ­côèÑ;v¬Òänvv¶2{¼bRøNõÉÉÉJb¿b,gΜÁÍÍM§oÅò=wÆ®y——Ç¥K—*a}·þõ•æøAy霦M›ÞWÿºrÜ4Wõ \Å;¦Aƒñé§Ÿå?ƒ "::šÀÀ@æÍ›§÷ñ4Y®]»Vå>Û*^”éÒ¥ 5"??Ÿ“'O* ]4ˆÌÌL>ÿüs®\¹rÏ2>>´oß^©{>|øpüüü*ýìS§NUï¼ó]ºtaÈ!8::*õÇCBBª,'óÙgŸÑ¾}{å±fÍ |6uÅí^^^•ö¯-½zõbñâűfÍðòòbÔ¨Q :”¶mÛÒ¾}{-ZD^^žNÿ¿{ÜôÁÙÙYY˜yÕªU´mÛ–¡C‡âááAÿþýyã7ÚØ÷Ò±cG‚ƒƒòºnš‹cú²bÅ ¬­­ÉÌÌÄÍÍ~ýú1bÄ:vìÈûï¿€§§'ï¼óŽN_Œ)..F­VÓ·o_¥mðàÁÊÅ1™­/„BÔ )Å#„¨¯"##éÓ§yyyøùù1sæLÆOóæÍñ÷÷gÚ´izOûBˆê ÂÃÃ,,,P©T¨ÕjÜÜÜÈÌÌ$**ª¶C4x²xn 4h›6mbÒ¤I¤¤¤°iÓ& ü_|‘ï¾û+++­> L:(ŸïééYé{/Y²„ØØXNž<É+¯¼Âž={011ÊËñDGG3wî\V¬XÁµk×”2.P^~ÇÏÏ/¾ø¢Ò»>ÿüsš6mʧŸ~ÊŸþÉŸþ @Æ yçw ¬òs›˜˜°yóf¦L™Bxx8 Ê,[[[‚‚‚3fLua½3yòdÚ·oÏìÙ³9|ø0;wîÔj·±±ÁÛÛ›Q£Féô­+ÇmÕªU :”ššJjj*¦¦¦L›6… ²dÉ’‡CUüýýÙºu+QQQL›6çŸ^«ÞýßѱcGöìÙäI“سg¿ÿþ»ÒfffÆÄ‰Y°`ÆÆÆ:}›4iÂSO=űcÇèÛ·/ 6TÚˆ±±1%%%’ØB!jˆ$ö…õ•¦†µfÂUE8;;3þ|\ÂÃð ç̪οBˆúÏÌÌŒ‚ƒƒINN&''µZ“““²f£x¸Œ²²²êo³¤{÷î5òŸLm8pà€R²£ºJKK9|ø0©©©¨Õj:wî\c‹ÆÞ¼y“¸¸8.^¼HYYvvv¸¹¹aaaQíþ±±±dddдiSºuëv__ÛŒŒ Ž=Ê7hÙ²%ÊC÷çŸrüøq²²²077ÇÉɉN:U𾓾Ûý~ß–••GRR¸»»ëÜ9bÈ.\¸@bb"ùùùØÚÚâááAãÆk;,!îJós¾cÇÚ·oOaa¡Þ¹*++£¬¬Œ‚‚ÌÌÌ8}ú´²€tmرc‡ÖÚ#¿ÿþ;^^^Z‹É Q“4 ê&CîwQ=Çç—_~ÑÙÁðáÃïûý ýBÁƒ~ޫ߃7C?Þâáªéóð3Ï”ÿûÿ—Ôºïö;ãpttä÷ßÇÑѱÒýÚ´iÞ={”rUÅ_ÝŸ£íÛ·+kŽÝiÍš5øúúÞ=ð{Œ' K]9Ëï[5ëaýžPíÛ·çž{ø+nÍßÁwn«î¿wnÓ—ÒÒRbcc•Š$¿þú+ýúõ«2>ù+·4hЀîÝ»×JâC­V+uÓ´Uw T‡]¥‹? ¸¶Xm7###ÜÜÜ”’NGGÇ*‘B!DÝ'5ö…õ•¦†u`` îîî4iÒ„ÂÂBÎ;Ghhh­a]ŸwBˆGXXñññÊŒ}|}}:thm‡gð¤Æ¾B!„ Ɍoñ¨KII!%%…’’’‡:ÎÍ›7IIIáÒ¥KuœGIM×°–ûBˆêªé5@„.™±/„B!„0h’ØõÍž={˜7o-Z´`õêÕ@y9€9sæ`ddDTT5"##ƒW^y… °yóf­µ*ÒÜ}šžžNóæÍ‰‰‰áرctíÚ•Þ½{ë-^xá\]]9sæÌ=÷¿uëß|ó “&MRJû‰¿Ô¥ÖrÎBTT—ÖyTIb_!„BaÐ4¨üFeIR‰ºÊÑÑ‘˜˜–,Y‚ [¶lQ¶8p///öìÙCLL ;v¬2©0qâD%¼~ýzBCC™:uª^û÷ëæÍ›ÊŒÎ×_]ûw¡R©pqqyèãÈŒ}!DueggãêêZi› –––äææJbÿ!’ľB!„ I}QߨÛÛãèèÈ… Ø·oC‡eïÞ½<þøã¤§§³wï^¼¼¼Ø»w/Ï?ÿ<_ý5çÏŸÇÏÏ;vpðàA”¤¿‘‘k×®U.ÄÄÄðî»ïÒ¾}{&NœHii)áááÄÄÄPPP@÷îÝyûí·155­4β²2–.]Jtt4íÚµãé§ŸÖjÏÉÉ!$$„³gÏ’ŸŸ­­- àÿþïÿÈËË# @Ù7 333¦M›F^^ßÿ=iiiáààÀk¯½†»»»Þu}P“5¬ëjò^ã­Yuõû@Ô-õu C"5ö…B!„MJñˆú¨gÏž@yYžÛ·osèÐ!† B»víØ³gÒVqß_~ù…ÐÐP^zé%æÍ›Ç¦M›((( 44”ÐÐPòóó‰åÔ©Sœ:uŠ•+W²}ûv†Θ1cØ·o)))L›6¾}ûVY›úôéLž<™7²fÍ&Mš¤ÕžžžÎâÅ‹¹téEEEDFFâëëË—_~ÉÍ›7•2C«W¯fåÊ•\»v={ö°víZ²³³ÉÉÉaÙ²exxxpèÐ!=áú¡.Õ°–s¦¢¢š^Dè’ûB!„Bƒ&‰ý#3dkWÏž=ùñÇÙ»w/GåæÍ›ôìÙ“[·n±víZ²²²HHHþš±¯Ñ¢E Ž;F£FtfÛùå—”––ʤI“X¼x1P~‘`ݺu8;;sâÄ T* `Û¶mJB¾¢üü|¾úê+¢¢¢èß¿?þþþüë_ÿRöqttäÊ•+äääpíÚ5¢££™©©©X[[ššª”kpqqaüøñdddpýúu¾üòKV­ZÅÚµkéÖ­›rÝWÓ5¬ëz)žºƒ!“ó¾¸ui G•$ö…B!„Mjì‹úH3 ?..Ž­[·*Û Y¹r%K—.¥¤¤{{{Z·n­Õ÷Í7ßÄÎÎî¾ÆKLL )) ­¶„„Ä~rr2·oߦAƒxyyп­Ä~ZZ/½ô'NœÐê{éÒ¥»Æ²sçN&MšÄ•+W!ªK5¬åœ)„¨LM­"tI)!„B!„A“û÷§¬¬ìo=„~¸ººbggGQQß|ó ­[·¦U«VÊìü%K–]¨ÈÒÒò®ï]ÙÅ®fÍšЩS'Ö¯_¯õðóóÓÙ_3Ó¾´´”ÌÌL®^½ªµÏ‚ 8qâ'N$''‡M›6)}ªŠàý÷ßçÊ•+¬\¹’üü|fΜ©ÕïQ¢©a½sçNrss(,,$11‘ñãÇ뽆µü !îG\\þþþôèуN:áîîΨQ£Ø°aCm‡öHľB!„ I)Q_i’ø×®]Sø®®®ØÚÚríÚ5­}îG‹-€ò:óçÏgÇŽxyyakkËéÓ§IJJÂÊÊŠììl¾ûî;²²²tÞÃÞÞž®]»ðú믳lÙ2µö)..ÊkíÇÆÆòé§Ÿjµ[XXиqc¦M›Æ‡~Hqq±Ò/))‰­[·²råÊûþŒ†¢¦kX×õR¢¸¸˜àà`ÌÍÍ dÚ´iJ©ŸG‘¦†õõë×9{ö,±±±?~œœœ6lØ€½½}Å"ç8!DEš5@V­ZÅäÉ“=z4o½õ‹-">>ž•+W’]Ûa4©±/„B!„0hRcß05 kkk‚ƒƒ;vl•_çúlêÔ©L:Ugûºuë*Ý?::ºÒíw~¯7kÖŒ˜˜ýÜÝÝ9räyyydffbkk{ן|òIþøãþüóOš5kFÆ µjìwèÐ .pñâElmmQ«ÕJ ! &0a­m¾¾¾x{{“‘‘ƒƒÆÆÆüôÓOUÆaèâââ #>>^YœÒÅÅ___†ª×±dƾ¢ºêÒ *ÃûÍG!„B!*û†+++‹7Þxƒ!C†póæÍÚÇ`4nܘ6mÚÜ5©_‘ƒƒ 6¬´ÍØØ˜Ö­[£V«ï+µZM›6m066¾¯~†FJ]!ꪚ^Dè’ûB!„Bƒ&5ö ߦM›ðööfÓ¦M˜™™Õv8Bè¦ÔÅÀuÚpvvfþüùz›+3ö…ÕĬY³ðññ!77cccJJJP©T 4Hïk€]2c_!„BaÐ$±ÿhøý÷ß™={vm‡!„^U·Ô…¾Hb_[JJ )))”””TkÿÂÂBRRR¸téÒCŽLו+WHII1øµGDÝQ—ÖyTIb_!„BaФÆþ£ãË/¿dÏž=µ†zS—J]ÔÕsæÇLŸ>}”Ç!C˜1c©©©û½qttäÚµkÕÚÿÀ8::ÖÊ‚Ï~~~8::²qãÆ[<ÚT*...¸»»Ó©S§j—qŸ$ö…B!„Mjì×oeeeÊãÚµkìÝ»—Y³fUY{ýã?®á…Ð5~<ÄÅ=x»FPPøøø`aaJ¥B­VãææFff¦ÞK]ÔÕäýÝœ:uŠ˜˜Ž=JJJ Û·o'88˜®]»’––ö·Þ{âĉLœ8Q•Bˆ:Ijì !„B! š”â1666ØØØÐ£G D¯^½töÙ±cgÏž­²|‰5!!Þz ¦O‡áÃï¿]CSê"88˜äädrrrP«Õ899Õx²¹®Ÿ3GÅ·ß~Kff&íÛ·'33“µk×òþûïSZZJxx8111н{wÞ~ûmLMMøúë¯9þ<~~~ìØ±ƒƒ¦, ­ùD³ßðáÃÙ¾};ǧ[·n¼÷Þ{˜˜˜hÅsèÐ!¾þúk&MšÄ³Ï>«´ÅÄİvíZÒÓÓyâ‰'˜2e vvvwåèÑ£lذŒŒ LLLpvvæí·ß¦eË–•œœ–.]J||<ÅÅÅ888àããCß¾}õ{à…µFûB!„Bƒ&‰ýº­ª¯ÏßñÄOèý=Å£åï|_6h`ޥ勴n½œ ñÚkORXx¦Úí•Ñ”ºxØñB}kkk5jDff&7oÞ`øðá¬[·WWW¬­­ùùçŸY»v-»wïÆØØ˜_~ù…˜˜"""HOOÇÈȈ‚‚BCC˜5kMš4Qöû÷¿ÿMãÆ¹víëÖ­ãøñㄇ‡+1\¾|™¾}ûbbbBNN¿þú+)))<öØc,Y²„©S§Ò¬Y3:wîLpp0Ë–-#>>{{û*cùñÇ9~ü8¤¥¥±víZV®\ÉéÓ§±°°Ð9o½õ?ÿü3Ï<ó VVV¬[·ŽœœIì a@¤B!„ I}!DM*-- ++‚‹g`d¤ÂÎnú}µß)..zôèA§NpwwgÔ¨QlذAï±×çÄþŽ;ðóóÃÍÍÔÔTT*ƒfÏž=¬[·gggNœ8All,ÿøÇ?Ø¿?‘‘‘ZïÑ¢E ®\¹Â7hÑ¢E•c 8ÔÔT:„‘‘«W¯Ö*û“——ÇÎ;¹zõ*äæærèÐ!nݺŬY³022âàÁƒlß¾>úˆÿýï|öÙgwå›o¾áÈ‘#,]º”ï¿ÿžŽ;rùòå*×9qâ .díÚµüùçŸ,\¸ðA¯¢’ľB!„ I}!DmÈÍý€Fܨ 22’>}ú——‡ŸŸ3gÎdüøñ4oÞ¦M›¦ÿÀ«P×û)))üúë¯\¾|™ž={²qãFºvíJbb"III˜˜˜`ddĶmÛHHHÐz7ß|;;;7n¬”é©LÿþýèÔ©¶¶¶”••qîÜ9¥½U«VtïÞSSSÚ´i@vv6çÏŸçæÍ›”••áää„‘‘³gÏ®V,_~ù%=ömÛ¶¥K—.œ/¾ñÆ|ûí·:Û›5k”'á?ùä­¶¶mÛj½¶´´¬ÖXW¯^àÖ­[ܸq(/”››  Ôæí»Æ4±¨T*~þùg­EÀï»âë?ÿü“O>ùsssqvvÆÓÓ“ØØØ*/RϘ1ƒaƱÿ~Ž9Â×_Ío¼¯¯o•w² !ê—Kì{xxÔÔP5êÀûÙ„á’ï[! Ÿ\¼Bˆ¿Hb_Qš4ñ ?ÿèµCù,廒¶±±ÁÒÒ’ÜÜ\½%ö料ž3½¼¼°µµåôéÓ$%%áîîNJJ k×®eæÌ™ôž‹-¢qãÆìÛ·›7oÒºukž|òIöïß×~¶¶¶xyyñû￳qãFÆŒCff&Û·oÇÙÙ¹Êú÷ÅÅÅÊ¿Çg×®]víÚáììL£FX¶leeeõöë(„Ð%‹ç !„B! šÔØBÔ¤ ai9{û ÊÊŠÉȾ¯öм½½9r$¸»»Ó¤I 9wî¡¡¡XYYáàà ·Øësýª4mÚ”¨¨(&MšÄŒ3€ò ¾;wÆÖÖöÞsÈ!|øá‡\»væÍ›óÓO?ݵtOEááá¼óÎ;„‡‡³jÕ*Z·n­”÷©Œ££#ï½÷!!!Œ5Š^½zѽ{wbcc«ìsñâEBBB())à±Ç#((Hë.!Dý&‰}!„B!„A“ûuƒ¾“‚{öì¡W¯^•¶9s¦ÊYÎâÑRÕÏÿ½<è÷ë3Ïüõ¼A˜>†?]ív MÜAAAÌš5 rss166¦¤¤•JÅ AƒˆŠŠÒküõ1±ÿóÏ?óóÏ?ßuwwwŽ9B^^™™™ØÚÚbnn®´GGGWÚ¯ªÏìååÅ¿þõ/ÒÓÓqppP¾^}úôÑésç{7oÞœ_~ù…¢¢".]º„¥¥%ÖÖÖ÷ŒeÑ¢EÌ;—‚‚Z¶l©Ó~g¿ÿüç?|ÿý÷ddd R©hÞ¼9*•¤…0$ò-„B!„0hRŠÇpdffræÌ6mÚDpp峜ûõë'I}Që:wxúék×033#$$„àà`’““ÉÉÉA­Vãä䤕˜ÕÓ¸qc7n¬—÷211¡U«V«¿faÝê²¶¶Öºp/jµú¾ÇBÔ’ØB!„B4Iì×o÷;ãúŸÿüçCŠDˆê û{íwR©T¸¸¸}úЩS§ÚE!$±/„B!„0lRcÿÑñÞ{ïѳgÏÚC½Š‹‹#,,Œøøxeƾ‹‹ ¾¾¾ :´Æâsfyb_!ê Iì !„B! šÔØ4xyyñÙgŸÕvBèUdd$cÇŽeذaøùùaeeE~~>IIIøûûMHHˆÞÆ“ûBQHb_!„BaФá>^I컸¸àëëËСCõ:–”âBˆúCûB!„Bƒ&5ö…õUdd$cÇŽeذaøùùaeeE~~>IIIøûûMHHHÄ"çL!„¨[$±/„B!ÙÖü IDAT„0hRc_Q_ÁÀuÚpvvfþüùXYYée¼º>c¿ªó¹B<Šdñ\!„B!„A“R´±W¬XÁ§Ÿ~JjjªÖv¦M›ÆŒ3P©ªþ–øþûï™;w.éééÊ6kkk¦OŸÎÌ™3«üƒ àÖ­[Ìž=›eË–‘ŸŸ¯loÛ¶-!!!x{{WÙ÷êÕ«ìß¿_y$$$PTTDÆ ÉÎήÎGW\¹r…îÝ»“––¦ÓV÷úì³Ï˜3gÎ}©O………<ýôÓ$''ðÝwß1zôèZ‹ça‹'&&†æÍ›×v(B!„¨Ç¤Æ¾¢¾233#$$„àà`’““ÉÉÉA­Vãä䄹¹¹ÞÇ«ë5ö…BüEû5h÷îÝôë×¢¢"ÌÌÌpss#++‹Ó§O³jÕ*Ø·oßCùÏùƒ>`Ñ¢E4nܘ'Ÿ|SSSŽ?Nff&sæÌáÈ‘#¬[·®Òþ , €¦M›Ò±cGΟ?ÏåË—™={6.\`ùòå•ö---eذalÙ²€6mÚààà@||<üñC† !<<œQ£FUÚ¿[·n:#Ô'Ÿ|BZZM›6%((ˆ'Ÿ|Úµkw×¾éééÌŸ?___&Nœ¨ÜiѸqc½Äw/}ô§OŸV^—””ÔȸB!„õ™”âBÔw*• —‡>Ž$ö…¢þû5äöíÛ¼úê«Ѷm[Μ9þ}û8uê«W¯¦AƒÄÇÇ3oÞ<½}ôèQ%©ß³gOþøãöïßOtt4iiiŒ9€õëשÓÿĉÊ,õ!C†––FLL ©©©L™2(Ÿ9¾qãÆJÇ_¶l™’Ô $99™Ý»w“ššJ=˜0aU~SSS<<‹‹‹Ãßߟ=zЩS'ÜÝÝ5j6l¨íÐjŒ‘‘‘ÕYж*'Ož$77Wy}ûöm.\¸À´öíСÊ뜜­²7šºöEEE:}-,,èСC•qdgg³mÛ6Μ9CAAööö 0ggçj}Ž¥K—rðàA&OžLçΫÕGÒÓÓÉÈÈ@­VãêêZé>ñññ@ù×ÒÊÊJÙ^VVÆÁƒpuuÅÚÚšóçÏEzz:¶¶¶ 2¤ÚÇ 2ׯ_çܹsØÛÛcoo¯´i¾ö?þ8­[·æúõë¬[·Žääd6lHß¾}éÙ³ç=Ç(((`Û¶m?~œ¼¼<ìììèÕ«Ï<óŒÎ¾‡¢´´—j/ˆ}îÜ9®_¿®õ󭝨…BQNjì !ê«ÀÀ@"""8p N[@@ÎÎÎÌŸ?_ëo±‡¥.$öëB †Lfë Q¿Hb¿”••±{÷n€*Ëȸ¹¹Ñ¨Q#òó󉎎ÖJìoÞ¼™?ü&Mš“““Nÿàà`fΜIÆ u’ΚDûíÛ·)**RjÊW”——§µ¯F||<999w½W¯^Ê󘘭Øcbb”çwë¿yóf’’’t. ü]ãÇW’ËÍ›7O§ìÑ®]»èÓ§ò:66–^xA§ojj*Ï>û¬Ö¶Þ½{]i ÁÁÁ|üñÇÊ1Ö022bܸq,]º33³*?ÃÅ‹™3g¶¶¶|üñÇ\¹r¥Ê}õ-44”… Ò¹sg%§®]»ðŸÿü???eû­[·”ã´~ýz<ÈÂ… µ~›5k_}õo½õÖ}ÇvñâE<==IJJÂÍÍß~ûM«]óµŸ:u*={öd̘1Z 7ÏŸ?Ÿ×^{~ø¡ÊY|7nd„ •óÞ½{óÓO?i}¿Ž;–S§N±`ÁfΜY­ÏáëëKBBŸ|ò sçÎÕ[ìB!„ø‹”âBÔWÙÙÙUN²²±±ÁÒÒ’ÜÜ\½%öeƾBÔ’د—.]R’º•͘‡òÛƒ]]]‰‹‹ãÌ™3ZmóæÍc÷îÝìܹ“#F°wï^­äüáÇ•„`hh¨ÎŒîaƱ`ÁŠ‹‹Ù²e C† Ñj?uê”2}èСZmc©*öŠ3ÕïŒ]óÚÜÜœV­ZݳÿÙ³gõšØ饗´fü¯X±‚’’úõë§s÷C‹-´^·jÕŠ‰'*¯ããã9xð VVV¼òÊ+ZûVµˆÑ¤I“øöÛoèÑ£ƒF­VsäÈÖ¬YCXXYYY•®m áïïOnn._}õVVV5šØ×—eË–ñÛo¿áííM×®]¹xñ"kÖ¬!//)S¦Ð¯_¿ûZ§àÂ… xzz’’’B=ؼy³ÖÝ%&&òÍ7ßðÔSO1`ÀrssùïÿKJJ ?þø#žžžŒ3F§ßŽ;x饗(..ÆÁÁÑ£GckkKBBáááÄÄÄЧOŽ;¦¬ÏУGN:Å¡C‡ªõ9 8yò$Ï?ÿ¼ÞbB!„6Iì !ê+oooFŽI`` îîî4iÒ„ÂÂBÎ;Ghh(VVVz]‡M΋Bˆê’;h'Oœ8Íš5àñÇPJ×h4hЀŸ~ú‰.]ºpèÐ!æÌ™CPP¹¹¹Œ1‚¢¢"üüþ{÷SþÿüÕ½IQëQTHîIdY_•vIë¾n».ëήûe±.–¬Ýïº.¾ø®ëº,²"JB®[XÚˆŠI‰šæ÷Çüæ|›f¦¦L3Íôz>ó¨9Ÿó9çsfšOsÞçsÞŸ=z´Âþ½¼¼0}út„„„à‹/¾ÀÊ•+áçç333ÄÄÄ`Ú´i‹ÅèÓ§úöí[lÛsssqóæM¸»»C$ÁÆÆÖÖÖxýúµBÛeõ wFFÑ¢E  Ç­ìØß׌3äžoÛ¶ b±_|ñ…Üère7n,å`ùò刉‰½½½ÜrUöíÛ'¬ŒY³fÉ•1þþþ8xð :„   …mìß¿GŽÁ‡~ˆ¡C‡»Ïò*,, {öìA¿~ý„e&L€§§'rss±cÇ|ûí·jmëîÝ»ðóóCrr2üüüpøðaaŽeΜ9ƒqãÆaýúõÂ?E‹ÁÓÓ<À–-[‚ãùùù3f òòòФI\¸pUªTʇ ‚?þýõ–.]*¤êС6mÚ¤ô.e®\¹‚¼¼<˜™™¡mÛ¶i;)bŽ}"ÒW!!!˜5k‚‚‚™™ ˆÅb˜šš" ¿ýö›ÖÚÂ>“ˆ¨|a-(˜‚E6²wÑ¢EhÖ¬\\\„'²²Â)[ f͚ؽ{7Œ±jÕ*œ:u €tDøýû÷Ñ AlܸQeV¬XÝ»wÃÑÑ#FŒ€““jÕª…   äçç#44{÷îU¸Ú¦¬íü1<==ááá!¤‘V ·]ö\V7-- nnnðððÀ!CäÊT»¾’ª}||‚úàçç‡>}úŽh/,##“&M‚‰‰‰\`WùûûËõéÜ þþþ¤w¨ãöíÛø×¿þ…äädâØ±cEõ J•*X¹r¥Üëgkk+ÌùpåÊ…/¨§OŸîbYµj•\P¾§²”S[·n…X, ±HïÒ)8_…X,ÆË—/åæ{ \hÕªD"‘FÚNDDDŠ˜cŸˆô•……Ö¬YƒçÏŸãÎ;ˆŽŽÆÍ›7‘‘‘ÇËÍ3¦ LÅCDÅ‘H$ru×+n}*9öµ ''GøÝÜÜ€t47 d;vL®ìÍ›7J·ãëë‹yóæA"‘`èСXµjvíÚ ìÝ»666*Û™™‰ØØX$''+”=}úqqqÂ$»Eµ===]È%çÎᢄª¶ËêËÊ###‘––Ø»w/$‰PVÔ±ë›û÷ïãÖ­[¤ùÒUùä“O.\PèÜf̘””|ùå—B{}¥l¢'à)ŒdE‰‹‹C§NššŠ¾}ûâàÁƒEÎM Ó±cGXYY©Üwvv¶BÀ]67„µµ5:wî¬t»½zõ ýüÈRN¹ºº w µ¿oß>ØÙÙ¡víÚÈÍÍ–ËÖQ5niÚNDDDŠ˜Š‡ˆô©©)6l///4mÚTéyBYcŸIDT¾0°¯ƒïÞ½ 8€tô­,罬LÙÈ]™ ÀÇÇ©©©˜>}:`Íš5ryä ûçŸСC¬Y³6668xð RSSñÏ?ÿàäÉ“¨_¿>¶mÛ†6mÚ >>¾È¶W«VMt6kÖL8«j»¬¾¬ü£>rè:FFFBYqÇ®O®^½*üž””„mÛ¶)}ܽ{€ôÂËË—/…:çϟǦM›P½zu,^¼Xëí×4U£H>øàÅ_Љ‡¯¯/ÒÓÓH??Ê&.;•í_ö¾¸¹¹ÁÔTyƲÂsCÈÈFí ìË&öÍÌÌÄ… „å²u”å×/mÛ‰ˆˆHûD¤Ï®^½ŠñãÇ£}ûöhÚ´)¼¼¼0xð`>|Xãûb¿HD¤?˜c_ ¦ ‘¥®™;w.† ;;;a¤}vv¶Âú…cÓ¦MhР$ Ú´iƒ±cǹÿùóçãÆ‰D‡³³³Pæïï³gÏÂÍÍ )))7nΜ9£²íUªTÁ‰'ðàÁÔ­[W®ªj»ì¹ì¸íííq÷î]¤¦¦ÂÅÅE®nqÇ®Oþùçá÷¹sçªUçÕ«W°³³Ã»wï0zôhH$,_¾vvveÕL­)xW†2Å}y¼qãé\ Ož<Á¨Q£Ð¦Mµ&Z.nßÊö/»Èbkk«²NÁ÷%##Cø½}ûöØ¿¿\`ÿäÉ“hÚ´)nݺ…°°0têÔ )))²‹šh;)bŽ}"ÒWÀˆ#ЫW/ 0¶¶¶ÈÊʽ{÷0~üxDDD`Íš5ÛSñéöµ à¨Û””áw'''¹õdeÅåÈ[²d‰ð566aaa*SÒ”7 Ô—©\¹2FŒàà`DDDàéÓ§¨Q£†Ò¶;88ÀØØõë×–gee é@ ·]ö¼àq[YY AýÂešÎ¨+O¿ûî;µòãËÅqqqˆ&7¾té’ÜzGöoß¾/^D•*U°bÅ µ¾|š;w.&Mš„æÍ›#-- Ÿ}öNŸ>­òDý}˜˜˜(:ïnÁ2ÙúÀÿFß_¾|b±ñññxòä ¦M›†íÛ·#,,L˜ˆ5j„jÕªiüˆˆˆè˜cŸˆôÕÒ¥K±wï^¥çü³gÏFƒ °`Á‚"%i ûïïï¿ÿ8::ÊG–VNNRSSaff¦ÖÀ7"2, ìk““D"Þ¼y#äâ.L"‘È¥ÿPE–ÂÅÜÜ8xð † ‚¸¸8¥Añ—/_ £Ç Ó +¨ðàØ/Ø–„„xzz*Ô-˜¾§pÛeÏ_¿~Ç+ýGST}}%{ýiÊ¡ªU«ª]Wöe)77·È ‘ ""°··/“À¾ì$XÕ¸‚w&”¥€€,Y²€ô3€ˆˆ,]ºóçÏ×øþdYž={¦r‚eGï·lÙ•*UBVVnß¾-Lt€ôôt#55µØ4ð‚ÏŸ>}ª²Ë ¦ÿhÕª•¤ŒŒŒÄàÁƒêž?^ø½pÛ N ‰¨¬_·n]…»ôU›6m„ߣ¢¢Ð½{wµë:99!88Xeù³gÏðÝwß>ýôSxzzÂÚÚºô-‚lB&UnÙhƒ²Vpbè.]º`Ò¤I Å¢E‹àëë«2•Mi5iÒ€4×~VV–ÒQqqq ëÒÏ\Û¶mñÇ &&'Nœ€‹‹ ÜÜÜЭ[7,[¶ 'Nœ(vâ\"""Òö‰H_uïÞƒ ÂÒ¥KáååäääàîÝ» …­­-µÒ}î3/_¾,Üýþöí[ÒØ‡ìÿƒlYY3f èdòc"2<œyòaaaþ÷!`RìmÞ¿ 988`Ö¬Y*£FÖíÖ­fÍš… &”ÉqȾ ¦¥¥É¥L’Ù±cG™ì·8+V¬@óæÍ!‹1hÐ ¼xñB£ÛÿøãH'}–¥²*lçÎWWW…»ad£ð#"")|¦½½½QµjU?~—/_–[—ˆˆˆÊs쑾 ··7‚‚‚P¹re˜ššB$ÁÓÓéééøí·ß4º?CíSSS‘““#—ÚöìÙ³ÈÉÉANNòóó1sæL|ú駘8q"®\¹"¬÷×_aÊ”)FLL >ûì3¬Y³aaa˜2e öíÛ‡M›6¡W¯^X¸p!Þ½{‡}ûö¡OŸ>˜|XãóÔj*ž¢\ºt 7Fhh(222ðßÿþmÛ¶.š$''#44!!!ðññÁîÝ»qýúu\¼x¡¡¡øòË/ñÕW_áØ±cX´hÚ·oÁƒãĉX·n\æƒÐÐP„†† q™ýû÷#44Ý»wÇŠ+pøða|óÍ7øöÛoHSö¬]»?Fnn.8€~ýú wñQÅÆÀ¾–XYYá矆±±1nß¾úõë#00~ø!››‹ `ùòå u7n܈]»vÁØØ;wîDõêÕåÊû÷ï‘#GB"‘`ذaHJJ’+Ÿ={¶ÇŽpvvF×®]ѳgO¸¸¸`îܹ¤)`Ö®]«°///Ìœ9°{÷n¸ºº"((îîîBÞó¾}û*M³“'O&L@Ë–-Ñ£G8;; ùÇ׬Y£2 ϲeËàîî.<öìÙ@:šºàr???¥õu¥cÇŽX»v-ŒŒŒ°gÏ8::ÂÏσFÏž=áêê www¬^½ºÈ\ºÔ Aa’¦íÛ·ÃÕÕ={ö„··7üýý1räHµ­I“&X¹r%àÀÂÅ1MÙ¼y3ìììžžOOOtîÜD“&Mðõ×_|}}•Þ-áíí äååA$ÁÇÇG(ëÖ­›pqŒ£õ‰ˆˆ´ƒ©xˆHß™šš¢aÆðòòBÓ¦Mu’ÊÅPûÌÙ³g#''6lÀ©S§pôèQˆÅba£ÌË—/ñÃ? 77W.°ngg‡ÔÔT¬[·põêU\»vMõ!7HNooo<þëׯ HHsò§¦¦bß¾}X¹r%/^ @:'ûZ€cÇŽ¡^½zÈÌÌıcÇ ###tïÞ‘‘‘ Þ\¿~“'O ïëë«tÛëÖ­C“&MðâÅ ôïß_Òt<˜–ôÑG¨T©’0XÑÉÉ 7â+yyy i ëÓ§Œ…‰’e™ >|///Ô¬YÍš5îüø±&ˆô'ÏÕ².]ºàþýûˆERRD"Z´h¡r´z‹-ðæÍ›b·+‰pëÖ-•åÖÖÖX»v-‚ƒƒqõêU$''C"‘ÀÞÞžžž¨\¹r‘Û722ÂôéÓ1aÂDGG#-- U«VE›6m.F(cccƒŸþË—/Ç•+WðêÕ+Ô®]ÞÞÞ033+²îÚµk•ÞIPªæP‡,Ç}IuîÜ;wÆ£GpóæM¼xñVVVpqqAÓ¦M•†‹Ò¨Q#­~¡ªQ£¢¢¢põêUÜ»w•+W†———p爪¶XZZÛÎ… báÂ…*Ë#""ŠmŸ²ôSpñâÅ"ëuêÔ©Øö5iÒçÎCbb"nܸ¬¬,Ô¨QÞÞÞÅNX|õêU¥Ëíìì——Wd]M´ˆˆˆþ‡9ö‰ˆH•êÕ«#==K–,A“&MäÊ þÿ¨R¥ŠÒúrëÊž7J¿ Ù`°Âÿ¯–/_Ž[·na̘1 ÁùóçÑ­[7¦’#" ì넱±1Ú¶m‹¶mÛj}ß"‘HÈ›^ÚúªîP‡½½½ÒÉ+GGGa2Z}cddOOO!¥SEãìì ggg]7ƒˆˆˆJ‰9ö‰ˆÔSGì8ß|ó Ž= äççãÒ¥Køë¯¿¤Ó¶É…¥¤¤ ::ZH‡LD0°ODDDDDŽ©xˆˆÔSû³gÏFvv6Ö­[‡nݺlmm1vìX· ˜9s&Μ9ƒ#GŽàôéÓøüóÏ­ëfQ9ÁÀ>4ö‰ˆÞŸ!ô™ÊxyZ IDATRÆššš"88Ë–-ÃãÇaff†êÕ« iqT¥B-œZ¶K—.rëÙÚÚ*Ô+ü¼púÙÂûjܸ1‘œœŒ5j@$ “ôÕ6"ªØ'"""""ƒÆûDDê©Èý¢‘‘êÔ©£ëf(011AݺuuÝ "*‡”Ã%"""""2̱ODôþ*rПˆ¨ö‰ˆˆˆˆÈ 1Ç>‘z8bŸˆH0°ODDDDD©xˆˆÞûL"¢ò…}"""""2h 쩇#ö‰ˆôûDDDDDdИcŸˆH= ìéö‰ˆˆˆˆÈ 1Ç>ö‰ˆˆˆˆÈ i+G³‘¾ãˆ}""ýaªë•%MöŒŒà"¢ §<ô{ªús""]xŸ>IV÷}úVŽØ'"""""ƒÆûDDêáˆ}""ýÁûDDDDDdИcŸˆH¿ñ¢éJTT€Ò]øT¶\“ýûDDDDDdд•cŸˆHßqÄ>Ñÿ¤§§ÃÚÚùùù011Ñè¶e}ªX,VywiqØ'"""""ƒÆÀ>‘zØ'"úŸJ•*¡Q£FÈÉÉ•••F·-‘H ‘H @|||‰¶ÁûDDDDDdИcŸˆèý±Ï$"*_Ø'"""""ƒÆûDDêaðžˆHh-ÏÅ‹µµ+­3äc#ÃÅ¿["""ª(˜Š‡ˆèý±Ï$"*_´Ø÷ööÖÖ®´êâÅ‹{ld¸øwKdøxñŽˆèØ'"Rsìé¦â!"""""ƒÆÀ>‘zØ'"Ò ì‘AS5y.s쑾b`Ÿˆˆˆˆˆ G쩇#ö‰ˆôûDDDDDdÐØ'"zì3‰ˆÊ­MžKDDDD†áÍ›7HKKƒ™™j×®­ëæ‹}""õpÄ~Ùá÷'"Ò4ö‰ˆˆˆ*°Þ½{ãùóçT¯^;vÄÈ‘#ann®´ÎÙ³gѵkW¸¹¹!!!A›Í%*æØ'"}¥êÂdYa`_=üþDDåûDDDDXTTÒÒÒP­Z5˜™™á?þÀž={pïÞ=¬Y³F×Í#ÒŽØ§ŠŽ#…‰4‹ßŸˆ¨<`Ž}""""Â÷ß'Ož`Μ9€ððp¡L"‘`ýúõøôÓO1kÖ,¼zõJWÍ$*öÉôîÝ:uB§Nàçç‡àÇÄ»wïTÖ9{ö,œáçç§Å–ÒûH$ïõxŸý–¦¬¢â÷'"Ò%ŽØ'""""ŽŽŽÂïÓ§OÇêÕ«annlÚ´I‡-#*9öÉp¤0é ûÌâñûiGì&Nœ,[¶ ­ZµÂÚµkYYYøþûï¿ýö1`À]6•¨Ä˜cŸ G SYàˆý’á÷'"Ò%ö‰ˆˆˆõêÕCµjÕ=R:a¿X2üþDDºÄÀ>á믿Æ7Я_?<{ö _~ù%ÀÎ΀tdszz:àéÓ§:k'Qi0°O†ˆ#…IÛØg*â÷'"Ò%ö‰ˆˆˆH°dÉãÂ… G:uàáá>|86lØ€¥K—긕D%ÃÀ>"ަ²ÀT<¥ÃïOD¤ ì‘ Aƒèß¿?`ñâÅ€íÛ·ÃÅÅ¿ÿþ;fΜ‰nݺ鲉D%Æûdˆ8R˜´}Õøý‰ˆtÁT× """"ÝIMMUX¶{÷nìÞ½[xÞ¬Y3Ü¿=BõêÕaii‰üQ›Í$z/±O†lÉ’%Ø¿¿0R¸sçÎððð@\\†Žž={bÙ²eºn&é ö‹êá÷'"*8bŸˆˆˆˆÔâèèKKK]7ƒ¨ÄØ'CƑ¤ILÅ£yüþDDe…#öuäÞ½{HLL„••7nŒ>ø@+û•H$¸{÷.>|ˆüü|888 qãÆ011Q«¾X,Æ7––†ªU«¢yóæ°°°P{ÿ¯_¿ÆÍ›7ñêÕ+Ô©S7Vy¢UV^¼x-[¶ ::/^¼nÁ^»v-Z¶lYlý3gÎ`ïÞ½HLLDNN eË–ÂdUe!%% xóæðº‹D¢2Û_y1eÊ\»v ¾¾¾øæ›otÝ"""ÒS ì“!áHaÒö™DDå ûZ±cÇâúõëÂ2sss 8¡¡¡¨R¥J™í{óæÍX²d ’’’ä–W«V S§NÅŒ3`jªúObëÖ­˜7oRRR„evvv˜>}:fΜ©2w)¼}ûsæÌÁ† ••%,wuuÅš5kн{w•uŸ>}Ѝ¨(áqýúuäææÂÒÒ/_¾TçЩ©©hÛ¶->|¨P¦Î¶–-[†¹sç–hŸï#22Ó§OGLLŒÜr <+V¬&Ì2D×®]ÃÙ³gQ³fM]7…ˆˆˆôsìSEåèè¨ë&žáˆ}""ýÁÀ¾;w;wFnn.,,,àéé‰/^ >>Û·oÇõë×qáÂXYYi|ßÓ¦MÃêÕ«ÖÖÖhÖ¬ÌÍÍqóæM¤§§cîܹ¸|ù2<¨´þòåË1{öl@ÕªUѤIüõ×_xòä æÌ™ƒÄÄDlܸQiÝüü|ôêÕ ¿ÿþ; ^½zpttĵk×pÿþ}ôèÑ;wîÄàÁƒ•ÖoÓ¦ÂňÒZ¼x1>|ˆªU«"$$Íš5ƒ™™ ~ýúEÖMIIÁ‚ ýúõØ1c„;-¬­­5Ò¾‚:„O?ýb±&&&hÚ´)ªW¯.Üq±uëVDFF"::U«VÕøþ‰ˆˆˆ Gì‘¡aŽ}-y÷î>ûì3äææÂÕÕ ¸páþüóOìÞ½ÆÆÆ¸víæÏŸ¯ñ}_¹rEêôÑG¸ÿ>¢¢¢‡bРA€_ýP¨ëÖ-a”z=ððáCœ={III˜4i`Ó¦M8zô¨ÒýoذAê/]º<À¹sç””„öíÛF´´4•Ç`nnooo|õÕWø×¿þUÊW8uê`Ò¤IøüóÏáåå…–-[¢eË–ÅçÏœ9ƒ¼¼<ˆD"lß¾¾¾¾BÝâ. ”Ô›7o0f̈ÅbØÛÛãòå˸víN:…¿ÿþ[HûsïÞ=,\¸P£û&""Ãddd¤“QyÀÀ>éöפK±/ŸG"*ÏØ×’ÿüç?xôè`ãÆ¨W¯žP6pà@|þù瀟~ú /^¼Ðè¾÷ïß/ü¾aÃÔ¨QCx^©R%üôÓO¨T©(±¿bÅ äçç£J•*øù矅; LMM±zõj4jÔ€4MMa‰Ë—/ ½¨0gÎ។vîÜ 333dgg«ÌQèÐ!¼zõ ÑÑÑrû+ Y!WW×R×­]»v™O|sîÜ9<}ú°`Á¹ÜÿFFF˜úè#Êß3""""úö‰ˆÔÃÀ>‘þ`*-‘_]\\àëë«P>zôhlÞ¼ÙÙÙøý÷ß…Qô ±XŒêÕ«« HK$\ºt ‰öööpvvÊž “üšššâóÏ?ÇŒ3pñâE<~üµk×Ê/_¾,ä³5j”¾ëÕ«?~@pp°Â:êLh«ÊíÛ·‘™™)<÷î 11/^”[·qãÆ¨\¹²ð<##ñññÂórssêV®\7VÙŽ—/_âäÉ“HHH@vv6êÔ©ƒO>ù 4Pº¾ì=€Ö­[+]§uëÖˆŒŒDJJ òóó‹œã ´RRR––‘H777¥ë\»v €ô½´µµ–K$an777ØÙÙ᯿þÂo¿ý†””Ô¨Q=zôPù¨ãùóç¸{÷. N:¨S§ŽP&{ïkÕª…ºuëâùóç8xð ÈÞ›ÂdËkÕªU&A} …‡‡ú÷ï¯rxxx ,,LnùÛ·o…×çìÙ³˜={66lˆ©S§"$$Ó¦MCãÆñÓO?•ªmÉÉÉðööF»ví0aˆD"¹rÙ{¿fÍ8pNNN5j‚ƒƒ±`ÁtìØÆ +ò„þèÑ£puuE¯^½ðÍ7ß $$_ý5¼¼¼Ð©S'…¿×#F ]»vØ´i“ÚÇѯ_?´k×ÿýï5Úv"¢’ú駟дiS¸¹¹áÛo¿•;}ûö-¦L™WWW´nÝšw‹‘Þáˆ}2$쯩,qÄ~ÉðóHDºÄûZðøñc!«lÄ< Eäææ†«W¯"!!A®lþüù8wîþøã 8çÏŸ&|¤#úçÍ›@ˆmÑ¢…\ý^½zaùòåÈËËÃï¿ÿŽ=zÈ•ÿùçŸÂƒž={Ê•l‹ª¶©^¸í²çVVVprr*¶þ;w..¼Þ½{Ëøß¼y3Äb1:wî¬p÷ƒƒƒƒÜs'''Œ3Fx~íÚ5ÄÄÄÀÖÖV!ÐݰaC¥û;v¬¸nß¾=ºuë‘H„Ë—/cÏž=زe ^¼x¡0·Á‡~{{{¤¥¥áèÑ£ðññ‘+ÏÉÉAxx8Å÷¬<Ú°aNœ8îÝ»ÃÃÃÉÉÉØ³g^¿~I“&¡sçÎ%š§ 11¾¾¾øûï¿Ñ¾}{?~\în‹‚nܸÿûßhÞ¼9>ùädffâÈ‘#øû￱cÇøúúbذa õÂÃÃÑ»woäååÁÑÑC† A5pýúuìܹgÏžE§N'ÌÏо}{üù矸té’ZǑ۷o:tè ±¶•ÔáÇ1oÞ<=z¶¶¶ ‚­­­0—άY³ƒððp$$$ ÿþ¨W¯Zµj¥ã–©‡}2쯉Ê~‰Hר×Yn}@>x|ëÖ-ØÛÛ£zõê¤#¯©kdŒ±k×.´lÙ—.]ÂܹsÈÌÌÄÀ‘››‹`ôèÑ û÷òòÂôéÓ‚/¾ø+W®„ŸŸÌÌ̃iÓ¦A,£OŸ>èÛ·o±mÏÍÍÅÍ›7áîî‘HX[[ãõë× m—Õ/xÜHLLD‹-`dd$·²c_3fÌ{¾mÛ6ˆÅb|ñÅ0`@‘u &_¾|9bbb`oo¯Ö(ó}ûö ëcÖ¬Yrå#FŒ€¿¿?<ˆC‡!((H(³¶¶ÆO?ý„þýûcݺu°¶¶ÆgŸ}†jÕªáÎ;X°`ѨQ#½˜<7,, {öìA¿~ý„e&L€§§'rss±cÇ|ûí·jmëîÝ»ðóóCrr2üüüpøðaáneΜ9ƒqãÆaýúõÂIý¢E‹àéé‰`Ë–- Áñüü|Œ3yyyhÒ¤ .\¸€*UªåC† ÁÇŒ¿þú K—.RHuèЛ6mRçÊ•+ÈË˃™™Ú¶m«‘¶•Ɔ 0nÜ8´k×€ôDtÕªU˜4iòòò°uëVüúë¯pvv†³³3zõê…-[¶ðÄ”ôûd(Ø_SYãˆ}õñóHDºÆT4h€7ªlÊ+°{÷n8::bĈprrB­Zµ„üü|„††bïÞ½ '=ÊÚþñÇÃÓÓÈÊÊ!°Z¸í²ç²ºiiipssƒ‡‡† "W¦êØõ•,Píãã£Ô???ôéÓ€ô AaAAAˆŒŒD·nݰxñb¸¹¹¡jÕªøðÃqéÒ%|ýõ×ˆŠŠ’› ¹¼ò÷÷— êÒ¹üýýHï:QÇíÛ·ñ¯ý ÉÉÉ ıcÇŠ ê@•*U°råJ¹¿m[[[a·+W®(|A=}ú´p˪U«ä‚ú€ô=•̓±uëVˆÅbÒû€ô.‚izÄb1^¾|)7ßá@«V­R •¶íDD¥qíÚ5xyy Ï[·n„„¼}û<À«W¯Êeß_ˆôª´…²4Dú‚ýµþøâ  P¶×•ë ûêã瑈t}-ÈÉÉ~777 Í HÙÇŽ“+{óæÒíøúúbÞ¼yH$:t(V­Z…]»vÁÂÂ{÷î…Ê6dff"66ÉÉÉ eOŸ>E\\œÜ„­ªÚžžž.ÌpçÎ្ª¶ËêËÊ###‘––Ø»w/$‰PVÔ±ë›û÷ïãÖ­[¤ùÒUùä“O.\Pø’$›|V69lA¯_¿ÆíÛ·ñçŸj°Õe§K—.J—ËRÉþ&ЇN:!55}ûöÅÁƒaaaQl½Ž;ÂÊÊJå¾³³³î²¹!¬­­Ñ¹sg¥ÛíÕ«éçG–rÊÕÕU¸¥à¨ý}ûöÁÎεk×–›çB¶Žª‰pKÓv"¢ÒÈÈÈ€ðÜÖÖùùùÈÌÌDFFLLLä¾gØÚÚ sðéƒ5kÖ(].KX6lPÜúþûïKÜ6*Ú?üPª2CÅþZ\¿|ù%ðÿ§þ%./Ø—ÇÏ#éûZP0ø(4pà@ÒŽ]–ó^V¦lä®Ì‚ àããƒÔÔTLŸ>€ôD¥`ùÂþùçtèÐkÖ¬ <ˆÔÔTüóÏ?8yò$êׯmÛ¶¡M›6ˆ/²íÕªUÍš5ƒ‡‡G‘m—Õ—•ôÑGBý¡C‡ÂÈÈHn¤TQÇ®O NÄ›””„mÛ¶)}È‚ö™™™xùò¥PG"‘`È!˜4i’““±víZ>¾¾¾HOO ýüœgâ}ö­lÿ²÷ÅÍÍ ¦¦Ê3–žBF6j¿``ÿĉ¤ïó… „å²u”å×/mÛ‰ˆJC$ÉÝ5'»#O$A$A,Ë]ìÏÊÊ2˜ÿÙdøöíÛWdøóÏ?d'** &LPYþÕW_áôéÓ%n#)!äªVfÒ¤I £Š‚ýuùwù2pþ< XY«Vÿ­~¹®1x¯>~‰Hרׂ‚©Bdýܹs‘””„‡¢Y³f¤£o ¯_˜±±16mÚ$¤æhÓ¦ ÆŽ[äþçÏŸ7n@$!<<½zõ‚½½=>øàøûûãìÙ³¨Y³&RRR0nܸbÛ~âÄ Ü»wW®\F«j»ì¹¬®½½=îÞ½‹û÷ïcóæÍru‹;v}òÏ?ÿ¿Ï;#FŒPúX¹r¥°Þ«W¯„ß÷íÛ‡]»vNø;yòd8;;£R¥JhÕªöíÛ‡€€äææbÔ¨QruË£‚we(SÜ—Ç7nàåË—Â\ £F’Kuó>ûV¶ÙE[[[•u ŽÌ(8êBY`ÿäÉ“hÚ´)é|’’"ÌA!«£‰¶©R–'–––e¶mÒŽ† ÊÝ!vïÞ=888 R¥Jpqq©©©B¹ª‰ã‰Ê›™3gª,³µµEvv6-Z¤Ö¶æÎ‹¼¼<•9ûóóó1{öìRµ“Í›7ùùù*Ëóóó1oÞ<-¶H÷Ø_ëKKÀߘ4 ‹;JV^^ñÜC?D¤kœû §OŸV™3÷}˜˜˜@±'’…×þ7úþòåˋňǓ'O0mÚ4lß¾aaaÂDÌШQ#T«VMãÇ@DòÔé‡+²~ýúaóæÍ9r$,--ñã? ÿW¬¬¬Ð­[7„††bË–-HOOÇž={ÔNÁ×¾tøºi–µµµÒ¹œd&÷ï߯±×<66–ïŸ]¸p¡B½Þ쯵G¯‡……+š6ý {ö\Ç‚ŠwÙW^Þh²¯4ü<ê?¾ÎR¼h§¿Ø×'''ˆD"¼yóFÈÅ]˜D"‘Kÿ¡Š,…‹¹¹9qðàA 2qqqJƒâ/_¾F ¦V0PÿàÁ!°_°- ðôôT¨[0}Oá¶Ëž¿~ý?Òð¨[__œÐvèС¨Zµj‰êß¿”^ˆ‘)üž•Ù?9U|Á;ÊR@@–,Y@ú@DD–.]Šùóçk|²‹,Ïž=S¹NÁ²‚eZ¶l‰J•*!++ ·oß&º@zz:‚ƒƒ‘ššZl""m?~<¢££áäässs4jÔHnóúõëˆzõê!##ÇGÏž=uØb¢’±´´TØ×ô‰¬‰‰ Äb±F·ITûk¢òƒŸG"Ò5öµÀÈÈíÛ·Gxx8"##•®sýúu!JÇŽ•®sëÖ-Œ?°|ùrL˜0íÛ·Gll,ú÷ï³gÏ*ä/øüéÓ§*ÛX°¬`úV­Z AÊÈÈH ¶mÛhÑ¢êÕ«'Wîíí {{{ÀÖ­[öûäÉ!ç¸ì52BÀ6$$¤È”.€â?wwwÀÇqûöm¥udï ?‘«&ÉN€ÓÒÒäR&ÉìÐQ2È+V yóæ‹Å4h^¼x¡ÑíüñǤ'çª&'Þ¹s'ÀÕÕUánÙ(üˆˆDFF ŸioooT­ZÇÇåË—åÖ%"*ªW¯®pRZ““S‰NJ‰Ê‹Š&ÃÇþº|{ó8u X·01†-Y¹.Õ/²ÏTŽŸG"ÒöµdĈBz–Ñ£G˶þý÷ß±aÃ…õ 3f P«V-lÛ¶M89qqqÁÆ«V­ÂÑ£Gêýÿo >Ę1c„‰li`~Ù²e8sæ ip½àèh˜1ciÚ•/¿ü¹¹¹¤ÿÔ,X€ëׯfÍš¥°oL›6 pêÔ)¹|rÙÙÙ>|8Þ¾} sss|õÕWJ_»§OŸ"!!AxÈ&6•H$rËeékÊ‹%K–ÀØØçÏŸÇ Aƒ”¦­IHHÀ´iÓÒÉÈÞ3‰D‚aÆ!))I®<,, +V¬ ¾ûøø”É1ÈFÂË&‚+xkùéÓ§… µÍ»wï†H$ÂÇ1jÔ(nßËË ÞÞÞ¤ÿ7nÜ+ÿî»ï„ +'NT¨/ ÖïÝ»999B`ߨØ]ºtÁ¯¿þŠÌÌLÔªU«ÈYDš••…„„ÄÇÇ—É#!!wîÜ‘›Œˆ¨¼Q5ŠžA*"Ò´Ö­>fϲ³iÓ€‚ãߊ+/ÏØg•/ ìk‰••~þùgãöíÛ¨_¿>ñá‡" ¹¹¹hР–/_®PwãÆØµkŒ±sçNT¯^]}®R IDAT®¼ÿþ9r¤Ê ðìÙ³…Üø;v쀳³3ºv튞={ÂÅÅsçÎ ½Š¼víZ…ý{yyaæÌ™€Ý»wÃÕÕAAApwwòž÷íÛWiš@:É«,Ð9a´lÙ=zô€³³³|Íš5*Óð,[¶ îîîÂC6±ì»wïä–ûùù)­¯+;vÄÚµkadd„={öÀÑÑ~~~i“¥¥%ÌÍÍU>ÌÌÌ”>LMM&&&011žËÖµµµÕõa)¥jÄ~qwU•V‹ÀO?}û–®\W8bŸˆH0ǾàØ±c;v,þþûo;v €ôD#00›6mRŠ\¿~“'O ïëë«tÛëÖ­Ctt4nß¾þýû#22fff¤éx"""0oÞ-”YXX`̘1X¾|9LLLêÚØØ yóæˆ‹‹ƒ,--…².]ºë1°OÚP©R%4jÔÂɘD"Q81+XVÜOUu ÓÌ¥ISñ>b­ßþ?Ûn©Ë©|á瑈Ê#£/^”é·Ù˜˜´mÛÖ`Gñ]¼xQHÙ¡®üü|ÄÆÆ")) "‘-Z´ÐÚ¤±oÞ¼ÁÕ«W‘œœ ‰D{{{xzz¢råÊj׎ŽFZZªV­Š6mÚ”è½MKKÕ+WðêÕ+Ô®]ÞÞÞÂC÷èÑ#ܼy/^¼€••\\\дiS¥á‚òóóqóæMÜ¿oÞ¼Z¶lYd¿â”ôïV"‘àêÕ«¸wï*W® ///…;G Ybb"nܸ¬¬,Ô¨QÞÞÞ°¶¶Öu³ˆŠ$ûœ‡‡‡£iÓ¦°··×J`?::mÛ¶-££*^xx¸Üœ-§OŸ†ŸŸŸÂäò‘®NH+zàTöº«û:”t}RÏÓ§O…yŸ ªV­ž={Vâí©štW,sòÜ2PÑ.̰¿Ö,m÷í[Kþÿ”Z%.×µiÓ¦aõêÕJËzôèÇk¹EºÅÏ£~à÷­ÒÑÔë`Èÿ§ÃÃÃáîœXYYitÛ²sëììl!G||¼‘äСC€Î;«ÜÏruÀØØmÛ¶ÕIàC$ yÓK[_Õ]ê°··W:9pEàèè(LF[ÆÆÆhÑ¢Z´hQ­R‘‘<==…”N³³3œuÝ ¢2Q’€¾ìgáeÁ¤ á‹5Qi1Ç>éþ]’.1¼ŠxÌD¤?8œ„ˆˆˆˆˆ sì½?¹‰ˆÊö‰ˆˆˆˆÈ ò-âDDšÄûDDúƒ}"""""2h ì‘¡a`Ÿˆˆˆˆˆ s쩇#ö‰ˆôûDDDDDdИcŸˆH= ìéö‰ˆˆˆˆÈ 1ÑûcŸIDT¾˜êºDDD¤}‡Æ‘#GNÐT°\ˆÀÀÀ2m‘&1°OD¤ö‹DDúƒ#ö‰ˆˆ* ž={¢G%®Ç >é#æØ'"zì3‰ˆÊö‰ˆˆ*¨ž={¢gÏžj¯ß½{wtïÞ½ [DDT6˜cŸˆH=̱OD¤?Ø'""ªÀzôè¡VpŸA}"ÒgLÅCD¤ö‰ˆôûDDD\=ŠLËà>é;ö‰ˆˆˆÈÐ0°ODDD*ƒû ê‘!`Ž}""õpÄ>‘þ``Ÿˆˆˆ(÷{ôèÁ >æØ'"z ì•/¦ºn•ûÝ»wç ¦â!"RGìéö‰ˆˆHN=xâFD…}""õ°_$"ÒLÅCDDDDDMU`Ðl‹1"2dì㈈Êö‰ˆˆˆˆÈ i:°_ÔöˆˆôSñéö‰ˆˆˆˆÈà1ÑûaIDT¾0°ODDDDD}"¢âqÄ>‘þ``Ÿˆˆˆˆˆ ž±±òSªˆˆþ‡}"‘þ0ÕÖŽ.^¼¨­]i!.þÝQE¢jÄ~~~¾–[BD¤Ÿô'"*_´Ø÷ööÖÖ®´êâÅ‹{ld¸øwKdøÔ½x÷>@Êêò$ˆôSñ©xˆˆôSñ8±X¬ë&éûDDï‡ý%Qù¢•À~LLŒ6v£õLúˆ·D†Oö9wss+r=‰DRêG~~¾Üƒˆ¨¼JLLTÙOݸq£DÁª;wî¨\?>>¾Tí#"*/¼'"ÒZKÅsâÄ m튈ˆˆ ¹uë–®›@D¤uW¯^Å·ß~‹Ã‡«\ÇÛÛmÛ¶ÅüùóÑ­[7•ë]¸p‹-©S§T®Ó¬Y3øøø`þüùðññy¯¶éSñé2ì·mÛ¶¬wADDD¤WÞgn*?à(¿Äb1–-[†… ªuGQLL 1dÈüðð±±ÊÞ½{‡9sæ`õêÕjíûÌ™38sæ Æ•+WB$•ú8ŠSÑûC9~ö%¤/ø·JDT¾0Ç>Œ¼¼< 4ß|óM‰Ó„ýç?ÿAÇŽñâÅ @NNºwï®vP¿ ~øŸ|ò ²³³K\—ˆHW8bŸˆHh-Éã ²~2”Q†jܸqØ»wo©ë_»v ]»vÅÙ³g1hÐ œzô½zõB½zõàïï¯0WÃO?ý„¦M›ÂÍÍ ß~û­\p±¸mÕ®â¶]\»¨â:~ü86mÚôÞÛ‰‰‰A‹-ð믿¾÷¶Nœ8¡‘6éû¢Š#ö‰ˆôûDDDDêÉ“' ÄÈ‘#qþüydggãóÏ?ÊgÍš…˜˜„‡‡cñâÅ>|8®^½ @zòDEE¡sçÎèÒ¥‹VäðáØ7o6mÚ„C‡a×®]øþûïÕÚvqí*jÛŵ‹*.±XŒ &¨,733SºÜÄÄDéò;wî¨ÜVIGZÏš5 ™™™%ªSž°/!"€}"¢ò†}""""µsçN´lÙ#FŒ@:u‚C‡!-- yyyغu+–.] gggtíÚ½zõ–-[±±±øóÏ?Ìœ9¦¦¦8vì`Æ 7nÚµkwwwÌš5 6l€b·]T»ŠÛvqí¢Š+22‰‰‰JËöíÛkkk¥egΜA¥J•ÔÚ‡±±1ÂÃÃUö###ajª˜íôåË—8tèZû(Ø—U±OD¤?Ø'"""ƒgddT®ÚríÚ5xyy Ïagg‡7nàÁƒxõê•\yëÖ­qíÚ5¡nãÆåžžžžrå…ë&$$àíÛ·jm[U»ŠÛvqíÒ¦²|¯uý7ª¥¯å°aÃðé§ŸªÌqïîK—ªõ¾L:~~~*ËÛµk‡Y³f)-:t(û’ÿǾ„¨übðžˆH0°ODDDd 222`gg'·ÌÖÖÈÈÈ€‰‰ lllÊŠ««¬ÜÖÖùùùÈÌÌ,ómU—¨°îÝ»P>'??ݺu+Ñ¶Š¢î¶ô û"ô'"*oØ'"""2P"‘¯_¿–[–••‘H‘H±XŒœœ…²âê*+ÏÊÊ–—õ¶‹ªKT˜››Õ}‰D‚zõêÁÜÜ\ím½ï:ú†} QÅÁTÑûÑd9kÖ,ÄÄÄ << èß¿?êÕ«‡V­ZilDDï+++ T)-YŸ*ûÙ°aÃo£Ìû™™™¸sçLLLàáá‘H¤‘Ûቈˆ¨|ÈËËÛ7o‡;wî J•*¹ODåsìO;óòò°uëVüúë¯pvv†³³3zõê…-[¶0°ODå’¥¥e©îhR¶\Õº¶¶¶%nW™GØ!‘Hàááºuëâùóçe½K"""Ò"SSSÔ­[‹ÄÄD4oÞ\Ç­ÒšõADªr*ö%D¤)ÚHÅóàÁ¼zõ ^^^²֭[ã—_~ÑÈö‰ˆ4¥R¥JhÔ¨äFØî ¾/ꧪº¥lRæýŒŒ Òɪàƒ>(ë]‘Ô®]±±±Âÿ~"¢òÄûDDÚ ©þ2##&&ÿ×Þ½GE]ç *‚а˜yÍK…·¬ˆJÓÖVCÊVÀ¶-µôØvùÕªm«Õv9•»’»yZw[;z"wÍÊ4mÍV­V DÒ51ŠPÓ%6´…Tnóûƒ¯30 Ì0žsæ8|¯>x¾óù¾çý}:Ø=áÁ€OêСƒ·›à”ÇûÖ‰r)¿@`³~Ö[?ûáD íb}n;ÐÞ]w·[àÌZ]{íZ§k[ÒîÓ§í UMMÎ;§Iuu¬CCC]?8x‘+™úÖë/kÍ“—ŽG·@¨±¾áÒK/UÇŽuðàAcÙ¡C‡Z4q$´g¤Ñx”âàKÌfo·À±éÓ§kýúõ×1Bû÷ïwù˜))R\Ü…Ÿ»té¢É“'kéÒ¥Z¹r¥N:¥õë×kùòå-m6´Kdìxö im1y®$-[¶LûöíÓ Aƒ¥»îºKS¦LqÛñ = c@À Äû¼oêTiÂéúë¥+¯lþ~çÏK_~)eeIiiÒ»ïz®îâÎëeÿþýõù矫  @aaaúÉO~â¶c@{A`@À£Æ>O8r¤îµr¥Ô©Ó…å+VHu/I*-­{Y/UUµiS›¥­¿ì0`@›ž }øµ¬¬,­]»VÏ<óŒ.¾øbo7>ŠR<Ø/..Ö£>ª7ªÊæy´*))I³fÍòعϜ9£?üáZ¹r¥ÊÊÊìÖ………éþûï×Â… îôUUUJJJÒ²eËTjó|]xx¸fÏž­… *88¸Ñv|öÙgzä‘Gôé§ŸÚ-=z´^yåã¦Õ‘ÒÒR™Ífeee¯“'OJ’-Z¤'žx¢ÑsKRff¦âââtæÌ»å½{÷6Þ'''kîܹ Yž>}z“Ç·:qâ„ÒÓÓÕ«W/§Û¸£?ð7m•Ìà*¹‘ÿꫯKpQc€§uë&ëíV´Ž'û©©©>;ÖWX'ûÞ´i“Kû¹3¨/ùH`¿¨¨H£GÖñãÇ%IÇ×E]¤œœ;vL÷Þ{¯¾þúk%%%¹ýÜeeeºé¦›”““#IêÞ½»†*I:pà€NŸ>­¥K—jûöíÚ½{·"##£¦¦F‰‰‰Úºu«$©oß¾ºüòËuøðajñâÅÚ»w¯¶nÝê4û?--M“&MRee¥:v쨘˜IuÁþÌÌLÝxãúàƒtë­·:Üÿ׿þµÖ¯_ïp]uuu³úbþüù:s挆®E‹iРA 2&±)++Óã?®ÚÚZÝvÛmš?¾zöì)Iºä’KšuŽæpG€ögäÈ‘÷á5öxBPT[+>-uïîÚ¾§O_8†?à‹P¸ÀÕà~BB‚âããÝz-õ‰Y³féøñã ÓÖ­[•››«O>ùD'Nœ02Á_xᥦ¦ºýÜ .4‚ú¿ùÍoôí·ßjïÞ½Ú»w¯ŠŠŠ4oÞÀ äpëÜݺu32õÝÍý Ú§‹/¾˜à>œ"°Àî¼³îß+$W>rŠ‹¥¿ÿÝþ¾Žë%4”˜˜Øè¼£ž êK>Øûí·%I‘‘‘ºï¾û¬ïܹ³¤ÎÈÈБ#GŒuÊÈÈPFF† œž£ººÚØî€Í4õµµµF°zܸqû&“I?ûÙÏ$Ißÿ½Î;g·~Ë–-:ý¿ççœÕ±üñÇö:z÷§º¹ 222d6›e¹¹¹FÙ¾’´{÷n͘1£Á—-Ý»w×Ê•+=vkûÀÜ¥æ> ÔØà &“ôÜsÒ©SRf¦4mš4uªtÿýÒÿ¦«3””H¯¿.½û®TS#]·¯/Í'ëÀ>߉‰‰²X,Ú¼y³ñ³;'ÊuÄ«ý3gÎæFGG;Ý.**J]»vUEE…]vxPPÞ~ûmEGGë»ï¾ÓŒ3ôñÇÛeãlÛ¶Í(í²`ÁM˜0ÁîØS¦LQrr²>úè#•””ÅZ•••éƒ>$‡ß¼XÛsõÕW7ú»FGG«°°°Av»íÏõÁ5×\c·»ûW\q…~øa•––¥†î¼óN‡5ósssµk×.Û=]q饗ï³³³5iÒ$UTT(<<\3gÎTTT” µfÍMŸ>½ÑÇSZÛŸÁ}4D)žÒ©“´t©´vm]IžwÞ‘Ö¯—®½V²æÄ}ú©´o_ÝD»!!Ò#Hwß-uôzº¥ïð¥/8 %lcž gzõ#ä›o¾1Þ0 Ñm/¹äåççە⑤޽{kÍš5ºå–[´cǽð úýï/©®&ü¬Y³d±XtóÍ7;œü6))IéééÊËËSll¬^xáÅÄÄH’>ûì3-X°@ÇWTT”þô§?9ýšÓ~I ÚßÜ>°îïè­1nÜ87NùùùF`ÿÙgŸuø%Crr²víÚ¥ÐÐP%'';<Þ< ŠŠ 0@Ÿ|ò‰1ñ®õ¸·Ür‹Þÿ}§íimX܇-û<©cGiÖ,iâD)9YÚ±CÊʪ{Y…†J&H³gK}úx¯­!cZÇš¹ß¼Zcß¶æzSõá­ë­eqlÅÆÆë&%%)--Mµµµš1c†Š‹‹Õ«W/­Y³Æa]Íž={jÏž=zúé§uôèQÅÇÇ«oß¾êÛ·¯âããuøðaýîw¿SFF†ú8øäµ¶§¹í?{ö¬jjj\îÛuŽúÀìܹSÙÙÙ’¤åË—Ûõ%)<<\o½õ–Óú¦RëûÀ5÷aE}m¡o_))IJI‘/¾°|ñbéãëÖùjP¿)ž¾^’±®ñj`ÿìÙ³ÆûàààF·µÖß·ÝÇÖ‚ 4~üx# ?þ|¥¥¥åzÕÞ·ÊËËÓ¾}ûTZZÚ`ÝéÓ§µoß>åææ6XWUU¥êêj—Ú_ÿwhn8Ûß—|ôÑG’¤>}úhòäÉ·:t¨Æçp;úHo½õ–xàM˜0AãÇ×Þ½{½Ý$¯"¸‰ûÚVHH]ö¾ÕĉuË|“ç€ÿðj`ßv"ÚÊÊÊF·=þ|ƒ}luèÐAk×®ÕÅ_¬¢¢"½òÊ+’êÊ¿L´ý4­ç½÷ÞÓøñãõñÇkìØ±JMMÕ©S§têÔ)¥¥¥é¦›nÒŽ;tóÍ7ëÝwßµÛ·S§NêСƒKí¯ÿ;4·œíïK¾üòKIÒµ×^ëôÆI’®¿þz‡ËÝÑŸ@zòÉ'µyófedd(==]?üðƒ·›äu÷A)hš7®‰\† e¼Zc?,,ÌxßTy™òòòûÔ×§O-\¸P³gÏ–$9Ò¨·ïHII‰î»ï>UVV*..N[·nµ{DwüøñJKKSBB‚>üðC=øàƒŠ‹‹³›`·[·n*++kvûCBBÔÑfvœú}Ñèþõ÷ñ%Ö jùZÓIDATASuk[ßÚþ ½ÈÌÌ”ÙlÖܹsµ~ýz………éç?ÿ¹$Él6«ÿþ6l˜8ÐêsÕÔÔ¨¦¦FµµµÍþוm[»OsQs¿}#°­C)ð-^ˆ4ÈxüøñF·µ®­%K–?çååiÏž=NK¿|øá‡Fùé§ŸvXwÓd2é™gž1¶ýðÃ5sæL»ßá‹/¾hqûë÷í$¹Žöwt _aí¿¦jÞ[Ëí8ÒÚþ ­5ö”š§¼þúëš={¶ªªª´{÷n­[·NáááÊÏÏWïÞ½Õ¿·ž/¾D'¸ß~QcšF)ð^-Å¡¾}ûJ’rrrœn÷Í7ßø#F8ÝÒáǦ뮻N555ºçž{ôý÷ß;ܾ  Àxåô¸¶ël÷‘¤+®¸¢ÉöKÒ_|á°ýÖý›:†uGÇðÖâo¿ý¶Ñí[ßÚþ UVVjΜ9zàTYY©~ýúiݺuêØ±£þøÇ?ªW¯^Þn¢_ ,OûD}h2öÀ·x5°/ɨŸ––¦ªª*‡Ûlß¾Ýxçp›ääd­_¿^’´bÅ ½ÿþûŠŒŒÔ‰'tß}÷9ܧ[·nÆûÆjÏÚ®³ÝǶýß}÷Ó`ôŒ/ê·?**J”dÿ{Ög]×§O»/|ILLŒ$iïÞ½v5ðëÛµk—Óu­íOÙÝwß­W_}U’Ô³gO8qB’”ššª¹sçzåéEp¿ý¡4ûÐ|&“©Å¯   §O”6—×û÷Üs$©¸¸Xï¼óNƒõÕÕÕZ¶l™$)::ZC‡m°MNNŽæÏŸ/©.kúôéêß¿¿V­Z%IÚ²e‹^~ùåû]}õÕÆûúãÚ²]g»$M™2E]ºt‘$ýíos¸¿uyHHˆn¿ýöëï¾ûn£‡n°þرczÿý÷%IÓ¦MóÙ›ö_üâ’¤²²2½ñÆ·IOO·{ú >wô'Ф{Üo_ì@ëp½Ð5UrÜ›¼Ø¿õÖ[uã7J’æÏŸ¯ŒŒ c]UU•æÌ™£¯¾úJ’”””Ô`ÿŠŠ M:UçÎÓ•W^©¥K—ëõÛßþVR] }³Ùl·ï7Þh”Ùy饗ôÊ+¯Øý±jkkõꫯjÑ¢E’ê²ë­mµŠŒŒÔ¼yó$Io¼ñ†V¬Xa·~ÕªUzíµ×$IsæÌqøˆüã?®îÝ»«ººZS§NÕÿû_c]qq±¦NªóçÏ«k×®zê©§vâÿú!??ßx}ýõׯº“'OÚ­kªTNK]uÕUš\à(ÁÜ–Åbiñ«¶¶ÖîÕ¦’’^™SRR$IwÞy§ÓmŽ=ªQ£FéäÉ“2™L3fŒzôè!³Ù¬¢¢"IÒ£>j´·š5k–V¯^­®]»Êl6kذavë+++5vìXíÛ·O—^z©²³³Õ½{wc}FF†&Nœ¨ŠŠ Iu¥nFŽ)‹Å¢ÜÜ\#ª””;¶A*++«Ý»wK’†®!C†èСCÊÍÍ•$5Jééé qØ[¶lÑí·ß®ÚÚZuéÒŘðw×®]úñÇe2™ôÏþS¿üå/î¿uëVÝvÛmNûØÖ´iÓ´nÝ:»eùùù>|¸$);;[ÑÑÑ öKNNÖìÙ³®ÒÒR‡Ç.,,Ô˜1ctüøq™L&ãË“ÂÂB¥¥¥©K—.š9s¦–/_®^½zÙ}‰aåŽþxdž $](­ÖÖRRRìžæ²N’ºsçNŸÛ:–èÚµ«±ŒÚÝÚÒ?þ¨ž={z»Œ“'O•%à=AAAï·©üãÊËËS^^ž$©sçÎúÕ¯~¥%K–4„NHHPjjªæÌ™£¼¼¨””íÞ½ÛÐÇÄÄèÍ7ß4¾ìqÆý €­‘#Gzüû÷ï—$»ñÈÙ³gêñs€$ã©GÉHÀ5{öìQXX˜Ãx#ÚŽõžÊ:Î6l˜:tèàñóZ«º8J~ö„ÌÌL—÷ñ‰Œ}[ÊÉÉQyy¹úõë§n¸A:uòd ?üðƒ²³³U\\,“ɤž={êšk®Qddd³QZZª¬¬,:uJ=zôШQ£áR;¾øâ £”Îe—]ÖfÿÜíСCÊÉÉ‘ÉdÒ!CZTqGÚŽ¯fì·ÅÀÏš˜0vìX#I€À>€¶”——§û¸Áž={tîÜ9£Â¼ÃzOåqNzzz›öý.cßÖ€4`À¯œ;22Òè¼–ŠˆˆP\\\«ŽqõÕW7˜¤×EEEs´”;ú€¶¨ k=‡Åb1æ“1™L>;é=€Àc2™Œº­ u¬ãzÆóÞeý0ÎiÈë“ç€æó¹Œ}wkˬ2Hx×!¨ç\@Æ>@#6mÚäí&š©½Üѱ^K³:6mڤ͛7+11Ñãçwá:UsÆ9›6m’ÅbÑ”)SÚ EÞC`´ ®º6oÞldz4¶oýÉ´¨ð\p“åú‡ÆÆ9‹Å¸—s%IKºð÷÷‡q¥xê± êüõ ì@EÆ>x‹¥Ù›7on0økξÖmü!³@ಽÞq= åøõ=-çXËò¸š¹ïgìwîÜY’T]]íéS/²~Ö[?ûý‘£ >Àê}žÇ3öÃÃÃU\\¬ÂÂB 8ÐÓ§^RXX(©î³ß×4'c¿±Áž+ÙþÙ °‘±UsÆ9ŽÖ¹š¹ïã(gì c€_!cªæŽsâãã[”©_ÿ<¾ŒÀ>x- ìKuƒAëþÍ9Gs·Oaò\܃ÏQßÓÜqNkƒúMßWPŠ Öà~K„††º±%о´äžª5÷pþ„Œ}Ð.x*ãÂd258?dw<õ¯=\‹píøž±½ïh«qŽõïïwûnæƒ@Mcl_E`<‹ÅÒ ³ÞÇ®ÿsmm­GΩ_sÖS×=™íøž±½ïh«qŽ?ÍUD`ÀÍüa pÕÖÖ*(ˆéÔpÆö¾…qÎö@@KMMÕ˜1c<~žk®¹Æãç€æ"»’!C†(""BRÛsΟ?¯ÌÌÌ69WKØïÓO?õv MÔÔÔpÍÀòòò¼ÝÀ!SII Ï“€€’’âí&à'NtºŽ‚Dø2ö@À¨©©ñvhµŠŠ uïÞÝézj쀀QQQáí&àqö@Àh,›€@A}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}ü}¼Èl6Ël6+88XÁÁÁMnO`?b*))±x»´Wõ³ô+++ÝžŒ}üHGo7€ö¬© ýúÈØÀØ  ˜Íf™ÍfÛÕÕw¶ÜûøSII‰ÅÛ ÐÕÏÆ·ÖÖw¶Ü2öð#½ÝÚg™øMeè×GÆ>~„À>nd6›e6›lW?ßÕåÎØÀ˜JJJ,Þn¢~Ö½µ†¾«Ë!c?BÆ>~„Œ}ü}ZÀl6Ël6+88Ø®N¾»–;C`?B}Z ~v}ee¥[—;CÆ>~„Œ}üûø‘ IUÞnh–ª I_y» Y¾ ²X,+¼Ý Ð4“ÉôšÉb±•––¦Jïí§vFDDÄ™L¦Úššš™’vz»EÀ¡5553M&S­ÉºÄb±•••ýŸÅbyXÒHI¼×>Ú½*I_™L¦×ÂÃÃÿn2™j%éÿ;g‰Fî¹úŽIEND®B`‚qtrvsim-0.9.8/data/screenshots/1.png000066400000000000000000005430301467752164200173770ustar00rootroot00000000000000‰PNG  IHDRöx¹¿sBIT|dˆtEXtSoftwaregnome-screenshotï¿>*tEXtCreation TimeThu 20 Jan 2022 23:58:58 CETh!ù IDATxœìÝw|TUþÿñ×IB€ (u)"`D)ŠÊé¨ÈªwźúWW]×um(ʪ`[¬Š +@Qª,ÒBï!$¦“Ìdfîïp¯“d¤Âûùxä‘É­çÞ —Éûžû9'˜¦éHOO¿Ã0Œ;€N@0"""""""""""RUò-¦i¾]¯^½· Ãð)))MNçLàÊ*l ˆˆˆˆˆˆˆˆˆˆˆ¶ÌëõŽ‰ŽŽ>ì0MÓát:?F¡¾ˆˆˆˆˆˆˆˆˆˆHuu¥Óéœiš¦ÃHKK»Ë0Œ7ªºE"""""""""""R:Ã0î2ÒÓÓ×]«º1"""""""""""rRŒôôt7(WDDDDDDDDDD¤&Èw P_DDDDDDDDDD¤¦vTu DDDDDDDDDDD¤ì싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A‚ªº"""""RómÛ¶ÄÄDBBB¸üòË«º9"""""g5û""""rÎÚµk .$>>ž””|> 6¤S§NôïߟöíÛ—ëþŽ=Ê‚ Î #**ŠvíÚѲeË€ËÌœ9“üü|ÂÂÂ9rä)í;11‘… жm[zõêUl™-[¶°`Á¶lÙBZZ^¯—ºuëÒ¼ysºtéBïÞ½iÖ¬YÀí¿þúëÌž=›˜˜vîÜyJm‘S£`_DDDDÎ9{öìáñÇgÑ¢EçÏ›7§žzо}ûòì³ÏÒ¶mÛ·µlÙ2>úè#^xᢣ£KÝïƒ>xÒöµlÙ’ûî»[o½Ã0ìé ,àÛo¿ sçÎtìØñ¤Û²¼ýöÛL:€3fš—””Äý÷ßÏwß}wÒí4oÞœM›6•y¿"""""Rþ싈ˆˆÈ9eùòåŒ=šcÇŽP»vmúõëÇùçŸÃáàÀ|ÿý÷dff²dÉ®¾új>øàúöíp{û÷ïçóÏ?àÉ'Ÿ,s;êׯOƒ ìŸÓÓÓIII`ß¾}L˜0_~ù…×^{Í^f̘1v°ÿñÇóì³Ï–i_^¯—O>ù€¨¨(lÏKKKcðàÁìÝ»€ÈÈH®¾újZµjEXXééélß¾µk×’““áC‡î#22’˜˜˜RolˆˆˆˆˆTg‡fÓ¦M 4è´Öÿúë¯éÖ­±±±åܲâ싈ˆˆÈ9cëÖ­üñÄårp×]wñøãS«V­BËåååñâ‹/òÊ+¯““èQ£X¸p!]»v-·¶Œ?ž‰'š–••Åo¼ÁË/¿ŒÛífæÌ™ :”k®¹€~ýúCrr2Ÿ}öO=õÁÁÁ'Ý×?üÀÑ£G1b¡¡¡ö¼gžyÆõ‡ÎÔ©S©S§N±mäåå±dÉ’b½ý-Ï?ÿ<Ï?ÿ|Ù^DDDD¤š9|ø0C† á×_å­·Þbøðá§´þܹs¹ûî»iÞ¼9_}õU…‡ûŽ ÝºˆˆˆˆH5‘ŸŸÏŸþô';Ôâ‰'xî¹çŠ…úPPïþ‰'ž`òäɸÝnÆO^^^…¶122’Gy„'žxž6kÖ,ûuPP7Ýt)))e*½û-cÆŒ±_{½^æÍ›@ll,Ó§OêCÁ9ø€Ž;2~üø m¯ˆˆˆˆœ¬ð¾¬á~i¡þµ×^[áíU°/""""g½ 6ØAy·nÝN¹—w·nÝØ¿?¦i²~ýzúöíK»ví˜1cï½÷žìOž<™æÍ›Ÿq{?øàûu÷î݋Ϳá†xôÑGÉËËcÖ¬Y%ûÛ¶mcÓ¦M 0€úõëšÌõ×_ÏÇŒÛífðàÁŒ;–AƒÑ­[·€ãœ©Ï?ÿœ&MšðÓO?Ѿ}{{úO<Á5×\ÃîÝ»™6m_|ñÍš5cîܹ…Îé#<ÂUW]ERRÿþ÷¿¹ýöÛÕk_DDD¤šIOO/—íTviŸ²†ûUêƒÏ‘s@rr²ýºE‹§¼¾ÿ:þÛ*O¦i’À¤I“xá…ˆˆˆà/ùK±eëԩðaÃØºuk±:ü–’Íõ÷Ïþ“6mÚpüøqÞ|óM† FóæÍéÑ£ÿïÿý?æÎKvvöŸ¿·ß~»P¨Ń>@ff&;vìàý÷ß/v£¤I“&Ü}÷Ý@Á g;vì(·v‰ˆˆˆˆ >œ·Þz‹  ßûÄû¨[B}P°/""""瀌Œ ûu:uNyýºuëگ˫÷Ñk¯½F»víì¯&MšÐ¹sg¦OŸŽ×ë%&&†y󿕸€Pïà[¬2=7æê«¯¸úõë³dÉî¹ç"""ìé>Ÿ;vðá‡2~üxÚ¶mËÓO?m×ë?]íÛ·§wïÞç]vÙeöëž={Ò¡C‡€ËõèÑÃ~m ˆ,""""R^J ÷ï¸ãŽB½ù¡jB}P°/""""ç€àà`ûµÿ‡ð²ÊÏÏ·_;ÎriÓñãÇINN¶¿üó6mÚ°|ùòBAwQ½{÷¶Ÿ$˜;w.n·»Ðüï¾ûŽ””n¾ùæRÛ]§NžyævïÞÍûï¿Ïøñ㉋‹+ôçææòòË/síµ×’——wZÇ Ðµk×ç5lØÐ~ݹsç—ó,8++ë´Û"""""R’@á¾×ëÅçóÙ?WU¨ öEDDDäà_›ótzÜû¯U.m4hÓ¦McÚ´i¼úê«Lš4‰K.¹€Ý»w3tèP~ûí·×7 ƒQ£F––Æ¢E‹ Í÷ïÅ?zôè2µ)""‚k¯½–É“'³xñb<È·ß~ËM7Ýd×±ÿùçŸíRA§#22²Äyþ7J[®hÏ)‘Š`…û:É8Î* õAÁ¾ˆˆˆˆœZ¶li¿Þ¶mÛ)¯ï¿N«V­Ê¥M^x!£FbÔ¨QÜrË-<ôÐC|÷ÝwLž<((1s×]wašf‰Û5jGÁGzÿ ÿ·ß~cñâÅ@Ay›Ö­[ŸVƒ‚‚èÑ£o¾ù&/¿ü²=ý½÷Þ+ÔSIDDDDälåóùJüLîõz+¹5¿S°/""""g½öíÛÛ=Àããã ÕÜ?™¼¼<Ö­[@xx8:uª6ZÆψ#Xºt)_|ñE‰ËžwÞy\qÅ,Y²ÄØwΜ9vOö²öÖ?™qãÆÙ75233Ù¿¹lWDDDD¤º²Ê Ô©ÅëõÚêVû""""rÖs8 8·ÛͧŸ~Zæu¿øâ Ž;ÀÿýßÿV!mô÷ÔSO ÀÓO?]¨ÆQÖ ºÇ>.«÷~DD×_}¹µ«mÛ¶ö뜜œrÛ®ˆˆˆˆHuc…úþ¥Ng¡²<§ÊÂ}û""""rN¸çž{ìד'O¶–-ͱcÇxúé§nÃb¿.-€?±±±Œ7€0{öì—!;;Û^&77—Ï?ÿœ^½z±|ùr à¦À”)Sn³k×®ö‡úçž{ŽŸþ™£G’œœLrr2.—ë´ÚÚ¨Q#»×þ¡C‡˜5kV‰Ëúøk×®  îÑ£G©ûÈÏÏç©§ž¢cÇŽ<øàƒüðÃ…ÎÀÑ£Gyùå— Õê¿ÿþûOõpDDDDDª½“…ú–êî|‘³CXXóçÏç¶ÛncñâÅ>|˜»ï¾›¿üå/4l؇ÃArrr¡ò×\s o½õ–=ønQÑÑÑÜzë­Ì˜1ƒuëÖ1`À€BógΜÉàÁƒO«½&Làý÷ßÇår1eÊFEppp±åºvíJ‡ضm›=íTÍÍÌÌä½÷Þã½÷ÞÃápРAêÔ©CVVV±’E·Þz«ý䃈ˆˆˆTœzõê•ëöÒÓÓËu{g›²†ú–áÇpçwÚëXá¾ÿüŠ¢û""""rN©U«sæÌáÃ?$..Ã0ðz½=z”#GŽØÊ Ã`ÆŒ|úé§DEE•ºÍÉ“'óÒK/q饗Uh@­3ѨQ#;DOHH`æÌ™%.ëä;FŽyÒíGFF2wî\n¹åš5k€Ïçã·ß~cß¾}…BýîÝ»óÑG1uêT Ã8ÝC‘s@½zõÊ嫲|ýõ×§ê[J빿`Á‚ m³‘žžnVèDDDDDª±ääd¶lÙBJJ n·›E‹ñõ×_Ó~ðÁåÔWwGeçÎ$%%‘——GDD5¢cÇŽÔ¯_¿ª›'"""rN©©=ö+"¯è¶9r„¡C‡²oß> l¡¾¿Ï?ÿ¼PÏý6mÚ0þ|7n\amV°/""""âÇív3räH–.] À¸qãxå•Wª¸U""""r®©©Á~Me…û §ê[¬pÿ‚ .¨ðP싈ˆˆˆsüøq®½öZÖ­[ÀÃ?Ìc=VÅ­‘ŠtäÈâããéß¿ÿi­¿`ÁºvíZá¡>(Ø (##ƒ§žz —Ë…a<ðÀ´iÓ¦ª›%"""""¢`_DDDDDDDDDD¤&qTuDDDDDDDDDDD¤ì싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©A싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ(Ø©AjD°¿f͆ Â!Cp»Ý…æåääØó~ùå—*j¡”fêÔ© 2„'Ÿ|ò´Ö×ï¸j¼óÎ; 2„¿þõ¯UÖ†/¿ü’!C†pË-·TY¤âÝÿý 2„÷ß¿ª›""""""""R#Tz°¿uëV7n\¦¯Ûn» €ÔÔTV®\ÉÊ•+ñù|…¶çñxìy•}8¢]»vö9hÖ¬iii']ç(tî>üðÃJhiÙìÚµ‹•+W²uëÖÓZÿlüŸ®¼¼Ÿ—ËU¦¯¢½óÏyyyö9ÈÎÎfîܹ¥.Ÿ››Ë¼yó ;¯×[I­•ÊFÇŽq¹\üøã%.çõzY±b…ý~øé§ŸJ\öðáÃìÞ½—ËE÷îÝ+¢ÙRÍø_‡Ër­ðz½öòEo®ŠˆˆˆˆˆˆˆHå ªÊ?ôÐCôïß¿ÄùQQQôêÕ‹Å‹Z)m«4h@jj*³fÍâŽ;î(q¹/¿ü’ììl{ù³MíÚµíßÛ¶m«¸5U¯wïÞ¬^½š;w’’’Bttt±e6mÚıcǨ]»6ÙÙÙ¬X±¢ÄíùÏëÝ»·ýúž{îá†n víÚå{"""""""""rFª4Ø¿à‚ ˆ‹‹;érQQQeZîl3lØ0f͚ŦM›Ø¶m:t¸Ü¬Y³¸ñÆyã7*³‰•Âétž“¿ÿ’ôîÝ›_|Ó4YµjÆ +¶ÌÊ•+}úvÒõW¯^ÍÏ?ÿLff&7¦_¿~´lÙ2à²^¯— 6=ö### Íß¼y3n·›óÎ;Æãv»Y´hÛ¶mÃårѺukH½zõNÚ.ÇÚ5kX¿~=iiiÔªU‹N:qå•W^†3SñºwïNhh(.—‹•+W–ì÷ìÙÇüyóX±bE©Áþe—]Fpp°==!!¤¤$j×®Íþð‡B뤤¤pàÀ Ãàâ‹/`ïÞ½,^¼˜£GR·n]zõêU¦Ò>yyy,Z´Èƒ¡U«V 4ˆ:uê”ñŒ@ZZK—.eÏž=¸\.bbbèÝ»7^xaÀ勾gŠÚ±cÙÙÙ@àkNnn®ÝÞN:{ÏïÝ»—åË—“€×ë¥^½zÄÄÄн{÷€¿ƒ³Iy_g÷ïßOjj*uëÖ¥M›6x<–.]J||<ÙÙÙ´hÑ‚AƒSÎG""""""""R}Õˆ`åÊ•Œ3(ÊûËÊÊâÑGå“O> Xzذa¼úê«Ô­[·\Ú[žFÅçŸÎgŸ}Æ?þñ‚‚ ÿÊfÏžiš\uÕU4iÒ¤Ôm­X±‚‡zˆ;wœ_·n]ž|òI{Ðâ@²²²xì±Çøä“OÖæŽˆˆ`úôé\{íµ×OJJâ¶ÛncõêÕ…¦Oš4‰|Ç{¬Ø:ÙÙÙôë×€¹sçÒ·oßBóÇŒCBBO>ù$½zõâ¶ÛnãðáÃ…–‰ŒŒä7Þ`РA%ÛÂ… ™8qbÀHPP·ÜrK±õÓÒÒ8p »víàÒK/åÊ+¯¤~ýú¤¦¦²víZ~úé'Ž9pÿÙÙÙ\ýõìÛ·áÇӦMŽ=Ê¢E‹8zô(/¾ø"­Zµâ¦›n:¥sdÙ¶m/½ôŒ7ŽF±wï^¾úê+²²²øÓŸþÄÊ•+ö˜þðÃyà0M“óÏ?Ÿ¡C‡Ò´iSÒÒÒøïÿË®]»¸í¶Ûxçw¸á†N«}åɪ³¿}ûvÒÒÒ¨_¿¾=/>>žÌÌL5jD«V­ðx<Àï=óýùO+ì—Õ„ ˜5k—_~9Ý»w'//ü‘-[¶°hÑ"yä‘€!ýæÍ›¹á†8~ü8‘‘‘Üxã´jÕŠÄÄDæÌ™ÃŸÿügXê¾|ðAÞÿ}:tèÀµ×^KíÚµÙ°a_|ñ+V¬àšk®aÉ’%4mÚÔ^ïŠ+®`É’% Þ¼y³ê,[¶¬X°o­wÙe—ºfÜ{ï½|ùå—8®¾újââ∊Š"99™„„–,YBFFÆÉOj S×ÙôôtþøÇ?’’’˜1cèØ±#)))Ì›70qâD Ã(u<‘³E•ûû÷ïgݺuç…„„йsç3ÞÇ„ ؾ};‘‘‘|ùå—…jˆÜyç :”øøx¦L™Â¤I“ÎxŸåÉáppóÍ7óÊ+¯0kÖ¬BÁþªU«Ø¿?QQQ 4ˆÌÌÌR·ÕµkWV¯^]¬¬ ÀÓO?Í<À§Ÿ~ÊSO=ÅÿøÇbáÛý÷ßÏ®]» á7Þ`øðáŶsðàA»„IQ?ÿü3M›6eùòå…Êr¤¦¦2lØ0¶mÛÆ+¯¼rÚÁþgŸ}Æ•W^ÉG}T¨¤Ð¦M›8p ¹¹¹¼ñƼôÒK…ÖÛ¶m?ü0¦i2zôh¦NZèɈ¿ýíoÜ}÷Ý|öÙgL˜0¾}ûÚ;W•¢uö‡ bϳzñ÷êÕ €víÚMbbb±:ûÖ²tíÚõ”Ûár¹øì³Ï˜5kV¡Þãñpï½÷2gÎfÏžÍã?N£F ­{ß}÷qüøqÎ;ï<¾ýöÛBõüÿú׿2|øp¾þúë÷½hÑ";Ô¿õÖ[™2e N§Óž?vìXþøÇ?’””Äý÷ßϼyóìy}úôàðáÃÅΉÚ7mڔÇóã?rß}÷Ú·µŒµ(xeþüù¼ôÒKŸ|ÉÏÏ·KøT¿þú+ñññ¥.è)•q]¿~=uëÖeñâÅ…n´<ôÐCŒ3†%K–ðä“O2pà@ !"""""""g=GUîü¥—^¢_¿~¿¬Ò;gb×®]vIŒÉ“' ›  ìž8q"3fÌX^¦ªY½ñ-ZDZZš=Ý4wĈ„††žt;]ºt êCAy——_~™Zµj‘ššZ¬ww||<ß|ó Pt õZ´hAÇŽKlÃk¯½V¬Övƒ øë_ÿ ÀÎ;INN>é±R»vmf̘Qlœ€‹.ºˆ›o¾((«RÔ”)Sp»Ý´mÛ–—^z©X¹#§ÓÉ«¯¾JÆ 9vì˜}Þ«’UgŠ÷Ä·~¶‚}€=z”ºìe—]Vì¸Ëê¾ûî+Ö³>((ˆþóŸ†×ë-¶ß+V°yóf à:P4ˆµJ'9%_¢^}õUÎ?ÿ|&Ož\(Ô¸üòËyðÁXºt)[¶l±ç]xá…ö˜ EßÖÏ?ü0†a°jÕ*Ün·=ÿàÁƒvÐ}ÅWØÓ0M ÐÁÁÁ¯CUé¹çžãŠ+®(õ«´ ¾7” IDAT2¯³“&M*öôDXXÓ§O'<<œ¼¼¼€%¡DDDDDDDDÎ6U쇅…ðëTÎ,Éüùó1M“Úµk3bĈ—»þúë‚RÕ­7-@ëÖ­éÞ½;n·›¹sçƒw~ùå—@ÙÊð”EDD:t(‚|õÕW„††žv©‹ÆsÕUWœ×­[7ûõÉz—¤ÿþ…JÒÚ¾=t(èAýí·ß籤!aaaôïß `]ûÊfZëš›¦i_àì÷ìÙ(Üöääd»Vùå—_~Úm9rdÀé5"66(þ;µjö7jÔˆk®¹&àúmÚ´±oH•m#0fÌBBB.7nÜ8{àÛï¿ÿÞžîp8ìcö/Çãv»Y½z5‡ƒk¯½–N:‘››Ëÿþ÷?{kùÈÈÈB!¶u¬@©5ö«›   BCCKýòT¹¨ÊºÎ—ø^‹‰‰±o.BDDDDDDDälT¥¥x¦L™Rn¡t ëׯ ÂÃO?ý´Ôe ÃÀ4M:T.%€ÊÛèÑ£Y»v-³fÍâŽ;îàË/¿$;;›öíÛŸR •œœ>þøc¾ûî;víÚEFFF¡ÞÈÖkÿã7n z:ŸîM—Ö­[—8Ï¿´Í±cÇNkûEŸ´ýüü|Ün·oß¾Ýt5--­ÔÞøÖ99tèÐiµ¯¼õîÝ›U«V±uëV222ˆŠŠbË–-dddРAÚ¶mk/(Ø÷}ºõõ-[¶,q~TT‡.ö;µ‚Ý.]ºØÁ{ ݺu 86ÀŽ;ìZ­ÄÄÄТE 8PìfUŸ>}˜?>Ë—/Ççóáp8X»v-¹¹¹tíÚ•¨¨(úôéC||<Ë–-³o”XÁ~ïÞ½ =%KïÞ½Y±b<òŸ~ú)ƒ¦wïÞtíÚµÔp¼*ýûßÿ>éuø›o¾)ñ)ªÊºÎ¶nݺØÓ8þºvíÊçŸn¿7J{ÚCDDDDDDD¤¦;«Ïýí·ßØ»w/÷Þ{o™Ö9ÝP¹¢ >œ‰'²iÓ&¶mÛfЧrcdûöíŒ1ÂÜÖápMÆ í€2!!¼¼<\.W¡u­P»qãÆ§} ¥• òw­r&µ}+†ßß#ð{i—“©.ï‘Þ½{3yòd|>«W¯fàÀvÞ³gÏBÇÜ©S'"##ILLdß¾}´lÙÒökÕªuÚåa‚ƒƒK P­6ýZÈ6lذÔíGGGœî?mLLL©Ûhذ!(6h­UF'--øøx.ºè¢bµóûôéÃ믿βe˘4i¦i²|ùòBËø{ûí·¹í¶ÛøùçŸY¿~½z‡‡‡sõÕWsûí·så•W–ÚÞš¦²®³'{¯Xó½^/YYYU>†ˆˆˆˆˆˆˆHE:«ƒ}Ë…^Xb ‡¢üKÂT'µk×fèС̙3‡^x+VÄ7ÞX¦õ=cÇŽåÈ‘#´nÝšgžy†+®¸¢Xé™Ú%NüYámuƒ ¼<ðÀ' ‰r)U.¹äBCCq¹\¬\¹²P°ï_† ~—^z)‹/fÅŠ´lÙ²\êëŸ.+ð?Ùû©¤ùþ7-N¶ ëFNÑ­[·&66–#GŽðã? ö{öìIpp06làØ±c:tȲûMš4aáÂ…¬]»– °jÕ*6nÜHnn.ß|ó ß|ó ÷ÜsÏ<óL©m®‰*ú:{²ß³Çã±_oADDDDDDDälsVûVHÆÝwß]Å­9s£GfΜ9ÌŸ?€~ýú•)ˆX½zµ]O}æÌ™´k×.àr)))§[ûIHH8ÕfWkþçïòË/çꫯ®ÂÖœ«ÎþªU«X±b¦i²jÕ*à÷Ò;þzõêeûd×®]Àé—á9Vïê£G–º\bbbÀéþ=ù‹ ¨êïðáÃÅÖ±ôéÓ‡Ù³góÓO?ñ§?ý‰ 6Êe—]Œ;ÇêÕ«Y±bû÷ï Þ7%ý‚‚Á»w±dÉ^xá¶lÙÂôéÓ¹îºë¸ä’KJ=ö𢲮³'{¯XóCCCK-Ù#"""""""r68«‹[ÁÙ† HMM­âÖœ¹Ë/¿œfÍšÙ?ŸJ+Ô¯[·n‰äÑ£GÙ»woÀyqqq@A9Ÿ’ÂÖš¨}ûövè?¸jMa…òñññüüóϤ¥¥Q·n]:vìXlY«ÿÊ•+ Õ­¯Š`ÿ¢‹.à—_~)VöÉŸ5pQíÛ··K/Y73Ù³gø*7dõº_µj?üð‡îÝ»z’ÅZfÙ²eÅzô—Exx8C† á‹/¾°{’[å|ΕuÝ·oIII%ηÞ+;w.uÜ‘³ÁYì1‚àà`<Ï>ûlU7猆Á»ï¾ËŒ3˜1cýû÷/óºÖÀYYYdff\fÊ”)%Ö·>|8AAAx½^žþùSo|5Ĉ#øðÃ9pà@Õ6èY¡¼ÏçãÅ_ GëÞwéÒ…ˆˆŽ9ÂG}œY}ý31dÈ àýXÒ€Å+W®,6à­%$$„k®¹(x¥hý|Ë믿”f8p`±ùV@Ÿ››ËË/¿\hZÑe–.]jßD8•`ßÒ A"""€Âã<Ôt•u5M“7ß|3à¼;v°lÙ2à÷÷–ˆˆˆˆˆˆˆÈÙì¬öÏ;ï<{0Çwß}—I“&´1''‡Ï>ûŒûï¿¿²›xÊâââ>|8Ç·Ãú²°zÕš¦É£>ŠÛí¶çy½^¦NÊŒ3JµY³fÜ~ûí@AþÄO››[hŸÏÇÒ¥K퀭¦xøá‡©_¿>999\{íµ%öߺu+>ú(?üðC%·°dV}(ž!p(¸‰a½¬e«¢¾>@ÇŽí`þñÇç§Ÿ~*4ÇŽŒ?¾Ôž×&LÀét’ššÊ-·ÜR¨·¸išL›6>ø€‘#GzÚÅÒ¸qcÚ´iÀÆâ¡ýÅ_L­ZµØ³gÙÙÙÀïïúûî»ïxâ‰'ؽ{w±yV{¬ëU¦çlPY×YÃ0xíµ×˜;wn¡é Œ;¯×Ktt4cÇŽ=­í‹ˆˆˆˆˆˆˆÔ$gu}( ýõWæÎËôéÓyÿý÷‰‹‹£Q£F¸\.:ĶmÛp»ÝtêÔ©ª›[aÚµkÇõ×_Ï_|ÁìÙ³Y±b—\r ‡ƒ5kÖð믿ү_?²³³K ¶Ÿzê)öîÝËâÅ‹yýõ×ùðùä’K¨_¿>iiilÚ´‰””ž}öY®¼òÊÊ=À3ˬY³9r$‡bРA´nÝš:Bzz:[·nµKºTEéš’ø×Ù·8×_Ïž=ír2PµÇ2uêTúõëÇáǹîºë¸ôÒKiÕª‰‰‰,_¾œððpþüç?óŸÿü'àú]»vå™gžaâĉ¬X±‚Î;Ó«W/êÔ©ÃÆÙ·oŸ½ÜsÏ=Wb;úôéc‡ñuêÔ¡k×®…æÓ³gO/^ @Ë–-Þ$ÈÎÎæõ×_çõ×_§E‹têÔ‰úõë“••ÅÆ9xð Æ xc &«ŒëlïÞ½ÉÉÉaüøñL›6:ššÊ²eËp¹\3}út¢¢¢ÊùèDDDDDDDDªŸ³>Øw:¼óÎ;\}õÕ¼òÊ+ìÞ½»XïàÐÐP ÀM7ÝTE­¬Ó¦M#<<œO>ù„„„{ \kÐË'Ÿ|’n¸¡ÄõCBB˜={6o¾ù&¯¾ú*ÉÉÉ,Y²ÄžoqqqłњàÒK/åÇäÙgŸå‹/¾`Ïž=ö¸–V­Z1xð`.¾øâ*je`—_~¹ìתUË®_HÑп*ƒý&Mš°`Áî¿ÿ~–-[Æš5kX³f PPƒÿ7Þ8éÓwÞy'Íš5ãÉ'ŸdÏž=vøÿ®ÇÇO}웽{÷¶ëà]ÆÚvI¡üþðÈÊ•+9xð ä[êׯÏwÞɃ>Xê1ÕD•q áÃ?d„ ÌŸ?ß~ÂàüóÏgêÔ©§U"IDDDDDDD¤&2ÒÓÓU?Kíß¿Ÿ]»v‘™™IXXM›6¥C‡„‡‡WuÓ*ÍÑ£GY¿~=¹¹¹4lØnݺÙÈ–•ÏçcË–-Ÿ¯Â$"""""""""""§G5öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDDDDD¤Q°/""""""""""Rƒ•4Ã4ÍÊl‡ˆˆˆˆˆˆˆˆˆˆˆ”z싈ˆˆˆˆˆˆˆˆˆÔ öEDDDDDDDDDDjû"""""""""""5ˆ‚}‘DÁ¾ˆˆˆˆˆˆˆˆˆˆH ¢`_DDDDDDj€| ÈÀ ƒ40³€<ÀWµM)GË—/çºë®c̘1dddTusD¤š2ÒÓÓÍ@3ÂÂÂ*»-"""""""…™¹F˜™FàÓ†Æ4ÃÀ¨iF‚QpVqƒÏŒÏô‘éÊàHÖ¯$d"#7‡aP7,Šóê6'¶ÎyÔ ‹Âaî§wÜÃS?¤æ3MÓ41 £LË—u9Ó,gfýlš&‡Ó4q:«÷¿‰´´4.jß–;Zgg&l‹hÇÌ?¦C‡UÝ4©"yyy§•´B  äéòz½äå呟ŸÏW½zR8‚ƒƒ «ð‹»ÎÙñù|äççãõzËõýY ÃÀétŒÃQ±Âè<Ðy(YVV»wï&##£Ä‹MFTTmÚ´!22²ª›#"""‡A˜É`¦cp Ì0]€0ÀÆ Ó¬A¦Ù“h0«ºñ§,/?—owÍgáî¯Øö[<ÙFÎΠ‚Ï“>¯Û¤uésÚ e`»a;‚ímäæçÑï&°>ógœ® îw=LTX½ m·ËåbÕªU$&&bù;7;'‡üüü Ý¿%$$„Z4hЀþ”9 –Šåóùðù|„‡‡üœÊ4ÿ¿ýüCû¢ß}¸Ýîjß‘ÕápàózèÑРO#Xzt'ú^Åko¾Í°aêºy"R”Øc?44´\vàr¹HKKcãÆlܸ‘#GŽ”ËvËKll,]ºt¡K—.Ô¯_¿ÜŽ»(‡3ãñxÈÉÉ)öaÀápàõz1 £ØkŸÏgÿîÿ³õ¡Âº¹b¯Ö÷¢ó¬u­Ÿ­×AAAø|>‚‚‚ÈÏÏÇårL­Zµ *ñž™ÎƒÎC…:tè[¶l©v7;*ŠatêÔ‰æÍ›WuSDDDÎIGŽaãÆög,ë³—õ¹Ëÿ³VI_þËÙ6La¡Y„‡gžMXH¡¡¹„»q:=€Ÿ¼^—;ˆüü0Ú¶»”f-.Æ4b±@íª>=e’çÉeÞÖOøÏ/ÓÈr¦S+:Œ°º!8œ…;ˆ8 'AŽ Ÿ“ÜL™ÉYÔöDq×%÷3´ý x¼ù<²èÿ±-w#í;üíëv1ï¦EÔ ¯_amÏÍÍe⤿³2§ÙµÏ¿0ÖðyiûëÅÞ's®ž‡„„Ú¶m œ‡Óáv»ÉÌ̤~ýú¸\.|>ŸÝ;88—Ëe­V/i+Àu8ö ŸÏ‡Ç㱃]+Ѕ½´­^ØÖ|«'¶âz<‚‚‚¶ãs¹\x½^BCCÉÌÌ$$$¤ÜïÓy8·ÏCYþ=íÞ½Ó4iÖ¬ÑÑÑUR¨2†App0ÑÑÑ@ÁS »wïæâ‹/®â–‰ˆˆœ{òó󉊊âøñãvÉÓ4 )Öq¢¬½tÆ1œŽ£F"ÇQF2# ‡‘ÃÈÆ0\€IA°ïjY»Q‘9`&t7‚À Ç$–êZscâzþºà.rëeÝ&ÃQBú<¾‚*C£à ÃAáÄi8q:N|ú£ê…Q?ª‰ É9vœ /êDHpÞ|PñáþÁC‡ÈŠê >wžâî‹…úÖÏe-cküþ=?¬»<Á?Ìfô˜1g]g—š®èM½@AÑïÖ=ÖÿàÞ?è÷ßV ›Å4M–.]ÊܹsY¹r%©©©téÒ…›o¾™þýûc/›ÍªU«˜?>_õÍ|¿1°©ƒ;ãà—Tx>ÞdsºÉ±ü‚«Ó€M ž¸ÈÁÇÛrÕUW1kÖ,Ú·o_¡Ç$"Õ[…û‡””’’’*r7å"))‰””š6mZîÛÖy83>Ÿììl¢££ñz½áv»í× W­^Ù.— §Ó‰Óé´{kv kõöµ-½bmËápØû‚‚šþõø<=Íê%Fvv6 4ÐyÐy¨ÐóHFFõêÕ XJèlaÝpq8Ô«WC‡ÙÇ."""•Ë Ê¼^¯ý™ÊzÂÑú¹¤-p‰ †#Ìß0Œd ’qŒÃHÁiÃpƒ > 3È_õ¢r1Hœ`†µ€HLêVØñŸ®ÍI¸÷›[qÆú %óHy.ÂÍÚÔ®ƒiúÈÈOÇê¡vý¢¢#qôØ2‚p:‚rœønѲÕ¿O3‚ÀðR9¶Ïë-ÖSßvû7M³P o½.3¿}zB"Y÷/Þ^úOòóßSYžjÂÿŽõ·•Õ ®VÉ «dŽõ·Óé,à}o½¾ø˜[ýòË/ :”±oP¯lJû‘Y_ÆÄû!¢~cêÖ«GNv6éI‡iUËËe ^lgp七ÅGL¦l-8¦àÿ¬‚àöׄ¯59˜mòTkSv1ðÿ®bê´7¹îºë*üØD¤zªðR<§ÛK»*äææëURtÎŒUÏê)íõz #//ÐÐPrssí?¬^Û^¯×.Ëb­S4àôïÍìß#Û p}>yyyvïï¼¼<""" •u±zk[ûòz½…Âc‡Š:XåZ=XÎÆP(4Æu¬gë Á"""Õ] `Í? +:ïd¯FNã# ‡#§#‡# §ã†#Œh £ x1Íã`¦ãp¤P72ƒ4LÂ1¨ƒI ԪϓŒi¹©<´ð^Ìò2=Ô΋à†6#èÛkÍ£Î'4( L“lw6Û’ãùfçYµýGê4Ž a“¿÷ØÔ‹ÿÄÏ•ÐY¿°3ØŸõ²k¡é­ʽ¬‹„û›»LâýŸþILÌ7 2äô*g¤hÍûÌÌLöîÝK~~>qqqvÇ+·ÛM||<ùùùtèÐzõ 6 Ãþì_´Ž¾Å¿s“ÇãÁ0 {»%•+OÖ>–'›ü_¬Áyµ zÆ@ϯÏ$ÝÄqo¡õ¡^HÍsðÝ“¿­ó‘™u‚ ahA¡1—·àËW¤¹ñ0÷ É¸ÖšÕÊæowÜÂæÍ«î¾È9ªBÿÕ½ÈVwÕ^‡3gµÇ꥛ŸŸOxx8¹¹¹öw(¸ƒo…ªPðh°Õ[~ïId•`"HœØ¾ÕsÀúÑívÛí.4ÐŽ Ù7C*òÜé<è<”…u gc¨o±ž¢P¯+‘ªå_£,Á}é¡¿‰aäâ0rp8² ¾ÇN”ß©Fc £õOÔÎ÷b˜Y`†aú <<ÃÈ¢ —~Ù@&n |ËCSÆÏ|^ÓNj˟&ÕHÂL5Ôb8ôz„èˆâ5èë„FÒ¤N,}[õgÓÑõ<÷ã“ÚµŸÖZÔÛ?Ñ[ßi}9~]©÷1 û§ð1ÍW$ô-îŸH÷tÛâ«GÂy8p`sÙ$.##ƒØØXÈs¹ˆ/Ãú+**Šôôt;؇ÂåvŠNóm•í±zøW¶<±ÁÇ“9èÖ `ÿN‡Aô‰ËÐÎL“7wùX›aˆ †&á>³ g¾Çg|7‹ûNÚFl³M¤Á+›<ÿÎ ª»/rŽÒí<©1¬ ÏçóŠËå²C\ëgÀ.ÉbÕV·Vkÿ°³hˆ á¯ÕÀãñ؃¢ºÝnÂÃÃ1MÓŠ­ÇŒ+“Îö>uDDDDª–'†¢¡ý©‡û&#чÃÈÃaäbÇ1 8¢0Œàh‚a49QŽÇ f*¦ ‡ ‡³¦ï8޹¿™n0*&ØÏÏÍ`ãï"?· eWM“'ßß‹3ÈÉ—>Æ-ý¹LÁãE»ñÞðOùû’¿±vû þбM±ÞúA'~²{ìWb yšÁ¾Üûù>«ωi¾S-Ű-Õç‰s™Ï4É÷šx|&µ£¢Ù±s˜8CÈË71  )ø[ëØ±ctîܹØ6…úE§U‡Î?¹^øûF“:;èÑð÷öÌ9àãÝÝ&¡N¨ AFA }—·àVA°_ðå5ÁúkÕ:FÁímtˆú}{uC þÕÞݶ>W\ÁìO>¡C‡•y¨"R…JL Ê£—©u—ôT”gÙ ÿ2˺ïŠè­~:ç¡*Uäy8Ýõ¬÷„æBA½=«üŠÜæçç*‡â?ø©Ûí.ÔÓ»è>¬ÛÖ<—Ëe¿‡<vikEÛeÕc¯¨ó§ó óàßF)LçDDD¤ò•ôÿïÉ‚üÀó}†0ò1Œ| #ƒ00jƒQŒÆàhfΉ dF¸0M7¢·~~=™íe×O“ip^KÚôz®Lëìúi*lÞŨη3êÂq'¶S¶¶……3©ÏÓ úð ÒR z;ê­ï×cßç(+åiì’2Ô“d«EK³Øáþ‰Ÿý_Ÿq[üöY•œ?Ì è«ÿàØ´üŒ¶ç»èr&^hpy£‚¿+¿ýÕ+Ì÷ׇqâß+=ô=¾‚uó}5ö/‹†ëš;èeØcgøL“Tdº!2¤ ð_–´—Aý®fÊ«Ó>|x…£ˆT/Õ¦k©iš4iÒ„›o¾™ .¸ XÐvª|>ûöíãÓO?%11±Zܱ-OÖ Ã0ìï†aœñyg4S“ IDAT«Î¬@Ö?Ì ³Õó/¹bÕ`÷øÔê­m…ºþõÇ‹ž·üüüBuÊ­²+áááÅÂ\ÿïÖþut*ë<ˆˆˆˆT¥¢¡”ä—a˜`˜':_›Ô•qN ‚ zß‘'‚Ót`àø½/`bRпbB¼£ÛþKvòZº×ñ•eZç† ;PûÐzºGµ+¨… Ž»sxzÙc„Ô "¦aÃëë;N|tÌ%:Å?·íP¿È÷€á~¹ôØ?µöIÅH;îeO–\/'Rl^wA-üºáNBœ¡A‚ ³ ì.’ã”v#Ñ?´w:öÓÕþËT…|ž‹7qû|ômâàæ ^ÙfÚõóýƒ}ŸY°|¾š„C¿Xƒkb ¢C }¯Ïdc,O2Y—Zì{Í‚õ{4„ í4‹ÈæÑ»Ç±yófþþ÷¿ŸÕ‘ˆTB°_Öÿ„óóóéׯ±±±v 3Õ´iSúõëÇþóŸBu°KR5ÁÏ„Ïçãÿ³wÞñQÔùÿÎlɦ‘„"5ÒBè €HÑóh¢¢pÊY8±+bá§€"Þ}EAÅÃ;‘ÃC¤ˆõÄñ¤ŠiRH'Ò7Ù6Ÿß³3Ìn6•l²Ñ}>0»3Ÿùìg>;;™y}ÞŸ×;%%…®]»’œœLRR‰‰‰Øív233¹pá‡fË–-zâÏšjkU#„xL²,ëb®¡­ ¾Æ×n·»˜·qfˆQÖÊj­ÕjÕE\—Ëå#—&“I6 ÷C¸ª£„ &L˜0ajš’f[WNÜ—QQÍhB¾À 8§º .¨þ¢D.‚"À‰ðFæ É„Ð$­®ª%?óégÐá7b¶„RP®ýl¸¡ÿ`v}ó&1ñ͈NlQ®ýò\vž_3™ƒÎ½tèÜ‹Éâë³/ûFí{¤j̵TA1]·ßñòãkƒ¸o±XˆŠŒÄ@ ŒŠŽ.÷çÖ$Z¤¾uÖ#H ¼>è½RÔ¥¬5ZòYè¿^ãuSVºº»·^§·T¨FîŸ/ðp0[¡À (Ó…ârc’d’㬲L£X3Ñ&& ›SEQðx<Å’èº\.Ý.UÃßs?eOuâðúã0¸±L”YáßEê#³ WDA÷$‰>Émë¨íW„ =OðÝÁ÷gnˆðºmYdðx6dÀ¯ù Ó»ÊÌì&xõý×Ùµkï½÷žOž‚0aÂü¶zòÜòÚêѶm[ݲ¦°°¢¢¢J}®Íf#Ò›x¥mÛ¶8Žr ûÁá*Ò%aµZ¹ûî»i×®O;N'f³™ РA:vìÈ AƒX¾|9?ÿüs¥FgCMŒÔnúŒâªæe® °V«5 Ðk$2z«kýHÀ5®×ÄY›Íæ#âjIYµ¥¶O°lWÂýî‡0a„ &L˜PÄÿ9çò"÷M Y á]B>ˆ|Y¢@ÊÜ‘ ÊUàWòAJBM”Àê]Ví,J»ˆýßý•]Û“`FÙÚ?&ÎD‹.mØ÷íSÈ&k™åóÝnÞqe‘S?’Ô´¶˜M¯åŽ)`Ô¾*~ò4TcTuI‰rý£ø6lÈk3f|¦Žöö+i &ø!ÈÈ÷p(GM.ë*rs1¥ÐIRR.ÉŠŒB»DgîCx\¤¦¦úˆÒ§˜ÆQ–~aŒæ¯Iàû.Eá¦&2½ê Ž@®¢-Ð bÍ—¬vr‚ïÏ)¬<¥–‹1C´¢ÍNEPä)žX÷¤þu@áÅÎ&þ¯³Ì¼ýßrÝ€,\´ˆöíÛWû1‡ &ø„”Ñ‹~Ú´i8p RuµiÓ†_|ѧîÚŠ¢(\}õÕÜxãz¤pih–#wÞy';wfáÂ…U–³ Ð"®K ³Ùìó^Q=zzóæÍзo_}›Ö/š¬Õ©¡%[µÙl¸Ýn×è¥Õ³PÙ~0¶Uëƒp?Ôþ~|2228pàÄÅÅ‘ššJ\\\M7+L-Çáp°wï^233©[·.©©©ØlÁIî¦t}ôQŽ9Ÿþô'ÆŒã³mΜ9|þùç´mÛ–7ß|³ÚÛ–ŸŸÏˆjäåÔ©SéÞ½{µ·¡¼¤§§óØc0wî\š4iRÃ- SïŠ'à ü¾tq? !E!ˆVÿ‰‘,e# 5XK`( ò€ q—«A,ƒ$Å D4 ”-žWÓŽ=û8Rú‚È©T®¬Oý¦ñ”uËèVƯß@¶9’Öm[a1[½â½I_ʘ‘‘%õŸ K* ¨ë‘ùF ?O}£X+Ë2ñññåoGŠøš§¾ÔØ{õbÕ¥Õ;›Ää}nñ Ü×~K÷9%B•t$“ïç„jÄ~F¾›Ãy& ]‡ÝžHv…l\DEšp¹ábB‚ÍFlT'Ož$..Žäädl6V«zÓêñxhݺ5Ï<ó Ó¦M«Pä~(”4ëÁ(æj‘×þØ&“‰Ý»w#„àĉôêÕ‹FóT7úµ[­VŸÈo£­‹Ö-:Ûb±è‘ÚöPí§Ó0Â!ܵ³‚…‚ôôtvíÚÅîݻٵk‡ÂãñÁöíÛkº‰ÕÂŽ;Xºt)_ý5ééé>Û$I¢OŸ>L™2…Þ½{×P «‡={ö胢¥Ñ´iS~þùçjhQÍáp8صkÛ¶mÓÿýúë¯!¸þúëùøãËUËåbÚ´iÌ™3‡œœK‚P:uxà˜/xe·‚jt¾UV]šœ5gˆ"T[·7Á®1bÿŠ("Ó¯ïuv@‰fÑ<ûàÝüüóx&Ožìcq&L˜ÚMHýšµh}“ÉTéÄ“&“ɧ®ÚJBBƒ ò±ÉËËcÅŠlÙ²…¬¬,=i§Õj¥I“&ÜvÛm´nÝZ-###9r$Ë–-ÃdªzoÉšÂ?:Û¸N‹ªÖ(((Ð}ø<k×®%99™=zø¾f³“É„ÕjÕ-^Œç“fÿ¢ÍŽôÄÅÕ=(RÞ~ø÷¿ÿMff¦O¹øøx† æ³î›o¾!??¿X¹‘#GÖº~8tè1114lذØùà8{ö,±±±z}þçÃÇÌÅ‹HLLô雚âèÑ£ <¸¦›Qã\ýõ>×ßèèh¢££9þúˆ¿ýío¥ ‹-ò¬¨©žP¤4ŒŠ'ÏÕ:'Eä#aGEHx-•,.‚Èö†( n@FñdgÒD$”„D„¨4QWÙA׋­¼Ü³9®ò½9n~ú&žwþ(KÖrXý\6%zìËìnÿϽûu”.­%‡TþúžkŠã—´G ^õ¡…¼Sô¤uåýoõ>Ãt½]]¦¯V—…~¹‘Þ¨õ”ëÔåö¥êÒìÝß;@^³® []õ8Ü‚,ÈnP\ Ün7¸e·"(t ÍtìØ›Y*öŒç?°¯å`Ð^ðþúÕµ/ãMˆëMŠ+!T!^{BüðˆÀ©À_®ÙÛ®oN)8<!« tÀd¨CñFé;u;@Z<ÜÒT¦w=5J?-c%ÞìöÝæ·HP…}clyðãѳ¥2Â~EÛÌz].£FB’$ýXöïßÏüùó),,$&&†ÆëÁ‡¬¬,fΜI¿~ý¸õÖ[õ?piiiìÚµ‹ƒ–ëY°ú¡²£€Œ^êFQ×øÚßÎÀ½™™É7ß|Cjj*M›6Õ˘Íf=Aªñ³´zµœÚ{³ÙŒÛíÖo´ï#˜Þò•é‡ÜÜ\=Ýn÷‰Lô¤°¥•«-ý°`Á<]»veøðá>çC^^žOÔÿš5kðx<4mÚ”Î;ëåƾÌÍÍõ±ªÎ~¨¢££IMM%--Ý»w³uëÖšnRµÓ¾}{þò—¿0pà@RRÔäfv»>úˆ)S¦““ÃÓO?MÏž=IKK«áÖŸ>øÀçši¤ª#¨C™äädºtéB—.]xÿý÷9wî\¹÷1c†.ê¿ôÒK<ñĺ¥×¬Y³˜4ik×®eÚ´iL™2%X‡¦Œ;–#F胿ÕMLL ßÿ= æŽ Sµ$%%‘‘‘Á·ß~Ë!CJ,÷ÑGéå/\(;jú÷„1Z?++‹èèèb“å³àÑ^K %"(DÁ$Ü^!Ì„ I IE ‚zêä{o[•¨ †ç+¡ÿW¥DHQN}Þ©(Äñqj –˜¸úÉKhÃæ>o€òó¥$SêNhêýaŒ£<~?%ÿè{EQô™ÑÆØ@b¾¢(ºmjuJH¨ÉmeIø5UÞ(Ì{¼Q÷KŽ©âþƒ­UqxS™Ÿ.(8u>’Yø û.\BõÛØHbpc‰1¾×Ñ‹Áºs‚-™‚#ùêgvK’¸¯•Äÿu–™à[ú÷ïÏG}öÝæ7@‰Â~UQÆl÷å)kç„äçç3zôh–/_^¡hó@uU¤­U-ÂU´^!ýúõ#11Qõ³²²xï½÷0™L$&&ìÐ"Š­V+6lÀb±póÍ7ê ÇСC9xð`…ÚŒ~¨ì~šHj—ý£´EHÛl6dYÖ#¨µr þ±ß³g'Ož¤[·nDDD`6›õ?üÆÏÓ[-z[ûlmvca6›ƒ~U¦ŒÇ¯á/†—V®6öƒ½ñóÏ?“žžÎ-·Ü¢ÏfQ…¼¼<ÝÞJ’$"""8}ú4tîÜ™úõë<ŒÞý5ÝÁ¢aÆ|ûí·4oÞ\¿I|á…B^دê>ùðÃ2dˆÏÔ^PgBÝwß}´jÕŠ!C†àñx˜;wnxoWÆ~íС­[·.WÙß"C‡eÈ!4lØP_·|ùr]Ø/ëøsss™9s&·ÝvO=õ”¾Ÿ$I<þøãìÙ³‡E‹1kÖ,{ì1ƒt4¡Cy®‘ÆíÁ0õ¯»I“&º=dMœã²,ûX•Ö†šþ Vç÷TUÜ~ûíÌž=› ”8[mÆ 9r„¸¸8 Ä¢E‹€šïïPÁP•““Clll©~ûå‹â@Œ@AA,‰L,v$ŠPe/ !,@MæÅ#(¢1BJFˆâ†Ð.„?+G¡àÇÖ?5‹É–Àæèï=nõR†Òz@gõ”*œK—Làk˜ÿÝjžúz¤þ(uyÃDuÙíÏêòÓ‡|÷»õu™ØÜ»Â»ÿöÅêÒíÛ¿5~œ~”ØžRš((±´ÙAþÛüÿi¯ƒù÷I,©_¯IòFíkÛðö]Š*îz\M„ûx;è”(1½«Ì?ö)/·w_Y‚¤èš$qM=‰®I`1Dç{„`çEXqR°ù¼Ð'®hQÿßl½ ˜ÜQæþV2kÎaÈðÆ[³¹í¶Û‚Òa„©‚nÅS‘ f ˆýÔÔTn»í6–/_^!°ÊDìWçCbi¸Ýn’““uÑQÁüùó‘$‰¨¨¨R£î­V+ ¬]»–öíÛÓ¢E @¤lÞ¼9G-sD¨Ý€o› Ù¥­×Ä}ÿãÖÖðý÷ß“ššJ§NŠy²kášÏº–„U‹â6Ök2™ªí<ªH?”vüåYWûA¤e»Ý΂ hÓ¦ wÜq‡žô477—ËåSVQ¶lÙBƒ 0`@±óÁ8ø¡M=¯©~‘‘‘úµ£¢ê‰ÏëׯO£F–óx<ìÞ½€¸¸¸J^0:th©ÛûöíKJJ éééÅ¼å Ø»w/ ”””3Æívë9 hÕªU´û¶nÝ:`Âɼ¼<¾ÿþ{öíÛG^^IIIôìÙ“ž={–9»SÁ† ظq#4nܘÁƒ×ÚD¹wÝu³gÏæ›o¾áâÅ‹Ó.\ÀÈ‘#ËõwÝáp°qãFÒÓÓ9sæ Š¢Ð°aCz÷î]â쮳gÏrüøqÚ´iSb‚ö¬¬,:¨¹M.÷ºTû¤Y³fDFFêVE%Eê—/r?A#&$EƒˆÉ®úì{…}°€ˆÄ£D‘™…š D=„T]ü $%GØÏ»1õºÑiГÁûÌJrþèVNî߼фµaBŸ@×TÛÍÞ=®":uêDttt±}ŒÑüF«P@‹ØW…}I¿ ©Âþ%Ÿ|³tÉRçëS—O¥B‡‰wzÉχ µ®‘ª°/û£Ý-øþ¬à‹‚3vˆ±@’Mõä/ò€Ñ(2Û Sv(|ØG¦‰&Ñ…L~ì^víÚÅ /¼öݦ–R¿Ü@ÓZmÛ¶å¶Ûnã“O>)÷Ŧ6{ì+ŠB“&MtaÿôéÓœ8q‚ÄÄÄrý±2›ÍDGGóÕW_ñÈ#èëãããõ©kµcdv Oõ²TÞ(ÐîÝ»—3gÎ0`ÀÝjEK^¨Ea#±Ý»ÿrl£*Jeú¡4_–eŸd¯ÊÕÆ~0‹6]óðáüöÚk <˜N:!„ ;;;`Ù .ðÙgŸÑ½{wÝ‚EÔ0–ŠŠªÑ~5"""˜9s&7n¤nݺ|ùå—Ô«W¯X¹7Þxƒ¹sç"Ë2|ðAH ûåAó¦t¹\>ë###ù¿ÿû?Ö¬YCýúõÙ´iÉÉÉÅöÿÛßþÆÌ™3‘e™¯¾ú*díÊî_þ÷¿ÿª•G×®]–iß¾=5âôéÓ|÷Ýw>ÂþÊ•+yå•We™/¿ü’þýûÛÿÛo¿å¶ÛnCÁóÏ?ÿ»ö¿ùæ~øa"""8sæ Ï>û,ï¾ûn±rƒfþüùÅ‚²˜5k³gϦGº%N Ï>qâcÇŽeÙ²e>e&NœÈË/¿Ìc=À´iÓxíµ×|®/½ô£FbΜ9Åf©æççsÝuª§ògŸ}Æ 7ÜàÓ.>ø€>øÀgßÅ‹ûäÓB0sæL^{íµb9u:vìÈܹsKœšúôiFͦM›|Ö?žñãÇ3|øð€û…2­[·æª«®bË–-,[¶Œ‡~Øg»Ýnç³Ï>ÔA€ ”Z߃>È_|AAAAÀíýû÷gîܹ>3@½g5jçΣoß¾|õÕWÅî#Ün7#GŽdóæÍ$''ûj -ÐA’$L&“žs¤¼¢~Iâ¾åÂÈDq(ä‚°$@B`FØ·‘‘š!D4Aõµv Ç%a?ËD„-OáÁûÜJ’}êbêöÞÔa?TÚgòž—ZHõž•ê²³×c¿ž÷žø6¿¿c ÞÁÓóG}÷Óê1ÕŽçŽb2~€±Ò"‡‹ÅB\|,çÎóyNÐfãú,n¸$î½ôÍfs1Ñ¿:‚®$oľY’T;ù§É+ì ÜÞm²’¢FÕ»Á3i2Y¢E,´(Á0Ç)øì¸Ðâ-Ð0ÜB©}V€ÿÑF™Áâ=URb%fvLÿàïìÚµ‹yóæ &Lhta¿,¯vÍ'M’$ž{î9}}RR’n©ãt:iÓ¦ ·Þz+Ÿ~úi¹ÄýÊxÄÓW¾¼u !hÚ´©.¶‚yY!‘0""‚ÌÌLÝï ^½zåjG(ùëkhçB >(É[Þ(®¬h­ÝnçË/¿¤cÇŽtëÖM±M&“OT·±~íÆAÛìHõËé‡@o†J*g³Ùj]?ø{/ºèþÅ_°mÛ6î¸ãâããK-»iÓ&ÒÓÓ8p >ûC+«( QQQúk¨Þ~EdYfÆŒÜtÓMdff2~üxæÏŸïó]­[·NÝÆŽ[é(ÚšÆn·³oß>€bö4²,óÞ{ïÑ«W/2223f ÿùÏ|úá»ï¾Óí{&NœHß¾}«¯ñ•dË–-¬\¹’œœâââhß¾=={öÔþüVû¡²hçK‡J-×±cGNŸ>­—ט8q"6l`íÚµŒ3¦Ø@É™3gxàBп&L˜PõâŒ7Ž… Ò·o_zöìIaa!kÖ¬a÷îÝü÷¿ÿå™gžñë’Ç{ŒåË—3hÐ ºtéÂùóçY±bgΜa„ ¤¦¦²aæOŸN·nÝèß¿?.—‹U«V±oß>/^LÛ¶m?~|¹>¯W¯^8–/_NNN]ºt)6`Ô¼ysŸ÷>ø ‹«¶ W_}5×_=‰‰‰=z”%K–°k×.n¸áÖ®][l€-??Ÿ¡C‡rèÐ!dYføðáôèуüü|¾üòKf̘Azzzå;°¹óÎ;Ù²e .,&ìþùçäççÓ¦Mºwï^¦°ÿÝwß!Ë27ß|3iii$$$pþüyvìØÁ·ß~Ëš5k2dëׯ÷dª_¿>ï¿ÿ>Æ ã‡~`úôé>ÏFS§NeóæÍȲÌûï¿Oýúõ«®.ƒÒž./b_C³åI@¢(DÂÀƒ`F’£P„•Ì‹Ñ[-"®ÀUöE‰¤æ‘ 4«irÏgШkÉ3½Â„©„ 4 á÷{XÌfŠì\…ù>‹4±¾Xø öšo,[]ýñññ˜-€«)€î¯/y…}á#þ¯9Eáù2VSñöºKŽ ¾8.$ˆ³€Å"!„ê½ïVnå’Ý‘.‰ðTªL¤Y­×­v\d9[W­bûöíz A˜0aj5±ŸŸŸÏßÿþ÷·ge©Ùà=­Zµbøðá|öÙgeŠûµ)b¿¨¨ˆ›o¾YŸúkL˜ Ю];}Ú®ÛíÖ#ÁJûÃ$Ë2‡ƒììl}Êvƒ p»Ýµ>ÁaE8Œ‘Õeý!7™L˜L&Ìf3;wîääÉ“Üzë­ÄÄÄŒ7¢Í®¨N*ÚŽ!11Q(«S§N‰åJÛf$”ú¡¤ÁM˜ÏÈÈàŸÿü'}úô)µlLL ¹¹¹,]º”^½z‹Ø×¢øÔD?„õêÕã7ÞàÞ{ïeÓ¦M¼ýöÛ<þøãœ?žgžy!½zõÒ#Xk#ï¾û®þûùÓŸþTl{rr2ï¿ÿ>7Ýtk×®õiΞ=« °ýúõcâĉÕÚöÊâ/x:kaüøñŒ7.àïè·Ø•娱ceZ–\qÅ>å541/Ð@‰ÇãáÞ{ïåÂ… º@ø{›5äp8Xºt)K—.õ±Òr»Ý<üðÃ,Y²„E‹1eÊ”*·/q8|ùå—|ñÅ>ÅÏ?ÿ<×]wGeܸq?~œ×^{G}T/óâ‹/rÇw°jÕ*fÍšÅOøÛò×ׄ5OJJ ³çÌ᱇"Êì$B–Ôä·Ú$£Ç¾fÕ# ŸÜ›ÎÃßv*LîxI„pzã·*͇h³:+À#@QÔp{}ûÝa¿U¸»¥ÌUuÕÏsxß|ú«àL᥇P±2 &LŪ°ïŸÄ6Š¢™™Y®ú<W^y%7Ýt_~ùe©=•öýoJ«Š²úÁãñðý÷ß3fÌý!ÜØþºuëê¯W­ZEvvv¹¦HY, õh -ñiY«*‹öǺ¤ˆôÒ0FoWDàˆŽŽ¦  €%K–èÉ %›5FÃk¯ƒ•Œçrú!ÐÀ†,ËÔ¯_EQÈÉÉ¡nݺ%–3FãÖ–~(k0GKŠûÃ?`µZËUvÓ¦M>eµA‚šè‡P§wïÞ<úè£Ìš5‹Y³fÑ£G®ºê*ž~úi.\¸@ݺuyã7j­ðøË/¿ðòË/ªSRÂE-jzÚ´iLŸ>>}úЧOÆŒÃùóçk•MÛ¶miܸ1&“‰C‡±gϲ²²˜‰-a^µm{aa!ÇǚŠäÕW_eÒ¤IL›6õëׇ\$ouóä“OËa6›™:u*K—.Åãñ°~ýzFŒQåŸýôÓO‹t«W¯=ô'NäèÑ£ :ÔGÔu–å„ XµjçÏŸç—_~¡cÇŽUÚ6—ËÅk¯½À=÷ÜSLÔõ~sΜ9\{íµlÚ´‰;wÒ©S'@Í—1þ|@à3Šú þÝ{íµ×øî»ïŠ HÕêԩðaÃX¶l .dÚ´i€šÇ`ݺu˜L&FU®ºJKBسgOÆÇË/¿ÌçŸ^LØU´_¿~=?üðƒ>3GÁý÷ß‚¾}û†Ü ¨ñÞ°¤„¹ÚëÊÛòøÔŠf³#¼Ñ¾jYOÝs¹œàöDi‚ö]EN°Ø‚h±áoÅ#’OdÁÙà}f)F7ä\Óþ ý¶ï+~s X­ØÌê* ¿´r ùªƒ‘#Gât:yâ±Gh«a’¼Â¹¯°¯EóË’„„*Π￟.À‹?+üµ³L”WÜÏpÀá}šM›6•jIqúôi6lØPn¯}›ÍFRR’>HpìØ±r‰&¡(BjþyÕi±$IIIIÅêðqýëöyT™~d5ãñxÈÈÈ 33“¦M›–hIcdªMýPÞÁœˆˆˆr‹‰þem¨‰~uÆŽËO?ýÄ?þÈÓO?ÍàÁƒu 7Þx# ÷~m 33“Ûo¿‚‚êÖ­[f„ª&Ò¬[·Ž1cÆè¶šMM ÏùP¢~ýú,X°€AƒéùG4vïÞ̓>ÈîÝ»ùä“OèÓ§<ð@Àzj{?\..—K\×ò–”„1Ò·¨¨¨˜'|ÿþýyöÙg™>}:Ó¦MC’$]´0aB@ïýß wÞygÀõ 4 qãÆœ‰ÙNž>¾\ís»ÝtèÐÁ§N:U®džÁê‡ÊÖ§Y™h‘ŽþZ_·;NÜn·þº¼Â¾Ûí&66–Ò¢E‹bB¹†ÿ:ã{­½Áè¿Êöƒ–ÌÕˆ$IX­VòòòuFHIåJ"”û!бh¸Ýn¢££éÚµ+’$qàÀRË&$$0pà@6lȶmÛŠ%®©~¨ Ô«W'žx‚)S¦j’YÍo¿ª vŸäççsóÍ7³sçN¢¢¢X¾|9]»v-×ç&''óüóÏóä“OššÊĉkÍ÷X Üwß}L›6ãÇsäÈ‘Îßr?@Ùç`tt4¹¹¹äåå•ZVvm6[‰÷;²,óæ›oÒ½{w@cß}÷ÝZ™´»<÷þÛ•×ÚKªK»f{<%Ûu”v½.m›&†—uV«µÌöù÷‡ÿëÊ´/##C¯{ìØ±¥¶Q#77W¯ïâEÕºnݺ¥£Ñ>2”­èõ©$IŒ5Š×_… R§NŽ=Jbb"ƒ Ò÷)MDB0iÒ$Þ~ûm}]TTõêÕÓé 9yò$ âE(# `øðá|òÉ'€*õïß?$û4ˆïÿ¾ªÅ}ãgòÛ®„A5ÎÍ’¨“l 9}€¼ ù$¶m´~Ñë5~Ukž;gýí¤½.Ey‡¿£.“šªËŒ_}ËÕ÷zîß=O]~öºÌ lk\SÇ)Iw\4ÇÛ¦ +Ò%!PöÛ]˜LNüŸ°›Ž;°]mâ@®‚d`ɘd„G¢žE¡iûúœ8¹›žm }ÁGŽášk®aãÆ\sÍ58NÎ;GëÖ­9|ø0íÚµÓ?«:σ‡~˜¢¢"f¼4…kë "LŠ¼Â¾À8Æ¡PL!¼ vUKƒ¹0q›Â+]e#$®o(q]ÃÛ‰VYµóÑ8œ'XvLðS¦ }œÌmML˜$p(ê`ŒP½ýQ“÷š<&)8Ϭa„ >5nÅÁ‘#GPÅ'Êoîܹ>¢êÎ;Y½z5 åŠ:¯MV<6›sçαeËzô衯?}ú4[¶l!!!¡\£ÌBÒÒÒhÑ¢…±ït:9þ|‰mku£ ¹ZÛ$IÒ£¨]ÄW—Ë…ÇãAQ}YšÈ —"²»téBß¾}ußôŠXÏ=ÕƒEeûJN2«EŽj¢ÊÕÆ~4˜£õMZZÉÉÉäååéÉoK*Û§Oºuë¦Ûîø'Ï­É~¨ äççûXÕ¤§§³cÇ]Œ¬-0|øp¶nÝŠÍfcÉ’%úƒCyÈËËãÿø‡þþÀüøãµvæ‚?:tÐ_Ÿ>}ºDaÿ·ÞeѬY3vïÞ­[¢”„&ú5kÖ¬ÔrZžPgš-^¼˜ñãÇ_~C«c”raaa™å5“ÉTê «0¥Í /¼P®²mÛ¶Õ_š½ˆÚ4c6wÝu¯¿þ:ß|ó~Oñ§?ý©Lû,Å‹ë¢þ¸qãxàhÞ¼¹O™5kÖ0lذ2ëÚ¹s'_}õ•þþ믿fòäÉeÎZ® ´Á²²žS*+îû¿÷HÐ>»ºE)I’TÛ äeK\‘!fÃãq+äÒ<¹}Ù…/‡":\PN'kÖ¬ñ™M^•X, €ÅbñhGìW;]ZÆð§lYgϳ?¡>²~2^Q9ЯT›`árƒdò^O¼þñ&lÁ•3ik³`-(¼T/ê ùéÓ§‹Y5+Š‚Ãá¨qû²'Ÿ|‡ÃÁì×_æºd5r_õØ÷zë{Ñ"õ=& ·X…:“AŽäÃÿÛªðj7™z65_‰íR &!Ø“ ËŽ)숫’L<ÚJÆ"«Ér ÈŒú¹²GT0y$¯Ð_íÝ&L˜*"èÉs˺¹²ÙlØl6rrrˆ‰¹äû§‰g‡ƒ²bÅ Ê}c]™‹`Ý –·^Y–©S§ëÖ­£E‹$$$àr¹X±bE…,x’““éÙ³'EEEúºï¾û®X¾Ëmoua¼!t»Ýºh èµÑÖ@·á’`_ZľÛíÆf³Ñ»wo7n¬¯/¯õL Oõ`žG•釒,vŒvE¥•Ó¨Mýà,n·›ÄÄD:tè@AAyyyȲPØw»Ý$%%ѯ_?’““}|a¿¦ú¡¶0yòdŽ?Ntt4-[¶d÷îÝ<õÔSüç?ÿ)WðPÀn·së­·²yóf¬V+ .¬°uÌã?®Û÷´nÝšíÛ·3fÌ6nÜÐ~­¶a|P/íoÕo½Ê¢]»vìÞ½›={ö”ZNÛnVýy÷Ýwùì³Ï5óÚµk™:u*}úôáꫯ®ºF £8yòäɃ4´ÁP5kZ2åÂÂBÆŒÐþ¥4´œ(¥ÞOž9sæòZôlÙ’Þ½{³qãF¾þúk@ûË‹f97|øpŸ7#çÏŸ/³žüü|î¹çiiiœ9s†Ó§OóÐCññÇ׈_tig=hAå_WVÜ¡_ý! ÿ»œPd—‰‰·j‰sÝÎ"‘qM«÷ƒý„ýsçÎ1÷ßÿšM¥,ˤ¦¦Ò¸qãÀ3½¯)´Ç­/š{“‘'5W—玨Ëúåd·X]&·ôÝoçbßzC€]`G6ÿ>›Á¾„d$Qùî—%°"¸±¹…á-›Â™}´ê”æã,ÕºukNœ8áhA›6mÈÊÊ¢}{u`«&ŸÉž}öY ùðí¿ódž‹,ymxTç}UÐGÔwËàVÀ%«ÉpNÚá™­ ÓºÊ4ŒòÎB‚-çaÙ¯ gípu]c[˘½J½l&ÕnGFRíheµ×5Ý¡ÌâÅ‹Y±bS§N¥{÷îÜxãœ={– &ðÎ;ïÔp ËÆn·3bÄ6n܈ÅbáÃ?dàÀªã½÷ÞÓ­Þzë-zõêE¯^½8uê?ü0Ë–- FÓ«•-[¶è¯›4i°Ìï¡ÊbÀ€,[¶ŒŒŒ öìÙCZZZ±2‡âĉ\wÝuëÙ½{7“&Mà¾ûîcÆŒ 4ˆü‘{ï½—7†üÀ™1YìæÍ›¹öÚkK,ër¹tøÎ;½mµ íoRis´ÁEQX½z5C‡­Ðghý^TTTꬫ7V¨ÞPä®»îÒ#--Íç\-‹Ã‡гgÏˬ_¿¾ÌzüqŽ9BLL .äðáÃŒ9’•+WòÖ[o1nܸr·©:0>wÑîÚë@å´úŒËš¦¬~Ðfü$''ÓªU+ìv;¹¹¹ºøo¼¦he“’’h׮Т`·Û1›ÍÅ·²"öèìß¿_V¼ãŽ;¸ñÆxõÕWyøá‡Y½z5óæÍãÞ{ï­Éf–Jaa!·ß~;ëÖ­Ãd2ñþûïWX Û³gžÌôÞ{ïeĈÌ™3‡Ûo¿ÿþ÷¿Ìš5«Üž×¡Hzz:óçÏ }ûö4jÔ¨X™ßC?”‡¡C‡…Ýnçí·ßÖÑl³Ù̼yóèÝ»7'Nœàá‡fÉ’%A?žË!--æÍ›sìØ1æÏŸÏc=FTTTÀ²}ôÙÙÙþ þЂ?23û,ƒšÔ¶uëÖ¼ýöÛÌ›7¯X™¬¬,/^\ñ1n»í6}FC«V­*´¯–káøñã·?~¼Ìßæ¼yóX¾|9ÿüç?III!%%…±cÇòÖ[oñ׿þ•k®¹†nݺU¨mÁÄ(¤6lØzõêé³HKôÂ}e¼ö¢~iÿÁEõϹ(›h 9€Ü vbëõ©ž dÅÃ¥ï'ØÎ>y0´†mªqôˆ}ï‹M Ôež:ÛžÝ+Õe¤Ýw¿w¼I¼;xLöxój~,!›7¸‹¹?÷Ì9$Ô/¡Tà/Æ,KD™`h +ïŒPE}‹Tæà^Yëj2ˆQ’$¦M›FQQ+¿Ç "d E€[³ß‘Á%À"«ÿÌ ˜%uƹ"xp“B³h‰kê™I‰‘|“c&­ý³Á‚„l½oúCæ&L˜ŠR¾¿`h³Ùˆˆˆ¨”—j¨ˆ•A³ä9xð 111%ÚhÂuLL ‡Ãgj¯B$é7áG« Öx<ŸÄ©FK@³7wš`­Y¸\yå•zô¶–DV‹`7&¯SE€¢¹£à]ç]eú!99¹ØÔïääd½.m¿† rîÜ9ŸrM›6Ån·×º~èÖ­›þ½ !ôo­Z$¢$Iäçç—z>hBPÌ7×XguõC°8uꔞwГ, !8räˆOÙ&Mšè} ª >nÜ8mÚ´aòäÉú¶ë¯¿žÑ£GóÁðúë¯Ó½{wŸi³¡‚ÛífÔ¨Q¬Y³€gžy†ÔÔT<°¼Éd"%%ÅgÝnרöíÛóÚk¯éÛ† £>ÊìÙ³yñÅéÝ»7]»v Úñ\ýúõã`ðàÁ>3¿Ün7ÿùÏxöÙguÿóçž{®Øþ¿•~õü?tèÏ:M¼*((ð9?Ìf3-[¶ô)›À£>ÊŒ3X´hW]u•ÏàÖÂ… yÿý÷xàtû#O>ù$‡&**Š?üP¿67iÒ„Ù³góç?ÿ™+Vð¯ý‹Gy¤j<Ȳ̄ xä‘G8~ü8#FŒ`Ö¬Y>}æñxX¼x1Ï<ó  æ5jTIUþnéÔ©?þø#+V¬àî»ï¦S§NÅîeYæ•W^aäÈ‘ìÚµ‹#FðöÛoÓ´©¯=‡ÇãaݺuÌ;—9sæè~Å‹…qãÆ1yòd–/_NçÎyâ‰'ôý²³³¹ûî»õ˜ÚLTT”>øXQzôèÁÉ“'™?>wÜq‡Ï “ôôtî¸ãÝ*3{÷îe„ Œ=š‘#GêÛþö·¿±qãF¶mÛÆèÑ£Ù¸qc±¨øšB»ß”$‰øøxŸY`•%ÝvÇ%ƒÅ+æ›e ³,0Ëàò‹[2Áè––bu ¸Ô§¢¸¸o’ RÒ¢÷ tC£k„ S BÚŠçrÄèÚjÅ£a±XHLL,3"ØétúøªkëvíÚŶmÛˆŽŽ&:::¨m­.4ÿô@IJµhs‡Ã$Iz$·¢(X,¬V«>Ò«W/²³³uKc½ZàëA¯ ½ÚçÕ¤åJeú¡U«VtëÖÍçA¿°°³gÏúÔ›––¦'n–$ ³ÙŒ,Ëäçç׺~°X,<Œ‰pµDÃÚƒFTTT©çÃõ×_¯GîkvO¿E ž'žx‚;w[ïr¹ŠYѬ\¹ÒGŒ›2e G%22’þóŸÅ®å&L`Û¶mìÙ³‡'žx‚/¿üÒ'ÇJ(páÂþ÷¿ÿéï§OŸÎôéÓK,_§Nb QŸ|òI:TL€Õx饗شi;vìÐEÿ¤_¡ÀöíÛu¸qãÆÔ­[ÇÑ#GôÙN“&M⦛n*¶ÿo¥@M2^R”ì¦M›|¶Õ¯_Ÿôôôbå&MšÄ† Ø´iãÆãí·ßæÊ+¯$==ýû÷Э[7¦L™Rlß?üPö}óÍ7‹E6Œ‡zˆwÞy‡É“'Ó«W¯¶®¹ë®»Ø±cÿþ÷¿Y·n:u¢U«V4jÔ‡ÃÁ¾}ûôYSuëÖeÑ¢Eö†ÿ=pß}÷1þ|Ξ=Kÿþýõ€€ 0xð`È믿΄ X³f ;v¤sçδhÑ!gÏže×®]ú@îìÙ³}>gìØ±¬^½šÕ«W3yòd>üðCzôèA~~>ßÿ=¹¹¹ü¿ÿ÷ÿ˜1cFõv@1~üx¾þúk èß¿?×^{-7æÔ©SlذP@§NZl_m´°°ÔÔT^ýuŸí‹…ùóçÓ»wo~ýõW{ì1,XP-ÇUò •å±_¢ùm7&Í­nŒíÊÍ’¨ßÂD¨ùë ¹‚†‰WÖp;yyylÚ¼9hÉs­ C‡%222×ðtTgN˜3Oª+{æ,Þç}-ßê}å§…Øó}Ëiûi‘ÿ™ù>ŸJ êT!åòαLØJ·¶˜ Ú$èSÏEŸø|ê+b¬ P‡ÓÓ)((àÔ©SôêÕ Pϯ½{÷Ò¨Q#vïÞM‡Bàr¹Ø¹s'111!¸âŠ+ªãPË…Édâÿø;¬þj)}“Uÿ’ ¯þ3yß›$Q“èê”p)5 ùڃί[óØd “7i®ì {ì‡ S›©ñä¹FŒb|÷îÝùå—_*õ¹Ý»w¯•Ésý)o¢Û¢¢"\.œ;wŽƒrñâE*58jÉ>µöT#š«Ý(E\“É„,ËtéÒˆŸåf IDATEQˆ'''‡¢¢"=ºÈét{µþ4Fíkb.”µìó¨2ýPTTäc»cô×7öC^^žy«YÎhy~ ý FŒâ|m:B•O>ù„Ï?ÿ€¿þõ¯Å"–A'Þ|óMn¾ùfNœ8ÁäÉ“yóÍ7«»©AeáÂ…º%ÅßÿþwZ·n]¬ŒÕjeþüù\sÍ5;vŒÇ\·´ %† ƦM›ÈÌÌäÔ©SÅ0®¾új&NœÈþð‡bûþ–ú¡ª°Z­|þùç¼ð |ðÁ8p€j@ÃwÞÉ+¯¼Rldß¾}zäúwÞYbäúË/¿Ì¦M›Øµk£GfÆ !7pfä7Þ gÏž¼þúëìÛ·C‡ùÌŠˆˆˆ`ĈLž<9¤ÊC‰ÔÔTV®\Éßÿþw¶nÝJff¦>(í?üÐCѱcG¦NʺuëØ¶m›ž¿T±òª«®bذaÅCL&K–,áùçŸgÞ¼yçêz`òFè›UÌ×D}íŸâ×|£`ï¿Þ_Ü÷_/IxøªÑúrø÷&L­EÊÊÊ xu« ?öS§N±jÕ*vìØQfÙœœF¥GÅÇÇW:b///OŸ ìt:Y¼xq™Égºté 7Ü@ãÆ+õ¹%Q‘~¨Š¢——‡Åb!''§ÓIDDÑÑÑDEEUú;¬ª~8sæ €.äh`%++‹}ûöaµZFgk–DÚ{£ k2™ô¨scY»Ý®×e6›‰ŽŽö|eYÆl6c6›‰‰‰ÑÅm-ú_«Kû£̾}ûh×®žÀ§ª÷Ãï»Êó{Z¹RõäÔ’kºs¨ Í@Ùºu+@…“Ú†©GŽáÔ©Sœ?EQHJJ¢cÇŽåN̦8999lß¾ .˜˜H·nÝÊu¿ò[åäÉ“ìÛ·ììl, 6¤S§Nγ¦|\¸p;wrñâE$I"99™víÚ•ë7}áÂ~úé' ¸âŠ+èÞ½{­ÏåT•¸Ýn¶mÛÆ‰'ˆŒŒ¤eË–´kW v(5Ä”)SxöÙg±X,ú=˜‚ˆˆ=ßUIžúe½´4Ú+_Ûív&L˜À?þñ ³Û‘ËOÝJמÇÙ³ÕÆ5C‘B,õRV†‹_v4¢ËíË‚jA2ûí·y³¨;gS. ðË'ÝWŒeéŒç©W¯^Ð>;ÜñÌ4¶} ÅdÕ×78¼Š§£wðp ÙÔ™×|€m®šüZJ©ëm˜WóДU}éwBiÏ=šº«-Ïzí2ÓÕ<+EüwÿÛª°õ—¢(¸=VtòÖ^7‡… O‘¥ÀRP„%ÂL¬ÍÄàV‘ O"2÷8¸ìtìгٌÇã!;;›M›6Ѹqc:uꤟ×ÇŽãàÁƒôíۛ͆$I(ŠÂöíÛ),,¤k×®º¶¤( ¹¹¹!cUìp8=z4¿¬ýšÎ‰…°»¡ÀûO}-(pƒÃðèm†gÚ]:¿K²Þ× ¡ÎX|ÌÅ›}΀ªæÀ„ Så”À^-V<剦e™½{÷Ò±cG@}`ÐFV/‡½{÷–{Êg°­xªú34«EQHLLÄd2a2™.ëÆ­¦#_JBá#âj¯5; £ˆkü§•Ñ¢¯ ÂF!WQÔijš fÏ…Ûíè7¯-ƒ}…û!ÜaÂÔ-[¶ 8#L剋‹ ?@¸âŠ+ÂQùÕHRR×]w]¥÷4hP·è·ƒÙlæê«¯æê«¯®é¦T •± ,+"ß½d¿v¥½®vïl¡þËÏ‘ˆ®cB’C/˜"?ÛETR›êé›’<öÅ¥Hë·gÍÂ$+‹ÅÂccÇŽØa$`p‡Xòxs§tÉ ˜MÑf‰AWÚÞ.ŠÉVb›´ñÉk2™HJJâÆoÔ×ißuóæÍiÞ¼¹Ï¹.˲n1ÊDDD0oÞ<þüç?óóæÿÑ6NBBßñÿç‰jؽv-ôߦ¡xô¾5røq5L˜ZMЭxÊ‹ÕjeÇŽ8Z¶lyÙQ?‡ôôtöíÛW¡)èÁ² ’$UØ?¿¼„¢é/˜úVù?Th¶+N§SìÕlWŒ¸ÝnÝ®Å_ô-**"""‚‚‚}JtDD„ž€Õ?amuô[¸TÂý&L˜0a„ Só\ŽOI”dÑõk’œ‹2u$„'ô„ýœ .b§Öh4a_| Ö ƒ÷\(Õ³†…}-‚^KŸmùê=LŸ¯¿¬z5O}×S|>'T‘%‰Ái± ð÷­…œ4˘ÌCZG2¼miõ-D›%„P¢|ƒw¥åâÐ¥ä¹þDFFòÑG1bÄ~Ù¾ŽæÑ !écSš°현¨°5Î;«3¾Ä~˜@,I IA6›˜üß³ h#;ÆÒ®®™«„É$süøqŠŠŠhÓ¦ pé¹ï矦I“&Ô­[W¯3++‹ôôtÝŽTãôéÓdeeѾ}ûê;ÀJÉ’%K1bGvn¢aä¥D·Ú©ì•ï+Ø—½ï/îç¹?dx8eNbü Ïò—¿ü%dì‰Â„ S1‚.ì—÷FO’$bbbt‹‹ª¸QÓ<µËK0oJk↷²„b[…x<Ÿèj­þ¢®,Ë>#òþ–-%ù²û—5 ÀZ€>P¤‰Âf³“ɤGy[Ð÷C¸„ &L˜0aB…`<;øG×z_“h³Šì’Rzc‹­\ BñP¸n¶¸ªÍW"eXñT'B_%Ô¯M5Qê‘õÁD,Ëtˆ¾ÈGÃm=q†+ë4$ÆjA’$òóóÉÎÎ&""‚_ý•fÍš°{÷n’’’Ø¿?}úôÑëÛ·o]»veóæÍôìÙP½ë8@£FHOO'%%¥Æ¯eËÒ¥K¹å–[8¹o;‰VÃÌ%¼ÁùèVDÜw)‚Í™ Ûó­üåÇxê©§ª<'^˜0aª—  ûEâ„ñGlÂ-öQ×¢x´„]pIxÕ|Øu¸Ýn]ÕÊz<] u:Øl6‡z_T„¢(X,Ün7V«UÏwî‡p?Tg?„ &L˜0aÂÔ$•o+b‹áŸ«,PòÜš@f“Ày~îËO W¥Ú=X¢[`ލS£íB …ÿÏÞ‡EU¶ÿÎ ûŽ " H¸/$¹olnešb¾í–[™ fZjšY¦YjÖëÖk®•å[n¹¤¯Ê&殈ˆ ‚ìˆ,²Î0¿?øÓ 3þûý\×\ ó<ç<Ï9 ÎÜç>÷“ššŠ_|byÝ”,Ò××ÇgË—ÃÖÆF=cŸ­Ò‹c€¹ÐÒ¨FÿŸ©íßµðZQQ¬¬¬W©1¤R)¬­­‘™™YÛÓ¯3VVV8tèÆŽ‹¤Ûá0ŠO”óû¬V‚§LiáL–(•\‚ ¼_ôAè矣]»vuqDTÏÍâ¹ ­).ž[ë…æùùùbÙ“²Ôª žª~XP-·RRR‰D"l…¯eöB X©T"??ÆÆÆÈËËï,)**‚©©)òóóahhX/™ê<<DDDD…B¡¨ÒûmAý²ïÕÊ>×è+ïûºW:žy‹V0oÛ³žÇ®XVôC˜X;C¦WOwT±ojf†Ôi`ßÌÔT3(Ìà~£¢ú³Q*•prrBTT`nn.Þmnn+++äççÃÉÉIÜ®G …³³³Úß œ;wâëúúú°µµÅýû÷Ñ»wo­sh¬¬­­qðàA¼ôÒKH¼ )´¯Œ[†Öì}%p?·©%èÐgöÿü¹FÉ""jÚMýÆ€5öK5Ö¹ÃÀÀEEEâW!p+”@²2™L à %™´—ðÙloá9±¤ŠD"A~~>LLL——'.žš““SSSµ×xxêë<5¹\Ž¢¢"1WÞgˆò2ô+Ô×V†§ìW°R]ß.Fúéx’R§ãTGf‚fm^¨ßAËö%ÿŸP£TÂÈȯ¿ùfO¡¤¼û ò7:r¹...H$(..V{ÝÞÞ‰D­ôª¼½½5þFØÚÚÂÖÖVm߉]ºt¿¯Ê]B­­-<ˆ1cÆ )öžÖÒ:Ú¨öK-TâT’°ë€uÛ¿ÀèÑ£Yƒ¨Òدà®P;M__oЀ„7uqK'ÏC©êîOøO¸¨¨2™ (((PËÔV-{"•JÅÅuTƒ±Â‡²‹¢ íª¥[€J½Èd2ñ†j–¸ð¡A__ÙÙÙ°°°@ZZšø¤.ÎÏσêy¨èi[H¸¹P½CÐX/J57ùùùÈÍÍE^^žxS½SQø*ÒTjB}úò” êWöÿø’’¤§§ÃÔÔ¦¦¦ÐÓ«›<6¡ä…UÛž0²·«“1ªO‰'—àhÓ­ß)µÎ¬Æ¾@mNÊ/ßô4+{ÞU?£”ý{¡úº¶¿º.V´?Õö¦ð{ЦM9r£GÆÃ±(;eµ<*rŠ•L‘ã¡^+|´¼ta\Õuረy©ÓŒ}XXXÀÐÐr¹¼Ê·iÖ¡ ‡¡¡!,,,```Pëc<­çÁήôMnvvvö£§§ccc¤§§ÃÖÖV â _ˆYÛÀ?X ô ƒêU~]W¨…×…¬o===18\XXñ¹¡¡!ŠŠŠÄmår9Œ‘““ƒÔÔTXYYÕɇž‡§û´J·ÿƒ…GAAôôôÄSõõõ¡§§‡¢¢"˜˜˜àñãÇHOO‡D"Á3Ï×¢gÏžwÔ‰DŠŽ^KQ\à 4ÚF@¦o ©ža½Œ5løp;½òëÆÈmÙJ‰RE1dÅy¸qãZ¶lY/󤧧CVœëÄ«(‘êA¢,yÆ=¸¥œÅ°¾¨×¹v•ÉįJߪì¯)rvvÆÁƒ1vìX$''ÿÓðÿý(qíQ ‚Ò•9n"‚?ý” ã=E$™™™Z߉ÔF H©T"55QQQǃjœ½]Û,,,Ю];¸ºº¢K—.°µµ­õ?þ<5#d%''#!!=B~~~COK±±1Z´hGGGØÙÙÁÜܼN~xxÊ“““ƒ¿ÿþ‰ŽŽŽ°¶¶†žž^£ù·\[”J%är9233‘¥R‰ÀÜܼ¡§FDDôT(((À“'O——‡¼¼<äææ¢°°2™ ………õ:!‘ÃØØfff011¿Êd²zËÓ*#=ýõ’’’Ô.´h+yY„;ÑÒ‹;öööýâ‹õ~‘þ!$ª&+êRÙÏ.Õ¹ˆ'Ôó¯¯Ä«ÚtëÖ-Œ;iii0Õu3À½\%N%)бï|ùå—èÕ«WCO“ˆêˆ®¤Ô: ì ?~ü)))ÈÎÎV[¥1Ð×ׇ……Z·n ++«:Ëlåy¨¥R‰¼¼û /¼ðB“=&"ªœ ì är9äry£ 6 õëja¥²xjF¡P4Š7Ú*êÏC)žírrr-^øhŽ„ '...ÌÔ'""j`ÚJ~Ö—²åJ‰ˆš³ .àý÷ßÇœ9sðÖ[o5É»ˆ¨ê<°ODDDDDDDDDDD•§+°Ïè=Q¢³îJc+CDDDDDDDDDDDÌØ'""""""""""jRØ'""""""""""jBØ'""""""""""jBØ'""""""""""jBØ'""""""""""jBØ'""""""""""jBØ'""""""""""jBôt5(•ÊúœU‚ÎÀþßÿ]Ÿó """"""""""¢ÿ7`Àm,ÅCDDDDDDDDDDÔ„H233µÖÜ100¨ï¹€¢¢"mÌØ'""""""""""jBtÖØ/ïj5 }""""¢ú”““ƒ˜˜dee¡°°°¡§CD”¡¡!,--áìì ssó†žQƒÐYcŸˆˆˆˆ¨¾$$$àöíÛP*ùÖ”ˆ*G"‘ sçÎpttlè©Õ;fìQƒÊÉÉÁíÛ·!“Éàææèéñm*i'—ËñðáC\½z·o߆¥¥%3÷‰ˆˆè©ÃÅs‰ˆˆˆ¨AÅÄÄ@©TÂÍÍ NNN êQ¹ôôôàää777(•JÄÄÄ4ô”ˆˆˆˆê?5Q³“——‡äädäææ¢¸¸¸¡§CZèëëÃÌÌ vvvÈÊÊ8884𬈨)qppÀŋſ!DDDDOö‰ˆˆ¨YIKKC||nÞ¼ èÑ£ŒŒŒÄí qãÆ @×®]ajjŠ´´4œ>)))000@ûöíáéé‰6mÚèœczz:bcc!‘Hлwo@dd$Μ9ƒôôt´iÓÏ?ÿ¼ÚHMMÅ_ý…øøx˜˜˜ÀÝÝýúõ«ðœQÓR/}˜˜˜ //iiiâëk×®ÅÞ½{1lØ0¬Y³“'Oè0zôh1°¯T*±nÝ:¬_¿c 2›7oÖx ¢££1uêT„‡‡«½¾páBÌ›7ãÆÃˆ¥Ùƒ.\@ÇŽÅ>)))bÛ©S§ŠU«VA.—‹}ÆV­Z!55S¦LÁùóç¡P(4æ¡§§‡É“'cÕªU000Ðh÷óóÃìÙ³ahhˆ˜˜Ì;û÷ïWë³téR¬X±3gάY³ëÖ­ €U«VáÕW_ÅæÍ›¹(‰™úeÒ ôU%dê—ÝŸ0^ÙŒ|¡ÿ aÕˆˆˆˆˆˆèiV/ýüü|äççŒ5Úsrr0qâDÄÅÅÁËË ;wÆ“'OÔ²æçÏŸÝ»wºuë†qãÆÁÌÌ W¯^Å¡C‡Š‘#G" ÿ¿Ÿ -- cÇŽERRôôôàããƒ^½z!//ÿûßÿ°~ýzDGGWêX¶oߎßÿöööðòò‚……îܹ=½ÒS™••…°°0888ÀÃÃ;v„±±1>|ˆ   „‡‡cûöíÈÎÎÆÖ­[ËË××ÄÈ‘#Ñ«W/¤¥¥áĉHNNÆ’%KеkW„……aíÚµxî¹çàîî¹\DEEá÷ßG—.]0oÞ¼J5~õØ?~ü8”J% K—.í.\@‹-àçç'–ŸQuòäI1¨ÿÎ;ïàÛo¿UËBûí·ñ¯ý )))˜;w.8 ¶ýòåË‘””ccc:týû÷Û,X€+Vàû￯Աüþûï˜4iÖ®] CCCv+++ìß¿ÞÞÞ‹Á)•JìØ±ü1þøãÌœ9½zõÒ:Naa!Ž;†ÀËËK|ý“O>Á¨Q£ƒùóçãÁƒX½z5Þÿ}±Ï§Ÿ~Š7ß|زe æÌ™#^x "¢§ƒ®šúBæ|Ùšú5¥+3_Wí|]w5F›6mÂЭ[7lÞ¼¹¡§S- } ¹¹¹;v,à›o¾aÉÈjjlçñþýûˆ‹‹C~~>lll`gg{{{Þ1LDDDT¤u=€ŸŸ-Z$~?qâD­ýV¯^­5¨6l´oßkÖ¬Ñx£8tèPÌŸ?púôiDDDˆmb ÿÃ?T ê€D"Á²eË´^pЦcÇŽX¿~½Ö >ØØØ`ذaA}a¬éÓ§cèС€Ã‡—;Ö| Ôö?}út¥kŒ9R-¨†††X¸p!€Ò»nݺU©c#""""MÑÑÑ •+Wz*ÕÖÐÇ —Ë„   FFF000@QQrss+œ3U_rr26n܈ãÇ#))I£½M›6˜0a¦M›{{û˜aÓ ”nll>øà¼òÊ+077o´s¬ˆê¼âÊŽÙTÏcC333ÃÙËõ- IDAT³g]»v­÷ó8oÞ<1¨ÿî»ïbÑ¢EjŸYŠ‹‹qáÂìÛ·~~~ü9Õ¡Z ì¯X±-[¶,ݱž,,,СC¸¸¸h-M#P T—õøñcñ¹­­m¹ãÛØØ 66Vm›ììl¥ýòTÔ.(o®Âx¯¿þºÚEkkkØÙÙ‰wdddàÑ£G(,,Ô¹}}}çLõu]%Tû FˆˆˆÊÒ•Y_WûÚ›Sæþü… ¢  @|ÍÆÆVVVÈÉÉAZZ’’’°yófìØ±›7oÆ‹/¾Ø€3¦ªrrr‚““SCOƒ2™  h±³²²ðÛo¿(½ú?ÿùF}}} <ƒ.÷³Õ\­öLJvíÚUy»ò‚þªm …¢Üýl©ôŸ¥„`zEo,…r=)o®°dÉ„……ÁÌÌ +V¬ÀK/½$^ì¬Zµ ëÖ­«ÔxDDDÔxíܹK–,XYYaîܹ˜0aìììÄ>ÙÙÙ8}ú46oÞŒ7nàÖ­[ ì7°ŒŒ øùùáÎ;xòä ¬¬¬ÐªU+ôêÕ ½{÷ÖXÏ)..III077G÷îÝÕÚÒÒÒ ©T*.dzãÆ øûû#553f Ú·o¯¶]rr2Ž9‚¸¸8˜˜˜ÀËË ƒ Ò:ßÂÂB\½z@éÝ£fffxðàŽ;†„„˜™™aРApwwW{\r¹¡¡¡¸téÒÓÓaff†gŸ}Æ ƒ‰‰Iö­¶cS¥T*qþüyÐzþÒs <÷ÜsÕšÇÝ»wˆ¸¸8Èår´lÙ­[·ÆÀѱcGµ¾W¯^Eaa!Úµk§õœ›7o"''пÏyyyôêÕ FFF•ž§B¡ÀÅ‹”fìkK:R*•¸|ù2"""ððáCäää U«VèÓ§†Zí…moÞ¼‰ââbÀ„ *ì_^Õ\­öëB«V­ÄçIIIåÖŠøð¡Æ6›픔è|ã[ã¹`ÿþý€Ï?ÿS¦LÑÚ/==½ÆcÕ†ÚÊœ¯¨¦~Ùöæ¹ýúu,_¾ðÌ3Ïà?þÐZöÏÂÂãÇǸqã°}ûv|ùå—Xµj•$¼õÖ[عs§Fà5)) ƒ„††âرcøæ›o4Êœ 8¿ýö[µmàØ±c˜7obbb4Úììì°aüüòËÕÚ·.2™ £FBnn.víÚ…·ß~[­ýúõëâ±·hÑ)))/¾øâ üøãðððÀéÓ§«4~nn.¦OŸŽ}ûöéì3nÜ8.\€••U•æ¾cÇ̘1J¥Ï<ó |||жm[ddd`ÿþý¸uë^}õUìÙ³¯½öZµÏQYzzz:t(Nœ8€€À¾j þÑ£G¸råŠøþ¾lŸaÆUyü©S§âÀJ¥9r$ú÷ïkkk¤¤¤ ..'OžT+ó)Œãçç§õ"ÂÕ«WÅ >höƒ ªR¶~e„……!==ÞÞÞèÛ·/ììì››‹Û·ocÿþý¸wïF…¿ÿþ»Rk‡©R½saóæÍxõÕWëä.""""ªœFØ700ÀÈ‘#qôèQìÙ³óæÍÓúAeÓ¦MJ³~^xáñuWWWtîÜ·o߯×_ OOOÛBÃÃÃñçŸÖx®ª ?xð@ë›åÇãîÝ»5‹ˆˆ¨<C†ÐI/´×–FŽœð;@3¿læ¾Ð¿©ºwƒãÇG·nÝ*½­P&PUvv6.\¨õýˆT*Å›o¾‰/¿üRkpÊ”)HHHÀÒ¥Kѽ{wÌ™3G-°hgg'ö•J%6oÞŒï¿ÿ¹¹¹ûêÑ£6n܈®]»Vúxšáýâk¯½†_ýUkŸsçÎUkß………8tèþ÷¿ÿaøðáâëŸþ9† ‚èèhÌœ9±±±øî»ï0wî\±ÏÊ•+áãビ'Oâûï¿Ç‚  §§ýmú¡C‡0eÊlݺU-³Ê”)x饗¥K—bóæÍ•žû70gÎ(•JLž<[·nUÙ²e˜Ã§Ÿ~Š ¤¤¿üò ^ýuÈårû¹qã&OžŒÂÂBŒ;3fÌÀ¸qãÔj–Ï;+W®Dnn.úôéƒ>ú«V­Â{g-Z ""ãÆCtttŽ©±J/Ž?^gŸV{ÿ .T ꀭ­-fÍšˆŽŽÆèÑ£Õ‚ú@i-òO?ýššŠˆˆc8::bÓ¦MåzFŽ ___ÀîÝ»‘™™YéyõÕW(**B×®]±yóf‹ 2™ ?þø#lmm‘-¾ï®-B <11QQQâëÅÅÅ …D"ÁÒ¥KüèArsssôíÛ·JãÆÅʼnåŒtýNèëë£wïÞj¯õêÕKüìPöb„0¿O?ý‰¡¡¡jwéÄÄĈ¥Žªz!¢2žþy­A} ´Dé¿ÿýoÀÿþ÷¿j•Û±c‡xá/!!+W®„——¬¬¬àêê ___µ¿DDDDTw}Æ>Pz«ôªU«°xñb„††ÂÕÕƒ†¹¹9®]»†û÷ï‹ýV¯^­±ýÈ‘#±lÙ2|ùå— ——¤R©¸Ø®ƒƒ¾þúkLš4 tfHUD"‘`Ñ¢EX°`nÞ¼‰Þ½{cðàÁ°²²Bdd$®_¿GGG¼òÊ+رcG5Ï‘&ggÀ_‡K³O_Wº°áðÆTi?þ'Ž©í¯ªã ò(?µl&eÇkl®]»&>¯îb‚o¾ùH$ø÷¿ÿW^yEl›3g6n܈U«Váܹsزe‹FPXpäÈ<ûì³Ø³gÖÀÞÏ?ÿ,ÖÿöÛoñæ›oªµðÁ˜8q"nݺ…ùóçãðáÃ5:®ÆÈÑÑÑÑÑ8pà|||ªýžO—·ÞzKë몥X„÷›e¹¹¹‰Ïccc5Ê·„ÚìÚL›6 ëׯGAA‚‚‚ʽ€!(..ÆÑ£G”f{ëÚ·±±1^|ñEìÚµ ˜7o^…û®,WWWØØØ -- §OŸF—.]çÏŸGnn.ÜÜÜ0qâDÌš5 gÏžU[7K¤»»»Wùç©Z>ë?þÀœ9s*µT*…§§'<ˆ€€Ì˜1@i ú³gÏB*•âå—_Æ?ü€k×®áܹsððððÏ…KKK õaÀ€Já½yó¦¸àse988àÂ… øá‡°cÇܾ}@éÚ7oÞÄÍ›7±eË 2»wï†sûÛNDDDÔ”4™Ôñ3fà×_E‡——‡S§NáàÁƒ¸ÿ> 1cÆ =zT-+M•ðuøðá°¶¶†¾¾>\\\ĬÕÛ‰-,,ª=Ï©S§âË/¿„©©)²³³qâÄ ìÝ»ááá9r$N:¥¶¸/5=Â]y†††U®e®*77?ÿü3àå—_V ê |}}Å….üñGWzzzضm›Ö ~qq1¾ûî;¥w7– ê@Ë–-ÅlÞóçÏãÆÕ;¨FL¼ïÛ·:uÂÂ… qâÄ dgg×xßR©...ZÛ,--Åç:tÐÚÇØØX,Ó”““£sœò²Ò»tésss¨ôÏ/""ùùùJ¯úé'¡ÄS\\œ¸ý£G¥õQÙV% <==¨¯{%í½½½amm 777¨-`|æÌšemtÎKø7äèè(Ü?øà 0«W¯FXX˜Îga¼ÀÀ@1Y(,, yyyxî¹ç`mm-fä«Þe Ÿ‡‡‡Ú]µqqqqøì³ÏàááGGGXXXÀÄÄ&&&j¯TKvU…‰‰ ,X€ÈÈHDGGã×_Ň~¨v¡"44C† AbbbµÆ """¢ŠÕ8MiæÌ™˜9sfµ¶Ý²e ¶lÙRéþ£GÆèÑ£…{÷î¡°°¶¶¶èÓ§Œ+ÜÞÝÝîîîZÛnݺ ôƒWÙ²<íÚµ«ÒíÌsæÌÁäÉ“qáÂdddÀÚÚÝ»wG›6m‹/ÆâÅÚk¿ñÆxã7ÊÝÏž=+5a1a""jþ&O/Íݽ}+ݵõ+"dÎ ûk,ã56B ‹šÖ”>þ¼¸¯²‹†ªzçwpöìY¤§§#<<\k¦ïСCÑ®];­Û_¹rIIIŽãêê '''ÄÅÅ!,, ={ö¬Êá4zŸ|ò âãã±k×.ÄÅÅáÛo¿Å·ß~ ™L†þýûcêÔ©˜4iRµ2ùõõõu.<¬úzÙµž´õÅÚè*³¢Úž““£Vº²ÿüsüøã5‡ˆˆˆˆ45‰R€Ò…A›}}}lÛ¶ ‹/ÆÁƒˆsçÎ!++ aaa ÃîÝ»qâÄ ˜˜˜4ôtµR(å¶ ë0”­Á_‹-BëÖ­+ì§zw«™™™Îm*“x#Þ7?~ü—/_F·nÝpþüy`èС€áÇcíÚµb¼H·µµE=Ôö×¢E óR=7FXXŽ;†\ºt yyy8|ø0>ŒyóæáÛo¿UÛG§Nàè舄„œ>}Z-°/¬³0tèPèëëãâÅ‹ÈÎÎFll,RSSÕŽWPçñÞ½{˜2e ŠŠŠð /`ùòåèÝ»·Úú^ …BëÞµ¥[·n8tèºté‚ÌÌL9r„}"""¢:Ò$ûÕ±oß>Œ5J£ÌNAA>ùäñï´iÓbzDDDµ¢¾3ß›Z¦}miÙ²%€Ò÷ÙÙÙÕ.ã÷øñc¥ –lSÍÒ¶)KµÜKYBé ’’,X° Rs+¯LSçââ‚?þü1JJJpîÜ9¬_¿þù'BCC±aÃwW64!C]…B!Ž+ÊìØÚڊϽ¼¼0bĈ*ÍgöìÙ˜={v•¶ÑÆÅÅE¼[äôéÓÈÈÈ@qq1ÜÝÝÅ‹,ƒ†¡¡!®\¹‚ÌÌL1Àïå契˜#$íTÖ Aƒ0hÐ ¥ìüüü°bÅ \¿~ßÿ=&Nœ¨±°²··7~þùg±ÎþÅ‹ahh(îÇÔÔ @HH‚‚‚ÄE©íìì4.ÄÕÆyܳgŠŠŠàè舃jý›"ü~Ô¥V­ZaàÀ8~ü8ÒÒÒŸŸ_¥‹Þ~ûmUc¶Í›D"AÛ¶m^á…–†´wï^,_¾\-Ó^°aÃ¥ehTGË£§§‡×^{ Û¶mÃŽ;0{öl<óÌ3µ:çÊûaaaâ e“n¼½½„5kÖˆ‹ÊÖUùËV­ZÁÔÔÙÙÙZ'„qóòò°zõj­s6lV¬X???ëÔ!˜«µ½¸¸k×®-w‰‰‰b®îÝ»ÃÌÌLlKIIA^^œÿm]ÒÒÒÄE»wï®V ˆˆˆˆˆjÏSó.kûöíˆÅÉ“'ñË/¿`Æ رc…Y³fÕJm}"""jþºvíŠþýû8 –ب Õá³Ï>  4söüùó:·9{ö¬øÜÕÕµªÓkô—””ˆ‹w>mÒÒÒðúë¯#$$Dk688X F ¥T£œœ¼òÊ+‹ã®[·¿ÿþ;`Þ¼yUºx³téR´lÙ¹¹¹9r$BCCµö»qãæÏŸÿê@9¼¼¼”^€ŠŒŒ„™™úõë§ÖG¸£àÊ•+Jo­(ЬËñãDZpáBDEEi´)•J|÷ÝwâBÁÚ~'ìííÅu¿„ù”½ã¡_¿~033Ã;wÄòVÂqÖ6áoÒõë×±mÛ6µ¶¬¬,¼õÖ[/w¿üò ŒÁƒãæÍ›jm±±±èÚµ+&Mš???ñîU.\À¨Q£ÄóöÞ{ïÕ䈈ˆˆ¨OMÆ>Pz[mÙDDDDÕñÉ'Ÿ`„ (((ÀôéÓñÇTX×üÀHIIÁ¬Y³”Ümll––†ÿüç?Z3y‹‹‹Å Ý3Ï<#«¢W¯^èСîÝ»‡uëÖÁÛÛ»NÐlŒ öíÛ‡}ûö¡U«Vpssƒ½½=ŠŠŠpçÎ\¾|@i­÷yóæ5ðluû裰víZtìØÇ‡™™.\¸ §=<<ðñÇWiŸŽŽŽ8tèÆØØXxzz¢S§NèÑ£ ‘‘‘ˆˆñÎZ?.àŸÚó¢ÒîîîÐÓSÿ¸Ò§OXXXˆãš”ÑÌÉÉÁúõë±~ýz8;;ÃÕÕ-[¶DVV®\¹‚˜˜À„ tã½½½Åsoaa¡±°µ¾¾>†Š'N:tè''§jϹQzj2ö‰ˆˆˆjÓ€ÄVoݺ…‘#Gâ·ß~ÓXt¶¸¸§OŸÆË/¿ŒÙ³g#//OlÓ×ׇ¯¯/€ÒŒñåË—£¸¸XlÏË˃¯¯¯X;ûÃ?¬Ö†R©_|ñ$ """ðæ›oŠå6T) „„„`Ú´iÍnñ\sss¼ýöÛpttDzz:N:…Ÿ~ú {÷îÅåË—ahhˆI“&!$$VVV =]Æ}ûöÁÔÔÄÏ?ÿŒ¨¨(èééáÝwßÅ‘#GÄ’,U1hÐ \¼x“&M‚¡¡!îܹƒƒbïÞ½ðóóCbb":vìˆ>ú}ûö­ƒ#+¥¨×v¡K&“©•¾ªIö{÷îÝ1vìXXZZ"&&‡ÆÎ;qàÀÄÄÄ eË–X¾|9~ûí7ûP£‡‡‡Ö50TûÔU¶>Pº††ŸŸŸ¸Èïµk×ðË/¿àðáÃ044ÄÖ­[±páÂjï¿gÏžøÏþƒÑ£GÃÂÂÅÅňˆˆ@`` BBBÄ ~=°mÛ6üöÛo,ÃCDDDT‡$™™™\Ɉˆˆˆš!ëZ(q£ºèl]Ù¶m¾øâ Èår¥5Ëaee…ììlÄÇÇ‹Á|}}}lÚ´ ãÆ·/))Á{gcÇŽZ·n¾}û¢¤¤çÎCff&`Ò¤IZëc÷éÓ Xºt©x‘@—;wbÙ²eP(Édpuu…““”J%RRRpóæM1 ûömXZZÖü•C‚ å|||êt<Áýû÷‘€””””” M›6pssƒ¹¹y½Œ_U±±±èС€Ò²Lýû÷‡B¡À… SSSôëׯÂ;F*+??—/_Frr2Š‹‹Ñ¢E tîÜíÛ·¯•ý76 …QQQHJJBZZ о}{¸ººVë"Ic)Þùжm[ôéÓGçÂÛÕ¡P(p÷î]Ü¿?†žžZ´hîÝ»£M›6µ6Ne:t€f$"""¢æŽ}"""j6"°ÑÑÑøþûïqòäI±Dˆ*KKKŒ?3fÌк0©B¡À–-[°iÓ&qAP ,X€É“'k»*}8þ<Ö¬Yƒ°°0(•êo% z÷î^x3fÌÐ(ƒRÛ*°ßÔh ìQ)ö‰ˆˆèiõTÕØ'"""ª ...ظq#är9"##‘’’‚ììl˜™™ÁÉÉ :u*·$…L&ƒ¯¯/fΜ‰k×®!11‰mÛ¶…««k¹Û^ºt©Jsíß¿?8€G!<<™™™J¥°µµEçÎÑ¢E‹*툈ˆˆˆˆêûDDDDµDOO®®®5Ú¾OŸ>µ8#ÝZ´hOOÏz‹ˆˆˆˆˆˆjW3"""""""""""jB˜±ODDDDÔˆµlÙ›7o8;;7ðlˆˆˆˆˆ¨1``Ÿˆˆˆˆ¨377ÇŒ3zDDDDDÔˆ0°ODDDD‚R©lè)5 ¬±ODDDDDDDDDDÔ„0°ODDDDDDDDDDÔ„°5; …Bí+QsÂÀ>5;%%%j_©q’H$ ="""""¢&‰}"""jv„EXØoܤRV…$"""""ªö‰ˆˆ¨ÙÈÌÌ„……5ðLˆˆ¨>ùûû7ôˆˆˆˆjÝðáÃu¶1MŠˆˆˆˆˆˆˆˆˆˆ¨ aÆ>5+ãÇoè)Q=áß|"""jŽþüóÏ û0cŸˆˆˆˆˆˆˆˆˆˆ¨ a`Ÿˆˆˆˆˆˆˆˆˆˆ¨ a)"""j¶z DDDDDDD•2lذJ÷e`Ÿˆˆˆšµª¼1"""""""ªoÕIJ«·À~NNbbb••…ÂÂÂú–ˆˆˆê˜¡¡!,--áìì ss󆞎VzzÌe """""¢Êó÷÷G=кuk(•J€R©Ÿ TÛ*úªkÛâܹsUš_½|ÊMHHÀíÛ·5&NDDDM_aa!RSS‘––†Î;ÃÑѱ¡§DDDDDDDT§ªÐ¾–}M"‘T{ü:ìçääàöíÛÉdèÕ«˜5GDDÔŒÈår<|ø×®]ÃíÛ·aiiÙh1·K IDAT3÷‰ˆˆˆˆˆˆšƒ:°ÇÄÄ@©T¢W¯^h×®0sŸˆˆ¨‘Édâÿñ—.]BLL \]]xVDDDDDDDÍ—´®ÈÊÊØÛÛ×õPDDDÔ€„ÿë…ÿû‰ˆˆˆˆˆˆ¨nÔyƾ°P®L&c¦>Q3&“Éüó?Õ:ÏØ'""""""""""¢ÚÃÀ>QRç¥x,ÃCDDDDDDDDDDÍÕ‘#GcÇŽ­ó±ê-°ODDDDDDDDDDÔ9rD ìÀ˜1cêt¼zì3sŸˆˆ¨ù‘H$ =""""""¢Q6¨äÈ(•Ê:ÍÜgÆ>Q5” ê Ž=  î2÷¹x.Qé ê Ž=*øk[½/žÛXKñ¼ÿþûˆŽŽÆ«¯¾ŠéÓ§«µýðÃ8xð ºvíŠ 64Ð ‰ˆˆˆˆˆˆˆˆˆ¨18rä>\a¿ºÊÜotû?üð,,,*õøá‡jmÜË—/#88111m÷îÝCpp0®^½ZkãQÓRTT„àà`ãñãÇ ="""""""""j ‡®TP_P™û.c¿¸¸………•ÚgqqqÜ kŸJ¥²ÑÞq@uëÑ£G1bÀÏÏîîî <#"""""""""ªo‡.·üŽ.ÇŽP{™ûzñÜßÿmÚ´ÑÙîääT³!"""""""""¢§Ù¸qã0nÜ8DöÊ|­Í¤ñFØïÕ«ƒ÷DDDDDDDDDDD*])ž²ÛTç*Æýû÷€„„H¥R´k×#FŒ€££cÇ,¯íÑ£G8uêîÞ½‹‚‚ØÙÙÁÝÝ®®®:癞žKKKtîÜY£=!!‰‰‰€Î;ÃÒÒR£Ï•+W —Ëáìì ›ŠO«ÄÄDøûû#..EEE°··‡···Ö9%''ãÁƒ€N:ÁÊÊJë>333q÷î]@»ví`ggW£qµINNÆ™3gƒ¼¼<ØÙÙá™gž——ŒÕúFFF"77ööö:rss xöÙgahhˆˆˆ@BB‚Ú¾„6AïÞ½!“É4öàà`$''COO...1blmm+uŒDDDDDDDDDDe5êŒýªÊÊÊ‚¯¯/öíÛ§Ñ&•J1eʬ]»V#è[SJ¥_ý5Ö®]‹üü|vwwwüøãw–-[‰D¢u.DDDDDDDDDDº4ºŒ}ÕöªdìçççcäÈ‘bväÈ‘ðôô„B¡ÀÉ“'Š;vàÎ;øë¯¿ §§~èeÇ­lÌ™3;wîtïÞ>>>077Ç•+W°ÿ~ÃÓÓÁÁÁjÙâžžž€¸¸8Ü¿ÎÎÎb›B¡@PPø}@@fÏž­6îéÓ§&&&èׯ_•înÈÎΆ··7"##!“ÉðÒK/¡_¿~000Àµk×°oß>üù矸ÿ>add°±±Á®]»0fÌ᫯¾ÂÒ¥KÕö½bÅ œ;wR©»ví‚8·êŽ+xôè†.^8p ¼½½Ñ¢E dddàï¿ÿF`` Ê]¹¢×U÷|||гgOüú므ѣGk¬ý``` ö¿zõ*F¬¬,XXX`„ èÖ­ŠŠŠ€3gÎ`õêÕHMMÅÆ+þaUÓÑ£GÅ ÄU5vìXŒ;¶–gDDDDDDDDµ¡Qgì_¿~)))ZÛZµj…gžyFü~ÅŠ‡D"Á?þˆ7ß|Sl[°`Ö­[‡Ï>û !!!øî»ïðñÇ×ÊOœ8!õ§L™‚ 6¨•d™ÁªU«°zõj ùäñõÚfΜ‰¨¨(`ûöí˜8q¢Æ±ÅÆÆ"77·Jç£<‹-BJJŠØŸ;w.ÜÝݵöÍÏÏÇ[o½…¬¬,ôêÕ GŽA«V­Äöùóçcûöí˜;w.vìØx{{×Ú\‰ˆT ùª÷Ô'""""""jܤw©Bte‚×^{ žžžZ«W¯ûçää`ÇŽ€W_}o¼ñ†Æ>,X c7mÚ„¢¢"­c–7míß}÷ÀÙÙëׯ‡T*UkwwwÇG}ð÷÷Gxx¸Ø&‘HÄ99sFm»3gÎ(]e¹[·nÈÍÍÅ… ´öñôô¬ÒùŠŠÂþýûëׯG¯^½4ú¸¹¹‰™ø[·n…\.Wk_¼x1ÜÝÝQRR‚)S¦ %%ÉÉɘ6mšxÜ‹/®Õq¯_¿.§>ùä¼üòËZÏÉÉ Ý»w¯ôÏ·6~„Çž={###ìÞ½-[¶Ôè3mÚ4¼ð €~ø¡J?;>øàƒª>ÆŒƒ1cÆÔYÿ²"""""""ª{õد333XXXh}˜˜˜ˆýΞ=+fhOŸ>]çþ„¶´´4\½zµÆóËÍÍEXXàí·ßÖ™5?mÚ4±–ºŸŸŸZ›Ñ¨Q Ú{yy©½ÑÑшWÛGeýùçŸP*•033Ã+¯¼¢³ß„ ”.„¡Ö¦Zf'%%S§NÅÔ©S‘šš ìÞ½[£ö~MÇ=|ø0ÀÈÈ3gάÒ1×—C‡(]W¡cÇŽ:û½üòË€ˆ¨ÎU6Ÿ™úDDDDDDD•#‘HªýJ¥±ÓªjÔ¥x.\¸ ±à¬6BðW&“á¹çžÓÙ¯ÿþjÛôëׯF󋌌íÛ·¯Î~¶¶¶hß¾=bbb4äBÐ>==èÙ³' ð÷ßC&“aèСJ¥Ø´iΜ9ƒ%K–ø'Èoee…gŸ}¶Jó¾|ù2ÀÎÎ{÷î-·¯D"R©D\\œÆ8vvvعs'Æ'ÎGø·nݺÖÇ.ƸººÂÜܼGZÿ„cÔÓÓÞ={tö»sç€Ò5²²²t.LDT[**Ëà>‘:…BÑÐSЩÑ-ž[v›ÊôÏÌÌXXX¨-bZ–øüÑ£G:û•}]õ{Õ績˛«­­-bbb4ÆíÔ©Ú´iƒ¤¤$œ9s=zôÀ¹sçPPP€¾}ûÂÜÜC† žž.^¼ˆÜÜ\˜ššŠtwww1^Yiii€{÷îaÆŒ•Ú&;;[ë^^^ðññÁS§NKÕö¸=Pza &Yî•ù¹—ýÝ+¯MPTT„œœÀñãÇqüøñJÍ'++ –––•êKDTB‰cÇŽi¼.´ðäÉDEE!66¶ÜÏË•1—×·ì:¤•Ѩ3ö+K¸m¡¢+(ªíª ÜÖtܪŒ­m\ü÷¿ÿE`` |}}ÅEq…l~333ôîÝçÏŸGHHF…àà`µ>ÕáêꪶÈpyz÷î­õõëׯ«ˆŽ?ŽeË–¡eË–µ>neÎ Eõæøñã1pàÀJmgmm]WS""Ò då »ÇŒÃL}""""""¢&¦Ñeì——-¯‹DÎÉÉ3Úµyøð¡ø¼U«V:¯š”w•EµM5x˜˜ˆž={ꜣ0¶¶q===ñßÿþ¡¡¡(**³ñ=<<ľžžž8þ<agg'f¯«ö©,áÎ###Ìš5«ÒÛ•'77“&MBaa!zô褤$$&&â½÷Þþ}ûÄujk\[[[Àƒª|ÌÂEaÑdm„uÊŽ«í¹¶}ÀÂÂÙÙÙpqq©Ñ¹%"ªKcÆŒQ{οADDDDDDDêLMMÑ¥KØÛÛ«Å¶ËÆ¹«òUW[u4êÅs+K¸UA©TâìÙ³:û YîЫW¯Û­[7BCCuö»wï’’’tŽëáá ôöŽÓ§OãÚµk066V[@X ÷Ì™3bF¿½½}¹ ´ê"ì÷Ê•+ÈÈȨòö___Ü¿fffسg¶nÝ ‰D‚“'ObãÆµ>®°&Bdd$«´­PêFõâNY7nÜÐÙ¦z§…°®‚6Â1ž:uªJó#"ªoBù"""""""ÒíþýûˆEll,âââðàÁæÏŸ 4£}ñâÅbÉ¥R‰'Ožà½÷ÞCTT`Ñ¢Eû¯h\]m ,€L&CFFÞxã ¤§§‹m%%%ظq#vïÞÿcï¾Ã¢¸Ö0€¿»°ô&Ò¥ˆDTT{‹½—koÄ’b)£&S4Æ$J,1–¨ÑDo®½Ä‚ 5*X°Ó› Ò;.°ËÞ?#Ëî*‚èû{wfN›Ù䛳߀qãÆÁÁÁAmû%Aú›7o€°méslß¾= ‚‚‚-lwéÒå¹ÇýÅ_ ..ýõÖ­[‡ß~û mÚ´µµ5òóóƒû÷ @i퀼¼<øøøàÉ“'hÚ´)V®\©Ô®D"Á¶mÛбcGÄÄÄ`Ö¬YرcÇ ÷[⫯¾BDDNž<‰ŸþÛ·o‡··7ÌÍÍ‘––†   ¤¤¤`ÅŠJ wíÚÝ»wÇÙ³g±zõjýôSL›6Mm›¥ÇW^Ÿê޽÷Þ{°··Ç_|ððpœP|¯:u ?ýô6oÞŒ¤¤$?~\©­ºuë¢_¿~5jgºÑk?ˈˆˆˆˆˆˆª(==ý¥þ%^tíÛ·/€ò­*2™ 7nÜ@||êÕ«‡¦M›¾ô±¿H¿EEE¸{÷.¢££!“É`ccƒ ÀÆÆ¦Üz±±± ‚\.‡““Zµj‘HTU§¤vŒ111ÈË˃±±1œáâ⢴ /QmWò;¶äAfÏž=kd~~~:t¨°}úôiôèÑCø„QeøùùÁÍÍ R©UÚvɤ⼼""¢×‡H$‚B¡àïwqq™ÂëôôœZØ—J pÿ¾pÿ¾RiôõujxTDDDDDD¤ÉKìëêê"??2™ ‰„Á}""¢×ˆH$~·Ëd2Å¿ûéÅ(@rr&²³ŸÀÀ@VV¦ÐÒâÒHDDDDDDTì¥öMMM‘””„äädØÚÚ ?ßMDDôÚP(HNNPü»ÿMRTT„Õ«OàÔ©ܸ‘!ìç½01‘Û"‘Í›[bÁ‚~°µ­£¶-™LŽ}û±nÝøû?ýߢ…>Þ¿5||:ÃÀ@ùÁIA ¿ÿ~‡=@VV qã:øôÓ>hØÐ11ÉØ¾ý΋B¡€ŽŽºvuÂGõCn®+Võk Jmöî½ÚÚOÿ¯¦££…nÝŠëèêJ@DDDDDD5ë¥ö‘œœŒ( XYYAKK‹}""¢×€B¡€\.GRRBCC!‹áìì\ÓêV·nÅàãTö߸‘§²ïìÙ 4h`Ž>è«r,** Ÿ|²ûö%ª»}û f̸„?þ¸_ß¡hÕêé5ö÷¿iÓü•ÊŸ;— ƒ3X½zV­:µk#”ŽŸ<™†ví &&«V«ôwñb–ʾ“'ÓЩSctîì¦rŒˆˆˆˆˆˆª×KìÃÕÕ!!!xð༽ [f\€fÍl(ö½¼ áîn++ØÚ^@B‚¼Â±7k¦7·z–#"""""¢—¯Zϵ··‡©©)¢¢¢™™‰üüüêè–ˆˆˆª®®.LMMáììüÆõÀØXgÎÌF||*æÍÛýû“{÷öƒ»»r ÜÊÊuê©´ñí·‡… þ€øê«þhÞÜ ÚÚb( „‡?ÆŠDZuk,Âà °`Á>lÛ6b±––&8wnV¯>Ž… o mîÙs..6عó¶R_«VµÁÌ™=¡§§kk3„èèdxxlÊù@OïiʱXŒzõÌUÒQͨ–À>PˆDÀèÑíáà`ŽŽw+•­[WŒ¿ÿ‡6mTÓQí#®é½É eÏU/=]uqÞÂBüüT×3JM-Â¥KaÉŠž«/""""""zµpÆ>Q *Y·ÄO?µ…¥¥jþ²ÜÝí•¶³³Ÿ`Þ¼¿°qc”°ÏÔT„ÌLàï"** ß~;††zU0r""""""ª) ìi— ?¿»¨[×}ûz@")ÿ¿N::ZÂëìl©Ò±üüBFàèÑ;‹EXºt($m4nl‡,pôhÊ¿}f`òä.055Pª/• $$ÁÁ`ffú±Ç3ðþûâàÁ$aßܹ.X¼x ~ùå /øú†!&æ7¬_?vvæBY±X¤ÔWn®T)Ç~FF..\Æ¡CwѵkCL˜Ð©Üë@DDDDDD/ûDDDDj$'g¡W¯MÎ|ýu-RnOO{lÚ ˜;÷(zö¼…BÄÄ\$!4´@(Û·¯;:wvƒX,š5ÿÁ›‘ Ç?„`óæU8ÐÖÖFÉŠðða&ΜIfß@@€!Ú´i„C‡®áý÷#!A®4–.]¢n]cxx8ö<˜„‹×Á×÷-Œ× «+Á˜1vؽû`âÄðð°‚T*C\\üü’„¾ÿø#ýúy n]ãç»°DDDDDDôÂØ'"""R#88^êÀ¾}¡X´¨ü:C†xb󿛏v-AAy V[®oߺpuµ¶6´Á®]Ã0yòAÄÄ"3S]»â5öc` fÙ¯\é¯Ô€#GîaØ0oüý÷=•c©©EX¸ð<ÆŒé ´óÁÝpèПÈËSàøñT?žª¶ï÷ßwQù4U/.žKDDD¤FëÖÎ4ÈRØž;·]…ullÌð¿ÿùàƒ«=îãã€#GáС鰲2U:Ö½»;gaéÒ05©­ß¥‹)V¯n‡ÐÐYðôløúë>5ÊV¥ŸY³ºÞ}· ú÷¯«t|È+lÜ8@)O»vqúôX l‰²lmµðÉ'M8?ü0ÚÚZ*eˆˆˆˆˆˆ¨úˆÒÓÓ#"""zõùùùaèСÂöéÓ§Ñ£Ghk?߇Ÿ<)ÀíÛ1033€«k½gª›˜˜„„ dg?¹¹êÕ3‡™™a¥êÊðèQ:ââR!‹al¬3XX˜<Ïi<“¢¢"ÄÅ¥âñãLÈdrXXÃÑÑzz’—Þ7Ñ«ÂÏÏnnnJ¥00¨ÚO-+ ( äååAWWðàÁôèÑpàÀ@Ïž=5¶ÁTÌ'""""""ªÕ¶x®‘‘QuuUmBBB...‰D5<¢Êá}KôæP(8þ<š5kkkk( aÉëÒe+û¯¦ºíÛ·ÇåË—_ÒÙQ‰j ì— Ôf%ÁÐÒçô:½žxß‘:ÏÐ/ù·ì>>$$""""""ª^\<—ˆˆˆˆˆˆˆˆˆˆ¨áŒýPvÆ"QmÀû–ˆˆˆˆˆˆˆˆ¨vãŒ}""""""""""¢Z„}""""""""""¢Z„©x^SšPmÄû–ˆˆˆˆˆˆˆˆ¨vãŒ}""""""""""¢Z„}"""RrèÐ!>|¸¦‡ADDDDDDD0Ï xSSš9r¾¾¾Jû6lØ€† >s[£GFzzº°Ý¡C,]ºôE‡HåxSï[z5LŸ>=z4¦NZÓÃ!5:„C‡ Û¬ÁÑ‘:ÕØãÇÇÑ£GUö‹D"èééÁÆÆ^^^˜4i:wî\#|õ|õÕWøá‡Tö9›6mª’>páÂ¥}¹¹¹ÏÕÖ•+W””$l›™™½Ð؈ʺsçŽðóaýúõ7n\ ¨XXX`§`· IDATff†-ZÔôp^صk×——'''899i,wãÆ Ü¾}ÞÞÞÕ8:ª¬²AýC‡A¡P`РA58*"""""""*ë•NÅSXXˆüü|•/©TŠŒŒ cçÎèÝ»7fÍš…¢¢¢šrR(øý÷ßÕ^³}ûö!;;»¦‡HTí …ð} —Ëkz8___ôéÓŸ|òIM¥JL:}úôÁï¿ÿ^ÓC¡çT6¨_âðáÃLËCDDDDDDôŠy¥Sñ”Ô±µµÅ±cÇ”ö'''#((k×®ÅDZeË4oÞï¾ûn•¹²ã{URšœ;w>T{,//ûöíäI“^Jß …¢J®CUµCš½j÷íËVú<_¥û«ì¸^'åÏ–-[›› ;;»×î¼k3MAý‡æÌ}""""""¢WÈ+Ч„D"«««Ò¾&Mš sçÎ2d¼½½‘••…mÛ¶Uk`ÿU³k×® ¿¬À>Qe¸»»×ô¨ŒC‡áàÁƒ–+™µÏœûDDDDDDD5¯VöËãèèoooøùù!22Råx~~>nݺhÚ´)ŒŒŒððáC;v ñññ044DûöíÑ©S'ˆÅ¯tf¢råääàÀJû,--‘œœ,l_¼xÑÑѨ_¿~…íeeeáØ±c …––ÜÜÜЯ_?èëë?óØnÞ¼‰sçÎ!-- VVVèÙ³'ÜÜÜ*UW.—ãúõëJû`kk ™L†S§NáöíÛÈÌÌÄ AƒÐ¾}{•6ÒÓÓqñâE„„„ ==ppp@·nÝàèèXáJÖˆŒŒDvv6tttP§NXZZ¢yóæhÒ¤ ´µÕ+Éår\¾|wîÜAbb" `jj sss8;;£eË–°°°¨Ôµ —#22)))055 ^ºt W®\AFFlmmѧOŸ ‡NKKéS§ŽÜÜ\˜ššÂÂÂhÕª´´´ ¾7³²² Ô–po¦¤¤ 22b±^^^€œ>} 055Òù...Âú÷îÝfìk#Pü¾œ9sqqq‹ÅpttDÏž=+¬Sïå›äàÁƒ• ê—(™¹Ïà>QÍz¥Sñûì³rÛú믿0wî\ddd(í·¶¶Æ¯¿þªö|Õ¥8IOOÇ´iÓpüøq•òcÆŒÁš5kÔö_ºììláý+±lÙ2ôêÕ ãÇWz˜S§N´k×NØNMMÅâÅ‹±{÷n¨íkРAøþûïվ™˜3göîÝ[î{¬§§‡¥K—böìÙJû8€O>ù 뀽½=îܹrËUµWá¾­eϳìöòå˱k×.ôìÙ7nĤI“péÒ%¥2Ÿ~ú)æÍ›‡Ï?ÿ\m+W®ÄŠ+ŸŸ¯ö¸™™âããþþþ3fŒpìÖ­[*÷øÌ™3±råJÀßÿ÷Þ{ºººˆÅ¬Y³ð×_ eMLLðñÇÞÿ}â£>ÂW_}¥v,÷îÝC÷îÝ÷ïßW»ÐíÑ£G±`ÁµKÀËË çÏŸüüóÏX·nplÛ¶mضm›RùÝ»w )\¦L™‚;wîhcVVæÌ™£tŽ%Äb1Þ~ûm¬\¹RíCƪx/ß$,7ýŽ&GŽÀ™ûDDDDDDD5©ÖÏØ/=;ÔÛۻܲkÖ¬ÁÁƒѬY3 :FFF¸víöíÛ‡«W¯¢ÿþ¸xñ"LMM«cèUjçÎJÛõë×ÇàÁƒÑ±cG\¸pAØ_Q`ÿ¯¿þÂäÉ“Õ}1bÄ 0 ÂñT @ÿç?ÿŒ1BéXdd$þùçtèÐA¥¤¤$Ì™3G%`cjjŠ&Mš ..ñññ*)ÔY¾|¹Ú ~“&M```€;wîàÌ™3•:¿²¶lÙ¢6¨T—J¥1b„JP¿W¯^hÕª?~Œÿþ÷¿Bê””Œ=044ܸqCåšöìÙžžžÐÑÑAjj*}ZØ>|8†dff¢_¿~X´hÑsõ¿lÙ2ܾ}"‘¿þú+Æ'ûè£ðÃ?à‹/¾À… °zõj!QYÏû^Õµ"Ï£GдiSµÇ$ f̘Y³fÁÑѱܴõêÕÃ?þ±X¬´¿G˜>}:|}}ñûï¿cÉ’%B>èò”ÅXSvíÚ¥2†#F@¡P`èСøøã•fÆïÚµKm.úM›6!++KißàÁƒ±yóf@¡P`ùòåøöÛoUê–žÁ™››‹7*×ÓÓÃÞ½{ѵkW@tt4  ôÀ¦t[ê^—ÞgllŒE‹¡wïÞÐÖÖÆ½{÷ §§…BM›6!<<\©Î/¿ü‚ &Ûï½÷ºwï.¤è‰‰‰ÁÆñᇀƒ¼DÿþýñßÿþWe,8sæ d2™ÒX6iÒ$øøøTê½+¯?M}¯X±2™ –––øã?`ff¦ÒŽ––z÷î]é1WvŒ999زe €âOËŒ;V¥>ú~~~ð÷÷ÇÚµk1gÎH$µm?Ï{IDDDDDDDT[T[`_.—?s’€ŒH$‚±±±Ò±‚‚H¥RbÏž=055ÅüùóUÀ-âdäÈ‘H$jÇ2qâDøúúB*•âܹsB>huJú(içyέ*ýñÇJÛ...hÚ´)är9ÌÌÌеkW¥¶{÷îÅŠ+TrT=zTi["‘à»ï¾ƒ®®®pŽóæÍßþ‰¨¨(¥²EEEB™³gϪÌb?~<:uê$”qppÀ‚ 0}út¥r …Bézjº¶¿ýözõê%l—ä —Ëå*ø–-[bìØ±Jm5kÖ }úôÁáÇ•®Ëœ9s@å>º}û6.]º///¥ôZZZÂ8J·_ú!@qŠ#XZZ*í¯W¯ž0ëøeßG¯Ú}[]Jÿ (}Ÿ–(ù9ckk‹®]»ª½.­Zµ^GFF*-xlgg‡¨¨(ìß¿ И¦¼q•÷^”.7qâÄrË–œ‹ºóT×^érR©'Ožú111y®{¤¼¾Ëã… „uB&Ož¬±)S¦ÀßßÉÉɸ~ý:Ú´i£Òöó¾—DDDDDDDDµ…¸â"5ÏÞÞ>TúJLLDHH–-[†ììl,_¾S¦L)·OOOÇ\\\`dd@u¶ö«, JûFŒQîvvv6Ž;¦´¯¨¨÷îÝSÚתU+ØÙÙ)í‹Åèׯ_¹cºsçŽÊ>u‹,>žžJAýÒd2™J  ŒŒ Lžøà! k׮ő#GpåÊlذ᥿Ç%ßeä•Vú2¥•þ¾}øð!Z´hQµƒ«@ÉÏÝììläææÂÐÐPm¹øøx•:ôb^ä¡QI]~òˆˆˆˆˆˆ¨z½Ò©x*[?&&F8nll¬1•Ë?ÿü£’o¾Ä7„ ³‡‡G¥RñTfl/“º4<ÏZöìÙÂv«V­pùòeaûÎ;¸ÿ>ÜÜÜ„}R©Ti«tJuù±÷ìÙ£’›÷îÝjÇUQ*žòö‹D"x{{ãÂ… ¾›7oÂÁÁzzzjëÅŸBxüø1´µµÕ¶íää$,Ð _¥ùÑÑÑjëêêê¢mÛ¶hÛ¶­°oݺuX¼xq…u«Ò«rßV7M©g**[ÞþŠ®H$BÛ¶máíí.]ºàîÝ»¸pá>üðC¡LÉ õ¢¢¢J©¢~Kôè‘Æ²¥×À(}=\]]add„œœøùù¡ÿþåöUVé÷Ï“ŠÇÃÃCØ÷Ï?ÿ gÏžjëøûû+ÕyÖŸoê÷Á›²X6ћⵘ±¿~ýzáué…Ëúßÿþ‡Ï>û –––*Ç6lØ xÆw‡ª~U,)) gΜQÚ׸qc 0@c .àúõëÂvpp0‚‚‚вeKÀ°aÔû0}útlܸ®®®HNNƧŸ~ª6‡~iíÛ·‡µµ5…}‡Âúõë1eÊèêêâäÉ“øþûï+}¾ÏbÒ¤IJýØØX̘1«V­‚¹¹¹RÙèèhìß¿[¶lÁ´iÓ0wî\Àƒ°|ùrŒ7]»v…¾¾¾R½ÔÔT•üùÂë ÀÚÚDãÆUÆXöS¥ëÒëC$¡^½z¸{÷®ÊÚ¦¦¦ |R¨*¸¸¸ÀÏÏÿüóòóóUÒ@åççcûöíjëjiiaøðáØ±cvïÞ™3gV˜†ª´=Ÿ6mÚÀÊÊ IIIX·nÚÀ~aa!~ùåÅ ä–~èHšåææ"88¸ÂˆÏòDSÙò>&""""""¢ªS+ûr¹\if4Pœj"** {öìÁ®]»§’˜0a‚Ævrrràããƒ;w*x}}}…\õ3gÎ,wf÷«â¿ÿý¯Ê ÌéÓ§còäÉëøùù)­Gþù§Ø?~<Ö®]«”‚çÖ­[h×®JšžòH$|òÉ'˜7ož°O¡P`Ñ¢Eøâ‹/ ¥¥UnªUœ,Üß¿?Nœ8wwwØØØ ++ !!!Jë ”&“Épøða>|‰ 6„½½= žžŽÀÀ@•ëÑ©S'áõDZqãF,[¶ pqq¹¹9är9BCC¡T·sçÎUx¨º¤¤¤`þüù˜6mÚµk§²¾Ä¥K—„æe:–¤º ÇÞ½{1`À€þÙÓ§O¬_¿IIIX¾|9–,Y"¤JIKKÃìÙ³¥±þ'Ÿ|‚ ++ ÇÇ–-[àåå¥T&)) »wïÒx•>Ÿ€€;v ãLJ‡‡‡ÆƒÕÑÑÑÁܹs±páBœ;w‹-ÂÒ¥K!‘Hyyy˜={6BBBóæÍ{é뽪jE*žGÁÕÕµÜ2õêÕî]»`bb¢1uÅìÙ³áëë‹–-[¢[·n022µk× 80;{öì ÇZr¼ì¿Õ©l‰D‚Áƒ—;–®]»ÂÂÂBiFíÞ½{ñÕW_A"‘@__›6m°a×—§T·$ˆmnnŽQ£F ³fK”Mq2eÊøûûãðáÃJåär¹ð@bêÔ©8tè’““UÚR÷ZS_e‰D"ìØ±&LÀ¥K—„ýyyy ÔX¯t»¥Û/,,Dpp0‚ƒƒ5Ö6mš6mªv\)))åÎb®S§>ÿüójKÅS“÷mM¨l*žŠŽ©+'—˱ÿ~ìß¿uëÖE‹-`kk‹‚‚DDDàæÍ›ŠóïϘ1C©>}ú ~ýúˆŽŽÆ´iÓ@˜aÿÎ;ï`Ù²ejû.OçÎѵkWœ?kÖ¬Á¡C‡Ð¬Y3dff"00………X¼x1¾üòKµçloo­[·bÒ¤IˆE¯^½àîî( DEEáÎ;022RJã“'OÆŽ;˜˜ˆž={B$AGGðÛo¿¡oß¾^ïwß}—/_ÆáDZ~ýzìÝ»ÞÞÞBzž´´4€FU¥ïåëÌÐÐMš4Ò÷¿¦Ÿ •ù÷MýyBDDDDDDôª¨3öÕ‘H$033CÓ¦MÑ·o_L˜0Aãb‹%OOOÌŸ?_)ଭ­ñãÇã›o¾f‡¾Ênß¾{÷î)íëÞ½»J𙲴µµ1dÈlÙ²EØ—ššŠ“'O )|Ú´iƒ#GŽàÃ?Ä­[·”êwèÐkÖ¬QÊq­‰H$ÂæÍ›ñÝwßaýúõJ³ÛMLL0oÞ<̘1‡ª°­çajjŠƒâ÷ßÇÆ5åuuuáé鉾}ûbÔ¨QÂ~Œ7ˆˆˆÐ´jذ!fΜ ¥ýýû÷Gnn.®_¿®’²§tßýû÷ÇâÅ‹áììüœgJ5ÉÈÈcÇŽÅùóçñèÑ#œ={V鸮®.† †/¿üRHUSúØÑ£Gñý÷ßÃßßñññ¢Ï2™ì¹Ç´}ûvÌš5 GŽATT”0C¿Aƒðõõ‚íš¼õÖ[ðóóÃ’%KpúôiÜ»wOéçM:u0lØ0•znnn8zô(Ö¬Yƒk×®!55U8ŸÊæw‹Åغu+~þùgøúú"11Qégµ¥¥%æÏŸ©S§Vª=RYåŸr( ò+ •ÔODDDDDDDôòˆÒÓÓ_ê4»«W¯¢mÛ¶56›/66VH5sòäIxyyA.—ãúõ눇<==aaaQé6KÒm”¤„P—Cýupÿþ}„‡‡C,ÃÍÍí™òm—–““ƒÀÀ@¤¥¥ÁÊÊ mÚ´©ötG‰‰‰xðàÒÒÒPTT8::¢Aƒ:322…ôôt¤§§C$ÁÌÌ 7†ƒƒC¹u‹ŠŠ…¤¤$¤¥¥!77úúú°··‡››[µ^‡7å¾­)ÑÑшGrr2ŠŠŠ`mm ÕÈxbccqëÖ-Èår899¡eË–ÏÔMKKí[·––ØÚÚÂÕÕµZ€Êd2ܼyñññ‰Dptt„‡‡‡Jº#ªØõë×áææ©TZåëy”õóòò„Àþƒ” ¯n~~~:t¨°}úôiôèÑã™RCùùùUûßÓ=zô8pÔ®AXâü+WKK«ÜEv©XÓ¦MÑ´iÓnÇÈÈÝ»w¯‚=?kkkX[[?W]33³ç^R,£aÆÏýP„júõë£~ýú5= ££#_¨ ssóûÞÕÖÖF›6mЦM›韈ˆˆˆˆˆˆèUV+rìWU¿U•O™¹…©6â}KDDDDDDDDôz`N""""""""""¢Z„}""""""""""¢ZäµOÅS§N¬Zµ àääÄT<ôÆâ}KDDDDDDDDôzxíû†††ðññ©Òq0@Jµï[""""""""¢×CµöåryuuUmŠŠŠ¼žçF¯/Þ·DDDDDDDDDµ[µö/\¸P]]U;gggüóÏ?5= ¢gÂû–èõסC‡š½\<· ”Ì€&ªMxß½þø}NDDDDDDôzª¶ûíÚµ«®®jÄë~~ôzâ}KDDDDDDDDTûT[`ßÞÞ¾ººªVW®\A»víÐê‡Ë5=¢JÛÐQÄ >Ñk®ä÷SpppM…ˆˆˆˆˆˆˆªSñÕ" ìÕ" ì½BòòòjzÏE.—#??¿¦‡ADDDDDôF``ŸˆˆˆèqàÀxxx ++«¦‡òÌ-Z„éÓ§×ô0ˆˆˆˆˆˆÞÕ¶x.•/$$áááHII‰‰IMç™\½z1115= """""¢7gìÕ"œ±ODDDTÅÒÒÒpöìYDDD ''NNNhÔ¨Z·n””8;;+• ARR¢¢¢ˆW*£££ƒ–-[BWWWc¿ …>DPP¢££‘˜˜xzzÂËË "‘Hc½»wï"##CØ×®];H$H¥R\¼xÁÁÁ°µµE¯^½„OÈd2ܾ}¹¹¹ÈÈÈ€T*Å… TÚ733C³fÍ4ö_ÖÇ‘wwwVªÑ›„}"""¢*´wï^̘1IIIhÙ²%êÖ­‹;v &&=zô@PPÂÃÃaffHNNFÛ¶m‘™™)´1f̵mïß¿C‡U{ìñãǘÁåË—a``€¼¼<´lÙ{öì‹‹ ._¾Œ.]º(Õ+»]"<< 6ÔpÕ”Ïqøðဎ;bïÞ½°¶¶®°Ñ›„©xˆˆˆˆªÈ•+W0bÄüç?ÿAbb"nÞ¼ ???DFFâÊ•+ Ajj*²³³…:–––ˆŽŽFDDæÍ›ÂlÿÒ_±±±2dˆÆ¾ŒŒ0xð`œ:u ?Ftt4Μ9ƒÈÈHœ={;wîÄÊ•+ÕÖuqqArr2"""0vìXÀ† бcG8::âþýûÈÊÊB@@ôõõq÷î]@çΑ€ˆˆx{{ÃÞÞ^eÜHJJªTP.\(¼¾té’𠂈ˆˆˆˆˆžâŒ}"""¢*rõêUÀÄ×ë‹1 IDAT‰aee%ì‹ÅhÛ¶-fΜ‰+VÀÈÈH©ž™™ÌÌÌP·n]€££#4hðL}aúôé*ûÅb1ºuë†Aƒá×_ÅÂ… ¡£££RÎÂÂÂ' ,X€Å‹cÑ¢EÐÓÓ´iÓ—.]RJ©ccc000€D"yæq—åããƒÏ>û `jjŠ6mÚ¼P{DDDDDD¯#ö‰ˆˆˆªˆ§§'àØ±c°··‡¥¥¥€¹sçbÔ¨Q¨S§ÎKGaa!RRR——CCCXYYÁÜÜ J¥jûeýôÓO˜3gÄbåxV6Oþóš7o¼¼¼ððáCtéÒ¥Ò3ý‰ˆˆˆˆˆÞ$ ìU‘N:áèÑ£øöÛoñõ×_¼¼¼Ð³gOx{{£{÷î/<£]…Bëׯcë֭ؾ};òòò„cMš4L&{¦ö¦L™¢Ô¯ZZZèÙ³gµ÷KDDDDDT›0°ODDDT…ú÷ï^½z!44áááÆ;w°iÓ&aÕªU1bD•ö©P(°~ýzÌš5 C† Á† `ccH¥R$&&bݺu¯Ò~‰ˆˆˆˆˆ¨f0°ODDDTEŠŠŠ ‹!‘HàîîwwwaÁÛŒŒ üøã9r$üüüУG*ë×ßß³fÍÂ?þˆ¹sçªM—séÒ%\¾|¹Êú$"""""¢šSýŸ¯&"""z egg£S§N8~ü¸ÚãfffðññœA¦ôÙòÞ>/'s}Øë@,!9§©OPTÉ‚X$‚‹¥Ì $Ȕʖœ‡yåÿˆ7h¡‘¥Œt´˜]€ÈÔ<<[èâÅ™èich3+´°3†‰žÄÿ@¾?¤Ü ë·q0Eo׺°3Õ…®vñ³±¤\|6ú™Æaª§†¸¾õ‹Ddêe_…ëVæÎ‹   ¼õÖ[øâ‹/jz8DDåzôè._¾Œ?þø½{÷V›Ÿ>44àêꪶ @JJŠÚEc¥R)ÂÂÂЬY3¥~Éb¼*uòóó±aÃlß¾ýÙO긻»ãܹsÈÎΆ±±±ÊñÔÔTdddT¸î?ü€ùóçêÖ­‹‹/¢I“&/eÌDDDDDDµûÕ¬…1õt†‹¥¡°¯P®Àñà¬<…œ|ùKë{Xs+¼Óζ&ºJû3žÈ°óú#l |y‘æpñÐfV˜ÙɆ:¾,© Û¯=¶€x”S:ZbÌêìˆ-¬¡/yèˆËbÕ¹hœH×X×Ü@;cáËÅÊÚb d t^P‰3ª®¡;Ç5‡M™kƺZÖŸÚ¶fur|¦>5ÑÖÁÓÞ`¨£þ[ñE®Ûë ((çÏŸ‡MM…ˆ¨Ò~ÿýw`ôèѰ³³ƒŽŽ222påÊ,]ºC† Á°aÃÔÖíÖ­š4i‚¥K—báÂ…¨W¯ž‘!"5fz°4ÒÁìNލg¢‹¯NEª­+?qEGg3À£¬|<Îʇ«•!ìÍô°zh,:†cRÔÖß9¾¹ÊÈbÏ~Þmg]d>‘aµ ÂRò û÷‰ÄÃti¹u- u0½CñLÊ“!©Ø{;Qø¤E^AÕ?yÑëFDDÕËÁÁ£FB÷îݱmÛ6lܸQ鸓“>ÿüsL˜0fffjÛ°³³Ãþýû±téRtéÒE阗—f̘#F3ûKÔ¯_Ä’%KЮ];¥c'Nĵk×°eËlذŸ}öFމ^½zÁÀÀpêÔ)|úé§Jõ>ûì3¥íŽ;¢sçÎJJëܹ3Nž<‰Ï?ÿ¾¾¾JÇ €_ýƒ *7¨Ë–-èQ£ÞÞÞèÝ»w¹å‰ˆˆˆˆˆÞD ìW‰–ßôo m±qR¼÷×}<ÊÊômboú7†«•!fttÄ碫´o7kC!¨#. ó‡"-¯ /ãó^ ÑÏÍo56GÆuq:,U©~# a–úùˆt,8 ia´Ä"|ÜÕ c[Ûbx køG¦«AþŸÖBpzíÅXl½ŠSâ¬Ú-ëãó^ q5&©ÿŽ«¬B¹ÁI9z”ƒ¦Ö†ÂL÷gÕΩxÜLÀ»IÏT·£ ´Ä"äËŠðùñpȪþLiUq݈ˆ¨ú`Ïž=€wß} HJJBnn.¬¬¬`oo/ÒËÓ¤IüùçŸX¾|9 ‘H`eeµé}J4oÞýõbbbsss8::ÂаøS‚žžžX¿~½ÚºóçÏÒß¼ˆ^½z¡K—.ˆŽŽFRRŒakk kkëJ·1räHDGGãñãÇpww‡‘‘Ñ ‹ˆˆˆˆˆèuÃÀ~5ÐÔ6ÆÅ)l¾:)õàxp ¼M1¬¹F¶°Ææ+qȪœû½\ê ¯¿>)õàIa¾ñ‹D·FæÐ—ˆÑ£±¹J`ÿmo;ˆE@N¾Kއ Ÿ()ðÃù´¯o†úæú˜Ú¶žJ`_`Šw=Ŷ\ŽeIeXt, §¶‚žDŒñž¶ð½«2þ† *õ‰ËQ¯ÏØ·0’(NeóÌuÿMA””SðÒƒúUq݈ˆ¨rNœ8ÈHõŸ:«¬*Í¢‹Å¨W¯êÕ«÷\í‰D"8;;ÃÙÙù™êiii¡AƒhРÁsõ[tuuáêêªqÊprr‚““SŽŠˆˆˆˆˆèõÂÀ~5éÑØ—)E@l¦Êñ½·1¬¹ô$btt6Ãߥҫ¸ÛA,!ýI¡Æ€´@3[#"¤å >óéƒK£â€´´°Qiª ´æÈ“þM¬ ae¬£tLK,B×Åc÷ KUYäW^¤À»I˜ÛÅ Ímae¤ƒ¤œ§ ÷5µ1òÙﻣ:CþQV>®Äd “sôh\Wm€º2 ÚjÒ°® tžæÎ—ü;Ó±ž©šÛ*/왚‡ÜR)uŒtµàlþtf¥½iñyh‹E*us d¿•h‰Ð¡¾ܬ aÉyæÆ¯ŠëV˜˜}}}š   Åi J§–P(¸zõ*€âE"ëÔ©ƒððp9r °²²ÂàÁƒÑ¸qãç_ZZš°¥½½=ìíí…c÷îÝCvv6lmmáää„´´4ìÛ·‘‘‘ÐÓÓC÷îÝѹsç ûÈËËÃÉ“'qçÎäääÀÚÚ]ºt———JÙ€€ÁÅÅæææ•:‡ÐÐP¤¥¥ÁÒÒRXP²ªÆND•sþüy,_¾ü…ÚhÛ¶­Jz""""""¢—…ýj Bq~}¸þ0Km™‰9xRX}‰^ö&JýNÎfx¿ƒr ä³ã6â2Uƒû>mìðA'ÈŠ0ñ»žö“²‹í-´Å"!§|i-¥²%\- aôšÆ~#îé~Oå±—žY=NSýltr®Ç:z*^Ô’> ÑÜVõ#ü3::`FGåÌ;ÿ½‡k¥Î±…­1ÖýÇM¥®­‰.vŒk¦´ïz\¦í¹§R¶a]¬ì‚úæúJûcÒ¥øòD¸Æq×ôu+±fÍ|÷ÝwðððøeµjÕ ðçŸb̘1Âþüü|´oß°ÿ~\½zß}÷Ч÷ß‚ ðóÏ?ãý÷ßæ±ÅÅÅá­·ÞBXX<==qâÄ ¥ãS§NÅÕ«WñÁ sçÎðññAnîÓ‡DK–,Á¤I“ðÛo¿iLmqøða¼ûî»xüø±Ê±®]»b×®]J³q'OžŒû÷ïcÅŠ*¹ª55jnݺ…¯¾ú ‹/®²±Qå͘1>>>/ÔFé‹DDDDDDD/ûÕÀÊXGœ«›1E :í ܬ U‚À›®Ä¡µ½ ¼M±|`cLþó®RpÞÝÆ3ÿÍ¿òl4B“•g¸Ÿ OÃä¶õ %¡£³™ÊlñuõaoV<;ü\DšÒ1çRcÑ4öÒ3ÕËŒ½d[ZX„Ç¥Ò)×Ï^×7ׯÒõ™°T„”ºÛ[A,ájL&–y@’\¦ßÇÙùøßíDaÛÕÒÍm/ÉåtE±j®™¾6~é CäÈqènâ2óѰ®>¹[áëþšgª×ôu«j7nĉ'0hÐ ´jÕ qqqسgrrr0gÎôìÙ5ªt{QQQxë­·Ž;âØ±c01QŸžéöíÛØ°aZ´h>}ú ;;‡Btt4vìØ·ÞzKm@ÏÏÏLJL&ƒƒƒ&Nœ+++ܺu ;wîÄùóçÑ­[7ܼySÈÿܱcGÜ¿•:¼¼<Ü»Wü@¨S§NU6v"z6 ÊQmÃÀ~5°6Ö^—7²0@jn!ÒŸç¼OÉ-`[]¥úE `á±0ì™äf6F˜ÕÉ«ýc†:ZX1 xQÞÁ)Ø[*]âÞãl|„·ÛØaiŸFøé|4b3QX¤@s[c|ÔÕ b‘§ÃRqªLÀÚÚäijž’±k‹Ehli€ÈÔ'È—!·@޼B9 $Z°1V»õ¿©}’sŸž·‘®ê™ê!4) É9OsþÛ”Iô¢¶>RÚìn -ößM‰à µŠE¦>Á7§žæ\žì]Ímš[¨´_“é`a¨ia&ヒ°ä§ø!©Ø0BõÓ%júºUµãÇcÏž=5j”°oÖ¬YðôôDaa!vìØeË–Uª­ÐÐPôèÑqqqèÑ£<(, ©ÎÙ³g1cÆ ¬]»"‘ðå—_ÂÓÓ‘‘‘زe‹Jp¼¨¨ï½÷d2ÜÝÝqéÒ%˜šš Ç'NœˆÞ½{#<<ß|ó£S§NØ´i“‚¨"ׯ_‡L&ƒD"AÛ¶m«dìDDDDDDDDôúc‡j` yz™óþ]xö½ööøËÇGÞiW+C¥c%³ûKKÍ-Ä£a(R“ÚØ¡Sqqaϰ7ÓClº_•l^ãƒÏކáqv>¾ìÛ¿ë ¿÷½ðÓWˆDÅ3ýçEÙ$=¥Ç’WXœ~ȦøcB ìžØúÿžÛ“’±ë(ßR%ùíóþÍ]_×@‚SZa÷ÄÂŒõ’vK—¯ít´ÄÐÔ°ïN¢RPb3U¢”öº]·^½z)õ eË–èÕ« 00°RíÜ»w]»vE\\ˆ£G–ÔSSS|ÿý÷B`ÌÌÌðÎ;ï(®—N§OŸÒ\µj•RPºwïŽqãÆ¶nÝ ¹¼ø½èر# >>ññO<–ËåÈÈÈ@vv¶R;%Z·n }}åO»<ïØ‰ˆˆˆˆˆˆˆèõÇÀ~5ÐÕ~z™ åÅð^ÿgï¾ãªªÿ?€¿.{¢Èr NTTR07ŽÍ´4G©_-µ\i™9+s¤™™-Gæ(5wij¨øWŠ EIJY‚Ì{~¼9çÞˬ˲÷óñ¸¸÷œÏ9Ÿ3/¼?Ÿóþ´²@óžÍiÀÑ‚¢iÊó+»ü(›/ÅB`Ù«-0ðkÓy…rÌ=©2ðkq–&†pw¬#õWVß­í-¥Av•™¨Ô]€¹^jB)OšÕ7—%ò u71¤÷ùE©ƒ:5¶†­…1``+[È*“Ú¶½¶iigË¢`ûÙšÊ=}ï©ÆÏo¿ùúújü¼eË–€ÄDõ'MŠ FŸ>}€#FààÁƒ055-±\¯^½`aa¡ö¹¸îììlµ€û™3guêÔAÿþý5.wذa€¤¤$DDD\]]áää*½ö÷íÛ‡zõê¡Q£FÈÏW>|ý×_EŸŸ®àƒý·“šƒ!îvØñv{µùùJu16”!íy‚¢Ów“³Q´^cC™Æº‹ Æ4=86CÊ$ì F†ŠÞȺ¶½6iZOil‚”’Ç&(îEÛoÚòWׯ_ðü¹ö}áááðññAr2]7£G†±±±^Ö­iý‘‘‘€V­ZÁÈHsƲ¶mÛJ¿ß¹sGú]쵯ØöÍÌÌÄ… ¤ÏÅy4å×/oÝcŒ1ÆcŒ1ÆØ‹sìWçJ)SÄÔ5›ƒãHx22s ¤žöfFjó'€/O<Àáw;A 4áöÝÔÝÛyZwg´°³@nïï»ÇéŠÁX/E§ãÝ=a84±Xš`ALÚ¦¥î†x–[ˆ©n£Q]3ÄgäJƒø*ê®`ß›¥ôIÉÎÇë[‚ÑÀ±Eƒ×š+¥**^¾¶ªcªHó,WóñÌÌ-ÐZþEÛo&&ºÇ()LHH aƈ‹‹Ã¤I“еkW4jÔ¨ÂëÖ´þ´´4”öF›zõêI¿§§§K¿wïÞû÷ïW ìŸ8qíÚµChh(üýýѧOÄÇÇ#&&F*£¯º3ÆcŒ1ÆcŒ±÷د‰™ŠPX*u ¹*ésìêPäD¥v5™äÝb_mwÇ:x¹™öà# lIiÎG¥ªõEYy…8šx©‰5ê[(zB+×¥%}.€˜´)¨onl ¥QÞVåò ê(–™“/—‚Ó´\Å>IÌT¯_mT(W[•Ò£«i›€ÿî~ÓeáÂ…†ƒƒRRRðÎ;ï@.¯œ CC:Ÿu-_yš8? è}õêU"44qqq˜8q"<<<àïï@Ñ[¿uëÖhР޷1ÆcŒ1ÆcŒ½¸8°_2r¥T)ÅS݈dP¤oyøT{j!îvân‡üB§î>… Àr¿s瀕©êšÓƒ±iÚƒ¿1iŠ€q£ºfÒïŸ*>×V÷æõ9À‹×]|oal{ 9ü‹/÷ajŽÆyj›ôEo|sÍÆÔ3מJ¦¦ì7±ñA[¯ð”í듟Ÿ–-[{{{lÛ¶ 2™ X¾|y¥¬OìÿäÉ­ó(OSî½ß±cGXZZ"++ aaaR??? 4!!!HHH(1 cŒ1ÆcŒ1ÆcÚp`¿ n<¦.;5²Ò8OK{K©×ûõØ ó¸5°Àü~.€ïÏEcÞ‘H„%<ƒ¹V n CõàÊ=Ç•{âWOiZRO䈤gRš—N­5–íÔX±MÅëü8Ci>-å‹öI|F.2^Œžç÷’³¥ß[ØYjœ§•½ú ¨¢š²ßÄ[µ¸>|X)ë-ÎÊJqŽùúúbæÌ™€%K–¨ä¬×www”k?+KóøÁÁÁj󀑑¼¼¼P¯üãÇÃÅÅ­ZµÂ Aƒ Ž?^âÀ¹Œ1ÆcŒ1ÆcŒiÃý*rúÞS@³úæðh¨ÜÚÎ_(à|TšÚtsc¬~­%ÌŒ p>*;¯Å£@.`Þ‘»ÈÊ+„GC+Ìèá¬V.;¿PJÓ¥‰5LŒ4ònÍê ä)õþÎ/p!Š÷ÐÂVj|Èè)ˆ|’…¸bæ¸gHÉÎWÙFevuLðrsJ%$î£Áçϥ`û+­l5ÎãׯNkùš²ßš4iHLLD||¼Úôß~û­Ò֭˪U«Ð¡Cb̘1HMMÕëòÈËËÃÞ½{5γcÇ€««+\\\T¦‰½ðqîÜ9øùù¼½½akk‹cÇŽáêÕ«*ó2ÆcŒ1ÆcŒ1VZد"‡Â’ð´(P»x ‹JïùîÍm0ÜÃAm>e‹¸¢Y}s$gåá³îC쇛žƒ¥'îÆuiˆÞ®õÔʹM½­­M±x€‹Ê «2à]¯FèÒ„û§ï=UÉûÛ®Äêšaa= ðþËMв¨Gú–Ëqjë– ~+*ïÝ´.Fvt”¦™àK_7˜ ¿PÀï×ÔÇ=iЬ¾¹ô²25*Z¿LåóÆ6fËWÀÞ¢A¶j Üëé„—šhî‰èg¿éƒ8¨«\.ÇüùóQX¨87N:…Í›7WÚºu155Å®]»`nnŽGaÒ¤Iz]~—.]àíí ˜;w®4x¯èÛo¿Å‰'3fÌP+/ë÷îÝ‹œœ)°o``___üùçŸÈÌÌ„“““Z£cŒ1ÆcŒ1Æc%Ñœü›é]N¾ŸûßǺa­ájkÃïvÂõØ Ô53B‡¢üRsðýÙGjeßìà¿6 €…Çî!õ¹jàÿøx5M°ööøÒ× £~A¼RÏù-Añr3´q°Äà¶vèÞÜá‰YÈ/ÐÒÎNÖ¦h,€Õ§ª­?,á¶^~Œ ]áÕ6 Щ±5"ŸIu8™‚ãÉ·}×õxôq«N¬0¯_s¼ÑÁñyhïTGjàø&ð¡Öt2ïz5˜ÎNjŸÊð焎ÒûøŒ\øýr]ã2ªÃŽkqè×¢>Üë`åà–xÛ3Ósájkv¸—©ñé QE÷›>´hѾ¾¾ð÷÷ÇöíÛ$&&âòå˘1c¾ÿþûJ[¿.îîîX½z5¦OŸŽ`ãÆ˜2eŠÞ–¿yófôìÙÉÉÉðôôDïÞ½agg‡ܾ}àããƒéÓ§«•õöö†¡¡! `nn޾}ûJÓ „;wàÞúŒÕTùùùˆŠŠR_ÄÒÒ7®ÆZ1ÆcŒ1Æc Üc¿ JÅŒƒáˆËÈ…¥‰!zºÔC‡†Vœ¹ŸŠ‰»C‘™[ R¦¥%æömØzù1.?J׸ìUÿ…û)Ù°6£|ûFJùö³ó ñÞž0ìºçùrÔ37ÆËÍlÐÛµœ¬MQ pôö¼½óž<ËÓ¸üÎ=Âwg£‘•WG+ôq«fõÍ‘W ÇoWã°ðØ]­Û] 0ã`8‡=A¡\@K;Kôv­‡úÆxšÏüïaï„2íËÚ ¿PÀ´áˆL ½“|[7@ ; D¦à3ÿ{:Ë×”ý¶}ûv©÷ztt4>Œàà`Ìž=kÖ¬©ôõë2mÚ4 <0{öl„……émÙîîî8wîzö쉂‚œ:u »wïÆíÛ·ajjŠ™3gâÈ‘#044T+kee…:úöí 33ÅÓ$¾¾¾Rì3V3-^¼­ZµBëÖ­¥×Ï?ÿ\ÝÕbŒ1ÆcŒ1Æ$²ÔÔT¡äÙÊ/((^^^°±±©ÌÕT›K—.ÁÛÛÖ\,uàîXNÖ¦È-ãΓì*4ÖÔÈm,áPÇÉð4+·Ÿ©¥ßÑUÞ£¡ê[#=§¡ñÏÔ#t±µ0F‡:°45Ä“gy‰ËD¼ROÁÁÉÚm,!ƒ ‘O²“–Sr!%úÞoë»Ë¤`}i‚€ëׯãîÝ»°¶¶F—.]`g§}Œ€MTTBBB••{{{x{{£N:Õ]-Æt¿ŸЦMäääHbë‹ ÙÙÙ05¥§¿ÂÃÃ¥¤«C@@†*½?uêúõë#£Ò?¤˜––†ÐÐP‚€”” 6 óçÏÇŠ+*£ÊŒ1ÆcŒ1Æj êøº_¿~€¿þú п­ËàT<Õ@.·âŸáVü³*_wn7gV¨¼¶§J#%;ç£ô;ÐimŸ‘«’©¬ª{¿Éd2xzzÂÓÓ³ÚêPš7oŽæÍ›Ww5cUÄÆÆFz¢&!áÅ{¢Œ1ÆcŒ1ÆXíÇ©xcŒ1ÆcŒ1ÆcŒ±Z„{ì3ÆcŒéYvv6®_¿ŽððpÄÅÅ¡M›6pww‡»»{©Êß¿·nÝBhh(êÕ«‡¶mÛ¢sçΨ[·®Ú¼qqq¸ÿ>ÀÌÌ ]ºtAJJ NŸ>;wîàùóçhÑ¢úõëWê€A@XX Ñ®];ã‰0ÆcŒ1Æ«>ØgŒ1ÆÓ£àà`|üñÇ8}ú4lmmáêêŠ/¾ø°`ÁÌ™3õêÕÓX6++ 7nÄÇ èܹ3âããŽ;â»ï¾CïÞ½¥$¨U™ IDATùår9Æ€€À Aƒ0uêTL:ÑÑÑhܸ1lll [[[üüóÏ>|8 ´?´)—˱xñbiL)S¦à‡~€±±±>vcŒ1ÆcŒ1=àT<Œ1ÆczrúôitîÜÎÎÎG||<‚‚‚‘‘£GâàÁƒ2d23ÕÇ»ÉÍÍÅøñãñÍ7ß`÷îÝxúô)®]»†˜˜DEE¡wïÞèÓ§öíÛ'•100ÀáÇ¥ûGÅ AƒÐ³gOܹsGü;!!sæÌÁÈ‘#±fÍÛ­2PðÆ¦§=ÄcŒ1ÆcL¸Ç>cŒ1ƘÄÇÇãý÷ßǤI“°aÕ^ñVVVðóóCË–-áááU«VaÙ²e*å7lØ€àÚµkèܹ³ô¹¡¡!š5k†µk×ÂÂÂ|ð:uê777€¹¹9\\\¤ùß~ûmlݺFFŠ?ó0oÞ|УG•å3ÆcŒ1Æ«~ÜcŸ1ÆcL¶nÝŠÈÈH,X°@kª777,Y²Ë—/GDD„ôy\\fÍš…E‹©õ•Éd2Ìš5 )))øé§Ÿ´Öcþüù*A}eãLJ›››Îò¦¦¦Ø±cöíÛ‡]»váðáð¶¶Ö:?cŒ1ÆcŒ±ªÇ}ÆcŒ1=8pàZ·n¦M›êœ¯S§N(¿èæÍ›€®]»ê,koo>}ú`ëÖ­(((P›nkk‹V­Zi-oii‰Þ½{ãØ±cÈÍÍÕ:Ÿ••†ŽÑ£Gk€1ÆcŒ1ÆXõáÀ>cŒ1ÆX ‚€ˆˆ´jÕ 2™Lç¼ 4¤¥¥IŸ‰9÷ëׯ_âºÜÜÜžžŽììlÓ´õÖ999!%%©©©%®‹1ÆcŒ1ÆXÍÄ}ÆcŒ± ’ÉdèÕ«Ο?üü|óÆÆÆ »ÈÁÁ£³¬ ¸|ù2ÜÜÜ`ee¥6=((Ïž=Ó¹Œ[·n¡]»vÒ:cŒ1ÆcŒÕ>ØgŒ1ÆÓƒQ£F!%%—/_Ö: 8zô(lmmáíí-}Þ¹sg¸¹¹á¯¿þÒ˜bGtëÖ-„„„`Ê”)ZŸ 8sæŒÖò÷îÝÃÉ“'1|øpOdggãСC8pàÒÓÓµÎÇcŒ1Æc¬zp`Ÿ1ÆcLF…7ÞxŸ|ò âââÔ¦ ‚€}ûöaýúõذa¥iVVVظq#öìÙƒmÛ¶A.—«•ONNƧŸ~Š^½zaòäÉZë1oÞ<C‡•R1ÆcŒ1Æ«t'aeŒ1Æû¹té‚‚‚¤÷€+W®`ݺuÒç–––6llmm¥ÏLMM±víZ¼ýöÛðòò—_~‰víÚÁÆÆ1118tè¾ÿþ{,Y²o¾ù¦Úº}||ðã?bÒ¤I¸téFŽ gggdee!<<Ë–-ƒ‰‰ vïÞ kkk­Û““ƒnݺaéÒ¥èСÌÌ̉o¿ý)))صk—J½‹‹‹‹ÃÁƒ¥÷¸wïž4è/cŒ1ÆcŒ±êÇ}ÆcŒ±"ÿý7V¬X¡öy@@¤÷mÛ¶…‡‡‡Z€ÜÙÙþþþX¿~=fÏž­’Ʀ[·n8sæ zõê¥uýÓ¦Mƒ··7æÍ›‡JŸ[XX`Μ9˜={6lll´–4h6mÚ„U«VaÊ”)*Ó&Mš„/¿üRåIMš6mйsçâ믿Lœ8mÛ¶ÕY†1ÆcŒ1ÆXÕâÀ>cŒ1ÆX‘åË—cùòåZ†¥¥%æÌ™ƒ3f ::)))hÖ¬uæµyzzâäÉ“xòä cŒ1ÆcŒ1ÆcŒ1V‹p`Ÿ1ÆcŒ±Úâ?€eËA({Ù'O€÷ÞÂÂô_/ÆcŒ1ÆX•2ªî 0ÆcŒ1ÆJ!>žó#F2YÙËoÙüú+0mšþëTGeöö@½z•³¾ªðü9ðèýn`´hQ½õeg11ô{Mª×\¾ùøøãÊ_ßQ›6e¿ßÖ4¦¦LÙØééU³î´4ê‘Þ§OÕ¬¯604:wËW¾*¾“cµ öcŒ1ƫɲ²(0ߣGù$‡QQÀ?Füç?c/„{÷ègëÖÕ[ÆcŒUþËž1ÆcŒ±šìèQ "‚zí—­ìóçÔ(е+õدéž<‚ƒ°0Ê;ß¾=àá4n¬»œ Ð`²7nÐ@‘‰‰ôô€§'ðÒK¥K?Më¾u‹z¹vèôêEùÊõ­  ¡F›´4JYqîœú|66@»v¥«ÿíÛÀ©S4ˆj󿀗í¿’dfRjˆˆ .Ž|õô¤í×wÚ¦¼<:Fâ˜VV´žâ½¢ÓÒ€ÐPEnî† )|qÙÙÀõë@x8Õ½MÀÝ^Ú-;-Mñ™·7][99Àùó´/œœ€´§³IM®^¥óåÙ3JáãC½i+‹ ÐúÒÓéü踯£›Õ¿¸èhÅÀ›Ð¶-`kKƒï^¿Nç¹95 :;k¯GY®Ó°0Å´­[ôY§N€Ÿ56þû/¥0²²¢q@ʲWJ/9™öÛÝ»4€©­-3}û&&¥[F\¥<ºwOq}¾ôRé@}ð€®ó‡i}Óùߤ µag§½¬\N×Nx8I×xëÖt­–õ{¡4""è8@ƒ´ŸD¹¹´sr轙Х‹bú³g4]c"&FóýÍÙhÚTw= é¼¼s‡Ž›£#·Ý»WÎv+ËÊ¢ë+,ŒÎqÐáJw¼ss©î¡¡´œéÚ*퀷åùNÊÍ¥óD|j΂΀Òñ*î•}úhoì¯è÷BEÎõœJ7AßåÑú»u£kØÍ­rR 2VKq`Ÿ1ÆcŒ±š*7X³†þ!~啲—?~œ,{öP` ¦’ËéÉ‚Y³(˜áæFÁ¢ÐP n]`Ý:`ÌÍœ„`ÂÊ1P ÈÅع“–5y2åü× )( y§N¥@qÇŽ<ˆ¥‘õ¿½/R€FYñ÷¢{÷4µE”Žå“Oè}÷îTç”`Ù2`þ|ÍéD‚'sç—/Sà¥Y3 lÀ;ïи –yó´  q"”ݼI緲ヨ,Q¼oÞœÎåcL)hNŸ¦­«+ðÅ4mÁ`Π^=õ:ܽ«¾¾ôtàÊ*sñ"­G<öìQÏg}ö,0mÕ©iS H‡†R=6n¤ó¹2DFR]Ùܹêó üý·jð+72DÑ Ð¶fdPJŸ;Û]·.°kÞ••õ:‰¡À·¨m[ ”º¹Ññ2…ίÏ?§ÏîÝ£câDÉß²(( ëã»ïè½­-5F$%Q}úô¡<ðºÖYP@ûhÊÚG:PƒEl,'ßô쩹l~>ðÕW´uëÒ~04¤ }J 塯_ŸH×$.ŽÎí_~¡÷ݺÑu“ ¼ù&µàæVΣÁ“'ÔØ%¦ìY²„Α¿?0t¨âý AÀ‘#Š÷¿þJçˆhÇÍctìH÷mú»wi½»wÓ~kß^±Ïzô¾ýVµAAŸ¶o§Ôwâ>ðò¢{æåËt?Ú²E÷t÷ïÓ9÷çŸT÷V­¨,,_®;G~E¾“ކW¼ë-º–wï>úˆÎyñ:9Ø´Iµa°¢ß =×CBèûüúu:§›6¥à~h(•=uŠî[ÞÞÚ÷cÿ1µ¡ž´e‘ŸOíÖ­Õƒ©5Í·ßÆQÐìñcê)öøüê+ pÌ›§èÁ­¬N Xžj7¦ß‹¿’’tõªççŸS)#ƒ0±±üY´øãÍå¤ÀÔ AÔ‹ûÑ#êa™›K=¨SSiZT”þ¶ÛÏO‘~íZ زTïÈH ùúRTå þéÓ”§ÚÙ™Fññ4VAF=árð ™™êËnÙ’Žóýû4ð,¬_O "ÎÎèÍÈ ëÎÜœJÊþþèÝ›ö]Tg!!´-óæQPM¹QBŸZµ¢sâþ} žô³øy³oŸzVSS:®÷ïSc!@×Lß¾´ôãGtœÎœQ_Y¯Ó&M( )îçzõè| §àæÆtîîÝK½¢ïß§ã.àõÅÐÀÐñJJ¢s(,Œ‚ǹ¹°ÌÏ×¾Œ9s€±c/¿¤c->tïõØïÕ 8vLsÙÍ›i;ú‰®Íÿ¥k-6–îO§NѶkKAìÛ·©LV•ú”îKÏŸÓúÃÃ+¼›$vv´mšzÙ40sl¬ö:ϘAå/^¤÷| ùþvîœö ~D5`S#Fr2ÍŸ”D爧']ƒ•5ž…›‡·nQòK—蓜LNÛ¨Éýû4ÖFV£ÄD*›žN÷éõë#´¯»"ßIo¾I jôþéS`öl:¿ßŸî•iiè§ëXYE¿*r®§¤Ð²ÍÍé|Œ¤ã{ë­O윚ª}ß1öÄ=öcŒ1Æ«‰ ©lóæ¤,«3g¨çݯ¿Ò ž5Õ¹sÔp±e õÔSfgGA!'' (öé¼öšê¢÷£GÓº )Ö·¯jÒøx PMšlØ ú4‚•¥[¶¤ží«VÑ6× ½ÄtóæQcÂÂ…´ïÄz^¸ ºobc)x=c]›ÊÓìí)økiIóT;;zݹCïœJîXZÒ¼bª›Ï>£ëjýzÅgMšÐñ.ÞˆVÞëÔÖV±ŸùEÑPÕ½;ý\²Dätq¡ãíïO ?ú"“Ñ“š¸¹ãÆQý##u§qÚ¼x÷]Å{ñ>±a¥>™>ÖŠ÷fþçúùöÛªƒžš™Ñù¾m5b—ŸOûÜÊŠ””Ÿ@15¥tFûöQ0tÖ, Êêë^oc£û †F´O30 ²b ÖÆ¦l÷·ÌLº†zõ¢sSy› (•Í7ßÐwä{ïQÐ]¼ŸêK÷îŠsT™­-/?ÿL Íš©NÏÍ¥'‰7¦c£|ï²¶¦'髉>¾“7¦^ÿÆ(ÿÖ[Š{ÖÈ‘ªïý|/”÷\¨¡!6–ž2SNýÐ~ž=›ÏJ“‰±ÿî±ÏcŒ1ÆXMtþ<¥¤˜;W{žomärJ !Új*¹œªÝ»«Ÿ•½ö¯æÌQäg×$?_Ñ>!–_¿>}&æƒV^÷çŸS°â­·4/ÏÐÖY“uì¨ÔÉdø PßöÍ›©wäĉÚsÛÚR rß> œé‹µ55Tùû+‚ÇGR`ò½÷½1##égñý[·Ò´ 4§©^–/Wô\ÕeíZš_ ꋊ[)ð4{¶öý6n\ÉcBÔ&P NSN{åíÓ×uªƒ¾Åxº¯ñŠ’ËéÜ¿wŽe^ÎÍOxˆ:tоíâ}"*ŠÎåâúõ£ŸGRs1è Ð9üÇ(.îôi È.[¦9­@ûë³Ïè»BÓºk£'hÛ§NÕÞPadD1ÑÑÚÓºèKF}§ÄÄÐøâÓCÊãtˆNŸ¦FÊ/¾Ðþ½íí­Ú@$ªŒï¤ºué;`äHõ{Vñ÷úø^(ï¹PƒMÓ¦tü#"Ô¯Ç~ý(øïå¥}{ûâûÕäîÝ»ˆŠŠ‚……Ú¶m‹úõëWÉzA@dd$=z¹\ކ ¢mÛ¶044,UùÂÂB„„„ 11¶¶¶èСL˯õÙ³g¸uë222иqc´mÛ²*ø$55¿þú+.^¼ˆÔÔTÈ‹r`~÷ÝwèØ±c‰åOŸ>½{÷"** 9Eÿ$uìØß•ñ‘ѧOŸâ7ÞüüóÏhÛ¶m·äÅ7kÖ,ܸq>>>øL9¯#cŒ1ö¢úç×ÖV5_niQÏuë´„j‚Çé©‚… u^ihHékŽ¥€œr¯ZA Aþ¶l¡ ev¶bZëÖª…âë¾pNt ¨ÏÜÕ•A[p[yZñÞׇѹµt©îe''ÓÏ[·(ˆ¾ôìI=‘ãâ¨ñé÷ßéóìljÐzí5E.øV­TË8@ǵ¤ì:ÑÏà`š_—‰uïGÑÁƒ´^]ë¶´¤íÓ–©&™ø7oÞ”>311ÁèÑ£±nÝ:ÔÕöX’l޼˖-Ctt´Êç 4ÀìÙ³1wî\éxÄvË–-X´hâ•þªW¯>ùä|úé§0ÐñÇpnn.,X€7"++KúÜÕÕk×®ÅkÅ©V’””„ÿýWzݼyùùù033Cš¦Vràåå…G©M+ͲV¬X… –iÚäååáLQîÊŒŒŒR•ÉÉÉAçÎñàÁÀ/¿ü‚±cÇê¥>5Ñ7pæÌ8êûÑJÆc¬¦»vz!~ý5¥ )«õë©§^Mòˆjê1\œø÷€r/>±dútJ°~=ÍgaA½Ô)×ï½{Ú×-¦ƒÑÆÒ²öôÀ. A m74TmÑÄÂ?^{ê„ò{áGFRè  íÜI9¨_{üM›RjåºGDhïQ*¯›2þ¿ • P}{ô(¹àE:_€Š_§Õíüy`ð`j$Z¸Ò›Y[So}1€[Ò8%ý?bfF…Èœ:•rôGFR^ÿÛ·©^óçÓ9õý÷ŠÆ(‘øôJI©GÄÆÛ¤$ÝóÕyyŠŸ%Ý£Æ×žØXÊUG_K–Ð>–Ë©÷~Pbü€âÄûMI÷LMßëÕù¤¯ï…òžë¢ví¨nùrzJ""‚ÆÂX¶Œ–·t)5|èj`dì?†ûUèìÙ³èß¿?òóóajj OOO¤¦¦"<<Û·oÇÍ›7qáÂX( ¥'sæÌÁš¢A’êÔ©ƒöíÛÃÄÄ·nÝBrr2.\ˆ«W¯â –ñ•+Wbþüù[[[¸»»ãÞ½{ˆ‹‹Ã‚ …M›6i,+—Ë1lØ0üS”o­Y³fhÒ¤ nܸû÷ïcÈ!رcÞÖòhc×®]Õ#ÊkéÒ¥xôèlmmñõ×_£}ûö0.j1v+¡å;>>Ÿþ9à­·Þ”)S¤'-ê(ç«DK–,A¸ÒÀH………U²^ÆcŒU±M›èŸgqÐɲ¸y“z@/[¦ÿ€‡¾ÙÙÑÏ»wKž·¨cƒT ^ÄÓ§Ó ž³fiö^¸ 9#V´ ä'zú”=%[j ™Œz@þý7åà/Mm}{ዽòJ cfFÇrÞ<ªß´iª9œe2êµyþ<¥]ÒÕ«56–~:9é§ÎâºÏž¥€£®ÀRX˜~ÖYSTô:­NII”×|Èõ|í¢œÅS#Úˆch“‘ẢÕ§ÉåÔdeEƒ¾zz*¦=zDc6 B÷)倭³3ýŒ×ýäUBýlÞ\wk ñþ0gŽbLŽª4e bãbqÍšQàYñ˜%$è¾4t4¬Öï$}}/”÷\O–Éd4&ƒ‹ 5┞믿€Q£è¾ÿé§å«c/ α_EòòòðÎ;ï ??®®®ˆˆˆÀ… pûömìÚµ ¸qã/^¬÷u_»vM ê÷ìÙ÷ïßÇ¿ÿþ‹ÀÀ@ܺu kÖ¬Aå^KŒ1Æ{ñ„‡Ó “â|eµe ýÔ• »¦°µ¥¼ê‡ëîmš‘AóøúªÂxö,ý=Z{nm½4 <ÇÇŽOžh_·>óËkS”²ÊŒCÓŠû¯ª5iB)Nž~ûzizxP¯j€½4õF¢<З/k_¾ P:[[Êg­/£FÑùtõªöy¢£À@ý­³&¨èuZ®_§óeüxíùÚ‹A¡‰¿¿"€®‰˜‚¥ø@ç·nѹ¥¹œ³35jÅÆW®¨Nóñ¡Ÿ§Né®›x¿òŠîùÊJ¼§jëLVÚ±Ч+É€tÎ9R¶rúKß cÆhO¹%>Q Iß¾ôS×½57Wó¶U÷wRE¿*r®Ô8¯­ÁÄÔ”ž@ts£±ªú;“±ŒûUä÷ßGLL `Ó¦Mh¦4pÐèÑ£1±¨eÆ H¹Ó“ýû÷K¿oܸöJ-»–––ذa,‹þÈÑÔcÕªUËå¨[·.¶nÝ*=Q`dd„5kÖ uQž³+V¨•+W®@ ,rê׫W;v쀱±1²³³µæ¨ÿ믿‘‘‹/ª¬¯<Ä4B®®®å.Û¨Q#˜éʯX är9&Mš¹\ŽÕ«WWéºcŒ1VŶn¥ŸåI·w÷.=æþÉ'ªUÖdŸN=ü–.Õ„ÏÍ¥@oTõæVà‹½X5Zrsï¾£<ÍÚ,^Le¿þZs*6–zW&ww kK]’’Rrβòõ¥Þ°Ó¦é\©¹wiE¯¾JÁ÷ë×)ØclLƒ"6n¬hœÒ4Õ¨QÀo(rô'4°ãúõÀ† ú}jeäHvÑ"Í·¬,àË/KNeQUä:­N⦚®oAŽ/]ïߤ$ :>®>-.ŽîcÇÒù¡," ¥õhsëý,Höð }:s¦ö`nh(]Ë ôéSòv”…ØOR¤¦¥~¨»|ýúôÄÌÇÚçyð@‘³]Ô´)]¿_~I EÚ$%Qªµóçu×£,ÄÎ~šŽ3@ÇS×vwìH²FZ~ IDAT×ÈÂ…ôô\qr9=‘§­±¦:¿“*ú½P‘s ¿]~øA{ú´ØXJ«×½{éÆDaì?‚SñT1`îââ±å]ÉäÉ“±yófdggãŸþ‘zÑÀ•+WPXX;;;­iApùòe‚4Wz /®è^ ´Ñ0ˆ‹••Z¶l‰àà`<~üXeZAAÔÿÍ7ßTä×ÈÈ'NÄܹsqéÒ%<~ü5’¦_½zUÊg?©ø B ´< À±cÇpàÀ|õÕWjó”f@[m©ôOR^Ñ?}QQQ¸T죶mÛÂZiäúôôt•´7b^ûüü|µ²ÖÖÖZ¿ÍË˃¿¿?®_¿ŽÂÂBtèÐCŠ÷ä(ÁO?ý„   ̘1e*[ñññHLL„¹¹9Z¸¬È¢<’Íš5ƒRþGATÔs¥U«V¨W¯îÝ»‡#GŽ >>ööö2dZˆM•ÃÓ§O hܸ1+õj½““š6mЧOŸâàÁƒxðàÌÌÌзo_ôìÙ³Äudggãĉ¸uëž={ôêÕ /½ô’Ú¼—/_†\.GË–-K= vdd$ž>}ªr}ë«îŒ1Æj¡èh`õj ä”ç;RL'1a‚~륋\NyÑÅÔ'åÂè±~å Ž£#e•S¨4n lÛFÛ`ölÀÕ•þqŠ¢àìùó´mÅÿ–<˜‚ˆ RJ{{ê}lÜH†Æ©n?ÿLå‡ Q›6¥uCuž2…ÒYääPâ³Ï¨Lh(‘Ö­:w¦õeäH N-Züï”O;=Æ z{xP/J1-Md$m›Ø{ú‡((#ž3qqÿ–ýé'êI*¦EÉ(€”˜HÛóÅÀË/SõgϨü‰´½mÛRÎ{}SNÑ îhaA¥¿Ôx ˜šk×Ò)^^ük׎ö[L åKÿþ{Ê‹ýæ›ê僃=RÅT@?ÿ ˜›+æ©_1B}°T33Ú'£FQõ³ÏèÉccj|Y»–•íÚÑ9óë¯tþ¼ù¦jJ¡òkn.¥}(=…x½”#ÛÏO½Ç|l,]yyŠ'öìQô4(½Ð°ašCÊsæåÑ`Çâ~Þ²…ö«r ‘£G©§²ØÓ žÿ¿þJ÷ŠŠþݱ#¿±d §æÍ) CÛ¿i“âɨ={( 9|8g(‚³/½DãžÜ½K÷WWºO„…ÑyФ °b…öãüÁ°ìÓ‡æ‚@×ïÑ£TnÑ"ÅØÊfΤãÛ­5,ôìIÇçÉ:v‹Q#ÙâÅê)QQÔû[yñØXÚ¿ëÖ)>30T¨ÚÔ”=æÎ¥'kzô m¾qX³FѰE ¨Ã‡«>abBågÍ¢`¬-óéSÚÿû÷Ó ÓŸ}FÇGÙðá<~ýu 44lHû-.Žê°r%mÛ¶mš÷yyØØP»+èþóÒKtÞ[[AصK1= @š7WL·°„¯¾R_oA 8 -[j^÷ï¿ÓöW†à`ZÏK/Q=DAAôyÿþºË?{&«WÓqR®w·n‚pæŒör«V•|žvï.QQÚ—‘š*óæ©—{ï=AˆŽ„%KŸ½òŠ ¤¤”i×hUü¸jzÙÛ Âþýêeýý¡qcÝe›6¥uèR–ë4>^úôQÌÓ²¥ \¸@Ó.^T|>mš ˆ×DŸµk'ׯWx— ‚ ‰‰‚ðÑGêuîÓG„mÛŸuí*‘‘tŸ8PñùwßÑö½óŽê2,,aéRí×Id¤ ¼öš üü3í_MçÚþý‚ ëo•ÂBA8xPý:mÜX¶o-ÿã ‚“SÉç»­--G“çÏá‹/Ô·yÚ4Ú¶âû­¸ü|AX¿^½‚0aÝû´Õ_è®|ÄWç΂°f }ïé[n® |ÿ½ê=V<þ™Îaåcpì˜ú2òòaófº•—Ñ¿?ûÇŽ)>Ót®—ç;);[FŽ,ùx¿óŽ äähßþò~/Tô\_º”îÏo½¥¹Þóæ ƒ¥>ŒŒéKuü?-þ/»oß>aß¾}:ÿÿåûUàñãÇxöìhì1hÕª®_¿Žˆˆ•i‹/ÆÙ³gñÿ÷=z4Ο?/ ø PþE‹Ö­[§Ö£{ذaX¹r% ðÏ?ÿ¨õ¿}û¶Ôýõ×_W™¦\muWî©^¼îâ{ 8‹Éè(çΕÿõÆo¨ôøß¼y3 Ñ¿µ§6l¨òÞÙÙS¦L‘Þ߸qAAA°±±ÁÈ‘#UæmÙ²¥Úº“““1`ÀÄÇÇÃÊÊ &L€‹‹ °}ûvŒ-åãõÓ¦MCff&~øáØØØ AWnÇjãÆ8~ü8^{í5têÔ ±±±Ø³gž={†™3g¢ÿþe§ ** >>>xøð!ºwïŽcÇŽ©%…ÒO9:êN3w.½*ÂÆ†zâ.\HçKN¿bÏïÏ>£—¾•ö¸jòÊ+ÔKº¢Êr::R¯fM¼½5çÊÈ«noO=Ì?þ˜ö‰ õŒV~ÂVÓßÔšRŠüþ;õÚŽ¥kÅÕ•zkÓ¢…"ÌĉÔëùÉzÒÉÑhÔH÷ Ðõ¨6Œz¯?~LÛàäD½Äu= òÆôª33z‚æ½÷è:³µ¥û«ø„KIת‘õ¾3†Ê§¥Ñ~oÒD‘&IOOßàÁãÀؘŽg“&tÿª &&t_;–îÉ99´ÍŽŽŠ0%m·±1åË—‘”Dõvs+Ý2ÊódnNìÞ]Ö-VUÞï…ŠžëE1-À?Ò>{ú”î-UüéÆ^Pد1J@)CCCáà໢ÑÒŠn’Šå*300ÀÎ;ѱcG\¾| .Ä×_ ÈÌÌÄèÑ£‘ŸŸQ£Fa²†äºté‚O>ù_ý5Þ}÷]¬^½ýúõƒ±±1‚‚‚0gÎâÍ7ßĈ#J¬{~~>nݺ…6mÚÀÜÜVVV¨S§ž={¦Vw±¼òv§§§#** ÉdÒvkÚöŠš[ìömÛ¶¡°°ï¾û.F¥³lÛ¶m±aÃéýÊ•+•ϵùüóÏ œ?”þA5jXâ2öïßÇãå—_ƸqãJœ¿¦ò÷÷Çž={ðÖ[oIŸMŸ>žžžÈÏÏÇo¿ý†/¿ü²TËŠŒŒD¿~ý‹~ýúáСCÒšœ>}S§NÅ?þ(ï°dÉxzzâÁƒøõ×_Õ‚ãr¹S¦LAAAÜÝÝqáÂÔ­[Wš>vìX 8÷îÝÃòåË¥R=zôÀ/¿ü"¥ *ɵk×PPPcccxyyé¥îŒ1Æj11 ûÑGå+ÿð!0u*=B_›YYQ꙲04¤àbEìlЀ^ÕÁÔ”RahIX©LL(×mdjJ©%ªC:Ô@ñ_Tžë´º5lH¯Šrv¦WY™šRZ¥´¹eb`@må´/U¥Q#z•—µ55–‡LFAírŒ“W!66¿¾MLèþTÞ{Tu~'Uä{¡¢çº½c%â'ª€Ø[€Ô³wÉ’%hß¾=\\\¤åâ4åùEŽŽŽØµk ðÍ7ßàäÉ“€>ø÷ïßG‹-°iÓ&­uXµjvíÚ…&Mš`„ pvv†““† ¹\ŽuëÖaïÞ½RðPWÝOOOtêÔ YYY V‹×]|/–MLLD«V­Ð©S'©Çº8MÛ¶×F¹¹¹Ø±c[ C±^w>>>j(Å¥§§cæÌ™044T ìÖF P ê4v€ÐS'¥†Þ½{#66ƒÆÑ£Guõ nݺX½zµÊþ³±±‘Æ|¸ví„b½%N:%=ÅòÍ7ߨõ oß¾Ò8[¶lAaQÃîÝ» §t”Ç«(,,DZZšÊx¤€Î;Ã\9¯kêÎc¬kßžr—7X¶nåZ¯Å30ÆcŒ1ÆJ‡ûU ''GúÝÄİoß>È>zô¨Ê´çZF`÷ññÁ¢E‹ Ƈo¾ù;wî„©©)öîÝ +++­uÈÌÌÄ•+W«<¨Y‘¤¤$Kƒìêª{rr2PÚ±QB[ÝÅòâôsçÎ!11°wï^‚ MÓµíµÍÍ›7‘‘‘çÑ6nyêÎc¬–«È›ŠGücŒ1Æc/4þË¿ (óòò£G@½oÅœ÷â4M=wEŸþ9úöí‹„„|R4øÚµkUòÈ—’’‚=z`íÚµ°²²ÂÁƒ‘€””œ8qnnnضmºvíŠððpuoРèlß¾½pÖVw±¼8½gÏžRýqãÆA&“IÓJÚöÚ$22Rú½4cwþüyüòË/°³³ÃÒ¥Kõ^¿ªÖXÌ7ZLý¢¼–%5脇‡ÃÇÇÉÉÉèú1.)e)×­iýâñkÕªŒ´XŠ !{í+öåçÌÌÌÄ… ¤ÏÅy4å×/oÝcŒ1ÆcŒ1ÆØ‹ûU@9Uˆ˜ºfáÂ…ˆŽŽÆ£Gо(×\vv¶ÚüÅà—_~‘RstíÚ|ðÎõ/^¼!!!077G@@† Ô¯_ À™3gàèèˆøøxL:µÄº?~wïÞŵkפÞÄÚê.¾Ë:88 22÷ïßÇæÍ›UÊ–´íµIzzºô{ñ4."qà›bòòò0yòd‚€•+W¢Þ 0HŒòSš””N&$$iiiÒX “&MRIuS‘ukZZZíÇ€ÊqQ>Þšû'Nœ@»víÐx/A!–ÑGÝcŒ1ÆcŒ1ÆØ‹ûU@¹×m||¼ô»³³³Júqš¶^º¢eË–IÁ¼+W®HBmöîÝ ðóóCs ƒ—X[[c„ €ÀÀ@$%%鬻ÜÜܤÓYYYR:âuß+o·……\”6SžVÒ¶×ʽ¼µ^år¹ÆÏƒƒƒ. nüþû﫼¾øâ iÞíÛ·ãý÷ßǧŸ~ª×ú×D .Dpp0’’‚wÞyGë>¬(CCCÚQñiâü€¢÷ýÕ«WQXXˆÐÐPÄÅÅaâĉððð®W1ðߺuk4¨®‘cŒ1ÆcŒ1ÆX­T$ž¬´œannŽçÏŸK¹¸‹A%ý‡6Û¶mömÛ`bb‚ÁƒãàÁƒ;v,‚ƒƒ5ÅÓÒÒ’’*ÁôâÜÜܤß €‚ëÅÓÆÌ;¥]yÿý÷‘ŸŸ€Ò³|þùç¸yó&`Þ¼yjë644Äœ9s'OžÄO?ý$MËÎÎÆÿþ÷?äææÂÄÄ}ô‘Æ}—””„ˆˆé%l*‚Êç÷ïß×X¾:Èd2i â={ö¨÷¿ýö[VCÍÊFì /—Ë1þ|JÓN:% €\ÕLMM±k×.˜››ãÑ£G*úÐ¥Kx{{ ó?$$Deú·ß~+5†Í˜1C­¼¬ß»w/rrr¤À¾|}}ñçŸ"33NNN:Sd1ÆcŒ1ÆcŒ1¦ ö«ˆ……¶nÝ „……ÁÍÍ ƒÆË/¿ ???äçç£E‹X¹r¥ZÙM›6açÎ000ÀŽ;`gg§2}äÈ‘xï½÷ Æèèh•éóçÏ—rãÿöÛohÞ¼9^}õU¼þúëpqqÁÂ… P ˜ï¾ûNmý]ºt‘gݵk\]]1tèP´iÓFÊ{>bÄivàÃ?”Ó§OGÇŽ1dÈ4oÞ\Ê?¾víZ­ixV¬X6mÚH/1Hž——§òy¿~ý4–¯.³gÏF—.] —Ë1jÔ(tëÖ cÆŒ‡‡>þøc¼üòËÕ]ŵhѾ¾¾h ^WWW¼þúëðööÆ€ðÞ{ïU[ÝÜÝݱzõjÀ¤Æ1}Ù¼y3êÕ«‡äädxzz¢ÿþ=z4ÜÝÝññÇ|||4>-áíí CCCÀÜÜ}ûö•¦ 4HjãÞúŒ1ÆcŒ1Æc¬<8°_…üüüpôèQ4kÖ ™™™8zô(.^¼™L†×^{ ç΃J™›7oâÃ?@=â}||4.ûûᅦ»»;RSS1räH)pP:žÀÀ@|øá‡°´´Ä“'OàïïÇ#::ÆÆÆ;v,®\¹‚† j\þW_}…¯¿þÖÖÖˆ‰‰Á¡C‡pçΘ™™aΜ9RZMŒqìØ1üïÿƒ‘‘nÞ¼‰¿ÿþIII°··Ç¶mÛ¤Þí/øûûcøðáÉd¸téþøã„„„`øðáR £šnûöíRïõèèh>|ÁÁÁ˜={6Ö¬YS­u›6m €RÂÂÂô¶lwwwœ;w={öDAAN:…Ý»wãöíÛ055ÅÌ™3qäȪ•µ²²B‡}ûö…™™™4Í××W*Ã}ÆcŒ1ÆcŒ1V²ÔÔT¡2W///µ€õ‹âÒ¥KRг´är9®\¹‚èèh˜››ÃÃãÊ}þü9®_¿ŽØØX‚xzzÂÚÚºÔå/^¼ˆÄÄDØÚÚ¢k×®e:¶‰‰‰¸ví222ШQ#x{{ÃØØ¸¼›SkDGGãúõëËåððð€››[µÖ§¬ç­ ¸~ý:îÞ½ kkktéÒEíÉ‘YTTBBB••{{{x{{WڀŌé‹x M›6ÈÉÉ‘ÄÖA ²³³ajj ‡———^×S*c¶œ:u ýúõS\ž1ÆcŒ1ÆÓ¥:þŸ3’üõ×_€þýûk]ÿ—[ àååU-sss)ozyËk{j 44ü¢kÚ´)š6mZÝÕ(7™LOOO)¥ÓMóæÍѼyóê®cŒ1ÆcŒ1Æc8cŒ1ÆcŒ1ÆcŒ1V«p`Ÿ1ÆcŒ1ÆcŒ1Æ«E8°ÏcŒ1Æc5€ ›[ÝÕ`ÿ……xžù¨ÔQ÷cŒ1VYþŸ½;«)ÿÿþjWJYKDö"dߊ±cìŒ}0–ùZÆúÃÌXc™1 ƒ‘±/Ã0Lˆ"”%²D")QEÚëžßïÎéîm·’y?û¨{Ïö9çž{n½Ïûóþp}ÆcŒ1Æ>©©éØ·ï*nߎDF†LaÚ¤IàèXrÇëaÚ…ø…àúÞëx~î9ÒBÒPέì\íÐq|G”©P¦¸›—£—/_Â××ñññ°··GÛ¶mQªT©Bß® ¸ÿ>ÜÿpG½võŠ©…9óööÆ AƒðæÍéµbëÖ­°²²*´íFDD`ùò娶m›Âë£GÆ÷ß5jh]^&“á×_ÅôéÓ^_ºt),Xc`=,, LJŸŸŸôZƒ pèÐ!4lØ0{C^¿~Þ½{ÃÝÝóæÍË×:ròäúúâÒÃÓ¥×R¤àêÔ«ˆ ˆÄõC`ZÆTí²áááhР¶mÛ†áÇJûcŒ1–{\Ї1ÆcŒ±€­mXZæ.S˜•|²LþZü—JP_^Ú“4ü5â/Ä>-–垺t邉'"88ïß¿ÇåË—‰Aƒ!!!¡P¶ûìÙ3ôéÓ‘‘‘¸~ý:>|ø€„„øûû#::ýû÷Gl¬öc¶~ýzLŸ>;wîÄ‹/ƒ£GbõêÕX¸p¡ÖeŸ?Žž={¢råʸqãpçδiÓ]»vÅÇóµ_Ü0-n IDAT7nÄõë×ѱcÇ|-Ÿ“WO_a_·} A}y;#pxîaËW«V íÚµÃĉñìÙ³Bi#cŒ1ÆrûŒ1ÆcŒ}š6µÃÇÓpåÊ\ºôúõ«TÜMb…èÙgxôÓ#€ž¥zýÝ Ó_NÇ‚”˜ôxlÆØÒÃÓqqÛÅâlªZéééX¶l†Š%K–ÀÁÁhÛ¶-vìØoooüý÷ß…²íY³fáÝ»wصkZ´hÒ¥KÃÜÜ...رc¢¢¢°råJËGDD`öìÙØ°aÆŒƒªU«¢bÅŠ0`vìØ5kÖàÞ½{—ß±cd26mÚ„æÍ›ÃÜÜMš4ÁÚµkQ»vmlܸ1Ïû„åË—cÈ!hÕªUž—Ï+»®@xGõkN¨‰)áS0/q_ #;ê¡¶5 σž«]ÞÐÐsæÌARR6mÚT(mdŒ1ÆXîq`Ÿ1ÆcŒ±D•*åЦÚ·¯ªUÍ‹»9¬EÞ‹”~oñ-мos”«RF&F¨l_½—ô–¦‡y†}tœ^¸p>>>;v,LLL¦5lØ£GÆÊ•+‘””¤Ó튽/^ŒŠ+ªL¯V­ÜÝÝáááäädµëøóÏ?ƒV™Ö§OXYYá÷ßW»ldd$–-[&Ýgii‰1cÆ`ëÖ­xðàAžökëÖ­€¯¾ú*×5þó".:÷¾§›U 0hí T´©3Ôk[]×u•æõßã¯q=:uBëÖ­ñÓO?!$DsoÆcŒ>®±ÏcŒ1ÆX õòå[xx\ÆùóaÈÌ`h¨Ö­«cîÜž07ϼôÆPüü³"#©4JéÒFèÕË_}å†Bˆ!þ'þˆ[oá}ø{€Y%3´ùª un„”)ðõðÅ£Ó‘”===ThT=æõ@ùª4¸jãÏã~ßû(U¶:ŽS-½bd’]ã=ñf"ÒÓÒ^+n·nÝ4mÚTíô®]»ÂÃèW/{Œ™L†;wîàÇ€R¥JÁÉÉIªiÿúõkKóÛÛÛ£J•*Òó2eÊàáÇ([¶¬Æ¶•/_oÞ¼Arr2LMUëÅÿûï¿èÕ«*W®¬2­téÒøâ‹/pðàA¬_¿ ÓÅ2;mÛ¶U»í-Z Ay4h ±òž?Ž_~ùöööpqqQ;OAÏ·˜§1ÒºF;À¬Œ™ÂúÚ9à4N"/GBCCCŒ7~~~8qâfÏž«}dŒ1Ƙîq`Ÿ1ÆcŒ±jëV|÷bÉ/¯88;Û _¿ìwÇ?Š»w³—OŠE—.õáàP­HÚú)‰‹ŠÃß=Ë̼Ã;œ¼u÷pëä-\ýúªÂôxïx\­~½çR&~¹Êå0åï)j×/Ë”Áëg/éyž?ª >+[[ÕR&,ge­ËÂvœ­ÊëåšP)JµUƒ¾• P·}Ý×™‘‰+N heôZûéí ÖàBpûöm888h,S¦LÀ‹/^oÖ¬?~ŒÖ­[vïÞ-õ`óæÍ>|8`åÊ•8|øp®KÓ¤§§cÁ‚ˆŠŠÂüùóÕÎóúõkÚo”+GïW¯^©L‹ˆˆ@™ýꈯ‡††æªÍpöìY€£££Úéº8ßÞE½“~/e¡zó@O_¦vÙ½>¼ý ±½¶¶¶°µµExx8—ãaŒ1ÆŠöcŒ1Æ+¡Ú´qÀÙ³Ã^ ˜ŒääTôëw ýûŸÂСG1jT{\¸0PšÇÕµ,NžœŒR¥Ôgä2íôôõ0zÛhô<Öz–ÙAçX¿XÜ8~W~¿¢0¿ÍL»? u[kì§¥¤áð¼Ã¸ów¤×š®hŠÆ®u»:333Ó ©sxZZšÊ4{{{9r:u´iÓàíí €óË—/ÇÞ½{ñÓO?aîܹjK験žžŽÅ‹cóæÍ8|ø0ìííÕΗ‘‘RéuÄiééé*ÓÄý÷O™øzJJJ®Ú˜˜ˆjÕª¥v]œo‚ 7Hƒ¦û$rÑ™L¦±Í†††èÒ¥ ô—1ÆcŃKñ0ÆcŒ1V‚5jdƒêÕ IËW¯âqòä]izdd.]zˆ˜˜÷Òkݻבÿ+PzúzhÑ¿*xWÀ¡‡ò ™Q™8í~Za>ÇïÑkn¯Ké$¼IÀiðrÿKéµF‹¡×œ^…ÒþâVµjU55Ua^yb©uÙüò¯[X¨žꈃP[__Y~Ï·Òå³K¥'«i»¤Åd÷®0³ÔÜÈÞ¿¸¸8­ó1Æc¬ðp`Ÿ1ÆcŒ±®mÛì ÜFLL¦Âô={"±{÷séyÆՋ¬mÿOo>Ň;ª5Éî„!ñ]¢ÖeCüB°³ëN¼¿œÝ£¢ó®Îè;¯/ô ?Þלœœ¨±dË»wTÓ½zuíçš‘‘‘B½zssó\õ0yòdlÚ´ 7n\ŽËTªT fffxóæÆyÄ,úÊ•+«L³µµ•¶­©M4–Rfnn.ýžÛò=ù9ßÊUÏ0÷ý«÷*ÓSS‘Õë§TƒR0+£=°/î§8cŒ1ÆŠÞÇû—"cŒ1Æc,WkäzÞÏ>+Š- ±5ÿ‚LÀ¹ÍçpÚý4„$ªa._=|G8v ÚׯÕ.ïØûÛìGzePë[éÃý¬;:ŒîèQ°õÖ?·ðêéÇWî¤N:€¨¨(µÓÃÃÃPÉMâââ0vìXìß¿;vìÀ Aƒ0lØ0xxxä¸ý¸¸8Œ78räF•«v¡]»v¸uë–bÝy9AAA°³³S;À®x£âùóç*ÓàåKêu!Þȉü6Þ¿W ¸Ë+ÈùV¾ZövŸxŒÌtÅ›Ïî<“~·nmc»£££i^ëœçeŒ1ÆXáàÀ>cŒ1ÆcôôLÄļCtt<¢£ã‘˜˜].ãÍ›Òëqqª™ºµkW†½½â@¸¶¶F8q¢·Ê¼Ÿ}–»Lb¦]ZJŽ.>Š«S¯J¯•ïV“ïNF¿zH×8¯8ìølBod—B’eÊðÏêpæ‹3 ë쵫lÛ >:ñÑñø{Ùß8Ùç$vÜôÍ¥_jÖ¬ ===ôïß_c°Z×Úµk¸qã†Úé'Nœ€«««Æ÷›7o0zôh=z'NœÀرc±cÇŒ9_~ù%¶nݪq_bbb0bÄœ:u žžžjËïh+ãîîŽ+W®àéÓ§jÛµÿ~Œ;VmÏGGGT¯^]ðWÙÕ«Waff†æÍ›kܾ¼Ò¥KcðàÁ ¶=¢‚œoPµNUTJ7Y¯'Â{»·t|Þ$àÂê Ҽ͇io{FFΟ?hÔ¨Q®ö“1ÆcºÇ#f1ÆcŒ1VÌ?ŽBÿþ»ñàúRîJdþïøé§!ÒsCCôï_ k×K¯}õUctëÖyáþýìõ6kÆõõ *òA$Œ>€Ä›ŠeO¬¬QѦ"d2èêANSƒS±§å8ÌrÀàÕƒ‘Ÿˆ€oTÖ{²ÏIµÛK LBü«xT´­¨2-44TÊŽÿòË/s]Ʀ Z¶l‰¡C‡bíÚµèСƒBæù™3g¤ »¡¡ê¿œ1115jüýýáååWWWT·ý·ß~ƒ©©)¾úê+¤¦¦bÚ´i û‰áÇ#((gΜ‘n0È;wîú÷ïG©-4xð`,_¾7nÄúõëa`=ŽÁÖ­[aff†Ñ£G«ÝïråÊaáÂ…˜7o† GGGiÚ³gϰqãFÌŸ??ÇDòÜÜÜpðàAܺu }úôQ™^ÐóMO_Ð:Nïˆýû÷®L¹‚À](_¯<^ž{‰Ì(Êà/çV :4ÐÚÞgÏž!22¶¶¶¨[·n®÷“1ÆcºÅ}ÆcŒ1ÆŠÙ¥KÁƒúê¬[÷óæ½GÅŠe¤×Ú´±ØïÕ« LLŒ0eŠ3¦L¹"½Þ¨QîËö0õný}K%È W?DÚ²4<ñ{ÙÕÚó~z„èIÑ0/o®2-'²LõµìïÞ½ €jÇwîÜ9ÏëÍ/===,Y²ýû÷Ç„ ðå—_¢zõê¸yó&–,Y‚iÓ¦¡K—.*Ë]¼xK—.…zõê…§OŸ¢iÓ¦Ò‡ÂÆÆ0cÆ ¼zõ Ó¦M“êÝoÙ²—.]B»v퀀Õ$þþþHJJBLLŒÚ{¹rå°eËôéÓ†††èׯŒqæÌ,[¶ »víBš?'Æ ùsç0jÔ(Ì™37FHH6oÞŒZµjaâĉy:–]»vxxx`Μ903S¬o_Ðó­J*€:.uÐvs[\ɺ$^ODâõìõš9™aà¦9ŽípñâEÀ´iÓ`ll¬u^ÆcŒì3ÆcŒ1VÌzõrÂðá¡øçŸ—x÷N{)•ºu1sf … >4ib#ýîêZ Òóž=\ÉúÝ VVºmüPËA-‘•€ÐÝ¡²Þ¯òŸ•‡Ë$—2FãnñdÂDü!\K·,¦cšÂº–5㵨›~~~€©S§ÂÒ²hÇNpppÀ¿ÿþ‹ñãÇ£oß¾Òë+V¬ÀìÙ³add¤0¿L&ÃÑ£Gáãã8uêÂÂÂàìì,öÏ;‡E‹IËìß¿ݺu“ûbù˜Ë—/ãòåËùn{ïÞ½áããƒ1cÆ`ýúõèæÈ±cÇп­Ë–)S˜?>FŽ)½>|øplܸVVVyj‹­­-ÆíÛ·ÃÏÏOêÁ *èù&ÒÓÓƒÛd7XV±„×/¤=I“¦Y°Æ ƒ`U]{Û333ñÇ@ŽÇ‰1Æc…K/..®P‹0^»v ...ÎyfÆcŒéL«V­àåå…úõë#%%E%° A€ HJJ‚‰‰ Ê´tqqÑévòÂËËK!Ðpþüy¸ººª-Ác%]zz:êÔ©ƒððp*”…)J ABBjÔ¨¡uÀÜMbb"BBB “ÉP§N”)S&ç…ä<{ö ÑÑѰ²²‚½½}¾K!¢iÓ¦pwwÇ‘#G ¯_¸Ãá¥%§!úI4RSQƺ ¬kZ¹húùóçáææ†Y³faíÚµ…ÚFÆc¬¸ÇÿÓâ þãÇ ’}šÙ¹­Zµ*ªM)ÿOvߨ§‹Ï[Æ>}þþþÅÝÆc…L¬¯ïææ†Æ[; Ñ öºì«Ò¥K£iÓ¦ù^¾fÍš¨Y³fÛáää„iÓ¦á—_~¯¯/:vìXàujclj ›Æ69Ï('##kÖ¬¥¥%f̘QH-cŒ1ÆXnncŒ1ÆcŒ±B!Ö×?~|¡gx³Â·xñb¸¸¸Hå•>6/^¼€¯¯/6oÞ¬u ÆcŒ î—ÎcŒ1Æc%f̘=zwS˜T¬XçÏŸ—ºãllmmñòåË"Ë1Æcêq`Ÿ1ÆcŒ1ÆJ -Z E‹ÅÝ ¦C¥K—.î&hÅA}ÆcìãÁý5cŒ1ÆcŒ1ÆcŒ±„ûŒ1ÆcŒ1ÆcŒ1ÆX Â¥xcŒ1ÆcŒ1ÆcŒ19‰‰‰†L&ƒN×- 33úúù˽çÀ>cŒ1ÆcŒ1ÆcŒ1&§B… Òïb ^MÓÔ½®üš¡avx>333OíãÀ>cŒ1ÆcŒ1ÆcŒ1¦¤M›6²ò‚ ¨çå§åôSÓ²2™ ~~~yjרgŒ1ÆcŒ1ÆcŒ1ÆJÎØgŒ1ÆcŒ1ÆcŒ1Æò /™úâOå×ôôôò½}ÎØgŒ1ÆcŒ1ÆcŒ1ÆJì3ÆcŒ1ÆcŒ1Æc%öcŒ1ÆcŒ1ÆcŒ±„ûŒ1ÆcŒ•û÷?üdÕä̓ׯñã  Ý·‹1ÆcŒ1V¤xð\ÆcŒ1ÆJ‚¨( Ìäg­;;€©Suß6V²<$%ÑïÖÖ@Ù²ÅÛF’“ˆú]_¨S§xÛSÒedaa€LFÏk× K`äý{ºþË«T (W®xÚó_÷æ K¿[XU«æmùÈH 1‘~çë/c¬€8cŸ1ÆcŒ±’àÐ! ÆN˜÷e_¿Ö¬ œœtß6]Í,oòzÜ.^ll€zõèáçW8íby7ztöû2dHál#99=~J¢µkºu³é»wÅÝ¢¼KO:vÌÞñqéRѵ¯ÍÙâã‡ì÷aûö¼-ïçÔ¨Á×_ƘÎp`¿˜<~ügÏžÅåË—ñöíÛ"Û® xôèÎ;‡3gÎàÞ½{ÈÌÌÌõò™™™¸}û6<==qãÆ ¤¦¦æiû>|€ŸŸΜ9ƒ   ÅðGe\\Ö®]‹¢K—.èÔ©:uê„ÀÀÀ\-ïííÉ“'£{÷îÒ²3gÎÌs;Þ¾}+-ÿàÁ­óFEEÁÛÛ§OŸÆµkלœœçí•D3gÎD§NðÝwßwScŒ±âüø#ЫкuÞ—?r„² §MË_¶a{ü˜‚Í·nwKJ–ü·¶m›7Õ« ¯],6m¢€mݺ…³þ”ÀÕص«pÖÿ±™:¸|øâ‹ânIþ'NÐyqé°~}ÑnÿøqÀÑ‘z 0Ê®÷ó£ïÔühÙàë/cLgJ`?´’ÍÏÏ“'OÆ;w¤×Œ1tèPlܸ–––…¶ííÛ·ã‡~@xx¸Âë*TÀ7ß|ƒ¹sçÂPK×Ä;wbÑ¢Eˆ’ëX®\9Ì™3ß~û-ôõ5ß'JMMÅ‚ °uëV$ŠÝÎÔ®]ëׯGŸ>}4.ƒ«W¯J;wî ==¥J•B|||nv] Dˆ]\åäf]+V¬ÀÂ… ó´MMÒÒÒpñâEÀ{ (ùúúbΜ9¸víšÂë&&&>|8~üñGT¨PA'íùââÅ‹¨\¹rq7…1Æ+^ÇŽQ)†3¨DG^¼OÙúnn@»v…Ó¾‚Šˆ ÏŸÍšwkJŽü7CCÀÙˆ‰)ܶ±¼«T‰ææ…³þøx JvêT8ëÿØXXЬ£G‹»%S£= -­h·ýèðä •ž)S¦h·ý±ªS(U*ËеúÕ+ݶ‰1öŸÅý"téÒ%¸¹¹!==&&&pvvF\\>|ܹsW®\™™™Î·={ölüôÓOsss4nÜÆÆÆ¸wïbcc±páBܼyýõ—ÚåW­Z…ùó第¬Ð°aC|¸Úå[¶l©r3"¿¾ÿþ{DDDÀÊÊ «W¯FãÆadd°··×ºlTT–,Yøâ‹/0iÒ$”/_S];~ü8>ÿüsdffÂÀÀ5BÅŠ‚ˆˆìܹ¾¾¾ðó󃕕•ηÏcŒ±Db"æÛµË_@îÄ ª3ýË/%³¾4cŒ1ÆcLÿe_DÒÒÒ0bĤ§§£víÚðòòBÍš5û÷ïLj#ˆÅ‹Kx] ÖÙ¾}{9r•*U$&&bâĉطoŽ;†£GbàÀ Ëß¿_ÊRïÛ·/öïß333ddd`Ö¬YøùçŸñûï¿£OŸ>j3ï·nÝ*õ—/_ŽùóçCOOqqqèÓ§®\¹‚‰'ÂÍÍ ÖÖÖj÷ÁØØÍš5C›6m eºçÕ¹sçÓ§OÇØ±có´¬··7222`jj ”Êï]ú\HNNƤI“™™ kkkxzzÂ)«® øùçŸ1sæL<~üK—.Å/¿üRhmaŒ1ÆX1;u ¦¬ý¬„„\KN¦›-[RÆ~aKI¡rÁÁ”‘X­P³&•ŠìíKEGS9™{÷èùƒ@Vâ„DOhØ0ç"e2 0xø ì쨆±³³öãž=`)4hXYÑúnÝ¢² ¦¦tSÅÆFý:23i¾Gh*W¦õ´m›÷÷,7tyܺyäåܹÓqëÚ(]:çe£¢€Û·é=OL¤JÛ·ÏÎ0Ö¥çÏgϲŸ×¯(÷^ (ˆÊWt3ËɉÞCe¯_SÛƒ‚€ÔT qc*;R½ºæ6ÄÅÑübIѪUiŸ 4”J¿$'ÓgN[/ŠðpÚö½{€‰ Ф СPI^øð¸{7»—Æó瀯¯ê|66€­mÎëËÏqÓ…ÄD:׃‚hR==*[Ôµkî MO®_®]£ õëÑ>ääí[ÀÛ›ÞçèXÙÛÓûK×mŠò¸‰×€>ò%Ü”?#¯&&ÙÏ=¢ó%,Œžß¸¼x¡¸ ccúlÉ/§NQ^#ä ëtÝxõжéì 4ožsY:A ÏÍýûÔö è8:;çnû©©ô½pÿ>µÃƆ¾GrûcøNÊëw¹²§Oéóì'Õ«Ó5®F j[ÅŠ9·1–;qqqBa><==…¸¸8áSåçç—«ù¶oß.çÏŸW™>~üx€`ff&¼}ûV§mœ7ož´í¨Lÿþ½Pºti€0lØ0•é#FŒ–––›7o¦¥§§ õêÕ­ZµRYV&“ 666¡}ûö*ÓÃÂÂ###€0oÞ<µí¿}û¶’’"=Ÿ4i’@011Éqß•™›› „={öäyÙµk× {{ûp  <~¬~¹”:¶òÛòó„§OaÄz.®ÇÒRNR]GHˆ ’=O»v‚`eEÏÛµ„ë×óLÕÑÕq;}šæY²„Ú B½zÙÇÃÅEîß×¼|jª xxB¥J4ƒÙï? Ë–åïœÕ$#ƒÞWùý›8Qu¾gÏTÃîÝŠódfÒgÃÖ6û|ÏUKKAصKÒÒÔ·cÖ,ÅuoÞ,ïÞÑþН‰çÌòåô~ÉKO§õ‹ó89 Bõêô{Ë–‚pû6ÇfÍtrØA„ rw¾89iÞoA(Øq+¨]»hb[]\èx‚`g'ÞÞš—ýæšïæMA0 û=—aÁAз8r$û\wr¢kšx\]é3¯iy]7//ZîøqÍóÈd‚ЧOö¾)ŸK¡¡ªï}llöô˜Åc­íqì˜ævõ5B^T” tïž½-[[AèÜ9û=˜8Q5/G×OùóMüÌŽAßâ>¨óä‰ ¸»g¿ÇòçÚòå‚pø0ý~ú´ârÃwR^¿Ë奥e_ --éš-¿}WWA4HûöûÈ\¾|YÉd‚L&233…ÌÌL!##Cú3--MHKKRSS…ÔÔT!%%EHII’““…ääd!))IHJJ…ÄÄDáÇBBB‚ ¼ÿ^xÿþ½ôüÝ»wÒÿ¯éééÂáÇ…Çkýÿ—Ï-"b‰›Zµj¡K—.*Ó'NœHJJ’²ÛE7nÜ€¿¿?BCC5®_\»v þþþïªgyùò%ÀÌÌ õë×WYÖÂÂu³hz¡t>##'Ož 8P*=#244”2ßýýýU–¿yó¦TÏ~„ L šø IDAT*Û®Y³&ºví 8ª¡ö¡““LrÊÐ ((þþþÒ#-«&aXX˜Âëþþþ*uîß½{§0ýéÓ§€ôôt•eµ ~›––†'N`éÒ¥X¼x1>œã Ãâ{Í›7W;øzTTd2YÎ#¢¢¢ˆGiœ'00*c‚ Ÿ¸¬l'Ož`Æ øöÛoñÓO?᱘E’Ooß¾•¶©0M|ïÅ2Noß¾ÅöíÛ±`Á|÷ÝwðU—¥¤FRRŽ?Žï¿ÿß~û-Ö­[‡›7oª÷úõëð÷÷ÏÓ€Ø!!!*Ÿo]µ1ÆØ'àüyÊ.3G}Ʊ6éé4Ðb½z4ènazó†¶ajJµ!!”~ïe|ŠËÉgˆêé‡QöëîÝôÚo¿ÑsùÇÓ§À?hÞvd$•)zð€2«W)»öÖ-ÊžnÞœ2ù•™˜Ð¼¡¡€ØköÜ9 sgʲôñ¡¬Þˆ gO@¹×hp0e0Q¶{l,µ!&†Ž³3eUzyå÷ȪÒÕq-[F™˜OŸRï;TSÛÈ;x÷NuA/þ÷?:nb{@@½Köï§ååÆ×*zo† ,-騫ëµjkKïƒ8ÈèñãÀˆŠó¬[¸»“&Qò£GÙí+WS¦óæÑ~*[µŠŽÕ©SôüáC`à@Üz÷nÚÿèh:®^^@R’âòË–_~Ió‹ÜÏžÑ1oÜøì3Ý"=mmÃÏžOž¬z¾„†Ò¹«-›· Ç­ ìí èš’’øûSÖ}l,Уðù犽9ÔiÞœ® ׯÓÏk×h ’cÇè½:”®ÊüýiýRöòíÛôÞ>}JÓ=¢k`B‚úíõq“¿F4h :½V-:n¡¡ôUV±"ËÐPúî²{*È?""€~ýÔ·¡8®òÌ;}éšMûsá½gÞÞÀž=š°MJ¦±N¢öúûgŸ3Ú± Ú´¡ýºu‹Î™k×èZzì°e 0húe‹û;)?ßåò¶o–,~ý•¾›¯^¥íGFÒ1?žö1¦;œ±_0¹É|–ÉdR¦ø˜1cÔΓ™™)eÍO˜0AaÚÒ¥K‚………ªvùüQ ”*UJ T˜6þ|€`hh(¤iȨS§Ž¨fì߸qC(sÜÃÃCí²þþþÒ<{÷îU˜¶fÍiZxx¸ÚåW­Z%Í©vyyÉØwqq‘ÖÓÃ[)ËãßÿÍõ²;vT»ýû÷ïK=äuëÖ|}}¥çÊçÑ™3g¤i.\P»î &@áfìûí·ÁÑÑQã_4h V­Z¥qÊÂ÷߯Ӷ3Æûœ±Ï>‚Эe£¾{—÷åÏ£ ¹;tß6e¾¾´­_ÕÞ–«WÕOÏMª:ii”™Ø¤‰ hêõš˜(:ѱüðAóºöìÉÎtw„èhÕy䳯߿§ PwwÍëMO„¯¿¦,Ѩ¨\ïV®å÷¸ BvÆþ€‚ :ýÄ š®îoÑ#Ghš§§æõß¾M™¥6ä½mÚlÞLÛ~ò$ûµ}ûh;aaٯ͟Oó)¿—.Ñë;wjÞ†ØÓåÄ Íóܽ›}¾Ô­+·n©Î£œ­/¾_šzgdÂðá곬u!*ŠÖ=~Þ—ÕÕq+ þþ´Ý}ûÔO3ö«W×|¸væY·NušØãAÓõkåJÊNV·n]·¼~æsêý!¥ÿ¥$«VÑt qŠó‘ƒ B•*Ô«@™¸Ï÷î©_öõkÅ^òRR¡_?:æš¾·ÅluûòŠã;© ßåbO‘øxÕi™™‚àæF½è+A8cŸáÅ‹øðá¨Í˜}}}888‚ƒƒ¦-^¼]ºtABB†Šôôt…é7nÜÀ¢E‹7n„£££Âtwwwèéé!##C¥7}º4¾ÅîÝ»ñ矪]ÎËË  @tt4jÔ¨ `Æ 3f ŒŒŒpñâEtêÔIúl@Û¶mPæ~n$%%!((Ю];µ1ÆØ'âòeàìY`î\ L™¼-+“?ÿ T©B™¢…­NÊ”>{–2•3W]])³9ëï)ñö ÌtMµäÍÌ€ÿû?j›˜e­Í˜1€‡ nì'ùšÂgÏÒö§LÑ\‹Þв£ÃÃ)ƒöc4ne·*ÿ6V΂NK£ãÙ¹3Э›æõ:9ѺgΤLW]k¡‹ÿwÄÇãÇÓvþù‡^Ê mÞÈ[ }.-¢:ÓÇkÞFŸ>”µ:{6ÕÉÖÆÅ8}hÚTušüù"“Q&këÖÀ_¨_—mócSÇ­ Þ¿§¬ßçϩֽ8.RbëÖi¾N´lIõÿû­SžXSýôiÚfJŠâô™3)3[yÝÛq+*Å}P–žNuþCC){_&£1I¢¢TßËÈHê=±p!½ N… À®]ê§y{ÿ ,]ªù{»U+ÚïÜ*Ê車~—»ºÒÏS§¨—@FFö4}}ꥱy³æ}eŒåž[ž?.ý.<¾ÿ>¬­­Q1kà*Uª€TºF¤¯¯½{÷ÂÉÉ ×¯_ÇÂ… ±:«Û˜|°È!RIy-Z´Àœ9s°zõjŒ7kÖ¬««+ŒŒŒpíÚ5Ìž=™™™8p )u S×öôôtÜ»wõëׇ©©),,,`nnŽ>¨´]\^~¿ß½{‡°°08::BOOOÚouû^PsçÎUx¾k×.dffbܸq2dˆÖe4h€ß~ûMz¾jÕ*\»v ÖÖÖ ¯k²dÉDEEÁÌÌ —/_F“&M¤iC† A7-䘛›ã·ß~ÃàÁƒñóÏ?ÃÜÜ#FŒ@… ðèÑ#,Y²aaa¨W¯–.]šc[Š›§§'<ˆ/äþ‰ùúë¯áììŒôôtìÞ½ß}÷]®ÖWWWDFFÂÕÕÿý7JkØÍÛÛS¦LÁ¦M› —õ‡Ï²eËàì쌧OŸbÇŽ=z´Â22™ “&MBFF6lˆ+W®ÀÒÒRš>räHtëÖ Ož<Áòå˱råJœÿý÷ßqíÚµ\íK@@222`dd$Ý8*hÛcŒ}"þùµ²¢yuípò$°qcîO-(kk ª._NƒQT:ÃÕ•‚Z:PI ]ó÷§Ÿš0"±M¾¾šƒª¢‰ ‹œ·-–Kñð²Ênª%6®\¦OÏy½EMÓˆâëÊåA^¼  ffÀÔ©Ú×-ßCB(˜¥ Y%DHÁЫW³ËÝxx_}Eå$®_,PÜ¿/h@È… i@GM hpÏS§¨DNÆšç=:{ð\m^¼ s`î\íånìís^WQ+Œã–Wqq0ݸ‘Þ{yÚÊ¢ÈË©=­Z[·RX>Y®];Ú§+²Ë[5oN’·lIìZµT×÷1·âPÜ×€®[ÀÎt]/‰U¯žbÀYÞÝ»ô3§rÕ•8è»ÈþÎѤeK`ÇíóˆŠò;© ßåS¦ÐõmÁº™efFŸŸÎiŸÛ·/œåûãŒý" ŸÑkž• ³lÙ24nܵjÕB`Ö&â´Ê*W®Œ}ûöA__k׮Źsç“'OFhh(êÔ©ƒmÛ¶ilÃ?þˆ}ûö¡F3f lllP¥Jôïß2™ 7nÄ¡C‡¤à¡¶¶wëÖ ÎÎÎhÚ´)³êá‰Uå¶‹ÏÅe_½z4mÚTÊX7—ËR·ï%Qjj*öìÙ€Æê@—.]Tn¢(ëß¿?|}}Ñ«W/|ÿý÷ppp€••Ú´iƒëׯcÖ¬Y¸zõ**Ég!}¤ºvíªÔhìq|…7näj=AAAèØ±#"##Ñ»woœ:uJkP,--±fÍ…s»lÙ²Ò˜”þa=þ¼Ô‹eíÚµ A}èܹ3† عs'233dgì¿xñBa¼‰ÌÌLÄÇÇ#A)ãA¼ЬY3˜ª©›œŸ¶3ÆûDP6Ý·ßRv`^mÙBuÈs bëR£FÀ¾};{6;`ðÃTÃý‡(“S—Ä:¿eËjŸO¼¹£»m‹û’–FA#M´4 þÚÙénÛÅI ÉdÚ÷;) °±¡}×e §R% 0?OÏÅ,ý¯¿nÞ¤ZÐâ8NÍš).+ÖòV—ùª¬reú©©nz^‰ÛÎéo÷Ò¥êÕu³M])ÎãPu÷îT³}À ð_ºDõÆOœÔŒa§VN× ñZ¥:­gOʆ¾ŸÆmøüsÊÞŸ02ÏQ]¦¸[q)îk„xc¼E àåKú>|²O:'''iZ²º{@ÁàE‹á»ï¾Ã¨Q£0kÖ,ìÝ»&&&8tè,´ÜÅMHHÀ7T€˜˜ܾ}/_¾Du¥?"•Û T6'00mÛ¶ÕØvqyqº¯¯/^½z8tèþüóOiš¶}/iîܹ# ÆÛ»woµóôïßи!k@ä•i>|@PPïC‡………Þ¼y#µ[ ì·oß^gmgŒ1ö‰Ø¶2݆Íû²wîþIÿ|‹Á¢Â&ÞhÖÓ£ÌÕZµ€¬øHM¥@Ø!ôOÿ·ßên»b©Ç¨(í˜èhú©ËàzVMÌžM¤ÿŠÊ•©'‰ƒƒær…ÍÕøî;„tËÊ ýúk`Ó& D‰A7åÌR1˜'þµÉJòÐÌ+1—ÓÀ‘oßR ûcJÞ)ÎãP‰œ” ÚÚªN¯Y“2Œs•]bJ±·ºr ^&£2"FF”Mß°aö ±ññTâgÐ dT,Eÿq+.Å}¸t‰®ëÖQ™u½’®\ÉLZžøÞË%i©¥îæý­ý½Ôq¥ºùN*èw¹øY±° ^ò=""h ï¾}éØl70+¡8c¿˜ˆ#‡H˺³94럴²eËJõÙÅiê2wEK–,AçÎ9Y#Ô¯_¿NNN—yóæ Úµk‡õë×ÃÂÂýõ¢££ñæÍœ={öööصkZ¶l‰‡jm{… ¤@gãÆÑ4«–¤¦¶‹Ë‹ÓÛ·ojÕªF===iZNû^’Èãs362A0räHLŸ>‘‘‘ذaž>}Š> îîîðôôDçÎqèc­×*Gù†‘¨|ùòr¾¡óðáCtéÒ±±±èó“› ~n¶­nûâûçààCCõ÷?5 !Þh‘/ÇsæÌtƒíÊ•+Òëâ<êêëç·íŒ1Æ>¿ÿÌš•¿|wÚj:ëÚÌ™šk&&ÔsÀÞؾþñ×$¯=ÑÄL]1{[“K—èçgŸåmýÚtíJÁ+1c¼8e> ÊàÜ¿Ÿê4±žý?ÒÏ©DÏgŸÑùîÝS.beEõøOœÐÞ{ãý{š§{wõ%Vò£Bª«}ú4ðúµæùÄòR…)¯çKq·ÈH:fÆ©ê¹ï äí­yZz:}–[¶T,…“@¥D<=Õ/W¶,e?tSI^q7‘¾¾öã“•Œ–£¼œ3Å}¯÷C‡j.5&_šG^³fô]uò¤öï*Mß9;+¶AÔÔÂùÞÐÅwRA¾ËïÝ£Vaaê—·±¡ñ"#\öØgŒåŒûE@¾TˆXºfáÂ…GDDg •”õ墭´ˆ¾¾>~ÿýw©4GË–-1yòd­Û_¼x1îÞ½ SSSxyyÁÝÝÖÖÖ(_¾<ºv튋/¢råÊˆŠŠÂ”)Srlû™3gðøñcHÙÄšÚ.>—µ¶¶FHHBCC±}ûv…esÚ÷’äÝ»wÒïÊe\Deµt=|ø0öîÝ Ø¾};f̘;;;”.]Íš5ÃáÇѳgO¤§§c„ R±¶š’@ŽådîÞ½‹øøxi¬† &(”º)ȶÕm?>« ¥¶÷¨œ\V üû­.°öìY4ʪýë™õOATT”4…¦^ùi;cŒ±OÀÐϬ²…yòø1 š;ge±•Ÿ~ùEóà•‘‘T;ºm[ 4){ˆ™õÊd2 (,éèHÁÝéÓ5Dïß§ ÆY³€Nrµ;¹bkKÙâß}GA9Mbb€_¥lc]Ëïq+¨™3©Öòôéšßs™ ¸x‘ÞMA´ügÄÏJ»vÀ>œju=JÕê’†–,¡sðûïÕ·+5•ÚF¿šƒù±x1YW¯Vÿžˆw–òåi@må‘å=} d%Ó((®ã&–mÕ”Ì ̘‘»uÍ™Cc/(“ɨdÈéÓTÃ_þoð—/)»xß>Í^1©K̘–Wœç@™Û÷ïÓ¹%/#ƒ®K9Õy¯Qƒ~ª;'êIqïžjà¿8¯âÿiênh¤¦6Pzu,,¨çÏÁƒôž«û_ëÒ%ºî«ãäDïõÂ…Ô{N™LF=òrººøN*Èwyp0kYImjÝ»—ÝVƘNp)ž" Ÿu%×eËF즥4MS–®è‡~‚y7nÜ€§§§ÆR'¤Œîž={ÂNM÷ã2eÊ`̘1X¹r%|||#ÕmWn{ÕªU¡¯¯{¹A¥ÚáÊmŸËï·™™jÉe"ÈOËißK ù,oMW™– €ƒ*T¨€Áƒ«gÆŒ8}ú4Þ¿OOO•öŸš… búôéhÒ¤ ^½z…#FàüùóÐW( Úß#ùiâü@vöýÍ›7‘™™‰‡âåË—˜={6<<<àéé) Ä õêÕC…¨±Èc¬d Ö¬¡`H:y_þÏ?éç˜1ºmWnÄÄPý¯¾¢¶›™Qéà` XÙÛS`MºuÁƒ)S°jU Ü “=¢r—.Q&b¯^ŠËNŸNµÖ­iùöí)àýú5 d¸hУU•ƒf‘‘”™™–Fõ€ èÈÝ ‡±1à¬Ñ矫VQyêTš¯jUjûË—4ÈçªUD+Œ’ù9nø¾pž?NY»âß°§OgO?wŽ÷üüsªÿeÊPpjÌ:îóçÓ¶Ë—§kŸ?§sñï¿éØLšD烮ØÙQ ëwï¨Æ¹XòBþÆM›6ê—­^ŽË!4Pæ7ßÐà·úú\ýí7 xýù§ê˜‰‰TK=>žÞ_€²À•ˆ;Jcl `Ö®]”}BÇÅÎ.;8úÿGÛ¼Ÿ>O7R±†²yflLå3fΤÀ\—.”…ûö-½gGŽP–õÿý°l™îŽ[A”-KeÅV¬ ëJóæTäõk Ž._Nç@ï… }úP@:$„‚ŒbMïnݨÞ÷Úµt~T¨½ß[¶ÐCÓ®þIçðàÁôY36¦óÀßXº”ÎswwÕå rÜd2àØ1Å ¼xáäIÅ4•+Óøʽš ¢ýÚ´ øòKº>yB=[þú‹J>ÅÄÐó!C²ù¢N¨¤ÕÒ¥4 jµjt“%6–²®·n¥÷"0Pñfrq^#z÷¦ïœ… ©$O¥Jô ¦öž9CïKd$Õâ¯_ŸÊÈßݺÑu{äH:wúô¡ý~ýš®§óçÓqññ¡›>¿üB½-Äïìo¾¡ÁƒÛ´V®¤^ VVTŠæàAê‘׺5-{ü8]K  ÃwRA¾Ë`òdúltêD×fA uŠP/Z¤þúÈË옚š"99Áâ¨ïJAP(ÿ¡É®]»°k×.£wïÞøë¯¿0räHܾ}[mP<>>oÞ¼…`º2ù@ýÓ§O¥À¾|[‚ƒƒá¬ftxùò=ÊmŸøð/^¼Êðävù’J¾TJll¬Úñ^k邚U{SÝ‘ò{VÄž!šnNˆçVaëÙ³'~øáôèÙ³'|||°|ùr,^¼XçÛ³ñµ½GòÓä³÷œœPºti$&&"((HèºgÏžˆÅÊ•+cÆcÿQY=ö0n\Þ—}ñøé'`âDÝÖrãûï)Ø >¸5oµKÓß6FF`Y³&»vµÈÖ–‚ 7R†¾²R¥(€Ô«mgáÂìiÕ«SPkèPõƒ3Q A>p¶aƒêöëÖUDÑÓ£@©›½”ÇæiÖŒ^<˜Cº–ŸãGA<±lȶmtC©kW º¥¦RpwÏš~à Û´Q¼Ùäà@ëØº•n®Èõ`@ç°§'Õ×PÚ0ߌ)€µcäD5jÐ>8@@jÒ¡enÿðƒêù:|8ǵk«.Mç“|íðazˆÌÌ(ج)pÕ­ƒçÍS¼Iei ÌK5¨;unÝ¢üÌ™Ù=taêT æ÷mK¾ÝƒÓ{ª©gK~[AÍ™Câ3((,ª[—‚ôŽŽt£âða –ÚÙѹàïO7(Äe<<èœ\¾œzñˆÚ¶¥y]\T·]£•éÜ™¡[·*N·µ¥›†#FhP5¿ÇíÃ`÷nõÙ×Ê™öݺÑåºî;ÓçyÆŒìÒU«}|(°¼aej7j¤دZ•n.,]Jû!¯ys(õóÏU—ŠïQ³&Ý0X²DõFÍȑكºnÙBAúAƒèú'ÞX¯ë..¤_·.{ù (“¿uk:Ï<=éG… Ù×ÇÒ¥é\Û½›®ÿòe˜ÜÜè‹£™·m®^¥ïŠråŠÿ;© ßåNNt^õèAçÚüùŠÓÛ¶¥›hýúéþ;±ÿ0þ4===´mÛ^^^ðõõU;ü`«”¿0³Ü¿S§N¬Zµ _ý5Ú¶m‹7n`ðàÁ¸xñ¢J=pùç1ZêúÉO“/ÿѬY3)Héëë‹ájjµ^–ëÂ¥ÜvùAA}}}1dÈËÛÚÚªôb(©Éý#q÷î]µúÀÀ@Ë‹ï[~Þ3]K-i p?ÓÖW‡äoŒtïÞÓ§OÇÆ±lÙ2téÒEç7̪«‚ÄÄDµ%¢n‹™?róôÞ¹¸¸àÂ… ¸víΜ9ƒZµjÁÁÁ½zõŠ+pæÌ™ÎeŒ1öôê•è5*ÙlP9ƒ‰uß¶œ,Z”ýû¦MÈxû–ÕªiØVT¾Pfjµjšƒœº²};=”íßOœT¯NÙÒkÖÐû–‘Aõ͵«µk릾½=¸bc){ÚȈÖ-³€€‚oCCCÊÄ6ŒnèÄÇÓ9T£Ïs’ŸãVPÆÆtbäHÊROI¡zÝ•+g—Q—ˆ4j=ä}ù%êÅóÕÎŽ®šnœ˜™QÆ4@çyT]ßé3^½zî2ÍósÜÊ”¡uA B׺ÐPzÿkÖÌ>×:v֯׾|½zô™Z¹’ö_þú–SïéâºF4nL7zÂéÍåËÓ9#þ_çìL7EµéÔ‰>‹/^Ðz,-)x_ªM×VÕȈn\ˆçlL 3{{íçlq'仼Nì›PcÇRׯ©çIåÊ´|.ÇÉcŒåö‹Hÿþýáåå…GáêÕ«h£Ô5tGÖwcccôìÙSeùÄÄD 4IIIèÙ³'fΜ ===8pM›6ÅÕ«W±`Á¬^½Za9sssT¯^‘‘‘ðööFJJ J‰_DrÎfe졎\&ޱ±1zôè#GŽàÈ‘#X³fBU&“aWV.GGGÔTªåÚªU+X[[ãÕ«Wعs§J`ÿåË—RÍñþýûk;„%J½zõ`ccƒˆˆºwïŽcÇŽ!!!UªTÑZ"‹1ÆØLãÆTò$¿AŸ©Ö¯®_dŒ1ÆcŒ}t8°_DÌÌÌðÇ@__AAA°··Gï޽ѦMôìÙééé¨S§V­Z¥²ì¶mÛ°wï^èëëcÏž=¨¨t×tðàÁ?~¼Æ ðüùó¥Úø»wï†zôè~ýú¡V­ZX˜U‡ÔÆÆ”ë·‚œß~û-`ß¾}¨]»6ú÷ïúõëKuÏ ¤¶Ì@ƒ¼ŠÎ¯¿þNNNèÛ·/ììì¤úãëׯ×X†gÅŠ¨_¿¾ôƒäiii ¯»ººª]¾¸|óÍ7hÑ¢d2† ‚Ö­[cذapttĬY³TzmÈëÚµ+&Mš@ƒ СC 4NNNèÑ£’’’`llŒ?þø&9uOϧ:uêH3{xx víÚèׯZµj…®]»J™èÅ¡aÆX³f àèÑ£ÒÍ1]Ù¾};Ê•+‡ØØX8;;ÃÍÍ C‡EÆ 1kÖ,@—.]ðõ×_«,ÛªU+ ##¦¦¦ 7^zõê%Ýãl}Æc* RwV_?粌1ÆcŒ±Oÿå_„zöì‰S§N¡fÍšHHHÀ©S§àçç===ôéÓ¾¾¾(«TgîÎ;˜1cʈïÒ¥‹ÚuÿüóÏhذ!âââ0xð`)pP9̘1¥K—Æëׯáéé‰'N <<FFF9r$nܸªU«ª]ÿÊ•+±zõj”)SÏŸ?ÇßÿG¡T©R˜={¶T–D###œ>}_~ù% qçΜcŒ1ö–—L}ñ§òkzzzE×`ÆcŒ1ÆcŒq`Ÿ1Æc%×ÔgŒ}Š™€´”4˜˜™wSØ@fF&Ò’Ó`jn ð=zÆc¬ÄáÀ>cŒ1ÆcŒ£¿\ß{ÏÏ=GZHʹ•ƒ«:Žïˆ2ÿÏÞ}‡Eqµm¿éMQ$‚…€(ŠbÅ5*h4ö[ŠÆM,‰-j|Ÿ{ÔÄõµ×¨±kÄ vP± € ‚ ‘*uçû㼳첅¶€˜ûw]\»;3gæÌìÌÏœóœwlKºz¹ŠŽŽÆÙ³gñêÕ+¸¹¹¡eË–°´´,òíJ’„[·náöíÛÈÊÊ‚‡‡4hccã<¯ãÖ­[¸zõ*²²²àéé‰F¨'Zhh(233add„Zµj廼,!!VVV033+ð:r~þaë ¥H°ô°D£/¡íж0³Ô¿Ý¸¸8ØÙÙY݈ˆˆ(ïØ'""¢RçÊ•+²sí³?•Fé¯Ó±{ún„,Q›w"q'âpkí-ôú³j·ª]B5ÌÝ©S§Ð·o_ÄÆÆ*§õéÓ«V­‚½½}‘m722óæÍÃêÕ«Õ¦<sæÌÁ»ï¾«·¼B¡À/¿ü‚qãÆ©Mÿþûï1}úô|Öïܹ€««+ÂÂÂò\VÕóçÏѵkWôêÕ ß~ûmÖ‘›—`G¿ȈÈPNK½Š _^@ÔÕ( X6V¶VZËFDDÀÃëW¯Æ'Ÿ|R$õ#""¢¼Ë{S""""""2E–{fîÑê«JŽ=ŸîÁ‹G/бfyçççŒ9wïÞEBBÎ;‡¨¨(ôíÛ‰‰‰E²Ý‡¢[·nˆŠŠÂ¥K—””„ÄÄDàÉ“'èÙ³'^¼ÐÌ–-[†qãÆaݺuxüø1ž={†Ý»wcÑ¢E˜1cFžë¢P(0gÎxxx Q£F…Ú¯+VàÒ¥KhÓ¦M¡Ö£ËÓ°§ØòÁµ ¾ªÈu‘Ø9e§ÎòU«VE«V­0räH<|ø°HêHDDDyÇÀ>•:ï½÷ž²µ>Qiô0è!î-½0*g„.ûº`\ô8LOŽQ÷GÁyˆ3 #"§WŸ.ɪj•‘‘Ù³gcàÀ˜5kÜÝÝQ¶lY´lÙk׮ũS§°oß¾"Ùöĉõë×£I“&°±±A™2eЬY3¬]»111˜?¾Îò‘‘‘˜4i–/_Ž!C† J•*¨X±"z÷îµk×bñâŸyófžêräÈlݺ ,@åÊ• ¼OÁÁÁ˜7o €æÍ›x=úœ_R¼ø¾Úˆj1ß&‹þçúÃÌUôP_ŽGÁ´–755ÅäÉ“‘’’‚•+WI‰ˆˆ(ïØ'""""z¥¤¤ááÃgˆŠŠEJJ !á5^—pÍÈ¢nF)ß7ùO4îÞv•í`fa†Jn•ÐuVWåüð#á€TµÔíŸþŸŸ† õÁ~ëÖ­‹ÁƒcþüùHII1èvå^3gÎDÅŠ5æW­Z½zõ† ðúµökå¿ÿý/ ÿþóºuë{{{üñǹÖ%113fÌ@ß¾}ѹsç|U«V¾øâ‹åøÏMÜ“8Üœ#V˜T6Aß%}Qѹ",¬-P»emtø±ƒrÙ€M:×Ó¶m[´hÑK—.EHˆîÞ&DDDTô˜cŸˆˆˆJæÔ§·UZZNœ¸‰•+/àÈ‘ìœåÖÖF2¤:NŸ~ cc#L€••9¢£_bÆs8y2YYLMÑ¢…¦LéŒ2e²/½|9?ý䇨(‘ÅÆÆ ]º¸ã‹/Ú£bˆÿ ‡qmû5$D$¬¬ñÞï¡^»zHMJÅÙ gqïÐ=d¦ˆUß©÷>üöCT¨RP¿c}Üê~ –å-Ñf˜fê3‹ìïÉW’‘‘ž¡6­¤]»v аaC­ó;tè€ 6 22µkg P(„¤¤$€¥¥%¼¼¼”9íŸ?Ž»wï*—wssSk okk‹;wî |ùò:ëV¡BÄÆÆâõë×°²ÒÌøðatéÒ•*UÒ˜gccƒ~ýúaûöíX¶lLLLtngݺu ÄÆõ.—›Gá矆››š5k¦u™ÂžoÏž)×å>ØÖ¶ÖjëwoåŽC8ˆ:]LMM1lØ0øûûcÿþý˜4iR÷›ˆˆˆ ‡}""""¢7Àë×é˜0aV¯ט—’"á—_B•Ÿƒƒ¡qãXµÊÿ÷ê)CNœˆƒ··3zôh¬œ6|ønܸ¡ÞzùàÁðñ©w÷ªÞ“·_\LöuVO3x¸vî·ÜqíÀ5\øê‚ÚüW§^á‚Ót"ZâÛU²Ã˜}c´®_‘¥À‰ŸN(?Wì^ñ êÀ½{÷P®\9T¨PAë|GGG@LLŒZ`?00ÞÞÞjË?~íÛ·Lž<6lPÎëÒ¥ 8 ÖŠ]×6 >>»víÂСCµ.÷úõkœ?_ýµÎu8;;ãÙ³gˆ…ƒƒƒÖeÂÃÃ1}útÌž=õë××¹®¼8qB|׃†¥¥¥Æ|Cœoqã”óìœí4¶Q¶BY•3‚/!á\Ò_§ÃÜÊ\k}Û¶m X¹r%ÆŽ«ÑcƒˆˆˆŠSñQ©såÊ\¹ræææ07×x *m6o>¯Ô÷ò²†““f[9OÇŽuao¯þ'½ƒƒ jÕªŒýû¯`ß¾+8wî.FÒlUݱc¸¸h¦2¡Ü•w,—a.ÓíˆT:54ƒÁ&&¨ÕºV®ëÎÊÌÂþö#x~°rZëq­ Wá"pýúu¸»»ëLckk xüø±ÚôFáþýûhÑ¢`ãÆÊ >üúë¯øä“OóçÏÇÎ;óœš&##Ó§OGLL ¦M›¦u™çÏŸÐÿpÀÎN¾Ÿ>}ªu¾$I˜?>1fŒö‡3ùqìØ1€§§§Öù†8ßâcâ•ï-Ëj><026‚•kv—I:ëëââDDD0Q b`Ÿˆˆˆˆè pòäåûI“jãõëé¸~}2"#gàáÃ1>¼šr~Õª"(ùÞ{î8vìµõ\½:¯_§¡GƒèÙó ÜAƒZãŸú(—ñõ-FÃÒ’Æ ÂÈØƒWFç½aT.;èüÂÿ.ÿuçÿ8¯¶¼ógŒ½5µZèì§§¦cç·;ôŸ å´†?4D}ßµ/ ‰‰‰°¶¶Ö9ßÔT<Ò–:ÍÍÍ »víBÛ¶m1vìXœ:u €ÌÏ›7›7oÆÒ¥K1eÊ­©t´ÉÈÈÀÌ™3ñ믿bçÎpssÓº\ff&(Sÿh#ÏËÈÈÐ:ÿôéÓøã?0þ|¼óÎ;yªŸ.ÉÉÉØ¶m zõêZ—1Äù&I*ƒ4èzN¢P(:ëljj bÐ_"""*Å–Š' @÷<¥ÝÛ¼oôöâyKD¥Ù{ï½WÒU 2¸:u*ˆ,Yrû÷/AË–•P¯^%Ô¯_ãÇ·C“&P³¦#ÜÝ«(ËÕ«ç ''SDE‰€åÓ§¯pàÀ åü¨¨Lœ9sÏž%(§uêTffÌÊYFÆFhÒ³ Þ9õv|º©·S‘“…C½©-çùžè2¥K®©tc±mì6DoVN«÷]=t™Ü¥Hê_ÒªT©‚íÛ·cРAèÚµ+¶mÛ???üøãX¹r%ÆŒ“ç–úééé˜9s&-Z„]»v¡C‡¹* ””|÷ÝwèÔ©z÷î]èõ½|ùRù^îå ¡Ï·Â’SéêÕ@DDDE¯ØþšoÞ¼yqmªX¼µûFo/ž·Do?>¼#*}†>À¥KÉ€t„„DˆT.3r¤+ZçHçbnnŠÞ½]ñÓO÷ÇŽã·ßÔ[ÑnÝz ÆÆÙAÒÆ5ÓzPÁ¸6tÅð£Ã±¡ß$ú'ªÍk»®-Ú|ÞFw éÿyú[?ߊ„sÙ_þÐ]'w…±é›ÙÉÚÁÁ¯^½Ò9_n©¯¯Å½ƒƒ6oÞŒ¡C‡¢{÷î€Õ«Wcøðáyê¿~ýS¦LÁÊ•+±fÍôéÓGïòr>øÔÔTˤ¥¥©-«jëÖ­8þ<.]º¤·Õ^ɃК_?§‚žo6l”ï3^ké‰ éϲ{WX—ÓÝÊ–- ˆ‹‹Ó»7ó¯D""""=ÒÓÓÕ~ˆÞUªTÀ¡C£°jUk4h =ºzu8|}×ãî]õ¼å-[f§ð˜>ý:ž=ËR›¿iS6n|¤ü\·®“kNaW¤™“<ü|8’ã“õ– ñÁºëÔ‚úíÖ·C÷o»¿±A}ðòòB`` Î”-ññ"§»““þsÍÌÌ 66ÙAç2eÊä9¨Ÿ˜˜ˆÑ£Gcåʕذa† –kX[[#66Vç2r+úJ•*iÌûý÷ßM›6…‘‘‘ÚÏÁƒOOO\¿~=OûP¦Lå{}Tä|³sÊ07ái‚ÆüÔäTdþ¯×¥‡%¬mõöÅCy<"""*~ìKDDDDTÂ$ زå®_Â7ßtĈ>xþ</‡°°çØ´é®]KALL~ûí4V¬øXYÞÓóÝóˆµX±×DEgÍŠvàh¿£ÊÏÆöÆè±µth@[oŸºªUáXݱˆ÷&jÖ¬ ˆ‰‰AÕªU5æGDD)wt‰‹‹Ãˆ#°{÷n¬]»GŽÁÇŒôôt [íSiw÷îc|úéIÀ£G øá‡î¨Q£²ð¶¶V>ü4àæÍçjåkÔ¨77sQ {ñ"»¥îŽ1رcºtynnv011Æýû/qà@v0ÿÃÕƒó¦¦&èÙ³:–,¹«œöÅõñÁ P¯Þ ܺ•ݸQ#æ×/¬¨ÛQØ6x’¯¨§=qôrDEçŠPd*`dj ¢%uÚÝ4ljº îÝÑQ$¿JÖêÀn´n/%0¯ž¾BEÍVÿ¡¡¡ÊÖñŸþy±õ‘ŠfàÀX²d Þÿ}µ–çGÅÁƒqäȘšjþËùìÙ3 48qâ|}}ˆ¼í¿ÿþ;¬¬¬ðÅ_ -- cÇŽUÛ§¨¨(|òÉ'ÆÑ£G•T?~={öĽ{÷´¦êß¿?æÍ›‡+V`Ù²e01Én¹¾jÕ*X[[çÚcÀÚ·oíÛ·ãÚµkèÖ­›ÆüžoFÆF€Ðf\lݺp~Ìy®D…Ú}<Y1"}—]{;x¼ï¡·¾>DTT\\\P«V-½ËQÑa`ŸˆˆˆJ¹¥>ÑÛÂÖV3§þÁƒ/¼Ð˜Þ«—† k£1ý½÷\dö»ti 3Œã1cÎ+§×«—÷´=¤Ýµ}×4‚¬pgѤÏNÇÿPÄjæž¿·ôžŒz‚2ÊhÌË"K{.û7n¹ãÛµk—ïõ”‘‘fÍš…ž={bĈøüóÏáää„+W®`Ö¬Y;v,|||4Ê>}ßÿ=üüüÐ¥K„……¡aÆÊwîܳ³3`üøñxúô)ÆŽ«ÌwÿÛo¿áÌ™3hÕª®^½Š«W5 %%Ïž=ÓØ·³³Ão¿ý†nݺÁÔÔ=zô€¹¹9Ž=ŠÙ³gcýúõx÷ݼ]'qqqسg’’’Ž„„¬]»½{÷Îsþù:6l؀ɓ'ÃÚZ=¿}aÏ·Ê5+j6«‰–¿¶ÄùÿÝ’/%#ùRöz­½¬ÑgeŸ\Çv8}Zô;v,ÌÍÍó´DDDdx ì•°zõœ±p¡7Μ‰€vìˆÑXÆËËãÇ7EŸ>MQ¶¬æƒ€ œ•ï}}Ë£n]ñ¹sgOçÿ÷Þööe‹f'þEšömŠÄ˜D„n Uæ7¯Ð±šjsKsÔÿ >Œx€È=‘Ê€«MS4ÒŽÕ‘üJÿ€ºùáïïøòË/Q®\ñŽàîîŽÃ‡cøðáèÞ½»rú?ü€I“&ÁÌL=uB¡ÀîÝ»áççÊÁf½½½•ýãÇã»ï¾S–Ùºu+>øàe`_’Äñ>wîÎ;WàºwíÚ~~~2d–-[@<Ù»w/zöì™çõDDDà§Ÿ~R>`€åË—£Q£Fy컸¸`øðáX³f üýý•=d…=ßdFFFh?º=ÊU.‡“O ]%u—coGô]ÑöNözëš••…?ÿüòuœˆˆˆÈðŒââ⤢ÜÀÅ‹ѬY3”/_¾(7Sbмyó’®Q¾ð¼%zûÉ×ùùóç•­Ûå`ˆ$Ijïóûšsšœ"A¡PÀßßÍš5+ÚÓãĉj†“'OÂ××Wk*¢7Yll"¢£_">þ5,,LáàP•+ÛÁÜœç2eSͯOOÏ©Gff&BBB˜˜ˆwß}Wošääd„„„@¡P fÍš°µµ-‘z¢aÆèÕ«víÚccý­æ +ýu:ž•:ééé%]""""""¢ÃûDDDDDDDDDDD¥ûDDDDDDDDDDD¥ûDDDDDDDDDDD¥sì—û÷ï#<<ÖÖÖððð@… Še»’$!$$‘ª¤²Ê IDAT‘‘P(¨R¥ <<<`bb’§òYYY¸qãž>} {{{4hÐyÞ~RRnÞ¼‰„„899ÁÃÃFFF݉‹‹ÃÚµkáï︸8( ÀòåËáåå•kùS§NaÇŽGjj*ÀËË Ë—/ÏW=^¾|‰Þ½{~ýõWxxxäsOÞ~&L@`` |||ðŸÿü§¤«CDDDDDDDDôF``¿˜ùûûcôèÑ RN377ÇÀ±bÅ ”+W®È¶½fÍÌ;jÓßyç|ýõט2e LMuŸëÖ­Ãwß}‡˜˜å4;;;Lž<S§N…±±î iii˜>}:V­Z…äädåô5j`Ù²eèÖ­›Î²Ïž=Ã… ”?AAAÈÈÈ€¥¥%^½z•—]Wzòä š5k†ÈÈHyyY×?ü€3fäk›º¤§§ãôéÓ€„„ƒ¬ómˆÓ§O£R¥J%]""""""""¢7ûÅèÌ™3hß¾=222`aaoooÄÅÅáÎ;ذa‚‚‚pþüyX[[|Û“&MÂÒ¥KeÊ”AýúõannŽ›7oâÅ‹˜1c®\¹‚={öh-¿`ÁL›6 `ooºuëâÁƒˆŽŽÆôéÓŽÕ«Wk-«P(ЫW/>|P­Z5¼ûî» Dhh(ºwïŽM›6á“O>ÑZ¾iÓ¦# jΜ9ˆŒŒ„½½=-Z„úõëÃÌÌ àææ¦·lLL fÍšèׯF¥ìiQ¦LƒÔˆˆˆˆˆˆˆˆˆ(7̱_LÒÓÓñé§Ÿ"##5jÔÀÝ»wqþüyܾ}[¶l±±11sæLƒoûêÕ«Ê ~ëÖ­Š .ÀÏÏ‘‘‘øøã{÷îÅîÝ»5ÊߺuKÙJ½{÷ŒÄéÓ§qãÆþøã8p@ëöW­Z¥ êÏ›7aaa8sæ """вeKÀÈ‘#ñôéSû`nnŽæÍ›ã›o¾A›6m x$€ãÇÆ‡¡C‡¢I“&ðòò‚——W®ÁùS§N!33VVVذa|||”es{(@DDDDDDDDDd( ì“ÿþ÷¿xôè`õêÕ¨V­šrÞÀ1tèPÀï¿ÿޏ¸8ƒn{×®]Ê÷«V­‚ƒƒƒò³ ~ÿýwØØØ€Öû .„B¡@¹råðçŸ*{˜ššbéÒ¥¨]»6‘¦&'I’°`Áâ¡ÂôéÓ•9õíìì°iÓ&˜™™!%%EgŽú¿þú ð÷÷WÛ^AÈi„jÔ¨Qà²U«V…¥¥eë@DDDDDDDDDTLÅSLä€yõêÕáãã£1äÈ‘X³f RRRpøðae+z¸|ù2²²²P±bEiI’péÒ%H’GGG¸ºº*çEGG¬­­Q§N²eË–E­Zµpýúu<~üXm^ff¦²%~Ÿ>}4ù555ÅСC1eÊàñãǨZµªrþ•+W”ùìGŒ¡±íjÕª¡C‡8tèvïÞùóçk,“—mu Fbb¢òszz: <<jËzxxÀÖÖVù9>>wîÜQ~ dddh”µµµÕ9ømzz:Ž9‚k×®!++ 4@÷îÝó½/AAA8{ö,bbb P(P½zutèÐAí!‘¡ÅÄÄàéÓ§°²²‚»»»Öeˆï²|ùòÊé’$áâÅ‹wwwØÙÙáÁƒøûï¿tïÞ5kÖ,pý^¾|‰€““œœœ”óäï¾råÊpqqÁË—/±gÏ„……ÁÒÒíÚµCëÖ­sÝFJJ Ž;†›7o")) ŽŽŽxÿý÷Ѹqce/]º…BZµjåy@ì¼|ùRíú6T݉ˆˆˆˆˆˆˆèíÄÀ~1$ gΜid¼½½accƒäädøùù©ö:„ï¿ÿeË–E`` ªW¯®Q~ñâŘ:u*,--5‚Îr ===Êœòª’’’Ô–•">>^oÝßÿ}åûÓ§O«Õ]6·ò‡Âýû÷5 Ö°aÔÁeU3gÎÔH{têÔ)´mÛVùÙßß~ø¡FÙˆˆ´hÑBmZ›6màçç§±lpp0>úè#ܽ{Wmz­Zµ°víÚ<íC`` F­ñ½Êzö쉽{÷æi]ùµbÅ ,\¸žžžÊ~N 6lݺ PNOKKS§½{÷ââÅ‹X¸p!$IR.óí·ßâçŸÆ_|‘ïºEEEÁÇÇ÷ï߇··7Ž=ª6_þîÇÖ­[cðàÁj7Ïš5 ƒ Ÿþ©sàç`äÈ‘xò䉯¼6mÚ`óæÍjçë!Cpûöm,X°S§NÍÓ~ôë×AAA˜3g¾ûî;ƒÕˆˆˆˆˆˆˆˆÞ^ ìƒÇ+çÚZÌ€±±1ÜÝÝqíÚ5 ðÌ™3qæÌüóÏ?8p Î;§œ¿|ù²2 ¸bÅ xzzª•ïÕ«,X€ÌÌL>|X£µøíÛ·•­Ñ{ôè¡6Oµ.ºê®ÚR=gÝåÏÖÖÖpvvεü½{÷ ØïÝ»·Z‹ÿ5kÖ ++ íÛ·×èýP¥JµÏÎÎÎ5j”òs`` .^¼ˆòåË£ÿþjËÖªUKcÛ/^¼@‡ƒ²eËbÈ!¨^½:‚ƒƒ±aÃ|öÙg¹ÖÿܹsèÔ©’““aee…>ú 4€‘‘îܹƒ½{÷*Ç/x“­Zµ GE·nÝаaCDEEaûöíHJJ¸qãо}û|S<|ø-[¶Ä¡C‡Ôz[¨ºqã~ûí74hÐ;vDbb"öï߇bãÆðññÁàÁƒ5Ê8q½{÷Fff&Þ}÷]|öÙgppp@PP6mÚ„Ó§O£mÛ¶¸~ýºr|†–-[âöíÛ¸téRžö#%%ÁÁÁ€V­Z¬îDDDDDDDDôvc`¿ȹõõàñ­[·àè舊+*W® ÊÔ52ccclÞ¼^^^¸téf̘E‹1pà@ddd`À€9r¤Æö›4i‚É“'cÑ¢E6l/^ ___˜™™áâÅ‹˜4i²²²Ð§OôíÛ7׺gddàæÍ›¨S§¬¬¬P¶lY”)SIIIu—Ë«îw||<ÂÃÃáéé ###å~kÛ÷š2eŠÚçõë×#++ Æ Sk]®‡‡~ÿýwåç àâÅ‹pttT›®Ë¬Y³kkkœ;w 4PÎ0`>øà½å“’’п$''£F8vì˜Fo¥K—búôé¹Ö¥¤9rÛ·oG¿~ý”Ó¾úê+x{{###7nÄÿýßÿåi]!!!ðõõETT|}}±oß>åÚœ:u cÆŒÁÊ•+•ã;Ìž=ÞÞÞ ÃÚµk5‚ã …£FBff&êÖ­‹óçÏ£\¹rÊùŸ}ö>øà€··76l¨L"VsÖ]þ,—}úô)ÜÝÝѰaCe‹uyž®}/ÒÒÒ°iÓ&blÕ >øøøh>^ù>gYùòåu–W(xõꑆ©´Sí•¡MnédnܸW¯^)Çj1b„Zª›Âl[Ûöåc¯ï;²³³S¾Wý¾µö;†zõêã @LLŒr ¹Œ!êNDDDDDDDDo?ö‹j«Û˜˜å{gggµô9ò<]­tesçÎUó._¾¬ ê²cÇ@çÎáêêª1ßÖÖC† øùùáÙ³gzënll 777e‹éääde:œu—?«î·µµµZ¾xÕy¹í{i¡ÚÊ[WàU¡Pè,oddccqyÊùÛÿíf̘ëׯÃÑѱ±±øôÓOõÃÂ011 ÿ;R'/d·¾¿rå ²²²pëÖ-DGGcèСðôôT^¯rà¿víÚxçw ¾DDDDDDDDôöb`¿8;;+SÌȹ¸s’$I-ý‡.ëׯÇúõëannŽÞ½{C’$|öÙgZsç¢åqll,h|Uæææ¦|/š³.ºê®š¾'gÝåÏIII:[Xë+_Z©¦J‘ÓÇäôüùs匌”Á^¹UwI{†èz8!Ÿ[E­sçΘ;w.°~ýzÁÏÏóæÍ+’íÉ­ñõ}GªóT[ï{yyÁÆÆÉÉÉV¦áéܹ3ºté‚7nàÉ“'¹¦á!""""""""Ò…ýb`dd¤LµqöìY­Ë¨¶úþûïk]æÖ­[øòË/ ,À¶mÛФI¼xñýû÷Gff¦FÕ–ãª-ñsR§šþ£Q£FÊô8ºê~îÜ9åûœuW4·ò...pvvÖYÇÒDN»ˆ42ÚÈëÒ´iSÀ?ÿüc¸Šå“œjIW€ûáÇÅRÕž-:u¸qã³gÏVËYo(uëÖ ríËi¤r’Ç@P]×\³f͈VùGEõêÕáîîŽ.]º@’$=z4×s‰ˆˆˆˆˆˆˆˆta`¿˜ôìÙ€dóÂ… ó×®] @Õ;wî¬1?99}ûöEJJ :wîŒ &ÀÌÌ Û¶mƒ­­-.\¸€éÓ§k”+S¦Œ2½Í©S§ššªµ~ÇŽ˜™™¡fÍšÊéæææøðûvíR¦Ü‘) ¬_¿àéé‰jÕª©ÍoÞ¼9ëÖ­ÓØntt´25‰|ŒÞµk×V>¤Ø¾}»Öe6oÞ¬w zJìÚµKçrE™ªçÝwß<}úT-e’lãÆE¶m}.\ˆ  ++ ü1âââ ºþ>ø€ôYNe•Ó¦M›5jÔÐè #·Â÷óóÃÙ³g•×tóæÍaooC‡áÊ•+jËåûÅdÈ!pppŒ9R­…üáDZjÕ*åT5 wïÞEåÊ••©H‘^gõêÕ€%K–àÀe ˆŒŒÄ¨Q£ÔZ + üðÃ8uê\Wm S¦L Ò®|ñÅÈÈÈ Ò³Ìš5 AAA€o¿ýVcÛ&&&˜4iàøñãøå—_”óRRRðùçŸ#-- æææøæ›o´»gÏžáîÝ»Êy`SI’Ô¦‡††j-_ŒŒŒ”oß¾]#¸ÿã?ÂÏÏOï:úõë///ÀСCñ×_i,ŒN:¦ÒZÈ=M ¦M›¦öáäɓʋ›……¶lÙ+++DFFbĈ]“&MмysâüÏÙëâÇT> ;v¬Fy9X¿cǤ¦¦*ûÆÆÆèÔ©öîÝ‹ÄÄDT®\YoŠ,"""""""""mØ/&ÖÖÖøóÏ?allŒàà`¸¹¹¡k×®xï½÷йsgddd fÍšX°`FÙÕ«WcóæÍ066ƦM›P±bEµùýû÷ÇðáÃ!IŒˆˆµùÓ¦Mƒ··7ÑÂÚÕÕ~ø!zôèêÕ«cÆŒÄXË—/ר~“&M0uêTÀ–-[P£F ôìÙuêÔÁܹs}ûöU¶0ÏiüøñÊ@çW_}///tïÞ®®®8~ü8`Ù²e:ÓðüðèS§ŽòG’§§§«M÷õõÕZ¾¤|ýõ×hÒ¤   €-Zàã?†§§'&Nœˆ÷Þ{OoySSSìÚµ ...HLLD¯^½àîîŽ~ýú)ƒþõë××™âÈjÖ¬©|p°aÃÔ¨Q=zô@óæÍÑ¡C >¼È¶›ºuëbñâŀݻw+ŽÊš5k`gg‡/^ÀÛÛíÛ·ÇÀQ·n]Lœ8àãワ¾úJ£lóæÍabb‚ÌÌLXYY¡]»vÊy]ºtQ>ck}""""""""*ö‹QçÎqðàAT«V ‰‰‰8xð üýýadd„nݺáìÙ³(_¾¼Z™   Œ?€hïãã£uÝ?ýôêÖ­‹¸¸8ôïß_8D:???Œ?666xþü9Ž9‚ýû÷#""ffføì³ÏpùòeT©REëúçÏŸE‹ÁÖÖ=¾}ûpïÞ=XZZbÒ¤IÊ´$Ú˜™™áСCøüóÏajjŠ   8pÏž=S†*·n›˜››ãÈ‘#øè£`dd„€€lݺ7nÜÀG}¤La¤O5péÒ%Œ9––– ÁÎ;±sçNÁÉÉ ßÿ}‘îdž ”­×#""°ÿ~\¿~_ý5–.]Z¤ÛÎÍ—_~‰®]»R‚ƒƒ ¶îºuëâìÙ³hݺ5233qòäIlÛ¶ ·o߆……Ƈ¿ÿþ&&&eË–-‹ ÚµkKKKå¼N:)Ë0°Oo##£ÿÃØ˜J7£¸¸8©(7pñâE4kÖL#`ý¶P=óJ¡Pàòåˈˆˆ€••<==‹mÐØ×¯_ãÚµkˆŠŠ‚$Iptt„··7lmmó\ÞßßOŸ>…½½=š6mš¯ïöéÓ§¸zõ*PµjU4oÞfffÝR#""×®]ƒB¡€§§'ÜÜÜò½ŽÔÔT\¾|ÑÑÑDпaÆZ˹Éïy+I®]»†û÷ïÃÖÖMš4Ñè9ò6 Ç7œœ 4oÞeÊ”)éjé%_ççÏŸWö’$Iù*¿—©ÎËíUWY…BåÒ%áĉjc¶œ,^ ôî xy¾n†’RÒ5 Òäõë‚õ\É) ¨WððŽ)üú(w …¸5oôë'‚üyñ¦Ü#BC/¾Ê–ÜÜgg BÀÉ øå—’®]ñð÷Þ}¨][üøûf½K–µje¯7>Þ0ë¥ÂS(€Ÿ€nÝJº6Dô? ì½éâ  .]€-ò_~×.ÑÂnìØ‚µö/j÷ï‹àصk%]* RS__`ýú¯+44;`|÷ná×G¹KMΟïýýóÖjÿM¹G„†:ˆVú;wÿü#mÝ*R”xx”lýŠKÓ¦ÀÕ«À¢E†]ï—_çΉ>ôf¹t Ø·˜2xç’® ýiIW€ˆˆˆˆˆr±w¯HÅ3~<`œÏ¶9 ¢µ~ûö@«VES¿ÂŠŒ=5*éÚЛîÕ+nÛ¶ðëê×O¤§JI† )üú(wÖÖÀÁƒ"0Þ¹3P±bîeÞ”{Äš5"uÓÅ‹y«÷ÛÊÄD|OŸv½eË-[»wv½Tx¿ÿ.®ÝJº&D¤¢Øûŵ©b÷6ï½½xÞ•ÉÉ"0ߪUÁ™û÷‹@ÔÏ?¦l×C¤ÆÌŒý’P§ðŸÿ”t-òïÔ)‘ºéßÔ§Ÿ›7 Ä5[µjI׆ˆTÛ_öÍ›7/®M«€€€·vßèíÅó–èíLJwDo‘ƒEн{E2?^¿š6-ö‹Zj*p挨ïÓ§"P­šHôâ…ÈG­š èÉ‘bãæMñùöm‘«Z•‘P·.`g§Û (A \]EŽfooíÇíÎQ'¨T ¨YS¤Ù8}Z<±°<ÀÖ¶À‡$OEZ‹»wèhq̼½ t§Nzð@ôâD/Žzõ€råÄç” (({àÉwÞTCm[•B\¿.ŽùÝ»âûsq6E]]³—¿{WŒù ­^iiÀÙ9×--&M²ç'%‰ùÏž‰ÏgÏjÖÉÙYÔA—ÔTq|T’66-…ó*¿ç„…‹÷ ŠëóØ1qLììÄ1oÛÖðà=>Ìþ\§Žf* I‚ƒEÚ/@ÔÁË °²R_.9Y\§ÁÁbðT##‘½C |yýõxøPÔEUõêú…†¼GT\œØ_IÊ>>9Ï;++q¼ô}wÏŸ‹k%8Xœëõëžž"7^¶ Uª5jˆ÷¡¡"mÍë×â_T=ÒÒÄ=âÖ-ñý9;‹ó´fͼ•‰û}÷®8jÔZ·9úó"#C¤¹xQôÖ©SGÜïê××\63S\Ûrz-77 råìù¯^‰ý§|ï×F¡.\?ññâžÒ®X>8xùRÿ:RR€“'Å}B¡ÜÝE ±ŠE**y°eww‘·ÞÇ--MlO¾·Y[‹{ z¼øù‰û|:ù»×¬['^?ûLû|ù:Ä:USæ¼·â|µ°Ð¾®üþ‘Ó›t܈ŠC\\œT”?GŽ‘ââ⤷•¿¿IW(ßxÞ½ýäëüøñãRTT”ôàÁ)::Ú ??–¢¢¢¤)""BŠˆˆPþÞ/©Ÿ;wJÊŸ#GŽH%ümBjª$5m*I HRJJþËïÝ+I€$mßnøºå$I‰í¹¹I’¯¯$Õ«'>ûúŠWÕ¿A IêÞ]LÏígêTýÛ~üX’FŒÈ^¾E I²¶ïûô‘¤û÷Õ—ŽÎžHÒüù’´lYöçzõ$É”]hÄ IDATÉI¼oÚT’.]2üñ’ŸŸØ ¶ÙªUv=>ýTì[N ÙõSÝÙÚµêóÊ•“¤gÏ ³mUIÒ°aÙeZµ’$W×ìÏ]ºH’½½$Éÿ>{&ê"ÏŸ=[}}ý¥^ï.]Ôç/_ž·óÅËK’ÒÓu×{ÇÍ2®®ú÷UU~Ï7I’¤ädq]Èe~ú)ûXµl™=¯GIzú4ïuÉMf¦¨Ÿê¾Ž©¹ÜÇšÇdãFõeÖ¯Wÿþš5Ë>\]%éÔ)ÝõHM•$Ímüõ—î2†¼GÆ×_ç­~~ÚËge‰{±‹KöýQ¾7–+'Ž«®óuâDõmüú«$ÅÇ‹kGž&Ÿ{óæ‰cfHHR¯^Ùu•¿oy{;wŠ÷‡i–MK“¤ $ÉÁA,ãá‘ý;B¾þuý^“ù•+’Ô»wö~ªnúôì{‹ìÌõ㕳^Ó¦©Ï_¾\ûöãâ$iüøìíªÖûÇ%é›o²?W®,îɪîß—¤ŽÅ|Iª];{ÙÇÕ}f¸ã¶k—úþõë'î›6e¯O>_ú÷çRn<ËO˜ }¾B!Iݺeo³Q#õù¡¡š×Ê‹Úו߿#ÞäãFosçÎI …BR(RVV–”••%eff*ÿßLOO—ÒÓÓ¥´´4)--MJMM•RSS¥×¯_K¯_¿–RRR¤””)99YJNN–’’’¤ÄÄD)11QJHH”Ÿããã•ÿ¿fddH;wî”vîÜ©÷ÿ_žKDDDDô¦:yR´Tœ{V|_3gŠÞ&±±Ùƒ£V¬(Zmkke=zˆõ…†jŸ?v¬(ïï/>­y¾„†ŠõëëÝòÑGbåå›6Õ½lN9ßÑôÚ51À* ¾³‘#EKàsçÄ5ãï/~ÆËnÍ[X&&â<0@ôè¸{W¤åÊÉÅE´†]¶L|þë/àÓOÕ—qs–/ç^j* ZQ¿x|ø¡8®ª=TYXˆeåc._óúêQX Šm„†ŠÁq=<4ëðø1Цöò?þôêŒ%–»w/»çÉüùÀ˜1À·ßŠbN ˆm<(>ß¹ôé#ê´q£¸¶ž<fÏ÷\¹¥º!„†ï½'Îñk×Dëé‹Å9»w/ðÛo@ß¾ÚËJ’¸|ó¸É=®^uÞ»W 8-º³¯] ØØ¾~ªîÜÏiÓ4S¾T«&þA>tH3U‡……ø§_Wª$>çUF†xèQ¶,pà€z* ‘îdçN,˜0A³åcag§Þ5åJàË/³?›šŠ@æš5"½ÃW_‰ ¡rkß½+}sçÓ§«§07i6lÁî©S-[Ô»ÿ—//´––ÀO?‰ódüx±žÝ»‰AƒÄ~© ±íÌLñ]ÛÙ‰€NÎTENNÀ÷ß‹€ÿ‘#êóʗן&G_ZccQVð”/Ÿ¿óEfd¤þÝ[[ç­\aÎ7@”“SàLš$Öeb’]§æÍÅ÷6u*0o^vʕ²±a¶mߣ¹¹˜¾u«.÷è!®S{ûì4GÍ›k¦»hÙR{º"{{q®ýú«tV«¦½eʈ@÷£œ {03³ìtR––â5¯u8{V|ÏëÖiŽåP±¢x8U¹²ü·m t릾Œ©©ØvR’øüóÏ"õѹsâ|“ýç?"°™—ôYy‘–&ÎE''qN«^ã¶¶@Ïžâ»PM¹¢jÏ`Ñ"qýwì¨>¯LQ¾Z5q>­Y#î]Ú89‰u©^keËŠòUªÍš‰‡=_=¿reõô;ªä㩚†+§ßå;wăq™½½›˜ˆëû §@Ä=âÛoÅ6¶lQ¿þ]\ĺÅ}ÓÚZó<2ÄqsrÊNÃvâ„øÙ¶M .Ÿýû«Ö%:Z¤ó\߆:ßÑ Tê«’zDG¾¾ªä œÜ"õÕ+ñÝL˜üý·˜&I¢—PãÆÚs~«JH-p=AgùáÈ«W†­wi¦Pˆ-[Ÿ|¢{¹nÝÄàI“D@]ŸfÍDpS5¨/3d°ñÔ)`ß>ñ€N×5Þ¼90l˜æôôtq ´k|ðîmxy‰ò&dç«ÏéÇu_kM›Š”ß|“ýࣰbcÅýtÆ õ ¾ªÏ?÷GmüýŃÕ3´?P75ëׯÇMV®œP÷ï¯y~äå|Ù¾]ô`=:÷e « G¼‰Ç¨±Å>Ñ›F’DëW{{‘Þ"¿.^-ŠW¬(º%U9:Šàà¼yÙ-íÜÜÄ?â-[ŠÖº‚$…!œëÕÓ¿œ\§³gEk»œ|}õ·Ú®UK¼^º¤=Uûö‰ïwÎýËÉüÞ¼)RÀäda!ÒyXZŠ@: z,Y¢»õda·}õªxuw×_¾MÝéIJ#Co€îàqµ½“ÏáÀ@D¾p!;mˆ âACl¬8ÇsöâÅʼnsgÅ ±UºZnÿ›=~,zM͘‘ÝKB‘BæàA‘¶¥n]ÝËl¸žú\¼(^u º-kÚT3íÍãÇâA¨µµz/(mäM!!âAANúŽ ʬZ%2yzê_6/ä`7Ö½L¹râ¾¶gæ¼à`ñª-%L¾s2äq“uì(~¿ÄË—"T¯^ùKWVPý;âM;nDÅŒ-ö‰ˆˆˆˆÞ4W¯Š®úS§f§îÈß~Á]AÅ¢P¯žH=*ZÜ'¦Ï+ºÀÏ«?ýAAȹvµuÍW%?ÜÓŒää訿¼¥¥Ô„„ä¯~ºH’Èókb"‚«ú~¬­E0O_ õ–ù66Ú[ƒjÛrKJ}uzê|+ "8vò¤ø,·Òÿê+àÊñðFj6j¤Y>* èÔIôÒèÝ[øÏœé©öï||Še7J9—wn÷ »WKÎVÊ%Eîy‘Û5®í÷“œÎD¡Èýãì,î1ºÆÄÈíZ“·£¹¼zò$oÛurÒ>=2R¼êëegk«ýA²!›!ìÙ#îacÇ_+õ‚üñ¦7¢bÆûDDDDDošÕ«Å?þæ¿lPH“2wnñ¥@‘}42yv«W:tÓÒÒÄ@œˆ¦§N5ÜvÅkLŒþž r°FΓSÎNsŠ‹-ûôɵ12­9³µ¥ËÉ«ÌLà‡€Y³Ä±µ±i ÒÓEkK9½!·-·š|öLä¹þ·0ÔùVR|}Åà¡÷Ÿ|"û+WŠ šÌÔÖ*vÔ(1`î¹sÚÇH¨VM´´¥lòxò}ÂÂÔË”4ù\òDä@¶ªJ•D ww`ýúÂÕ#&Fÿ=æÑ#ñš—‡'yáæ&^sõæMíÓåÞ<úŽÛóçÚ96äq+¬¤$‘[ß×Wô&)ý;âM:nD%€-ö‰ˆˆˆˆÞ$wîü‘=pa~­['^õåt6´ tõ,,DÏy Z…B÷zäìóJn%,·BÖåÌñšsP=Ùßê.ú´xÕ×u?¿>þˆÏ®[Addˆ€þ¬Y"`;w®Hû±x1°|¹È=ýúµá·-§Ið÷Ï}YmA,¹õgV–ö2¹å—å÷|),Co%EÎ˾p¡xíÓG¤éØQÜ7Ž×> gT”ÈëþñǺ>6to]Šû;/ {{1ŽÁþýú{o$$ˆe:u*þui×N¼ê»G¤¥e÷üPU¶¬hi½u+Q¸zœ:¥{^F†Ø~Ó¦š){ä{Œ®ß7Úë€Hsäá!z¤è*ûàîzɽ]üüt×ûÂíÓ yÜ ëàAÑCmÂõÓscl¬ÿ^ {^AÿŽx“ŽQ ``ŸˆˆˆˆèMòçŸâõ³Ïò_öþ}1hîäÉ¢mqùé'Ñú[×À™QQ"Ò²¥öârϹ¥sN …h!™3àëé)‚”ãÆi\n݃RNœ´m«}™øxל÷àh8t¨aµ:‰z}ù¥hA­Ë;¢å}Ζ±éé"ú?ˆ&gÌcc±¯¿ü"Æi;6;%ˆ¡¶]·®HÉ2mpã†ö²’$‚nõê‰sCUÅŠ"èyò¤fðìÕ+`üxÝu€ ÄÀÐúÆ„…e`(†:ßJŠü@F¾Ç´j% Ÿ|"‚x»w=zVVêåÊ”¯Ú"ounßYaôQÒfÍ×äœ9ÚƒÉii✠×ñ›20§——¨óŒ¢XN …èY¦ë!ׄ "'ú¸qº/(â¡éÂ…ºí“'‹q´•]»Vv!!"à¶r¥8^Íš‰@¹½½˜ÿø±Øÿ°0Ñ ;4T¤)ÓUfÛ²ÆÅ1›6Mà Qþþ}àüy<™6MûÿüG¤’™šŠ:¬['ÒÕ”)DG‹t0£F—/‹óÇÌLÌ«YS=pgb"Ö±d‰È±]¦Œh *ýœ31BÔKny, 9œýýŲ/Šs,>^´ •§]¾,RÓäÌ!^Ðó->^ p[[q TÓõœ>-ÆÖ ûäà`ØTG¶¶â¾çΉclc#¾yzD„8WsŽQ˜{Da:$~.^û Q!×ùâEt¬][30ok+zJÌ™>,ö##CúH»lnÛ P_Lõô¤ùN¢º§¦jï/±±tN5ÄÓ“Î_ßOxŒakKƒq[ZÒ‡/_Ò:çϧe::R»WªDéž4ÇpÈËßE¡ÝX‰õôéS8;;çë:ÌÞœ„‡Ë›»·ß øì’ÕÝ\±±±"?žžž"66V”TÞÞÞ…]ÆŒÆû-c%ŸtœŸ>}Z„‡‡‹G‰ÈÈH“>"""Dxx¸ ¡¡¡"44TþÝ/¬Çþýû…R©”žžžB©Tò·Á˜–-ÂÏÏø²ááBØÚ 1q¢éë•%K„X¹Rˆ¡C©þ™sç œõ2^¾¤ù2—­UKˆ9s„¸}[•JÙŒ !¢Aí²NNBìØ!DZšþr4ߺuBܼ)DÿþÚåmm…X½Zˆ¤¤<5O–ÒÓ…8xP·î€}û ñûïBÄÇk—Ù±Cõ|BìÚ¥ž~âm»ævüô“iÖ­)5UˆíÛ…¨VM·ü!Büû¯†ÎÁÉÉB|ýµn{O™"DPú³¶mé}fJ¥¿þª»n[[!ÆŽâÔ)ýßûÁƒúë›ùáà@í¬Onö7!Z·ÖžÊZ–´Ì©Sµ§/_n¸ísküxZöÑ£ÚŸNŸŸ;§¿\jª?ü ½ßÔ¿ü"ÄåËÚípü¸ºl\œî±eèñöÛBÄÄè¯C^ι•’"ćf_ï¾}i; yúTˆI“tË}ðé/óè‘íÚe½^[[!Ö®5í6kJKbóf!µ×Û³§ÞÞô=KŸ5m*Ä­[Ú儸î;!Ê—×­ûøñBxzjŸ#2ŸÛ¢¢„ضMˆzõ´Ëvê$ÄÕ«Y×="‚ÚW³\µjt\]¼¨}®ÒwŽ?sFWWíòƒ q÷®_~©®Ÿ¡vûõWÝíž1ƒöï:u„èÞÝpÝm7!„P(„6,û}õÃi¿ÖG©ÂÃŽë„„¬Û×?ÿÔÝ_úõâüy!¦O׎Â4GV»±íÒ¥KB¥R •J%222DFF†HOO—ÿßLKKiii"55U¤¦¦Š””‘’’"’““Err²P(B¡Pˆ¤¤$‘””$EBB‚HHHñññ">>^~'ÿÿªT*ÅþýûÅþýû³üÿ×,66VäçU´kײU¼˜ºzõ*Ú›2×&c€÷[ÆJ>é8?sæ 7nŒ””ØÚÚštB! P(`õfpÆ€€´k×Τë1Æ™3g0P£çÖÙ³gááá!ßQÀX‘M½  oÆZ³†zÞ¸A=- ËóçÔsóÕ+ê™X£FÖföìõMK£^}µjékˆJE½ûž>¥T-ÎÎYç~ð€zÙ®[G©D„ ë11Ô#×ÅE= h~“z»¿|I½E«V¥m(ëV*é;‹ŒT§ÉÉi»EDP/mêÁ™9 Lvâã©üë×´nggÓÞY‘c÷·’àõkêI’BßWÕªúÓkå§¼œ# [BõOO§ó‹1çÆÂ”–Fß{L õ––îšÈ©„:Ç$&Ò±^£†qçV…B]¾N:Þr’¶(#ƒî‰‰¡uÖ¨aÜ1ššJw(´ÝµkÓz§O§;ä^¼Pß)¥Ïë×t'@çGG:o8:ÒVÇŽe½þ¼¶›±ÎŸ§»œ6oÆÏýrbci»K—¦63¶Îyý;¢ Û•h—/_FÇŽÐÿ¿Ò³ækcŸ3&õØW©Tðöö†‡‡àÈ‘#€žY¤Å*áu0ÆcŒ1VLÄÄPPuƌܕòøäõà}…¥rå¼¥ªZUOÛXææ<Éí-Óff$44@h~²´Ô²¸¬Û‚‚mšierJ ¶åV¹r@³f¹/ŸyÝߊ£ ŒOÏajy9G6;;«¡¸±´¤G¹Msdg—·ß&[Ûܵ[©Rt¢^½Ü­×ÊJ÷ü’žNi”Ú¶Í:¨Ðñ’ùBûÓ§t5'íòÚnÆŠŠ¢ ƒçm9öö”®-·òúwDA·c…ˆûŒ1ÆcŒÍšQÏÂÜöø]¿žž‹Êà‹Œ1ÆXI’žüöåÛ?tÈøòññÀªU”[~Ø0Ó×/¯FŒ† )ùw1V‚ðÑÊcŒ1ÆXQ‘—¦yèœKJ~ø¸s‡ÞïßOiyÌÍÿû? {÷B­cŒ±Böø1°q#¥s(Ñõëô»ñý÷”6/+^^4 vF½§Ï$ÛÔƒ<› õ+VøˆeŒ1ÆcŒý·ddP`• :”>{ù’ûR‡1ÆØWj*åxOH ÷ÖÖÀG]»æl›¤$ÊÁ¯RÑ{`áBàÝwÿ[é»cùŠû…äáÇ ­­-\]]Q±bÅY¯AAA ƒJ¥BõêÕáêêŠR¥Jå¨|FFîܹƒèèh888 yóæò€‰9‘˜˜ÄÇÇÃÉÉ ®®®ò %66[¶l··7bcc¡zóC»nÝ:´ÌA¾ÈsçÎaß¾} AJJ  eË–X·n]¾Õ¹(´[a˜>}:|}}áî¾úª°«ÃcŒ±’¢\9J‡ÀcŒéãêJƒÈæVŸ>ô`Œ±|ÄýæííÉ“'ÃÏÏOþÌÒÒ#FŒÀúõëQ¾|ù|[÷æÍ›±téR„††j}^©R%|þùç˜={6JgqÛÕÖ­[±`ÁDEEÉŸÙÛÛcÖ¬Y˜3g̳¸ý;55óæÍÃÆ‘””$^·n]¬]»ýúõ3X6&&W®\‘~~~P*•°¶¶Æëׯs²é²gÏž¡]»v Ó™–“e}ûí·˜?¾QëÌ‹¼´[Iàëë ///T-®ƒc1ÆcŒ1ÆcŒ1–8°_€.\¸€ž={B©TÂÊÊ nnnˆE@@vìØ???\¾|¶¶¶&_÷Ì™3±fÍ@Ù²eѬY3XZZÂßß/^¼ÀüùóqãÆ 20ÌŠ+ðå—_ФIø@où¶mÛê\ŒÈ­%K– ,, Xµjš5k @½zõ²,…E‹†ŠI“&ÉwZ”-[Ö$õÓ”×vcŒ1ÆcŒ1ÆcŒ•L<ÂVIKKÇ~¥R‰ºuë"00—/_Æýû÷±{÷n˜››Ã×× .4ùºoÞ¼)õ»té‚ÇãÊ•+8þ<ÂÂÂ0räHÀáÇqðàAòwïÞ•{©÷ïßaaaðòòBhh(¦M›øí·ßpôèQ½ë߸q£œ^¶l‚ƒƒqᄆ†¢S§N€‰'"::Úà6XZZ¢}ûö˜1cºuë–Ë–NŸ> ˜6mƇ6mÚ eË–hÙ²e¶ÁùsçÎ!==666رcÜÝÝå²Ù]È S´cŒ1ÆcŒ1Æc¬äáÀ~ùý÷ßñôéSÀ¦M›P»vmyÚˆ#0nÜ8À† kÒu8p@~½qãF8::ÊïË”)ƒ 6 L™2 ·ÇþÊ•+¡R©P¾|ylÛ¶M¾£ téÒX³f 5j€ÒÔd&„ÀŠ+ÐE…yóæÉ¹áííí±k×.XXX@¡PÌQäÈÄÇÇÃÛÛ[k}¹!¥ª[·n®ËÖ¨QÖÖÖ¹®CN˜¢ÝcŒ1ÆcŒ1Æc%§â) RÀÜÅÅîîî:Ó'NœˆÍ›7C¡Pàĉr/z¸~ý:222P¹reƒi!®]»!ªT©‚:uêÈÓ"##¶¶¶hܸ±NY;;;4hзoßFDD„Ö´ôôt¹'þû￯3ÈoéÒ¥1nÜ8Ìž=W¯^EDDjÔ¨!O¿q㆜Ï~„ :ë®]»6zõê…ãÇãàÁƒX¾|¹Î<9ÐÖ{÷î!AÅtç„„„àêÕ«Z󺺺¢\¹ròû¸¸8ÈƒJ¥R§l¹råàêêj°¯_¿Æ©S§…B'''ôîÝõë××;¿)ÚÍ¢¢¢ 4lØPï<¾¾¾r*T¨ .„€ aư··Ç£GðÏ?ÿ ** ŽŽŽèß¿¿Á6ȉW¯^!((àää'''yšôÝW«V µjÕ«W¯pèÐ!ÃÚÚ=zô@—.]²]‡B¡À©S§àïïÄÄDT©R]»vÅ[o½¥3ïµk× R©Ð Aƒˆ„W¯^iߦª;cŒ1ÆcŒ1Æ+™8°_„¸páL#ãææ†2eÊ )) çÏŸ× ì?~_ý5ìììàëë ò­rs IDAT«W¯Æœ9s`mm­t–íiiiP*•rNyM‰‰‰ZóJ|}}—eÝ»ví*¿öòòÒª»———ü:«òÇÇÇu. äÕøñãåದ… ê¤=:wîºwï.¿÷ööƻᆱS644:tÐú¬[·n8þ¼Þ:¬^½ß|óÜÆ333Œ7?ÿü3¬¬¬´¦v»IÖ¯_•+W¢E‹r?³V­ZþüóO >\þ<55Un§Ã‡ÃÇÇ+W®„BžgîܹøñÇññÇ]·ððp¸»»ãáÇpssÃÉ“'µ¦KßýgŸ}†.]º`̘1Z/Z´£GƶmÛ ü|ôèQLœ8Ïž=Ó™Ö­[7üñÇZí>vìXÜ¿+V¬Àœ9sr´C‡…ŸŸ–,Y‚ ˜¬îŒ1ÆcŒ1Æc¬äâÀ~ˆˆˆƒºúzÌ€¹¹96lˆ[·n!00PkÚÂ… qáÂüûï¿1b.]º¤œ¿~ýº\¿~=Z´h¡U~РAX±bÒÓÓqâÄ ôïß_kúýû÷åÞè К¦YCu×쩞¹îÒ{[[[Ô¬Y3Ûò<0i€zðàÁZ=þ7oÞŒŒŒ ôìÙSçî‡êÕ«k½¯Y³&&Mš$¿÷õõ…*T¨€aÆiÍÛ A½ëŸ®]»–£íP(¸wï sçÎ&«;cŒ1ÆcŒ1Æ+Ù8°_¤Üú€vðøîÝ»¨R¥ *W® ¨V­È)X$æææøã?вeK\»v óçÏǪU« 1b”J%†މ'ꬿM›6˜5kV­Z…ñãÇcõêÕððð€……|||0sæLdddàý÷ßÇ!C²­»R©„¿¿?7n ØÙÙ¡lÙ²HLLÔ©»T^s»ãââ‚-ZÀÌÌLÞn}ÛžW³gÏÖz¿}ûvddd`üøñZ½Ëõquu•ƒò°bÅ øøø J•*ZŸ²ÿ~y¾åË—cîܹZÓÇŽ‹^½záСC8rä(O+ìv35OOOìÝ»C‡•?ûôÓOáææ¥R‰;wâ›o¾ÉѲ‚‚‚àááððpxxx௿þ’LjÐçܹsøä“OðÓO?Éã,^¼nnnÆ–-[t‚ã*• “&MBzz:š4i‚Ë—/£|ùòòôQ£Fáí·ßÆ£G°lÙ29RçÎñÛo¿é½KDŸ›7o"==h×®IêÎcŒ1ÆcŒ1ÆJ>ÎáP4S°H={/^ŒfÍšÁÅÅENq"MËœ²ªV­ŠÝ»wÃÜÜß}÷NŸ> €z„?~üõë×ǦM› Öaåʕؽ{7œ1vìXÔ¬YÕªUÃÀ¡R©°~ýzìÛ·OfU÷·ß~nnnhÕª•œD ¬f®»ô^*† ¢U«V5j”Ö4CÛ^\Iê=zèõÀÃÃï¿ÿ>êÑ®©¤µ[¯^½´‚úЫW/t×INÜ»wݺuCxx8Þ{ï=;v,Ë >”/_«W¯ÖÚ·+T¨ ]póæM­ô@pöìYù.–ï¾ûN+¨Ðw*¥œÚºu+222P}€îÒѯ"##¯_¿Öï€| uëÖ°±±1IÝcŒ•pþ ,] äæüÿü9ð¿ÿoîcŒ1ÆcŒ_Ø/)))òkKKKÔ› €ì±cÇ´¦%''ë]Ž»»;,X!Fï¾ûüñ¬¬¬°oß>ØÙÙ¬CBB®_¿Žððpi111¸}û¶<ÈnVuñâ…œKþÁƒòE Cu—ÊKÓ/^¼ˆèèhÀ¾}û „§eµíÅÍãÇq÷î]”/ÝÞ½{._¾¬ -iíöÎ;ïèý\Ja$m[Vnß¾îÝ»ãÙ³g2d:¤36>]»v…­­­Áu+ €»4ÆAÙ²eѳgO½Ë4h:~¤ÔIuëÖ•ï¤Ð쵿ÿ~ØÛÛ£FP*•òçÒ<†ÂÍMÝcŒ•`QQ˜ôÈÔ#G¶n¶lÒÒLW§¤$àÁz¼¹(þŸ¡RÑw!mjja׈1ÆcŒý‡p`¿hÓÞü#5bÄÔûVÊy/MÓ×sW²hÑ"ôèÑÏž=ìY³k×®ÕÊ#ŸÙË—/ѹsg¬]»vvv8tèž={†—/_âÔ©S¨W¯¶oߎ¶mÛ" ˺WªTIt6kÖL8ÕPÝ¥òÒô.]ºÈ¹àG 333yZvÛ^œÜºuK~ŠíÛ·ë}  /¯_¿–Ë”´vsrrÒûyÅŠda" îîîxñâ:~ô ›uë[¿ô½4lØ¥KëÏX–yŒ‰Ôk_3°/ 움˗/ËŸKóè˯ŸÛº3Æ+Áöí àÍ[FyþX½<ÈâïF£¨TÀ€@£Fô˜6Í4Ë-.6lê×WoLLa׈1ÆcŒý‡pŽý ™*DJ]3þ|Œ5 ööörO{…B¡3fæææøí·ßP¿~}!жm[Lž<9Ëõ/\¸wîÜ Îœ9ƒ:uêÈÓzõê///4lØQQQøä“OpîÜ9ƒu/_¾}úhõ%åÊ•ÃØ±c±|ùrœ?111pttÔ[÷êÕ«ÃÜÜõêÕ“?OJJ’Ód®»ô^s»mmmåàtæiÙm{qan®¾æûï¿×»@Í@ñµÝ²2þ|L›6 Í›7Gtt4>üðCœ={V«­M¥T©Rh]C4§IóêÞ÷7nÜ@FF‰™3gbÇŽðôô”b€F¡R¥J&߯c%ÌáÔŠç³Ï( nŒøxê­ß³'`à.±\«^ÿEeÊ;gÎvMcŒ1ÆØö @Íš5accƒääd9wfB­ô†H)\,--ñÞ{ïáСC5jnß¾­7¸ûúõk¹÷¸fP83Í@}pp°Ø×¬K`` ÜÜÜtÊj¦ïÉ\wé}bb""""ôö°Îª|q%µ@©sŒ*_TÚMº a¨W¸æ ù©OŸ>Xºt):úôéƒóçÏcÙ²eX¸p¡É×']dyþü¹Áy4§i^”iÙ²%Ê”)ƒ¤¤$Ü»wOèºOŸ>xñâ–/_ŽgÏže›†‡1Æ“%%Q`¾sg {wãËÿý7üø#` ÅcŒ1Æc¬xáûÀÌÌLNµqñâE½óøùù!>> ˜©ÏÝ»w1eÊÀŠ+°gÏ´iÓ/^¼À°aÞž®SF3?xLy?5§i¦ÿhݺµœæÅPÝ/]º$¿Î\wÍAA³+_«V-»Š«¶mÛʯ¯\¹btù¢ÒnÒÀ­†ÜOž<É—õf¦90ô;#iorø.^¼X+g½©4iÒåÚ—Ò!evûömù:æÚµk€rèŸ}úèLOJJÂ!C P(ЧOLŸ>سgÊ•+‡+W®`Þ¼y:åÊ–-+÷ä?wîRRRôÖïÔ©S Ô¯__þÜÒÒï¾û.àÀrʉJ¥ÂöíÛ-Z´@íÚµµ¦·oßUªTlÕ“{422žžžÔmTT¯^]Ø®Zµ*Ë”.€nø¢ÒnÎÎ΀èèh­Ô?’;wæÛº³²råJ4oÞ9r$bccMºü·ß~ ^,¥²Êl×®]€ºuëêÜ #õÂ?þ<.^¼(ÓíÛ·‡ƒƒŽ?Ž7nhÍËcŒé•š ¬Y4oôîm|ù“';w袀••éë—ÙÕ«tgAÿþÀÏ?Ó€¿ÍšQ \OG<|HÛ×µ«ú‘œ \¹¸»½zsæÿ÷@·nÀ›»\eB^^tá¢Gº˜pî0~<åÀ=ˆŒ4\çëש~Mš#FÛ·Óò¾øpq¡í0fL›§O¦Mµ·§W/ø˜1ÆcŒ1áÀ~;v¬œžeâĉZ=äOœ87ȩ̂iÒ¤I DµjÕ°}ûv9EŠ‹‹ 6mÚøî»ïpôèQ²£G„……aÒ¤IZ=U*¾ýö[yÀÜjõŽ€Ù³g ´+ü1”ozP !°hÑ"øùùæÎ«³îR¥JaæÌ™€Ó§Oã矖§) |ôÑGHMM…¥¥%f̘¡·íbbb(?¤M…ZŸ?.b=¡–.] sss\ºt #GŽÔ›¶&003gÎÔI'cŠv3éN•J…/¿üò´³gÏbóæÍù¶î¬XYYa÷îݰ±±AXX&L˜`Òå·iÓíÛ·@û¿4x¯äûï¿—/†M:U§¼¬ß·oRRRäÀ¾¹¹9Þyç>| ¨V­Z–)²cŒ1œ= \»ÌšØØWV©Ö®5¢AwóÛ±c€‡Юðèðä àë DG }DA÷Ì4ž?§^í#FÐg¿þ têÔ¬I=éãã©ll€»wµË:D)ŠúöÂÂèqñ"]¹r…îÛ×pïûÊ•iÓoo .ŽzÛ{yQ€þ—_€O?NœÈy;T¨ŒK¯/¦¶ðõÞÜ ÉcŒ1Ƙ)p`¿€ØÚÚbÛ¶m077ǽ{÷P¯^=¼÷Þ{èØ±#úôé¥R‰úõëcÅŠ:e7mÚ„?þøæææØµk*W®¬5}ذaøßÿþ!ÆŒƒÐÐP­é_~ù¥œçΨS§Þ}÷] 0...˜?> `ݺu:ëoÓ¦ æÌ™ؽ{7êÖ­‹¢qãÆrÞó!C†`øðáz·ý³Ï>“Ÿ~ú)Z¶l‰þýû£N:rþñµk×L'óí·ß¢qãÆòcïÞ½¨7µæçzË–®]»bݺu033ÃÞ½{áìì |ðÁ0`êÖ­‹ÆcÍš5HLLÔ)Ÿ×v3…úõëË3ïØ±uëÖÅ€о}{ôêÕ ÿûßÿòmÝÙiÒ¤ V¯^ 8xð |qÌT6oÞ {{{¼xñnnnèÙ³'FŒ&Mšà‹/¾¸»»ãÓO?Õ)Û¾}{”*U ééé°±±A=äi}ûö•/Žqo}ÆcYÊÈÖ¯êÔ¡ðÆòò.\ ‹oR+æ»#(Nݺ@©R€™àèÌœIŸý5Õ+³J•¨w|… ô~î\º°};и1-«Màòe`ð`u¹À@`Ò$`éR`áBÀÙ™Ö ––@‡t§@™2Ôë_ßµk“'íÛåÊ©?·±>ü^ç4°ÿì•Ù¶ ع“êT·®örcŒ1Æ3ì >}úàØ±c¨]»6pìØ1x{{ÃÌÌ ýúõÃÅ‹QAúgæ ???|öÙg¨G¼»»»ÞeÿðÃhÒ¤ bcc1lØ09pP:žóçÏã³Ï>C™2eðüùsxzzâï¿ÿFhh(,,,0jÔ(\¿~Õ«W×»üåË—cÕªU(W®ž>}Š¿þú <€µµ5fΜ)§%ÑÇÂÂÇÇG}„Ò¥KÃÏÏGELL ±}ûv|òÉ'Æ6g±0uêTœ:u mÚ´Arr2þý÷_ìÞ½ÿý7‚ƒƒQ©R%Œ;|ðNÙ¢Òn;vì{¯‡††âï¿ÿÆíÛ·ñùçŸcÍš5ù¾þ¬L™2ï½÷àóÏ?ǽ{÷L¶ì&MšàâÅ‹èÒ¥ ÒÓÓqöìYìÙ³÷ï߇••¦M›†þù¥J•Ò)kgg‡æÍ›zôèkkkyÚ;ï¼#—áÀ>cŒ±,]ºœ:Ìžm|`X¥~ø¨V 4(ê§Ï¬Y€¹1FêÕ~û-ûå¬]K½Ý5~C¨ƒö’Í›—/qãt§I¨×ýþý”*(+ÉÉ@h(Ýmðê•zýYŒU%»s‡î ¸u‹rýe¸NŒ1ÆcŒå‘Yll¬ #çããƒvíÚé¬KŠ«W¯ÊAÏœR©T¸~ý:BCCaccƒ-ZØ ±ÉÉɸuëÂÃÃ!„@•*Uàææ†r9üg199ÞÞÞˆŽŽ†ƒƒÚ¶mkÔw›7o">>5jÔ@ûöíaaì pÅÔÓ§OáïïØØXØÚÚÂÅÅM›6ÕÎÌÔífì~+„À­[·ððáC”+Wmڴѹs¤$ Á;w””GGG´oßeË–-ìj1–%é8?sæ 7nŒ””y@lSB@…B«7¹»ä¤ Ù3g´Æ9{ö,<<<´“g¬X>œRñRvcx{;Rÿ7ƒÎç+33  ?{du¼Oƒà>{¦´€O>¡4¥Ú:4ëù^¼ Àþ/¿Pï|M©©ÔοüBé„4uè@m9t(ðæ®Qß|,Z¤~¿u«:cŒ1Æ+¶._¾ŒŽ;P)ýœù³œ>gþLJ·®R©àíí-g$9rä gÏžëÇÿåsss´k×®P666rÞôÜ–7t×@NT©REïàÀÿÎÎÎò`´Æ*ìv333ƒ›››œÒ鿦N:¨S§NaWƒ1ÆØÉÍ›4ðìªUÆõ Ž—/Ÿ}ÀÛ”4È:¨5jPÐþÅ ÀÉ)oëHJ¢4=Ù Lkk ŒCm¢)9˜:ز˜2…‚ÿ€…˜H½÷½½sVŸ> ±>ý”ReñOcŒ1ÆcyÅ}ÆcŒ1ÆŠšM›(- &k ??à÷ß)ï|Õª¦¯›!ÞÞ`Ïêî À@ ®W¬˜÷õ™™Ñ`½G?þØÙ¿Œ (¨î À›Yz:ðñÇ9[Ö²e”ËÌ W/ÀÓèÝÛø:1ÆcŒ1–œcŸ1ÆcŒ±¢$ €òÐñEîzµoÝJÏzÆðÉw>>†§…‡Ó˜Ÿ|’uðß#GÒ.ä®üž=Ð×Ô€´´œ/ËÜœî®øýwìøwè¢cŒ1Æcù€ûŒ1ÆcŒ%Û¶Ñó¨QÆ—}øÍ5 ¨]Û¤ÕÊ‘/¿¤üù™)tAµjÀ矛n}ï¼ÌœIit<0<_@°b¦ýy”ŽG¥Ò-óòeîÆ'¨Xرxÿ} ð>lü2cŒ1ÆË§âaŒ1Æc¬¨ V¯¦€rýúÆ—ÿýwz.¨Á[½¼__õ{  Kàë¯WW ÷Ñ#ºØHÐV®¬½ŒÛ·Õ=îïÜ¡ç_~llÔóT¬ ¢;à®™°p! ´nMëíØ¨R…räGFÒ]ë×S}úõÓ.?i]Xº4([ˆnÜ ñ ¤ÜýAA´ŒÎiÌ¡àøqý9ø+T ÀþÁƒÀàÁ4¸n:Àÿý¥ëaŒ1Æc,8°ÏcŒ1ÆXQñÇô<~¼ñe#"€5k€‰ÆM[/}T* \ÿø#½ïÛص X»–ê 9 í¨Q”"ÈÙYw9§Osæhöå—Úï;u¢ úîB(WŽîr8ÊÍž­=½o_ºà1`€nþÞ½þ, à»¤|yº àÿ\\èâÅôéÀòåêÀþíÛ”W?*J·NJ%pæŒúýâÅ@Û¶tÑ!7lcŒ1ÆË„ûŒ1ÆcŒÑÑÔK|ôh ysãËïÙCÁô‰M_7}ÌÍ©'þ?h¾x1ÝqÔ«ØÛ^ÎìÙºÁxc•*E=ãß{Ò½|IAüªU)ýOVúöÜÝ'O€W¯€êÕil š.„þrƒÓC ”wË–\ocŒ1ÆcYáÀ>cŒ1ÆcEAL £gÌÈ]ù'Oh`ÚÖ­MZ­\qp GA³´š41¾œMÁÜåÀcŒ1Ƙ‰p`Ÿ1ÆcŒ±¢ Y3êå^:—¢¯_OÏff¦«cŒ1Æc¬HâÀ>cŒ1ÆcEEnƒú¥ÆaŒ1ÆcŒý'ð_ÿŒ1ÆcŒ1ÆcŒ1ÆX1Â}ÆcŒ1ÆcŒ1Æc¬áÀ>cŒ1ÆcŒ1ÆcŒ1VŒp`Ÿ1ÆcŒ1ÆcŒ1Æ+F8°ÏcŒ1ÆcŒ1ÆcŒ#ØgŒ1ÆcŒ1ÆcŒ1ÆŠì3ÆcŒ1ÆcŒ1ÆcÅöcŒ1ÆcŒ1ÆcŒ±b„ûŒ1ÆcŒ1ÆcŒ1ÆX1Â}ÆcŒ1ÆcŒ1Æc¬áÀ>cŒ1ÆcÅÅŸK—B_öùsàÿîÝ3}½cŒ1ÆcªtA­èêÕ«µªW’·•\¼ß2ÆcÅLTæ‡ ÌÌŒ/¿u+°e 0eŠéëÆþ;22€à`@¥¢÷µkVV…Z%VHBB€” qã®IñÂí$'aaôÚܨ_¿pëÃcÅTöÛ·o_P«*PW¯^-±ÛÆJ.Þo+ùøâc%о}€BL˜`|ÙçÏÕ«Áƒ–-M_7V, pv6}ݲ“œ X[çî"×™©ÚíêUÀÃÎI'Nï¼cšúUÜn¦5f °?½nݸy³pëÃÔró»À+4œŠ‡1ÆcŒ±¢.6X¹èÛèÐÁøò/_S§r ”©ÍŸLžl\™ €Ë—qãò§N9‘’BÁÑíÛ ¯Å‘)Ûíñc N@``Þ—W”q»™ÞO?. vMXf¹ù]`Œšë±ÏcŒ1Æ˥Ç)ÏgŸQÚcÄÇSoýž=Îó§~¬xòñBC+S¶,б#pæLþÔ)'^¿¼½îÝ ¯Å‘)ÛmèP -‚ÔcÇæ}yE·›é9:Ò£lÙ® Ë,7¿ Œ±BÃ}ÆcŒ1ÆŠ²¤$ ÌwÀÒßSNçJóŸÿŒ1°°øo¦s‹Û1Ƙ ñ_öŒ1ÆcŒeÇŽQʆÇ)(dŒädº(ж-õØÏo ”+90ˆŒ¤UÝÜ€æÍõ§R©º«ÀÜèÔ  Ξž>jÖ¤º·nýºSR(µC`  Ô¨AëïÐxñ¨WO»‰‰À;”O zÚÚª§?} n³òò%m§€‹ ÕÿÜ9Ú~!h[zõÊ•Ó-ûìµ3@Çf*2!¨ýccÕŸµmk87xaío¹m7M*}ÿtŽ”ö577ý¿ ¦<·æUh(pû6ÕÇÊJ}~Ð<ßfåñc*{÷.`oOûKëÖ@ùòÙ—Íë¹58˜¾ó'Ohqr¢²ÎÎôÛ‘ù7!¯‚ƒˆzݪý†Ÿ:Eõ··§ugõ[¢É˜vË߯XÁˆùùðôô±±±¢¤òöö.ì*0f4Þo+ù¤ãüôéÓ"<<\¯¼ÿ¾ê–1Õ¹5/”J!¶oW×µeK:Ç´Ïß¾MßiæïU’˜(Äš5Úß¿t®iْΆäõÜš–¦>Ç•/OmÞ¹3µŸô»2dHÞÚ'³¤$úý’êøÃ´ŸBtꤞ6`€Ñц—“›v3Õïc%Ð¥K—„J¥*•JdddˆŒŒ ‘žž.ÿ¿™––&ÒÒÒDjjªHMM)))"%%E$''‹ääd¡P(„B¡III"))I$&&Š„„‘ âããE||¼ü>..NþÿU©TŠýû÷‹ýû÷gùÿ/žËcŒ1ÆXQuö,pí0k`cc\Y¥X»–zuöí›?õ“:D½ûöÂÂèqñ"õh¿r…zÔöíK)45kF½ë{ô ^±Ÿ|¢OÀË‹zÕnßNoܨÝ/_Ò²ml€û÷©Wê™3ÔS1$DÝ{W³W/@ ?yBãdfaA½í?¦F†¼ÿ>õ~•Á|õ øüsàÃ?¦íxýس‡zÚJ=1óÚnyÑ¥ Õëñcê±ëäD¯3?bb€ºu³_ÞŒÀ´i4ÿõëTW//àøq„QŸR¥€6m€ƒ©‡jL õà¾wzS§¦R*•Úå¤ïÌÛ›ÞOž¬¿î/wKN¥¥}lÞLi®ââh»ýüèûÚ¹“î²t÷9€¶³ukê1@ß…õ¬>vŒö‰þý©§±¦‘#i°u+mã­[êíˆ&M¢ù®\Ñ.kªvû¿ÿ£}Tš¿mÛœµÙúõt À¢E@ÕªtÜܾM½©Ÿ<ªU£ºGG«Ë™™ûöѺ\]u—ëâB½ð?Îz0çÂÞßrÛn;w¦sÛŋԣúÊ:×ܺE=ºßz‹ö%M¦8·æÕâÅt¬¬\ <Nß÷“'t7K³f@ïÞ´ ú¤¦cÆß}GûΫW´¯<}Jç˜nÝèܹ¿þòy=·nÞLûêÏ?S[]¹BåÃÃ]»è·ùñã¼·‘&[[j èý´iÀĉt޹t‰~Û¼½é1mÝ•‘YnÛÍÔ¿ Œ±éxcŒ1Æ+Š22( V§úŒååE©i¶lÊ”1}ý$P\º˜7Oû}KKJ±c0`0g°{·vGGuJ†={€ÕÓ,,€Ñ£ß§ËäɤÓ@Á–/¿¤´šjצ@ûñã”B@“¹9¥Ï¨XQÿv•)CÃ*U²Þ~''JcÐ…3gh;†U·Å°aÚï¼·[^T­J϶¶ÔÆ..¹_ÖÒ¥T?©þff”fcêTš¶h}ÇšÌÌ(ˆ«O½zôOžL,ÍÔ4Òw&]¬©P!ouÏ-[(@ìïO))4U¨ŒEécfÏÖ-E|&L6lÐNUdgôéC)uZ´ `èÒ¥êéff”^  öüãíõW¨@YV­¢ ;ª§™ªÝÌÌ(‰$§©T,,€êÕ鵇ðÔDR«µ—‡-5ÏÖÖTWkkýËvp GViY {Ëm»)•tQ×Î8zT»Í¬¬(UËþý ž>‚Ùšçú¼ž[óâìYÚwí>ø@ýy©RÞ¸‘Ò½üñ‡þò6Ðqvó¦vº R¥è¼¾v-mÛäÉÔõê©ç1ŹõÄ zþàí~­­#è¢HNRËΨT‰^ÏœIß¿ô½˜™íÛ_|Aõ^¶L7Èž—v3åïc¬Àp}ÆcŒ1ÆŠ¢K—(·îìÙúsOgE¥¢àYµjÀ AùS?ÉæÍÔk~Ü8Ãyw€O?¥ ÔÕ«úç©U‹à™™™Q30z¿gV¿>••ògîéìáAÁÿvíŒÛ®Ü(_žûÆé¶Eæ÷¦j·Â6z´þú×®MÏ™ïRÈL¥¢vxôˆ.Ф¥Qp Ðý. Û«WÔóyÎÝ ¾¦áÃéBN³fÚŸoÛFÁãyó ?P¯õt^¶L}'HfcÇê_¿tåîÝì·¥°|ú©v€ZR­=‡†æïú‹Óþvîä—.Õßfa¿úŠÎÒ"™åöÜš[*]ÐëÐŽ}J•¢Àµ>‘‘t¡bÁÃc˜™Ñ>ÔÃsýzÃ!Sùë/ªç’%YÏ÷â=ûûSj‰Ì²h5«iUªÿüCP©Ç~½z˜éÔ‰z7j”uÝL¥wou@(;¦j·¢J ¨ ¡ú“'ÔSö§Ÿ¨'»ÄÑ‘î‚(Šîß§çV­²žÏÙØ»W÷óƒi_Ìn`_iù·oëßw Åa@KCuÌn å¼*Žû›pÎê" >ï]¼¨?žÛsknED—/ÓEé¬Riö×$¥œÊ.e‘£#¥•Ù¶‰—zÝ›âÜúÉ'T÷yó¨×¾­-ÍÓ£Õ«K—üK÷%1öXÉk»1ÆŠ%>‚cŒ1Æ+jnÞ¤ÜÒ«V©oË7Ư¿RïqC½%MEÊù\ª Pd=¯­-åþÍôM›RÐnÙ2ÊHù³—.¥ÒK–PÉÒÒôë΢Òn…åÒ%à½÷€† ):tWJZå¾þë/ù· SR=Jß”!h¿ìÕ+û¼tÌ›²õYqÝߤ12§ËLºx“¿õÉ)é8Éœ‚+³2eô_T‘îœÈÉqV¯‡¢PÐwjªs«…÷G¢ß‡éÂÞ¥K”ö­sgº+.»‹|)/íÆ+¶8°ÏcŒ1ÆXQ³iFŒ0¾¬ŸåM^ºT37¿˜™Qõ£GiY)¥EA’z„›™QN` ž4à‘#”Å‚R¨E¡Ý KL åúîߟ.@éÿ!%…öá¢FJ/”9FNHc\ºD¹Ó³êíNÏRz–{Åy«Y“ž£¢²¾óêÙ3z®S'ÿë”Ò…©ì—}õŠöõ̤qMž>ͺ¼4¸|½zês¨©Î­*õŒ·³ÜÜè! £1Dú÷§1!ŠÊyi7ÆX±Å9öcŒ1Æ+J€ß~£òr0غ•ž5,ÌO#Gqq4Poa˜>zêëceEw-Ô«Gy—U*Ýy¤ÞÓú¦êÞ§¦VØí&1´ÝùåÖ-Êï^ÿçÅysw§ç³g³žO:‡ôî¿õÉ©J•€ñãiÐòÌÇ€&CㆴnMçì#G´sÛgæïܹCåjÞ“×s«¿? `¢zÍš4ÎEx8pýzîÖ‘òÚnš úw1–kØgŒ1Æc¬(Ù¶žG2¾ìÇ”`Ö,uïâüöÎ;4â”)Àƒ†ç V¬ ÞަôÃÔ3ÓPÚ’ðp(³S'ý¹‰]\èYß@¥ÿþkx€Ç¼*ìv€&Mh°RCƒ†¾|™}¯[cIiRSu§ AAóìX‘z³?ybxžà`umS±²¢^ßþIƒš ôÞ»ôìI–jÎ3|80x0Ÿúzý Aƒyþú+°aƒéï¸)¬v3…6mhP`énIz: ºe‹þrÅykÑX¹˜6Ípüî]:|ñåM/*.¤ 1«Véoûðp`î\ýeíì€iœŠíÛõ™_¼ ï­kW`âDíiy=·R»ž"‚Úâ‹/kk þëËù\±"pè¥/hØzZß½ ¬[G9–íìhyeËRùêÕ©œT/OO º:EéURSiðbé Ô¯oÚv3;;º””DAä”Úýü(@4r$på õv–Σ/_Òwvê]0)WަI®äd ,yzR;ÚÙQ›4h@Ûìà@ÛüÏ?tñIZ¦Ÿ1?ÿœæ‰§²ÑÑÔ~šã#”*E>~÷íeËÒüS›/YL˜@ûS¦m³úõi{§N¥}ÖÊŠ¾³ˆZ÷ÎÔneËÒ7šétJ—:t¦ºÛÛÓ>®PÐö¯_OAÿÅ‹?ÖîM{õ*pà]l²¶¦6­]›Rvi~/GÒ~X¶¬iÛM:V½½Õûö™3Ô3ÚÊJýÙõëÚǰJEÇ×ñãt§B™2´¿5jDõ(‡ù®]t¼ÚØÐö5l¨½ý¶¶ÀŽ´=NN´½>>”3Í:6’’tÏ…½¿å¶Ý$nn”jgÊísă´?ŒI©gÖ¬¡v˼޼œ[ó¢B Y3 ðûøÐrÓÓ) ú4]¸®[—Î!¥JÑC©TŸGêÔ¡ß°É“éØ²±¡òaat ŒKÇÍöíºw¶åõÜzÿ>µÍ±cÔ¦¥KÓñöêý7l¾ùX°€.Þ™êo̸8ºhxê­§\9ÚÍK^^4þŽŸŸîoR^ÛM’›ßÆJ°§OŸÂÙÙ9_×aöæ÷Nððp¸¼étø¦Ó‰ô^¯ØØX‘ŸOOO+J*ooï®cFãý–±’O:ÎOŸ>-ÂÃÃÅ£GDdd¤I"<<\‰ÐÐP*ÿîÖcÿþýB©TÊOOO¡T* ùÛ`ÌË– áçg|Ùðp!lm…˜8Ñôõʉôt!¢AÚÍGß¾Büþ»ññÚe¢Z5õ|åË ±}»zzLŒo¿­žîä$ÄñãÚËX²Dˆ•+…:Tw½€sç œuݯ]¢];ír-[ ±kÕ[úlùru…BˆaÃô¯Sóñá‡B¤¤˜¶ÝLéÔ)Ým—Ö½k—qqÚó_¿.DÓ¦ÚóNŸ.„JEÓCB„èÔI{úСB$%©—-ÄŒºëìÞ]ˆ¿þ¢}@ú¬m[!‚‚të­T ñë¯Úû@ÇÀر´]iiùÖlâüyª[æmh×Nˆ={²þÎ…X½šöwͲ:á奿̼yÚó6jDû­äÚ5!\]ó¯Ý2«†BìØ¡.'DÿþÚóxxб-Ù±ƒÊIÓ‡ ÑÞ_$þ)„££ö²úõ£ïbútÃçˆÂÜßrÛnš22„8tH÷áäDer²ÞÜœ[MááC!Þ_»ÞåËÓo]|¼­[ë?HnÜ¢gOÝ6ÿê+!²‹3åöÜDûÕ/¿Q«–nÙN„8p€ö Sò÷×n@ˆ)Sèû‚ž§NÕž®ù›¤)/í&„ñ¿ Œ•`—.]*•J¨T*‘‘‘!222DzzºüÿfZZšHKK©©©"55U¤¤¤ˆ””‘œœ,’““…B¡ …B$%%‰¤¤$‘˜˜(DBB‚ˆñññòû¸¸8ùÿW¥R)öïß/öïߟåÿ¿f±±±"?¯:øøø ]»v¨ÝHîÅÔÕ«WÑ>¿r2–Ox¿e¬ä“Žó3gΠqãÆHII­Ô«ÏD„B@¡PÀÊÊ €víÚ™t=Æ8sæ (¿?{ö,<<<ä; +Ò¢£©—ê€Ô3ÕXkÖPú7´ú+hii”èåKêùWµjÁ úü9 –ùêõ†®Q#ëA'5%'Sܤ$ê5Z¥ŠáüÃù¡0Û-5•zíÆÄк«USĘŸ"#éN KKjóŠ_F|<õ&}ýšÊ;;«Ó¯ä7!¨7uh(õŒ­Vz>ç´kj*•}ù’z“W­Zpû\a¶[^ÄÆÒqZº4µ™1q†â¾¿©TÔ ûéSÚל©Šƒ/¨w¾…õÔ76>ôü9¥;²³£^é669/›—skj*í7ÏŸSûW­J¿+ùt¬Éå¥Ý ëw±"æòåËèØ±#úÿWzÖ|mìsæÏ¤û*• ÞÞÞððð9rгgOƒõ+&¿%ÏÇ[[[¸ºº¢bnþ¨È!‚‚‚•J…êÕ«ÃÕÕ¥¤Û ³‘‘‘;wî ::hÞ¼¹ÌɉÄÄDøûû#>>NNNpuu•wà‚‹-[¶ÀÛÛ±±±P½É=·nÝ:´lÙ2ÛòçÎþ}û‚”7-µlÙëÖ­Ë×zÿMŸ>¾¾¾pwwÇW_}UØÕaŒ1Æò—ôÏóŒ¹+ÿä ¥ŽiÝÚ¤Õ2š¥%åè- •+ç>‘ д©iëcŒÂl7++º¨Ô°aÁ®·zuí4¹Q®¥ü( ffìÊí++JQT ³ÝòÂÞxë­Ü•-îû›¹9óó9%D¾¨TI7Í1òrnÏ˹ÕÊŠâšépŠ“¼´[aý.0ÆŒÂýæííÉ“'ÃÏÏOþÌÒÒ#FŒÀúõëQÞT9íôؼy3–.]ŠÐÐP­Ï+Uª„Ï?ÿ³gÏβGãÖ­[±`ÁDEEÉŸÙÛÛcÖ¬Y˜3gN–ù‹SSS1oÞlÚ´ µk×–§1ãÆlذ±±±&]÷ä×7n„£££ü¾L™2ذaÊ”)z{ì¯\¹*• å˗ǶmÛä; J—.5kÖ Q£F(MMfB¬X±]T˜7ožœSßÞÞ»ví‚…… …ÁõGŽA||<¼½½µÖ—R¡ºuëæºl5`mmë:ä†J¥Â„  R©°zõê]7cŒ1ÆcŒ1Æc¬háT<D ˜»¸¸ÀÝÝ]gúĉ±yóf( œ8qBîEׯ_GFF*W®l0 -„Àµk× „@•*UPGcp—ÈÈH€­­-7n¬SÖÎÎ 4ÀíÛ·¡5-==]î‰ÿþûïë ò[ºtiŒ7³gÏÆÕ«W5jÈÓoܸ!糟0a‚κk×®^½záøñã8xð –/_®3ON´5äÞ½{HHHß§¥¥BBBpõêU­y]]]Q®\9ù}\\œVÚ)¯½R©Ô)[®\9¸ºº¬ÇëׯqêÔ)B¡PÀÉÉ ½{÷Fýúõs´?ÿü3|||0uêT´hÑ"GeL!** ÑÑѰ±±ACƒæøúú ï²B… òçBøøø6l{{{þøc£ëwww<|ønnn8yò¤Öté»ÿì³ÏÐ¥KŒ3FkàæE‹aôèÑØ¶m›ÁŸ=Љ'êmónݺá?þÐÚ_ÇŽ‹û÷ïcÅŠ˜3gN޶cèСðóóÃ’%K°`Á“Õ1ÆcŒ1ÆcŒ•\Ø/rPW_y077GÆ qëÖ-jM[¸p!.\¸€ÿý#FŒÀ¥K—´‚óׯ_—‚ëׯ×éÑ=hÐ ¬X±ééé8qâú÷ï¯5ýþýûroôhMÓ¬‹¡ºköTÏ\wé½­­-jÖ¬™mù˜4°?xð`­ÿ›7oFFFzöì©s÷CõêÕµÞ׬Y“&M’ßûúúÂÇÇ*TÀ°aôæmРÞõOž<6ltêÔ }ûö… nܸ½{÷bË–-ˆÕ;¶dÊ”)HHHÀ?þˆ *h`ßT6n܈“'O¢_¿~hÕªÂÃñwï^$&&bÚ´ièÙ³§Qã„„„ÀÝÝOžNŸ>³gÏ¢cÇŽ?~|‰Ç¬®.]º„'N`øðáܲٳgÃÞÞGŽÁÏ?ÿ\ª}…‡‡ÃÕÕ111puuÅßÿÍÍ!Ïõë×1sæLìØ±ƒ›ßÁÝÝöööˆŒŒ„§§§Lp\(búôéÈÏÏGóæÍq÷î]èèèpëLJž={âõë×X»v-—BªsçÎØ·oŸÜQ"ò"??***ptt,—ºB!„B!„/åp¨’)XÄ={ÝÝÝѲeKXXXp)NÄ늦l€úõëãØ±cPRR¦M›põêU¬GxDDš4i‚½{÷*¬ƒ‡‡Ž;SSSLœ8fff066Æ Aƒ  ±mÛ6œJ¥€k×®q£X6mÚ$ÔØ=§œ:pà °û¥#9_EAARRR¤æ{À5ØÙÙACC£\êN!„B!„B*Çûä%%¥ÏN¯LýJ““Ãý®ªª €õæX ûüùóRë²³³åîÇÅÅ+W®„H$Âøñã±iÓ&xyyAMM 'Ož„¶¶¶Â:¤§§ãáLj‰‰‘Y—€àà`n’ÝâꞘ˜Èå’ùò%×(¡¨îâòâõ·oßF||<àäÉ“‰Dܺâν¦‰ˆˆÀ³gϰ|éŠôêÕ p÷î]™íâÅ‹Áçóñý÷ßsyìkªÞ½{Ë].Na$~&Š ggg¼ÿÆ ƒO±sˆuíÚššš ••%pÏ ¡¥¥777¹û3gÎÄõë×Ö]GG—/_Fdd$5jÄWÕ]üZ|ÞFFFÇû÷ïaaa!U¶¤s¯I’’’¸ßW¬XQª2iiiÐÓÓC^^¦M›‘H„õë×sÁþšLrT†<%ýQ{úô)6WC\\¦N ‡RM´\Ò±å_Ü€ «««°Œä}IMMå~— ì‹]¹r-Z´À³gÏpéÒ%8;;ƒÏçssPˆSø”GÝ !„B!„BÈçKLL„––„B!”••ËußâxNAAÁ'§ä¡À~%ìuËçó¹ßÍÌ̤¶¯SÔKWlÍš5ÜÍøð!.]º¤0Õ ÀRÞ@Ÿ>}¤‚úbuêÔÁĉ±nÝ:ܸq 044”[w())ÁÊÊŠ[ž™™É¥)ZwñkÉóÖÔÔä‚úEוtî5…äò·ß~+U~|q 888/^¼à&7ÚNt€Ã‡ãÁƒÐÑч‡G9Õ¾zZ±bæÎ‹V­Z!>>cǎŵk×>;™<â?ÖB¡Pá6’ë$ÿ¸‹{ß?zôxñââââ°páB>|—.]â&b€fÍšÁÀÀ ÜÏBÈêøq "X±(ëü;>Ë–óçÿ4#„B!„ÈW»vm4kÖ 999rS%‘H‘H„¬¬,.ãÉ‹/Ê´ ìW333hhh ;;›ËÅ]”H$’Jÿ¡È¡C‡pèÐ!¨ªª¢_¿~ðññÁ¸qã,7(ž’’Âõ— ¦%¨ŒŒäû’u ƒ½½½LYɇ®hÝů322+·‡uqåk*ñõ€ñãÇC__¿ÔeÅ6 Ø ‘àÆ¸q㌌Œ*$°/nPÔ+\rdBEêÓ§Ö¬Y€½úôéƒ7n`íÚµXµjU¹OÜÈòáÃ…ÛH®“ì½ß¦MÔ®]™™™ å&ºîÓ§±nÝ:¼ÿ¾Ä4<„Bˆ >˜26¬ìA}8pðôfÍ*ÿº•“}šK¹#& ¹‰a[·nÆK­wrr‚‘‘àÀ2Ç‹‹Ã¥K—^£/‰‰ °Ý°aC±)]éñ&&&Xºt©ÂŸ©_æûöí‹¥K—böìÙr¦¦¦€øøx©”IbGŽ©ã–ÄÃíZµBAAFääärÝÏž=°IŸÅ©¬Š:zô(ÀÒÒRf4Œ¸þ7pûömî=íää}}}\¸p=’Ú–B)Vr2àáôí tèPöò§OIIÀœ9ŸÖÛ¿,rrqÃûýû@‘ÏbÅ  „y§H9ËÉ\]ÿ¾ r°cpëдiUפrM˜ÀþfLšTqÇðõZ·þëLG!„| (°_I&NœÈ¥g™6mšTù‹/bÏž=2ÛIš>}:ÂÂÂ`llŒC‡q)R,,,¸t-›6m¹sçdÊŽ?ðöí[LŸ>]ª²P(į¿þÊM˜;hÐ ©ÞѰxñb,íÊ÷ß@€£W¯^'Ož–.]*sleee,\¸põêUìܹ“[—••…ï¾û¹¹¹PUU•ê‰.)!!aaaÜ8ǼH$’Z!·|UY³f ”””pçÎŒ=ZnÚš°°0,\¸°BÒÉ”ñH¡PˆeË–¡@<<Àµk×°ÿþ*©—ššŽ; ¼}ûVª±£<´oßNNNØó/ž¼Wì·ß~ãÃæÌ™#S^¬?yò$rrr¸À¾’’z÷î3gÎ ==ÆÆÆÅ¦È"„B8gΰT} ФI¬_¿^¦ìÞ½{áåå%%%=zõŠ|91b¦L™‘H„ & ::Zjý²eË¸ÜøG޹¹9¾ùæ 8X±b–fëÖ­2Çoß¾=–,Y8vì,--1hÐ ØØØpyχ †‘ †‹þðÃ\ söìÙhÓ¦  sss.ÿø–-[¦áùõ×_accÃýœ8qëM-¹ÜÕÕUnùªÒµkWlݺ<'Nœ€©©)\]]1fÌ 8–––°±±ÁæÍ›‘‘‘QÕÕ•«I“&ÜÄ̇†¥¥%'''ôèÑS¦L©²º5oÞ7nx{{scåeÿþýÐÓÓCbb"ìííáææ†Q£F¡yóæX°`ÀÅÅEîh '''(++#??èÞ½;·®oß¾\ãõÖ'„R*™™,0ß¹3àì\öògÏQQÀ¼y@­JšbËÆøßÿ€ví*çx„B!„|ehòÜJÔ§Oœ?3fÌÀ›7opþüy,¿~ý°oß>èêêJ•yòä ~øá¬G¼‹‹‹Ü}oß¾÷ïßGhh(FŒÛ·oCEEKÇsãÆ ¬\¹û÷ïLJ¸ô7K¿3räHlÚ´IîhX·nôõõ±fͼ{÷ïÞ½¨««cöìÙX»v­ÂóVQQÁ… 0wî\=zOž<ázùbÆ ˜0aBi.a3gÎØØØ`ùòåxøð!þý÷_©õèß¿?ÆŒSE5,ÙáÇ1pà@ðô)køHIa©aäÍ餫 ´hQr ">f×:3°´d½§ÿKM(Wn.ðø1—Ç^kjÿu¨AREÇ:œ VââñhSuu }{¶ýõë¬gqv6Ë9îê ü—VS†H<{ÆÎ]Ìɉ=#99À;ì\Œ=€:uäï'= d󮁱‰KííV­ä_³Œ vÝÅ#ß½“ÝÍÌ*®vttá$³›¤Y_Ÿ=OAAì|44Ø5W4‡Wf&ðü9 ÄİsmÚ”]«"ßÉ8IIÀ‹ìÚ[Xuë²{Ä–ÙÚ­‹žCp0{þÕÔØõîÚ•=C¥ÁÊ>{èé±cÛÙ::ÒÛ ìÍÉa#ttXãâØß„Ø:??V++`ð`ö\V„ädàÑ#V÷Œ vÍ]\Øh…’|Ê={ù’=«QQìõÇ@l¬ô6ªªlî‘â&ìÍÏg›ž>eÏ|z:ûѵ+`n^ºs'„BÊ/99¹Bg;ò÷÷‡£££LÀúKñàÁ.eGi …B<|øÑÑÑÐÐÐ@ëÖ­+mÒØììl!&&"‘FFF°··GÒ|øü¯üýû÷}}}888”éÞÆÇÇ#00iiihРœœœ¸ˆ/Ý»wï‚äädhjjÂÂÂ-Z´®he}nE"‚‚‚ðêÕ+Ô©SíÛ·—9ò%‹ŠŠÂÓ§O‘™™ CCC899Aëk"MjñûÜÏÏ666ÈÉÉá&Ä./"‘"‘YYYPûïËð‹/¸ ¤«‚ŸŸŸÔœ-×®]ƒ«««Ôdò„Ô(¹¹,p”“.{ü— aM€ö~ú ˜9“i›7gÁæ„`Éà—_¤6nßfצ4^¿fA8yòò€¿þ-bDzµeAÍ  ¶ÞÝ­“wí½½o¿-|=|8pìÛß?²ýij²I;GŒöîeÁÕ^½X `ó&ÌœÉ~¢£Y _W—lõõ?þ`Ç(š‚)<°¶–^–šÊÊ-\ÈÒäˆÝ¦ {$s·‹D,ŸûâÅ@@;nãÆ¬AÆŽeó:˜˜HcÛ66ú£$mÚ°ý–÷gýÜ\ÖØ#™*ñþ}ÀȈ9z´ð¼utØý(:‡ÙáÃ,­Uj*{íèÈ®G@ Ò8 tÌÌ™À®]ìwwwö úù±sURbÏL«V¬¼¸§¨ü|ÀË‹íK|oY ÚÁس˜<™m([>3“móßRØÙ±F)>ŸíkëV [·Âí/^”>ÿ† ÙõŠŠ~û¥²?áál’m/¯òîߺ̚ŞÑFmíÂç|Ïö÷ÀÝ5ÚmPû”{öák —)Ι3€¢9ß>Ægö7ÂÀ€50$%±¹fάøùK!„Tºªø>-ÎHâëë p+¦s}Ë­JJJptt¬’À‡††—7ýSË+5PFFFr'þ˜ššr“ÑÖ4<ööö\J§¯¹¹9Ì©'!„ªpí \ýùgÙƒú°e Ь W$55÷â¾{—ÂJÒ²%ŒÉzÏœÉl}û²€°@À³ß}Ç’’)ðºtaÁ̬,`Ô(ÖùæMÙchk+Îó/«Vžž, Ú¯_aÏߌ ´]¶ŒõÒÞ¿Ÿå—4t(ë½›™É®óÇÀüùÀ￳ óŒ,héãüú+ë)lcÃÒ#ñù¬±áüyö3v,på ë ®¬Ì®åÁƒ¬A`ÃÖ¸ ©iS¸LKV®ŽgAç¥KYOO¶MP ˆ>{&Ø÷ña îîlrå† Y`2/”×®e÷ÁÇGºGòœ9,Êç³ÞÞ3f°†„¢ Ë?¨°gíÞ=öÜøú²÷Õ«ì|õôØ(‰Ž÷ïYƒÐÍ›²}++v¿Ûµc_qOí¤$vß¾ý–õ*oÜXºÜ¶m,h>r$°z5»gïÞŽªˆŽ¦OFfAl##Ùú»»kÖ°gdäH .(`#^Ö­c> òG©ä沉fïÝcG={²s.(`õغ•·Ož† ce¾ù†í[|.ß~ËžuuVÏd×ãÑ# m[àŸXcÜÙ³åÛxî0`{Ÿ;ÇFRðxì>rDºLžO¹gõê±sÿøؽ›^º~]v‡ŠŠâ‘1âýÌË®­mሌìl6yôÌ™ì=ò•~Ï%„Ru(°O!„BHuTPÀ‰ææ, VV7o²à¢§§l@º"hiNú)N{Q††…éGþúKº×¬Š k øóO`çND–íX¿>ûWS“m[ÖIé}|XÐüÒ%P-z>ƒ±@a§N,°ÿ_ŠL) ²^Økðócç1|xaÞ#¤_khH×uÌÄ—]ddÄ‚ôuê°^Î]»²^Ê’ ظ1béR´]±¢°·uûö¬¡E²7qX @¯Y,_.½NU•ìfÞ%KX㊸nJJ¬·µ8°ª«[öëþ¹j×fÇÎÿ÷?62e×®Âe¦¦¬Þ"9Ô;ub?Eéë³çí?Ø(€¢}• ®®Àöí,°.Ö¨áêÊÊí~í»æG²{.¦¬Ìyöìa£s¼¼äŸ÷îÝl”H` tà_Y™ÕuËö^˜1ƒ¡­¬Øzq:,6òEü>uvfüß/a ~ÆBBÊ/°Âßsæ°¿i’Ï›¡!kª]›m£È§Þ3]]ö£¯Ï^›™•ýymܘ]Ó¢44XãÎÌ™²##!„J@“çB!„RݹÃzp/^\ºœÝ’„Bt46fÏš Q#/ŠÇc9òäóÉ®¼<îÞõ|V¤M–eÞ<Öó·8::,°?b„lZŽâÒt,[¦xbã X€vçÎâ °À®»»l •¢ÇÞ¿Ÿõtž4Iq½ôõYïêS§X¨êlâDÖ!¯‡|IéQÒÒX¾úwïØ( q#SIÏÚìÙÒA}1ccöot´ôr¡õòïÐAqÀ\YYþè€H™75ÜÈëͰs7Ý[yÏ‹MaP(|N$GdˆŸÃ‚ùÇø²àþüùŠïÇøñÅ÷š—ô©÷¬>¬á®¸É”k×f鵎—¿¾<îÙ§ÊÍe£-þøƒ¥ÍªÌcB!ŨÿËB!„B¤²<Ù6°T+eµkë=^‘æÖtâô9B!ËÓ_33Ös¾"rÆ[Y•|56f½°““ Ó}*‘ˆÍ  ¬\òykj²óÖÑù¼cV'11ln„¸8Ö àîο„BÖÜߟ¥t)o™™ì_CÃâ·«][~Ïõôtöoݺ%ËÊŠÍ5•UöÑ>åM$b b;—Ü褨Ç~UÝ3€õП3‡¥4›5‹`Ñ×g 22XïýŠ:6!„R ìB!„RÝìÝË‚ª£F•½ì“','ýš5Ÿþ’Õ¯_Ø[þСª«‡¿? J¦H)*$„¥#’—j¦¬x<6ªàÜ9–[½,=ݿӧ³<öwîÈïAÞ¸1›8¸¼‰è""ŠßîãGÈ.Ú ¾÷ïÞ_^$bn[YU{Ëã±ù!nÝbé¯TUo*yUÝ3€ÍkàéÉ&Ýuv–]ŸŸ|ÿ}Å›B)åØ'„B!¤:yñØ·X° ô9§%8Àþ•œœók –m{mm`î\–ú£h>ôÊvó¦âu¯_W¯²”L%å‹/­Ñ£ÔTlý\ò&§­®bb€ Øù+J “—W1Ç60`s5\¸|ø x;EóØÙ±`½¯oáhyBB€§OY0¼¼ž—Ï5r$=ðè‘âm¢£Ù(ƒ¢Êûž•õyýë/ЗÔ/ë± !„rF}B!„Bª“ƒÙ¿ãÆ•½ì«WlÒÜE‹X/Ö¯Eóæ,0(NWRTR’üžÒóæ±ÞÄsç*žxS(dw’S×|ª¥KÈHÙå))l‚_ 6YkyéÝ›MÒ:kðò¥âí^¼Ö¯Þ¾•]W·.Kôæâò‘‘…yú«ñ¨ˆìlùëÀ~¨¸ã¯ZÅÁ6°¼íEÅİgAmm`ÏàÄ 6ÂD^CVb"°d {¦§M+ת–#€¾}ÙÄ¿ò523Ÿ–ÿþ*¯{fjÊþUô<æä°F‘¢ÿ رå]ï¤$ö·ƒB©"ÊK—.ý©"‹† B]<[ü&&& ?¥'!Uˆž[B¾|â÷ydd$êÕ«‡üü|¨TDnhµþ˘˜X¥_"##ѬY3îuTT,,, ToR¢£Y^ü¹s?­Çý¶m¬öþý@½zå_?y„B69æÕ«,­Œ¿?K™ñð!ËU¸<:š¥¾QVfe£¢€cÇXÙ @W·0mI~>ËiýÏ?,€l`ÀòÝÍù®­ÍD23YŠœv¬'OX0tôhàÞ=–/^òïšб#«ÃŽ,y^+ÿú5ë=½b°l;—þýñ÷‘ˆÕëÒ%¶Ý•+,ïvnnáùúû³¼øMšÈ¿vîîìß:uØÄœ::€@À‚·n±Àûë×À‘#²“ª³yüýYšwïXùÀÀÂc¿zÅ®wÑþ<›84”5nˆÓ£äå± ~P°s'0~<Àçʦ†QVfûÝ´‰Ý--–ï<"‚û—_€©SÙ=íÞ½ÄǨÔbb//v?oÝb½ÓµµY…ø¼ƒƒY ·hz#uuv<»w³ëYPÀrö¿xœ>ÍFSìØÁÒŸéê–ÓÕeÇVVfYYYìzŸ?Ï&« cÇ¿÷UT“Ï»^„Bªªø>maa îµ<”cŸB!„êÂË‹ý;yrÙËÆÆ›7³žº66å[¯âdd°ÛÙ³²ë<=¥_÷ì ¸¸6:³ÜØ|>{½j êY[³×ÉÉ,µ8EÇöí,×¼¸÷­X—.,°¾jÛFRß¾l΂þýåORkmÍÊîÙÃŒ©©Òë'OfÁ{WWéò99ì~8Q¸ìñc(—4v,;g55ÙcKÖÏÃ¥O‘4u*ëÉ,o®„«WYïlIË–I¿îÔ‰]y£7êÔa!ƒ±r‹ËÖëÏ?YP_Q®öY³Øyýü3›`TLS“õÒ¾rEq “O üú+ †‹mÝ*½M£F@Ó¦ò¯Û¢EìÜøõ¸kÚ”5R´nͮ۩SlRTssö¼}Î==Yc“›[áóüà›¸ΜaÏKìzˆõìɶ[º”]c1væÌa×,(ˆ=K󿱉gųf±F™¥KÙ¾Ä45Ù(Œùó¥Ó¯^[¶°ßX£Ÿ‹ m!öûï¬áHü¾??ÌîÑ£tö–ÄÒ’=³,5¤)SXcÄ¡CÀ³g¬Á­à§{ IDAT«W¯Âcê=“dbÂîÉO?± ’ÚµfÎd鮊–ëÕ‹5à­\ ¬^]¸\G‡Ý‹)S؈ñ{Ý:ÀÞþ3/!„R:¼äää MŠèïïGGGèJ~¸ø‚×%„B!„B!„Bj ìB!„B!„B!5ö !„B!„B!„„û„B!„B!„BH B}B!„B!„B!¤©UYzðàAeªÒ}ÉçF¾\ôÜB!„B!„R3UZ`ßÉÉ©²U©’­¹qX*¨/)Ã?‡Fvzv%׬â[{N&¨/&JÁÇÍÑO£+¹V%SQQÁÙ³gqëÖ-ܺu [¶l©ê*B!ä+Eß"!„B©"¦¦ ƒ]»:WuUH¹‚´;iíÚøîñwX–µ S_N…A_@Îó ªÊj–»Ñðlí3€’¾^ˆ%éK07n.š/kÎmw{ïíªªb±LMMÑ¥KtéÒ-[V¿Q„Bù:P`ŸB!„*dd¤‹æÍMd– …"|øŠ°°XÄÆ~„P(*õ>³²rñöíDE% ½Œ½½‚ÄÆ~ÄÛ·›+(SYR"àÖæ[ÜËÛ¢QëFPÕP…IS Ý6”[woã=äTE-+ăã¸ß;­ë„6½Û@]KzÆzä>švš€ˆxñ¾ªªI!„R­QŽ}B!„Bª‘„„LlÞ|;w>FTTa`ÝÁ¡6.ìŒ!C ¬,¿NtôlÛæ‡#G^#)IÈ-?Þ?þè‚ÖÅLHš‡nbÇŽ@„…å45y1“&uÀªU—¸mëÖUÇøñí0p`»Ï<ÛšëñÅÇ:„´hÖã^ÓP¿ïˆÝ[ '#·ßÆË /‘Ÿ•ƒøfé7¨kR™š‰Ô©µfj0·7—Ú}ËúÐ IÈzœ…´iÐ3®úÉYSâSpçÐD\€¨@ž2 ¢Ïâ>Ш£Wþ¯àÔ‰Ïj:jh5¼:îÄí#öa,÷»­‹­Ôþk©ÔB‹±-HˆJø"çÈÊÊBPP^¼x¸¸8ØØØ yóæhÞ¼yÉ…DDD $$Ïž=ƒžžlmmagg™m_¼xÄDv?êׯ&Mš ""7oÞDTTÔÔÔТE ¸¸¸ N:åzž„B©8Ø'„B!¤ñöއ·w¼Ìò€€L ~cdžbóæoahXÀ‰D8pà&,¸…ÔTÙžýGŽ¼Ã‘#‡ñë¯mñãß@MMEjýË—q˜;×WŠäzÏÊáàÁ·8xðm‘=¦âæÍ‹pskÚµÕ?ýdk¨d~2þîó·Ô²T¤â\Ð9X?³Fй Ü›}Oj}ÊõÜkxý÷c¯ãS¸uz-õ ¤$ÛXS·I]$!‰mÿ>¥Zöo¼ eÒ©R®¥À¤¥ †8àÄ€(H]à÷·š»6‡®‘.„B!ï'rëêÔ“ $ëšèr¿'¿K.ç3¨zÁÁÁX°`®_¿}}}XZZâ§Ÿ~,_¾ .„žžü{™™‰={ö`Á‚;;;ðù|ðù|´iÓ[·nE·nݸíù|>Úµk‡¬¬,Àºuë ®®ŽùóçZ´h””ÄÄÄÀÁÁ;vì@ûöí+ðì !„R^(!„B!Õ”¾¾:uÒ–Zvôh V¬ð…PXØ#ßÛÛS¦Ü” ê[Y©¢E é ûòåÁصëšÔ²ÔÔ,L˜p\*¨¯©Éƒ­mñû‘#Ϳʠ>èé¢ÑäF2ËõZéAEM†–†2ë” •Ñ´KSîuú‡tîwºr£¡W¸<-!ísª\nl\l l¨,³¼®i](«(ÃÈÅHféxS.€Ÿ•š…~aà_MCMf{uíÂç*%.Ef}MvýúuØÙÙÁÌÌ /^¼ŸÏ‡¿¿?ÒÒÒpþüyøøø`À€HOO—)›››‹ &`Ó¦Møë¯¿ðñãGâÝ»wˆŠŠB·nÝàììŒS§NqeŒƒ«W¯–-[†ùóçcÍš5àóùxúô)¢¢¢ðêÕ+ØØØÀÁÁׯ_¯´ëA!„OG=ö !„B©fzõª‹_í‹V­£V-%äæ àç‚Y³.!:Z€ýûß _¿ د^ñ1eÊ®ìÞ½]0xp;°@jzz6üüBðý÷WP€ùóýÑ¡ƒ%›6n¼ÿ €³³֭냶mÍ¡¦¦‚ÔÔ,üóOfÍúWªÑ ,l ¬¬Œ+ñŠT/<%&ì€Gýáâw!úïÚ$ÞOÄC߇x~þ¹ÔöfÍ0ÄctêI²ÜŸÜãð —‹Ê0ÇBE²r°Âœ98õã)Äz¦ÔypèÒÒÿoáh%}%ô=Üm¿iË£ÌyÈ9u©ó.¨ç]ø|>¾ÿþ{L:»wï–¥¡­­>}ú iÓ¦hݺ5<<<°fÍ©ò»w·7aggÇ-WVVFãÆ±eËhjjbÆŒhÛ¶-¬¬¬zzz055å¶ß±cf͚Ž®U«¬¬¬°ÿ~äççcöìÙ¸qãêÕ«WQ—‚B!å€zìB!„RÍìÚ5vv¨U‹}\WSSAß¾vؾ½'·Ÿ_ÀÛût:Ôööñöm"‚‚"‰W¯øhÔÈcÆXreõÄǧ`íÚg<=GÁÉ©)—ªGGGcÆtÆo¿u•ªŸ™Y=…yþ¿<%Újq×ÇAý¿Ñ ü\|oö¿á¶kýskŒÝ5V*¨_Óéê`Âþ h±²·ì;7¸0ø—†G£•Æ_»¾v .¾6Dxx8–/_.7õXYYÁÝÝk×®EXX·<..óæÍÃÊ•+¥‚ú’x<æÍ›‡¤¤$ìܹSî6¶¶¶˜8q¢ÜuµjÕÂâÅ‹ñüùsœ={¶ŒgG!„Êöu'„B!¤šéÛ×ææ²©\ cÇÂT.W®¼ƒP(Âýûï¸eÞÞñ°·ÿSîÏ–-áÜv¾¾Ñ‰€×¯ßsËúõ3……lp)2Á))dÞÖS.Ovm™uΜ1hå ¨™Ó4u4¹ßóÒóäî;7#·p{=M¹ÛTu ùy:ýÑIf®«.¦^œŠF-eÓihK§ÊÏÍ—Ù&/»ðzhÕÓ*‡ÚVÞÞÞhÖ¬5’½.’Ú¶m €åâ{òä ÀÁÁ¡Ø²†††pvvÆÁƒ‘Ÿ/{m]]]¡©©øYjÚ”ý (ö8„B©z”Чмzõ QQQÐÔÔ„­­-êÖ­[)ljDÇÛ·o! abb[[[(+ËæÉ”§  OŸ>E||<ôõõѪU+¨©ÉæÅT$##!!!HKKCÆ akk+5Ô¶2$''ÃÓÓ÷ïßGrr2—ŸvëÖ­hÓ¦M‰å¯_¿Ž“'O"** 999ÀMTUQø|>ÂÂÂÍ]w ù¹X¿$óæÍÃãÇáââ‚ÿýïU]B!¤R(++þl$ÙK>+K¡P„ÌLA™“ÜÜ<äJUÕÔTQ¡¯ ʼn|‰Œ'2Ë£îF¡Ýàv¨­[[fný bS^ÉÏ#ŸS˜W_rûê"=)‘7"e–§=NûÐwÐ3‘¶–j-èºê"å;çÌ”L¨Õ–þ>‘‘Xx-õVý„ÁåA$!,, =zô(ñû %¥ð¹çÜ/Í÷F+++ܸqYYY¨SGzrb##ùwbêêê°µµExxx±ÛB!¤êÑ'ôJvÿþ}̘1ƒëqªªª5j¶mÛŠ¢»ÿ~¬Y³ÑÑÑRË 0þ|,^¼µj)~$8€•+W‚ÏçsËôôô°hÑ",Y²DápR€Mô´|ùrìÙ³™™™ÜrKKKlÙ²ýû÷WX6!!÷îÝã~žæÍ;‰¨¨n"‘ÿþû ?þèW!ç^“ååäÁ{•·TP¿nϺ˜ñt¾ñù<ÌNöK†g/OD<Œ*¯¤¤Ç¥ŽÜëË—‘›ÅRï peë®Àn¹T5TåÖC  qãÆàñx4hÔ¤¼%*8 ž½<¥‚úÝöwܰ90eÂ-»5õ¼Wzsç%f?̾p› ·SøyÖßÇ gØ3¨ß[f-ÍÖcþüùàñxÐÕÕ­Ÿ‰Gމ¤¤¤bÓ܈D"œ?úúúprrâ–ÛÙÙÁÊÊ ¾¾¾rS숅„„àéÓ§˜>}ºÜ‘ÿüóÞ¼y£°üÍ›7@êØ„B©ž¨Ç~%ÉËËÃØ±c!`ii ???4nÜpüøqŒ;?ƪU«°yóær=v`` ·Ï.]ºàôéÓ04dy[3331mÚ4;v gΜ···LïŒgÏžq½Ô €ãÇCSSùùùX°`¶oߎ}ûö¡ÿþr{ÞïÙ³/²/¡k׮ŲeËÀãñœœŒþýûãîÝ»˜6mÜÜÜ UUU…:vìˆÀÀ@îgY]½z0wî\Lš4©Le¯_¿Žüü|hhhàðáÃPWWÿ¤:”Fvv6¦OŸŽ‚‚áÒ¥K\š ‘H„íÛ·cÞ¼yxõê~úé'üþûïVB!„Tœ´´, æ‰+W>J-÷òŠ…—×pvÖ©©6BB>âñã ÆÕÇ·ß²\Ûݺ5Çÿþ÷?ÿ>¿:ýGG-ØÛBSS?fáñãD–3&þ9JJJغu(üý÷#)IˆãÇãpüø.tê¤ÆëÀßÿ^¿–Ÿÿýkó<Mø ™2¥–µ1B=³zæ Á«Åƒ,Èž–‹£Ga½À#6Œàz°;wÄýŸï£€_€¨=QØ|e3Œ‘àŸ€œç¬ O“‡£;(¬KDD7"÷»ï¾«ð4—gÜÏàéOO¥–)é+¡i—¦Ð«¯}+}Ä!Ž[º.‘ç#ñíoaao°r°‚ñcðOð‘~7;[ì„I?dÄf õFacA×ù]¡¤`’f@€3gÎf̘}ýêß³äÈ‘8{ö,-Z„Ó§OÃÄÄDj½H$©S§°k×.œ:uJjÔª¶¶6öìÙWWW¸¹¹aÒ¤I2#¦±dÉtíÚÓ¦M“[‡ÔÔT¬^½Û·o—-þúõk,Y²“&MB¯^½Êé¬ !„RQ¨Ç~%ùóÏ?¹a“{÷îå‚ú0jÔ(.ȼ{÷n$''—ë±OŸ>Íý¾gÏ.¨µkׯîÝ»Q»6Ëûéãã#SÞÃÃB¡:::8xð 7ÙR­Zµ°yóf4kÖ KSS”H$Âúõë°F…åË—s_6ôôôpôèQ¨¨¨ ++KaŽz___¤¥¥áþýûRÇûâ4B–––Ÿ\¶AƒÔØèŽ„ÖSiõêÕR¹ÿy<~øátéÒ€ü{F!„š!8øLP_Ò©øóÏ© ~Ïžu±iÓ.ï=,YÒS¦4æ¶ñ÷ÏÀDbÓ¦08ðV*¨ªª…ùô›41†—×.»{7^^±ÔW èï ™ >¼Øðy9yx}ÿ5„IB™õ/7¿ÄûˆÂ ‹µêjáÛ“ßBÙ]{A”o¾• ê÷?Õú ­Ÿ>eAvCCCtïÞý³Î«$ÉqÉ2A}& ñêÞ+ ðló3™õÙO³ñðÄCî5ÇÃà ƒ¡Ó•–E©"ÄzÅJõíÖÙ¡…K …u‘lÐ2dÈ'ŸSY…Bx{{cÛ¶mÜø³ø¹s礖Ÿ8qôüjjjزe ”••áè舃âáÇxõêþý÷_Ì›7#FŒ€»»»ÜT8...رc¦NŠiÓ¦áêÕ«xùò%‚‚‚àåå….]º ..»wï–É­/éÈ‘#øæ›opúôi„Ba±s|*>ŸøøxhhhÀÚÚZî6?ÀnaîW‘HÄÍ `mm ===¼~ýÿüóø|> 1`À…× 4>~üÈMìÕ°aC4lØ['¾÷ÆÆÆhÔ¨>~üDFFB]]Ý»wçGŠ“••…+W® $$022B×®]åÞ—€€…B4mÚ´Ôb‡‡‡ããÇRïïòª;!„ê¯}{KÌ™c…Ó§£Àçú÷¯‡öíM°yóS¤¦¦U14TÆÿþçˆÉ“»A]]:-‹¦¦öîÑ£CñóÏ~¸! •,?p )F²GçÎ6ìØÝ«Wk4į¿^À®]Ò“¡º¹éaæL' r„qæ€t~:"ŽDpérêöª ÇéŽPUWEËž-ñzêk¼õyËøk;ÔFÛ‰mad!=BµYçfï7>³}¤RÛhÚibàÎhêԴغܿ0kÖ¬ ¯ tuá|ÀA‚v‡Mì«l¨Œ¦ß5EëÞ­¡¬¢ŒÞG{ãÖ¯·¸†ž&æß™£Ów¤öUϬ&yO‚÷bo¼=X8ÿ•²±2º®ëŠ®ã»Å >7htêÔ vvvå|¦òeddàÈ‘#8{ö¬Ì:OOO©×={ö„‹‹ êÕ“ž[ÁÌÌ —.]®]»0þ|¤¦Þó:àæÍ›èÚµ«Â:Ìš5 NNNXºt)zöìÉ-×ÔÔÄÂ… 1þ|©ÏäEmݺ]ºt»»;† &UÞÝÝ3gÎä:rB!¤z£À~%‰D¸uë [·nr·±··GíÚµ‘™™‰7nHö/\¸€Ÿ~ú ÚÚÚxüø1,,,dÊoܸK–,ºººLÐYhÏËËS8QSFF†Ô¶b?æ>l*ª»äÏ›7oJÕ]2eNqå/\¸€W¯^É4 |®É“'ËL< «V­ÂªU«¤–]¿~ÎÎÎÜëû÷ïã›o¾‘)¤‡CwëÖ 7nÜ[‡7âçŸæ®±ÇäI“°sçN¨©©I­“¼EË]nll\!A}ضm<<<кuk.€_TÛ¶m°”R#GŽä–çæær×éÌ™3ð÷÷‡‡‡‡TÞ×¥K—â÷ß/vŽEbbbàââ‚W¯^ÁÞÞ—/_–Z/¾÷âÑ &Lš¸yõêÕ?~<<¨ðú;wÓ¦MÃû÷ïeÖuëÖ ^^^R÷jâĉxþü9Ö¯_%K–”ê<†Ž'Ožà—_~ÁÊ•+Ë­î„BjMM5lß>Û·Ë®›7¯ââ’ññcêÔÑ€……4äYØg‹îÝ[ {÷HNÎ@LL>~Ì„––:tu5affÀõò—§aC}üñÇ8üôS*Þ½K ‚‰I]é ##öÅê[Õǘíc9÷ êÔ«ƒ {'{K·?³–f˜ûï\¼xŒÐÔÑ„±•1”UŠï5-™ŽfàÀe9…OÂãñÐmb7t›(ÿs=8 v€Ã`‡Rí¯ŽAL<0‰î‰Há§@EM††ÐÐÖ(±¬¸AcêÔ©•Ö»¼N:øûï¿?{?µk×ÆÂ… 1gÎDGG#)) 7FýúõK•JÉÞÞW¯^Ň mmm˜››CC£äë°|ý¾¾¾xûö- ¬¬ ‹b!„RýP`¿ÄÆÆrAXy=æ6y–µµ5‚‚‚&µnÕªU¸uëþý÷_Œ5 wîÜ‘ Î?|ø nÛ¶ ­[·–*?xð`¬_¿ùùù¸xñ"  µþùóç\oô¢_$뢨î’=Õ‹Ö]üZSSffò'¾’,ÿòåËr ì2DªÇÿþýûQPP777™ÑEs\š™™aúôéÜëÇÃßߺºº1b„Ô¶M›ÊïI5cÆ ìÞ½ëMÔ·o_hhhàÑ£G8qâ<==‘œœ ooo©r;v„‘‘âããqîÜ9™aÕ999ðóc“ØUÆ—¸ÏµgÏ\¾|ýû÷GÛ¶mƒ'$}œŽ IDATN ##sçÎ…››¬¬¬J½¿¨¨(¸¸¸àÍ›7èÔ©.\¸ p¸ñÓ§O±k×.´jÕ ½zõBzz:Ξ=‹7oÞàÈ‘#pqqÁ„ dÊùùùaÈ!ÈÏχ©©)ÆCCC|ˆ˜˜™u –š°UQݹ€/_¾ä%Õ]\^¼þöíÛˆœ>>2sÈÓµkW¹€‰••%pÏ ¡¥¥777¹ûk®BBBœÊ5/??_)))*((Ð<  (99YÉÉÉ×Õ¤*þŠ(ÅS Š&srr$IÆ ÓË/¿¬š5k5ï-m%-zôÚk¯iÛ¶mÚ´i“žþyIÒ{ï½gUG¾¸äädõîÝ[ÑÑÑjÖ¬™>ùäÝrË-rww×Þ½{õ /háÂ…Z¿~½6nÜhUK¿xìuêÔQŸ>}©n¸ÁX8ÕQì–ñ–öž={ªAƒJHHÐÈ‘#e2™Œ¶Ò®½*ùùçŸí'NháÂ…vûY’öJMMU­Zµ$&õzè!-]ºT5jÔÐû￯ððpèСCš>}º–/_®7jÉ’%6³á¯5 6´»¿víÚ’J «Þ½{+55URáϽE ¯äÜ–ó}Clù¾„††ÊÍÍþ?“Å׆hÛ¶°A=´|ùríÞ½[÷Üs$ ûfddhÇŽÆ"͖ľ½úúW;å¥Z5w­]û˜NTvvžU›——»BC”i¡OÎãëëk”q×û• h©Kéš)S¦è¡‡R­ZµŒ™öYYY6ý‹sqqÑþó…„„Èl6«k×®?~|‰çå•W-///EFF*88ØhëÛ·¯¶lÙ¢ÐÐP%&&êñÇצM›Æîçç§õë×ë·ß~S“&MŒäª£Ø-¯-רÇëÌ™3jÖ¬™ÕØÒ®½*INN6¶§L™R¦1éééFbÿ«¯¾ÒÒ¥K%.ø[t±ÞÎ;뫯¾Ò€´víZ=òÈ#êׯß5Ü-ú© {J+'c©¤Ó§Oë‘GQ×®]Ë´Ðriç¶w~Ë„š5k:cù^I…ëFXMì[lذAíÚµÓ´nÝ:õêÕK‰‰‰Æ–>å;àHE>8õôôäï"pª^ÝS:—Þ@¥"±_ ŠÎºMLL4¶7nlÕÏÒæh–®Å´iӌʞ={´nÝ:‡¥N¤Â’7’Ô¿«¤¾…¯¯¯F­éÓ§kóæÍJJJ2ê¶=((H...jÑ¢…±?33Ó(R›þRá÷®[·n’ kè¯_¿^Íš5Shh¨  ³Ù¬õë×—ºp.à‰ýJ2xð`I…‹lÚKôΟ?_Ra‚¶ÿþ6í™™™ºÿþû•••¥þýûëé§Ÿ–»»»>ÿüsùúúêÇÔ?þñ›q5jÔ0fòoÚ´I/^´߆ $Iîîî 1ö{xxèî»ï–$-_¾Ü(¹cQPP`, Û¡C5mÚÔª½{÷î ”$ý÷¿ÿµ9ïéÓ§µnÝ:I—îÑõ ((ÈHؾýöÛ%–t‘lgÄ[0>yò¤¨”””r=þwÞ)©pÑgK)«â–,Y"IjÞ¼¹Í§a,³ð7oÞ¬mÛ¶?ÓÝ»w—¿¿¿Ö®]«¨¨(«¾@Y‘د$£G6ʳ<úè£V³­¿ÿþ{}òÉ'6ýŠ7nœâââT¿~}-\¸Ð(‘Ò¬Y3Í;W’4kÖ,­^½ÚfìÈ‘#%&‰Çg5¹  @o½õ–±`îàÁƒ­fGKÒ /¼ ©°ìÊc=¦ÜÜ\I…Éè×^{M¿þú«$éÅ_´9·«««ž{î9IÒÿþ÷?}ôÑGF[VV–~øaeggËÃÃCÏ>û¬Ý{—””¤¸¸8ã˲°©Ùl¶Úo)_s­˜6mš\\\´}ûv=øàƒvËÖÄÅÅé¹çž³)'cùž™Íf5J'Nœ°j_·nfΜ)©0ù~ÇwTÈ5X>iRPP —^zIùùùFÛÆ5oÞ¼ 9oiªU«¦eË–ÉËËK'OžÔ#|¸"""Ô¼ysµnÝZï¼óŽÎŸ?o5¶oß¾7nœ$iïÞ½jÓ¦n»í6ÝÿýêØ±£î¾ûneeeÉÃÃC ,PµjÕ*äBBBŒ…™-Z¤æÍ›+""BÝ»wWß¾}5vìØ 9oY´mÛVÿüç?%I+V¬0Ž•—yóæ©V­Zúã?tã7ªOŸ>6l˜Ú¶m«I“&I’z÷î­ &ØŒíÞ½»\]]•——'///«/ 0Ž1[•ÉÓÓS¿ÜÝÝí~¹¹¹Ù|¹ººÊÕÕÕxmé[³fMg_& ,ž[‰ú÷ï¯5kÖhüøñúý÷ßµfÍI…5ø¨ÿüç?6I‘_ýUO=õ”¤Âñ½{÷¶{ìÙ³gkçÎ:xð † ¢mÛ¶ÉÝÝ]Ra9žÍ›7ëå—_Ö¼yótîÜ9£üTX~gèСš5k–ÝO HÒôéÓåïï¯iÓ¦éÔ©S:uꔤÂDÑ„ ôÿ÷¯ÛÝÝ]k×®ÕĉµdÉýúë¯Æ,ÿ€€½ýöÛ5jTYna•óä“OªuëÖúÇ?þ¡={öè‡~°j¯S§Ž ¤áÇیý÷¿ÿ­n¸AÓ§OWBB‚Í·Ýv›Þ{ï=uîܹB¯aÑ¢EŠˆˆÐ®]»tâÄ 8qBzæ™g4sæLÍž=»BÏ_’'žxBëÖ­Ówß}§gžyF·Þz«U½û«Ñ¶m[mÛ¶MãÇ×¶mÛ´qãF£­Zµj7nœf̘!WWW›±>>>jß¾½öíÛ§;î¸CžžžF[¿~ýäêêªüü|û¨Õ«WW«V­d”ý2›Í6%Àж•ö§£±¥•åÔ’’b.½Û•Û½{·ºuëvÝÎâÛµk—Q²£¬ ´gÏ8qB^^^êСC¥-{áÂýüóÏŠ—ÙlV`` n¼ñFùúú–yüÎ;uöìYùûû«k×®—õ½={ö¬öîÝ«ôôt5hÐ@Ý»w7@\ïN:¥ýû÷+%%EÞÞÞjÖ¬™Úµkg71\TAAöï߯cÇŽéÂ… ªU«–:v쨠  +ŽårÿÞšÍfýüóÏ:räˆ|}}uÓM7Ù|räzvüøqEGG+33SêÞ½»jÔ¨áì°€Y~Î###Õ®];VJbçÎÆÒÎiµfËÆfµ˜<¥‰ŒŒTëÖ­uñâEy{{—ë±-ï­³²²ŒJ±±±FE’o¾ùF’Ô§O‡Çà]®¸¸¸¨[·nNI|xyyuÓ¯t¼£O ”E`` ÝÅÿ 5jd,F{9\\\Ô¡CuèС¢*“ɤo¼Ñ(éôW¬àà`g‡TˆËIè[þ,¾Ï²î ¨ÔØ  !±@Bb€*„Ä>U‰}ªûT!nÎT¾o¿ýV«V­’Ùl¶Ú_üµ½ýÔÀ+4>à3öø ŠˆˆPxxøe#©T®‹suâÄ9ed\¸¬qyyùJLLѱcg”œœqEçÎȸ ßOÒ… 9W4@ÅaÆ>Q’ gï—Å Aƒ4pà@‡³ú\™‚‚}öÙN­ZuPIIY’¤§Ÿ¾U[·Õœ9‡••Uø3wï½zå•~êС©Ãc¥§giþü-š;÷WÅÅeûû÷÷׳ÏÞ®Þ½oÉT¸/77Oï¼ó½6oþ]ÙÙù’¤.]ê«W¯½ýöVmÝšfŒ¯«Q£º("¢‹\]™8‰}þÂ,³öKKî4Hƒ "©T€½{Óˆ‘Vû6o^cÓoÅŠ³Z±b‘6mºO½zµµiß²%F'~§èhÛÙýk×&kíÚ•š0áWM:Xµk×ÐîÝGõÒK?;ošfÍŠ³¿jÕ9­Zõ½†Ö»ïÞ¯€¿Ë½Låˆé6üÅ…‡‡—X–Ç’ÔP1š5 ÔwÔtØÞ¹³·üüLÆëqãV)--˪OLL¼""–[%õ½½Mj×ÎӪ߇ÓäÉ+”—W ÐÐ µoïUblmÚX_º4A/¾¸Ryy¥^€ŠCb8Lî“Ô*ž¿¿6l˜ {î ,²ÏEß~;@éé/hïÞçÿ‚""$I‡ç(..Áè›™yQãÆ}¥´´ÂOÔüýïMtàÀ¥¦NÑþý“•‘1Yß|3@-ZxH’æÍû]K—nWݺ¾Ú¹ó)}þùVñÜ|³¶n}@.¼¤ƒ'+-í-[ÖWþþ…o,8©+vWè=P2û@’mr?<<œ¤>PIÜÜ\åããa¼ž?ÿn…‡w‘OáŒú5<Õ³g£ýøñsÆöö퇴}{º¤ÂZú³gSÛ¶äîîjŒˆè¢yó"Œ13fü¨ìì\y{WSPõ§æÏ¢ž=[ËÓ³0__/ v‹fÏîmôY° ª¼.À Æ>0MìSSpžÀ@Ûönn—æääç_*…wÆØ¾÷Þvòö®f÷˜=z´RÆnŠÏS\\¶NŸNQpp€UŸ~ýüÕºu»ãûôi'©p-€õëÿTvv®ªUs/ó5(?$ö€•ððpú@’››ol{z:N´»ºšäëë&)O’”——oÓÇÝÝñzÝÜ\moo“\]ùð/à,ü6Ta-ZÔ5¶##« Àþ¶qq§sQRa ÿ  Z6}V¯>§øød»ã÷ì9flGDÔ·Jô¨\$ö'ËËËWvö¥ô.äØôÉÎÎ3¶sr.õ½ýöÖjÙ²°þ‚'õÏ®Uzz–ÕØ˜˜xMœ¸Âx=iRU¯îi7–‰¿Ô‘#‰Æk³YÚ±#NO?ý½±o̘ne½4€R<€;vFƒ/Ò}½{/×Ô©Gô꫃UPP —_^©éÓícÆlVnn¾}´·jÕª¡ùóÿ¦ž=¿$½øâ^}øá¯êÙ3@Õ—¬õëÿ4ÆÞuWmMœx§Ãx¾þ:I_=W=zø¨Y3?íÛ÷‡UlÏ>ª°°öåy \&fìNôý÷ÑV‰s‹™3£•™yQIIiVI}‹wÞÙm,¢{ë­­´lY_ùù™$Iññyúì³Óúàƒ#VIý>}jéßÿâp¶~Q;vdhñâx«ØÆŒi¬—_(“é²/@9"±8QDDg Þ@ÞÞ—²åmÚxêã{©zuOÖÒâÅa «i´wìè­™3ûX-`;lØ-úå—ÇôÈ#MmÎQ¿¾«æÍ»M«WWpp€ÃX† Òüù·«IëExƒƒÝµxq˜æÎ¥Zµj\ÅÕ(•VŠg×®]•uªJw=_®_ü½àÚШQ-Y2Öa»É$q«FŒ¸µÔc5m ¹sGiÚ´48qNYY9ª]»†BBêËÓÓ½Ôñµjyj̘^zðÁJLLÑÙ³iòññTóæõÊ4@娴Ä~÷îÝ+ëT•j×®]×íµáúÅß[àúWÖ‡w¦«¨§ak6›¯ø*F@€Ÿü®x¼§§»‚ƒJœÝÀyX<€ë\~~¾³Cp ÊÏ/ÐÂ…[µzu¬±oãÆx=üðP]?ÜCmÚ4tb„©”ÄþîÝ»u×]wUÆ©*³žQñ÷¸þY~ÎCCCKìg™m9:jPµìÞ}DcÇn±ÚwøpŽ>%I:zôO­\9Þ¡(E¥ÍØ_¿~}e sàÀg‡àà§–-=tøpŽÝöîÝUrDʪÂûݺu«èS¸L-ZÔStôsЉ‰WvvžU›¯¯—Zµ rRdJC}à/ªZ5wuêìì0\&gÊŽÄ>U‰}ªûT!$ö¨BHìP…Ø  !±@Bb€*„Ä>U‰}ª·Ê:QFF†Ž?®´´4eggWÖi@«V­šüüü,g‡Àu¯Rûñññ:tèÌfseœT¢ììl%%%éܹs UÆ ×µ OìgddèСCruuU§Näåå%7·Jû ¨`yyyºpá‚öíÛ§C‡ÉÏÏ™ûT  ¯±üøq™ÍfuêÔIMš4!©ÀuÆÍÍMMš4Q§Nd6›uüøqg‡Àu­Â³ìiii’¤ H’j×®]ѧNРAíÙ³Çø¿TŒ Ÿ±oY(—™ú\ß,ÿ×[þïpõ.^ÌÕ‰甑qá²Æååå+11EÇŽQrrÆ;#ã‚~ÿ=I.ä\Ñx‡l;àDúì³Zµê ’’²$IO?}«¶n=ª9s++Ë,Iº÷Þ@½òJ?uèÐÔá±ÒÓ³4þÍû«ââ.=dëßß_Ï>{»z÷¾A&Sá¾ÜÜ<½óÎ÷Ú¼ùwegçK’ºt©¯^½BôöÛ[µuë¥Oß„‡×Õ¨Q]ÑE®®>7@)HìN´wïo1"ÒjßæÍklú­XqV+V,Ò¦M÷©W¯¶6í[¶ÄhâÄïm;»íÚd­]»R&üª©S«víÚ½û¨^zéçbçMÓ¬Yq6ãW­:§U«¾×ðáÑz÷Ýûàw¹—  1Ýp¢fÍuÇ5¶wîì-??“ñzܸUJK˲ꯈˆåVI}oo“Úµó´ê÷á‡Ç4yò åå(44HíÛ{•[›6Öã—.MЋ/®T^^A©× âØœÈßßG6LÐ=÷Ùç¢o¿ ôô´wïóŠA’¤Ã‡s—`ôÍ̼¨qã¾RZZaÉž¿ÿ½‰£ÔÔ)Ú¿²22&ë›o¨E IÒ¼y¿kéÒíª[×W;w>¥Ï?¿Ó*ž›oöÑÖ­èÂ…—tðàd¥¥½ eËúÊß¿ð­Ã‚'µbÅî ½'JFbp277Wùøx¯çÏ¿[áá]äãS8£¾F OõìÙÄh?~üœ±½}û!mßž.©°–þìÙÃÔ¶m#¹»»c#"ºhÞ¼cÌŒ?*;;WÞÞÕdýiùó‡¨gÏÖòô,ŒÇ××KÆݢٳ{},ˆ*¯KpHìטÀ@Ûönn—~uÏÏ¿T '.}ï½íäí]Íî1{ôh¥† Ýþÿ˜l>bÓ§_?µnÝÀîø>}ÚÛë×ÿ©ììÜR®@E€¨td IDAT¹æÏýóÏ?«óçÏ«aÆjÓ¦L&SéËA^^žbbb”˜˜(IªW¯žÚ´i#ww÷2#;;[û÷ï×¹sçT·n]µk×Nžžž¥,âäÉ“:vì˜Ìf³Z´h¡Æ_Öø«qêÔ)-X°@¿üò‹RSSUPP Þ½{ëÕW_5úìÝ»WK—.ÕáÇ•™™)³Ù¬gŸ}Váááe:ÇòåËõᇪvíÚZ¹re‰}Ëã~\ÏrsómOOÇ¿·ººšäëë&)O’”——oÓÇÝÝñ¼77WcÛÛÛ$WWæÎrÍ$ö“’’4qâD­\¹R¹¹—fÿ4iÒDo¼ñ†FŽYaçÎÈÈÐ믿®ùóç+--ͪÍÇÇGcÆŒÑÔ©Såçg;sÊ"77Wo¼ñ†>üðC¥¦¦ûýüü4~üxM:UÇKÒÏ?ÿ¬ &hçÎVû»uë¦Ù³g«k×®Ǧ¦¦***J{öì1¾Î+üˆö´iÓôÜsÏ•xnIÚ½{·úöí«ŒŒ «ýõêÕ3¶çÌ™£'žxBÖ ¦ :´Ôã[ÄÇÇkË–- tا<î'À_A‹uíÈÈÃ:ôf¹¸Ø&ÝãâN+&梤ÂþAAµlú¬^}NññÉjØÐߦmÏžcÆvDD}«D?€ÊuM$öÕ­[7:uJ’ÔºukÕ©SGÑÑÑ:qâ„F¥£Gê7Þ(÷s§¥¥é¶ÛnStt´$É××W¡¡¡’¤C‡)==]|ð6lØ íÛ·«víÚ6ÇÈÏÏWxx¸Ö­['I R‹-tìØ1%$$hÆŒúé§Ÿ´nÝ:‡³ÿ7mÚ¤~ýú)''Gnnnêܹ³¤ÂdÿîݻգG}÷Ýwºë®»ìŽì±ÇôÅ_ØmËËË+Ó½xæ™g”‘‘¡Ö­[kÚ´ijÚ´©\\\T«V-ã^Mš4Iºûî»õÌ3ϨnÝÂ7’5*Ó9Ê¢<î'@U’——¯ììK3è/\ȱé“}éwºœœK}o¿½µZ¶ŒÔáÃ9Z°à¤BC×jüøÞòõõ6úÄÄÄë©§.}RrÒ¤ª^Ýþ§ 'NüR3gVHH}I’Ù,ýøcœž~ú{£Ï˜1Ý®à*”—kâó³#GŽÔ©S§äãã£uëÖ)&&F[·nU||¼1üÍ7ßÔÆËýÜS§N5’úO>ù¤NŸ>­Ÿ~úI?ýô“õôÓOK’bccõÊ+¯Ø=ÆôéÓ$ôŒ3tòäImÙ²E'OžÔ;ï¼#Iúá‡>˜HKKÓý÷߯œœµjÕJqqqÚ½{·vïÞ­#Gލ]»vÊËËÓСC•œœìðZL&“BBB4dÈM™2å²îÃùóçµk×.I…÷úž{îQçÎÕ±cG5iR¸PÛŽ;”••%IZ´h‘úöí«Ž;ªcÇŽò÷·Õu¥®ö~T%ÇŽQ§N³ôùç§}½{/×o|#I*((Ð?þ±\“'ï5Únj٬¹s$ÕªUCóçÿÍh{ñŽjÛö==øàôôÓËԯ߿Զí|EFÖÔ¿ë®Úš8ñN‡ñ|ýu’Z¶œ«[o}W#GÎWûö3uë­_(..[’ô쳡 k_~7ÀeszbóæÍŠŒŒ”$½ýöÛV3ÒkÔ¨¡… ªeË–’¤—_~¹ÜÏo™åÞ¹sg}ðÁª^½ºÑæíí­wß}Wݺu³ê[TZZšþùÏJ’† ¢É“'ËÕµðcÉ...zöÙg5jÔ(IÒ{ï½g71oÙïêêªåË—«yóæF[Ó¦MµbÅ ¹»»+55U³fͲ{Ó¦MSjjª>¬Ï?ÿ\&L¸¬ûpöìY™ÍfãœöXÖ¨Q£†1S¿¼•Çý¨J¾ÿ>Z\´Ù?sf´23/*))MÓ§´içÝÆ"º·ÞÚJË–õ•Ÿ_áÚTññyúì³Óúàƒ#Z¿þOcLŸ>µôïq8[¿¨;2´xq¼UlcÆ4ÖË/T%-À§'ö—,Y"Iª]»¶FmÓ^­Z5#I½k×.ýöÛoF[ff¦víÚ¥]»véäɓϑ——gô;t豿  ÀHV÷ìÙÓî"½&“I·ß~»$)99Y/Z¿éZ½zµÒÓÓ%ÉaûI“&ñ~ûí·6íK—.•$õë×OmÛ¶µioÙ²¥ $IZ¶l™Ýs´hÑB¾¾¾vÛJ’””¤]»v)**ÊØcܯ¢_‡6úÝð íÍ .hùòåzõÕWõꫯjñâÅÆ}*IyÜO€ª$"¢³†o oïK¿‹¶iã©?î¥êÕ=XK‹‡),¬¦ÑÞ±£·fÎìcµ€í°a·è—_Ó#4µ9Gýú®š7ï6­^=^ÁÁc:4Hóçß®&M¬Ë»kñâ0Í;JµjՏЫPœ^cÆ ’¤;î¸CÕªU³Û§_¿~Æöúõë5~üxI’———^~ùemܸQúå—_¬zµ˜2eŠÞ~ûm¹¸¸(22Ò¨¡ïââ¢zõê)11QçÏŸw£e1ÙÚµkËÓÓzv“%þ:uê¨K—.vÇßpà jР´~ýz3Æhûí·ßtôèQ›ë´wV®\©“'O*66V­[·vØ÷r¬\¹Ò¸Ÿ¥-T|þüyÝ|óÍÆënݺe|$iûöí>|¸ÍÃ___ÍŸ?¿Äc_íý¨j5ª£%KÆ:l7™¤#nÕˆ·–z¬¦M4wî(M›–¦'Î)++Gµk×PHH}yz–¾6Q­Zž3¦—|°‡Stölš||<Õ¼y½2P9œšØÏÈÈ0ÌíØ±£Ã~!!!ª^½º233­f‡»¸¸hÉ’%êØ±£Îž=«áÇëÿûŸ\\.Í\Z¿~½QÚåÕW_ÕwÜau숈Í™3Gk×®UJJбP¬EZZš¾ûî;IRxx¸Ml–x:tèPâµvìØQ 6³Û‹¾.étêÔÉjLy%öÛ¶m«qãÆ)55Õ(5tß}÷Ù­™£mÛ¶ÉÃÃÃêÓÍš53¶÷íÛ§~ýú)33S~~~1b„BBB” ¥K—jèСvïcÑk“®ü~@ ðS@€ß÷ôtWpp@‰³û8SûÇ7¶7n\bßF)..Ϊ$Õ«WOK—.ÕwÞ©~øAo¾ù¦^{í5I…5áGŽ)³Ù¬Þ½{Û]üö7ÞЖ-[«°°0½ùæ›êܹ³$éçŸÖ«¯¾ªS§N)$$Do½õ–Ãk(Kü’lâ/ë=°Œ·wŒ«Ñ³gOõìÙSqqqFbÊ”)v2Ì™3GÛ¶m“———æÌ™c÷xÿûß•™™©ÆkëÖ­ÆÂ»–ãÞyçúúë¯Æsµ÷e“Ÿ_ … ·jõêXc߯ñzøáÿ*  º~¸‡Ú´ièÄ8âÔûEk®—VÞÒn)‹STXX˜±°îo¼¡M›6©  @ÇWRR’µtéR«™üuëÖÕ?þ¨_|Q¿ÿþ»¨   iàÀ:v옞þyíÚµKõë×·o‰§¬ñ_¸pAùùù—}Š¶Ù»ׂ͛7kß¾}’¤>úÈ*©/I~~~úôÓOí~,®ö~ lvï>¢±c·èÛo“Œ}‡çhÑ¢Súç?ãôòË«€’85±áÂcÛÃãľ–úûEÇõꫯªW¯^FBÿ™gžÑ¦M›Œr=öjï[ÄÆÆjïÞ½JMMµiKOO×Þ½{cÓ–››«¼¼¼ËŠ¿ø5”õ8-Y»v­$©~ýú0`€Ý>¡¡¡êÙ³§Ý¶ò¸Ÿ(›€?µléøw®îÝ9là\N-ÅSt!ÚœœœûfggÛŒ)ÊÕÕUË–-SÇŽ•˜˜¨Ù³gK*,ÿÒ§O‡Ç]±b…|ðAåää¨Gzã7Œúîû÷ï×믿®~øAÛ¶mÓ’%KôÀcÝÝÝåêêªüüü2Ç_üŠßooïË-Ù¿¿$éÆo”ÉdrØï¦›nÒ–-[lö—Çý@Ù´hQOÑÑÏ)&&^ÙÙyVm¾¾^jÕ*ÈI‘(Sû>>>ÆviåeΟ?o3¦¸úõëkêÔ©?~¼$©]»vF½}{RRR4zôhåää¨oß¾Z·nU™˜^½ziÓ¦M4hÖ¬Y£±cǪoß¾V ìÖ¨QCiiieŽßÓÓSnn—n{ñ{P³fÍÇs-ùóÏ?%I%/²VRûÕÞO”]µjîêÔ)ØÙa×,//¯ ;¶§§§Ìfóuj)ž¦M›Û§N*±¯¥=8ØñôôtÍš5Ëx«üÑaÿ5kÖ ä_|Ñníw“ɤ—^zIRaâ}Íš5v¯áJã/ë=(ÚVÒ=p&Ëý+­æ½¥ÜŽ=W{?àzçÔÄ~Íš5Tøßèèh‡ýŽ?n$àÛ´iã°ß£>ªcÇŽÉÇÇG]ºtQ~~¾|ðA%''ÛíòäIc;$$Äáq‹¶#ImÛ¶-5~Iúõ×_íÆo_Ú1,ãíãZa™‰úôéû•Ô~µ÷®wNMìK2êßoÚ´I¹¹¹vûlذÁØîÛ·¯Ý>sæÌÑ_|!Iš;w®¾þúkÕ®][ñññ=z´Ý15jÔ0¶-edì)ÚVtLÑøÏž=ë0}èÐ!ã@ñøCBBÔ¤IIÖ×Yœ¥­~ýúV®%;w–$ýôÓOV5ð‹Û¶m›Ã¶«½Ÿp½szbÿÁ”$%%%é³Ï>³iÏËËÓ‡~(IêØ±£BCCmúDGGë™gž‘T8kèСjذ¡,X IZ½zµÞ{ï=›q–Er%éË/¿tcѶ¢c$)""ÂXðöý÷ß·;Þ²ßÓÓSƒ¶i6l˜ç±cÇlÚOœ8¡¯¿þZ’4dȦu¦¿ýío’¤´´4-\¸ÐnŸ-[¶X}ú ¸ò¸Ÿp=súª£wÝu—zôè¡;vè™gžQË–-Õ½{wIRnn®žxâ 8p@’ôÆoØŒÏÌÌÔ< ‹/ê†nÐ|`´…‡‡ë©§žÒ| _|Q={öT—.]Œö=z($$DGŽÑÛo¿­ÀÀ@=ñÄruu•$è“O>Ñ´iÓ$ήïÑ£‡Õùk×®­§Ÿ~Zo½õ–.\¨îÝ»ëÑG5Ú,X O>ùD’ôøã+00Ðæ&Mš¤?þXééézà´fÍÕ«WORáx@ÙÙÙª^½º&Ožl÷>fffZÕ¥ÿã?ŒísçÎ)..Îxíëëk”@*OíÛ·×€´fÍMš4I!!!êÝ»·Ñ~ðàA >\&“Éá¢åq?àjdff9ÕòžhmÉZþlÙ²åeÔ’’reËî–Qdd¤$é¾ûîsØç÷ßW×®]uîÜ9™L&Ý|óÍò÷÷WTT”%I'N´JÚ[Œ9R‹/VõêÕ¥V­ZYµçääè–[nÑÞ½{Õ¬Y3íÛ·O¾¾¾Fû®]»Ô§OeffJ*,uÓ®];™ÍfÅÄÄõོ¼©[n¹Å&†œœ………iûöí’¤Ö­[«eË–:räˆbbb$I]»vÕ–-[äééi÷¬^½ZƒVAA¼½½Õ³gOI…ek²²²d2™ôÕW_éÞ{ïµ;~ݺuºûî»Þ㢆 ¢Ï?ÿÜj_\\œZ·n-IÚ·oŸ:vìh3nΜ9?~¼üüü”ššj÷Ø ºùæ›uêÔ)™L&ãáIBB‚6mÚ$ooo1B}ô‘uæÌ›c”Çý8ÇòåË%]*­VÙ"##­>͵qãF………ÉÍÍésUÈ·ß~«5jÈÓÓÓá$eIÛìíwÔ·S§NÚ¹s§ÂÂÂ$Iß|ó¤’ß[_ïr›6mª={öhܸqÚ°aƒ~üñG£Íßß_¯¼òŠ&Nœh3nÁ‚Z¼x±$é£>²IêK’‡‡‡>ÿüsuîÜY¿ýö›}ôQ«¤v÷îÝ¥çž{Nßÿ½‡ RáÓ˜~ýúiÖ¬YjõððÐúõëõ /hÞ¼yŠUll¬$©Zµjzøá‡5kÖ¬“Ѓ ÒÆõøã+66Vëׯ7ÚZ¶l©>úÈiI’ËÑ AmÛ¶McÇŽUdd¤¶oßn$è;wî¬E‹{)û WªzõêjÕª•‚‚‚¬fØOΟ}_ÒŸŽÆ\v|×ÄŒý¢Nž<©èèh?^ 4P÷îÝåîî^‘!þüóOíÛ·OIII2™Lª[·®:uê¤Úµk—ù©©©Ú³gþøãùûû«k×®ªY³æeÅñ믿êèÑ£’¤æÍ›Û=_9rDÑÑÑ2™LjÙ²¥ÚµkwÙÇ(û ¨<ÌØ\"##Õ®];VJb¿JÎØ/ªqãÆjܸ±SÎ]»vmãæ]©š5kªoß¾WuŒ:Ø,Ò[…„„($$䪎Q÷ÊÓå$ô-ßw5µû]®x$¨t$ö¨BHìP…\s5ö”ͱcg´xñN%%7öMšÔWÍ›×sbT•#3ó¢.Ü¦ØØ³*((¬QÚ¯_k…‡wqrd@Å#±TQS¦¬Ò_$Zí?>ÇIÑT®o¾Ù« ~´Úwà õ P¹(ÅTQ7Üè윦iSg‡8 3ö€*jòäA8°ƒÆ_©;3œN¥êÑ£•~ûm¼,Ø®7ßÜïìpðñí·ßjÕªU2›ÍVû‹¿¶·àÀ8p`¹ÄQá‰ýjÕª);;[yyyrsã9׫¼¼>^WO~~’’ÒT§ŽÜÝKþ>//_IIéºp![~~ÞªSÇ·Ìç)((PZZ–RS3ååUMuêøÊÍÍñ‡ŒƒƒPæãW+""BRa‚ÿr”gR_ª„ľŸŸŸ’’’” &MšTô逓$$$H*ü¿À•ÉËË×Ê•{ôÑG»´ukš±¿}{/=öXgÕSÞÞ%?<Û´)VÓ¦­Ó—_^ª½ïímÒßÿÞ\Ï?—5ªc3fÙ²úòËh¥¥eû&MºM7ߢ?Þ¨ btüx®Z´ðД)·hĈ[åææjuŒ´´,ÍŸ¿EŸ|ò‹¾TçÿÎ;këÉ'{¨ÿNrq1Ùœ;?¿@kÖü¬Í›håÊã:q"×hóó3éÉ'ÛjìØÛÔ¤IݯÛÂl–-Ú¢¯¿>¨ôôÂ8ÜÜ\Ô­[MžÜÿªpÒå'÷ ¤:œÕ%*<±¬sçÎiß¾}’¤ 0s€ëH^^ž´oß>¹¸¸(88ØÙ!UÒñãIzZ¹ò¬M[tô=þø-[¶_³gV§NŽΞzj—;¬,³þõ¯£úâ‹ãúøã¾º÷ÞnEÎ{VÇGÚŒiÒäMš´Þ*IôhŽFÞ¬cÇþЛoÞkìß¶-V'~§_~ɲ9Ά jÆÕ5ê͘ñ7Õ«W˪ý«¯viذÿÙ½–´4³¦M; … ã9Z¡¡A¯ÛâÈ‘Ó=z³ÍþÈÈuéÒXƒßTê1€Ò„‡‡K*=¹?hÐ 4¨\“úR%$ö}||ªC‡iÏž=Ú³gOEŸ8ÉdRhh¨|||œ P大_И1Ë´yó¥YúÞÞ&µiã­“'/*))_’´}{ºxàsmÙò˜‚‚j9:œ¡sgo?Ÿg$ç“’òuß}ëUW7ÞØL’T¿~-=ð@}«þ’´hÑ)«×þþ.JN.$-\§×^+››‹bc4hÐWJK»ôF¥~}W5h੘˜,ee™ã]¼ø•>ýtŒ<<.½ ©S§†Õy¼½MjÙÒK&8P8>>>OÏ>»RkÖL(õš}}½íîvW‡|‚å'<<\f³Y«V­²Ûn™©_*eê|Æ åçç§ãÇ+--MÙÙÙ¥UBµjÕäçç§àà`’úÀzë­ÕFRÀ€:zóÍþºá†&rss‘ÙlÖÑ£g4cÆ:ý÷¿'uôhŽ^|q¥.-ûõçÿõ¯›5|ø-ªU«†ÌféÔ©sš5kƒþõ¯£’¤§ŸþVÿûßyzºËÓÓCK—ŽÕŒè£~Ð;ï²:ÖСAzýõþjÞ¼ž¶m‹ÓW_ý¬aúÈÍÍEYYÙzüñKIýI“BõĽմi€L&)77O{÷þ¦çžûN;vdè‹/Õ«×=öX˜qü°°´y³›rsó\Wו››‹L&“RRΫU«÷•””¯µk“•œœ!ÇÿÎ:flûû»háÂ8°³Ãþ@y(>s?<<¼Âfê[Pìp¢cǬk꺡LãŽ9c7±çmìö÷ö®¦AƒZjÓ¦ŸJoñþûÝõÔSw•CLÌ¥ò=‰‰ùêÑãóRã>~$'_TLÌÅRçÈ;ïÜNR•Æ2s_R…ÎÔ· ±8QnnÞKI±]¨V*œë¥Ò=99ù%?(ȯÔ²³¯,öôô ’¤³gS5lاںõÒÚ~~&…„xëÈ‘,«ºý—ë©§6«^=?ÝuW‡+>p9,3÷+‰}À‰Š/‚ûÞ{ÝlJâØÓ¶mC»ûwíúM·ÞÚÊfnn¾"#/•ª ­w™‘ÚjÚÔߨnÒÄ]o¾ÙS..Ž,XÖ”$}òÉf#©ß¿¿¿¦O¤¶mÉÕÕEf¥§g©gÏuà@ÙfîÝX11j÷îóJK3«_¿oôé§é1¢§JxÞT9$ö' Ò€u´fÍ’¤øøT}›üü¼­ú]¼˜£C‡wZ5kz«C‡¦’¤ÌÌleg_š}ÿüó{Ô´imEDÜ$wwWI…3äÿõ¯ Z½úœ$©];OµhQ¿È±s•šš©ŒŒlc_jj–ΜI5^תU]Õª¹[ÅÔ³g+D*))_'Nä*/¯@#Fô0jò_:V¦bbâuôh’:thl<ÌØ±ã”ÑgìØ®jß¾‰ñ:!!Y_}µG§N]Š)--Kf³Œ$}^^¾ÒÓ/%ýoº©‘Þzëo;v©q?GŽüAgΤ롇zؽ *2¥¤¤TÎg*Xdd¤l¼Þ¸q£ÂÂÂ俯\\ÛŽ;£ž=ç)1±0AïçgÒÀA ¬¡¼¼:•¦~8gUšæ§Ÿ†ëäÉdÝwß:»Ç vW×®utáBžvìHVrò¥Eh7o¾_·ß^X‹Ë–Ý{ï «v{\µbÅ}6Ÿøî»Ÿ5hÐj«ó†…5PÍšžÊÈÈÖ±c©ŠŒL1Ú6tÓþýO«fÍêš:õk½þz´$©E ……5‹‹IÑÑç´cG†Ý8†o … Çèĉ$ ¼Èj6ÿÇ÷Ðøñ}”œœ¡ÐÐ÷m®ÉÑ5ÅEFFª]»v 4Êë˜Íf«íËý³ø>KÍ‚‚íܹSaaa’¤o¾ùF’Ô§O‡ññ.p²æÍëiéÒ¿iôèouâD®ÒÒÌZº4Áaoo“\\LúÏ~rØçøñ\?žh³Μ[¤¾$­\ùK©I}IJJÊ×êÕÑ6Iñ;köì?4qâNã¼óæýîð8ÊÏ/<ßßÿ~›V­:ªŸÎÒÑ£9:zôx©q,]š ×_OÒúõû–èÉÉɳ{MŽ®¨j\Jï ¢ÝqG[íÙ3A¯¿Þ^~~ö Âßv›ŸÞ¿»ž ol®—^ ÓÍ7ûXõ™9óFÝygm›±Ú¿´Æ ³Ú?vl»ý‹ë×Ï_#GÞl·íÉ'ïTlìXÕÈáø{î ÔgŸõÕæÍäï_sÆþúöÛ1š4)Ôî˜1c«aÃKs‘ ëøwTóæ ï¤I“Båïoû–¦^½ZúôÓÞêÕËzà’®¨J(Å®”âÁõ"77O§O§(>>Y...òññT½z5U§Žo™ÆççèÌ™T9“*³Ù¬zõjªaCÿÒ–ƒ¬¬lÅÇ'ëÌ™4yy¹ËÇÇKùw‚òälIDAT«zuÏÇ%%¥éÔ©?”§ºu}U¯^MùøxUJÌ@q”âpYÜÝÝÔ¤I]5iR÷ŠÆ»ºº¨AƒÚjРô™øåÍÛ»šZ¶ RË–A—5. ÀO~¥w®–¤üÕŒµ$ø¯¥x(&??ßÙ!8Db\×6nÜèìULh¨ýu ,,¥u®ä«  ÀêëJPŠ\÷Ö¯_ïìUМ‚],ž ®‘‘‘΀rQÒâ¹”â  aÆ>¸n\Ë PV™™™òõõuØN}pÝÈÌÌtvT8ûàºQÒl®ÔØ  !±@Bb€*„Ä>U‰}ªûT!$ö¨BHìP…Ø  !±@Bb€*„Ä>U‰}ªûT!$ö¨BHìP…Ø  !±@Bb€*„Ä>U‰}œ(**JQQQòðð‡‡G©ýIìP…˜RRRÌ΀¿ªâ³ôsrrJìÏŒ}ª7gÀ_Yi3ô‹cÆ>U‰}*ATT”¢¢¢äááaUWßÑ~GHìP…˜RRRÌ΀ë]ñÙø–ÚúŽö;ÂŒ}ª7gÀ_£™ø¥ÍÐ/ŽûT!$ö(GQQQŠŠŠ’‡‡‡UýüËÝï‰}ªSJJŠÙÙAp½(>ëÞRCÿr÷;ÂŒ}ªfìP…0c€*„Ä>W **JQQQòð𰪓_^û!±@B}®@ñÙõ999åºßfìP…0c€*„ûT!.’r(“\Iœ(“.f³y®³£¥3™LŸ˜Ìf³KjjêFI½œphsÍš5Ã\L&SA~~þI›°ks~~þ“ÉT`²ì1›Í.iii˜Íæq’ÚIrw^|üååJ:`2™>ñóóûÉd*¤ÿÙœ A:Q$€IEND®B`‚qtrvsim-0.9.8/data/screenshots/intro.webp000066400000000000000000002261401467752164200205430ustar00rootroot00000000000000RIFFX,WEBPVP8 L,P¯*®>1‰C¢!!ù½ô ²·{òýfÁÇSÿ—^¾~uþÿÉ/š±ÄóÄÿCwTçrÖO?ØÓeºê ³Û‘¤ã§û/ð¶žO²O¢ÿ7þ+ö£û¿îÍï!ö¥äo¿þˆÿÿŸý7ßuûíýú¾nüþgûßù¿÷?á¿üÿêû—þKý/û?ò?ï?®ÿÿûcýgý'ùÏpçÿÊÿÃÿfÿþûûçÿÿû?Vâ?ÊûÇþáÿWý×íWÀŸäÔ?Ù{ýðù{ÿkþçýOïWË/ëÿæÒ¬ÿ3ÿãèùŸöo¿ošoøÿ÷=Ѿ¸ÿÑîüsû‡û?ͯ‹¿ü?ç×ÿóÿ™öýSý/ýÏóßëûý ;þÓÿKö‡ÿoü/ ú> îÿô{™ýù÷_é¿óÿïߪŸØÿâüùøÇê_пºþÃý‡þ‡øïmÿùÇé_Ü¿Ëÿeþ­ÿ7ü߯ñÿÛ[ÿ*¾`zŸò_ä?'¿xþNþ3õOéÿÚ¾þËÿ·ý—ÆÔÿ¼~Àÿ½þÞ?ƒÿ°ÿtýþýûAö øßñé_Ö¿Âÿ|þÉÿÓý7¹_ï?æn½yqæßçÁÿªý¾ýøúôËãŸ×?µÿˆÿ+ý»öÃØÇôÏî­Ù?÷|£ù/ôoî¿àÿÈ…þµÿ»ðøòëŸÙÁþÍÿÛý_Ü¿Þ?¸y$}+ü×ûò¹¿å>À‹ÿ.þ×ýÃüŸù_ï?ÿ¿Úþ*þ»þOûßú?÷ßßþÿÌø­øÿö¿ô?à¿ÉÿÏÿ ÿÿþçè7ñŸåÿàµÿÿ‹ýÏÿ÷ýÏ¸Ïø¿Ÿ_@ÿgÿè~ýþ±¸üüÿFRªÄhc!_6Èfj›9) åâuŠyçÌ: xÙˆ€¥ˆBÚýOöq¾óœðþ{ÐÞc…uA¶ŠühÏ’Ýi^½×Ú¤¤†×¿€¤<¾f?ßÅŸ\›bÐø‡µN‡ûÁq£V¨hkgÔÈ ¥‹ž©K?=S .–,~z¦@],XüõL€ºJl„^A3æàqd¼Vüÿf™Kwסªo™ÿeÖ©÷sß‚úÍwÿ(«ÔS"PM="Ó§›Úú8¿M Ÿ6u,6Kæ Ê(¤¬ÏM]ûCÉE!°’ÆÏé`÷y(m>lê0Xl—Ì ¤¸­‡y(m>l$áYþ6\Q8ÌãÇ¥yŠo–¸>á9 !«ˆ@lgк”Otm¶ÝÉÎy„\ô”y³ÄzëcGEpåÐË­*F=¨Yè–×ÏRFÖµ—Ê€œÈ9[ac’L»÷CŽ„>Ú‡_]hÛðÏTä}ó°¡í Ã9hJ?ÈœDO!•¯dÜ7-2GiŠ†Ò…²) ¢ôCÃX®¼=~/Xª$ø­ýaºÇéËuâv^ §B(´Iú8¿DÒ·¦'CévÉRâ{ ùØo-Ve`S¦ž³øñ•‡oæñ"rÆ.(¯R#åw¦MÝÆÙÔ`°Ù/˜AIq[òPÚ|ÙÔ`°Ø†!Ô‰Ñ×¹m P^À(b”Ì;ë<`§óêÕ‡l_Ä¿F°@̵|mÞ˜L¶bý¸‹¤~=in¼¿|ÍÑOXÿbü˜à®hý2qtŸ%'H´%o¸#+“é”Ab ñ¦aÍ69üÄ ÏÝ{çy¶7OÜ¿ë¼o’·ÆwYx§FPP[•é‘CS2!%Ål;ÉCiógQ‚Ãd¾a%ÅkRËβ è?0µˆü†@5³ñ6ßj‡Q´òÿ˜JŸJ"»a`™ 'fø­n|ÙÔ`°Ù/˜AIq[ñ]´ù³¨Áa²WrgnÄíÚ }ù5Gmû'ɼ@Ä%ƒ~Z·ê÷Öó:Ì›bKrô²VÚô>hûʳÐ8Ó5ƒ àlLÃ0»®ûϘv­ž¸væ t÷‰„ZÜ‹ÔfûƒÌ‡Ú+8´“T°.ÜÈ*…1¼E€™_C¸M¼8×ð åú‚—mÿó1ÞÌè:¼‡+óx»ð×é ÿþêüæÞ¦Ö8¤º©YŸ×ò}o¦c¾3fŒø¥¼•&¬Y9kB†ÂÍÔolñWV¤}'C+×CüŠg)!4• ¿]o˜bŠØ1géWI*[“£Šàw×Üå‡+# $³15!2[|xEg÷#3Þ¹ž¬Ì:.*_ÍÙ¤Ôr~””LV‰¿½"ßQ²_0qiï2»FËÒ÷×£ï¼Ô^—EßX)Ü÷ÊžX¹ÑÕfȽÁŒê#¾ýÙì˜#È·vd®p~ç5@RîòPÙÎ1 /!·Ê:H×Ç/øÚü»H]Óœ øá¶MEÖÒÔI\4´‹!«¹Ä¹x s|J 7ª^?HMv®¹`\¼-á¹Péþ¦ýeäËO·=VÚ⦧’4²©]Ê=ÀzO­Û_Êm@OhµícÎÉAEïe ãÿÐ+né±ì]»­QT‰4qŠ>¥9DÏþÍ>ö쳸{l w¿¸úàªè¨‚ Íwä¦èm>lê$¤™Ø¤QbBúO{~÷Þ‡Éâ‚¥e=¾ ìC[­b]¬ŽD9Ñ‹´$=Uå\!z…Sæ v…ô4¯6u,6Kàh$›+Ò‰o|Afàd@¹APHÛlV•(Å;% ƒóHÖ¬²qŠ …§ÜØ _0óhò © èt¥×“6þÀŒBð¾0wë&P!ĈÇT)øŸQÞ°6Ž's#dYrÏÞŸ©Å¨/‰œJ²òWôG×Ű"¨`Àa|Ï/¶±{c/´„½B£Pr“,I¯¾ŸJ’SíÀ)Pˆy(Ù‘ë vŽö/"(³¿=S $¾»ײí?¼œDý4µ7QÄ&ö—ˆ”(ŸP}6LöÕjz§ÊG;&Ø o@s`½sì‘¶,~z¦.¯:lÊX±ò=”¤*†½®þ†±Î"^F{4¡ŒOòކ»QÃþNpNÎ}p:LŸYн;¿Î“‹A-I™`F½“_µ µÓ²îöK£2œja(cÜw’ «vNý†A’åh±­†±E[­nœ¬uBPC $-öEqè´5²”q®Ø›@:Õ«:]ë¾­–ø\Ÿîï% ¦«.Xl¢ùϽ4dwØùñ?*ÌJm>êœÈ!díÿñzù< {‚Túçæü”6Ÿ6u,6çàÁtó¤§Âåt'0m÷K¹Ñ£¾på¡J.4‚8ôRˆò¼g‡[1¼™Ñˆ.?‰ôn';RòÅÑ–G´óH%îH9:µÒ¨¸õ=ið5G™(OíÓV&àNM(šˆ”sÑv±U,*À&{âÝb{ŒË `ÁKÃÉk  F:`G.]ÞÄãöO—ʪà¥ÝÛ‹6!…™u¾ñ‡¢oa"‚¡¿–ßÙl—ñûôBÊÍž;ë}ßÔ‚Ý)VU»p…å[§Á¼nS 3(2vþ§>°®åH¿ïûèŠ+±…WsÀðxiûQ[>ÑöX“²DŸ]‚¼³oa¾ÉbÇçªdÒÅÓ@WçªdÒÅÏTÈ ¥‹ž©Kz×yÃ̑ťüy¥g+ øVÔsUz>î²æg­Wÿ' xîäÿ™t`mUÝJÔ|;mò°Fµ„‡9ÚUÌݨ2*2ë¿?=S .–,~z¦@],XüõL€ºX±ùê™t±cóÕ2ä ¡âOnn­hŒÿÕýœTŠÝ> ãr˜R+tø7ÊaH­ÓàÞ7)…"·OƒxܦŠÝ> ãr˜R+töûÿê‡wÈy¤†ïþ-©Ôj.‹$Hõõ;˾æïyvlñ9”O…ywÁÝáÿJZÔ<ê;ðk«^æïx§Ì`W,YH#*݇"豆‹øî©D˜HX±ÊÅà¢ÊŠ[ù)Ÿ'âã´=kY<¤r”¥fçw„Õòš­°wvÒÚ]6púu’‚ý¾G&k÷pØ›!±__脳'@N†AÔ0X´KN3Ã;1¼ÜQkx`°´Ñh'ÀäÌÒÊí0ü5lˆ§—’²­”*Á¦i]ƒZ»EªiôÀî^´T:I2`Bã«û‡‡aëŠðÖÜ@nu½øÅ@¦†´›-CÀñiIœ#S_*—î–EÑóg·aÈ®è :‡`†H"ù‡"èë·mê¸fÇôIÜÙHÿy*3pI-IÓÍ®.c.²`v-¡»ë­›<©<ȵkÁÝâ.ɉæ0Ë=S .’KT.,}ùÁ¥G•wD¾bZ}€üö¹àÇœ<¨ãNXÃPÞ!­y‘Ü4à ŸWô¸îåðÌmËÇ¥Q[-“ï$oOƒ ꢯƒ6È«ÁÕè•÷½ªdÒÅÏTÈ ¥€Ì¤Îq[§Á¼nT# žE¼ò%5hb_›=»EÒÊ·Y¶6Ñœª4Àq=™±žLjh EaÌæ™™‰ãtÀ*Ë©k…:8î±UU;£õœÐp6ö_F¢bâէÈqK?=S ÷žz¦@\f¹$ÀVë›a4“צ¯ïþ-@µ¦^°‡ùŽtà4fU,ö¼ÍÞ òï!`ýÊvë# jñþ¤×74FP˯ŽxÉ -CûÏÖZÓý¯Ü±•MÝ–ž×uÅ7MqJby>¥Zæ[­L€ºX±ùé@Z™t±[é!<:µŒ²ç1HûæAòXêp•äö müÝÈ:Ê“8¾¦ˆXü¶>¿=S %Þ;È5<Ó®G…”ô‡çt°q÷"$n)|§$ú5S”%l®Ïg4­Z„ §YL!$ΩKd4]Ü#S (ü¦&&à™5ÛÑcKù Ûià†?0ô¦Ù—gæš'’\+ûîöîòf•õôØ5O!Ù'Vå0y ½a-+uá³?ˆ™æFÒwbá°y á‰Dê3àP@À`¯(—0MX`‹#®|ÝW¬"öDz%?ß2Œ;ÎyòébÇçªcëåRýÒÅήìÀ˪ M¹ˆ6šJSÿ~ñ5 TƸ'ŽJ— t®ãŸþ¤ƒ|væ ›¥f§±çv‚ƒËP¿l |,B··EöïÍÞWÅYßòé:ôdz‡ñ¦Â¯ ½Oa¨ò  E¶*C€ÖXÆÚO›µÙ‚„m pv2rr}&ƒàN;¥z«ÍÉvÞY‰ÿ݆(ó_” @],Xظßöرùé¹™¾™„ Ôô¸ùHÈÔª¾ün)T0!æi|PAP¢míê›@ƒ3ë¤xPa• WLˆ3³VÒ ßûp Òo^Øȃ;5m" ÿ¶Cà«b¶Ñ=%&]ˆÖÆÖ•IRæHÓz‚Ïg߬æÊ¨Æ0Ê »ûÝÓéP÷!µw)…Æ”¥ÿ«‡ªdÒÀfRgÔÇéóž¨ò¾¯†3­ºÒEëˆÅ•¡:BXQ²tÂj´í©Ýb[,x?² ô{÷5¾P{Sæ0§QªÑ†±×ìy=Y+åUºsع†§7~nðÉ «}xBš’ œ¢˜uRççÌÙâ›_x¦@5³x³»Ì2ÕKdHžŒ’gÔÈ ¥‹þÛ?=7 “7Ã2 ¥˜Ä 9UcF-OÖàorØ^ø!¼!lj—¤UnT[§±²üßDFseÁ]A&ŠEª8Ñ/W+ÓÄê7`Ò²zá]‹J™D.Šþà3<ѯÉó8×fb:éâWîSÞU3¾éòPˆJRnÅõj ÇœçAõëF ~%ð6õL€ºX±ùê˜úùT¿t±có«»02À:¯oÁ¦ØÎ/¶0f2B$?dñÀç>ï¤B‘¨ŠÇ9 ƒtƒì—T嫲 åÊ·aÈ­â.2û/É~¯Q Y§£–“{®ÿPV•НÕð$³èÛa^¤ŽŒ| Yq„ío†æQ~z¦@],XüõEUÅùê™Gà511'ð@zù·0ÎAaôu¸WÒ ˆÚOß’²:3ßä$ÞÐ}Ê`Ÿ‡vªŽò¾£Ò° G·aÈ® D¤ ã±'#¡àÏRѲ§Çãx `ñKlÈŠFlªÕ1;[á¹”_ž©K?=QUA±~z¦@Qø LLIüiEò*‡‡õw— jzM»åÝ;Õ¶ø2Fi¹h v‚o·eÔbdâç9é„…Ì;C¡@L×Â(/üž øo‰OÃ@ÿ. ÔбWŽÔÕË“ÑàQ½J ú¿mxÖû71 c%´ÔÈ1¸×sF¼¼:×v¥î¡À°uÜuÜ9w’Äœý¾|Qº½!Áß‚u<êdÒÅÏTÈ }bˆm‹œ¾-ų炙sÆ Ó}Ð0O  Õ¨ÑGû'5¼uLŸ•Þ=ÍÛ@©\²¿4Ç÷Ü[Ù±~ âBÀ¡®üs¯;91_”HŸm+–(Q0+[“<<©Ê“JåžDŽ"yàÚïyžŒ@],XüõL€¸êy+’Lßï5×q¢¯TËçú÷j-œè“Õv9•ÉÞ£T?ÍpÛßX“VÔ:Áe‘n÷pîõV&ˆ]UM³jðÜx¨Š²&@q%„Öú E÷Û4ÏJø¡°#5¼‹"øYD´²ŸDRa àAY¢VJŒYh}Ä LñuX Ù/æY¢Ê¨°”};vH˜ØŒït}gƒIœ#S .–,~r­I£Œ@Qaøí=]÷Œäø,Ó/—oólÉ¡‚CKaÜb™NGèâÏipL#b:ÆŠ`gg²Ëªú‹JacKnî;YiTwb l@šÓú|!Ò_­¯6U·…‹–Tªç1$V"¯›ç ‹Y®Ùžè7n;½Ú…AàðVßJ›/Ö©áö˜B¨·÷—çªdÒÅÏJ‚ÔÈ •ç&ƒ†öOÔ …¬È tA —lsuÀ(|Æý$ér‚åüÆ„$¡8–wõóÕ–UkÄÿޱsâš.okoaþ“aKh¢o˜¶/Úc7­es!v:¸áò?‚ùh aYžk]ñ æèûà{ˆ$e”¾¶3 šT4ó~IuS‰ßÓ­lCl¢nÊk¥4T?ûØ#þ–yMOxÀ”#ždDàmê™q'uñ–ª¶ j>AªÆ‘¨6/ÏTyOg§Ék$µL4>ðÔÞjcn k«ö2ùxƒ±Z¿Ey8˜½òHœ§Ý¯ïç,EXãè"Î:·«½ÂsFWضü¨0‘÷e\‡¾oš86>؆?§Ó·>ñBùXþ_l C¦ßöóÀ…àoà}L±Û~‚Lá…­Õ)“Q~ua'G]¸X²“æC^–+TRO/}ÅšèG5¹…lMÌÙÅý rÑä†Ît–DËi’g°‚H:¤ø¦!P?ÂQ4™‘cúPï"ø¥L§ç[v.ðF>[äņ·Œ#ÂÐD¸ODÛÚˆ}C *„Ý{šW©¨Ñ šNÿÊ›wâÇÚjñך”d±ï›kÀœ¼¼¼A%Å<ó6$bæ„']tì̧¹Ëím J!¶,rÍæsïZßHC2¾ä R¶[WLWŠ+š\ &­;@ùîö†ã×°Ûá©·¥bÖ\[zz˜JŸÙʪ2ì}ˉl‘§uçh‚Û"à(5ˆÖRò Ê’£ÃyòëªÕ+¬nÁí²P=`š–ÂZéíèúm¢`ÿˆ}QXj·¿ýåí©Ê h ¥‹€/xE˜´0 48½¤¾>À×BÜkV‰ÿŸÂ,W/hZövI6º",žT­U\C 7¢¡"4d±}€FŠ/ÜmܱæÀÜÁü«mxöóu!|†Þä€2P2Qð«)w¡·~2'$ëòÅ3¡hK²³G-%ü¶Є+×Çì'p©fJÞºí(ª{£€tÿåÁdï0KÀ©éð)S²DÐTEÒÅ­ÛáMJ3•Ü4Ý·‰=%¹ëW=±#+¤9Ã^õî­Âÿ £%ˆ‹ì'UúF¤BËу:GØ÷†¬•(hñoy]Õ\#–‘3Ù1@L€Cç·¡#\¤[а 0ùrÛ©/KÅĦ>ý˜dïw±1ÑÎÀzBƒŽ'*D)Z‚ÖüÇcBØŽ%£´?kp¦¦Cl¾^ ¦e«'¸¼ææ’æ•bùÞÚ¼\M¨ÀÆ=Ŧ›©B:èÇ̟IJBñ¸ˆAüÚ±N*ÁI–ûAV±€ý²ÎŠ­hJz~z¦ Vc¹`7 BÄæpsZÇpÁ=öÜÊn³œaU’WžÊ¥û¥ŠÓ÷7Ö_y˜n¨ß[|L}8¸'øüh݇Ðt«wØ÷Vz1·ØQó4P•d}6H„«ñúô ±¯—=ÿ!ëëÌj3Ö¾®ƒâ¨ã;¢Ï¡ƒIƵËí™+ H‹‚íþíÊ-àäðý¤´gÔ¨§DàÀñ¼¦9™÷ªrãÜ£Š[üHÄÒ>žž Ó±FÁ·#Ó)¬õßdzëÒÜjdÝñ¸þ{­á²­¦×¹ ’QSM3Ñú0ÑwpGµÔÈ ¤Š.|ƒ‘"-—FÑ›M"ð¬ÈBÆz0‘…g&ÊÔEå×%àø~Þ4ºõÕêmÈã±K«X0Åúø°[Ì û‘zEÈ);»Ï*NePÐ~Ê ªõó"Æ`ESÈ~z¦ ìYVµ–¨þƒ{¦Uœ?†“øÿÑ;榣 - ÁÄ8A ]W(ë«Æ:dmuÞ@Q²kÒÅÎLgÏÿ÷tø7ÊGQ¾àÊ<·(¤Véðo”Ÿ##,ú2TŸ³ÒÝ> Ö›ýt¼ƒc‹ìˆù[Øøåa‹­<1Q"G¿¼Ç3=ÃvB%9|aù §£dhú(µ‹k_ÁœTL€£d×¥‹ž¡HAä÷9ªëƒÕß„’ •Œ8x+hgìºÈO9±8P˵¬³«tø7ŒäZYÂÈ·¸¢uk,#ò2ø£ôâtX¶nŠB匯~¬‘¶*0ú$?¾övâDŸ,A¯YîÖ…f½É~¸–³'ÞÐikQÝ~ßQ7aWú¥G@‘Þ´Òg}ɪªúµŸGGùì±DêÝ=ÿYr˜R+tø7ÊaH­ÓÚ•dcyt±cóÕ2é_×ÛøB7½çüù"pA†e¤7³8%½álüô²éRa^ MD³âøÆ‹»„jdÒÅÏTÈ ¥‹ž©K?=S .–,~z¦@],XüõVg˶xr)ËxBèGÜQ:·OƒxܦŠÝ> ãr˜R+tø7ÊaH­ÓàÞ7)…"·OƒxܦŠÝ> ãr˜R+býÁ÷ÀþàxÎK‰âïa ü¤½m{LvᢿÚˈªÒ2Ç¢ àØÐlµ&€Å(e‹`Å)Ú$ìË“e(&õjFFÕaü nµV÷å€ ˜ûN†‹+q‘ƒ‚ f}¯u=¶>’ûupîÕedY`{;|T é’uÙ'²UçU[QæÙ‰}¹äF DBm˜XúAÃ5ˆÄƒnö:Sõªë­ û.<ÒÜ=Ð|^û7û·¹±Ì@vØw$³S.¯) k¸O5*ŸÀ !\[)om] {اr„ò(Œí6#\v\wZž·MÁ:7·ÀäõÊMœóþà aMÂé ¢ í1÷Ë‘/ÅT ,°|Ÿ/Kß4ÙÁg¿êiGQÁB©®_…BEc[ãëïÕ¡þ¦Ô`vN {ÙÈ’8×L]k;àÔ˜€*×iŒÜÞnàätuÌÃ)Ü›‡Ÿâ's”5!²«åW#íJM©_ÇíAgÄØpÿ5>K„/sGÅ€{®6¨‡|Í'~ŒQžCÍcØaöÑ­ç¿ÚÄ>HÿIò²\y°Aqö¨Ów»`ö /¢Ì‡ùö÷5ÂnƒÅ „æl2Nã3î…fFè‹"è¨ëýEÕAxÚÕÉ|‚1†Ø¬“ŒxýÄTtÆi[¿BzÖaIÕ‡—ü}/¤é€éh¶3RB夳÷S¬ÒeúW½÷V†Z»H„Ô§ÿ’¦WŽj<=¹ Ç5f‰)ÔJpS-§¤ä/R:÷ÁhÿæºÂyŠ5A¿­Àk8*åWwx¿‰¹kÜD¹´Jj$lvWZÁÑ6“õ0Š[qí¬x`T×ê4ØÒ$7ÙáË’YRd£"2 ’a,&x=oˆët2 ^êFKËżŽjdBdíC€Rô’‹^V9e´@ß$,Û:hUðŸúÌÒ¦M@Tlô½X JûW cyÖÈ["hpv?MápÿåŒØäÕXÀ# K ؘØh1 ÜZTXÐ2V£fi‡…»ÄX?@¿MÑÆö"`ì»á'ÅÜy­báZ"J‚äe4bóô¹,gøÑˆ›¹µãf± ÅN{ö“ÔJÏóÇØƒ!wA3GGÒà#¼ÙyåP>Y ¬öVA3Ëúákh·ró!, YÌ«ÍÆeÎ]sh«SœBmËÐ6U®ýo/Ëf²4¥½À3lß=U(á³ß(ý¬Ô¿V;V{¾‡T׌‚ƒOÅUŠ·ðNV0’O‘xÊu¶G¬$ã²æe;†Bqõ–çDæ’P‚ʹ%i…ʸ)Ñ êm>Lç—?Ø^ ¾¬*¶£8ˆ2ŽôPRx¢%ÒW… R†ÁØÊ©ê{Çgydñä.ÙN)èJM.L@õrýd#¯æ/ÌBä2u»ÞFˆŽZRà*|‹ÃÂÅœ4îֺõÐñ¸,½J×öÝ–Ø©§zú‚}³_ƒ²¹ifr«¥c-ƒã™™òp—Þ›ÿ˜­|^CÐ~§9öä»Góî-bˆQû‚ß)Ï}r­Ðê«9dìq É^ÿÌÕJwÒL?NÖÁPà>u‹aâ;=ñîSž“4áÓSzÖEÜÁìB,U‡$Áw9s€ÂYoPE5NàÃ1°Òüй0úÌä‡ùÓ,ŦqW)*QÌWž>ÒÅÖe*x÷ ÜóK2 *ß©kò¸—öu}µ:ò!<çK4ô*2ßê¡ß™Çéá¿ëÛŠÆû‹åñYy†‰ƒ¨1*$Fa±Y·.ûP /cÕè`B8fCøPþ¨¥<Ð*üi6°y°SÁ/¥"ÙY¶zN¤ŠcD5âï“8s£IsýHÜ·‹ïµØÉÒ%³¥ó|÷ËÀÕh·Ô]âRf¸S, c(ƒ¸UúÕߤµŽÍÜÙ›a)Ôz1ÞH´ãLÈ"LX—.*¢7*ÈçD•ØÈ @I?Ÿ«~? \t§ß„¡æ?ù#¾?»aÉ]N<ﲘ¶»ÓÇU“ qXÃ|0Q@Ú„ëÅûÅ£â XrËlÛ+ªgå5œ%Añ÷ú*Ì‹½}xÀÃ'ëäÑE¶•wÊïcÿàïiÖ¹#ïè9ˆ9Â¥·þɱȒ„ÞÕ'вîe ‹Œ2oÅ.¦½¥’5‘´ß9P°AÒ­e‰…Ù\ÎÅ ÙPàT¤Kjô›•MüJÇ$IsÀp~õ?&" -b‘ŠVyr[‘QÁŽ£$”´«šIWPR%2W}:#ºw¶C9å'mTað0bNÁ^íx\/pF+/:þª7>HÆ®ÿ1LŸNFþt1'­»ñ/ƒZÔYÑes€öØ{Ér¤ )É(Ó¯ôÁ™ç·*q9¡ø*Ý-ŒñhSA~ÿ åBÛý(r0èr ç‹»…Ó´%$Ë]JCz»h>#¥ÄR¤kq+®C‚Ò_ >'zª5„ÙxšÁ”[)`Ër’Ñö—÷Z`cÑ0¸õR¥Õ&Ðú&î­Â§¹PK9ƨA†ðHì̱ŸÞp ¦í•’a¢¹¹C€ÇÛ“¥ýàBn|g:Û(Îñ{gu‡Û°úË„nÈp1ùúŽ›œÒšúœƒsÏ ²O§y§¾Ä¥¿s,ÙöfuPÚÔ ·9ÝwÝC;Í g{v:ÅÃ˘·ÿYÇú RªÇ¶•ç£ÀÛoºS0Ÿä°ñ³2&.Cü ã«ûŽ«I‘¹l [Í4¬1õn^œê3Ý ãŽ5àò3¥ìR¿tñûåÀJo7uKI<ƒ ´5|s¤–$èh …è ¯íEƒëÛ8½ÇÝ‚EJ΃Dt–rCeq½ÒNŒìïÖ¼›¬áÿÑfÍ|ÀD]³&’NLÕˆRS§-uho²ÒšRõ€ænÙ÷ÝÉh«§%s<=%óîÍ‹Þ>Ç ‘Íjñðž}X)%édÄÞ‰|©èr1ÏPM îU|.t]¹†ÍSŒ‘ç yÔDÕ™¶Å'z>ÏêrHÑ@D1ä‘̹âT§»9=¯c[öcò‰S7 üè™\ÿVÞuaô ·NÌ|)Ø1,ôåë1ˆÚàÂÈÄæe°`’®!Yïü¬jÑ%7?Ñ«QèÜ]–Y‰È©m¤Ås7§8O{Ò%²Š’.göÝH˜ò×Ú%Qr|Ř Âì©ÿô_¼ç11nÉŽïj׿æ/Ôymp‰<½Al‹n3ÒÖÁ,à Ûݰ$á„•ôeÊTƒ5O’"Îùb‘ÎòÛR(Þ®¨¥âXâîjy+§]j¦kvn”À×,n—¦\wmÕ ûe"Mx»Ïµ#@ÎLqÄ8•O+ä@?ÞM…MÝ.4­â‰‘ªŸz‹Üæàî¸ÔBÿ-ù»5dÂ$à3ñ2vÀ0U<øz {¸FäõkMïbã‚F’z>-ݬÂU‰b4YGÆW»¯º¥áƒÚ=;õ¤ôB;QèÎÉ®ÔùDç*ï²Â•XETùØÐÍÊß«~Ÿeé—jLÅ9MÞI¿Ìcåî¦}’PÃì*]©›:²"Ø.È—*—9n,©l0]ÿ~󭩬«¥G3Ö7(Ù|OV?~XùåpøÉX?üé‘$ã-Hp _m…æHQÚiõ“O ˆågï.ͮӜ0ûEvá.‡–á)¸ô)³U¦ë¥)ŸìèóîᇗÉvq¡§ÿCÓðuš9–"^¼½ (Ä4~}\Uh<6`nÆv`÷‡Ï‡C¸ïlé­0ã—F¯#\É“­¸t dûr÷ó0­]Règ©æy®ÄM #Ot˃hWYO o°­µ'ç/ v‚%ê<ß»-ª³mõÚ® mš×–/sB5•¦¹Ð³ƒdçÒ3ûYGþq¨…cÏ䧯ÚwRpÝ~…é?éˆojC–¼Ô Cj]ƒ2T…žçÁ6`;)É'ˆ;ÏSíÂ¥Mw›ô MÈÂ=/†<©ZF«Ð‹.ו}8*äž4T ×Ò1ÿz(‚‡½AÆ€ê–-@ì~’ûq$ ¼£²¤ß˜?K vº3 mW ÂbÐð£w´"Á›Š<ë§ð~p£Ü% œ¬‰ Sz½Koî<u\Xå¥áDô’›¡\bż-ç Í/®GZqI‡;pˆ·p½ ƒË•d&Ö,Ü|ÂÀZLàVØkªÂó†½x¤ê€,î˜ÞJXKø©‚á×^²_x6˜aädÍð„£îæ/ #—Yg!ð=D4É´Á6 ?Áø<ò†`ÑŸyù5±‹ߤà^ɬ Kž·T⑃‚ë¨ÕTÐÿ½UQ"}<ög$D ïÝ]@ÂõÝYÁj1fn÷)¶KñHt”IœCyH6$ô«w ÉÀD%ÂP‚Ì\ÁæöoqÒ.~34¿Š¢hýé’L5ÖVBÉí5²î?#µLÌJr¾¢Ór¹ ¾7I¿B4Ò¾”3m#Û¢ð??øi¼L¬#6U·?´)<É ”qsÜ?ßzÐ D«2÷ôLa£å7ÂIß›‡Óâá“XyÿAZ#ßê!d. 6HÒÆÕ@ÿªSâÊ­Í‚±Iذn ‡‹huš¾†à¤é¾]:qð¼ü¿ûümS}¼Ùb½ vÏ3[ú(Ù vìúÙY¾ËêÄíE­G…æ4‘Lò(ÑýTÀ¬Læf‰ýV²bâ:“—žO1ßI£éDĸ“Íï¦PøèH¥B•vö=R÷Ü0ü÷Ð߃þuð¯yz>_L©ÓN{ÇZ@È —ÙwÔ:•tÕé aåQ”Rí‡ucsŒþ±Ï ×ò{ä-SN œcT©@OÚ¤Na‡Ô?P?ý]8ã©¢ì•ñk¾†Î¬[V§Ñ¤}Û`Ρ# ô"‡*ËÁ(ßã»ÄèDWûßã5÷Q§Ð±ÎèTš-E{½0¼‚âpîÿ¡¤>Yåûõ©êUò5]«K«ô›z&:!}‚L:1’Z‰]»ƒ¬„—/øÛÜÁæj Ÿ!£l.$TÏQp»°65¬MnÞ)_F¹ï(»Á™þÞ-Ó–œ¢ÃÔâÈíã°PDCŸ=RbB—[øèlí4ÿ`#Нùònï¹€š ªR7,1•”ÍmÜlºwÉpú\…;Þ‰´Å¬mñE¯›!¾÷ç°i‘›+禈V¢‰ãî2ë­Ž_šÖݬ¯¨ý:"Á±Òùµ„K,¿˜ ¿B—üƒ¥êµÉãT´û±vÓk_«Q¢|M¿eÇvéWX‚µÆQY›Í› ï…@^¾Ôi¯ÄWw7n"{]Ä1ß.¤ùóâ˪Žzz±YGBÏÂÂÜoÆÂ?+€‰nІøæMûÃæÄ_µéU ª8§ôG’ʨ»Î8× Ê¦'%ÎÅý|ó$ú÷+’“3"otô«Q P(¨ævŸÍzÉÓÀÊÃt.M¼÷fÏ•à¢,Î-³Þ›ë;ªÐ&1ê=„ˆÊ› 3)*39[»&ÜõY×KÃß^·5Å›õr%”³„198:~Ã÷TúÄ1ÞÂi‹‰´»L2Sâ1€äío42ž ˲¼1‘Y-ëg¶ä¤É˜ë¸‘XK¬È'‹ŠÌ „˜Yw!=‘¿ùBKædzºz»í>Já,üiœ·<¢ã°µ«Î–#38Þ'§Ã=¹{Gqx]‡º³ …È&€MŠÐ”a†úç,˜¾$]™™ôVBÜŸÔBÜó1_;ó½·¸4ßÛ ··Ò2ÓºX ÙϱHô(&×6¨óÑ䧺έ•¨Yœš«#êÕø+gb·u' NS{±üsœ`DÝy¯Zaö‰Ë©ÔNb×^•/ÉY"²Å5ºª¼Œ+C·8.Em)UõÞ·6 Ÿæâ9Û|L³[õàf­–6žH"+®au´ EH2l88‹ñg`gi0"Tœl8ZP#jµM›¶õ“é?Ê??1Ýš­ÚT"Ÿ,Y¦5<ÂÊ1Rგ[âdQSyŠK© }UY *°¹ÙåÛÍ&¿8(v'S ”Ù:¤(¢ß\U#Ü_qÌ ûœæHHB5éùàþÂr'ö±2ÛòßI,?[Àšø_áX lиT/?L„qæóF)Âdãq;äø'¯‰´Ž€g³¡;²IzɸҶ(T°mlµ†Zý—Wu}ZR‘¾uÍ„äøæìù0Å÷]è„ÇhÝTƒT-£ê²V&[fûÙ1»ÓP©Õ¢!™’š¨_ q®2•Üÿ­doη€›hœºW”Û^N麭±á=õNƒÆg#ÀOKL(]¨í*׳ æZ<’i¤ÈE“æ@&Rí Šä¥,®{5Q9Ï—›ì¯Á˜ù f™WK±äI4i‹èùñ(ßB"Ëd‡åòÁ±ŸÀÇD¾ÄÙŒŽ–`<ƒ`بÌA¥ivXß*Øk_|7Ûð“iœ•—þ‚BZœPÊQäéf³ò0S øànA&Ñ[òZîÜKøT³S!r'¾Oš­ZᾸöC uXýÔ¡NáЦM=ÜÉd1ªæAwt-231]9ûbé>¾LûÕ˜e±8d L]9¿;J'jÖOEº·P x7{8.sá¶…7A¨pw*b¦|å—ŒSå'¥ågí*>ÊîÄ{É.f¦1 0$±‚°DíLW>U’;0Šù·4ÊS(Ê-]8œÏš6ÈüåS}ÌêÀš\ ÈåWˆ‘‘{A~u¶ÖОW=½%XÜ軣#à7ÜŒângiLKGÛù1 €º±ñʵòxåôŸY¯BGŽ+¾f1ŽÈŠCÌ ¸?‘eàÆ¥Æû(§ak_’Ëÿ)Ô Ï—ÇÉrP³¢¨áÐ!¬KZ _þ[1›M2Ÿ\žã’ú{œsôúZž·^çò!¾¡]n2ãdc—ÄðÔ)IxR’ð¥%áJK”—…)'®­™IЗD2†Ä¿ñxù튓}‹M%eôùÙÛì)–½yMÓ/t¥Ã¬éŽáñ\\ÊC6J¹c%.Öu,5ç¥aA½®á}¾ Ê ãbÍŠÍrO½8¯¿®ŸEqáýæžØ¤~=×0‡¶¬FÙê…c´÷:™,±&U­ÆqñèÌ0ÊF¬^‡V”øâÄ«ì0¾IÄÉÿ![ýZòÖe^C²jj®œ˜Í?UýeµDÙô²fCY:!kç¶‹«À†røceÓ%ä€ð¢'ÄORÈÛ1ÇJÜ*`ef5ø;=¾trÙV]c7Ì1Á©T‚ï“CÞÀεè`‡ªð/ضŒ§¾ä‹æ*ˆú¦Í 3§HÊÊ®+:¼èF£š…=™óú¡ rµg´›6ŒëìÓ_Ÿ©ä²¢£Aˆ>Óæ®8ÁXŽì 'K¦-9D²JÅšÕÃ*úع+r•.7%®ä{i`Â牕ˆzàÕ67ÏíPœ&½ß8 |ÔÊFËÃ0ZhŒf¥x<.b Ñ"6Ø2¯~îëË!%¦U_°~ÊùŸk2úŸ[}!«B‘»Dt„Óeuõl×g Ìü ’Ãöä'ض -§Éݽu¸6'V„uäþ×,¾ö–eŸàæ·ý¾–Õœããé»§›iHïO/±ÄÆ®NbIEZØÉÞþSqÔy6'¯N¼ÄÙ©Ë¡rÛH ™É¶”ÄhdO¬—Í× 3-y/ÉùfL­³±cûb=º’ðÇJ °(ù‡NXë…‘ò~žtØZ` ›K•ÑK’~ã…í7²$NkoÙtmÞ¿èq…jàÄs§¡Ø6¥\¾ŸËoäõܧì_Þ]h-Æ™Ò!ÕĽx„W1$»ÿ<‚ýÏmúý‚¿¦jÈ?ßÜìc?|–iG‡3¶Aêmæ3Êåxp³j@Êba»KkÉ{æ8‘¯!Bå//9œ¶PsŸ¿ÝVld¡ÕmÀ¬#ít±*`´0†S õ]ÚEß#Ä®Œç4°}¾<€9‚­~6O$K^(”ŒNQ‹ž¢q¢…Zv„…§¾âa›ÛO~'«(;wbÐî0óý•¼Mù§V„~Yãå¬©è¥Ø'¼C=„ÚÄD_ÃrrB³ùÔkäW€…FêY)w"7ÕæˆDôžœêªös÷|5y-ԇݰñΓ‹#Q†jíÓ墎ÞXã¦ëÿè"“CiïÑ|zt±xp÷m|—$tìBíÑ šD™`6‘Ä®ô†’H_°üÂ\Œy̳"cÉt¶¤=ß[É0ÎmXAÕà ¢Ë´Š¤O€½øÞ»PÜí³"Îæ©&oÆsÆ“co¹ñ-“P£“ŒtzìˆËA°1-ù7ïfvoÊH\rqúyCT÷›GG{<Ùq¿=OüŒŽñnáçNïcIÐ^¹o»f±]60Ù‰·T¿žFëXpwÆâî:¾Á‹Ã$µ Á1cnt`±wÿ4vârÀRZ°È4•,¡™n~ex Uc_šÀ©ÇŠo}W'3‹š$x]Û#G:k ¯¦”—=AÞ`ëÜ ×»±R+GX-Ó˜µUL‡•9Š-w ƒ‘i;6;ñd]ï1μt1@¾½™…÷D)±úƒ¦uò«Âæ†b@û*C 5ìD£÷»1¹æÎ§ ’R~³Y`Є4[ Û×ÐV¯RÕËg+†¶r`W–º‰-“Jæ¸lŠ®ý‹Q?'^!IÆ»Œ³]*oœÞ@OÕ †Êwû´²™ëÇrmÉ>•m{Ì™‡¬¯»½ËÃnLõÄ·”Ó ²9*ôŠž¤·ÂÁÎmÁúžY3Ôdél¥±ª' ÜÜÙÆNŽU7 Ó2ffs§N¯\ˆ¡¸Ž¤Q;º9Œ`ÿ¾Ä,wU …íTÜëZ5:Ob'¤Z†üD·©I,§ºH0…áz¦³š#;¼ˆ©Agòw~7·Ü3:Þ(ŽÄsd®V?ZdO„•‚ ÝÓ¨½!?æÊâ» FaË®~ßI'¯65m¥Û–°·[Ω÷ò|:¶ª+åFª´Ä õ!¿Ð¹iºbë¼û,M„B.ä'LçÓPÓèUü¥1¡ÈÔ´ÖÏ/Äm-²¼Ïó:×ÁŽÛU ÎÍËþ͘“ÎmðèõuèË8•ÀoEÓÎ~䵆Ä&ÆDb/ì6p@IžQÝ1éÓWL‡…6H$¢.bÅ Ù³£$JšáÅæ½Á1Gø#Äñ‡¢FlE±Á•š7m vF»b2ƒ¸£¨¦¬G„!iJÞ9@•þ.åá5&y*0¡¯F¨ô׿‰¾Õø°áKŠäÊZ¨Ñ ±ã®CVµMÈ[‚{‡^jœzU‹¬ êÄÃML8x6×î+k·b`êMã«Â­¨Tœ u˜ô,¿àh×pwñŒ ïOÿ}.ï÷''i‰¡U‡ˆKPf@âÓ%ýÀÏg s&$öZkˆ‡Ÿïýv€ùT‚êônRsF$ïÓ0°ø!¶eå*êûêâoY­ùá¶ôÔuG÷2¥0.YpÃ×…~ïa5\Eö÷ã‚ò[ÝÏqäTdÌ U¬¸ãÑ×8›²‚¨£adzê’bîkhQ$R.ׯ&"¤8°Ï^½Uë“?ž<>'aTZÓ¥kµ,àÛÐõl˜AU;âÚÁ’—Òuçºý[L=AúøÞ8&AKË\W÷qh/ úã/gxv´êâ«»Ev\J¨:ˆ h:ÿH}9jèuÞuxš±7xrR“A€4ùê(‘…NFù9‹¾ Ðr¬a“Ÿ~Bã‘‹¡—Eáp=«J­ÄCUkáKâ ]Žöñå¦ 3#Òí¿OèŒUûú§ˆ¥Ú´õ8‡ILŒV qܾd½ÓxŠl'ÊWþúÓñ½†@†x¨6lf¡Î`6Û4øÂo®îàûª¾Iµ9¢H:4×øFû2ë7ƒB—áF„&JB1O9:PŠ¿cÈŒ'#rÄ6ð iì»Mž;UµzÎ{ê6¯÷“^/7ã:žö\w¿}¸\ƒ<½ Æï(ßÈ¿º /yhî!XŸÿÄ Ø÷`“+r`»â¡Wf!ÿy8ìK_…:óÇ÷Y8ðƒµÄ¨Iõlʈ֌¹l»{AFMŽKƒÞ”Øóp˜‘ç؆Êz‚'ùב²ø½ÊnÆÿ²ÂÒiŽ<Õß|?PŸñ ú‰‘ ¼þhß*Cúq¤´T… U‡ÛO/©±•+NMj‚þe½hžNSB»Ò³£_‘¢ áxcVxŒl½š§ÑºP@â¾iV‘K}T‰°˜Ù³ ¦Z­k´ð`\@üLi8g³×ÓMvwÖ}µðe<ÐV6«þE³ Þ‡MkR¿0ãh½/ºº˜¾É©3¦!û.Xàñ¦7…ô"Æ5Rö¤ÿ‚S!Š^ Tyןä˺íòEÎ'x$óRŽ28òqÞgí&ù¿oö«0N.MŽ#öƒ9sCßÆï˜•Pq†Ñ<ÛžÝHí h#šn1pýOÞ±(VŸ‹|· ¾%YƒK:õý½Òøîµ æ¿^v÷‹A3‹ƒvW=p]k;!IOÔ–+)éñuĘ́¥ ³F´Ê.úÂb7Ú–ÓÓè5/6iQu <É0”T@P¬o¾¥Ë}ÃÀÿ¸ªšk ”=Dv–†Fså>±ÖFî|)}1Ý$ÕG™^»a}g÷·v$Ú3‚vyRŠC]ÃÁ"¯]žm¾Ö¼:vMx™ôÎ;_N¼2jÁ®*ká¿I/°P2~CTÛ+}þìÀtLâšdt3Qì7èìwé7ñ0}‰tæM>nÝ£#·:Ä/ysÊi=bzŽ43»µòíi¿:Ó¾üÐGsœ?‘‹- BÏ~Hå›H-?;à ÁÑ'žF€øˆ±šJÕ!ФSG½Ì´CÉ­P_Ì·µjæ¸w†5gˆñ¸ÆÊ(p\òòIwcfqÌ]À<ž'þëÎnyc¥âèóÙ'ü“¥ · ø,`Ä»Ìz¦ß!; £»¹ÅËÍÕK½.B[>ù®YiU¬ÿ: ±\{”@½<µí‘RÐH¤p_}4D ysòq°Ú&ÌMÞ•ÂØÏýyzƒDÚàžkp¿ÍíÓŒ¤øtÊr”™âIý¯Ð~ê(Êd7‰Ÿ+ ÿkÓ`¤>¿ ²ð9Ô§ÖÌ1¦M¶bý3+†kksLôÞ ›­ô‰üR˜9ý*ötàU*ÂYZE zCÅfÒ OÎøpt@Iç‘ ¨Owq4+\t%¨kžXÿöš%œÚÙ¤­RªE4{ÐËD<šÕüËzÅæ*9$ØBLðð\L©´%µ‰mW‹7«Qw„ƒ=_X©m®£?ŽR»Tæ ´%´_Mˆr³š½ëÓg~–IÍ¡lÌïÊÀdÆcèˆFq™É ¶n'ªÍÛU±Õ@Y¥"™-×§2!¡dþ®(½°¦“væîúwú¼Øºß pÌU‡š¢–ÀR¦R=H 'Ödü¥7'µ[ôE98§ú 2Ð3Ðs³sOÀÂüê#6[ÿ7‡ÇRŒ "È®Âø’‚˨}«+ý×½é[…v¡nýÐO{-¾ù$§©GF`Fy™"ù£ô/^ð«2;f0¶Š¥ÈPw}ƒ„¨-‰H/A¬P€jHäÓXµ¡ê#´°Æáñ´Ï7j§p7Û"ృÿšH¯D‹Á<¿ôÚ7<à¯s·2àäè÷Á„gW‰“ø!óýø¢ÀÄäêø m)Ÿ¡$€š^ØŠ;7} ¥´öY|(ß´/ØH(r íô²÷…÷}p Sñ+ø¹ÌÞBñþEIMC>‘ † 1UP^‚gnäI†ùoÕ3{ûz)°òhJ°ˆ‘c€™&å‚r[³ ^õNˆ¤“—Þ"ðår–Þ³Jð–WÁÄÆ; pDyÒ–B?ÂoÅÏ>6·6|Íëï}‰Ö’ûW'Œrzf…%•>XÀñZLÒnõ™h§¥ RÈ‹õY¥®—~oÒlÒ-ÈŬ-a™ðõœº8¹?ÏÒ0›Î/Tˆ@²°Ø˜jzGÌÔŒâ6 =¦þOÎKÁÂi®E2 $™ä2%[“kº¯'ç!R)’“:»¥Vn|8Èîãá²R\ò„ÑÙÚ8JóK›Ké0µà‘X†n·kŽ@_žKË †}:½&Á9ØÀ®èøÈ^b=&Å”ÓÙÓÓs°«'˜áÃÖ–Jܵ\«!²ˆbŠ»Ðtì32‘öøòÑ6ï¡ÝÊ5¢èÏ‘5sÕÅBµ”⑇ŠCcN“òdìNJŸÍðT|zæô 0jüH+ ÞÿV ²ËŸ³vÓ‘Å+Šïƒ &Žuá¯挤ÃzHmßKׯJCšŠ‚E SÐØãëë|«E ˆèõÝJöfe© îu=S8íÆ6L] ÞÎ{Ô%@; ¬ \M¨;Âð%Sðb(¿nñ¹YØÒŒ båù€¾CP^¿@~G5Ì¥!íº­{¥æKIÎ5S&vÛ>|Y_“KÑà\Hq›Ìz'ñÀ ô;Ò‡iˆÝ@Òö5§Å.s`Ëåo˜ú@„PøA#©Gi«Ç ”,jávŠî‡õ;B£”ÃMVíèé,ÃçîzŸª-ˆ6À>VöWJXéHF7Ç o)ã¢Ý] 6—Ýk†á;^[ÕQbQ;Ëæ8 i lIžæàÇGNo˜jhÊŠ˜¯cd$¥¢ïy˜TH1˲¡Û€K¦H™ŽòPyˆl¼nˆ%«ŸÇ7—$Ë—kع¨›¡*—å/ Î5÷%Ë!Yí¨´‡ûãÈŸ˜¨hùŒÊLŸ+‡ç`†Ré1J±„è¯q¬†=â¦;3– ‘©o1*UnœŠéƒ­ˆíì'ý¯ªî¤#H““c%Τޒ9 ÁúLa’º[ФXŸÙwj7fÙÛ“±Ù@ùø…Ƙ°OjaÕZË Ú¢=0øÛΟ»És:Æk—1äß<%íTø£Øp¦Pg=Çñ‚2Ƨ"kùðàÒJí)^cFçusG—‹tWLL$½Í^x `°QaÇ`Êï#ÕÄŒ¸cžh|fÚýÂ>ÃÜÖƒkR\GpsîNbg?Ž€³øXqÝÆÂ;{AÔ#ZªŽ,j$-áL]ºú]A’chL$RR"ÙߺeªT0µ#n€ºE›EÀ/ ZrÄ`¹®äÌ ‹{·G” ʪÝ•²ž^2;“éŸJ:È\Y3вL³PÖ|¹èé®ý@yý¾Õ!¨×âV„·QV ¹úc=½ë‹Ûµ’\¬Oqe–†ý-ïÌš:»dlxÈwêÛ T`LÙf¥Ò¤CzW¢Óû`Õ "Ð…o`qÛYø÷+ËÖIzy—}³­áí]\{c!ž‰ˆTŽˆ‹ë± ½Ÿ‰³§3k°ÞWÈ”ùN§µ‡¯§¬ð„E™¨Q"nÛ€|Qš›¸yŽÏ²¾t±qæú“RÿßůȧPÌËØ=ÆaHøBà@d“Ç?»ZAY­:ÅŸŽÓªGÙ¾‡ sâO~äpÎ3š J Խ߫‘ÊÁŠF(¬þýçUÝü›dyî]_iÛÆÕøðþï1;ê)“,p šxw­‹ÞŸ@¸ Ih  0 ›LIŸ·µGFÕtļ8ߥ˜Õ”ÏÏ:¿ Ý™Ý‹ß»{Evj|1ÙòÖò4Þx‹e,´º—[Sõ,]:—+=ð…³[U+íP¡‡˜e¯T°¾»'pAa³•×In=ˆÌ´û‰Û->'º'vV†È@ý -_D±¿^å^ ¨ÊfØ ðçŸA*/‡»—¢l#ñè¦köùCSÂu8éž/0ñüK‘_N GÄçDƒEvS×ð¨vœ:\»>ç¿}ú-o§6C¤ ,Qt*ÛÙI%¸Ã¨®¶î>o»Ëš p™É¨LTºímÈ®o„+ý@ÓÛ!ƒ¢¦Ï;V>E$h4õ/ÓãR£…TSä/çýþj'prbD±_c䃋‹d‡Þ\²M”¬¢ ¯$£È”hÿÓÔ%‰áx\Ç ÖÌÈì{-~ùw=pv%*kPY‘šûò&=ñæ¡ ÃÒ¯S+´Œý_¥v“"ĶTñ'sU¿—ZEZOº*mP¿O¡E²ÒWÌQ¥Úø½lŠû˜ì-ÜW³™—C#±$0!ƒÄÈ} äw}×ãO>‰£…®Ê[Dkì£ °w8È¢Çgîý[d Œ F Êjz<割r+¢¶°xÞ-s7„Aý*ƒ,ëù¥]õR+ÓIæÜ6¦&èâß;±°X((«‡ÏÚ4ªcÞ¤ÿiT¿)K´NšÊLß&Í…sBÕ+̼gyMˆ’}Ôn†¥€XûƒÎt$çðÐSüóÒÅt)Ð\œÝk¸ÍÂ4¼Ô¡¿=¢-ªFZ“زzïdlL愃ߌöà‘™:Q÷.ïMá°³b_yYþÔ™wÞã(˜ê{Ê„…·ÍÍòÂMNcÍõN™¨xtF• „TZ_×ø7Žßû̳ T£=uæYoé^Fß¿E䇛¯Òä}ùµ~ÎñÄÔ®Š¾¶»´Oئ{YÌ 1¥¥32-õ[;þn TɹРFÊVã%”ñÞQÀ¸r%»î[aò2ONˆšÍš|Së<ïA¹€Ê6RBÎqIÈSÌÎÓ.ÐEÓ_.ÇjdP:<–RrïRƒ!ZtúÌ¡ÞâHÉ2¶XÐx(ãó €HfyØÌ²ÇSkTªÌGÉ XL’„°‰ï%V`†©“Mºó¢ÿ1òíö‚ùye·;·—þíùm E1Ç*nÇžxDÑuKä ,¾2‡eÔx²caÑÂZ#ñë+çÆX±Ó2ü/RµtÜÂt¬” Ñû,‹øÏô9¤c2Pd7üV•Gö—¥Â÷ÅénemNE¥—A¾c«Ùª´¤}ßµë#-ó BXÇKòT£eÐ2決¼C.…§oåY®0ûaˆc¢%çö¸.6ÙbÃiÒ(}·×rýI…[wºoÍd÷¶F½á],áCÂÎ~ÉI˜1Ë|iµTÇ~Ùzq €zN[/QGb‹Ú®Ä1.Õš”â·µÙF^i¹•ú*˜½DュEk)è“Èpý%‹a¨÷õÒ“3Ós'?PÁ™p¾WˆþŸá›û‘8eGp°öÉïtc®4Ë›¼;— ¨¢0W¸•`i ”Ÿhç‡Iñf~ìÀáÅÒäwÜÜ`ø”LEØ’˜“ç¾·cî/|›WI0È1Ÿ·Õ‹4œ¼TK<ï2˜»Õµ5âÈÆG#MSƒ Æe*ÏÑÖIU¼âtHк¥^$%G¤®w®eWë7ü?(ë«®?¤”<ýÕÃðÍBôѳo£2ÞÂú|=­Î#P•ÿ³_Ÿ4”¿øÏže7_³ÞYׄc7²Õ*%&Ö%Üú’y·¬[Â%(Ø÷ó—|¥x Õ˜$ù·öy ’xš%ÅFeAÔßE²–ü=öè MõþuÖÀɨmmä+æžß* PEZ°Wè%hÚ†â^1¹j |ë7¬}hENQ†r¾u2uš£ ê+}_ѲëæÞb¡¸À˜£ð鸉—B‡²VÍ_jÆ6xt‚ž>«Š6š’ð_F͵’|ÄÕÙÙ¸-¾ê’jøÑŸž´á"ÔÏþÉ_Ó´Íß>¾JW“‰P¶ ©À "¤•¾gEÙG3óÉŸÇ»šÓ•?Õ¼5•·Ô×ÓÁ#rwz. vtðm+=/ú#§ÆÃk‚·Ua¬œ˜ÉŒÌ=ù>…âlÊkcïqÞ \Y1§m©å ÷~gvY`ð{ÆÅv;²õF¤{ž’xÒ©ëà1/ >”ÓqóéÝ–Õ*½1a=ä#ˆ“YÔ_„î1qb# Ñ÷P[<üœ|§)ˆlqç:˜§m1º°½|(u`b¶²àwLê0qAp¥¸9ÈwÙ÷ŒüË©9º/뢷۬¨Ì.šŒ^Uá]ܨF©ˆún«žKy9ÓÔ7ãÀ ¼kk®­¼yžõ¤XxD©Ö“©ÓÂÚC…z¾;äÔe±kßÂÈt0­Ì7Ž·O—³ÌùìÌ ¹‡Á­ˆ—ÊöÙ‘„Øœc䜦‚‘ (Æí)sMZ•?+å-ËZ±Z ­îQ^Z“˜°œ6>éJð¾µ÷òØÌäsŸ:“œ±ºJ¦¾ÜÁjâ Ïž¢<­s¹?‡K!òÜ™9¨ßæýrf{ù}—¼Tµª•–”H5K&2 ÷èO”¿êoøWOòlñvüƺý /d É|È‘§+æqQüÏóuˆ2'9ç·0â[ģΙUWG!#Üq¨­O”çQïÝÇ®G>êK#Hº¨“°l q¤žýWú<Øëü±DLè+1‘2øyg³@RlkÖhò,ð¸¬ÂyŠ •J4HíŒÙ}?``뙑êLV¥-B¼àÙ,Âg”:Xf•Jë¦ î¾ZÎD-`ØÞr1H_iAÈÿì\ÎÄœífƒ²ë™/“cy)žíVñnúÏVœ”(Ab.à ^B\%³5Hx¼&yܵèfüµò˜2>ˆ»Š<˜añ¾XR£‹x†ëïM]Vž¼#—4cdJðf™&‹Cd¼[!mUÄñˆÊåý[Ókiù äŵ~hâ7cߪ”U¬ªœ!­êf•\C§vN3¸èGó8 PnA Þ ìY’ø–cSöTºF'ø1Aßc–põ#t[¢”*T`³¬ŸêÌPë5ùåŠg#_¼$¥äýØ&ûtË+Âx4Á™§ã·„óå×ígÑpq€:èùïú‡aUˆ‚Èø`E€Ò_ÕðÓֱߌ±£.ĔĄK©Ëy3˜¤ñØÎAíõVC:&d'M%°! ZÕÆö«½Æ).ýø&§  쳇 &­Ü ÊMøJJ‹Jgè3µ©YܨùõzÆîŠÇ$¡#aÖÜŒ,mYý¤ËœûVãæ^º™ìtêáá `T‘ÞàéŠ>ÿû¸)…%´Å“"»hx Fä98ãÅAAH‰Ü˜÷ö °12Ôàt§€÷¢tâ/6Q%"K[-RÊý»aÕƒò"&ìãäfÉLßø½·gB¼…D¯æ™d†ˆ@‹#Šª¢—9ižŠ-}“ ±p²’Ë>9Z˜í‚ !TI̶;&SI|MÕ-,ÞRb¬$D8nÅcÚiÔŠ¯±÷Ð;ˆº7ìÎD¦JŽ ‡ðÜ}³¢&Ö=—”™¡ >Çgž !ÆÐÊ µz-¬è†I){MÑÖ=¥©ÌšV}ܰoG&–c ­/`yÍØ1WÑM˜4Šs?<™ü{¸­0 Sùãø×ÌvQ§;'S½TeJ¬'‚× „fu±åÿDtøÂx­“M_V.`èWŽl³iÿ|X/ié±èúµâBv8kLK/J€ÇŒý3uìk¢O‰6ÿèZ=°I®Ú抉â7ª”Ëùñ|}9’j!5Ü6Öœâ(æFõA÷®Ël?(º:Ãà5OÞ°Ö¶‡=êÚÃ4ÚfÇÖØ©u@Ì"²Çüº`¼ÂaÐͦ¶ÅЋӈg,´Ãeݰõ„ V/žÍÄj6sa Ñt5¤Aî{³óïÃ5ê;†)â׺¦æ‡ÇbšU Þ\ºõ1æÀœ½TÌ*UøJ7^SL&ö#Ï •¦x]1íKŸêõæê@U¹‰H\ž|ùà3ˆN׸t]S²‚м˜KÞ^í¦‘¸d(Ëq,à|&hg¤Îk•¿Ñ­âÞeã Ú»?SU™ÚQN+¡Í޽HðH¶øÀˆÞV&)S>û´dL|é'cÉPËiYýñïw®¯ûó¹>1Ðïˆ$6?;ü$5¬~pŒ&­-–Þ€÷@m“ÐßÈZÇ(J"‰ŽHùPÙRf2“",¿¶óØ5±É1ÈÕ“Xo¼<Ã÷è+í1hrÇÒwlE„‚àYÿ܆²Ëò1È”%§?Õä•Ö_õT rôùGŸr`Žì;T™uߌ$ÒÈ(•³EßM•@Ýâd‰à(™ mjòe{¹£RwË.‹p`xZïw¬Zg‚Fîšt§ÅAÞ,Ÿ[ÁãÛÑfr ‚‘j¸‚ 篘û‰ý/ûôc[R@iôŠ)FÌO“Bs7ÎH'tI]^SÒOÔ¾k½Œh,-(8Ü£ý«KŠ7±œéç.È ¿ê W‘i,j)в¹ÏdÖòB¦êµº,DéVÊ|²ÀZÞí÷–:ö¤7Кcà§µ?–¥Ñ$`W$‡ŒÓ§$ˆ#رž Í]ɺçi›!ù™ˆQ7PŒ[“T¨­çŒ!zœ+äõ„r¢dV]Äm­Ê©SÁp4í»Ÿ£7»§<·èP&Õô¬R&Gê+GM”’§Œ9âžÉ Päf8ʽœ6¤WJÐâÅ‹ÃÕª誓Ì_ýA"zŸ<]²=ðP'p@§¤ˆoÍðÿêB )'CŽZ¦–jm»TÛ½e÷˜¨æk†XF >¹lPþªjëo¿Š”Ô`­+ =Äöµ0ÌÆØ‰)ïßí>‰ÀÈ*Pàäà-¥k—Õ(3l0rÕè°mqZì·3¸\á%Ú­'6â—æîw„•ã^å·“5ÓëjìÅÝÈí ZC#wˆð0xýÌu@Oœ¹aѨ-ˆn¥ÉœnôónÜêšß{íÃ(ÓŠiÖ» rõ¿$\Ìú2¶.FTíûïøÉ7©5U>š¿‚w§Hh7&æ,¤r9vöªºyÒÍ›0¦4®XAÍ¢žr™9é2‚zDž¯-x›^J@C”»…qÑÏü¿ë_?âÜ á6"'ÓYWÛ8 ±Þ–¡ÀEíEÅ7Æ6â¿™ð†gh> PÝÓð—¨÷º0Äÿoܯ±¬lBŽŽ<×ÍF!r®ã²šjÓª2¡o‘Ù ‹ÀÂe@ƒwb<—ß‘åDªèí¶¶.^Ë¢_º0¡#¥AÊÍGO>Pßœ‡ÓKdùeÞwóâðøÄ'ž8;r]¼’XVn»ü‡æ5˜öÏÄ—=e¹~×°‚_Q9 xBµA»7—#}ÑÑ##ݼ•ø`„{—ë}8L rG·™yoù—43ÝT¦â°²ò¦Ë¤Á{ٶθ9› ¤áù/)ê6­aÄHiºtÎØÀ‘¹t!ß&Ì5ïmmDù.À¢D!ì’øUQAV…_ë “;ë Œs(R¤¬dw6Ñi]ˆ¹cË)í=q„T|;̰9U Sw2\Ô¸t@Z _ôà]vñ¹ºx(øÂÇóYc+äÛdu +Q+ÏF'Q‹(+ŸÍLyy+ë!÷)ŒÚ®Ó@·—©?‹ˆÏ`eŽw¨5z QÈnˆ ßøã%òF¬Ðü3ÝŽW•ÿ™ ÷áUoI.ã44&,Ÿ€j븣Ë:ÔétåT€ñcHƒ8"Ïa¿öQG. ¶¨òÌÑÃÖôk]±KMçzwûœæã“áYkl§{ûdþ±ÞûŒS㥌£@C.ç+Úñ—(Ëѯà%yj(¨6’¼¯šA2!=dhJ¼õ)Tgp^’Þ·¥ ܦÑÇøÇ@ývzP1ç ²ÅÞnÿ“H÷_s;msoø> ¥LLzq ¡Xs.EêBëeÐoˆtèð¬xeLÖü(qЄëÜG»›¢?Øð¢c¢žÃy¿©£@ ÐÄ­)çëÏ®ùoX°ÿÄ>ß–Ún˜I)1mðÕ)§µBJlÌ ŽcüÊÊ®Y˜é­Þ Tl¾ÓíûG–)~ðˆ+@(´yÙY#ñQáŠ+Xƒæ¥(š^Òüñbž³ˆÈ+“÷Š'µ‹îDIe–k|î_#¨£KzÓã# ¨ØÃ4χѱmÞPHh˜ÐÚô4³:ÚK9½âz„ѽ¿ÌÝ×h®&;?伨·—ÞØDvóí]{•“ ÔÕ .ddFýHan»¦§™/O…ª¡a£;[[G+WZ%Fñû¨ÉÀâœGÓJѹ¼ÖÜz¬`¸O#>(fiÁü>„×Ç*Ž‘¨AôEÿzÆ}zm2WùA9Ø?‹-¹wañö|úÓ8òÅÔ²Fí ÙïZ)c$A å²þeSÄìàÍôƒË 3ÊÏi5“4A¥ªkFѳiæVP¶ Ô+ŠeQÿU붨Ë?x°êÎ À´å{ÔD’rú„”®ëŒ…$Ø(¢¢}­¦;Ö!N°ŸûjpøGYÆÓ𳞅éHN~õ2‡éÏNԅʧ€|=¯ET1nòümK#­™ý?i„/Lˆ#¹gY‚þ ÜÊ¡î/-¤gS¥ølð’¿ÓšË:ÎËØB©Â@u'YPüÆâEÙ]Õ/à ř«:.Ú-Òôs˜ŠÙ }!Y™Œ%R­oó4‰å•öÊ•³“ïÊ[+ï×ÍÍÉZ‡qFPñô±F?„ÔÊ%K- hâ6Íg'اÛƒñáöAtq¡ö]úyj(¨ ˆ™ÎØð*&Üñ%¡íªóÁkŒ){ââ,ñj«o@±ÐfZrš`Ãú»„¤­»>mÊñÖ°.ô©…SßwDp8èóIu(ªf·àÁCˆî„ Ç^â=ÜlÝþÇxtÛ‚ ÉËÞyH‰øâ+•:çù$®í¸r_ÿºiu;£H«T¤ ÃÚó`>ÖÑ¢*®wKzh‚;mPÿˆ•/Ù`¦(²‹5ÁÈõ¦†p²|N6”ïµ}®¨A#„¥~O]éB[\ÁÎ2û»Â˜2DË‘Aø”ÙÄ•ÚJyÈéETλ@êÕlcÀ7ÆQxj¡Y¦ÑNÏ“ñ°p8{ù2¤53.£Ù°À¯¬7ÿ[ÌìmA¦ál` ³]ãLóQÚð¾³ÐP°#[2€@);^¼×/µ¯ä¬'Wt@]½”9—˜"íO-b(úÄÎ4?0+Þkw¦”?Wr-EëN úb³€ì›•àø‡Â»òÂ[MʆŒÉêlÝ ŽÝE›&Óü£|H³›!r¬°”áúræ}•ïWÅä<¸EJó­¾ ¶H¶ù/j]P‹€l§»}Ô9uRçU­¸–çÀ:Ú%vf@ôF~‰•~ϜʉLäfüog{ àòr ý/iÁzµµÈÚTõq°wÒY ’)›ÆÞV³ÄÅ0èÝ ¬ùæÁqˆk/Ÿy€AÀ ï-yØ - ;TKú4j#b”J1äÒ¶wGZ˜€‰Ñ=AAcXC—侞þþ©O©+² (œ²ˆ4¡låXBr ‰ÀüÐÉäèa‚Û:†ÅE­ùÉM3—†d‘DÃHß±rÖq|B™ðƒBo'Z éCì`rD%iDËÅúM}KÍõÌnÚ«¼'ú48IH9-)j}±}l¾6—ö Ú÷À"*r#(ZïqeW¯/ÉA¼á àmÕf[€û|Š‘•ØëˆÒ2åcÐ?B¸ÐáÞur•¡48¬qÀ9LÞ&€'?Pöâ€È(¼) ±kjv‡y›Ž±g­›sTñ¬ùD#:|‘Î8 úrGbÆÊÀb/œ—¸*Äd£­N~?&‡ÿ•ÞââHpÎÃìî”ÖÞž“ª~KdCñh·4lЯյÉ_TcæHŒ~“Ù]¢ä%‰<â}ø³~(RÆ©QÿŒÀ€¨ÚVñqïiià¤ïÖYé1œE­OãKÚÐÃmá=;}¸’€cKsÀ;.Oe!3’gÛ´³C¯Ánœ­Øõ¨ßXnT…9H²ÑJa–ý“a¦2oïæ>Û£±ÒÞšÛ ®µ,¿^ ýïÆª1Aˆ|A‡˜×—„ø Û›ÜÂÂÓrî¿)¢¡e¦y|J–¨ $…ßžmN©Å²½Ê“ß!»°ÿè¢b=ÞcŠ2½|þ=ð®ç$žI|+<ÉtBÀäÂýL#«ÅÞÝm”VGN¬asÙb„iÕƒ#ôÇ‹ #GŒÇBB ˆh›£…ZÿÑl0 2'ã씓½”ž¾ß\íò9p ¹^Wù¿+;Ó'­6-Œ/±R,þQ_š<¥Lë$uÃP¾úàHZÑXŸ ì'´F'ªî§^v³ûAË`9õ²— šÍšj™»OndÄ3B’}g¹ý?§ï¸&»z–‰´FÉ™Ö<u–µhGMâ§-—ÌCi‘Ú-QíÛkr?ˆÆÌt@ÏøpiË-´×ÖA1€ŽPø9 ž<¯*èÒÂ!·arØÃQñC²•¸j™ê¦N?±z±rÝ÷ȉõs3“¨õM¤`+þx*ExecáyMÊEMÓ ºà”všÑ«À7/+\äß.;Ó3áѬ+º6#&ûk›kb)ÆÓÜ@ë%òuÑÑ´ÑûÞ=PfA!°vÛÕCJf(Y?áår[Ö«—0BîæÇ‘ÑD™¥©è‚Y“³¤ÛÛÂÒ«fÛØqBÖlî`œ.10iB×u` ÞIÙø§k6ÙÖ%µ°5°ÃÖ4P­ÍÖaŒäãO1ÇÄ5e-z™‰± ážU›|·I޶u€ËLçàP)ÿAc±aªúýA“±PJ‹œ_¤G^ò·#d ëðM³Žélƒ­("Q>o¢‰½.+ÓØ€µ$-ÃÙ,ËÅŸà èL¥†“*|Æ#Ã ±·!má"pBG ŸÕ¶Q´Ø™d>à‘Ã¥¶û|ï Â3€dÊ."ñÅúihuÕÈ·ü$BÖý˜HGþ]Ä;äg‘hýŽ„%g†"Bƒ¾¢:oÕEúЧ‡Á"©@Ç^ŽòÚ¡x§;²«xt!`ý…UŽV"+DÃK\ ÷¶R*¨4å$w=Qg¥K üð üª¸äЦd&–°ÖqÂfr8:õ rÉ·£•¾ 8ÅžS<ËJØ;AÂJxižæ»-V„¬´èWÛ˜p‡G2â ø_(P¡e^Í!Ö²* ——ü-•/W¤C 7Úy~‰þpj¬›=©£ðS­¥ìÐäZnÿÄžºuïø`44lã4Р—¿00+€¹ 9*X¦(èºvKFÄã:“u­v‘Äuî²Ü&¦ë|óÞåqŸ†Å.Ñ/?A¡{© ½¾Ä}Ÿ´áñˆk/ŸyågcTz5oɾËfÚœ4Ú\ætú\=ÛÑ+îØŸ[Û'¡¢üXJPºÚ™£zײH”~''f…˸›‚¡Ì]á _½*e¿„ì¹s9­2ŒyY‡ÇÍœA8¡®¾ž>¤86lQû£îW' n¥xuÔŒÔVš9S:&‡}í±|Ñqs6쇬Hé¯T³ƒ½?·–³ùºï;NÉGU˜¤A@+ö¦Q`2yœ5¿ÞQA6ó”`ûu›Ú nºÝGBb2´é®Úò1&W~24ÛÑ×»)+NâûÉF¡[î‚ÉVÍMY¹uU¸õ’A3ýz„\”Ë;ì2–×$`Ç£ü7°+álùÛ…ä|^éùŒÒÉÔUùŠà¼\˜Sjºjîýîio`™×fÅ‘ã Òd£·´ @½dëªë±ŠÃ‚‚à¸Á‰&ѹ«Ë¶ýu|뢵ñÍ!3hMÅ’ë÷£³ÚÕ£|•DÅÌKYCv]7mÏ>½•^íFìô§`ÆÎoáÒí†HÆ/3WEVÐÄÀtDöà/æûàHŒ-j÷ßÈP€¶XÈwu,;¡2D÷‚N¤>p€®%õºÿ åñJ@hšfÿášž£÷Ãâu¡ 3†4P k;TöPr4úÃÔªˆ@ᬞSºªÇ;ª'—)‘Lq(F…®¶be9 ÞWp`ïkÄÖù¨—²­·x~>‹í¾‡+ ^ÿñ˜ÔzP@!òÊŽtÃêÆ•µçý>“H•ùDH›#ÂŒF ¢@0 Lñasû¨ò+óýŽéª …#á¾GÊÈÍ{ÃÞÒoÛ1§Í!jý‘'\d¥ÂHœ×ÃlIÝ Ÿ(ú>úóÕ@Y_ÿEÏPZÈHÇìíh ï©OHÛr¹£Êðç©ÛfÈUíÙ“À’Øh;±&úp8QA×òœJ#hÔÔ¦¤%S€Òò'êyËÉpHZÃòeDΚ·D7ÇÈ¢O­BÇäK`‹HíûݲSa€Oójv§> _±eTßGo²‹¥O•h3QJJº¯^çnXa7-Ä–hä‹YAë=Õâi hG[×;×\Ù”¥RiwŸ¨ ׳ª! ]í:òÞ"åÔO/÷”ì mw#š…Ÿ6†ì½=–à#ß8`n[9NƯ/Ç'«4´6ì£u¦õ´ué,…_o5¿a½eå‹„¿•Á(j¯ûç÷g\N³ô…^R{tiOgiÊ—Fü´LH Ü ä²[—9EÿuúA¸:W¬˜:î¨*} ¤¨û…kˆï7£aÀ™8‚ÿH©Ã¶ÚÈëÚºŠ° c®£:0&°þëNmœ‹Xiä’JvÖgÈÍN.‹y¡88ï§T”©›ùæ/•%Y«‚£\K¼M» ŽbÛmŠ÷5£žê6¤7E¨ ôh¦,xþÏFpàZÀ+QÅgµ‰~^™8é•Ô®`òmW&&,÷¤úÕäÅ:n6¹?î… ÿøLn¸K_PÑ‚Ff»Ëí1XX·ÜL”u•y“soˆI…e.Úºz¬Nõ_‹–nÖªKËÏóжyÇ&?•ËU=q¸!”²ƒ=ª-G¬mé-Èv²F%Zþ²Š‡+e«wÂýîDI€BÌV‰ ñ˜¹Ò½¹” RÔž»Íß:ˆk:§=“© Îï¬SJ~¿vÝÔyno üb]ô÷:óm­b¶îw´#‹¹îrŠ€PæÑɶ4 £cb¾Wafó¶ÝÐé¨ëØþ¥I7@þ@Il(„[ùåG>ÿŒî·*ã®.³=´jS ‡f-×wÄw!ªwʘ‘“4¼Ÿ æŽà!~¢†Æ#ÎØ;[0}/ƒùÖGx9\ÉÛÁvÄ–8"+î-|¯êðþÐk»óëjf$HÎÃ…:4nîrÇ´gŠi°~ùH.¯ÍtQw‚‰ëM¨ˆNnô§Œ´OÎõƒ¡»ðšÛV«ñ]Í,Äãá“ɲ퓾ùä)NÞ‰1pßöä—‡ƒº‘3× ôÃ{Ý;éR:›J–þ\J¿®üþÜà7õߟÛàfb ½Þ„õØDT.j‘ 0ª·Ð‡Æ:~\Ç€fqTŽø*K`D’ÕeEÃ8¶( eœà,ÿ_6&çrœQXQ!¥O),7¾–Ã2¥V7™þ…JgåM£Ã0O·¿ŸVüì]êŒj j"¨ˆ¢ ˆ€j"¨ˆŸ¿ä®”€a¥UGpH¯suv4B ˆi;nèÀ:_iJ®}uÇYüE{üÔA› ÅjïKmþªU¹ôöX„úëNx›@oB{L`ÚyÕònŸ^ê@¡ˆBǺ¬#rI1ÄlU‰Ÿ±ý¶v®€ñ /VÆðr…¥/m;íפѴl $s iž†ÖÅö9³?œŒ:ûxסÉ43£ÌXØä©–,˜Jñ‹›Uvœ}§#·äúƒå¹Ò†·¬­·æ 5ËÅ dÕ”QèUUg¡Ý3³P¼÷#.hƒ毄°KÊèÖKÎ>å©âÿ²Êö~pš†-‰x†жËÛˆ,žÇ×—Ã}½ßt6Ûó]PuòêØ-²Áp5ÉðáNÑijŽP.´ê\ ôñeç:ñyòðl•/û·ésìU'ÂÁ`žæâ`G¦ßÀ*ã“kéGwí&JW]:kpÆ?¹M2é³~8Ä Õ9Ú‘J':z ÎÁy“‚R¤qûJ]í+4w B“8u…о4Ýxùݦil¬\üj ÂkÅ,Xè9 +þÞ:’Wj,m ß ¹2|õˆžÒ”map¹hô<Ɖßz6&Ìr¯Bgñ/*~cï0ý¾Àå`Û„ "Ñ>gôjWÓ³iZ`¼D¢#÷[Щ<4˜MêÓ1€ƒÉÁ9"bM³œ{Å1å¨-c¡£ž¿ðETÁp¬¥ve.±ðSniûÔžßíYÎZxPè€ ÝZ´+@xôè_ò@1<™%Àásr]øWª%¤Ô<;Ñzà à%|k‹V”óíúáM²@Ä!!âÞ:½ÿg¤‘M$¤j‘}IxA¨ý-×9"(™HÙo0´VðýAÐ$ìQµÿZªå£I×iéÒY¦"V¹¡A~©BcCEX, ñæf—)Êppôx~B#ª™ªÕ™ŠF?´rN xÿ6p$¯ËÆ\ví²äí±ÿ%á“;BC£)á3ÚôËq84i6è$2>›¦Dó¦™ £tèwø¡óóÂs•Ûp!V=º1úØ÷^p*’ús.´`W+ôa9!ö ÈÅ"rG5×>|ݤìaêú›©ë_‰š]eòôØS+Ïø¾ÉÒ?¶á¸ipï¾7ðQæï*Šï†¸ì-gYI'1õÓbqÝãg‰¥"“‡è %­êíë—ïJ\¡0ȈFa±a °^ögüÒû™Óÿ¶¹ä`6è~§Î/ÚŸ¯é9«5½Žø‰g®#— W-UÝ"›[èñ L+¨¯¯Â©1S:W¡…® †ž+Ö}*¹àõ ©§ Rÿç>Á/B´]gÇùó’Ž–d<Å»Þù¥}CçþÝ®…> *S'dJ³ '3zK Úv$ |˜äê ]«ÜþU÷N1MÐIÃwQ!$0ÁQÔ¾)b¢0AÖæ®©4I‹yR’ ñYL•(9í¶€ƒç·ûÙŒ—*Go>˜z̤“ Â×)SüÀ‹–‰‰¥× |¦Œ¿²ꢱ ËLÌËYX‹hÙnRX-_:¯¥ûK .¼yO¡èHÆÉ3H—‹¹‹P.ôUO®qàxD„[‰&vJ`"RÕð/Ð$50Vg>dÿ <ÐÉ’>¬+Ï9væ”Ó¢«ø—x{â‰æ`dHÏåí6Ù‰ËË1sJA¾˜ "]ˆì³Øv§]ºhd î¸,²K’_"Ùjy8I(yÿüF…ÑE~¯ÛÁجҋú™¥²Ž¯l&†{e‘ÄI)U.¾'¸†‹$U$­º…ä|ØÆ<ÓâDÀúfÔ’’2™Å.²f˜ú°fÀJKoœD ›¼x¿›k8¦0fGïÆÿóÊx/d ëœs•~N~3h¬úiù*žˆ©ºßnMj‘ÍÅmKŠ¡ßFŸ‡ ÕÙ‘¬óKj2Ý&·]s·(—F…0À»5þ~FA–û޵ 5?¦Hûè—^˜`Ž„úx2`š™Å{Y÷?]Ý‘fßUÏ-Ô2ñ“OÇMY!¥Èðí´2.ÆhC €I[&¯.Þ)ÿ¾ò¡Ì ŸiìË@ÈämÔ¡xã‰jz†•cû¹ƒnXd¼Mï|¬ÒJ¥²2V б…d~SšCþVÍHDûò0 w ¼U™ÇˆÑíD£ìéK¿í[c-¡—:^wª¨{¼`÷'×|Þ±Õ|H™ßS‘ÿbmé— »}-¨ÀH3ûü:†}óç̃k#äèh‚K±±×CT°’žôg­+â½âi˜ÿ)úÄxŒéh‰í±{‰³Y[œ¹_;î‰Èôdå¢p÷=uZ=J< mñ Ší~éÎH@I„>¡5;>†=†·œ,›9ã?yjXìõÅ$«,dâ ?{GÉR¦ÐXþ÷湚±de˜PèÖöÌ9±×™nßÉKJ¤à+¹,BÉeo6„Ϧ³3 ǧŠtÇâ¼æ:/ dhIíÌäû=þ:MÓUÂñŠQÐi„ÛL´ˆë§ªúv¶@¹„QŒ—#0é†ÿÿØÙoo»p™QHù!% $"ÉlýÞt=íQ¬*0=? µjß@$¾üc¾1fø±X¡‹œ—¸ü\2‡4sóÃÞñB6S0ÃáÐòÕøo Bô¦jl‰WslwŸøá;¥zèWïÞ²‹^QáÑ"òá‘]rÓɯæÖ߈^X/4ÛžpR´ í“E;¨n]ð~ã´“‹8DþÒaDI×G¥ôñéEªóNoÑg/ÃQ3,v!Éœ-—q/ÝÞu]ý¤¢¬TÙtÏ^*fclS®û» œ$·p QOªBÿÔ‘>O•bÐ[OǃΉÙ݈¤ˆ²r9”IˆUo›Âª“J„ùþ– p÷ ÞOÞéH"h"+#¾‹ëf ÿ­‚?iœ¸ÄvŒ u²ïz#‰Њ“¿•±Ç<ê‹ÜÜqëc>Œ•îÅ„Tô#}lM¨nJ5Ãm¸bMæt[`M…6Å׬OœR@YÐúZsD% UÅ¥ Dywd`W‘Ç»"´5tÛÂÉAåa| \Ŭæ$V_oÀ¼¨+Lïå=Ñ"Ê ˜ºÂ”…_ÖÑ\Ë Ãá5Øòñ]žØÅŒõð¨ö­a2÷“e̱gFÇNf-üðûH½cR¯ßsÛ`ïI´¬ÎÆJ$$Ï Fºí$},sá@ÿŽ|v={ý ÂÄß­ûB¢ƒ+S²;0Þ"ÚÛ,çwë"µpœnò}Â’ƒŽúþ”ˆ†Ù äêÒ‡ ½ƒŠLûx_õñ?9±7¡yÛ^Å}›²»¶ï„ì_jÙÛ”ÒX§3#'žé$¬¢'i#‘Ûv•î6*ì구÷zbj¯Ã¬“ch6¾ež:Q‚já,ŸZV6xdÅ÷òžˆ;?é£[ì¾M×'Q¬UX’€É6€-Iã(â^)RrVã—ºïuׇ;c)Ë’µ=5;¿N²?lËçhŸ]¤ ˨Á‹‹ŸjHÕ¤Þ×3úUÔìjzÔ|/„ÛÀ<²ùf=+z4ˆ ÓaÛŽý–^”ZŸ£>Ž9tžWç&)ÙîÏ­(FL9¸<`[7κ†ÌlŒPÎP¡F¦ ñ_¬Í‰ã*)‹Æußa hÙûp#ÓVb„!Áiž÷¸ÁU£jæ÷;Êׯ˯Úeä‹âˆCð7Êa?Œ+,¯w‘3*&[ݪcú“"Qmµ(f°ÚL²'3Sê‰8rè¿ ½Çˆï[;›EÌÝŸ7½J{½ºÏEs™ÀÛAKÙü€6‚åÙAà1Ù qrư)n\O…ŽšçËß\RøŽ¡‚ð®OzÜÇþ~¬Ýë )ƒµ§ƒëFõsH<=³Öê„´®À¿?w¡ rÅ!&½bA/ˆ¬Ê¢ðÕ²ÆàŸù·%0j¥„¨ê •$¾>U›MîüÿnC©Ú!xY8X=wÏ øêÁ38©ÑhWß[Y$B9‡Ë訉ì±#Þ™–j,sÞ®!'á4;ÖÏåð¸ÃRP_}ÏH‹ îCILÕBY©¶S” ³GaáÏDkË4þîÍáäÎãp8ÒÛdœÃ0Tш±jÊP¶þ! ð¢ëe½ ãLsßÛt=|Hžë\ W™³[„oœì^!1EdòóŠÍXøà4“”efßRq ¼»ìÕ¨Td¶¢¸oàËM×ýÑÃÌdˆ=õØ„ 8Áuô'ø‡”¸œ¶Ï°‰€lûu3ÈF™û P†/'Sdq°µ~ U>Q­Kìµ)„L?Z„Owš02'²þm±µìx3ViÕ]±°áÚ«f: }:ûÒªÈUr™p⫘N5¾ ou×ìgC-¿WóL¶ÔŸcL#媿ÐÇ¿Îú•BÚÂUaÌòr[~6 ŸÚHÍ}ø›@Ísöy˨#9bÿì2ß‚ÿé^=¤ÛIï0;$$ä6ê’ qÙ“"{<<ÝŠÒ[Í©ã2ðºó{‚1ú®òt§€[RðþO¼ÖSØÙí©dÎ7=£¢”7Š’2Å@± "Ÿ\uz”ÿ‹$>ÒRw©«×Ð7“ð™ÄÖš·>cÉ_ ¡‰rä‹6¤˜¤ödtC«à“M—ì—pL nO2ÝöÇøè{çƒR„KÚ¼M¾ò­f°XÀM_x`nL™WåBYOÅ j©ã—<Œ‹÷ ,Mž!—ÏÏ@YtÐÛ¸_©™ØûÉBÐ3oWæ´—£ ºDñ©N|±KÓ±¤v§§»Àìæ=ŠL­£è7zO1G㌉¥LM©+kß‹ü#ŽÀ öXÃð }ÿéod†¾ ¤,›iŒuÑd|s ¸oƒ4 ÆU‘÷¨Eãee ùºÚgV{ød7–×g¹´ˆœËï|í¸†^DQä ‘œ^ìÞkå<2¥&¯>¸|²9l‹7‹=uþ…Ž‹Üj µJõª]ÆÖ¡ÑC侌eº•·p3l£ÛÑêdžñé¿p!Q¡ØÓÍŸe7ÖY¿vžÃÂÌø‘ARiFä¯=DUô‚õ@á³C§Ü”×§Ba•‰è&l;Ï/°EÕbô1 MM˜4µf¨,1üò•.pÖ¾¸.ݾò&ûƒ†[°_"ÑV UmûÇ®-YõÅ1C³¨$ü'ßÇË»>Úÿ7™z±M —¥b›A/;JÅ6‚^v•‰&×ÃŒ° …©GòD$~Ö4‚®>=ïì±Ë1å£Î\Ú–Õ$Þ%ÜR•¸IÞæÆ9>àdFÄÚV0aÑ]«¦#°·g³Ôºš\ß” %Ò÷–"GÚõù#ùäÔ'Üœ[cæ/“¾JWÈŽ`á¦Ocÿ ÕDBÚ»°F«-z÷h¿Wg]©H+ò'oe£ð ÖöIDy>Æ¥™“MCVÊ$³I(nÌ0p&^"ìVi¸ˆ¦çé¾"uÚóþ[)¡oY™é¡ßaP¡ª…ý¤=NS=P_¸ÄÒÐå¨Ë;›­ÚcIºKBôx9i7»ú'Ò]¾@Ì\9Äø˜ '‰ä¸rˆ„è±eòDDPl'EŒX×wÜN(4®«Ëy_ñòúy1¤¼¹I¢cvjºv†iV3MÆÇ¶ÄIÂöæÈ5ádd®Ô)­“øÊ Ió`Tv?dë¶CŒgàØä‹ äºù0áQÝÜìü;QÕ(eØÔ1®nð—ÈSKo à6ÙmƒLù˜Oo|Sˆ˜)";À܈ÛÌvØÑa)•jÝ}~,Ñšºuœn¥L¸¿I"ljÞó):ð-ŸDí¢Œ•,ý¯¹¦’:à¿'¯‘Ä™H(î­Ø®QpVï¨ÍNt'c1nz]ê¿J1sXÓÀöÖÀUuèþKBþüM:žjÁ Ïdý´x ^±k`%íõ–ˆÇÙ:¦1“ø ƒ ù<哇0:r>mV‡©‡…ÃM/¶´”Êj[ô8CÕdTÉÖämË&§·[jiÓ¥oàj,¹±vD<Ž—g™@¬o ÚCWùM*¼°/ç²"†Òw7Lþëò°q—è÷À Þ>ò¡9¨&wþÒƒ!Áä.xlY‡•F&Âåó[ÃH;âÞíߟMåŒP7f­uÛ¡ð"W¨7EâZ;a&k#3#~Ëo’Í;ñëcmðš- æò,há Æ Ë|èÎß…mðÙŒ`æî@9h(Ý£mÐUˆÒÛÍÇ’dú¼S`‡ýEZó°qÊÒlYUkÔ”/¢‰Ebw¸roütX"m¤3ôúB—x•Eþ÷$Ÿuj¹üaÔÄ?…ŒÔæ¸BŒN§´yS”ÃîƒÔ iZæ®ä©>}u‘Ô»}•ˆÄȬÐ}:ïL8ìkû'b² ô0ªÇ·í«•ßýaú6Õ2ÇC³u ïgxxÚ‹Ë/ˆ|ª"NM¿…—;¥‘R”å+:ݤ!‰…Šbsq~2˜ùŽ"ÖñÑ3¿œ—øjcꙅ圌ñP] bd)йÄÔš²Û=ÅòGî …–<7¤ÇA¶³ y~Øc >’uw ú¦\|Cõ/9'wñº™u°?Q‘>Âþ^Œë×ZÝôÙ#ì ŒAI²þÓìÎã4rsEN ~ ÁG­ŠÊˆ©=V|Tþ|AizðJZm¤`òCåÌÊ8D¹l9uŒ@ým.üùø€ø26ú6ŠñجË.!ëª\õ܃Ò+¸t_“‹òcóH,GÜ6i•‰Ô™0!NœîŽØ†ø•EI{ë øË!ê‘, _¶ü—óH˯d4 îŠI~å“]ÅŽäO©Fýnœ“Ü|¡‚ͱO£ÇÿÝ¢)ãÚ&(úÇ6ON s¦WÁœðfKïƒïÂTÉÆ !þWûP¿Æx‚‰@?䊿mCÉF†¶Ät{\žd°„¿àaŽ )Võ˜WÙßc/"î#AÖÓˆÏÿ$¿»ψSBFTÒ¯|ž:ŽRd‰¤(øÌĆéFäÚ:|Íf,«æ,2f©Fn* ðgº‹V»aâW"-ƒ°×ø«2±Rxëåùb8M×SDÍO¨së¿\éŽÓz‰¢€êB{°€šâ'Fõˆ‘þ׆XEP 8Ú˜-ìãP×LI°³¸<¾Pf5À„„§—z¦Cdš,ãém´!³<î¦jÕk9ó›AûgÛÊbæükƒq‚ ´RÐ2ÞŒ†÷èªÖ;L•…„Í¡qËÐdK‚8í„Cöh4˜!B¦K[LÙña¦ûo€ëpÐ1 ¿W¸i”4Ò<Þ¬¾ó]h ×Ψúô°ñÊnho] ê‘&Z5¶8•Á’96ƒ°¬Bç~¹‡Ôj䇪‰>RÐ|!´~ü3X¥Ø¬<~’d9ïy3':aü­sG¢½²úqåpdú»8/AÜ dëwç…7¬˜­þ'é ½¥ß½VתMg;š¾%Õ-€&60´j& ŸwrÝw{s?ð±æ: ;çƒÑÛ/—±âÜéƒ'†íá0'…ËIÝ A7GÏG¡Ð]’F$¨d¢c=nÛdϺ锩Àè›§˜ÜÈF­ÝãUoÖš}Ôj_¾×Ìæ°ãÌÌʃ냈9š} S»`Ê=ŠIgÇåRúßJ;Ç…Ô©ŠØ/L–,ªÙud0vMà±ëŒ%b¼èÒºnƱí80Žêïp. RøÎ›B¤-‘Øe9X⺇¹ýÓ!8.|»ã¥lÝÀV‹«tÇwí_Ç9ó>÷ò»åˆêÉÅÅÇég·ýê‚ÌàáþO¹^*ÑÕ§–&¬‹ÂPßö£³ؾÙI \±9>ºð¦¹…ÕøXôN~ê˜E^á᨞B{T<¬~=³ÚÆÎtåï2×ýÀ»8Ãù%©à‚AÚ\‘ ’zZíÛ’4é‘°i_ÒÀ® ¤’þa×z|cÿ¬¼(¨å1´½‰FŠø…ß½ÿh †T[},óóö™êYUD~¯ïˆä aWÅ:y\Ã6¡!õÒq wTÛJÝ™rf^VGÆgÀw„õ°züTH ´H‡ïnGíCÎ*ã+ׇY·P}ýí§|kI³n†i Ý9;S$z`X-%=A a tŠŠˆ ¾‘}K\•g{¯¨e¤øR‰öi`lš^Šª¤4Æ.îÄcyßú:ÄôP†ð)yÈ1µ›“: |™]Ú¾l7á%Üß‘í\¹ð¦:”zsÈä•‚‹Vã~vÙ†Hy+òPE‰Ãy¯áåæao4€53½ïï=_HÔä!n*7Æ ¼,ò’°VYpö[À)baKÿ%ªÊ3»ƒvRáxH½ ™Þg›¿íÝDˆ/† F`Cw%$Îõ> ÅšB6Q{ƒÕHÛUE²–¡®N®P]Ñ:6ˆAú¦r”ë¹jÇümu)EHYÞ!x¢ú[Eß+ü…ÖBv~ÄÒ2tã•Ë' (u•&”¾r2³˜£5^"Eûe®E,Ì µ…¹T¦ü¸ÀPs¯'ž©^1o•ýÎüG„VÝ(—É{*þ"E!4Õ–Ó Žb·¦™%äú|}fµfqœ ß"ZÜo¿àŒ.^êm¥]%»QG qZ5„å8D`²çíy 6‚vŒÆï‘Z£ßTÐþV|Ÿ?Oý€È6UwLžŒfØ-vïÊD µÞ.^LB%ÆÇÌ2†ÖjÈltë³ »iw““•jZ$®uZÅí Üü27Å9¯g«îMm&œàÒ”t㸢|[ï¶f¯¹Häâ‰hïK­n¹Ï—óÏŒã=¼ÄrH'kr##ûFQœY7ˆ\·Üîw ¶êá8Ñ^Â~çK÷G‹¼¡^r:º'Lýê”ó¤O£ã‘ôaSžòQ²_Àèg²žqª%&`©²†Zù¦Ï•ù¿(ˆ¨M®ÛLð=O«ä¡dÒT“ÉQ‚¸µ·û\lÓw^€Ì¬¤3`,Í”2€h2ÝZÁè·ï<Æ¸ÙÆ5rÊtpi&ûC…/¦»–MO—Y jlsémIsIÛ;E´#31)G¨·WT%Tî!º)b–¦KbîÅXO~˜›Z«æLá%ß—å7F2ž<®äy­®™÷²ðìànûsqŠA»Õt´å°À£—%fSôü<Þf‡Þ4’Ÿû¢J!D®]Q†ÒVŒ(z±ÎjŠs`°pÊ×hבV]VüÂ娸¶Ñb-tS^Œ,C)/æÑì\Ô–ø¡÷HÃlµ4q<÷~Ïñ ±S˜÷©3‡È#r6FþƒA®éIx^•é‹`?ë_„ƒ¢§Lt«…¹hÃtŠÐùŸ €×ÕìyÖn<üY­²ñá!¬ »~]ZI^ñ£¨ ²±bõ`,rÃp'ƒ^S|“ͤ§\ Ô^l¥mL& ×Å1èc¶ã9 š4 †»¿£qõ×Å RûgNˆK@S0–Qú|HÁÿ<¸}­d±vxk©V‡EºX–ŒŸÔöThÌìù¨'=µ'†ÁÖ;ôL’f×øZ¨ƒF_œ1;ì»+R•‹1¬YÐèíÙ ÜñEBš½fy¶N#ž÷ 0·ä{Iv˜Ü%ÀåR&á-ôBòÜØ‹\ò–¥ØS¤È¦e{k?¢op' '¤’¼‡‰{3,A@m @†—›Þ•Mîß6;JI)9l#¼•]#¿¹­÷^‘O#hîíöæÞ½ÍjXEªOHëðV= ˆ>ÖŸbÊÄÞˆ_œáÒ|­ªÜ³77¢e­3ZøÅØ>”u#ê«Ýžd¾HÕ\ßÖu ûbgqL´Åƒ~” 5´`bà([±Ê9ÒkÒ Á=_/ü,³fýÜʆÏdþˆ킃4§Êûø†xº7mÃÌ÷n-kÆGLù…²ïŠíú@&l[¦øâ¨¶4u~ÌL‘Òè)#œ(ïÀM®XE1Lü¬õ悬H)óYÈ‹L È|/œFÁý·Nòo‡¹€Õ÷JbΑ¾ÿ~8GÇœúî<ü›Ùôn^\¥jÜÒÒó@KÅn8’0øKÕrîÅ-ðÇ¿(áÀˆ Ãdz6­‹¼ Ê¶ŽA|y}†5ÛÔ¾èV ÍT=ÖÏ @£%~!Ï4Qkq:Å pÂÔFMŽ;}Öô±¬°ð­¿y¢,â'÷Љ@"«â½‰|Ûuœqî™ÜÐuû ÈóX©ë÷ Ú ,å×Êy#^†áøsaƒê‘5š†ÛSŸ?ÐAÚR\F‹;w[-_"8O(™ñs*«ðë:òŠè½W Â]ljxªK³.Ç™Éï½X‚8HX^³ºœ70'å2®üV×üÎUyä|±ÀѲò…³–¬õa8/½&ëäºt¨rUwÅéU3úXÏÿ9‰Ü –ŽC¸YËp„7 amdy#GeÑ4-‹‹çÄ”À[Wðæ³¸À;=}BÃ-…-Á$†í¨5öÛ(ËòÜó5b'OžÆ;Êâ`¢Gá9õY`/à'ù â'UU‰¶“i®~ôñìQ Õ õÈBvbäÄôó±cÀíáßóÂm¨D€o$4M\Õª½´«*ðÞÖ +¼oE’µJ8OØaþr’)ÔA@éfþMÖ/ q%"Rä¯Z;ÿ§ì)^w6-›rZžþUÊŽHde§Ò÷Õ‡¼KX”eYžÙç´)7PüØC.qb‡T®Ï¾áˆÐµáT°ðå¡’ºsüõ•à Ñ`.´æâÚ48êZüÂòÏÌeUL¹ÕŽ=©W¤š:¾Øì€"wæFë/H (êâø0ؘ˜}©Ÿ,Í$kÌLåHfrÅð3âs¼þtÓÈ)Œæ×I—q›Z*Ö#>Év}üú)–}æ–ùq¸<®…—*+ ‹Pdo¹¯(ë6„UT«È7Þ»÷mQöBy(¿ÒJy¨<4/"e‰ñjyzí- Œ§~n­ðp2oGbãíkR•QÔ5}“38Ýfì jT4Æx½ŸË` qÄ’Ã§Þ !˜‡~êèýu±ŽÍ±)¼žº¹‡øVïκØúI|5ã‰váBuÍPwõ—±’Õ:fܾñ{áÎ:'MeÈûÌ5^ìü®uL„‚}¡IÛ–Gµ8(œU„ó€4ýcgí lܳKâ!tɯÌs¦.ÿcúpzþÿÆöLÀtæï…¯ò#‚R´¹.ÛÌ9*Ïa^Ïj+)+X®w;VW}¬-U–Î¥ÃÊFÒo¡o¢h†ô³zæ¯2Äö"Ý·k ¿ÈÅõ˜„ ŽQNûV÷šêKÀœ ùxû8X–1^äïB´l…¹× H? /‘ ŽLüˉ›¾T)/e ¿•|½:ß%qËÓ61ÈEloÍls¯ÛªŽÄ'u¢s× …y´Ÿ\"<ªSp×{ŠCaÕÕóo 9ö *Z½%>Z[F‘+æ½Ëód³—‰6ý…§©x gQÑž 1[-3³±Žu˜IjÒ¤"twðý!ÜR£‡Iª¨‡ÄMÒ§uº¥­îfžÂb0Ê—„ÿw¸¸n¤±b=l´’ˆÂ·œaÔïUm1ðYÇ¥d¤ˆýå,1+ë\ëÐrLæó¬06õ[4û0O¾åp`¤=•H:¨ñü®üq]Í'¡rK¡R·¦"63ÜS©ïA–,†e”*É¿¶.% ·Áü!gN iÓÄõ`ÎèHx-YÞç%tÇ‘VÇç, À?ÇUüŽœ¥ÀF‹º(¨üç¹ßiàq£K½ë#§Ç‚r ™¬Oe'ùÛ=¼«4¡¿;yÌCÉK8¶HÅ—†¨?¾¯ñp6Q üšÝd[fjPrù¢¸Ïï€ø“èl4xú²êkÎo,ÅŽzÁž³N¤§@à½Fd:R Ó̯ZjÒš´‹âpP&ˆš#¬]ÛÑÚÀ¦˜®O ñX˜[.2Áa…%Q‰}ô¸4ï3©ùÂN(4Ó?aϸBæç2)§SÙêXtÕÞ@8ÉcÏä2 êÿ 0â½ÝÒ3Ã÷M9#$ì/èq¼¹Þîió:óŠI[åX“§8xlYf|eŸHÀã|Õ~ÅäÑÓ9Aãy!™†!,½Ù¨Ø#O耣@MZ°¬ãI­ZÑ¬Ó Ú«æþ’ù—ÈMšºî½yˆHˆ­…ÿåuÛÈɿ͂ð*Òo~¶PD÷`¢@Ø9°AY'jSü(* %^ø‰÷Ét|ýŸÖÐö>Qv™î'y[{ʱֵ[" ØüEâr\YåwtDó·L9¡½zÀ &<û$ø8¶ZNÚhY{Æh= ó´§—©¿<þ2ÝÂðÐñ; .³$ÜÙò=3_ŽýŒÜÎ+Îõ›NÊ‚¡ÍbøI¢¸†¯&p²Þ[ó“ }Œˆ`ûÂEy>i4[OPÚ:Ý6êÞasöpÐZ%Ζc÷ûv.)c’Â×wI<Øæ®zGnGºP*S—)u à Û†·õ¶Á¯‡[vªÝͯ†ÿ„UI×qIx3…s0r€|íÆ‘˜Óý2í+íZ0Uc¹61&ÍÙø~B-r ’£ïBðÊF¶O2ƒ&îh÷í?À¯X[grFW•43´Hƒm²Ø9ÚfÒ¹ÎOô©ÏÝ =/“qJØdFjVh¬a”N%hMÔN* ™+7¶¡ -`Ù]xQ!…WþJõçq½™A² •uši¨Vˆ€²ëÌUå/¡n º†Ì9šd¸çOe 51¥PÒrWQþhÚ­\0khw#yåóP pÈ„¼;¾¼tÄ´&¥h¥3Á98c|f|*‰*K:3꜑‘ .ÐE'¸Üñg°ý1Pè lSðyû¥öoJš=é´—u˜p>Ó™« ÓöW5²æ\Q¯ÓiU߆9cÄ$–$"]—”ñ H( ÝÔ±šªÁ.6×õ^%| úèžûÈß u–Ó$ÚZú­²JŸ´: Ãþûˆ¤Ÿ³2UÒ­–”êÚWñ‚us¯„o£ãËÆì;hA~Õ&|éZvÆ}ÏEG(çýÁzÇ@f{]míµLëff3ÂL ·Ñî °Ï¹•’ÂèÛù°øÙ¼sXΣ6ñ3À ¯Ý>>¡V„ÓyÂé~‡Î~ªzžt›I„8>Çu8nHrCW;eÁ M‡{n23to¾K(Ë4Ùjà³eLd·—m´_‹ö¿\Wâ„rÜ>5yzS0sfaÄ÷ÔŸXóÑÀ\¹Ã¢y†ðƒçÏ3”|Nt Bp±xñ&45»SâeЕ^»0椽§gBœ—ƒ +¸ë>x¢l¼öT ÃH^$=C{»YúHšži¦íVÿ ”í`ŽÂ‡kÊW®.ó®òÛ¨z+þ&$”±Ç*¬†¿ ‹º—úmh.¯eÔ°¥UÒcWnûæ d³D¡:š†Ž_Õä™è pЧÓÎnûWæa£53-rÍášøÓ¢0¾þXþK¦ˆÕlÃMÐ& )-žɸªø2=_[Ä`Vg•. *¬\wò8@¤ÖÚ‰½¨Ûî½9¨¥SIÊobÎs;×銬—é™õ”<@E»~!CÒ+ébÖr|Éš1>€ü•ü0Ò×vgÉL8•H¦ò©µ®¾ËÌþš;?Y}õoA:ß î‡|m²·M-w±@SŽÃÞ—Ùõã¢\M)µ:!\"…>å¿v¢â 3=ÿ´D¯ø“Ï—èì{ÜÏv$í¢Ÿf×äÚA(Kç‰`vÚ*é–í¸F¼†Q©-w¾´ÙDT<rø];ñ71²¯u¹I@W¾§rÞr~è›`ìÊYŸxÖžmϤ£Ó›Õg·T7ôBºáûb­¦ùVÊ —­'rüqh Y~[¼§p¤–k*$$ RŽš/)"¼¬·zÑ8ÜoE×ÙØý.Q8à|þS#°EPêQèRC‘´ÒA_º§ÿb†©dú“&†  |ˆ?¢Ip¦wy®Ou$;XÇç[è L©Ùn“È_ûÌdõGšäi¥·JW·ï>$KµpN&þpâ9ÔNõs¢òŒJ£@4åzeXüˆPYü€àw€žé·¨½Ú @”y ½òÉHU\JB÷¦xÛ2Fÿm÷­ŠrA‘æô¼„…—Ü,Ðt;~+¸Cç„7Ps"$êÑb\TüJ–Œ8Ê>Ô`ü.²éàœ? Ps`ÙÜíèSÔQßUŽa`êÚ/ÝŒ1'.Usñ¶T%þÆÍÍW…\V§s\25q·Òâ‡ÐЭ‰ê׬ è ¼§Œ}ƒJ“äA“à»3\Sªõ•Mö2RéAÑÎݧÊwdØïòƒ<¬8*,ó5ÝØ5ÚïWS‘n9„>5ˆáÏØ?uHú_~^ûmSoêtt~dbRV+o‰\&æÌƒƒLø'aó õ<ÖìÙ!mÖë®ÛZȹç—?.”¼¢ }½4ºí1IU‘?è«#!îççH¡B"™5³'—eW±YB$nLÓ¸z³Ï£E¦Ãxv…„eïIæ« $DE›azçÄœFÜ¢d"¹óm°_Þäü y*gLý7𘀂^Ó¥‡&L)='YîóÛKÛ•âÐ^Ô&u<ÿ4Lu‚ã¶£• º‚z‰2²½0à€î& ê±Ìéê¨Ê=F°p[L‚ÿÿ¹^ž½@·4B*zÚ“E£‚{ª"‹ARogÛ½yþw|`Ó°eÿA ž-‰Öõ¸Ï)¯ráñc!©ažÒ)®–»ÊŠ5¥©ªÙþY8Ós=Jù»mJ¯§ 9Ñ6±ò.½#ëê˜bÑZ1_Qbó=À‘DÁ's˜a6rÌ*4¯»â.$ñŠÛëÓLg’œ¢’üP·"Rþ ‘ë¾2Âc:0ñ7'ô‡Cr¡´ÌCM=ôWåz»ËÏšïàZ©°‚ÂF@ý8£7ÞSù ÊRõÇÑ@_è_Rf©çKµy&§œi¼(øô`[;i2DS+”øgªÌñe*ßÍ*²¹Še=÷h¦wà|cƒ«¸î”êgÄoJýk¿²ãž'Ðß–¬aøf§†B®÷¸6@ÖȪ&rs$'ÂŽæß«õ`ð'|‡¾Ñ ãTÚF0ŠþJáÚhÕP‡†FÞÓð’õBM!P¶CHÒP“3N‡¡˜ou)ggÚr‘W§{9JYMмy:3ǶÁ•q<»i±¤!žv=øxCNò,ôJóB°Ômc™œ·"A»@³ 1ö J…¦;3ΣEÐ|DÙþ3ôaÊZ§ÅÏÅ7Ùs³•5öûBxAZôx ¯Žòȶ¢¬Cz™JõÅÞuÞ[T×<[ä!W­øD*WVUìr|¾Y·3¿>È4½•;n’IP)GZáÃ[sÚ1PZ`<»0΂š¨9ëì€5°Å4O»Xk·•Oqqć2©£·ô\è.I›æ!ígBÇ ²Š¼Í—¸_ ‡¦ÔçgŸ‹Å]Øm³d)âÞËÈH.º¯‰1Na ×rói^ʺ¸È–Ú¤xa›Ç 0Ô…Zß ‚ÏÁ ¼±I‡?჉`)ÁQÓúZN’@* ›'I#ÁyM^­n]̤ˆ¬ºE†ú¦no}i²*ˆ¨x }pcû–Õc¬ØUwÝg‡C öÏ¡àB/N­ˆís¢¨OœÙuy»¨Ãw£æq•Þ£úÏñ¸]¾­e“ØÅ™)Á„^Õ)8àa’ ,-}ÎŒn7aüš«ÄËkÙÇÑã·ìƒ\جÙß™F|rê;P R@ŠJ¿Úo&Þ'½¥×퉅ä„!œ“sâ}7þ¾RÃ8H‹–¢ ;5h“[&*žN5ò4*iD kÐb“€t&%Ùn™}¡sk¼!à‹¢ j°õ"6ç篥>›ùÀ íþ±½JP€'Ç6”\3 Û—$’œ}¶b« Æ”ä¨ÅÍòS[3íáNÆÐ„mœ"ÂÀæ¼~¢Ê”$ÝýW^!|Œ…ëƒfŒ" NáÆ…*j+¦da45E¿D‘Ж†Ð•xªˆmfœ_ÛLjÏæ+ÁuïbÎЖ+'=y½ËŠðiÂBk‘¡ô @PýÀÄä¢ááߢ@óÇ}<‡° >àoOMñû”›¸W$À9ßÈÀÙªªÚ†­7ºÆ¬f¯{©ÁEãDè§Âj% ©º‘+=-ª&öwÓÄÂ.¹^Ou‘CŠ› !¡9’€G‰=Œ‹ÓCð›•fôAf=ULðž15 â¸äñ oø¹ùŠÑTËþ90¡óœb;nU¿÷§Ï,ZAÛ«,~€"ÿKûß…MY@ Ç«ù*òßJO1’Ï1‡w%PÞߟoì=ÝZ"ZÅ>mo1f ‘ÇqÌ\NçÈù…B Ù O ?%_ ƒ?G¡·Ÿ®¢´ú)#«, Õýì\Iö°.ó“<Ý7ÓÓdlÄy Q/öf¯ë,Ôá ÔúEŸ¾ù'ËÁÔ—.Mˆ#¨^ãÙP7.è@± @æ*ë±J„RVF ×JSÝ\¡A»Ñ{$Ö#;«W¶Z-PðØýÉ—í ‰î¾ÝorÎ)ËdFÇ Ž‰ÝÏQA=oà®”ÜÚ®¶¹Qi¼!Keh°ÒÈ9²m5ĺ?÷`1,¼‰OËcbÏì¢De8*ø,pûJU‡oYÏI"V<ÀL…]T^Zg} æü³ àž5ߥ5f¨½ä®Rºcí3¨Ào_þ*9¶–¥¶”¹åò/Ý4O_Ó0a ÙךÀMoú}H%gšØÌ&F“ªë!#æ"jr‘28º_^G$_¹"1rˆloaåv 솸„aPÛì0¶_ÆÖ\ø-Ñð”¤Û¦C™Ñšg%7$‡ˆ*ê±u@Ä ª »Çà+b‚{Ζ³atHéƒÓÍ-=këÓöÊ| î,Jù•*ÔË3¤¸ÙŽZE•?æîÝÓù½”e²êÍé i¨$ŒðLUt˜ÕßÚ·Æ€î¢.þHÍ+x]^uíÔ³j“Œù5ÊI0Q¡Èâ#Pá¨ÚMAçE\{ÆF›¦2!i¬Ì( _H®6à¶×4¿[mu­ó—÷àOʳüõ]s³ßÑ_â¹g—ÓÂ2}ý´©E”—(H.±~=¼›šBs)ZÝj)¨„¶NÏLØÄeHddP‡ôpÒè¦[½°¡°b<¼Llìð~âVL–@ÒGd?ž)¤7#[è|×ܦ:±4†:ƒ÷8k,‰Ey›» 9´ã…?Ѐ“ Ò ^¢¤:øÓ¬€°^ŠÝ—nr¢çÅ)^ºbÝ N,œgžJHwó^øá/F"Bêd±Z ·ØfJKŽ3üžR„ÅÝ•}Ø.úH¸¼ûÆ´ï2ëP]—[Ô ¡¶¶7úkŸXì£ôóÏŸµQ+È §{II·%ã,iÏû9 x'Å»•ÁRkÍ¡ÐéÔm,K³ct$E’F]YöµÙÿHg> n9ÍÜé¤cÒ@mùì ?+!6¾#N±dKŒJ(󽃄€U9PxYévÇqJSS胡\1œLJI§MwÉ¥¹·CÝLü\ÔðÞÎAQ-’·F¸7fa“ù‡¼Ã1ÒúŽ=:•³ÞmîÛ¡x†š•ߺ5<JýÇîÖ6ÔÃ5ÔÁ¶?ÇD‰Ü´‚¯ë6K½b–`IÝïá\x(qi¢[lW®íxx/سÈ(Yõ®uì¶Ô¼æÕº¨Ãq¬´öûlšÁùþ{ RÄ™lÈÝ0ñ`¾™¯wæ>j‡4%D+æ¹­#öo4Ê]ÝNo,¾)>4ï2Ý´ð{{ó•fãA’p¿,ìñXÈŠñ%^ºžÙSߎpåokíëI_ß 7Nïkz˜ÔŸÄþ‹9¸ê¸¢âÖ“m“àMLõêt· Bs–ÛÌBõdhUï˃ÆÖ¢0ìÖÖ?ç™â÷žfâöý€âðhYà4øØ8­©“Þqvè¬)4J"ÝïD“‚Ô«,¹ñx."%wà˜øø Ù½\“èr¹F=ê9aãóQ·7Äe\Âͺ¤¬;ˆ`HnU3­üm‚fŽ¥™p,ÙNsÔˆ`OËpÐ.¥AóÐ÷÷3½C¹!ÿ½Êž§qa²•1(fßmsx$ɉú ¦­óà® ÷^Ø ëÌû{òë ¯«†æ—eù¯<±¢ÙÉ¿ò6YÓ_˜ãå¹ÔÚµê ÅÇ3¾v ØY0 ÎfFæ*ocÅ–rç_ñM”]© ñ¥gaw¯Œ¯á’ôu¨Ÿp)Ã,œÃõ  þ[$¸‡²ÂÊè&¥ (ì}á£ÐR#^/Ø(©BÕ‘>wvùÇYKšÖ“X -<‡-;üÚ%jòÜ’WÛ`ór¨–dá!Bï´FB>Q½$1EØüaäâ½Æ7àyI£ßLŽááÐN¿`Ò!ð€ ´\"š4SýKÆÇ‘) ·[9ÎJ¤¥,?ÑHò|õåH¬i.ã)ðg…† ¡Á(e—³@¿“å—›Î^ø¨ ɬ,ó.3Ï)L´Š­ò¹ÙeΣ§XϦŽr¤žò©Ô¶¡Ñm§_%­]Îy3ÞÉØ¦¼r|›¨¹¦–…Ô¡9m&ð£¾R[(hƒxC¸ö’}ôizùB|óqÉ ý ÕrißÇ"ü{ˆ¹$ )U^ˆË{VjrNÌr-×Û“ÁÓg"›!6IJ;ýпtìãu¨’ɉî•;Ió_·)6ˆ›Úeˆw™¦'…Óš Ä\J[ûërewÂë©1ávOœÓaå~V>¢¾ù‘­ÞJqˆ t*€3m³“¿ÔUy]$ÃÌÞ v¾ÃôÂç[È_å"µŽÐK{]ì}O‘Áá"‰ ({E³ïß°e†–CÐÛ>{ÅÓÒ@³‚ë2@×UKg$Áñ‘êfбˆhüڤɔ,P*Hèµ?§@b”*sýbZú{ýÏY;˜Ù—}$þ…¿ ÞZgܳ2Nôñ“°àÎFá åBh8ã_<Îéöu6Q…Ð PÛ!ØpÜ­Ál7€<¦ŽBi€­ ÷”ÁžSÇcÁ¢väç¸õ C³ö"ýä›Z0Õ§óÝ,£64°~“ø>,õ;PÙ/P‘Ü<¢›Ñ·µÍ·Ëø1&UÊq7ü—i)€V;nHìa¼žJÌÑ#Áã-"½.d¢ˆf²&£2mÞ#\Œ q––v®ô7¾~…%H°qfò^-Lüï,¡¯&)…ƒí?ßÕ¸\ˆ.ÒOßý&ä ݨ0L=æKÄé¡!51·M r/¬›Mè8å6.‚”?sÇùҋЗRã_^U°ÅÓ¾hVdÝ5•tÅvФ*Å«\›¹{ÕSœgÕØüѱ/AMß!ο.ÝRWil4ºížìäy¾Ôz:ɾ 69!Ík%›xW|=:OØã†ô›×VŠÏe…‡h‘nî$įý?:zï…wYM'à·ÍõŠ."1Ảµ]µó¨Þ<ª-ªÜ5ªßØÉˆv",ݓجrÙ¼U·ÕÕ~T¶¡ê| MŒ'oö´M"7¨¶’ƒ:YûÚߨes,ª °/*™¤dD{Æaˆb[çø SŸ”Oœ~ú4?×^úí¾gfù6dÒaü0wtª¦¦/ ¦=¦ü¶Q°±ÕíÜœ'"(¯¤|cμSJ£IR÷~(ááù&»ŸÏ%g'¥*£¶ü«šßžÈ«æ©$ÂP6ÏGµËg•‚ǽ„ ¬èS±¾ê,½ ÀàZs©ƒt:yÝ®o1,†% Á)Ú®NXü‡zœ“k ËFdýM»º`Õi5s,e`YÏ’ÔØŽÐó&uF9,gk^pg|»$JíÉØª÷*úHëå°!:!u0¬ ):l8aA‹Å¯éÍD°8|¬*æx¬¶‘ü/@5‚g$’™\lîò!¯ÁÍQúö€ØašäÐè1 ÊÆ3³Å lµÍÞÊ¿åíKqÅ (¨ØëHú§6ñ튛þ¼(`™¤“'2KxË,+¶ã;æZT ¦·N•h„¹IÑ)8/ö¨äô+o#V¨îÜeÅå….ãû×GŒ]®+h q|hÃÏ‚2Æî@å­B©9¤NtÕ:½‚”AØÇ2½éCš@ɯ:icwß3äFœ‚ßT/ äëÍR¶|mö¥™ÂkU´ˆE ¬¼ê˜ÁÍöB%郦Øò;¨ß7ùFÊOXÈ u¸J¥ö5/%AJéðº<ŸUž&\%]Ùö¸.âß)-çÛ1ºÔ?¿›ÆC…­=‡CVš \Hؾ”cÕ °©æažEâÌ*ž¯¼MŠüÙU`Fm|E 4¤Õ¯+=€Ÿ8ÊÌV-y"³çe•”ú ’…e1!ÒÌÊ+(Ї/Pj b.Í;ÍæÏbÐÅZ‡6Ê{-ˆûÐÅõ¼”³ —Úñ  ƒäGøW©u1ƒ•åÙñ\Á$s©¸£€í}ÞGk?onG±ò{hPjÛ(c!]ÍZáÇà?Ÿ`ïx©”œ½q®¡”>Å-Œâ ž‚ZM­Ù‹ 5V›íKvµÆò¤Œ4_„ÙZ)·é¥z¡‰Ìq+¡7š8ÄKSpOSõ2¯‡áFd!EïÃz½|rJåýçY ½pØø"h"Ê-•ýØB –4†¨ÖÙœ,åøÐE³w¬­¡}ÅiÓ<‰Öœ¬Q_0È™´˜ÐàÇ –°Bí´è/a·æVÝ&ÃxG}LÇÂöÈ8RAúŠcšoÍ“˜¬*Ÿ£ÛmPè¤h ðš3 n†Üj£®ÝÐn*+k°‹em76$¡ŽÝ}=vó#ù·ž«¹ßžV¯‘䊆Iñë«ý!Yò¼›‘L² wfó¼¬sßFŽáÏ6².¹RËè²ÅÆ7URËàþs‹‹L²AÏ‚£B/ˆO>>¼·îMxذJ‡ôäàXE?V§ãånMÐ,¥õ^ñ‹ª\÷l/UgލizêÙ¢"P­Å@œ€(RD(-ñH;Ù³½drºðXDÌPüñÀ1@>ø°å”~+ Ï2t‰Kz+hhZË­Ì1“Ú¸6uQ(ö!˜ýº!Þ [#wƒ‡8ÉËK “ÈÜ(J4-­Î¼{ùÔÏÜÐJÏ3xô†]“»q_1 ÄR9Áïø+úž)»J°£¾ð<Écþá`õ•rüTøÕUñ7øßΑõ%#]ϱ96¾qãžöAOý:†“0Zi>’^|®N ÐÔ²1 }rL]º7ÜZ\!@º_ážðU·…Ö%zÜQL’{‰—1ÚÿmÈ\Wã·ß)Ÿ.¤Hì%¼+ v²ozÏ#ÖyŒz JSWXH)üˆøÛ1*Ær6J˜Ì‚ŽZÎOûr5 EÒ~³—nH»”gì:¼éhYÓºÜoÿØžâŠf!í äÑØfÍN΃rd3Oÿ[Ç-cOZ¤aŸÅÅ€-ÚéNÀGè7U;†9éT“søÿoØ“î¿Xj%˜®—þ™Lc‘ÛšÍÍy¶W„ÙM*àgäÝïÁ&·Ü9Sq©5ÍJîßÎ÷Ñȑßh šz·im6Ú¦:Ë‘×Ê ‰ImQÍ))~p–ÀÂ7 T¬M¶wÝ«²‘\ 7ÅY”†Jļ»9%éÛ)“çäOpõ'¾š7ÿš)nÒHÇöa¦Ó;øÝ)›¹ÙÊ6͆ñÚe½0%äZæV N8üâ?l¿$›¦S¡]fgù®`”¶¢kÕSCÇÞ_d”¢·§‚òª0ñJ¡Ç¿òâˆÕâ›÷ ™‰ È°àòÍ÷§0º)2½·jÖŸß?ÚÛ(ŒuÁÓ¹¦µŒˆèçg¢i£¦Ëj ô¡Gw£öC@<ãdhÀ–‹¡mÄQ~Ït²¡3…ءݩôÒ©ƒibõ¥üNß¶(΢‹é²]yf|nœ|éÈ–™Ç²Å\䊄”Íç°‚±gäV—¤ÿ»Á‰¹ÉRì—šhtûEôð´,oW³n6h_L‹Ü“Ërx"‡©­¸r°x€Ý‹¥”Ï€=Æ1•¦Â¢Àô¾ycV›@û8çóŒoà_ω¾ã÷û½#yc¤ZE¨U:Å|lp§£’Ì›iZvà'X!AËŽ¼bÂó´QÆH3…õq×6 ›Óë7£¥øñ'íù™ÿî¶`V¨g^géõä‹yRçœ%ªHZ¦è*7UÛZHj1ÑE¤X¦H:Ðà›‹Ót¢¬Üq¾²·}{VÃ÷u Sdg.NJô}çôåu%óºÑå‹Ã•J7feœîÄ–œ;x'ÂØ3%MXþ{-XƒŒÝƒAB;K8µHP xb€°ƒÇ% úJ§Î"yýdEYNuv„RÉ3¢n—{éØƒU ¿'?øÈœV8€ ŽCǪ)Æ÷xaçöúHqgˆÀ΋zè®t@PapEÌ@Ò0ãL¢òÙhѵ:ítrÁâ'Sµø¹3JʓɰX¡õYðG7.Òžô©€‘á°mè1#Q!ûÆ´ñb€•"L1u˜R@ȹP­qÄúY»sà€JPôÀ¸þ¡{O‹r+F\`˜¬’ï \މ¨4냬—?¸ðúCŸ†þ7qz|‘S:3v<EÍè°Î'ZÔr‹9$_vÜs3¶”9óí;2ÓOy8§ëèèLk•×c’.UÍ ci"¨_Ye3àÙiÉŸg=Ž.vöhÿ¥kõ4x“òÚDO¦ƒ:fIЍ9kª3š»ŠøWï!¤&Ó×Ë‘ 0Üdª>ªÖâTE„ˆn³©÷àBI+5Kdñó÷>¥iÊ´)HÆ݃rð Ð ×¼räg«/ö¨ahu ¼f7Žý{"`Š`j_ÿg ½Q×ó”ÕâeX™)e+Ø£ Ìo#3®–3\~|ͯSè2Üñ•RÈ%+;oÊÌî@ì¥ÐýÁ©·;a4(CBv¢S¢ ¿am\ÇhÃÔs.~=y;ŒÄgr ©Ùù]b”¡p‡ÍŠFæ 1䟲N`àQ5Û!v–š[ÓL4CñîR+!·‚f0þâYW©h8dÏç6 .íR÷ý·®F+0soügKí“zÙpóì+fb}&mwôÒ’Ø?œ¡ÖKë/ÞØ¦ö®:I®tÍÅ»ò¬­Æ¬Fç.©à½xY}®Sü˜W@ŠŸ,ÿüì¬÷´‰D8ឪQ*%|¦ÿŸŒ\ω͖?JR8´E`¡³o˜‘ÅVQ›ƒ^ª±Óë—…)VAÌ2çÝÚC‘©à,°LÑ14w h©NÈ—–ÃØ iˆü`Sv0ÜPSUˆ¤ò>NÏyTØ)KiÏ#ÑiJØŠI2×ä½Ä¥QØÞÜH„ÉÄWžæÞ’ô‘2[.£Á×oºMØãk«ˆBÑÀµÂH«w˜\4;ÅgË<R¥ÐÄã¤`9á¢Ñ¢]¥¸ ´h—iJ˜XpÐa”‚2ž6ƒÒªg'´ïP%t~c›¼ÃŸŽ „zá/1`‘7~îä—ÑË$ô5±¯ÇË2pŸìM¥T€´‘ÊóÍtŒÈž:Ûá#Q–mƒD¼7Kfù®Œ¢ÌZM™ ûºç‚¡e_9˜nU´ÇsîѦ½R®Ê&-ræô‹€Ÿg*¢«›{³RX¿ÂÕN·ßoˆ/Á‘kú>é¨PÑ%/¨ÀÇå²éÂ7™”þ¡!“äŒ{ÊmzUù“¤±¼?€çÔ9Ó11ªk‚z5ÁÜ‘¨Mq~Ó4®Wò™Œ/¹ø«Mêu\y曔رø÷Ö9 î?F_÷ð¡(éX(¿Ï ÐsàÀ“ÌÅÜeŽ ÚØY›ž…L·àVëƒ9‘ņ3t~º¦”ˆ‘ï5„´2ñ8e]œàÞè (3ž¿Ñý`9ƪq¸.¦ÀÝÊW«RuÛ:fØýVŒ€ê„KvÈ‹L» U–nåW¯}`/ÔúSC0_ô¯#Írä%ƽ&‹Y8©úÜ2%2]Üïz¹”Z»ªq´DŒdÇ´éþž´Ýó†7’J‚}|@­ô[/´²=:&:$D™mÓ—Þ®¹šAé!âÅbN-²}ÒÛÖLw§É&y.¦TR¡‰,KŸAxr&Üñ8`9 "ìZ’jpè(EúEÓNøµôb´k½G+ž»-Ô®$Äî‰jÒ¸éý5<¥€CÓü}Ìk+°W|™Ë½—+ßÉvW å:Æ{+ÜG€djá¨9»#ß¿ÎJÖ`ÛEc0ÖFSûÄ€~ÑKª˜ÝÙ¼©_Ë#nüýGmúȰkHSií„‹kmÉ» ͦ£cª«Îb[…ù˜¯i-ÿF«®]C ™ ÂìsGõœ§Á¯¥Úå†<9ªw¥OkMa#ayƒý<'ƒ¯ÄÉïç“©V>Œû²ÇV1âi¸\K•ÿÕªFkkY ‹Î™l5q8tê™]Èo´ZÜð—®{ñ0q)„­ªÚCÕ ñ³ê7ûê”öRÕ.Â[™jd9„IÌ8(‚8éã _@{.ЦNs\芥†Ô>C¯®©˜QU¢Ý¤É½X*|€ÈåYè˜ ébWýu}#7#jä5p72½rxÐ//”+S¿ˆ—ß½õ&[Í¡âT;r¬…;í®ý"¶£MoŠn²Äéf¢³°.ñÔ l{Yï—ŸÏÙV’Ù}Þ¾Ëî´~ˆC0X8ÓtÍ®DzæT"4 –atß<ÁOBÿX̆Q ƒyOóÞ'=¨3µUw5iZ"Þ ýò ˜ÞðoÍži¿qJÏ!Ôô‡q•¦`Ádƒgέò€á5Ê`µxèÞ06Å~R;›ëO¨˜€ø%,“Ñš ³.ÿBTLÇÅåW|ÀºjHã_Åÿ»(z£JŸ‰î9mÌÀS +½\‰&¤i(&Ln)ÿ¾_AÊZø/ûî%€'Ü¿TÚ];?‹ £•ÔÞ2 bÐèøçoqÎÅ“D~V¬e ¼‰.fAx@Tìz‰™­O%ãdÉ> DÛ¤$“AØ…ë[¿³ª³ŸY–Šk¡m§.~FU31øŸ¶MöRh ŠÍ.šÅ²Êtˆ³’ºZVnV´­Êتv›`2™Ãøç1ej/?òø;¿Ì ðÞÐBŒçaÑK²=äyo‡,?©§{hrM3T|ŽÙIᘃø½lXÄ—kKƒÜÌЋ!ƒÄþ¹RéWÔ®ëoF»Í&Q-,ò‰7m¡3ä)4ÄX¯šÿR7aƒ7yNšwtÄÓ{°rúÆ¿S’3ìȼ¬3ÍoÜû%•F¶ã5Ñ× þmfH*/§®ÍÞ÷ÝÅhžüjEÿUØ5⥱\ƒ³½Ð"|Ũ²JÑ$8}X@iÊ`>îæ:ˆyƒ°<Áxd„†>1“ÊçI×ã"¾îέmë&¡¾܃y¥—$»!ôfBÿ¯Çßürkö,Ç~‰™p§Á\6 uÝë”Zxªæ¹ÁgÇn+—ȽŸTðÍÿÉ]“&|“­ ;P¸™C‘æEpÞÈa]AÏP¼m ö=áû¸'¸ÀÆÏäbù0·r-wá:)¾% [Ïæäq•°9žR„RmXCj$É`%î•\µÑYz¬½ã¦Çùô¹Eäð‡ú|̓¦nÇPsöÝIºki²_ 'òã{Cºýc¥ÜÌ 'ãÁ÷}#ùçË›IG0¬Úkô L—Œ(;Ÿ'þÛ\ÿÝÑÚèQa® lœþ¼ËgEE¯D¾P¾ýñ¶‰ÂíK/Ü“T ÷!°×œqþÞÖí2êÆúŠF8D¥Ïq‚H\‘Þë ÎR|Iû/:ÀÀÇUW|bÙ“ ìh>˾ f¡¿Â_èŒNY¦Ü·bÅVâo¦DšË9դ푸vl“?ýœ(.Ü$WÊÌÐKÃä èc&¶³CœËÎÔZîÓÜ¥ŠM “÷W-5ä¿¥‹=X³npþ´‚KµÎ|pŽ.Föÿát«'^rÆ!T4õP£Ê ±Jò{.zÀêP,:ýF3Ÿ«Pmï܈C§€öL†C£»@I¢_³5=À Þ;aú™ïöD\8;ßìŒXöK¥‚KXoú“ î¾êÓ„—h2þ+ÚïñdKA2’hÁh87¾lÚ´†òÎÌ ã;©ñ÷·zÐÎx‹"êÄcvlAO -m{PJæþnªæäë´^ÎvЏ{”Z‰x¶ „½‰?“»CÄÊËC²¶x¡¨Ûߟ¡ÍÕ&î]¢ý½ºÔ®Au ôÍKSéodG)³Ng`Cz·Ö÷’`„ÐQ‘‘ꉳÝüç V1g>ÈeŒç}ùdPrá’€>)ÎÔÓêF"… ›_yxÌ$΋ó⣨%b˜pwAõåN¸ïE´Á~©˾CW ©¢‰ö9‰[ŒòL3²¥–YËpüqé°L, •%Y…óðESžU+Á2É­~N¤ãíêèoWá8þúð¹‹wÃÝ ƒ+QéÔKAv;ý¦-!ª¨&–g z ÅFTs4.ªûz/½èεÀ`­75ÅfœK L€EwBŸê²ÜGàFb€XäfPŠ€jh‹M*Ïz(¦;ÎUð`qåØ÷7™ø,¬eCu•Þo7m㘹-+ aÎ y§}}½³{kiµ“A^ ‹iöØ8^+l¡š5[> ¥S~uVþÞ:$‚œV5ÄÇÆisgK=‚­Kãmœª—;Kb¿€´äŒQiy®YbûÓ¥üä"Ê«U®“[™QzµHk¾9ñ%[³î‰!Òrƒ?}Ùö úëÞk ïÄàÕi—ù“˜ÎPùú&;´iú~Ã6øÁ"»6æ©&*Çp ‰çšff˜è*Ksø€eÂ.¤Î-âŸÙúÊåÉ [W¤á‡gÏ¢\^üîø|/©Ì¶ÊdÒé¢?B¶¤Sp[¾™_š¡ÄB&D–£]’L=)·L†az ûÒøTVcé{Ío¶M ž ?¹¼08„홑› •š«ªl—‚íD+uÖ¾õÌàBŽböNpžZVð 8‡¤i~%y †s;ßL¼äyÑïlŒØ6µ3\g_¾¶ÔhM¾´ï5ãóAàºâÀ4æ,ôKzÀ>¤eïÎRdR" -9XÛ‰.èØøCö[³©«÷¦É•3XSÔÞïcÎȆP€K¯œM TÂ')DU¡¿¢‚añÖ%ù·¦Ì–F•,IŒç}½ç?x“çV@±zü}Q'âPsš=¹žK‰Â™Êã¶E³‰U¦b}ÄÍÌì•À€¤ÑË5æ~OœÁ·PݧH%g‡ÄˆJ‰òQü³³\§'la¦½ø·ºa&"?Ík_¦Ò¦Ä©§ j¦E0ïíý8¡–.à5¬ëyYªò • ¹ªSôö#‡„•hAxCW‹Æ@ÁC3‰hÚw½SÅ—ùð+ó pNuØwû78‚è,Ø–_€S·~<©×Ó÷RùD˜¯Û2•5-W³ês9 —(F$<íIüŒTÄ_šfôë /t϶f¦Ç²N´ÛòDÿ+œ[ªL½yð(—;|ɨÛJÖaåÒ9Á2Ñ×êè¤qãí÷“3€¥æ–¹Bù®O žS≖/«p8h49Oª0X_Ÿ·GjžŽ³c¼PÀèWžøÂm¶‡Rö×Å>º}Ry>DŽ­ wXyWàü&¢•xŽŠ×šb.•ŽÍ ƒ —lTõm<\F2ÀÝlŽ YNòT¼‡ï˜÷«ÈsË4çâõŠBÚ™Ø\š––*K@“¥äkÜSmñøwÉ-oXw~x³ Ó?"$/–ÌccåGjEVfƒ ‚ &¹? œj#Ä æÎC\ŽŠ_R;hŸÑ{1dy¢¦Y¥ t`m¨ ; =Þ½èkÝ-ÄqÒT3;8£,Ó­c>^¡Ɔ¿¥Ö.Yï. ¦ÒX„`f ÿým’ŒÑGMãQ0ÛnC°æÞ…ÊcõµSÂü0rr®ÎI#sµ luån]L\ÁyûYb2ì 0r9üq6¢¶Øv‡¶²3Ëçýn¦Bwǘ¥8œ{Õ.o¢¢³-DØ>45nž¸p¯½} q^/\Ïñ¸‹Xeãž’­•—®•ÿËZœ5~¼rÿ~ŽÆ­t›Ê-Øãñ‰áøÙÖœñ3Î0¨‡jjêK†V#âÇ~²vP(¸K=éb¼•ìzm¨Vö{…Z|!;2q±¤&ù®õ Õƒ‡=þÎ1â§lç­B»Ef@ÍiÉ(ºè¾úæ.ð%(þÉí_f²ÝðÆ"æÜ§È®ºüIÁ®ÔÚ-² )Ö³±BS-½âI“ç]°µhNbÜÛ¦rþB»Œ Êǽ—%€2ÍÆ"‰ ˜Dlí)ŒÛ[q1ï£-„gCÚwI±÷¼µµì>†Æèúã‡õo ðJÑêßz!Íé,$Ü!¥}Þ.‡ÌnVI²ý½/t¾b¬p07®ܾRÚÕ¡°P.Ý’€B÷çtoœ\ƒ\غ ÿ‘7$94æà¤ñj‚‰-€-‰þÕIOD5§ ~ M1,ÝD­q„Ý‹û}T¶o¢Dâ‘8¶ÞKÈûÂ'—ÿÒŠ+Š“µj6¶K—n»˜ /<N`½Ç‚ÕÁíG× äf(ü\¦üMÓ¿9³åÛ™8ˆ6•·ãk¶zº3m•´çRùW3Y–XÒ]J8p áó–KÆýA˜fŽdõi¨3â;Ñ/ ˜á[ŽRd'¤@-EézrâBà6·ŽÓæŒ÷çý×FÓ¥ÒçK@q‹A,–\Õ]è­%UžLõ;"†:”ž bF—sÃڦȯ@²ŽmÍtÄ¡ƒ_ާóLSì­3ÇyÈÝhKÊ]»ßÁV zO¯ö$°cx{L÷EìÓŒŠI%“`ûšn¾(Ï)]éóòë[X3ÅÎ ÉP—jýjÖÿ÷dE#ùê`X’{H¹w/g¦U )b„-n@ùóÉ>yž|Ô«6çäüÙõœT âïí-ÁYÚûtš|…MϲlÒ9ÔAkV=âDê³Ú\727êa³™e#Z Ñܨ1åé2TXá;îC„ƒ¹†rЗ€\ôÍÒÐÆ¢‚n2p™sç€5Õ•â?h)_:•þd胧'ö£Ì9v¬z0^¼^L³¨W¢z=6? ÁAÌ2IÍ÷; ƒW 9@#õéc{\\%Æ×–Œ·¼Y«–~Éð¾mvOceõè=sïo²t'®¨LœÁLTë'I¸yý@ WNÑA—ìÛ[BÔ±¼/„Næ we–s}ê6Â+ƒÃÝÁþ˜:9i’̘«}T´,Èï1Ü®ˆ‚ÊL"g QÔyçävMÁÊèˆ#ÉŠ&íÊ&鄸c0 kê’V—Âætï äUÕR÷ß)ôÄÕºâî•,ó£)ƒx!iNA½w2"ä\M-—ÂF1Wûþf%¥³—G%Ì™ÎÆ7‰»,nFGÏuív¬g*e—µhyÆî°hyâî—­Ÿújþ•(:~‚É}>¶æC7ÙR‰‘—ˆ‹-7w€ÛHÙú*ꪮ-u ®n•Ff²T€%ûjI_Šøý)dêþ+ñó†ƒf(ÿ/’Ñî´Æ ý/›ŒœŽ³Ë4ºL˜\o‹FT¹P»v Ú* ê­h€1_l·¬ ܪ ¼K‘”§ÊÜ7‰"}k2ïV„FRëÇEþb¹g£h×Z´°Ù8á©Æ—dÆ ´Ù{¼~ûJjЫžsÙÑ›¼B$ö€Ì¤3so‘`zРÙSÕwVõÆÔªZs|XÓÆÛDTŸ?CT˱ yhÂj´¤tRó°0¿Òô‘Dáx9äFì‰d„áñS»*µ‡¡sIòSÔä)—ñmŽ —¡Šl÷@Så×Ñå¼fúåby +ú®±îÊåÈó\ËÔDd¥<<ÚŒUçà.yÙ2.ªpÌã†gLÛ^o…9•¾k›”¿©]¦ª¨n·ÿ´Î ßMð2iî<(ÏñGýÆñLÏæŠÔ¹‚&:CõÑÛá"ß‚Yž!|wê5·Kp¶ìì`ñ£ òs9´&È*Ùz…ĘídcZ¸sL¶^wjkäF•üD6Suû‰·mÎwçŽÅ¢°íu$‚ËŸmWßâžØ…R‡Iœ ‰ÀX %ò)㵎þ'ÊËoñeEˆ”}•L­ DÕ\3D²"â½R+AØI†ñ6×DJª9«Åc!7d‰3d˱®¢hQ[E‹Dí #î L=„ùßM)}É*k}ýé‘$ˆ²†Oü%ÛÈÜãŽ}·8Æ<µ.hL !ç?v~@(ÁÔÂÞv!ÄpÊëíxžÅWDßÃú«ÖpRû¥‚¿€,e5 <ÊÁQ£f =•Tã{h!È–ÖÌ0ï ‹Ê…Ä@ùT @¹y9jø®ÐŒÜWp[õ%Ó ®± Bã룂rË…©°,Efä =¥Üj`ƒ¦ÎNU¬¶à¤(k¢`¶wƒ‡\÷yp«Ï`U“ýØcQ¼8wGEè^6&,GŒ3÷ž„œÖŽvtʸÿ-%…¥eTT[;ô¶¼Ò6­ åp9¢Æ\‡È›vN±˜È,WÅÿ¯Ñ'Áu®"aºµéû‰i¢„OE+‰¢æ>?_ DP‚üLËFZzÔßx&ÓjÛ@r|@‰È#‘f%’º²Å•FC‹2Z€â Ö›,FLÅŸð?«6Åó¢íÜsZÐ …ÖŽ¼|œ|Üm•ݳŒ°Ú«ìÖÓ02|—¿ ÞŒýÇ:qó»˜Ö=ƒ1/ì`[RŒÌÓY1úvƧ[G³xQ{”üKÖº 7õâ¶ ÎÄåf½É~kV+’‡íÌz˜'Ÿÿ/œ{"¤%«{B1VeÞ)Ôkãê3’VñëhŸÜOÍÍ12k#ð^1!Qˆfµä«†JƒŒ¼Î ¢'ß=‹ ç¹MTÜ8ÀV³lr7V°˜Ì?ªH#á,LWÑ"Õ¾6?H¯{ ئ“¥tc/Æ Ä_ À0R`T˜»x­#>»8JȃûçHßÕã£k¡ßêt“L…[^>¸I »IŒØ’Ke® ƒJÃï¼;ô‹Áff­AhA•6Áéy“¯x; o†Æ¹a °Ù;¤$2·rõ鈹öjœ ) hÜóèÏi¸Ái˜šg~bÒZ‡Ä 4ˆó†Å®º¥WT9C%ŠÉ¹!_h߇‚Áß?q7•!_ƒ68DÜ =‰× [±.¨dj=ÿOþuãŽX– õJ…æ:hn¬."ða¶ôƒ5Émim>¯‚Q^ð¨Ü9жÿâäB¥íœ÷Ù‡U˜)õ+[â¸h&e‰ò 5å 7„ <Ä‹Ùó`#¹MU¸« ~ûtô3x!o8¬÷=®ÓŽéY©¬d|BBÓ ìªszQ„¢´&¶œÚÁ^:$QlÌ"Ï•<±ŸÇVi{ºú'·–x~Ç)j99mN,ãM ±kĈIØÁŒtÀ$zÅ&ëÒþ¯V$°k"ôªWÕqÝ”ÑGHá[óõHQW°m~†i”TCUï×ÈææËàÉ.iúO7ÞèÁF7+ÍôâE•ÃsÃQ=(̷ᆩ0ûStµ¢ëãÍù•‚šúA­h€ÌÊÆ­²o·Ö 6Ÿú i"˜ô=®ãÀžÁùœá+B1Òzõ 5,­„;»Í#ì¾±xÓÚÒîÆò¼€Ëý^c¾À‰«Lì˜ l4Hf¬±.mdúñÕÒÚŸ€È6ŒüÊü|.à6]Ö\‚Â-½ç*µgxãZAÚ‘ ¸Ð™˜Hc$¢ôw"L36ØÒ*â@0Ûéb‘sÙõ§“Ú"mš¨åGÝùGäv N¹ r?G»4^ÝRó,]¶ê‰Bf»ú•ØM†‚(BÏøá”µìšŸú60²Þª½(‰y1)¸i,ÔÇmzƒìª.,V·žÊ­ÍMÂÉa:O×2ޱ"÷³X@©¦tWúúìäÆÁj'“}Kw–>Š¥+§¦à¢“ƒw](÷4Š 9 •¹¨Í§Y^°ÆFQ¤AšRçüF HŠh{Ù½>Ê'N†pŒ ¸Ào&Å!ÈÎ艱8Úe¢U[6ö¬"G>sè00à¼_p`P<­´ÿNï¼Q¢‚Mt~=GÅÖ'¹z"½÷+³‡K“²Æ4k¤ÞkÓÅŸ,žÃÒŽ‡­m¸­OlWŸë£iFï‘÷LÈrÎ̾Eµ AëmL9ÛVµsâ«Pîj#Ì­Êò„‰>yLÜ1Ôž•U "¯úC|³â‹(üDPTØañÒmJa¦=’RB/³ï¢êp5‚¦Ë…üÒ1† Ã{B¾ÄBø5칆¯·,ňtÿrƺ äP¯ŒP¼Í.p×cS@Ö'îñëJ˜{1Þ"gÑd°ŽPIØ…Ï7á„ G«=ƒu›!é^NI]”0·=ÎÓÁVL…ÛÜ9ÿ’“‰ûØp•öÊkbª²†£;[Gzpº‚Sj¦s ÄL¢FH­™ŽÐj:øò·z”%n[bòòÞƒPµE×iÙQ*ü¹Ežt°‚0@‡´ây¦¯“¡;ŠKÖy_ÞR0>QÅÁRPÔ½]¦~¨d®˜PkY²>'3úRd<ÇÂ^}¦0i°[3ÀÔ7¼,«mòÓµ¼wƒD¸Ì+Qt-«ç§Š øú2‡CåõBêÚ[E“eƒM$ JŒîx)ðj[kèzIà$õ›ý±"&àÊ"G8æ×¥Ó¼óœûôÜü`Î4PHér~äBϾâH¤aV±6² ×§Å2ø«ÇI2Ú›þH÷†¸ ä2¦4ÿ¬Q=;H°ÜÚä©\WÚ}IÊKx, H”Øÿ‚Ðgí‚9Ðxßq ÝIÒ_wë‚D‘œ$Vo§Q^±orzßxÚÀ4°M%Z†©€ê—ÞÊ´mOë4ƒçñðÇ PGݰ¸bPžº;Ê?2XP3ë'Ï7`P €µn &«’…<ÁÜŸ=><÷òJÑŽìa1 úóã)};Zí¡a¼9‹ì^e0¬;g]ûžŒ ÈÓYJÙEõlÑ—'atÁk¼ªT´`ŒûuPuv:;6R0éƒOÏÀXž(c³«>W;¼(ÂW÷ÈsCõ–Ï ìAóõá|£´×†ZDvMX–9ã-¯=긮¨VqòWlˆ0þy×›€Ág'%~Äb,,ë{‚v“ñûKã¦Ó鬾÷º!†j4.WÀ¦ ü?M ½C1ÂtK˜ÛÎT*3=aüÆ“Úm<€µÔÙK=í2€ƒZp‚v£óWb:öx±ADWüâ®A&¬ÊánÅÀ!æq‚m±j}aüÆDÀYÛSL#;{ËòCXt>ü: Fµ‰¬¢¹‚¦gÝ}T)jâUS4ýŸÞ{ ±ä0®×´o';úäW™¦&ìsóláqp‡µÚ°T³ éq}“D¢T¢i ~¿Tg8Ço8¿dXK–„O‘ÜkèÜížÍ0³Êoo§I©–ÔgOCk݉s±Ý:>Åzu¡ED¦ÄÕF¥¬5R:—ÿØ#ýþ³Äâ×04—å-AÂólUÅÃÝbÁœ7êZæx¡[J9/ÅÁp^U\±f§«î±½•¥åæíò÷û…)tøj‰´Sö­×äbYæZU¾·"gÄÐX5!ÛäPRñÛþ š‘­7ÞÏ £¤Ýaã`úu‹Pº(Î+âîºé&`Cn|µì}Ìð&[62 ?6[–¦Gv0¥ì…ýDíu®×0ÈzKÕø©kååRŽD+,lx;Ç*˪ӋƒX!ÙÏ€?Ì»âÂ…c FŠˆ–ªF†¤ü4~þùBò1™‚’0Xp=ò£“ÒÈ»ðœ¸äÞêLÛBÚ„vàò1dQJ:ðps ÈQ AfÄBõì]½¾Óàs÷Qàæöˤ1y¶R›F0æâHUææŸµ@W.ݸԌ>0ɱÜùÞ6óŸÓDr"q¡)±Å8•¥Þo«¶fM¬yGÇš¦_o¿…6T>{#øYÿ^ºÇãšHÏ)’˜í0jCei.,Nm'¼œþìlª£–büñkK? ü kO¨4$_ˆD?½‹“Ñí.•ÂÞ–cÁmj:ÿGÍâIÙÇ)|N¿O‘0’wt|“¢ÃÎ-±Ÿž7¸/PÝá-h;Ôëœæ/Œx¼Óòâ‚ ÕwE݉YéCêaeýÈ”§à¾b³`ò¤O7M5uò6„G¬±ÎE¤·¬n¶½rYåÚ“.óÃ˰Ü#m3r Wé”~é“UP*"W=Õ¯™Ø€ï¾©-ÚÀýɽIYkW²æ¿g‘„–4Çñ{JÖúÏ'ë¹bªJA•ÿ—ð:#¨”¤@°æ¨Q¥/½ 9.(&À´ÃÁÛDž:DSz Rú@Ý37~,áÓå ”b鞢Ïì%Z+·©)C“–n¸r;)yRëœS¸¨Pô³u.×e®;§g´v™ 9¸ï*%¾œ†±½M·IÒ†µ9æìåâcŠ<Û¦Om&¡¦<s! žë$PÁ*iûÏÌðÉ_ý¡ø8­¡ñ V$Ð @±ÃÆ¥åÃ[)rÜW#êŽ<)øP± ¾s£è°=º$n¡w™eî@cFÛáÄwƒ?€Aκž>×Ñgî_» +߈²!^¤ ¥°ºKhÇ÷Êt \UÒ±Pº:²¢Û$÷”°AþëÀˆ«Íß ×-»µkEÁhŒÛ–…Ӿؘ’ n¾²ÚS%}úÚÀ>‹=N6m8‹ûëô¹5´Ï½ƒhËÙL¡Ÿ ¯¢ R%ӌé—%Ô{ô­¡Ý!ùe°wU–BÌ#çm¿1ƒœžÔʲ™É'ýuív`{³Àµ8o“c®a@ù¤×¼iê[x¥5dün ;x‰kS”¤$(e¤Ú“èÐͪe4˜B‚&Éöí<Åvú&!vÈX©Ø¹æ•·hÉz"°)ȃV¼‹¶£}úV í‹B mÇ–,hO¹Î‚±Üô¶¾3J½½˜KèOoYU³gÈ4\\‡ÔlRPšÍá$ò{}?hÃÖæø[õjœfž¤óS€q+à ) ⳫçGK{*B:H°WÐšã²ø°~OÏ€üÃå}ñGtPljƒ$R±‹€NH¼Ç*”"N!pÐYŸEæVpiipT¢°6È'ú`K=h3%½ YuYaïØt.ôȳe”ƒ8½µC„…Ó·¶;;YFpågðÄ]hãlVrÌŸŸ?}ÊÕ¤K™/|cWOЉ1º^ɦâ§å¶ZÁ$cvêñ|øØËlðh²;‡ŽÊ¿‘£=Ý¥Š¦êq…U'[?%Zc¢ïê:~‘+iy$dHùõÎ"ü_×$úªdfŸð1K×›8 f£Ç‰æøà ÞSó$&Ú¢#ó®À\Þ;D€S݆Km r8ço„ƒoÙœɺN>‡ÉÆßvѦA%Z AFx’QÔ¥O¸ÿʱÄöZø#ÙêˆÜïH®­±Zå°í³C9ÙadŠÉPÁ®ºCS½›Ï8µr3†fB›ÀBpç“)“\Ûk)”sVðöT’ S"Œ&0šùE»+tÔaÀ`-?'gb.«Ý §nj3¤Ë“Ÿïw§šífy׉ÖóWåÚHj„Äæ>ä‹ñÀ&5£rØWFj}ÄŽiƒÑ䣉ºwŠwÅâZ"žÍ3Ï`Êú¶ìSí=ˆC2æÎ$ìmŒÀ¹Ûú¬ÇžO¶~²—²ŒÏ¥i&j;ùËWf8hÿUÈ,ÛxDjdlÖ¤;TtT¸JifÄ¿oW@ [Å}~½ó«:ùiè`vÑ€n°™wikºI#Ó3ÕøÎGMWÖ†ç=9ÉÿŠåø h²€ä4ùCô#ØÐXSì·œÒn·8KÉ{Ä&Ó ýGÝüàÐl+‹Y(°A9d†-b²–týgá¬èG]÷R‡á¡î#ÄÒûi™>HeÐ+ÃËn¨ªhÑ£„rÒžEQÐí5óܬ<9¡²!Ï{ʼnšfqhœŠ+AÌçñáA¿ªè±Z¯µÛÀ(TO¦ÊûåÏ…&3áõßsíLZÒ*E~z„(Ù¿ïßòiõ?ˆSI{– 8k#l¨ ëþ hÎ{&X=éÛª¾bK·µÖûÁê²¥cý$7ËËau¢«n‰ïÕ ŸÍ¡hâÊ[uÔ…=Â4>HÁ§+”© 5!˜¶lÓý±>ËPh‚°Ê^rXR!;•ëeÎqãT;pæ9pˆ²¦¼Ó²DÀ ¤L (K³zÓ§@‡ÏH 8Úa!”íI >x=³`±(=Ì×Ù˜ì±ôÙ¿4Ûÿ(¢pË”šqÚ-ïªý± Cܵš{ïød7HÇ»}P>Hða,Ø„ +‘[¿F’ `;W®Ÿ“Ç’s¹ÈŒt:Hî»òg‘^õk¾­n÷s‘îQ…޲Ið=ÄÃá& þ³;JaˆˆøKŸ?‘ö€ú9϶qZ§?@¹^‹Õ¾º-wïÛv‰iS€Ku¥Õߟ„vý ’V¸Š1Å; ›:‡íZç¾§›Æù{hö üx±ÊëþCûûèŒòž¢X¹ü”@8É ãóƒ¦VAÏÉ/µp¸ø²­Næ)}wßùÓSîСpÓðäù“´.ò(uS“‰æŒTÅȽÌ1Œ¥˜eSƒš œ@hLr¨ã鎲“¼š W8Öß÷"ëXï±-«Ìä©zÕô!¨}ÿŽÑøN½åˆ–›@û(¬T-­ˆÉᬋ¾²|¯c[m—és¨â¥9*A1›´>鄙ˋ åè™·ók*íB:™:"uÌ|¿BIÄ™ëÙåZÊôŸž×ŽòÔ@; gQ¤žÀ'°(¨÷Ή¯M.úƒû/òU³üƒ­ ‰mj7KqØ$C€ßã†Ô²gö.·JÝH² Œ‰ê¹–јóñ2|……ñ'ÖÒ0-O YúzUÖÇzòˆYø®å#;Wx$”’´Gýˬ.@8]#émÇQ8#gw;¦‘†dÏ݈^{IcÍþ!ëäôodÆQøÃÉX©’¯Û—Cý0CdªEec@´~¿Êg ÖÒakÚ ­ÿ̬ ½TFùmâvæËÈ@kj(5¬fc¿9’ψ,È/¾Ác‡½Ï£ŠðQ[½š2¸ú´ûšñWäÆZg /+E\ƒYóÂw XäS *d˜ã-!Iö.›i<˜Áé&Y1ax{vs¡ OLXþl%/ñMÁܰm±miLÜzCïëí†%”EqñHÇ ¹ =þN6MáØ9±B¨¯ ,e<>襫5掀¥0„‡Ó ž^R6H¾[¹‰Œñ 7}ã‚¡¯«›ÿjz•ýü8e{.0Áu }O€º3½q–»Žåm¡Á²/ò@u°h‹gzt “||/†…³0Â{Vq¶cc®‘»à!A]Ò‡ÙGw΢ٓ$DØG_nÃ̸¡ÌɦAÀª+Çt:c!6‡iõ‹ù2}L=„þyžÔoåܼªn3Ÿ0$ÚË<ºâÿÆÔ¤ç»gɹ¦oÅ¡1B&Òß´wãçû+Wq¦þB·Ò”°éVšàkË0õ²¯™ÕÅ(äq[…Æ÷! ¬÷³VL–ˆ{¹ÑÀÞŠ=oä¾”ƒ¶–úPÌrÒ©„¢QÄÖRªH'óL¼±|"„Öño×»â¹ò·®ävæ·n‚ãè?ê.²;õv'*k›?M|elXZõÙóål!ƒ»ú›$’ñØÏ–ˆ÷j¾¶D~"t\•ݦWZÇ’Ô%E4©ñWKdÄå¦ ñQVÞîjpïFÀ¢€DœP_%rø|Í\Ú¢íö£÷†½pqÃR`…\Ó7.ãšJTæÒ¨nHb´Þ¶½ `îµ#N@½V7 àþ^À¼\–Õý3+\?δ.ÇP ÷/éí2ÓáåÂö¦2 2q)q¡)$tÚXŠ÷c ÞL~º"wˆÞÁæk Pž§Ôº‚ ó ¿ebø!¹ƒV"„ uv§q»}2A,ʉé">{ 2+Å—ù%]rÔ—á<¸ÈµJµ-}J’ K¡`øj>NÕ[­7 öžSÇŽ"Ã'bÍvQübµêÅ ÀÝ1/íbT-ìw3lIZÚRœ n÷œžU’N™¬Ã’¨—šŸ –uH×ô;Xb§³0@!H"®Ô¢9h€$”\è-ȳûŸþÙ4Îý€œ€Ûö ýÂ…åä“H¨«nòóç¸S4 {+~ºÀ¹cB Ö’D&â«‚J98Îé#dÜ ‹<¾­ÙCéßé…zÐöèúò9ô–SA÷¥:t¼‚n~÷U‡æ”) yÂp×ï°uÀÖXDϧ¹Uç{+‘’ 7I€La–U>•u¸s|> <Œ×›Å%e&6íÌ¥ÂÞqáÌ¢WbÌy¯– à¥óW¦Àöuáü`ʼ¸b&‰µ1S•ÅltKµy®ãrxö;…ÝŸøf‹ØkE=ÂÜ}©#ù}v‰Ðëæ9ÐSšúln iA=mkZJnƒÀiçšÿcôÒWžDˆíùƒ¥«†ä8xÑ?n¨>¶’<Ä ÃÁ*¹÷þ #̶€º8¤lÐz¬B[ã›~­S"%¬K¹à¹¥r„Z‰Žæ‹é(Ê.$ûÌbäVìþ:%UG6Ž3'!c¢THÌ.óˆ½) $Îõ°N ÄSŠà€¨Òª‚‘Ü™·Á™KŒË’‡÷ÎNEQC”ý°ÌŰD¤§Ñ墼”«“œj÷Ò{¨˜ï{׫ü$åF®˜xLH¾7Õ£š§ù1³k "%DV—é&}÷Nî[u@Û¥1³Äcáp—bf _ŒEm²,CT¿:pš&9^Å|I—2ô– q2kŒö§•J/BùóíE‡¼™Í[™vÏ2D;6…A¿bÛë9ïVE¬E/B8К»>2{ˆf!yQ¿ê&:#û“D =*ÅŸñuä µÈEûÚ€Lo²zŠy;ÅÆ€ í°4gϾÜOLWXvI°÷Ÿ¹DCVjŒ9’f‹C* Ø‹ì¾ÏÝŽã8MË~¦b“»65@ük¬nû¨½³oäi|sÒƒ?ÂCo/´l<¡H£G³.œ\@K½&_í®¶ÙéN¸"C®\T:Ù#F8lÕ­¿G8brÁ,,,§éë ¬óË¡­P)fk@±¸qèãR\7–ª 6/¸r¼©súÊÈ£wrÐ3¾ )ä€qçTAmû=L]ñ<"Ö=wG³G,ÜŒìÂGD.kQOnC{4!EßÓ*!ííµ=§·ìðZŒ1å™tgî&šmÓœåòm2u§{nV`Õ6p,Ç9eá@“ÒÍ….‘åþ¤Èˆúi¶¨Ò:Ì¿G˜'л.qB<"ŠÄ®¨æ =,f£ZÏ«LÀ¬Í.ÌnhqŸ¨—r®øfvþ ž§âF­¿ ó=D’ÜÕo|þíàÙ´ý…bãŸEfõc•éƒ(\CÛ^½TðÒÇâç×Y^ïIys Y2Ífµñâ{Ž Á7´Ï¦,£¨n7%5$yeÜâÈfž@y ×hå.ˆLç' ^¶ÿ›W-òøãÔêž•´í”†gíPB8ŸòOèç‡y#^Ná‘<òad½þ-qýt,-v]`c܃'w†ahô²|¯Ì–¦ Ó[wJÆ©HÞÙ pK×òa—Ôrµ ŒXŸÜÝÿ©2ÊJ£­¦wG¸¬],k Õ¹s#¬;ùÖKëí¥Ç,º£þdŽŽðౌŽÂÏ×’Dl–{C„ˆ,9‚éRB[óû±Ú¬“H2àƒQºÍ¨Ië}a(ÊŒ¨ÊDA¬µ?k ÞÒÓ™«åG¼ü_êì¾é¿ù¾pþÔWÖÊÁtûXÜâŠ|û¼p¥†ÊX¬P¬ › ç=gñ1NN:£z1KJÞ“Ê;´ÒTø‰Ø²RnüP«± z‡&™lœè›qÛQ%8†ê¨½’/σZò[:5»¯%¢šPX\«›ñÇÐp ››8‹(N—¬¯X`CÐâ¡©ºúo€ cœâü«ˆõûֆïà¾í‰5)”à’ͶfFëq_eÁWÞ˜uý Ž–/8ÚñwW9„?ž@Ð’NiwbC¾-Ú®0RXß͈OŒ‰žÌ§,´—äÇ…?îynÔ…¢ºÏg ²êÂu|k¿¥½-ý ‘»Ó7p¨Ë,IÞÞ݆C‡…‚™â§_wóRŸf%“û—Wm^kÇ´¡ÉßY΃sŒ°Óö… åÖ$H_™Û†zÜ-ÉÛ˜&φ»ômQ_³©ìZµwÕÌ:?Ÿ„ée·*¿£ÅÛ&Y2Ký19 Ù=bz!Ã7ˆ½”‹æ+³\ÄÞ×™n·ªlº¥ýœÔ²EÖ¢+úë2¾y^Çæ¥~8c¡ËÝÍŒœ¢õf3ux¤–6¦Øìåaó[Ý7="©S45Š™‰Ó Mê»ßÁ®7Ç[c…Aèš…G^’‘¨Æ…ü~š˜Ö.ØcîÇf’uÀƒˆöî…A9:)RÐ<‹¾øÞ·LÊ óÈžhËeì°;5BëªUS³£ÌDû»÷Øð AÇ4É«)Lé ßI*šßŽOaí}º0´·Éôƒ-6ÚlQ@–XU ÛÞcO!ÆõǬ´n©ÇOÜsÛ-á"áIàgþš1ßO¦úDè+¬ÚõàT¯Ò­Ékò±¢àP|jÕàèó¾¥*›µ*ÿ¾œº™£u¤$‹å@É…½Nå>fèrˆ%^@˜x€3¾\ÿÖ³&p% ¶¶oQ–OCæu û‰û§ª(Á‰aç¦ôòSÃaôeÒŸÖîg)>§#Èó…6Ý^'ºCŒ] „މ8Q¶§Ãy²c¤³Ÿ"ñ†Åêó™" öN'|‡ÌÉ4¬Ü•6ø´ø\Õ‘ü­'.àcÒ°<;Y_ —Çâ™]«n) —Ž]„6…Lîžn{”D¼« »Åœ†Iha:×%#oÀaõµKd„ïýi4P¦):­£Æb¤ugMJ~µHMâ«K¸Œ¼™,^›«æÅä–ðgO¥…oð÷{zwhV?s;w[-`4›ÝÜ¢Ô†jR „QJƒ¡1ܦÑ\(’ô|ƃњ4A¡ÅàÓS“[«Ê×øBÒ›ðÌ[<åÓmëcÕu5©ê¥ 'ßÛûRÍfEá+ß ¥¤eÔ+ùp3ÍÑ#·áSøëK ÊÙ2˜M_t×GðÝ@V7­ä’YvÁ¾Éd²Ìlnb~òÑÏ ßwÅ b yã˜äy‘9¥£W_qcm{Áÿ³2ŸG!p5?æ‹¥wÌX|È2£Y~\‡× &ÙïqÌ›¨gÆ÷j¥ÄA&ùÍ|ú‘TÏwŽ¡–æUwh¬?ôd8 ÿ—=LÐTà.¿'? þ8,à>ÜwR’Þ‡ÝpY7ƒ«³¹Ý¶¥¡!»ŠÈµªð…ÒMßôuö`N ±))¬-Åc6&QæEESÜe°dÞÑIû³RÉŠ1õIÓAWVÒ>dz{Œr]¯wÐô%9ÁÑèÐü&ûyV¡¾KÙgì´-§&ÄnÔ$=@¯³úåÏ:•¦SU)òÉìCõÍ-ÐâŽÂÿ‹ak§Ÿ¥;h ¡ôÀýKk[Y5ñÛp%ê©~‹°ÅªAŽe\¼ÅyäÖ£P`šaª\?6°¼A€²Ó¯ 5BQ˜ÀÜÙÁhH^Åœ»›¬ï¿uCD¦QÊäÝg¥Îàiá«@¨—GÇôCä”ídØñ" ä¨ÿÃlÄ KÛyhØ’lˆ/^ýúØ#©Üy@´ÊßëŽ ðK{—R0]m0CvN=þ-•*;« ø9á(Ž °2ËCÁ؜ـTVõßHörb…p kKƒlÜý,è´ÝY ft«£<9}¾– ”½1œVcÐÙ§r``¨@°ß ¸Ö™r€a›û5™ö´HZNežMû÷9ô·9fµw‰’ü‡×€«¸p¢1¶¾K„05=ÀjjͨÃõ•Ü&4éH)œ'¨]ãUüÍCÑT.š•ö®†P6J5m¶Ð\ð/uqk£ ˆP(4¤“©²ÌÄÍê~²w ÃJÄI0 ë½ Ùmë\ád“R”Ó§4Â÷“c‘êo!iMnüýÖ™P…뢋ÜÊŠ–˜=ü ƶ26J¿ÌøZÃið“Tã¶÷þ—|¢žêiøó‘¢¨Xi©6tûRœ¥¹Æ!I^’Ìô“‰MÔJmþLš2cÍ'ª_ýÿ ¡ÝÇÑ 5ϸ©«¿'0djÂ÷¤:;"l Ùâ½dŽRÉå:ÑbÝD×gèoXWPñ'V|¦Ù­ëi“1Ë4 ’jÁ5ûQåÉTš|¢„òQ†æ=û;pÑ.És ¤×¥l=ëö‡aû¾øb4€Ú±†DUá.±ôü` ™T3#‚fMЕç1;Ÿª¢W´uYP/RÃ*^xn,1¢ú T· á4²‡—ÈÈGÍRA®e'BÀè*­j»™LN6Äcøf‹q>µ|ûSé¬ÎÂö€]ÆúW0?J|˜uzRé¼ßþ \nI o‰ÙýOæÔhêPúDµÍ­–B¼N?'-ý˜.î%z5"ì2Z38| î9Ê¢/UÍ´F-ç•·µÚf% &\æ¦r%šbè¡ë¼á¥¥ˆ””@ÿ7ÌJ,0­—ÏJÆ%Y®èåövi!«ÄÐÿÑ­ëSR_/çNôÌ‚îßÚÝì൚ Á_pÁd®OÔXÙ4 ¾X‚-P¿©QL7Œ¼xËyØH ¥´%] ª(þÿÊÇ#–bNÔ­ Í(e³ÃFœÀíJe‡ ˜¡€D!nN^À ó”£U !:ឌ ×üëm*?ƒ%¡)˜î€mgé¾òñ*o ~ÉVßµé8Œ‹~OJØµÑøä͚˟Óç,ÑG¸™„ * |ö Ú‹•.)À#ݽê¶Ü"¦ÎîPöÈÐl@<íí´§©§ËYkƒ-ÃëPûŒµ O]MAÒI†b¼iSbqTEñ¥`²-ž&•¶ZÌõöÈE­Ï„z&šÓmaÊópØû¬üdüRò!3(}/{`è3ùÝ1yºbˆ¢&„Ï÷¨ÿžf‰Nšá$îJß;Úcr:G¨JæLÌ€´&üì[å%ád“E¨‚†«@®^'ܳkò˜ŠJ© Vc7;°‚H`+A}»{ƒLeä(?à ügÅ—Ù<÷½æíp‹gj'„«²×_léÚÝ6sLÀ+°zºÄìDÉâðWÌŠTLˆ[Ú&ËfQ¡ŽïìëÍvŸÝ—”èÎé,2W¼¦XúÒØ‘ý>²_Y1òŽ2Ëýù$§¤.ûÉkwNìÔá°–Rq×ÓØ”P^¢Œˆ›DžC@“ð&¡rcí]ÒKÇ®í” €›Cq'AµÚó8°þ}Y}‹#ˆež'=E{{Aû^O*×Z©8k©WÚMô‰uî3^¥ÓvXuÁl÷_7û×Ö¢Z(T³ÔØÍˆjöåxM¦î« fšu?I›ã¨ÁÃaÁD3ðþ$Ld°Æ# mÕK{P¢g­E»ƒ²*”uKè9å›`Ø‹\¬…6œ‚ö#$é_«¤cç¦#™pAÔœ1­¨r™gµßÔ}ºFŽ’À×}“óÎk)Äé 9ÿ;”¨óÛô¢àþ&72Ÿ7¯Ú\a8ÏÙÔt:ÃëìÅ1ð²„nF4»œMÈ4ÍèŠåÜ¡Xxç!,¬ªœ´v,yè·¥ö_ƒ¬Çę̂xviUa¤¯ðC·í^C»õH¶ŠÝäjó&ƒrá·P2wÏ4¦”†K¬hàò§Mj ‚°4«‹Vc¹gh¶¦*# !£ÅNf°gŠÓ°ÆÀŽI˧G Ì.7v&=µz 8á ú¿x°WK¤=Œ‰ÚLŒOL£D‚ûu%Ré¶ôºì^)xÇ壤+ѼÑPVU·"ªjD•\fîXz+Ú–uµZXîî ~OÚ B´É<1Ù?÷9O@ÉK…B$ø-FÂíIÿqO™>xöâ’€¸ Ä:šÒ\ÒÀÝÛ’¤®Ó:±JÉ?웕xñF&NCûÛ6GvNÕŽnº~‡PFw3ªJfò<¶œj¡Y9Ñ[5&-:‹«=é „Š“ëcœW™ÞÖ'`Ñë×Fyª{Îè€ 9³Gôâ.ÅD§ºV}¾ë¶,—ÿ@ý¤Ç„˜gëIÃ+¥#ÜJ`ëkꪒ®6˜]K ˜­X†K²ÉfíÃ×íÞèÁ¼5UdS Ýv¥›ÚþXÁ%FexíË]@ˆvÁS©*€qhëÈÃæg¡Øªå¹h>²½ö³{ûÑ@l©ŒX©ÞÆ9ÜS¨sgSè¾ø¼¤LlÚ°.VwµYXJNûÆ3ÔÁ£eï#1–'Rʘ„¾ÈÓÞ÷q5õCîväpøÎMÕy†²z”-ù¥? Ñ–¸AB:,·Î¥DoÿŽ„È£i¡žn¡î=hîÂ(ÜA™™&òö³Í‰¹ñƒYƒ­F¥õѦº/€8*˜€ìÌ ´&Y¤O¡Õ}”Ñá ‡iHʺ!Èr¾[;¤V®CEcÜHÙ½¡Zá%ò0½hq´|eÄ8p[™S­ÈšìÜm÷tœ7|ð’AÃݾÏÔƒY²&œH¿±¸ÛI !Žs×m-¿LbhŽš}g´éXlúä÷K›ÃI§FÀ¶(TŒZ€›³‘1¤;ϰ>ÐYeÍýè§õ¨ !.»¼\H£ ¾ã€ÝéýÚ%/ëɘý9úVÏ:¿ =JR0²âó¸ÝµÑ——gõ¶¿?g“P‹Q˜è\–ÌL²{S¯:8ðˆÛê.ãÈ“L#þ_à/ö¿ýøöýÅSÃ~8Úþ‹ó£Ón•ËëºáÁб¤ÉB3æ L‰HEbó­Y$(°·ÇxÞÓgèWô§aƒK†Õá¢Å×)·F™¯ø/nwˆB-„Õž¢UD­8®j0¥é|.'Èàv‘† ZT¯kuòøué-œuˆ»¡¦æª(~¬¢É#ªë(e E2‰2|æ€"‚F $voޤWÚÁ"ô„¤•<µÐT³ë¿œ¶C9BÏéÌÀJžWÌ8Ÿà™?.ƒ©p|©dí=,ˆ½UãÌâÃîmŒÖ <÷9X"‹ªÇ ›÷쪿žÔ¨Ñ\.›7ݰ¨‘7°ŒñÇà SL›»Û!sÌÿª—Q‹tÐYîëhÚ9žä§ÎÖá5$_7Ä2&ÎÎm›t¸ÀŠ9ºÕDD -1~T³ôæä‚p=7bñ*'(/’OgÛ â;KÛðyöÕTÛš±k~P©ã¾k¾‚ †õ[›N’±Œòcó§Ñap8¦(peÁ‹j'O‰Ø@…ŒGv¤`Åsµ|KD} ©Rw¼|ƒdM¤ª3`fÄLRèD«Òñh©Öƒö/$Ûêò³¦I KÏÇ4+&Ÿe cÕWŸA˵'Ü+””kÂoÓé†\ÿž[ÏÏ<>¨j†ŽM«©ŒöËf¾9w²ªz8réÏ¿ÝoòInÃ>/ôY"©PE¹2ãÝå?„ë]™QÌÇxeJ!-$Ê0þ»º¤¯¹Ý JÍUüÝËm==òõ[/ÿ¢uèÏ.’“aW.7.h½ž×IJ‡³Æ÷–UȱGÓX Ä´~Åbq ¤òNàZ¢åBqE¹Ë£9¨ó>’ØÔýƒxoþÈ>D*§4h÷aS/ðJŒýhU5€šú惉dÞü'kÉ{±óÁ²2Á´³&ÁÆ>XRëo¬¿Ôqßf¤Áã[9:2ÞŒG¶CA™)lv? 1°oFŒN fR€ˆæ4@ÆUÂp1± WÝJ‘ î’$ÎãaDìüsÒÚ;+¬Ò>“ä }:õôÊà ‡xrrc5jIC¦ÖñÀÎK¬Þ ”÷«R5|O»v=„Ë@]¬”¶Að–aê05“©ø|´§ø¦¾úk7qo ¼£x*/O«‘çà†ÄEâPð²_~lúFó [ŽÀÊ(TÎD¹Të<ÕF÷ÖûÞªÍW ³éê d>¬C¤JéwkLM?’= 1çÖòv÷ÆÌZdè’Dy˜d`ìÖlàJ kkÝuçé æ|?)~‘¶Ó´¯0ï[Hᢰ?`ƒŸ‘èû #{”^FˆyŒ§s/ ðÉñ»î¢e ÷ºkêž,wa¾[Â^Ì{r‘;DKùŠA÷ á>8B¿C@•ÃÒ²:›*ì™& Lî0sRÅMªÏQÍ{ùH¾8ºs©¦ÿ= 8#”3ùAcß`1ß·ú:éŠS+NÝàòÖ‹`ÓÃär`jÔcÍw;±êøWB>ãvåÆÚ] ½ùý)¸©3žvt“7pÞ¡mÆî-˜lá çfºól¸ææ~¯Óê»Q›Èyÿ“ü_ù HÿczעϞ@"™¹Ñ…¾’'PGŽ4%·‚2ivVžÝ嘑¦þÁRil#S N™ëP­êá—}BsïA™¥²gånZ~½iSÌšcïRvÏ9T Šé½~ M-ÜctÔqZ Óæç¾ñ:Cú…B×ù{óÂ!äR:åƒ.š ãÞ’kÍÁ¬«·FA·óƒêkÓ€ç¸3w–NÕ|9+ çÈ>Y@óQ´†W3ò^ ¶HYs'úbœÌ†¬þ´Ý7ê|›K1ö0$‘ùÜA¡à]„ U Ö‰´^øOÜãDpýWzLl‹K’Ðüú)Tº!çbá•ßàsl¡êYrt¦RD’IJv¸ÌbUJÚ†“ܸW}y\s ú[¸<&¶†IÆ|á4xÔnü*÷Õ›ûþÄËÿ.!˜]ÛvQ*¨ÐIòï¼kˆÑyPž¬àÉZ¶JY\x *×Î4¾Ä蟡QG8.z‚óý:bïò,åÔtï49d›ëó”£lXh”ç¤ÝÄ‹z↌tl*tH&-˜Ò÷ñ!`¶6'j Îö‚±÷ ²¼˜ë¶·Q·¢o»Í¾ m—Ö\Y`+ÿ Ú n^5òÀ7õ rÌžGð× ñÛ„ÆÛÀP”=Ÿj̹‚x~“‚jÊáÓy³'#Jèï4“˜ô¸‚Œ?|ŸßSg‹^±oäüá­´“º X.ÄÈ´™‡Ã›C ±L§iŠÂŽ‚r®÷FW4BWäŽÚñ>jŽô-º=ðGþ»7Ýá%ÔD%s‹d™b<ò“a2Oè£9~#]Nbt ÛbûIsLÏ-Ãb—Ÿ* T)ZGÊv˜¬NËQ‹ô”à›õõƒ*ŠÃq`Úõ}Ð ùë/”Ü~¨G)lY‡ÎcK'àtÎD?½ýùA{”ÚC—,êÈ´%¬‚üUËgxµ$„†âK7{UðĠ߆\©ORç͈¹‹èUÉ\LyRv,uÔ^êRÊ#}w/Ž= $XQU„¨%î€2¡nŒ%¾Zçµi×óß’çr âÕ2¼¾G|þ~<7A¼³ŸÞkœþÃ7 H.NÏ­}XrÎ×ÇÁ§–7jºÏuãjÆ»ÍÇhHÀÞp µ /ßöÕkÏ +—ÖÇÖ…Çãgç¼Ãä™/_"ê!~áx8Œ'Éáþ-Êð&º]Èg¿Œøèè kwÊ1––¨ÌxfI‚ V>±0h zÉ‘¬‹ñµ`JI#Ú¸o኉d{ ù¥²h0Pz:ý¢—诧 â YEPás{nILÃæû…YöÏÿŠzÌ{?b‰Ša¦›XgL†œO?ʪR*Á&ÕŸ ±Ý+g‰Â7·è(„ÑYÙ%£X­ôÃDÃ0Û†>“S”.ðv å̵5Ä/þ]¶H‡š°=˜žuátú1aìr%ax†òvN]Ÿ-$º)<ÔF'÷4…âø•8ÃŽgÓ©‰à}/ƒ”—ƒòB‹ÓŒgÚ„¾é¶\tß:nѶ:…gs‰FϪ¦ žŸ7CVñ3³-äRíXd¨Ì Zñóà>±’Ïjx}mÝck*Žm;g¦âÿ$ÆÂZß3´Ïï>7ç±0z”-||#zÊÓ›;>Fÿ“£©qm±mcÍÏ×>R'ØdD¯Jl<ØÈ»f >n0@Öá±ZW*ÕÖœÛ[S?v$ ØÂM·ÅŽM¾®‡‹AÇp´ÄR#´DÚ¤Ûjtž„Ô$N+4š#Ì8ZF™o®,uÁM_÷Çüƒ†&Š·Þüú{p24!\˜.Ñ劺{Œ>±¬8»ðH£çð¾[NÚ2‰ {m`t]Ÿ{Âs¬Ð-§œF‚œ†8Y„|í´ Â>‚Âi×çĈ¬l¿E P%EW oáƒãÕõà²DȲÑKQ}dS~¹šõnÐ*‰ºlrùÒw;BkëÕÙÄ_c¡e/¹÷ô4ÚÍ[Oáp4,Å,ŠÃ¬·×B†º´a^¤w¦ ö(hÛM+‡µ–X0\¶_ã5ðJ Nø4šÆÛŒ­PgÊÓE€žÅ‰B€(êÙkèÅ3°£Á×¢Z 7ï^Nîò>URöºW\ÛãêV•ðZS¡3÷DT6`´?î…_dCöY'Ä ¯¤=j‹bÁìnîóòÊuþ2?Ü ð§{x#+ adLíòURöÑm~¿É¿§G´65ÿŽõ€ð0NþqPàG‡`-ÑJØæ Y8å¦Z7ÀÍÊoÇh)Qaæ·Ox–ä'}óóê;Wüø[JÀΑ£L—12wæ«où}Yy¸Ñ…ÒàýJu¢¢Ê(pI7äö00p,3Øçƒ ÛDÈ8À^«­ßÏ={QÄ0»ö(¡ô;«9Eo¶ : ‰§”ÒÆß6eRV¥î=³t IîvwgËaÂŒËhjí‹W /Iâ,Wql æ4+Ëé/TG±áç‰GSLÒq_›V¼ G#Á:éIÿÏfeÓ, ’e»Xf¼IF§T^£è<8áuG#6[èü8v9OÄ»ãŒh½‹·ì—‚KÃpÛéGaÏ-Ri(¦9AU$2¬@V(—ÔQùºYÚ¬Éö½˜€Ï´å¬gm œ`Ü÷¾ßb4* Ü2òãNg>d˜>À­»? WßÏ_spó¸Ô÷·Mq1p+ Ë C“@« 3Q ÔPÎñÖá×΢•j„K¥ãÒ†\KY(|ÐÁå§Yâd¨­¥øxÁ‘Nç²|.aSñ¸O=Ì}´%…Ðb­Êϳ–DQèމôÃË[¹áFèiªæÌ¿“Úœ`÷M£V”ÒNÝÄ«›¦ªÎz¯ÖÑÁ×—ïöŽwÒ&½«­œÈ˜[9*Έv’’ãõ§¥Á{\Ù´¨®=̱f@ä‡Ý÷îÅ@Âè+ƒTìq°…›‹ó-†—üh¥Bµ9¾>uVZ%â2âÁâÒ#aÅþµþU`º°a7ñ*õ(‡Œ¬û4äèoK,ÈOZŽWåD¿×Õ…ã?-º%õéŠ9Na²/aÛ›“˜˜ÖÊd¦òÖýÜ\V Õ´30ޘƫ”*¤<}Í qõÕ·+híߤbt±uïQDˆ§´x1 W˜K›Ú2ñ^³OÃÀÃèÀæVá~Ö[õ™ÚÚ¹«äWl·í¥ ò´1Hj§ægPVPŸª_ŒEï¾;¡/©ÄVŒŠ4¢4Syí)ÿ…¹Úˆ-AévŸ”’Òâ}Ǫ©P_ìtå¡§éŸÝУm·ßÛà‘*ñ’[8ö(áW#yơ暸À¸á VSÃtœ‡QŒ±2È™/Н~½[UÃø,ÿ÷çÈ,lKb®A@';þeWõ¬ý’Èã ¼¬Ä1 F™ ûc–Æ1k/$clÄf…vWÇp(âËvä¶3âúq+Þº‹9aÖèÈ¥‘ð êõ>pu"‰¶Å˜T›Zâ™Âß­\†²!®mâi!†í(Àä{,IgéD±aù£Žm<뿱„B8ÔJ8§ –sõ—ßB_füV]m¢m Cdov_ª/ dæCVn%yôÞ ½l¿À $ú 5V»°I’€Ô°ç‘y_}´¿¦˜ì+k]dÎß×DŸ2‡ÏœÂ(ë'ñ¿òª®h®=^1¼ƒ¿çX4ì,Mv̈mpt,é®0vò{òyòZtw´ Ð4ÏWp;„…÷ýYd8,âWIQÁåCÇTO¨±ã)¾°l°5µKÒ”ó­çSÄbEö“hÄ`XãŒÏæh±‚‡Èì– ÚmÆh-8äŸï÷b‹¬ ™Ê?cg~æÆNi™çbåÜf¹â#›ïRöªÄ+†/0J=Z2Žy€>[…+˜9q‹è™©þƒÏp¥¶Aø0šóy°ÈŸ·û“¤‰©Ð¯ãV õ5¶‰ÖÃjC14ñFìbÚ762ŠŒ6 ,ÍmøY£ÏÂ×åFù| }ž{†Môç!úE ÏÈmÞ¶,…3EóôjPÿ$λ€7úX·Ø<€À˜ qtrvsim-0.9.8/data/wasm/000077500000000000000000000000001467752164200151335ustar00rootroot00000000000000qtrvsim-0.9.8/data/wasm/android-chrome-192x192.png000066400000000000000000000056171467752164200215020ustar00rootroot00000000000000‰PNG  IHDRÀÀeœ5gAMA± üasRGB®Îé pHYsŸŸ ˜3·PLTELiqµ£”)£“)¢“)++§µµ¢•*¤“)1)‡_SpŽ/µµ²µµ!¯dA(D6gµa:"ÿ¶Šÿ”£“)!«+*™W91@&<";+i=+!:5®K1K㣇õ¯‰ bP§K?†¤pT¦|𯑔Ìx‡tI+%ˆ…f zUGöå† W2thY¼m,Ø€Á‰hŽ‚=¤_J·o7e%çðtRNS5Æ}J Ãð:´"þþÞ’­*ÔY°ómçóq ÝIDATxÚíÝiWâ:`ÅzÅaÑ­¶eZvdSA¯ÿÿw]Úf{Ó¤IÚñܾ_\†J²4[3•Je”QÆOˆ›û®‘¸¿É)ý]c‘àÞà>@×`”€ð\$q©5ÑH˜ oó«”E€¶zð@DN}¹PJ@ (% ”€PJÀÿp{—#²ðcþàééåÅs]·ãºž÷òò4øRóBS!v¯Ã ÷ÀP˜™k5-«Ù2  ül€–u¼ÞjøOnG$<ÐÀ{ßæéâ¦1@ÚgÅË@`®´ ?|$’€èB_:ù¡ @¦ä3 …^'{¼øEü—ŽR¸OÅPéé–ÓÙ,ÖÎzÌfÓúÊ(Ï/ðÄNürÚçpqþºž-ûÌLÔ.“¸FŠëC%‰'ǯÁd̸&.Fÿ ¡pÍìÌ1ŠOŠ¥ž¾îV}°¡ïc0`|ø64àðuJ\?wUüë;„"œ&ÇòAÈôçŽ#8\FUF߇¬Y×ÌA=Ñú»Ç‘ØÁˆø Ԭă1ñù×7Ž<À¶g}2òéŸÚéÁØáˆ¨ Öhÿ>Gôªèçv£–€·?ý™p¨ ¸àƒx¯›ß¼nÈï›l<ý£ÐVØ3¬.{·ø{5ù©f&€ïfH?°¬"Œñ÷²ø+k€F§$9R• Ö!y5¨£ai«p^ ®ø€« €ñùkà¬T¹Y`Uå·™~ g‡V«:ÚŒVÛpúÛÕ Í(Z€ú¡JåµÁ¶è»‘ÕnÎýsôs-Ëìy#7°µ°ûgðNŒŽFf¶F€=b¶Dº¯D¤"·÷Ö©ÁcGCå…*r]+àÐ-ÿEgÀN7ÀYYp€k‘!°r´Öžú‡”HxkêýçoQÌ¿c# p¾ð,Ðð¸#€çG"†AzåEcŒeVÀq|zÜÂlÀ1ü½ `‡tõ//µÏÌ5øC0&àññ_ €ƒdAUûÔbÍâfxü³Ì@C;àŽqüó Û«ãßJ²Àªé$£;7”|—"AÒÝiÔ€N„àq# X»ðxWpôâ(Àûñ&°ßne² þ[ux¸¨hU8~û¨?G¿Æw[¸ã‡Tã–^@è†ÂggA Þs탕@ PCKzsâœU˜ˆF`%P U ì#ÀJ0+ AΉ €¬j€&ZLl°(žèLdŒ Þ„ ÉØ@0ÉP‰í%T‹•I?ÂfâÒõyGšQáÑÛš8T¼b·1A@|/~·%I-¶.ôŒ‰ñÑäH°~K:G @˜”ÖÛ_Úuj><¿[†2Û-@Å>mb $íè‡ ÀT°²³úã쀅ý£ï{[ÜÉ^‹¬¨}C? àÛò#EH¢?cs,Á÷&§C|~nâk‚ïŸ?BK!Àm‚Âhd]㟪‡SH3*XG7²á:îSü‰¯ nd]‰o€óo”Ÿ‡ÿ<Ï®œ/ÙG“-L€™®Ä+8­6q;zì-çKVQŸ‰ H:sîƒ>Þ$]Ñ·¤ /y&‹˜€)²Z©€hÒq99µ¤tv%ˆ§ë˜€%²ñC#ÀƒVW!€ŽfÂ!20[Ľn&™WÁŸ£QRŽ¡åU°@[R¹­=SëÀР¾NlH„èpà\†Âä÷`hZi†Ü5{0B )ãj¼8´CèBŸ-ÏHŸØªfÜ&Ì\0G[Ò“f{x­¡Ø€ô©E+“™Ü] ’îÝáföv*M‡×žò"€é“»ÉÜ¢' øD™â2´?WÀ™^·ÔwiÛTˆ‰-;n<q(uþ¹íY‡i€³ÀQUÔÒö©Ð;îm£™êwçù|o`xKLª`‘/Ž• dt³Ýn¿Ún×QÙßDH6€·È§*¸“ÛjLÝ Neç3º%³¼eVU²Ðí¥.×1§2´EçJ©×qº•ÈVƒ¯ €SFÕ„ àn5PT;"Yâ³ïN €löhƒ©P\‰d Øc‹–,À˜[…Õwi[Fù€¸ƒýl³³¿ +ÎÏ‘µSî)€ÕiÞz8aÐ}‹uÆsd*‚kzÓ_ `/MÅß/‰M:óàšÞvÙ× ÈíÓ1AK²ñU@o|­ˆ š"åÿBlë± €ÞzüX=°D?}`ó7”¨´íÇÄ÷“ôÍ߀@@o¿×˜ÃÛïÓM9õ„üDª ½§<‚¢?‚ÂM™àQ%)iðC@ ‘ò–:ìõÁ8n¼Æ%ú hü=÷A8#âQÄñZ €?ŠØYä Þ\0%ì^ä Ç]f„#úŒ†ER0 „"3Ö1˜À€¸SyÀ¦V²È@ ПI&à‘8ˆÀ €>–>U‚˜zÔù$.C`À8#9š|ïæšxŒƒ1|†@ yŽ,ýh’ñd Ø­<ö1C„€|ŽL[.ð‡që_k`Ã;T4Æ5tÒûxžñëé„~½ŽùÇó`‚\ü’¾v»Mh‡Ánþ5ú§T-AU'=÷ÇäU—wŠë0"aö0ô)úß–Õn´Œ4ÓFШd$åQ‚«šy€Ö£ M tér‹4,Ðq\gÊy£fy˜JÊ£Szpîá*YKŸH¢Q`òÐ` QÇçÅ:QE›Ë^²Ï¸—ü–Ü‚œü½–ü94:zèY‹—PúQAV@Üáê耽ўΞ*€yˆ‹è‘ íéÀ9ÀM%¡<¸Ï)ýe‹ÿàœ(Hˆ6WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/android-chrome-512x512.png000066400000000000000000000166661467752164200215000ustar00rootroot00000000000000‰PNG  IHDRæ$ÈgAMA± üasRGB®Îé pHYs)ª)ªk³qo~PLTELiqµ£’)¶¤“)<:’µb;#¶£“)£“)£”)cF5«‰"µ£“)ÿ¶Ša:"ÿ”ÿª\ÿ . wW&C''(¤X95…mN94ŠaPr™sœH0Q`N§Æé§‡°wT9*mI1"ä… Çv˜Xl?‹©]tRNSaG°ת¨SÚriø,•1“DIDATxÚìÝëzÚºà°ÁÚõ¤.@6 ÷ƒÒ6!Á:Ygé›õ«]M›v^4#Y–žž@ @ @ @ â¿Éïbò2ÝþßɆ€‡àw‚. é €x@ ä€@±þÁŽ˜üsÄŽu’~±#&#Îß i³È EŸ1 3ë3á¿ €Ç~~Ä,PŸ—BýyOÎ çŠkìÿÅí€kÊÇ-!ä¹+®?¿=¯ :Åþ–÷gѸI0ë`’±#&3NLL§þ(žùoÌ1˜hÿgÎÓk ¤31™ü¾¹ÿ¢ ð@6ý÷ýN3xOþuÌÖÚh0¸ÿf ã“ÿ8è,zL¿~«Ó¤’ÿ@Û@01öùo ˜’ýö¾È¿Ë,I泯o˜˜+ÁIPÙ×d`btk˜hIÿ³íØî=0èúî)(öäÙE¨ £ ¬0 îÃ7 àÀ~ûì6ÈÜp4ö¯à€éïI”x“þ^@€WéïÑ €ïÒ/M>¦_’ôàtÞ¯m]úð9ý·8€I{òì{ˆÕè 8>‡"uzàãÿ7ö @±}'Hšèý ©ëzwöO”eY]†{Í ÈÐóñ'·´7‡ü#æñòç'ÍnWUÄ|'RÔ«ÿ5õMþnñrýá¹-Õì@€£âç¾+÷lïqjk5[Ð@eå—|ñ%Ìçï5˜è@À¾ÿ°¿c%_ À{c°«µ÷‚ àØwÜor~ˆ¸EÓ·% ”õÿØ1‹@¦òzxÏá_(ûR–ׯ°Ÿî2°ÖwB°ïf gïMf_ÀmrPéš €€cŸ®ïçÆ\g%ÑÒ€€£ÉO×hj ðH/þÕ‡<·`y( ÙöOnìWp›µV8$óOvË>ÑÀ5$ |lrí?)çª!@šÀ„ì-§¿Y{ •éï àJ §`Éuš;ê^ Ü[Ã~|Ä,HŸwFdHä{žÏÈs™u£0€Ï€øßï;ñåÒÎçªGà8ZýÕÈÔ#0ì]|ü•\ë‘ÝöN>þH { Ø»ùøë 1ì€@4ÿõR¨ö½dÃáàñ¿ÁpÜõGŒƒŽ_<f>Íÿ.7½ˆOöòS=/¬LÞ(‡ÿ&÷€p($dc}ï,3?>ÿ«¹ÇDË‘0ÔûæâÐKćá_€h 24çߊibûšÜ{‚e`+`¬ÀØ?B €ä ? ¨„ ô¿¾>ð ÀÞò¯€`# *`6Ö`ì¡ @çÈs!¥Ø¿Ï&N°z@h`+ÿZµ‚‚àÔ€W¶~´ÿ: غ0õ ÀQ8ÿsc!ñ,@0Z]m@ôöâŸÿ (à×/ É0? üÍÐüÚŠç?0ó³–6ÀÈ, ó@%‘ÿЈ¨_(¥úÿЈà¶³¡~Co©ù_p:AÂ0 ®PIå?@*.€Ls°±#@WØå˜—ªE`öô”i¦6v„h*u<€y¥XÞ·„ šŠ¨$óŸ¿h J¥Vþn L5‚±­-OZ €ñçÿ┢V*ñn '®óo w‡Iwd4¿ÿË€¼Q)Ñðà°-ü‡Ãez¶’ `иmÀ69¼äQà (S@|Øl¯$‰¨Ü7vpÁ*-Ä‹ 6ðŠI @åC° 'ý†€(p†ÃöÅ`,ÅèýƒÏýúÀp€rn2$h޲×#Μx)€ù¶Ï!οÃ9Z'ñÕ ÐO UX2[œà2³‚Ù™G €S¶I(Ç΂C@ÌØS€j5αm Øà9€zU,b•ÓÐ9NXÅ€èí/›Îx{ˆËå|ò§Œ@¥yØëB&Vo—3€éhE†€xÍå¼#(Z§ØÛÄIäJÝÛ@å¼h8 Ì£°Õ½  €k¼¶Î°§‚㟷˜Å ݇ö}à},›Ö€³Ö³|Àÿf•¶õ°X'7ØCÀ4fcí/‚¨X,.n°Ÿ F `¨ €Å›ì!`/€©þ7Á,6'Îk@@2U,V'ØËY¬ í²'e¼,E'€³¾€qÿWÁ¨'tlzXyøt÷¬a«í·pd ¯™°Ø8Ðj«á`V€Ü!€¹€Es¢«„`¬Ðš°8ÛPéªÁÈT怆¬ì8é:É3•9 aŸK‚Ö0ÛÀiŒÆ*oƒ›°8YÐjª¡`V€ƒsë˜m`¥ àüí{\6®º*€JÏ< S¥Ç²¾'àúõ§ËÊÉD€ ଧ €Â"ÀW/"KÁß—bÿ|=‹Ào«KÁÜ€¡Ús êµm”¯?1 ÁÁæÃ n Æ@­èÀj[ëôÔ€@ŒÕŽÔ€.`m«Œ#)îÐàDë6öÔ:&‚aò*½iÒ `Þ:nî4:š€0L9«@¼»y5XnÜ6÷ÇÐéh‚Pç–І€Ò>€ZCÞs›ò•Ó.ðÀNÃJ@ø-€Må=ût4Að&V´N§_Ž¢%ê‚ÀkìhüP«wAó¶Xp <t`§Þ€»œ*€F})(Cî“ÀTäê]`ÜuàdÔÊ] ÷~ŽFw7 ^]Ø)wÞ1†q õf€ÙŒã@¸{¬(½Y ÌóƒòZ`ø»Á¬xõæY» ÌbPò7ƒØ@iµê4 lµ¡M¡ïq÷¯¾¤T€ç$][CÅ bÀŸô ´-üa›öŠ= 0rV0ýZº]ÚûÖœ=–4ªóÀl}pæí ¶ àÂ%ÄêžÐUîc0ž]#‹€ÀŽp[ÎÔwƒ Wûò€Q˜fb—ÄÔ–\è/5®Ô` À™ñjàkî!€2¥ÀÁ†œÎ—ËóåàÖ€ }R\Ih¼PÅ@`È5€¢{­^uýW@άô‡5*<?4¹C‡èl}Ðæ.äì«„ãû Ì eëR°Î eeîIq `Õä0€â{ €Ä€x `ÕŠìÚ€HG€U)¶mâPˆîÛ€8¼†Ó@ƒ% €´ÞÀBíg’'ÃJxùˆ%øàîKɃA%t&|Ø ðñý‰0‡ÕgÜ]"Õö÷_z»rLÀ h¶¼vÞ'Ü  ìøµf`K˜´³7¬¤.è^;®œS€=†,—´÷Û»ý› vW€®K'À³má_šº“Àµñ›®Å;³Úvý6 ð^€qÔÅ‚ë­A€¢k¬¯ÐÎx»{y¬ë&Éά®º€‹—C¿Íëi¯rj@×wÒtuʈ%þ•Ñ—ŽÛ„»¾“uçïaÀ¯tðBÀ\àÊèŽ \T$p@„À1¦¼ñ¯Œî¨"“ÀêRð3s;@‰2 @`&ØQD–/Š8+ÁQ¨Ü™ >þ?‘eÀ“"Î:Pìv¶\ø3Á‡2q® v 8*Ö €¿k½´™àçjp+p‹TK™GôÀ™Æ€˜@}Üó°-@`ÏHA)!À p\¼yÞ‘Ù-¹“Àò†gö,0D¹ T@»/ôn[@ËÝ:L«ý8³À8l•»@ þñ¯¬i“ˆÞXWÆü¼Å,P£ø¡c @¾án/x7ÊÓ*@i\¥> Рäno9{ÇÔg ½$pmÀ³=´­awýŠýû”Ôe¤Þ¸8rÄž4ö¬¹3Á5»¼R’ûh”/ Qm´àÏf  W€ÞR¸I(Ôß "Ê=`X]àÙêÖ°vI»Qèí.ß¿ºUШ÷€Ý„¿ÚVXZ@^—4"«Ï>T€ƒ2€zHà‘€g-pkÀÿÛ»×í6q ÀÐì¶9"î&ŽeÀ7|Ißÿ×¹:6 ¤h`æ×ž³M0ÌçI(ж/ä¿ÇÖ{—ûýϵ¢3€û° @8~j¶ˆcwZ·†=·¾Uî²ã§ÖÜ÷1`+€`¼¾ûì×½âT«´¾5ðØÖ¾öüíêëG®0†íBD‰âTË´n {Q÷€§ú2àÒýùŠ|u¸@PR´‰ €ÝñcÛ¾ÿC}ñÀ€D¨„$`Š6t|uì\WæÍù³kXkrpÂ(¯l@îÐz€#€º â/ÍûW5,;(Q2§Ň”O&ñxõ¦í?Þ:<©zÀSm°r VÎ딆€©óA“å}ÅO,4Äÿßt78€Œ€X¸oG › >æ ýä©©8Pu€8œÕDPì:ð¤>îšÃSÞtÑ €Ä˜ ú«.hf‚µßynO‡¦ÛÄN*1 $$ÀO°Ð: |ù7<®q£ˆ€«P ìÛ´ÎçvõAÀ©q ‰ €£@ëT¤>JÀrÞJ§yKœ>ÖµááKãF!%b "@ÕÄCgÑø,àë-gy­7ükÜ*è@bv”=`€] À¢q¡€ ·Ð ú€2$·=àßßæ­¢ ä@B€²TOHñˆ º4¿mÔ€jЮP ì¦;à 7‹¬Üô€ù±y¹=€¿P ¼qu ÀÍ­Ÿù©ù¬( €Ë–îÀ¨î ›n ò ়4¿oÚ@é¥vPP<€^8f @¹$ûlЦ”KÅ;G\”¾:@ð”Ã@¤€ jðì @9pRÐA Àðyå¤%eH¾f ˆý—$K}° .q4l©÷µ$•¾X(<€°¨K@€ÖÊlTÞ @Ø”ÌúŽÀ#>€¥þ}“V¤ß!`ðÔÛØWá¨ôoœµ°>瀨g‚¶ÛC=hé[7;ÑIY€ºlÂð¬ë66ʳ/~|ÄŸáHþÜĽú;° @¥}ç¸9€­úäóχëþN ¸~j°æi!Öã@vÇKì>à €zXd¨ÂP üq v£|Õÿ_ € Ô(ŸcÙhÐŒ/ @hJ€,€ ´ @@] X €¦”™:I/2Ý(Ð̾Di?4%@î†@ &€»^dš‹± Í@f¾¨Lû )ÆÃ€ðè@é€Z@?4«AÆ÷‚°“&à{üò,ÀO¸zgTSh¦‚¦sÁàHƒ >•?2mèJÀÆ(Á áе¼"ó @! /º©àõ0€8€Jw²™oíz ûR\­ÐpF#@/ZD}Ð6﫤u™u EÀ´?ºqàw¤è¤+F€˜šÜõ@ß6ƒPº4LM|-ƒèÖ¿ @›™u A@Ò+møš Р?Ǽ;5ÞîÀè›À§²´@M@%ß÷ä¦þîè›À‡ªôù—Y§¢èqõ@_ ßp® À¹ ÄÓé4ö{ ÐÞ„hä¿ÌºÐE€h—ƒÞ°ÕŸZ‘`p@ ÿ2cÙZÆò¯ŒÀó"€€•ÀŒÀ¬€|WÀ Â#Hþ‹Œ¼˜IÈ·…HþeÆ>,… 6i03È@PG"v ü—ø0ƒ …<’°ƒt4®×@A!+¶9¸€ x`%®€±X gq ¬ýóBP¨¹ ÀV -`4`“Á–¿ ÀJGξÀ&ƒ¯;ë8ø©”7†å¿¿ýÁ pzË ¯¿ 4.ÿ@c°ÙÀîëßù¦ÐÐÀÈUP*)„'ã[t*Ká9°`9ÀK!ü xh[èÀ©î‘3+6}€kõïè !¤ «]Ÿr9° 0û¯¥•€10`8%D°2û­uw;rp‰¥ÙÅ•UûÒï#€¿µ_k8ó—KýYå ÀZ€ùø9;7a:ó{Ë¿€‘€îù¾Y䨀£ñÄ¿ºÎ€Ý’Ð'SNæ¿=¸²} ø}yÒ&M¿Xhꨎ6«~{ƒÞ–ûxVp¯ñËÀlm³ÆZVÞœ¬V}ÖF£›œ8 ?ÊÀ•,§ÒîÃ, O*gŽmàÝÀ €eöoÊ?\°\ºzçGǪ´¾Ý··)l9poÊêèàx*nöÕË?T@hŸYج¶Vv«ÒíNoÑ~JÏ À}6p}Ûø¢`»Zmœ¹VœÑ³æÉ8p]216]œkÁfµÚªOU¾qOýÛ×9SиcXcÁEQ–ù9Vg«÷(Ë¢ˆÇØ«Oç9$HE £KÍÙLþœ#…€ä‡&€0F]ÅZ{.o=>IGÒÔ1˜-÷$Ò_,g0ZÉÝëC]½?Ö• E@®!'ò1Ê×øÓ8aîkþc;Ïi\ÀÙ@ÂBïêÀH€ˆ@ÐóXõ¿`& M@°Cƒô`&`ˆS 0JÿC1€aú¯Œ]€%€€§ÿÀÈX„€EúoŒ[€€3‚búkF-À @Ïëày¿À˜8è¯ÈýÒú#×7|ŒW€;€^Ê@±vùÀ ;~F+À™@§eÀåËß`´p¼•I#û-Æ* @'0²ß ŠÅ`ðl)û­¦bŒ¼M < Åz‰÷ Q D€o…q“¯,öKÜ× càÀûÌ¡à~óÕÌ?]ÌôíÀZÜï}$ÀxðY w Ï5ßWê‘ @@¾œëÁY‚lIû9ïûµßÌãŽ! Cß-¼Æú=Þþ»ÛÃ# / =Î4p€åJàP@ÌÿkƒåÏÝÆí^þÏ\óá—º°ˆ1 ˜8ç_-€ËAq÷ü+P‹ ˜ ä_% HÏ?›C O@òGŒü+„  åiåð`€! pûrŒòO@N]ÀÏß_ ýÂŒ®= äkÆ{¯¨®ëþý'€¸têËz€çŸ Ú°èpçŸÒº0;,fƒ@Y@çàAa ] Y U @–’ÀÐÜ“ÀÐüJ( `x"Š"Š&‚*z.r2j6b:Z>R€”0 `^ÐÀü #€x@Eð€ˆà  À€Gnîyn@€“€”Ðà$ fô8 H}.¦ `\$ `Ä `ìLÀ Ø `Ã`-ànpóQ° Àb`O û}y”€¥ïƒ€ßØO 믿ÏçBŽ à'üR[ è`%à3°ž<×_O ¿VPd`a4T´9~?lPКEO ¿ˆX@2°ð÷¾óãCû.s1 ‹k|ý x9¾ÆîˆÐ_^óëoÀÇñ½0Pp{5<ðr|?̤FÀžx9¾'FbB 2€¾àåø¾˜H(g%ÐËñßbòK‘ONÏŸê‡&ž‘2àá^€—ã¿ðs­Óàæ€˜àd|ý‹¯˜! 0»a=‰z0¨dqÃ@ÇŸD= HèÐfÀoþñ?‰úÚ»e'ðôãO¢ÞÖ ”ðŸìãû \þ¡f‹yk̺Ôã{ ^þÁ>DÉ”Lÿg~"n¹p1€Qh,iˆ_à@|=˜š~àÓÀ4}U¦Ó8‰"06D‚Œ<îÇàžó~éTcpÞGݸŒ¼p÷(€GãnÜÆ]øûß4M˜pÿo!p?AÜsú988888888ÂŽÿbb9НdWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/apple-touch-icon.png000066400000000000000000000056151467752164200210170ustar00rootroot00000000000000‰PNG  IHDR´´ ögAMA± üasRGB®Îé PLTEµÿ²{ÿ /ÿ£;£“)ÿ”a:"ÿÿÿÿ¶Šÿ–·oëçâ& ÿ›À°§ÿ¯nÿ¨Qýýþÿ­eÿ%ÿµ† ©(1¼•™ÞÖÏ¡5 Žv'ÿ¥DiH3e>!¯¡FØÚóJ,U65%·Y5ÿªZù÷ðciÏ:+k ðŒm@()­OI}ª](&‘éåËÍÀ¸îêÕG0S^M¥ÈÊîàÛ¹LSÇœhO¤{—˜Z…ÖëìùqjZã£Ë†>9’Õ~²iò­ˆ>8­ÿ§MdSrј‘‹Dˆhž–ˆ6»”Ù›u¹s0Ä‹iŒ\d}ZCt[£·ºé§«äê¦MÛNãŽ-ùíÁ ½IDATxÚíÝiWâ:`‹FÅ«€ ÜAPDœQ”u@ÄqßFgùÿ¿ävKš4I[JR¸çôý2PqxˆoV˜[þÆ\ˆÑ!:D‡è¢CtˆÑ!:(ôšˆ8 ½ö¾$"vÚñàÐq1f5ž‚C_Š2/½‡þ& ÑA¡aÄå ã«0êÂÐ;‹02’Ðè þ ÑÒÐñÃL&#Ïç¢Kúë"2Ðj¬†è¢CtˆÑ!:D›!}À”Q'áÐÔºXœ´·éVñüèô45gD*uzttÎ×ï\ÂX#Ÿ¬÷qÔĶxޏD¤N9pÞlü³47×ì€.1Á~TôŒî•´ß(KGιÆé¹Gô§þð’\´K!ãÅí ½m<:.홬³Ïg}>YO’âÔÑEn.ó_‹U%§ƒ>¢I7‡ö]´¡(ʨ×z;©ñsdhª˜k?Û}`„†Þ ©(_îÚ {±›2wcMú,ãšm”ưC¨¶®X™½Ãâ DÛÇç„¢ô0ÚƒD+ÊÊ]ƒL‘â4Є9õVUè ÐôÚÕrÑ_ƒUMTÁ[™BpwCVGbÎØg.¸ùêEQ¼¡h—ð²çFcƒ€Fƒþ ®&Ñe#šÆÍ{Û=1hÌ\j§ Ð`™zÄÑŸœÎ(ÝÆÚºÚ ÚXˇ£Ó¼.´+mõ)µþF„xN+Øõº•Ø'šÛï— O¬.»6~h<^¬?Õw ]’XÒß±rþÐÊ‹•Ö÷½-/§Q)•´|N,°#‰£7¨×­Ój=>ÊM=Ìä6î4»Z+9žœj Ñ3âJ‰íô=z²0 4ìížD4j9óüØÂÑöc~Õl-ˆ<4ª…µªC Œàh^X•ñQzíò2CtK™­ÜbE-shŠ úŠ|þ*žÑÕ”UÔ2ÑhþqG&h.ŠE%»ó ÑóNñfµ$ôá`0xBµÐÖh-buí °.–¾Jš#jÑE톎F Uwt þòfãñ4UÐfwL££Yeú/WkÌ!‘PôÕn™uŠ…Ž;TB½ÇYP`V—zÒÐeØFº¢¦º¢‡°>¥¡ÓT®¡ÔòŽ¡|‰D~€…똉ÞáµZ¹bå‡Hô.] 5ô†U륚5îî¹UDåGZzeGd}}Ó­ü5‹úÙýÄ®$tµhìÆAGÌ¢~uEG`û±- SºíŽ.b÷Ñ FR‹CÇð/Ù÷ŒöPÒpjÞ”ƒ†ÃÿpGǼætäþ¯rÐp„wC£¿˜íôõŠê¥kÔz$Wx1o Gðï׎>¼¼¼¼µúp;:ÑFÏqmö09§¡©‰°&Ö3ÂWM±í}Üét~¢V‹çކk{ßW§„&#g,‹-$¨8ÀÐ@ÐmèÂðfã󡝯CGÀ.¢ÞN«ã«¦ÿtÌÚCN·žŸ_Í‘õ/~µZ­N§j¢_µ;×ç´‡ÖC͉ù}ãæ»ÚHìém·‰ÖÇPÍ™D'`oX5ç3ûÆ#éW«4Zn;õˆ‰ƒƒ Z1dz7¯è–Þ *4öˆ÷RÐØØÃ>sÁÑ+³ýPG!z~¼è,/„B£±Ç£46Ês@0ª qi5$ÆÅ*†£¼Ô¢pôÚ`0X´ÆÓŽh8N-ª-š)Öì ÑhWMaÔszÀÙ÷fçøX½{ÜQZ~T®WD£Ù«¦^Õc®O0½†MEYWÿQ'æ =›õì Ñœõi¯ê1ß `.â®°Ðz£3ú Íy'À«Úú½³ã ÌF[Ëw :ÍèG<¨=n&l¢¢¦_xèw³ÑÑè7ǽîjhToìUñ€‡~F#;ºßG,±?ÌÁUíŽ^ÓÏ mSm¯hðÒétZ­gÝà½cëUíu3áw|ƒŠ7ôEI—IôþÞ8ûdŽ¥îM´ò”óþçØhrç8R—'ÚiÛï¡N_·ht"™Œ¸¡mû=òyÇ I ÜY×§mh3œÐo;kê¦À=L¾Ñ-Ö&õ§ÀÝb~ÑÌÝb¼q9Ýüº/Ïú‰¹/oyÜð»rˆ£`qà€~b‹Æ÷š-4M¶×4µßÕ›j‹&ö«WÒ¶ýÓúêy›¢¯¯ðÑøþiR-MìT¿¡&2ü±Mí‚= Mž hô½¡‡WŒý¯'Á¡ÉÓ¥‡‘;ºKž˜ã‡¶4ƒ‡F’,´Ã[û9›Z8ú,“Pƒí'ŠN^¸hö‰"L½*çöã43uvë¶õ—F['sì³[–zü“î¾Ñ¼Sr¯Ãª†®_Ú?§ävPÊ4âRÐkÌ#Øüóˆ%/ç¿¢E‰r¼×¶BèÉÏ.¾ù¿Û ­æÈDgl»Ä™…‹ ÐÞÙ©sÆifB]º =Ù¹qß꩞Ð/ûTOõ³ºsþÔÂ>™ÐøÔ‰”·O`¢½«}£÷Í .‹ð"þSòNŽ|e\µ_t mþ1/ˆ­*Ú•l4º‡?>F}äÅœ?µÏ1†mYò†ÇU¯ü©ý=bÄF+ÿèÇ”/µ/´þ&PAKà¦V#«]Wcß#zñ¾æGíg<­I+ûè6†!œ^ÐþÔ>f.:5Ìâ½xï#Cü¢Ùí¯´Ÿ²ž>zñ>=®zÐùÝqÕ³€^W=èqÕ³S=#èñÔ³‚f©wgÍP7ã3f¨?d¡ñ±ýdhZÝ<`ÊBó^¥ÀG£)Â~…ƒ& íê²À¡©&0Õû{րώƆ­Øo,9|“]-½TÐ {15ôœ’Ö‹:ƒË.¹£mêm¡Ó­v8uÏéJ»»“Å ³?òl™¯.õ|£™[K½ç´®P '`^¾‘So‹žbFd? ”ó0§¯‘@ê®üÅqß}ÑëªìRÓÿØchͽµXs˜…®/Oc}ÝÏ7Aê÷ÃÑˇßþß&üŠ¢ð{·BtˆÑ!:D‡è¢Ýâ?ÑhPÓ«WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/browserconfig.xml000066400000000000000000000003661467752164200205330ustar00rootroot00000000000000 #da532c qtrvsim-0.9.8/data/wasm/favicon-16x16.png000066400000000000000000000013221467752164200200470ustar00rootroot00000000000000‰PNG  IHDR(-SgAMA± üasRGB®ÎéíPLTELiq¦™&µ³`;#.-¦£“)¥’)f@"¤“(a:"·83¨<7 ¶µµF*£“(Q1^7 =?‹£“)_: ‰}BtmV>4–S;\!%¯P@’J>¢8/Ž@:¤´c<"µµ¶¢”*´b<"??Œƒ>qjZ(&˜?1v¢‘.™Š3a:"ÿ«[ÿ¦Gþ¢%@&3 U2T6;ã™^å˜O¸|X­xc^*î¦xM2IÓkL3KÒ‰T¿…s°“ñŸSÀ:žg,dC$@+ì bÌ‚1-ÿ°sKGÏ0tRNS©Å’úõé#× üú>OÛÐÕÑMÎn×ùîíÐüóô´Ïº|øí¾)»YøÞùðÒÓ²Ž pHYsMM»Á_ÝÏIDATÓ=éRÂ@„'ÆÍn.®$\¹ŠÉ‰áTTT”÷ɤ´ç×|5SÝ Ð¸%5 ô –$Q—¨ÊPxqµ§6cíÃ=í5×xÅà¹7¯;r9™ïapnë‘øoø³Ü‹yÆôsƒ°ÕÜãW´Ûf!ãÀßß»×(Ur—¦±Ç ®±;]@Iσ¹æ&ÄcoÖRÿƒyŒyM–õ"˜H£t•$¢9¸Ó‹.ñ*YƱPœ!Ùð~Õ²íª5æ0ªÀ/¶šúá"°öWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/favicon-32x32.png000066400000000000000000000022171467752164200200470ustar00rootroot00000000000000‰PNG  IHDR D¤ŠÆgAMA± üasRGB®Îé pHYsššI-„VqPLTELiq¡‘*¡”(qO$¢“*¶¢“+¶b;#_Uu¢’(³$'¥¶£‘*¢“*µ"&­µ¶@:©¤“)²£“)iD#a9"¶µ`9!!(§fN=WTrMM|µ¤“)£”(¢’)¥–&£“(DD…hC#kG$37–´LL~xJdA*´.2›mcja:"ÿª\ÿ .µ£“)  wX$ÿ¶Š³@'ÿ®lî–2%#—O3C5"-:,pZ7.3(~3/¨D(4 H:™ÿ²{\7 ž-«w|éžd,(Œùœ0`A(M0 é§…—fiQOxÏnA-]É’”ÿ£>|YƒH2"Ë|%ú²ŒÔSõ£\Ä=Ý‹'¦n<‹cKŸbà’G[L Žj—^Zm¯s[aoó¦oĆr˜s`<ÿ˜ˆ|C<$§wZyLslWskW:/Žð›C»€vâw:‹2tRNSI9ß/%Vªª`óþëŽÔäþS²ü»¼áÁŽ;™UËü掎ªr|"ã´»ÆÛXkß½_uà…Š<IDAT8Ë•“ç{Ú0‡Í2&¦af'MGÒ½Y'aƒÁad0›&Í^Ý{üû=cˆå4Úû û¹{%Ýïî$Iÿf3Äc3WÂwï¼@`b)"ÄeÆ2^ Øïÿ½¿XPÌÁ/?DïÊ«Õ|~«TÀßiÆ“IQÈʪ(ã’/Åö…ãhd|"PH@}ãH£tûµ¥@l<"cŒÝ4Œ -G5­—†c·Âñx89Ö£Æu,Gi«¿àñ0Ç©wЧÔ4[92QTá^!ÕòAC³jµâ¾}Öèà 1IiÞ6´]«s\´À4Rà>l£Ûjï¶yÎI5­Š*ä—°‰îµ*¯Q ôá»ØÛã‡çúcý*à_„öaí´Ûã'¤Oà`í ýžíü,RšÆ¤$ÍÝ]ÖZ-·(=ÙÔÍ‹Óî}xŽÞIuvÔ‹Eø¬ã%:ÕŽÎ{TÇBa/ž1(õ'LÓ†pÿA~1ÙÞy;$6 ëüÕ.Ò`|—*¦X¦…úûX…}»Ý[‰§ž‰ ú¦‰æÙ‚š y_ñŽœpE&Šp^mZ]N8ÉfI öH$Æì±ç¤Ipq€ [_ˆ!@D€É)€xÈUAª¤Ò´*±*ƒwAbNPQáEB:Äù>.cjaÕ}óŠÇæ]}qb…£ëë«WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/favicon.ico000066400000000000000000000353561467752164200172700ustar00rootroot0000000000000000 ¨%6  ¨Þ% h†6(0` $9c!:b":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ":bˆ!:b9c":`w":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":`w´3µs´3)•¢:(”£f(”£f$Stµ":aÿ":aÿ+Hÿÿÿÿ+Hÿ":aÿ":aÿ":aÿ 0ÿ":aÿ":aÿ":aÿ+Hÿÿÿÿ+Hÿ":aÿ":aÿ":aÿ-Lm®*“¢U*“¢U*” +¶Wµüµÿµü´3)•¢:)“¤Á)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿÿ+Hÿ":aÿ+Hÿ 0ÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ+Hÿ":aÿ+Hÿÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ(”£«*” +¶Wµüµÿµÿµÿµs)“£’)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿ*“£¶Wµüµÿµÿµÿµü´3)“£’)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿ*“£¶Wµüµÿµÿµÿµü¶W)“£’)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿoY\§µüµÿµÿµÿµü´\*“¢U)“£Ô)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿÿ+Hÿ":aÿ+Hÿ 0ÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ[hoÙµüµÿµÿµÿµü´\*“¢U)“£’)“£’$XxÅ":aÿ":aÿ+Hÿÿÿÿ+Hÿ":aÿ 0ÿÿÿÿ 0ÿ":aÿÿ":aÿ":aÿ":aÿÿ":aÿ":aÿ":aÿ$\{Ò)“¤ªFz„¿µüµÿµÿµÿµü¶W!:b":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ/6Nÿf,=ÿq-9ÿƒ*0ÿ“#%ÿƒ*0ÿq-9ÿS0Gÿ.8Yÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ!:bµ€µÿµÿµÿµü¶W!:b":aÿ":aÿ":aÿ":aÿ.8Yÿq-9ÿ¦#ÿµÿµÿµÿµÿµÿµÿµÿµÿµÿ“#%ÿS0Gÿ":aÿ":aÿ":aÿ":aÿ!:b·³Úµÿµÿµü¶W)•¢:(”£f(”£f$Stµ":aÿ":aÿ$9_ÿf,=ÿ¬þµÿµÿµÿµÿ±(&ÿ–0;ÿ­8>ÿŸ,+ÿ³!ÿµÿµÿµÿµÿ“#%ÿS0Gÿ":aÿ":aÿ-Lm®ª%éµÿª%éµ€´3)•¢:)“¤Á)“£ÿ)“£ÿ%f‚ÿ":aÿ.8Yÿ“#%ÿµÿµÿµÿ6HÿOe’ÿH•åÿжÿÿ”ÿÿжÿÿ”ÿÿŠ´üÿ6r¹ÿ_UƒÿŸ,+ÿµÿµÿµÿf,=ÿ.8YÿŸ,+ÿµÿŸ,+ÿFz„¿*” +)“£’)“£ÿ)“£ÿ)“£ÿ%f‚ÿ.8Yÿ¦#ÿµÿµÿ­8>ÿ™‚°ÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿŒ¯ôÿOe’ÿ³!ÿµÿµÿ¬þµÿŸ,+ÿ2‹™ÿ)“£ÿ*“£)“£’)“£ÿ)“£ÿ)“£ÿ,b}ÿ“#%ÿµÿµÿtKbÿŒ¯ôÿжÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿжÿÿ”ÿÿ¢àÿ­8>ÿµÿµÿ¦#ÿ2‹™ÿ)“£ÿ)“£ÿ*“£)“£’)“£ÿ)“£ÿ)“£ÿƒ*0ÿµÿµÿ£\vÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿŒ¯ôÿ–0;ÿµÿµÿUmuÿ)“£ÿ)“£ÿ*“£·µs·*“¢U)“£Ô)“£ÿUmuÿµÿµÿ¨JYÿŠ´üÿE¥ÿÿжÿÿжÿÿ”ÿÿжÿÿжÿÿжÿÿE¥ÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿжÿÿ‰ëÿ±(&ÿµÿ¦#ÿ2‹™ÿ)“£Ô*”£V·µÓµÿµs*“¢U)“£’ª%éµÿ±(&ÿŒ¯ôÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿz áÿP‹ÿOe’ÿжÿÿ”ÿÿжÿÿжÿÿ”ÿÿ™‚°ÿµÿµÿ}LMÔ*”£V·µÓµÿµÓ·¶WµÿµÿOe’ÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿOe’ÿÿÿz áÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ6Hÿµÿ´ô·µÓµÿ³Ú·¶¦µÿ±(&ÿŠ´üÿжÿÿжÿÿжÿÿжÿÿIaˆÿ.8Yÿa€´ÿжÿÿжÿÿ?lÿ.8YÿpÂÿ%4ÿ-Mÿ ÿIaˆÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ6r¹ÿµÿµÿµM·µÓµÿ³Ú·*’¡E´ôµÿtKbÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿ-MÿÿP‹ÿ”ÿÿpÂÿÿ ÿ |ÕÿÿP‹ÿ/6Nÿ%4ÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿõÿ³!ÿµÿ§("­µ€µÿµÓ·*’¡EFz„¿µÿµÿ™‚°ÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ-MÿÿOe’ÿжÿÿ.8Yÿÿ9KiÿIaˆÿÿz áÿOe’ÿÿ |Õÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿ¨JYÿµÿª%é/Ž.µ€µÿµ€*“£Umuÿµÿµÿ“”ËÿE¥ÿÿжÿÿжÿÿ”ÿÿжÿÿ-MÿÿOe’ÿH•åÿÿÿ |Õÿ 0ÿ 0ÿжÿÿz áÿÿP‹ÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿ£\vÿµÿ¦#ÿ, rµ€µÿµ€*“£]fmÿµÿµÿ¢àÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ-Mÿÿ+Hÿ/6Nÿÿ+HÿŠ´üÿZw§ÿpÂÿжÿÿжÿÿa€´ÿ6r¹ÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿžp”ÿµÿµÿ, rµ€µÿµ€*“£]fmÿµÿµÿ¢àÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ-MÿÿÿÿÿÿOe’ÿжÿÿ”ÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿžp”ÿµÿµÿ, rµ€µÿµ€)•¢:[hoÙµÿµÿ“”Ëÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ-Mÿÿ?lÿpÂÿP‹ÿÿÿz áÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿ”ÿÿ£\vÿµÿ¬þ*’¡Eµ€µÿµ€m\\^µÿµÿ™‚°ÿ”ÿÿжÿÿжÿÿ”ÿÿжÿÿ/6NÿÿOe’ÿжÿÿ”ÿÿ%4ÿÿZw§ÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ”ÿÿ¨JYÿµÿ³Úµ€µÿµ€´ôµÿ£\vÿE¥ÿÿжÿÿжÿÿ”ÿÿжÿÿ/6NÿÿOe’ÿжÿÿ‰ëÿ ÿÿbµÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿõÿ³!ÿµÿ´µ€µÿµ€¶¦µÿ±(&ÿŠ´üÿжÿÿжÿÿ”ÿÿ”ÿÿ-Mÿÿ ÿ 0ÿ ÿÿ 0ÿõÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿE¥ÿÿжÿÿ6r¹ÿµÿµÿµMµ€µÿµ€*’¡EoY\§µÿµÿžp”ÿжÿÿжÿÿжÿÿжÿÿ/6Nÿÿÿÿÿ/6Nÿ |Õÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ6Hÿµÿ´ô/Ž.µ€µÿµ€*’¡E)“¤Á)“£ÿŸ,+ÿµÿ±(&ÿõÿ”ÿÿ”ÿÿ”ÿÿõÿ‰ëÿ‰ëÿ‰ëÿ”ÿÿжÿÿ”ÿÿжÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ6r¹ÿµÿµÿtKbÿ(”£«*” +µ€µÿµ€)“£’)“£ÿ)“£ÿUmuÿµÿµÿ¨JYÿŠ´üÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ¢àÿ±(&ÿµÿ¦#ÿ2‹™ÿ)“£ÿ*“£µ€µÿµ€)“£’)“£ÿ)“£ÿ)“£ÿƒ*0ÿµÿµÿ£\vÿE¥ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿ”ÿÿжÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ‰ëÿ–0;ÿµÿµÿUmuÿ)“£ÿ)“£ÿoY\§µüµÿµÿµÿµÿµÿµüµM)“£’)“£ÿ)“£ÿ)“£ÿ,b}ÿ“#%ÿµÿµÿ¨JYÿŒ¯ôÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿжÿÿжÿÿ¢àÿ­8>ÿµÿµÿq-9ÿ)“£ÿ)“£ÿ)“£ÿfad£´ôµÿµÿµÿµÿµÿ´ô¶F*’¡E)“¤Á)“£ÿ)“£ÿ%f‚ÿ.8Yÿ¦#ÿµÿµÿ–0;ÿ6r¹ÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿ”ÿÿжÿÿ”ÿÿжÿÿ”ÿÿŒ¯ôÿžp”ÿ³!ÿµÿµÿƒ*0ÿ%f‚ÿ)“£ÿ)“£ÿ)“£Ô*”£Vµ€µÿµ€*’¡E)’£ˆ)’£ˆ$XxÅ":aÿ.8Yÿ“#%ÿµÿµÿµÿ­8>ÿžp”ÿ¢àÿжÿÿжÿÿ”ÿÿжÿÿ”ÿÿ“”Ëÿ_Uƒÿ±(&ÿµÿµÿµÿf,=ÿ":aÿ$\{Ò)“¤ª)“¤ª*”£Vµ€µÿµ€!:b":aÿ":aÿ$9_ÿf,=ÿ¬þµÿµÿµÿµÿ±(&ÿ­8>ÿ6Hÿ±(&ÿ³!ÿµÿµÿµÿµÿ“#%ÿS0Gÿ":aÿ":aÿ!:bµ€µÿµ€!:b":aÿ":aÿ":aÿ":aÿ.8Yÿq-9ÿ¦#ÿµÿµÿµÿµÿµÿµÿµÿµÿµÿ“#%ÿS0Gÿ#:`ÿ":aÿ":aÿ":aÿ!:bµsµÿµs*’¡E)’£ˆ)’£ˆ$XxÅ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ/6Nÿf,=ÿq-9ÿƒ*0ÿ“#%ÿƒ*0ÿq-9ÿS0Gÿ.8Yÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$Stµ(”£f(”£f/Ž.·µs·*’¡E)“¤Á)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“¤ª/Ž.*“£)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿ, r*“£)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿ, r*“£)“£ÿ)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“£ÿ, r)•¢:)“¤Á)“£ÿ)“£ÿ%f‚ÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ%f‚ÿ)“£ÿ)“£ÿ)“¤Á*’¡E)•¢:, r, r$Stµ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$XxÅ)“£’)“£’*’¡E":`w":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":`w9c":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w":`w9cÿàÿÿÿÀÿÿÿ€üøø ø?üþÿÿÀÁÿÿÀÃÿÿ€ÿüÿøÿøÿøÿüçþÇÿþþ?ü?ü?ü?ü?ü?þ?þ?þ?þ?ü?ø?øøü?þ?ÿÀþ?ÿÀÿþÿüÿüÿüÿüÿüÿÿ€ÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @ !9`U#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª#;bª!9`U*“¢/*‘¡I#DiÁ":aÿ(Dÿ  ÿ-ÿ":aÿ":aÿ0Mÿ":aÿ":aÿ(Dÿ  ÿ-ÿ":aÿ":aÿ#Ch»*“¢/&–¥"uU_¶ª³óµS(”¡9)“£á)“£ÿ$Xwÿ":aÿÿ":aÿ(Dÿ 7\ÿ":aÿ  ÿ":aÿ":aÿÿ":aÿ"5ÿ(Dÿ":aÿ$Xwÿ)“£ÿ*“¢Ô*“¢/uU_¶²µÿµÿµ™(’¢`)“£ÿ)“£ÿ$Xwÿ":aÿ  ÿ":aÿ":aÿ":aÿ":aÿ  ÿ":aÿ":aÿ  ÿ":aÿ'@ÿ'@ÿ":aÿ$Xwÿ)“£ÿ)“£ÿ+“¢V¶²µÿµÿµä¶%(’¢`)“£ÿ)“£ÿ$Xwÿ":aÿ  ÿ":aÿ 7\ÿ":aÿ":aÿ  ÿ":aÿ":aÿ  ÿ":aÿ'@ÿ'@ÿ":aÿ$Xwÿ)“£ÿ-žÿ§(!˵ÿµÿ¶ë¶%uU_*‘£Ž)“¤»$Oqß":aÿ  ÿ  ÿÿ 7\ÿ"5ÿ ÿ  ÿ":aÿ  ÿ":aÿ'@ÿ'@ÿ":aÿ$Oqß*“¢Ô–73Ûµÿµÿ¶ë¶%#;bª":aÿ":aÿ":aÿ.7Zÿ]-Aÿ~(3ÿ—#%ÿ—#%ÿŒ(,ÿp,:ÿC3Oÿ":aÿ":aÿ":aÿ#;bªuU_µÿµÿ¶ë¶%*“¢/*‘¡I#DiÁ":aÿ.7Zÿ~(3ÿ³ÿµÿµÿ¥'$þ¨/3ÿ³ÿµÿµÿ—#%ÿC3Oÿ":aÿ*Ad½§(!˳ó¶²¶%(”¡9)“£á)“£ÿ$XwÿC3Oÿ¥'$þµÿ™:Hÿ[s¯ÿo¦óÿ. ÿÿ\ªÿÿ\ªÿÿ%|ËÿƒY|ÿ³ÿµÿp,:ÿŒ(,ÿ­&"þJxß*“¢/(’¢`)“£ÿ)“£ÿ=Nfü³ÿ³ÿ|w«ÿl®ÿÿ. ÿÿ. ÿÿ˜ÿÿ\ªÿÿ\ªÿÿ. ÿÿжÿÿG’àÿ©:@üµÿ³ÿC|ˆÿ)“£ÿ+“¢V(’¢`)“£ÿ-žÿ¥'$þ³ÿr†Äÿ\ªÿÿ\ªÿÿ\ªÿÿжÿÿжÿÿ\ªÿÿ\ªÿÿ. ÿÿжÿÿ. ÿÿŒ²úÿ™:HÿµÿWlsÿ)“£ÿ+“¢VuU_µ޶%uU_*‘£ŽrTWæµÿs˜ÿжÿÿжÿÿ\ªÿÿ\ªÿÿжÿÿ. ÿÿ\ªÿÿ\£õÿbŸÿ…§éÿ. ÿÿжÿÿ2–îÿ­&"þ¥'$þ*‘£ŽuU_uU_²¼¶ë¶%uU_³ó¨/3ÿ0œùÿ. ÿÿ. ÿÿ'‹Ýÿdžéÿжÿÿ2–îÿG’àÿ£ÿÿ(A`ÿ  ÿl®ÿÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿl®ÿÿ. ÿÿ©:@ü³óuU_¶ª¶ª¶;µÿ—jŽÿ{²ÿÿ\ªÿÿ>£ÿÿ"5ÿ0Mÿ=Äÿ-ÿ"5ÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿ{²ÿÿ2–îÿ³ÿ¶²¶ª¶ª*“¢/³ó¨/3ÿŒ²úÿ{²ÿÿ\ªÿÿ"5ÿÿÿ-ÿ%|Ëÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿ{²ÿÿif—ÿµÿ›2.u¶ª¶ª(”¡9)“£ámZ^ÿµÿif—ÿ. ÿÿ. ÿÿ2–îÿ2–îÿ0œùÿl®ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ2–îÿ­&"þ¥'$þ*“¢Ô*“¢/¶ª¶ª(’¢`)“£ÿ-žÿ¥'$þ³ÿ”’Éÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿ. ÿÿl®ÿÿ. ÿÿ. ÿÿ0œùÿ™:HÿµÿWksÿ)“£ÿ|MM޶ªµäµä¶ª´X(’¢`)“£ÿ)“£ÿ=Nfü³ÿ³ÿ|w«ÿ\ªÿÿ\ªÿÿ\ªÿÿ\ªÿÿl®ÿÿ. ÿÿ\ªÿÿ\ªÿÿ…§éÿ©:@üµÿp,:ÿ)“£ÿ)“£ÿ|MM޶ªµäµä¶ªµSuU_*‘£Ž)“¤»$OqßC3Oÿ­&"þµÿ™:Hÿ|w«ÿ\£õÿ\ªÿÿ. ÿÿ. ÿÿnÏÿƒY|ÿ³ÿµÿp,:ÿ$Oqß*“¢Ô*‘£ŽuU_¶ª¶ª#;bª":aÿ.7Zÿ~(3ÿ³ÿµÿµÿ­&"þ¨/3ÿ³ÿµÿµÿ—#%ÿC3Oÿ":aÿ#;bª¶ª¶ª(”¡9+“¢V$GkÆ":aÿ":aÿ":aÿ.7Zÿ]-Aÿ~(3ÿ—#%ÿ—#%ÿŒ(,ÿp,:ÿC3Oÿ":aÿ":aÿ":aÿ#DiÁ*‘¡I*“¢/µSµS(”¡9(“£ã)“£ÿ$Xwÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$Xwÿ)“£ÿ*“¢Ô*“¢/+“¢V)“£ÿ)“£ÿ$Xwÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$Xwÿ)“£ÿ)“£ÿ*‘¡I+“¢V)“£ÿ)“£ÿ$Xwÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$Xwÿ)“£ÿ)“£ÿ*‘¡I(”£r)“¤ª$Oqß":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ$Oqß)“¤»)’¢|uU_"9aŽ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ"9aŽþÿüçðÃð‡ððü?üðÿðÿðûðóøçøÏðÏðÏðÏðÏøÏøÏðÏðððÏüÏüÿðÿðÿðÿøÿüÿÿÿÿÿ(  )’¥"ÿ2Uÿ&@ÿ":aÿ%>ÿ%>ÿ"@fé)“£õ‹?=M¶íµ©)’¥(“£Ð"@fé 3ÿ1Lÿ 3ÿ2Uÿ&@ÿ&@ÿ"@féB}‰×µø´Ï· )’¥":a×;6TÿŽ/8ô¦-.ú¦-.úŽ/8ôI2Mÿ":a׳ųÅ· (“¤#)“£õ\;Sí 7<úX|¸ÿ<¢þÿ[«ÿÿT‰Òÿ¢>Jó˜&(ùVmtù(“¤#)’¥B}‰×¨38üx¦îÿ[«ÿÿs°ÿÿ[«ÿÿO˜åÿ[«ÿÿ’@PüZjqÞ.‘¢¶· ¤:@´cx­ÿG¦ÿÿ,gžÿ1‚Ìÿ*^ÿ1Lÿ[«ÿÿO˜åÿ¯%!жµO(“¤# 7<úx¦îÿ[«ÿÿ+@ÿ1Lÿ*^ÿcx­ÿ^™ãÿ<¢þÿ¦-.ú)’¥µ©&™¦ 7<úb ìÿ[«ÿÿ 3ÿ$CdÿX|¸ÿ[«ÿÿ[«ÿÿG¦ÿÿ¦-.ú.‘¢µ©¤:@´“°ÿ[«ÿÿ-ÿ1Lÿ:€Ãÿ[«ÿÿ[«ÿÿ^™ãÿ¯%!е©(“¤#>ƒø¨38üSŸñÿ<¢þÿG¦ÿÿ<¢þÿG¦ÿÿ<¢þÿ’@PüVmtùŒ??Y³ŵ>)’¥(“£Ð\;Sí¨38üs…¿ÿ[«ÿÿG¦ÿÿkÓÿ¢>Jóv1?ð)“£Î‹?=M³ŵ>)’¥":a×;6Tÿ–4>î¦-.ú¦-.ú–4>îK3Lÿ":a×)’¥µ|(“¤#)“£õ"@fé":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ"@fé)“£õ)’¥&™¦*”¢¾"@fé":aÿ":aÿ":aÿ":aÿ":aÿ":aÿ"@fé)“£Î&™¦ :_n#;`’#;`’#;`’#;`’#;`’#;`’ :_nàÀ ÀàÀÀ À À À À À À àÀÀð?qtrvsim-0.9.8/data/wasm/index.html000066400000000000000000000071041467752164200171320ustar00rootroot00000000000000 QtRVSim: RISV-V simulator for education
Qt Qt for WebAssembly: qtrvsim_gui
qtrvsim-0.9.8/data/wasm/logo.svg000066400000000000000000000145471467752164200166270ustar00rootroot00000000000000 image/svg+xml qtrvsim-0.9.8/data/wasm/manifest.json000066400000000000000000000007721467752164200176420ustar00rootroot00000000000000{ "name": "QtRVSim: RISC-V simulator for education", "short_name": "QtRVSim", "icons": [ { "src": "./android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "./android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } ], "theme_color": "#ffffff", "background_color": "#ffffff", "display": "standalone", "start_url": "./index.hml" } qtrvsim-0.9.8/data/wasm/mstile-144x144.png000066400000000000000000000047141467752164200200730ustar00rootroot00000000000000‰PNG  IHDRИŠgAMA± üasRGB®ÎéíPLTELiq³”'µb:"CF£“)a:"µ£“*°£‘,£“)µ?>‹¤“)¶¶´£”(žŽ/¤–&µ±d@"z[#EF…NM„µa:"ÿ¶Šÿ”£“)‚f%& "Ÿ,&…8"ìˆYI¨ÿ¥ER4=41¯[9,ì©…®|^ø±Š¾‹–b¢W65@-^WB~ˆ|C”‡7 2.›‰\SqZd§`ÍwÌ””›jP÷Þ€„MÆw,ª~š—sL6)ä¢{oO›â–ÔÂ"uJhŸ:ZØpÕîMTP ûõ¾† [+ Ê3z´(Á±0¤Ò :=^G(jÎS dš½&F„æC) }½ ç{ª@ö¨yòM½õt´žÂ´ð<—Ì;QD½9·…6çB"754tEh_ƈv m@‚ ÞºÁ[‘¾x˜:G#Òø#Ü…¢?£8À6„¢èø¡ CCÊD(×ýó R‚©8oØáÅèñå·ñ͸ˆ@ä.¥ùNñ@"q ¢¥Mˆž:ŠhIJ 趤ND!G|ÿå&ÐÕí±\J#@ˆí9 Uí3~‡~Â# ¤Ht©¤6jq]îÊÅ ”2ä‰âÚ‘'ŠHž(n i¢Ød‰â¢‰2ˆ&2þL¤–Ò$QNn)-:—‘¹˜„.¥ ¢d ³=~M1ˆ ÊEχè¡á\<ÌßúÀˆ é¥t‘ù]• jQìk¸ûAˆ2rj–°¯á>‰çŽ1?ÉÈÈ®öcB“!¹òéžòõ鞃æ<)îK$Ñý¤¸? ÿg ï‘d¢YWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/mstile-150x150.png000066400000000000000000000050741467752164200200650ustar00rootroot00000000000000‰PNG  IHDROo —gAMA± üasRGB®ÎéÏPLTELiq¡‘*£’)Žw'b;#¶¡‘)`I;ŸŽ*µ£“)´ *´b>'µµ¡’)‘sI¡‘*µ$¬µa:"a:"µÿ¶Š£“)ÿ”ÿ©Vÿ­gÿ¡3ÿ²y0 ÿ¥Eÿœ"ÿ˜!®T2 $ =';+hN3DY9/"%¢,%†85•»ƒb´…•ÙœˆŽl`[i20¯ó®‹öTE¦[6 ¾o†dPNL|·q6Õ‹EÜ‹R qO:gIÿ«_XhtRNS©þ©RÐûñ·*)´AJ­AèJ#ž¹{®£hEí(ñ–2q>¢Ã}æí¥ÄtÄ}š×w Ù?=©ßˆÂ0…±Ü\2l?&hMÛg¹§4•¤1%YG8¾ÜÛwäX•¬jiD:4Ÿ²øÃË™¯#É•Ã{Öön+Ò¡w~õH—ËÌYxå(¹Ûèpaõ°c Ç*ÇCM Ûèt:Íë— ÕѨéòêa¾ŽT¹\.jF•æ…Èà™èHbI¾X°b5ì€UV¸F€¬ã¢=¿lh!?á²êq`…ŽC¹r\‚¢ãâ"¡›%>ÜR,ú4XuyÓõ:šktÌh_œ·Ak+QÄuÕjµÝV«Öx¾¦>V-AcqßÔÖb®ŽÖVXG@Ú•vIWâºÔÇ"±+uÝýÇè8emåÒ½Jб¢£Ëuu&o®ÞV’u´:üM¢ŽG¥ó0VGšOÞÖèh“7×ët°‰Ü¾ñ:|˜•tи£ë‡œUÞX^õQi#Ð1VúRcu°}"ë¨7£ÁuÖ t”ôs–j cÂ"‚Ù3Ú\î?Z©VÇÜç…† íé:Sú[þÛ1[Çù9Õá9:"%ÝzG‹ëpìÒñðžŽWG·V ux–èn¤cá¼£ƒÞ´þ g3v7–ÎhôÊ+Çd4ZΩÿå|^µ³±¬ëJý0¬„`íj5>žƒoE×-Y‡]]©~ õu´^‚ê1w]©¿ß ¯æ²kÚ0 “o©„:žùjÇ Ô'¤ºÌd, »7^ÇB](•u4jtz¿ª­…¬-ˆWÖÁ‚ô…Ù:ŽÒé’zÿMÖá8#>½'—Fþ…nÐxdl ÷Çì Ý'Ç&øáb°¨#¸Ð¡cmƒô ƒFc´E‡5ü <¼™|³^˜ÂÑÎôÕ}<ÔKÄŠ«èÐ.ÿTvÍÓQ`‹ƒËD3:Ö΂åäy}@ÚŒ¢C¿8h¤¶tü-û%üÇ—Ž gAõx ªÉYÝ—Ón(:bKÇûEc}(7„»pl=pÅÆZòwgIŽ¢#~cÁ`‡º.£úº5Ÿû¯ç³*SH):JšMOÆú`­ex¥ÒbjZäî)9‰8|%mGÑ¿)i²b¬3¥ÔU¾ö!ëà·¬•_kªcV=ämÆ]5):†ê¸b°’à*¯Û¦Ó±†\GÖÁ"Ò|¹œ5ÞGVÜ 5}O¿(ê˜D›¡ Æ×¬´UnÂV¹x5îÃŒ}úGåtl#eí_MÑQ­×“uˆ)3™ÇFèÐm³½bûž"ʲ¨¤cÛf«õq`–aö‡tÄ6a§´> 9o­Û¢ÿ“Ø}mœgÊ ÝŽU¨ã2ºÝ¦×ÁáGÊd´Ç{–\‡´L£#<ÞÛŠE:„Ã_‹ÍtÜ ÇGsÖé|<’x,ÚÂQ×éXI®¹‹tˆG¥x]†ÍÊ‘|æÃ&â±â‡q´­XÖA.އB¢чU:¤CçÃåŒMò%®;+ ¥Cç‘Ì^:e6ò|%%ÁÛr¦ê˜-ã) Bæç~ΪiÔ4 +˜ŽÙh|§OXÁb¸ó„gÓ”µéLnÖ¥3I³›E£Ž˜¯Õò¹d7Çáåâ±m:¶I…t,œ›µMÇ6‰²ìò¡I£–TE<}µ›|l˜dÏKN²w\±ÈGö3)c:Œ÷éèvºÒ;“ÿ6¼N>x’tT,ðÁãŽthƒï%¥åö—’Ò_\tØ÷ü®Ã|¥Á3<†øP£ÒnTüîæ:èz«g¾EÙ×äZžâ%_§ã¼”7ÜÇMIéh2ÄGXÚMu_?Ô ¾XȰ£Ü\‡é>Öé8ÛB‡áíåËudLöñõ:R&ûø&ûøûøª“®CõqðÃu(>Œi.åôNLŸÊ¶õQi›†gOmŽòLžäãÔœÞC™³tùÔ­\ÒÑf—Ÿ:Âçšä¾’su>H†¬‹pò"Gîmú9ù3jU¿ØS<ÄÛN‚súÒ01øQl½#´qvÝl†!ðq!ÛÐ?6ô‘7ðIÂjM ÖLX,|êÐüj×ï>ž—ùÈxˆã[žV¼˜¯äͼ/÷=o6ö‰5¿··ñ7e!~oK6[ó?µh¹Ð¤¶WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/mstile-310x150.png000066400000000000000000000054421467752164200200620ustar00rootroot00000000000000‰PNG  IHDR.™ÐlFgAMA± üasRGB®ÎéÃPLTELiq¢’*£“(µ¶b;#´N7Fµ£“)¢(ž-b<%£“) ‘*µ¶µ†s5a:"jG$58”a:"µÿ¶Š£“)ÿ”ÿ­gÿ©Vÿ¡3ÿ²yÿ¥D0 ÿœ"!­ÿ˜U3" žŽ)1.z+>(:+k P3B[Up--©jKÃt¸_ŽlðŒOB¦­€•ö°‹wO*Ò˜’Ù™t奋ÁŽ•£^Ó‹MÛŠ3hN’Ø!tRNSÏ©Qª2ï¯7QîZ×m‚ÒÔŒš8tn xIDATxÚíÝÙVâÊ€aAÍ hcD#td€8wk¿ÿS*©"UIâÞ}Sù¿›V@{­ø¯LUIöö8âË'±ä ¨þ½õIßYz…óéZVXÁnKô/ji±z!rÁ_Ê¥ž`1:¯VNü›\®Ï,Mç%éŸä‚wžÿ2—R©É2uXéLùOr9;«±LÉ…\@.  ÈäÂ2%r¹€\ð÷4šMÆŒ°rÁ.¹H›R˜NÇãq¸²úg:µæ[-ÁÒ, ëô¨é8<ÍÇÓͦ;¨žî3…·@¹LÇÁ©]8}7—/ÕÕçöY¬EÉec+±`üN.âSUk1rÙK.r)r.ïÇ’ †\Š›Ë4´¤1›[öaÈ¥°¹ŒÍ$înïŸ<ïÊ¿ô^£èÎ|wL.Ó”d-úª%øókUJLäâu|ß{XÜèë™Ð8ïR'ÇÕ1£©–Âì^µ¢çâ]øËû™–ÔT;«Û —"å¢Õ.®t¾–‹ßö´`D/äR ¥ZYË%­%ˆü,#Ï» ´^Òé2¹8¬¦O`Hkùóv™Ó3sñ^îÒ^Œ\*ÂIœKüe…Åìb.i-·ž‘Ëj“®‹Ò\ª¹ãícÆŽÌEÕüò>–‹÷KýÈìç:—ªå„cGî墎 gOmct©^{U{¼¡ú5ßlçYЮår£jyñz¾¶«›zS½Ül[»|eA;–K¤¶DOÞ.¹øsµ=’»/åÊq~[ľ‹k¹¨MѦý–ô4]Æ/ssT–÷[M¤¹‘ª›¹Ü¼sL´9—õñÑ ç]Š’ËO¹I¹»°ê¦¹XÞ•ç_‚ŸäâºR¹¬­\‚¥u¯Å凉X,ƒõê%½{¹¸©®­\"ÿ3¹øÑzõ˜Qr‘+—»¶f4‰ ‡Ãþàñ9É¥Û¶ Õê…\œ×l6å¹’{}¶®,E.›ÈÕ˱v_]rqÖ\/úX.·ÚC„¯É¥`¹h½Ü½$ÔRÇ–Ë«ñÀzÕ ¹&ýÁÀÆx€í4]˜Ï¸’½KqrÑ;>»OoËmæ"^¼ÓÇŽõ^È¥@¹è½œ†Ñ2yÚˆ™‹ï/£4ñÐñ´—r­Ä2uZÝÈ¥ÕÒJ8 næËl.Ëù¾ ÅϬ{i°< –‹úÛ¯÷zoïŸd.ËçûÛ;óÝqò3òߌ\\÷¥”¨©\ZÓ0÷¬Ö ˜Í‚ ÷r8•?òC^|r\©ð ÎbdÓJƒÓÆë8Ü;IŸ1~ÂÂ,V. F‹Eä¢õÂxbáry/#–8z)t.«}˜MÅë}=5Aœ^Š™K\L˜Ke<Í.ÎE[½ÐK!s‰“™ŽÇãpeõÏtjÿL.z)L.£ald|'ˆoׯ‹7F.•Sz)Ìy—Òºu/ݤ íþº¢Žóó¡ü\?y!ö­,ÌèÅyÙ³º£4чsIF£¯z)X.¢–¾ú¢•/c[.gQ•^œV+™¹ôe-¢—Á®¹œE¬_ÜÎ%3Áˆ µs.ôB.»äröí¹|<—r…^Èåã¹ìÑ ¹ì ½Ë.¹Ð ¹ì’ ½Ë.¹d{áŠzrÙ–K¦V/Žh–j¹\ÔPôÄ~VW½<±äRjªkŒ^ŽYЮ°ŒäK.ÕËP{‹váˆÞ kWs‰{™¬œ¯Œ\“äýót5#r9Jè×i½|e1;£‘hææ»¬ki úÚ×ù¶VK2=*kÝK•kœ“›M×ß0s çÖ Zïä¢z©rC—sù„à ¿s¿zZÝç0ÚE!Q ÖM?>_Ëw–^ñþï“~° 8êÿŃΘ‡‹'@WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/mstile-310x310.png000066400000000000000000000115631467752164200200610ustar00rootroot00000000000000‰PNG  IHDR..¯”sígAMA± üasRGB®Îé«PLTELiq¶£“)£“)£“)¤“)·µ`9!b:"µµž'¢“(b;#¤“)³¤“)cD0‚g$a:"µÿ¶Š£“)ÿ”ÿ¬_ÿ¥Cÿ´€ÿ²yÿ›J-/sQ#  $­‹q&4.‡•eO䤅qa^%&œX82™Xè‡XLx=,eG>«¼Š”Ìw õ¯‰’nœM2HlU¤>µzQÖ–jÍ&átRNSíƒ?ë¢ÚVî|HV¼À«ª{¾”“OãIDATxÚìÝévÚº@áf¤MNÚÜž`2.cH &ÞÿÉ.²dK²,8{ÿêítϪ¿%Ƀìo߈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¨ˆ~ÿü±ÿ~~çþûçç]1ýæßþ+J ^±ï…i¹ûÁ¿>ƒK†X¾À.p Á…àBp¡‚®ÊIÉåß_ñþáð¸Öy%^½@.¤ÿ–3\à¸À.t@\NofaÆÎg‡¹,ºàH9ÑMÒÁ Á…àBp \à¸À.‚ Á.p \à¸\.¸À.p \àBp¡;;Ÿç2—Ó³Yì|u)ö\.td\z³à­‘÷÷f³Û ÊË‚n·ùþþ‘Uοÿ‹Ç*×½ó#©ŸY¥4×J”‚™š f¬ßu}{{{ͱs {.=­ÁŒ5K.—¥Åß[ºäh —÷n9CÝæÇö¸”þþ¥%ŽÖApée³²d>¶ÃåjõW^q¸ÜçòÑ,ç¬k˜•ì¸Ü®þ>†×¹ôÞƒò&i‡;.¥Õ_vÂáršKþEb>àòŸàÒÛ-¸—maÑ€ËÑpy/oµf.ÇËeÃnRïp9R.Ûœ‡t3\Ž‹Õ<†ãñhÔZ4‡ac€Ëás1-áx4h{_=û³ž?ì[ÓM¥n.ÇÅåC{ÄÃÑ ò„.óùƒQh?ÀÀåйè&¢qœJ"—Ù¢Á›†\S|Þå4Þ\ëk;€PÝr" U+)\¼'ߟ¼ÙLHÊN¸¸ÆE·q¤—vã9µ½ÄÒ¸ø~”6Äp9.iË–`y^V.~Õ„† \˜ËGÊäÑzNÏ×qñRÁ¼Ãåй$/rƒ–o,Ë L ñ"s¹X|L.Nt3?ù¸Hã’¬¥Ó÷7ãâEÉk˜fêés¸8Ñ…nK}¢–æÐ÷7åâyíqš¸(—÷œó —”© —Cå’¤%œ>XV5qñÚaâú%˵ÐÉš‹øÓТ¸$SOžSÒqñ¼Q’—4.W'÷+OØP —„ë-ÁÀó¶Ê%qBê$s¹µ|"â–cZ—^‚–¶·m.‰Òg—kë'h_ à¢^ùsh1rñ"õ )Hðr^²æÂ¾£ýsi&-[3•ÌEý}ª—f— è±kzß\Ô“¢ñò€ûH'ÕRþÏÞàrH\>“´ìŒK‚—Γ×aöÍ¥›¤ew\T/ÊòåüŠ¥®«\Þµì‹ß1-_ο•XéºÉE™ŠÂh×\T/å2Ý…—[V.{æÒMÖâ=V-K|<Êð§Çúéh~àòJH¸ þ4XöÍåmã«s‰\ E¡v:⣣\”©(û•ÿ<\¼v ›Žàâ(ùÝÈÛo ?ß ÷¹ÈkÎÐÛo¬^àâ&iL«™Jæbù‡ÃôÕ.\œä".?[‰\l©÷àâ$ipyó÷ÉE¹º»^~-¶¾ÂÅæ»2nR— ¿_.~3axaŸ‘k¥ .-Ï\† à \\å" .Í´£ÚJõçm‹ÿ¦/pq•‹4¸ žRjÝ'ÖxyJ\ž26¯v¸¸Ëå3é>tR)\æÕZ‘È%kUi€ëœŸÃŹåî׋w¤{¾í<\fcLk.ýÀîq¸Ýå‰åà¢ç2a†ù¹È'Ó×pq´+ë[‹.÷÷¯ù¹HÃË-\­¤½Y$nhýsoöòü¥êŠ‹ô¤Ô \‹ôƒË³pºûjär?Ìvý°æÒ·šàâÔ\x›qiôór‘®½ÜÂåæ¢Ñ†\îïrs™ØÌFpqj.jÛri,ªÕ/ý¼\ü®Ål—æ¢Ð³åÒÿ{‘å¡ÿÚˆq©çæÒ±Ø7—b»5Š\BÓ]F¸É¥+ß0ÒpyTï­jHWu3Ü6ªŠ\âêàâå)Ý|\^ä{Fy¹ÄO¾Ÿñù+7:»˜÷©Ü_ÌÃ%~‹±³ —ôêŽ ¸8ÑM£A._;ûýáë]ü†ö&\Úp9N.iÕ=¸+—Žò$ݦ\j‘ð: ÃNתÊÅ“¶JÃ帹L=û—=%p àr(\¢Í¹L<¸ÀÅ’KcâÁ刹Äïxr©M½¹„ñW2ÃåX¹4Z‘¸Xri'\o.LFÇ»vim… k—ãä2™Î'£ÈÄ¥ú<ï.ÿÁë._sOO9‰®7þ6¹DËŸ}ñár$\Ù¹ˆÃKmq©v²Þü*p™¬_£çÂU]‡¹|nÈåɯ)ïvYÞplˆ\~¬odk¹pÏ踹ˆ?õ²ø³w+=—Æú·ÀåH¸ŒV/{²æ{Žnñ Ìp5יּL…—×i¹ð¼‹Ë\*æw^š¸Ô•wu,ÕÔw ö \FÒ»Þáâ—®ñ“W&.}ñ\zqÐW€Ö\jÂt¥åV··¸4µï¥3r™ÆU|ò²5´¢\¸k s‘žK(½ê.Nqy3¾¯["-ž#¯60Öäýiâ\¤çH}…‹S\:Æ70¹ˆ¿.ÕÕåßÓOt\¤]Œ77gpq¨óOã×]Í\ZòË:¦Òl‰s‘– {¤ÝæR1~ÞÕÌ%R¾¬Å·¿Nb'Ú:.cÞÀà6—Ø©Q°'ÕOá"| öN<—ž¯~W³Ñ×G`Ä^¹«ãÂû]ç_ëuï3MÝ–6‡—jìJÝâCjË 1—LoJý( íŽKÇê#Œ†M¯âb÷øóñd½”©š¸dz7^ö~tóÛê+Œ.¯ò¥ºWáxåJÆÈ%Ó›/ñRDñ÷êösq‰Ý8šO@}á&õjá;1rÉô^]¼Ñ­Íldâ"Þ8ª‰³Q}ý¦ Fdâ’í­Ýx)"é›É-ïcìíQâ/OåOµÖ³QkuVmâbóM€K¼šé‹#i׋ýÆÇé5ÓµÞꂯ‰‹ÍGðRp%ã…] .Cé5O/«•Lcõä·‹Õ÷ŒðâÔlè¸L^ÖŹøÂ¯¼Ì»«/”ßõ×Wx \¬¾–†·f£AžïË<Êç8OËníu}óQÏ¥o/îÌFa–´¦sY¾—¹ñºÞ…¤çb÷¥W¼¸5•m¾Õúl沜êë»Z.–ß‘ÆKá³QüJÝÛv¸¬.·¬„Ñréd€W®ÔÙ /\<õ‹{:.ÒàR2ÇKQÅ¿#a3¼ØpϺHƒËÕ7¼Èb·Ë–gGÛç"•;• \d/ /»‘2;÷¸9]s‰o®×œm‹|VÔþ£*çY½\qhwÑEEJ^–Ë—gé–‰\”pÚs‘®þ¯k.q/pÙiƒÚjù²c.}yTkV²r‰ya2Úyµ[¢=pQ~fç"xa©»7.ÊtF;ç"k‰OE¶\V^N\öÆE™ŽWëvÊE¾Ü#MEÖ\¾].Â(]r`÷ÇE™Žæ^vÉ¥UÖOEö\f`®¯Á²_.Êt4ó²C.£²a*ÊÂ…öÎ¥ò¡zÙUË[.‡Ä¥ÞTaã'~-¸ŒË¦… \\çr×Ub\"U‹²p‹ó\zr»Ãísiÿ¿½»ïiÛ8 ´+QŠºX“&GICD+éøþßl@ ö탄ØÑóüWÈ‹Tÿtw9û:ËêW.ri{.¡^†ëÎåf˜ez‘KËséÍÇqús­¹ÜfÎŒ:—Ko8Ž×Oßù;¸ 6%—àDéE.­Ï%ØKõ•饅ê¿Mèa°©\*¯©¨—äÌa°ù\J÷WÒKrYÖ0X(õ’¯þfñüí¹ü5ÕK×rYÖò|3­wŸ(žî¼%½t-—r-‹^ù;䢗69x<i’Ëjƒ@›ÉE/-R¿¥~‘K±A¨–䢗È¥ªe3¹èeré½_.z‘KJ.z‘KJ.õ"—æ¹ìéE. ¹èE.)¹èE.)¹èE.)¹èE.)¹èE.)¹èE.)¹èE.)¹èE.)¹ÔõâÊeåÕ½¸~\Vï8RÝ‹éH.«7¨96¼È¥y.Õ»aÔæ’÷·˜KU/ûêæ|}Ð —AiëQ?-—~ƒ†rùãäÁ^ó^,^6¬ÑÆ‘~égý¤\VúY8—È jŽåÒÎ\–›ÐúÕÅsÉÏKÇVD s‰÷âxn7—|ÙK¾tž”Ës/ËçWÔÒ8—X/–º[Îåi|‰l™¯Í%²å>|¶Õ8—H/N¤·žK>hVK,—p/ásó? ÷Vú²—Ö‹¥ËÆ”.è%x"»‚X¨—¼öÚtµ½œ9šïî42nÔÕR!oXKR.å^ö .­È¥°~I­¥ÔKÞ[G.Å^ö݈¯%¹ôò—^qÔ¼Ù ¤å²Ú‹¯»´'—w’˜ËÞ§37ß“KJ0Çg‡‡‡ní)ºàÛs9ñßß¹Ïa>o­–SÿûÝs´­Z>\:ÙËv–/§jéê„tôþÄ;àrï)pm@­óWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚qtrvsim-0.9.8/data/wasm/mstile-70x70.png000066400000000000000000000043211467752164200177210ustar00rootroot00000000000000‰PNG  IHDR€€ôà‘ùgAMA± üasRGB®Îé;PLTELiq´´¤•*¢‘)¤“'µ¶ŸŽ(µµ£”(£“)µd?'³£”)_<# ’+µ¤“)£“)µsQ$!(¨e@#II€Žv&£“)a:"†k%vnVT?Na:"µÿ¶Š£“)ÿ”ÿ¦Iÿ¡5ÿ¤?ÿªYÿ©Rÿ .ÿ«_ÿž(•‚(²:#(  1Žv'ÿ­eG+@-`ÿ°pogZ--¯1'|#&¡[6 \:,R1K+V56 §†USE¨ÿ›G3&tZŸM?‰¶}h)$ŠÂy.韛ZCшDL2I02›ì—=†wGcMr«l;ƒYq¥u\å† Êj¢^ß ƒéc¯‚™Ó™’ý²~lŸxEû’šŒ2£g"Á•Ž>™l~Z>Ru!tRNSå6A9ò!Ò¿%•JSŠÏ3n'­î–|®ÈÙ‡jƒØÀL ¯~}17:„šâÇëOx;8±Q‚¬Ã5¿ç\ªP€‚ãèøÂ{Iáéyt!ð€†{ùÓY àRzÂ,½;„0ÅN–êË.Ñe–³n5ȤåI’l‘몥·=àU¦àÕ¤¬l8× ¼É#™ª­O+y—*ŠR€)X”–Žg Áwƒ0°Í¨—n È!€>cJ¾@òšìg³7Ñê´>a€U·à¸GˆI Þä—`…ØÀ‘¢äÓ»˜àƒ× é>ô‹Ä`*é}@44ñ99“Ðodõû®x#ˆ‚I_Ûl»™L!Ý‚%¨dœª €e0‚€ÉÙiÈm€e쟽·Vq(ðD€„ð—„H¦q¸íÐ5M7ì#€ý%[û¬p=,J1Å`éHqeì|\ hMå' œúQ /D[ùpÑ9Çí‹N§ò8màHYÓ°3,}AÁœ¨êvþqˆÜdrN€<ŽÄÚÝ9²ÅI‘—xÁ‰€† x€ ÄÁ^ÆKlëª~Î@ø– Ê¼õˆXWúªZRðo#mH” ¡j//X»èÂN­Aw ™ärÁ.Oä‚YȆw4Îq‘0#a——MÕ»€'އDë&-x–•\íâ÷8ëçȶÑdÔ—lg=WŽêõz¿énuã­ŽPú€³"& 5a‡/{ò@’‡¢| ­ Å$ÀYŠÀœò¯ÀôUp€TÅcÒ &*^°{Ÿ¬àFƒ¬h4x&ÆãñM§äœJë²×oÛ×ôÎ(À_fqd‚»7¼½€äC €Ý:Á“áÃé–[wÇ•B†¨°ÛSàÎsẅö (eÎt àè¸í`qT«CrõCG‡$àòç²»GtNÒ´G–w8{Dñ6½»K¶Ù$\‡ˆ°ºdV›L&ë"_¸¡²¬ àbƒ5’×å0»UètÃî©5:# `÷ŠM´ü`¥{ÆzÅÇ”`!”°y}coZÕØfÁæY+Ëœ÷ÝrJ áû;»åžý‚ï½æ×fïloý_°¯$=@Åz:ÜŽI šÄ‘ÈLhL’†Ý3ŠÑ6õø„t€îšÅèÿLMÈxؾ¡Õ)—DðlðÎiuðÎ)`r9ÀÔ°Jø­¡iÖ‡9’x«ô1ž`08“”DÀ»¡Iš*¯duKÑÀøÒªZ²7¯?oJ"à¶tU3M m¢¦ùV]5Í­{Rߦdð¡8a¨Ú~-Ñ™.©«dꤾɘ7€ÃÖ~ú6.N z*N ˜&&pÌý ž 2 À‚À0Ÿ‡ÍkŽ@4™*Œhèºé@‘ɰ_îí{›`43\À"¡ØPU]×U:.@S@ŽÓ H¼žÇbÏYñdd@ø_µŒ`k+ÁT{|ÏC­„@(% Created by potrace 1.14, written by Peter Selinger 2001-2017 qtrvsim-0.9.8/default.nix000066400000000000000000000002021467752164200154110ustar00rootroot00000000000000let pkgs = import { }; in { qtrvsim = pkgs.libsForQt5.callPackage (import extras/packaging/nix/qtrvsim.nix) {}; } qtrvsim-0.9.8/docs/000077500000000000000000000000001467752164200142035ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/000077500000000000000000000000001467752164200161705ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/build&deploy/000077500000000000000000000000001467752164200205525ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/build&deploy/building-wasm.md000066400000000000000000000051061467752164200236400ustar00rootroot00000000000000# Building and deploying WebAssembly release of the simulator ## Jump start WASM release is automatically build by the GitHub actions. Resulting files are available in `Actions` /``, section `Artifacts`, file `target-wasm-Linux-qtx.xx.x`. Download the files and skip to deploy. Details on the build process can be found in `.github/workflows/cmake.yml`. ## Jump start 2 Install `emsdk` and `aqt` (details below). Use prepared helper make in the root of the project. ```shell make wasm # build make wasm-clean # clean wasm build make wasm-clean-deap # also clean cached external libraries - when changing compile settings, of when it just does not work ;) make wasm-install-qt # install appropriate qt for wasm using aqt ``` Behavior of this commands is customized to local system in `.dev-config.local.mk`. The file is provided as a template and further changes are ignored. ## Dependencies - WASM compiler (Emscripten/EMSDK) - WASM compiled Qt - bash compatible shell (not fish, unfortunately) Steps: - Install `emsdk` toolkit. Installing just the Emscripten compiler might work, but I would discourage it. - Choose version of the toolkit and run `emsdk activate `. You can choose freely as long as all your components are compiled with the compatible version. Qt5 distributed release is build with version `1.39.8`. Some distributions provide packages like `qt5-wasm`. It is imperative to compile the project with the same toolchain, otherwise it might not link. - Source the toolkit as suggested by the output of the activate command. - Download or compile qt to wasm. Common way is to store it in `/opt/`. I use an unofficial qt downloader [`aqtinstall`](https://pypi.org/project/aqtinstall/). - `python -m aqt install 5.12.2 linux desktop wasm_32 --outputdir "/opt/qt"` ## Build - Move to build directory a build directory (I use`build/wasm`) and run (replace the paths accordingly and use your favorite buildsystem): ```shell emcmake cmake ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/opt/qt/5.13.1/wasm_32/ -DCMAKE_FIND_ROOT_PATH=/opt/qt/5.13.1/wasm_32/ -Wno-dev -G Ninja ``` - Move the resulting `.js` and `.wasm` files to `target/wasm` along with all content of `data/wasm`. It contains loader script, icons and other support files. ## Deploy - Move the contents of `target/wasm` to a webserver. Done. - Note: the webserver must use https due to CORS. ## Tricks ### Fish and co. If you wish to use bash incompatible shell. Run bash, source the file, and the run the shell with the environment of the bash. qtrvsim-0.9.8/docs/developer/build&deploy/media/000077500000000000000000000000001467752164200216315ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/build&deploy/media/obs-ci-step-1.png000066400000000000000000001320211467752164200246210ustar00rootroot00000000000000‰PNG  IHDR6š{WT)€IDATx^ìÝXTÛ¡7|î“ä{“xfh3C•Þ{iÒ”n9vìÝcïÇ®ØP° *–£¢("½#¨1ùòÞ$÷~ÉÍM=77ÉIÎ9‰ßÚ³†Í0{€õïó{|ö^{Ížaí)ë?kí=Z"#cž®àÓBD͈4" hDÐ ˆ( AQ@ƒ ¢€AD ‚ˆ4" hDÐ ˆ( AQ@ƒ ¢€AD ‚ˆ#ÀÜÆÑÕ3À'`2PVv®#ÈÜÊA(±ä6ûÀ>°ƒÂm–·ñ17)·5ÞÒðsˆ(ðV"SÒi#l=,lœ ½@nC½ }¡DbnC:‚ºÆÜ­\ÞAA“Ž”oIÞÐsPˆ(ðVH§ÍÁÕ—Ûú˜©£H-I/[Îõá4éHQSKò†Ò˜ƒz#Š¡Ç"ßÕÅQg~óMÂ¥ßE®õµ™´ ·¦‚°ËÿH¹þFA╯"V¹OFë'w’©s§poÎlMa¶†ÇÒU¾Èßen^xÚ/®þ=éêW±§^M\’fnÕg´+&çÛ„3¹»úðh ÝŸ>+ˆ¸›4Šõñ?ÐC?ÖØ”»ud™Y[;¸9yø»ùLP²r/侸@}è¼n7è#§¾^ ÄÜfÐ5äAA“Žõµ$OµÆTÅûQôÌ]V6§äÿ‹ˆ=Úν‰:" ÷OÓ&ã¶ìÝδáPñ…Ó2MD~žÊÝ:âF'¢À MîbSk]C ·Â"û'÷Bî‹Ü#‚ Œš`Þ‹:¨¯¨O:ƒ}QýA4éHQ_KòTkLU¼—ÅaÝÏHÏ2îØ=KGûÞr=“±1gãóþ™œ÷7'G[¶<àü_³žÈßœD”伯¸»xïa¢EÞW1YõÍø3¹Ss…jÚFñ$Ÿ$d^¦«nG~OªùO¯£ïº<6çÛä«?340’íÜÜU`:™R÷OÓÁ;Ϥúö¶¿êøÂ)43ÄŸZÃÝ:âÄÓxÍ9Aˆ yKg{C#ŧº‘{$÷Kî» `Ä‘î·jíZÙ¹r å}M:RÔÚ’<S£Q¬Ü·ï;~ììå„™ äËf.$…d©À½•}׳¤›ñP `‚„ÿ$f$f•këÉJ¸ýøþ" á-%®L–MmdæzÍU¨#Šl"åaÓ&e¾¾]¹» w¹»2™÷%©èêÈÝ$/4ãs UÄýÓFŒžDGšÓ†Šo`³ÿôEKÃaÝvt#Ê ôÞv¢Iª<ŸÕ‡Ü;R Œ‚©ë6‚ÔÚ ´ øA4éHQkKòThLUŒjDÙ±ÿø¾´ŒE+>#d|°lØ,URH6‘”½•·ã"½X‡~¿§wüü7¤B€»£®å!Ú奢7ÄÒ D»“d# _ÂĬ2…:žéÿ“’ÿOs#¦ÑøÂ R?1«‚3t,¹%ï³µ•Í·‰ºú ;ÑKàþ„ÜÊÉ&*`ÏO¤ã6_Çor ðâé™ÙϾ•ù‡¤¼L?Õé®üL¢¿?MÇ<Â{MYì…¯’rþs¼Ý'q¥®~Ÿ®¶qÐÖI{:ã²ÿ’|íq? ZyÒØ¨wöÑ䬯ãN.1‰ÊŒÍffÍ%^úmðšc$ ê9ÍÜÓ•põ›¤+¿Ý”eÔÿ ?b·5û>ŸÉ-ç13âB}V=˜zú·I—ÿ¶åš©¹9ir/IÙµ¼ž“äùX1Mç~æèªÀÀØvf^̹¯‚ǹ›­b†ÑˆI½Àp|9-ŒZÍ”è[F >ØåëäÜ¿MOÿ2pišÄÔŒ­¯0ÑKÏî.] sYZŸû=.¡!d«dêÙˆôß$å}—ñ“€Ù«ØÜ#3k{n¹÷®3ÇÎ\:’ÎØäD꧉ú}Kä¼i÷æ‰ …f“wmYÈìv_z¶*gûÇ€_ nR×m©µ8hðƒ<(hÒ‘¢Ö–ä©Ð˜ªÕˆB¢ÈÂå¬ÜÉBTœ¬#KÈ*)¤Ñ…{+y|}BÞ?“²›¹›XúNù¤£³9‘/œd±*$ûIWºÈ‚µ·­ÐD“>:Ù$4”ÍÎr?ÉÄ!G3 ¶Ù'  çÙ’læD”ð$cê r#Jtæ_ϵúÏOó[YN'˜ùoûERö—ã÷Yþ01ïŸ)ùߨs¦™QJÿ4ó9QW¾!· ÝþÀÙ­cÌ ´i{³tzúÓ¢è{¤$éÒÏ&®Îõ]’;ùÀ¿“Õ„³l¾"~Ò•çÉùÿ Ùç9'sJ:3¦4mGδÜï"¶Üòœ}v²4NÛ»û¨q›N¯œ¬dàH[?õ2HXI—žNÏýŽYFqLiìÙÿ¢›’¯ý!ö̸[ŽåÉE”±³è”q»éòôƒ+Ø»°ÙÏDSÂYš0mWvÉßlÏWbi";󤿈’xŽù«{åÿsâ’ æÄ'¹Â°ÙaÜ¿Qž“‡¿Òù]$¢¬•= -¼—½°"D¶ª`àˆâä9Ž=¬ <n9ÀRw×-îZã+³éòXÇIu¯/Ï ¡«öþÛ›;ž»Ø»poå;÷äç eÕ$=j;3i·|d©Ø ÔºvúzQý‹²'ÖÍÏ­ Ô ]À·9(IŸ¦ÜòغÍÛuþnYSeSçã²’½ëçÓòŽÂ0¨Ø¤”®ñäë¶è©ðYI©µIUä7ï^sgwcû+Ö•E¡ÜjòÆ:7¶Õr˦zKZ§^(¨¬jë¼wïö¼h/n¥mLUŒjD¡ºˆ}iK;ZHÈ*-'¸·’§c²”tãNövL¹´ÅѤN™t•;JYDëY8¥23»BæÄ±å†e¤$rQxoIP) `KÞ{iW›9w?íi@jší„gœQ/Vöd!³Ôî¦ý3‰ô|Âhz3sGSÇ)ìGžÂŸæ}âO)ù_;yõœ£¯'±O}Nv-ÛÉø MÎýÿ$âÞaÇ]¿&¬$²^;‰(d5(2˜®ò…â®1ZøœdY‰À9òê7É9ÿÉî¡}³]§.9‹ÿvÂýðïhç>îð=טµî nÓ‹¤ôDfçÊ&z±EM3õðóož®hŠôÉ9ÿ¡#›‘%ޤc2—jxÌùB 4T$œ}dgâï4§ˆî'v§l’a…]á}‰Ž¢XMœµaï©Ï_š:[¨l@†< ¤€Z©»ëæ™p½¶ö2]v Íhléxr-]·¸°ºâ÷&Dà¦â›Û£¹åQâ.Ö6w¼Ø°|é¶+ Í_F[¨t—A»€Ã>(.^´KF¸[û3nÉÍêòK“ý¼™=&Ÿ¯yq8e’Å€GAžƒ’É¥b“’.ÄiÒæœÆ–ç?)ûdTjd›Ô; xçÁS¤g/Z)_>{Ñ*RH6‘ Ü[‘ˆR^¼”[Þ/['5FmC×â¶îÚêëóæ-?þ¨½¹ãeˆ™J‘aÐÆTŨFböÂ•äØ°ù„"«ÌQ\¸’[_®åÒAœöy w‹oàÊôMÏåÒU¥…íz*Lþ´Ï® }˜žqV[âœöÇ”üïÌäzù„¶I crzÐîŽxi‡žHÎûkȦ«Vrgís#JÈ_v«žÝ¤$rAïwóº»IIDò$ù;R ÿ§éHæ“ú1fËWà H|J8{‚®ZMYjÔçIi<‹É0ì%˜A¤«¯ä'­;÷ò·ÈŸöãtê+„äwÂÚ/>ph ·œ^-…éÙWêõ¼YÅÖѶR1¢Ä¬ßÆÞ–0‘†:ÂÓšéë˜}FW#S™ „ºVtuÚžƒBcÙÁr_xÑoI¶ÏÙ#ì/¢ÄÝM+h%Ñ’ä«?Õ—µ€˜>y’¯ý‘}$\ÖnbSå©@>¢è›z,:|au$I\Ê#ʱ3Ù‘~Î|=c÷ØÍ¯ás"оYÔ¡]-Íø‹˜-é«Â”œy"½ÆWï•åFܺn”³Wl✵[÷ÒÞ0Y «¤[“°qŸÙÜÙíëèJ–§ž©Î[½¸¡­ÁÖ–Ù”r»åö¾é–ö~[2î–5¶W5¶^Ë:ábïâtª°æe]mÍÙ‘VΡ»³ 7<+,,\™Äô›ID¹”²êJQmÅÓöü ‡l¤»q*õõ$åÏºË æeY"éR_[Ýûèíã P ¥SZ²ÀÝÚŸ¸Û-·vDz«>sŽÚ-¸ÇˆT›Uܶ;rqΣ–³!*%F•šTWSø”´$õ®"Ê®C'÷?·|ývÒ’Ó’i!Y «¤l")…{+¥ÅÊ)d{ÖýÒ†ö’ÒÇ›ÄЇm¯¼gºWûb²{(–iÅí'VOãî–KÅ–9ì!mx.‚é¨H¼2Èrf¨’ž× © ­«VfDa§uÉÒ©_S"{‡/ú£c²ŒéDžXÊÝÄÒG¦0£(ûéªòˆ¢pÑáµw&ílMÎÿWÒåŸÙõœ=B9J¿þw2gæñ ¦}ý𤠶oèK UŒ(ìPEÛ‡ˆZ2•¬Š§µÑU'sfV_Ÿ÷OZBŽuÔÁj¿9{­|¦ÈOŽê/¢LËœ|ÂìÄÀ‹–$œ9ÌÞjÂ…¿¦0TéDA'ÿþ®/L"ÊÑÓ"²Ž?³|ÁLé»§Òˆrà lÀ‡|†m9™5N"Qˆ(¶3nž';ãEß|¼¯—÷É#Á\/P«!u݈ñ“¦Ò/˜7ï>Lç‘úÕ2ÙÄ­O\nìÚäGNÕ½˜íåu¸æÅ†Z¾'ÈÏ3!¯²ä(éõ’~ðÖÒö3‘,便_z³ùúÞŶ¶.^Ó¶6¶V“Qjª/û;»Y»_lèÚ5¡ßã[´|Ý{% H!·&—*½@]ÉÒí»s˜9õ”¯oI–fEr«q ÚêA¡è '4¨¨>â¿(—t”wm^>e²¥\9{”#Q—儸õÛþ TiRÂÐÖÕÖÑ#ùAë;Œ(¤õ–­ÛæLØYsd¬’B]¸·RQæ]k¼wrƒ£½‹ë¤Z»ù2CU$¢äŸÛáæìF'zYÚzm»Þ|u¯l~Ý TlI‘W@P˜“˜™òcGÚs¿—¬[;°AS£=Š"?­KžüÔ¯ðŽÒ ?uÜM,}Ç\Ò‰ŒÙ”@W•F¥]LÃqÈ ãŽ¬•/xß!…‘K˜· Ÿûd9$Bnò•ž˜¯/›¬Õ‡žÄf3m,îø^Z¢$¢Øs"J òˆ¢ï$ëâSìð‹üŸ& g®3¦TrÞŸe÷â¼(èÀÿM–h$ç|u¤9hï§(F”ÛìcàÉ"Êsù’~#ŠžÑÆL7Z±œ<¶0Ùc öéó”&w. o°ˆB¯-/èâßHyâ…²ìzŠÉ„òZ4qwH3M^âùnYˆê/¢DÌê™çÖQâÓw±»U%¢¸ù0W{SJa¢KiDÙ»³÷dæáó1¦ ÅméU“”œù£`€Çðö†Ôu£_$“L¢FÈ* *ìWÎòâ®5ÜÚkí_ß\BzÀ¡G*n튵r‰mîxéîàbåàêæfaãâä²¹¨íò,f í[ÚÔw¼ò–ŽÀ VºÚ3åjÏ )ƒMúRH)*æ ÕzúfÓH·ïævÙ/A7u¾.+LäVã´ 8¤ƒbçì09""6™Žk‘dB³ Y%…dS\ò¦Ì^·?ãzaÍ‹ÚÚšôcûH´‹(J‰(9Kø»ê*MÊ ¹Ûü# ÐEì?~ŽMzd¬ÒrR{+…sQªkó,lÝ+Ú_G¸ºÓ ÑçjÈ ÁBQù0EQê—dTÖ7Þ–‡RK"—„ëÍ]U/¨Øžƒ6¦*F;¢ð¤)eJd\TÜÌûd¬ª’O(z »›­bŒ3 ˜IOKpØÃtLǹÊ~5FõˆÂ“ z2‹/°ŸžûíFÛøï”üoMäfyIæ2çd{K¯=¥Hß&‰–yÆîyØ¥?òš¡5³Oç~+‡/ ¢?Õâ>u®ÈBv×FqÏRF(¢,g:º‰[Îl’Žð¤0Ë’½ ó¤i“žŽ¢jDá\cÚxÖ ºÉÂÄ%þ3f½B´¾Mˆýô#;Û¤R¤³¶èóDÓ"Š®ôQñÖG¥qE:Š2_VAÏhÓÉ,occ…ˆb?÷ðÆY²çŒ¾yXh?gÞðxÞžê]7v¢‹Ò./)T˜ÃòL¸^ùx«gB^ÉEdÕ)ðhuå1—Ћä²jã‘p$§¨¸¢&ÿú³;ä#ŠÛŒÆÖ…½‘ˆrv²,–¨r^ ›RTÏ'ªõuÄ~Ì(Ê!:ŠbA–KnÆr«q ÚTñ d¸?MÖiVè:³lYW;í\c\}¹x‡Îü<¯©ìî6 ¹ˆ¢ô‘ˆ’1eÆ—§J“²ÞmD±è™2§0ÅŽSqë[(E! ¤¹ó›=&¬-z˜5ÃBQ¥!T 潌m¹Í]»c˜±)U ©%=·•´u—ÝÉpWö5´Rƒ6¦*ÞADa­Ø°“à–Lß=3…™{s[_¿·ÏÊLì¹öÏiŸçZŒ?Éü.Ê…"þ°~%ðâß’sþ]¡Ðf7“y\¬éR¥ü͈(A¿NÉûZ¡Pß)›ìvúæÌò¾]|¾À9âò7¤Ëî-–9ßÀÉcÛ¯HýI²Þ¡š"ŠÜŸ&<ÿ×äÜߨ9õîÖr3ÙlJ33MàY’œ "ëºvÉáÒ“¿Ù«*¿MDY‘v1̼ßëx¥1?8Ã4ãþ[ÎSWºÍ½IVJŸˆHK/>[yÒ3Ôˆ(<¦˜ÀÐs«‡l9û++Ñ›2ÆúÅH\#¬ÂvEK/ù•|õ5ýUõEO—ïs“°ÔGÎî9zaÛÊÙk3׉&eçêÙ ·¦íOËܸi“)“y¸Wô²ž¿qßé½GN-_8SéO¬àtyP7»nô,aùñ“]‡NÒoèåO&èyÆ 7¿ÜØU-7ãeyñ3²ºo²?YžuïiÎÒ(²à0aFNS×ÕÌ$.Ò9¾}`:YX¿5gû|+[g÷ÈÏêŸVÚÛ1½†Q†AÅ^`TVmsG×îM›ÝliîìN²îýý® ÚTñ XÐèxü7önM;G*(ÝÊŠ<ôøÉÝÓÁÌùBvž!k/Ô>ÌZb!w”£;¢ÈOëê3ÕØSQlœä7_KBˆÓÄ9…O»–ø3gaÉG”ž+z¹*ï<¿L¥‰s*¶¤®Q`mÇ릶Æ«7.•Š•~:¨ASï,¢lؾŸ*ò–ÅÝ:= ×UÒË¿æu°6pÝA[*¢/2W¡•vÿìÑ{i,¯Œ?“.µÏŒ}N“kß3³yz²LÉÿF"Rüv\Ïa9íûÆŸùrÒ¦Âñknm¯Ÿ&ý è-GØÁuD…?MÏaãtæÿwÊg×}fíûy sjM>¸àDç|C'hY†ûŒãëž$\û:xÓ’:S—µ²cºÔÃŽ(z¦1‡ÎýýJ–ŽùÜèœoé¢Ï•Åæ2%lDáéÓ SŠ?ݨ,¢Å3Õ¨©szé’oèr®7½ôÊÿn\˜,dª/¢ pÑáéŠUúd\tÔMÅ®QÒúD¶G² [ÈD”4%%îZC]ý5v5`ùƒæÎ.z’‰ÃÄå9¥MJ+r³O¤¬¼ZÛ\éæáu¤¼¥õü–(k·èý¹ÊêÛŠK,›hÑ7–¼óˆ¢#òÞšy¯ªµ«èáƒõ³'r+(5hPŃB‘ø¡tðŠø8Ÿ–¶ž‹÷fTµÕ·uUÕÖežØçéÀö((=FvD±èƒJú4•<à ²Ðßh¥4¢X9…îÌ*,­o+y\¶e‘ì‚]Ê"гó”]O+èµï¦bKJ¼˜!y£zE¯wQœ=üI/áEçaMD1ô\ì·¦4úì%ä~›tõ£µø$®™øúìø%éDN õ•U›x<êÜWÉyßD,c.ýÄ0¢˜KÇgb·oS(·Üø ¦«zê÷&<æYã\ç] =öó¸ËKÎûGü…ÿ ÝqÏ%tš|—]…û§é9Ì·©nZÖŸ“s¾ŠN똳©çj¹tëü‰»;¦eý5áü/B¶ß·uuä '‡œüMrÞ߃&1s´†Ql’l[6ÈNéŒñ]õpê™ß']þcØ–Sù_—§ Æí?õ_Éùß%^þoWé/0Q´éÙÿ„­IŸþ=_èã<7'ìØÏ˜_—Ïÿ6!ë×a;ï:ú÷>ÓÔQxýÿtã(ÃO7À(P±ëF¿­ßÔw¢íº)Nôì;û÷‚нÀá´ ¨âAa‘CpŒs=wHµSPFÃûÕ¤òÖnùœà–¿+jmIž ©ŠwQè¡Ð‰^Ç8?“ò¶ô$vŸž34Pv¡-Ð$܈òÁ02³¶w‘]ø"C( nªwÝh—wÙºmý.O6q;Êï)µöíª~P¨ÉáÓŽõœ8A¯èeÑ“[È&nýwâýjRyb“dN(}Ú¿jmIž ©ŠwQˆñÁûÒ2²ÀÝ ƒ8¢–6ÎÛî5RȽ“ÇÀ-YCêºÑ”²IÙE‡7õÑá÷‘Z{ƒv‡tP,zÎí&}èÙ‹˜ŸØ>ÆüšÇb²*]ý¬Ç;÷~5)‹^M›>í¹[ß µ¶$O…ÆTÅ;‹(vDáISн‹ÏèÏø"÷HîùFÇP»nt~í±‘~0AɌ¯÷Z{ƒv‡zPèåžéˆÙŸn¤«Üó‚Þ•÷«I):5-i½0š†<ÃÕÚ’<Sˆ(ð΄œúå´Ì_Ç¿ÏÝôÁ02³vòð·vp›Z÷w%â‘Bö/½~—;¹GÌï€Q3Œ®›³é±­Ýò9ýv™,UÍ™3"ÔÚ ´ 8ÔƒBI&ò¿3HƒŠæœDñ~5)E…Nô:Æù™”wE­-ÉS¡1Uˆ vÒk|¹‘äàæ3A}¤YÈ áFÙðºn<µöíõ ŒŸ4Uiï™jÈÿï[“²"¦%3—u>~Ns&1ªµ%y*4¦*Q`ø\=l=¸Ý œúzúB‰¹•·\ÞyPФ#E}-ÉS­1UˆÃgnãHzoÜnÐGN}½@‰¹PbÉ-—÷A4éHQ_KòTkLU ¢À[!]7W_nOèc¦¦^ ÐØRů¨?¼ƒ‚&)jjIÞPsPˆ(ðV"SÒ{ûf¼½ïê %sÒÿÓ50ænåúð št¤ŒxKò†Þ˜ƒBD€@gÂÞPVv®#ˆtþ†1æ;(Üfys“r[ã- ¯1€ˆ4" hDÐ ˆ( AF/¢Ä¾]VYí 2ân’gä’ñäáLnùvWuÆZ˜É—Ø&.©iÜájÅ­<ʬW=´75—­êIBŽìâÖ!„ÁY~¡¾ÜrUÄçýS sËÞG£QŠÚ^Y éIó ÍF$¢Äµp·–/Ñ5(ñÕÖÅwIÿÊk¬,)éZ ñåÖ!Œ“;#fË—ð ,¸Õ”2ó‹×ÖcWøœ ï‘QŠ(‹¯Üoè|}§°ÔAd$r‰;u³´¼±íö­Ü©žL÷]`¹ òñgÛ.Ud°ÅÐ.áncC’'“4&.8|«´©¢¾)ýàz¡¾ˆ”˜¥^)¬©ª®ÍLÛ|¸æ¹|Dq[sùQ[wyQÙV+»·¯Kw|7=\Gä±þìí⺶¢¢¢U‰ãiå/Z¾LÜu³ª®­ªúɬ “·e=ªk¿›ÆÄ Ohá ý}·¶LÏúSô±f×ݱ“²d[õ-cs¾µ–˜‘4âc%ËEN§™e“Å•Ós¿‹;ùw˱¤ÐtùOLÅf!:+òì¦gü,pÑæéÙÝzvÙÑç¿N¼ðïAIA:¦ëδ^X›Y@rK쮹t‡º»“.?ãë M§_ŒÎü]ü¥?„oÉÖ—&+rX8¥1zõ±ðsŒ»ò—ðÏ>—„žŽ>󫄬_ù„ùÉÿ!n”" QÒÖmf æë›e7v혤£'vß×Ð\$Ò‘ˆÒÔÖtla¤@_D#ŠžÉ¤ìºgËBÈ Í&¬©Ìr·4Õ;¬ËoºöÙDm¡Ûý§]K#ýøú’)k®·<ÿ‰Â(JbQë^g&üˆR[Õ”0ѯ+L¸\çÐb‘@,q‹¿÷´+Ùš™E"Ê•u±dÁ+µ ¹£3Æ},_ßr_õóCž6ò;tþü7áóêè‰ ½w%çü_}ÉÔ+ßÐ\zöçÎ]ãIL" -dGQ‚ÒÎ2õí%]ynicË7´÷Üõëä«?áÉ¢ˆ’œûÛÀé‰ä¾tL–&_íæKGHL¾ŠZ£-žš”óS3žž…DZßzòä"JÒ•.S¾¡WäÕob7o×ÖŽ¿žxá–ü áF;¢m7ÔÖå°…Gkž¯³·$¥ñi•Ž´/N"JåãÇKÛ^L u¢n6‹r¥ËbǽÕ‡Í&d“:´„$ ²ç"Ê“Bé@„ž¤üY·¿„Ä &žª¼¾aOQ&š0…"ÇýUOvÒ­“sëÏ9²{ã ’ò¾54M³ ]©/[nþex| Y5ßðó°éÌ®Ž(${„'HëoúÅÔÙSh5]‹]J"JÎ/h,!&e}íjÁŒÀL¼ø7 K¾($1÷ONѺr3ÓØˆ2mO -ñ:ûg_k&bi%&eײ54ßhG#׌ÊÒõláÌGm§¼lID©­9GKHDiî|}pùÖº¶FO#cR²ª¬ýIÑã[÷K©kùiö3n?ʉfw’VÛg¢¯oD¹ŸN´…nÍ_²çi8/ºW˜Á”“ˆâ.fîEä°·¢dÝ:)§ODÑ6ŠKÎù¹üþ }ÇK gOótÅaÙ_›1 8pD1žýÂÆ„y¶'ÿì#K\|ánDI¼xŸ½“%¯§ÎÕ–|š”UAKŒ‚÷M9òóäkÛrÍTbÊ“‹(1›ãhϳ¦SËÈ#GD€÷ËhG¡ígµuWÙÂÕÏ7:2£(5Õgh ‰(åÅËÈBÔ©ª{'™aøûOOŽ·§[u„>¾fY•?“íDORðôÕ¥àd(­VÞÞí×3Š2>­âúæ‰<Õ" ßÀ-9ÿzâ³Ï¤Cb¡1Oß*6çoë] gdœ¤_kYDñ;÷…ˆâüÝd±ëWSgõŒ¢˜oUQ.ܦ[™ –{Ïç‹cž’ Âc.'àcìè@´%ž©ÝÓ,â!¢À‡e´# _ßìjc×¶Äñ|]‘s쮆–cX!¢ÐÓåuƒJÚ^ÆÙ˜[EeVg:[˜òõ-dÖ䬯#ö-iëJ ÷æëMHÍnê|=xDÑ&]©¿½@_$vŠ-héšeË\2K•ˆB¸ù}è¬OùzBû椫ÿ¯®ô”}Û}¿‰Ùýß!=ç£Ûý}xR Y0ðÞ‘œÿ/6¢øYÛh§D¦2ƒ6„ÀóJÒåNó±V|ûŽÞsQ"†ñ8…§kqù“.þÍNzÞ‹ŽùÖ¤ËíÆ&¦<]±åŒçÓö.ä!¢À‡e´# Y»Å§ß*{R×zçöµ(/¦¯4¢^ëî•ÝÙBºã‘«OßyÒRVÝqh3½¢—Ť¥W kªêŸe]=«¸M•ˆ¢#òü,ãNqmë£ââÕIÌi!<•#жÑdÿÓ³þ{ò©³Ÿ -xßKÉÿ‡±P62£ç°6<ý¿ãÎÿ1ál¥ç±?Јb¶¤)áâ¯üRž¹J3e•r+úÜWqY¿ ˆ_N#ŠÀãLÜ•ßON™Ä‰(BËM¿H¼p—]µ_ð`Úůâ.üvêΛ&FÌ]#¢À‡dô"ÊG‚oh#÷+%ƒàxш"Ê»D"JÒ•.n9ÀGKkŪUˆ(¹±9s’ PE ‚ˆ4" hDÐ ˆ( AQ@ƒ ¢Œ˜1|Áyº?£ý~Ä#ÈY%…ÜšÐD€·ò‰ŽÁÆhëé Db±±±±¯o||ü:é?²@VI¡H$ÖÓgª‘ÊÜ=€NêLÒáÍäý`ò@VEÁ"žoVê¬G‘ÊEEEB¡PWOÀÈ €2ˆ(C¤#°°°ÌÌÌ$yãÔÙSÖ“¬u¢t´²´´~§¥õ¦¿ÕÒº¨¥3UÇf²Mzf:¹á™3gÈNÈ®wðÑCD]}ÀñãIƸ[pW`&à­àiýƒHðw-Þ2ž…Á½Â{d'þþãô†Ü{ø˜!¢¨Jld²rå*-–l\"\/Ôú'¨èßµ„ë„˶,#»Z¶l™‘Ä”{_-D•|²uëV*ü"üÆ£˜:†nÌ¡1ã¢Æ‘nÚ´‰¼ ¹÷ðqBDœ®¾!? œøý»ßçæáùþ­ï- ¢c)zÅ;ø8!¢ FG@Ï?ñ‹ðÁ|B}ïÖ÷¢˜ûùóqö<" ÀÀ>Ñ60·°¤çŸŒÈü.®1Ç,ߺœÜ…™™9OW"€" À@tô™™™w î2çÇsÒÅH®>(LOOg~/…ó>*ˆ(ý£Íü>ã›7of‚á_¿K?Ó2kHîÈÀÀ¿=9D€~ŠŠ‹‹Ož=Éüþ 7WŒ(ÞÞÙóg€" €rŸèŒ3æÍ›76“l†öûŒÃó7-Û)¶äî~øÃ~¢ƒßs€" €r?£””ôðáC(Å8¡Ô×ZZiZZÉZZZ½ÿ6sªõO'\§¤¤$..ŽÜ5÷ñ|$Q”ÓÓÜ¿梙ZYŠYB¹ÿ’K&ì¿¡D”;÷os–ιs玾×õ€" €r"1s¢ü'‚O´~§˜%”#åÿÑÒòÒÒZ¦¥¥?œˆBöÀñ¿ûî;###îãøH ¢(1†/066~õê•p’Ê×þ§–Öß{–Ç+¢¼Ñ2œhøÓŸþT,ãº^ðÑBDPâÇ<]_ßÊÊJIªˆ¢`¸Eg¢NMM——yÜGð1@DPâ‡c´ãããóóóy3‡u¹ááF^ ïÆ8c>fˆ(JüŸñÖ­[—––öƒ ?à‰Á 7¢ü`ýŽ?¾fÍZò¸ àc€ˆ " À»‚ˆ &z¼+ˆ(Jàty€wEkŪUˆ( Ø‹‹‚EÜ 1¸áFa€FQ”‰Åÿú׿x<­ß*‰~mè¡ÓQ|zJr8•¹~­¥-ÖþöÛoÅbüt#|¼Q”ÓÓ7(((˜•:Kë"'Kôg€ñœÊÿ–ùos—Íýâ‹/ô†ÜÇð‘@Dy ÄfÜB)?£ðèÑ#©*ŸŽ2À?"ŠN˜Niié´iÓ~ôÉÇu®üX;×)‘ñá±)ƒ"ÕHeî€Kd2ÖÅ3`RØ4‚,Un€ÑAžô%L¸[¸>üˆb¼àøÕ‡åM/Z;ïܺ6?ʇ[g®+ Ë ¸å£Œ¼­“Îéj°ý ²@J¸5UÛñºåùO¨¦¶ç·¯¥Ùs«±Œ\2ꮓmCWr“  ·Î;%æë‹9…#àƒÿøÇoÞ¼±™l£õwÅ81òþWËvŠ-¹»þð‡úæ3éÊYìÇ}`\Úú½°»ª“ÜpŠéûô¢&ÏdÿÀpWßA‘j?í…¶Ù§7QßÒzõÂq3U[ƒ¯o9¼Ö#íÏç¾fV޾Aläó&Ø€G6‘ Ü[qé™Nø,-¯¨®£¡íyqiÑ® ó ôEÜj#â@õóS^¶Ì²y&+n}ãƒ#Ul¥AéO&ϨÙVCþ:©·M”à‰ª­ž÷÷A>­ÈÓ<÷²0Ô´<Œ§¢|#°¯Mc·¬ÚÚ ÜÊ ™>ðˆb¼£¡ãË£[Ö„L ôŠš³ù\sÇ«•ãí¸5û£ e¬+íjДÂëÉ'¤tÚÈVcî­úC"Êé° oÂcB䦋uMmõ¢~O~ÐðˆBžú>u „¢¢¢¢ôÌtÞ²a]zx(>Iý$óbæýû÷ …bÏŠh»ªâ ÷Q)Ð'5kë®ÒÕE™yÙy·}Œ5ë0 Œ>“¹å\¤©Ì-gш2ÑÓWú ÷ Ÿ›Yý¼¢è·¦rz’¥«7Ú ‡ÜÉ#Ép€娡]@EäßÈYe£ YàÞ¶=ɱ²ŽÒü´)cí¼¢R/Õ½¼s$Y±Ú K]eÉtâýŽ<)ÌçVeª?!5ìˆÂ¶‰RýEú.í.Â'‚úH,li¡!™< úYÆ“~ŠIÌUxÉ ý©¨ÐìkS`ž¼hq"·>h¦÷ ¢OÓñÁ‘ò%ô˜[S_ßìjcWöê)ò…±çj*Kvp+÷G" í–‘7tšRxrƒæiÕS ‰(‡\¬ÙU]±?y7?âeíI©Qïâ$oµF”1Ú¡PøæÍ ­W #é§Z"k¹#@@îôhÍsÒÔ¥mÝÍÝý78¥QÞGlÐÌÊ‘}±“'9;'„ýV[ňbmØ›1LÇe’¾!\,ì[ء҈¢Jü 1†[.ÏÐz%“ôLzŸ{&þiÍÏCoã ú|¡þÞEîÇ“¥Eû­Ÿ~šQ>¤ØöT(tÞ×0žŠýE.5ÀÀˆÐôˆB?MÞÅhá ŸÄFn‡›ÛŸYÊuVë¸YóÐeëˆY÷ëêžu=.)Z7‡ù^‡ò»'§°¦¶¡þbæáØÏ±%`•5m·sg;+ÜúÄfì´ ¶)Ø~CW}‚¾BDá:4u¾NoO{ºlßÎ6þVåãÏxƒE¾=)´°K8§æÚŠq¼~ZI×ÈëÙ›ëž=سvvfýËX ³þî‘00ÿTÞò–—%mZ#Û‰$pË™;%õÏ«ëÎÙn$¹œ¨nyÕÜùªº¹ÓÔ@,7÷äÍ²Š–®²òŠ+™á¦·§«'8sæÌ½Â{ÂuBÅ\1r W>(zpâäI]}Å,&rÔ^˪% Y3¼Ø£o>yGæí²¦5uõÙ™‡ü,MéA¡šÚy ½ô$ ëNÜ,kihï*-)Ú¾r†Ž³ó \RçÞ©èùG®—·t=©¨Ü¾8‚Þ…MäþK÷‹ë:kš®ç_N˜0„!Çac{0ò Ä?0œ ‚R܈bäzŒ”øI$FÎ'ªÊ÷ØÄî¼QÞ¹ÔÖ‚l [q싊ֆ¶çwoæÄcRº|Ï,ÏÛyþVIS}ÓÓÜó'ÆÊz™BûØCÙ¥M/Ÿ”—n]EJ¶•45t¾nly~m'ó¦ä7gûµ¢ºÚ¶ç…nÏ sâ>Hõ‘ï RòI´ C›µ¤f»öæ¾m@P`£g´-ãfaugUMÝñ½ë%²Ö¶‹^sñVYuÛ‹7gNf"¥ÄëruÕqv'á…OóÖ' ¾ûÊní ŠÝq¡¸¹ƒ×Ó‰ôÝWTÛÞÝÜþ¢äÑ^]ñ¸†Ž×±¦ô†"ÇÍMÏZ-ú¾™«·•Rå“H>¢xï,½s jÕ…ÒæÎ×Õµõ‡>“¥o\lÇš¤¸Ô#9ë^”•ΊoîxÁJŸ¨Ñ¾IçïÕ×?{^pûr¨µy7¨nf¾Ý¨mîÜá4–¯o6g[ÆýŠÖú–Ö›¹A–²ÆôS‰<ñÈiI‰EŸ„@V¤ãÿ4® |RåPŸŠ ÿÚd¿Ï;®®8¸òBuGwCKëÕ3ûMzžÃKŽÝ*k­­¯Ý½4öxísúF¡ô€ºitDà`€M,·Õª+sË)e y{:´r†“ƒ×”»Èò:é0“€Í/·Ìspô‹Ûp¹¹½›F”±Qi -OfG…XÛ{‡-<ÐÐþ|š9w·jBÞĹ/ÛóPñ•’(S§»4wt›šôT‰(™Eyñ!“ÇJ$ýµÒ†‚Ö²;éý¼'LÏ(gúÐD}³˜²¶W;—$;8¸úE¤Þlùòħޤ<ùzSIî.W{ïÈ‹ ///eÎÓèEÑ“šç×β³söŽXQßñzሠ Ë7oÞ,Û²lÌ¡1ÜtñöÆì³jÇ*rff亭{Hšå‹=“MüO‘…Š’-ô‘ðõ-Ò«™Þ›ÙfÞ' 5UWôõM#âW‘冦°Èh^߈²¯„,×Õ=:|ìü¦.²|us(¯'¢4¶¼,»w'ýÊCÒajîìž&Ur´ê9YÎH;¶íàùŠön{\Ô?8¦4ŒDDIìwÝk­«Ïç“§Šó‰†æ¢ÛWO7N¤/²KºÐØV7?:ÌÆ9`ÆÎ›mµFÆòeê±òò‡™Sü­]Ç/Üÿ°®î&éñ ì.7tåì[ææä곺ª½{t²w2‰åü¦Ž®…1ÁV¶î‘+ò[kDoý•¹ê¸oòÍH Ú† }ÓÃEÏšÚšOÚ›i!‘ûV^ß$­¼óæ‘Ï<ÝÝœü#÷´]\BÊ…v êÚ_nþtº½gÌê+MmMö"£"JåÃÒó;—zº{ðäZO~eUi{Žô5NLL«(ÉŸÛûԌیܤ§ÊgQ[ºN¯›aifí³¹©óu2ɽý¼q±m2íLuÙ“þ^žÁsn4wÉG”’м`ow#kßM·[ßžÃë;€`?ëz}ãí`?KGÿ•WÊ ÖpžšÐÉÉòÉÄ¥çÊ Žn²cÊ“f•ðA¿_úS±¿QùˆÒÜÞ^”µËÙÎÆÒ#úzsWÖlæ#Æ&.£¡¥dzðD;¯Ïï<%oŒLDé瀺inDô`Ð ~‡žT”¬â–˶|R^$ëüag«Ëî2£+É-.Ì`Ëw”wЈ²±¼ãò\æ]ŒJ¹÷ôö¾É ûT+*›¸äO—gú©Ok×Íb: ýU"JZ˜l´Di+ ,f‘^/;'ÁØsWË€…|—,fwâ0çnuÅ!²°½¢3oµ¬Í%ãÂ|™ Å~êð ÈÞ–zÉÒ—Op¤Ç`S¤T¥#ð÷G"ĸ¨qß¿õ}nÆxßËÿÞ„iÈÎ}||ùºÌÏ5”æ¥v–|C{H€t•~ÖJ|N’ò'…²¦Ô‚úêæÎO­Í&z±…ù6±£»ùY«Ÿ)ÓÖqäÕtI™F”ª²}tPeFA Y=äHî±…©òu#}zçE[7íÜ?Õ\í_¾*M oQäU•ÞšæaÅ“F²ÊNœÛYÙ™·–yæK‰OսȞíÍFmC§ÚŽî™Ö²¾_ß´àé«ÝîÖæ“.’4(èIAûÎïø”æ’ë$ÉÇZz6 ßÀfRh´XðFæõî¿t×ékj:˜'á+1ÞÒWœëÁ†§åìùʆÖKš;¾k(žt¾¦$O6@MÂá¾Ì«3­Ìˆ(µu9ôéÇë'¢8̾]Uþ9³¬gt­©koÀh èQ ÍH?kä?nýôa)D”ÚºËìeÎÕ¿<äbÝßmm¡yÇfŸ‡ŽóîÊG”#Á²1:Ë<ú&)ß;÷Ý_VQ²‘6²¾ÙÄÀà ´ò(Ð109%2žž‹BGK­dk–·wouì=2åzムSÙˆ"°œGªzž„DCÇës.>{Jˋ؎x¯Þi9†Ž§µ74VŸäˆ"ñ:É=EäÈ|…ï'‘ÌRˆ(SHDÉ! §HD‘öÕ(é‡ Qr›ººõžÂ1úøKØÄ¥p. K!0ØÍ¸­zDaGH”¶’ÙøœúÆ;r7±kî|Í(ì=†|Ñt÷HˆÂN(¡C`ÒâÍ2¿¨îèÎØÄteN—· ˆ]¸þóôü'äÐ/Ê¥Ûe$1Ý´i‰ÑcŽÀŒ¯1ûÆÐñ“ 6Kd{®+ iB÷¤p%Ù侎¹Ì×ÕÔáG”=Òˆ’ØQ N2“¾x}# _`œ¼b¾"…¤¸ªçëCõ4 ZÅ=…E"ŠüóP!¢_kxx)’(úfñÌ~8ÃwÙ“ÌŒl7ˆ'ýÄ/òÓÕ»N\-n¯«+ò2B'ì-‘ΟB ™ŒU¸Æ+©@ûˆ°›¹w÷¶ÞÓóxÒ—íöWSœ¬¦^¯©:Á½ÉöŠÎ왽çMQ %æa+QJnIJåJ# -ψq˜VQt)IaÏjÅ>ßÒ]U峉¥QßÎnb# OÙ—,¢Øm&½p½žt!´ß!QØ7^¥…лDÌX±õHVacWqÞ~vØjŒTDÆSQ¥ˆÒü­ßQDu¯×²EORß!‹(&›;:I_Ù,€¹2UYÁZ3õvMEó䱲f¬«Ï£å½½„n̼ˆg­>ÒC&°šN>€›žµ ÄýEåÌÕŸm_4‡ùí ¾À2ñSNû”jÅ>å¯è¥´ÂF”Ý•×V÷Nô:^ûâòÜÞ‰^<}ÓGmÝ›|d©ƒ<ù³ò È“ßj*ÉÛ_°_HO6ÎŽµ±õœºüL]ÍKQÌ&ìnîx¾&9ÖÚÆmê²Ìƶ:ßQüé ¥§ËºI©þ" _ß´ìYwÆŠ8#±¥gÄêògÝÈ(ý´’øpygÙ­þ^ãbÒ·ÒQ”þîQ×(°¨íUÖöTWGgï©ËKÛº? d~\ò@ÕóÂô-nÎΖNãW^¨++ ï,ù°144Ñ3š@zäG–'ÛÚÚ;øÆœ­}qu%s…±‘¥'úùû“hQø Ðp¬!o Oëoœ2€ÿÕâ¥òDÖ¢‡Eéù't~¥oG³±µFþ‡ÉV?n'…iÁN$r_¬{I–o]Ìܦ …9™$C[—™YÄœïÞñbíšÕ<¹ˆB–Ö’åÚêûeÜjdN—ÏÙÆôÿú‹(z&U$Õ´?;zààg;]¯gîn¹;s"‡Z š±ÕQìf^"MýiDðX{¿Äm×Ûj=ûž.?q×£úÆÂèà@KGÿå$?K{?B·›-_^Ú•êdïä¶äɳîå>ÒÓå+;³â½u ÅfãO4=k™=u²åX'Ÿ¨•íÝ©ì÷²êGÒHxßóÃ¥ßú³«ô<æA—¼Øsº\:6™™ê»ñbmmí éÅ»D»=+Í?àãaçsª¼óÆçSyLqucÇóu3¢¬­]מo|Zé,6ÚnhîèútН¡ÄaêêK-=‰·ßˆrøIéÍ9º†²7åÜæÎ'ì|ÔÑ1èRuƒFÝ~Þ¸Ø6™•]_v똷›‹kàÌœªFòË,¢ÄÚXêé Ç«¨©Ìöó1³v‹^‘ÝØZÍ^·Jݸ§Ë“ö¤§ËË7¬*§Ëã©(ß<¹×æ ÅaÎeR5ÑßÊ}ÒÎåõ¯ÛZôw€@Ý4:¢ðú‰"J ûc¹,=¿´ª¥‹ùuù›×æÉýº¼mäêìÂúúö®²¾·àóÜšú¶çùY‡¼ƒ®±ö›³ëê½ÊÚÖŽ‚;¹IA£7Ô«ô¢ÃƒnêO…pHÞ~ë sÒ'˜wm…×O+ ,Ãö]*(m쪨,[ëUË\N”ùÌVz<éEÓóŠÊŸ¾,)-Y?Oö­ªØ-%ýVyí³îªÚú¬“û¼Í˜G¢' »^ÑÞÔÖI>}]’·ç•45t|ùøIÅ-ËGü·/(¾ŽÀÌÌ<==dŒ³çÏÚN±Õ ×Ñ:§¥õ_œ@Âúµ–V¦–N˜©œy1“ÜðÔ©Sd'ôüx–óRæ:]Ź3ä 2i¤ôsþƒÀ:|Ï…‚ò–®j¦öxôŒ)ÅíË+où²¶®„×7¢ðôM7œüâIkCGWÙãâ}/:Ì(dÙ:tiúõÒŠ–®æö®¢¢{kg÷™b¡&ƒößæwQX …ôo"W¿Sù¬ñÙ‹‚[J/:l6gçù[›ë›sÏõ“>ß±{Êñ\æŠØÅ%%ëæÊi'í¹QÛÞÇÌ'o;ÿ ¶£ñÙóE+?U>eQ}üÃÙo¯y}GQè÷Ö 3Áú#;yãñœ5Ï;^UÕÔdœØïÛsÕZ]ÉÄí7Ö>¯¬®9±k5{É2פ-— *kZ;îÞ¹–0QöÚOÚ~±¸Ž,¿Ÿ‘’^=pD1Þý¸¹«¼d»)³þeá™ÑþÒzÐ'¤ê(dAéÛ&Ú†N«NÞ,m꼕yŠï.’«yýGò¬þüfMcÇ—[Çꈼ¶f¥P4ŸƒöÕÁÀÌn'Bð6Em¯V;÷ùCFêOHõ%ÏIuî¹ð·eðåêÊ4NMDã‹ý¾„¹åšÀ=q~¸»ìɦ' oîì¶åœ£æ=ˆ(@Íé,s…ó\ؤÉ"Ê{jŒ¶ÀP(þáwçÎï¾ûî§?ýiMMÍ7ŽKÿ‘²J ¿ýöÛ/¾ø"!1ñ“O> ˆ"7äîíc¦zPÝEdŸH"Šÿ{~QQ’FÈ»i(G7?c‚,UR¨[4™™›÷ÔU7ëo #Û¼%ÒVþá¤ÑT1謹·´£¤ýúöÙF"#‘ÍÄ#Ûsz¯”­é$¶ôùF¿A£OEúÅ“>KFWÞ9¿Ý%å…‡íÌÌtìæ)ro ·ŒD”÷ýFJic€Mkÿç»ØsßwŸèþhŒ¶¾À@ld$‹½¼¼×Kÿ%&&ùúú‘×—µmhxäÞƒië6ïäîTïÒYLÜ=Œ‘ÃÞæŽ—9g6³×)~‘¾ }g #'ôëêÏKÖ4³oÖ–=ºŸ:E½@©ñÁ‘ô;~U(½ÀÃXFì»\TÖø¢¢ºêøžµ£ùK #…ÎûbO—ר*¾ÀzùÁÜ¢êöÚÆ§—ϧùš¡kð.!¢Œ˜1Ú‚ótIb&‡D¬Z·ù•ü»EOòïmÞ¹ßÊ~ ³B?fcí\ÙSªFª |rí[Òæ”¼×b3Ò)$áäLî`±ó¾4jfh2DÐ ˆ( AQ@ƒ ¢€AD ‚ˆ4" hDÐ ˆ( AQ@ƒ ¢€AD ‚ˆDkŪUˆ( !0Š Ü×{Ãðp@u²ˆbaã ò¸=oP·1T‡QÐ ˆ( AQ@ƒh½™?4" hDÐ ˆ( AQ@ƒ ¢€AD ‚ˆ4" hDÐ ˆ( AQ@ƒ ¢€AD ‚ˆ4" hDÐ ˆ( AQ@ƒ ¢€Ñ#¢€†@D ‚ˆ4" h­«V!¢€†À( hDÐ ˆ( AQ@ƒ ¢€AD·enãèêà0X¤AH³pÛ …ˆÃ'™’¾8aãèaaã ,Ò ´eHqÛm¤¸®(lyþ*ÁÒLa«ÀbÝTr#––„>¥%SLßñKÞØ-‹>’«©~Ü­ßÐaÃéÛeÍ]Í_æÇ·ué­ö:[qëÀ†tÁ\}¹t Hã&â¶ÛH9Xýœ(7¶*l}ß#ŠÛšì_÷øît¦à〈ÃDçwqûå O}3¾–Ÿ²=x¢¶î²b…÷<¢Äˆ(0L˜ß¥ :ã‹ÛzoÏsK±,4}I’Çö™ëõ¾G”Ä"YDq72¦%ˆ( D&Ÿ€ÉÜ9p‘†â¶ÞÛ;S÷‚tÖ›žµx'^§÷[;‚ä+ 5¢°™çDlØÇm­,\ß8–Ø%ߦ%=h‰ÄkÚ¶9÷«ZëۻʫkÏ95ÁY~·´~uÅ!mCç5Go”6vM65áFçY§e6w—ÄfiAqei[7-)*©ÌÏYÌ<eEÏÔ/ugz~I}M۫ꆖüœË©Iá|é&¾]U;³“Úº«´2_ߢRZÒÜÑ)ˆ¤…â‚§¯HICK‰¶´Žõäù.Þ)®ëhdþ¢êógÒ¢Ô2ýADaBDQ‘:"Š¡õrÚY/½9O×hbcçk²\W—+_g¨Eh¿™n½w:œ–Ìì™jU^´‚–Dä7Ð’3f¶Ó÷TwÈ‚«¹ó˽ Ƴ»¥…$¢¬Èobï]!¢HüWÐýTeXŠ…¶öYùø3ž²ˆb`½±K¡2qëäšRR‹Ÿµ0éµ‹ØˆÇ´Û ¶ÎB R¢oGWå&’UëØƒMÒÆ”×Üѵ~jŸÜj5J%¹€é寓u\¼w–’ÕŠ’µtUìt°…ù³˜ö*Ta7ƒù6÷ÖÎ>_K‰—,¨l}UQv„¬æ53ÝkC1§¼-D©#¢øí/£½ç£“È꺲vº:˺w®×P# _ßôa3žP]yŒ–|Ñ"›BÖð´‚¾6Ó¥C7uõ×Ȳ®$¸ì™tD¢³ûĶõQ‘‰ó7¤×w0ýû掑²K™Ñ=4·3°¼¢êÚíâñ‰|DÑ7¸-½£ÚºÛž ûxz'z‰û›è%>PÖAKî]8˜0=.qÑÆ;ͲÇ|<žçqZX »‰§5Yµ¿EW‰KÉž¤Ä<(›®žfZò|ÃK²ÜÔV??iºo@ÈÔO7ÒÁœúÆ[ìu¥ˆBEÙýytuNqYm|ZEû=N ˜nDÉõÜö§¿ˆ"°œ×¤'+–'ðQÔIõˆzéë¸Ï÷³«–a)ùçV.›~™Ù§Ð>04íWÓÒ®Z:%&_}ŽÉÛSCD_–~¿•ô¹í0÷ígßÚÝ{_C(Dâíff·/M Äz¦1ô¥T"í£‡˜™èˆ¼›¥# ÷NGÊîëŠèÞ®o c÷à¶è&-¼{$„–ÐUbÿlY Oî\”kË£KcFãÓÊ0[ó>f°ˆ"rÜNW+ŠèèÉn%tL¥²¦êyCX@ëÐ÷ŠÐÜz²ü8—ù3‹ó˜·ˆ€ã•-Ò”ÅÜ‹¾)½m]ÃM'&Òî+vmÝsˆ0’M µ¥ˆB{Kì7‘7[¾¬)cú´«–ßH–3c\¹7ìOEhÇôZÊ‹—ÒUDõRDIÌûçÄ)Atõ]EK'7nD±ò:’xá¦të{QDŽ›h·»ìÞrZ¢gEKêêóÙ¡ÈaDëiù´Â{K³ñÉ“ÂÔ¥™ãŒ\Ó­»½mHåO¥_4ãå†>´ ¤½üªò½´„Öihº/GlDihMÓ*+بð`(ÎKîÓÕÓÒÖÖŠÎiêÈ _Lß*3û?QËŒ-À ÛÒk m*g;p´_z[ªôQá½»âc"̤“Ä`ÔŒRDáéŠhGÁAd¤k<™,\»–ütœÙzHúó¡ÒÙíF‰‡.V´tÕ5µ^Í:5ÅÙ’îNÀðñœy"·ô|œ»|DqH>A–Ÿ³vÏ`»u ×y}#Š®Ø{íÑœ¢ºŽÆ¶Î‚/òçE{ó˜“}Ó˜Û.ä1³Òã[¤çÑŠô™¯Ko´t‘^Ž›ØØÀ&rÿ¥ûÅuµ M×ó/'L`3 )¢Lˆ»•”ÝlmïjÑ7¢ØLÙyâ—‰—ÿ'fÿCg7/ë‰wÏçJ7¹Åå~½ ž,[ùf%]ªd÷6p‡ig¢Ó“˜ýÛÈÝyNî¤Ä>éYÌÒ…“öuOÛ±€(öqy‰ç뜃bÓ—|íOÑ/ÉEwï¥%ÓÎÿ)áÂ/CWìkëìòÙÏc×Ì$›ÆzL¹þf¼·YvZÒ=}×böQ `Ä#JàIæ‹¢(ëðŠu[¨"é-b޵l,b…:9Kýüޝ¬A#ŠÏ^æeïTìCÙ }Œ™ìv…9ijk6{4u¾nzÖ*9‘E^ÝöFVô|zöË¡}Ôì¢ét5¹íþ²6€Q0jE‘Ëœh»ÁÑÒÈíYX`3¶¸­û‹=“ùú–µ¯ëï:z’p:>÷â¹ã—™óUZžxH/9J#ÊÕú—Í]òEì¶ ¢½»¶æ¦‹ØX×hbì§ç[¤ß‰†Dóä#Šžd1óeðãÛyûOçÔtt“ÊŠqvÚ†ÎäÞZŠIe³‰—hd®µ¹®$´¥g®ÈѪç¤rFÚ±mÏ“ûjjk¤§Þ~ä†Qü<}ü÷ÿ&zÅ| ¹ˆbé<#>çOÞ“‚-lþö+ѾßÙÝïe—ÈÝ*î½÷Þ{ïÝÆôŽÁ Œ{/²ÜecŒ ›ž@¡›BÉ&¼¼÷öìÛïÛ¼Ý I6m7 ¼ÍwG# Y# ašdþœßáŒî\ÍŒd|ÿº÷Îxy®¾œ=8AVå¾òw[7+ê¼ÿ’-¤†‡9­ü$£n•dk êXylÉ}éÏ^!v~¾eÿ™Åï°E”ܱ/}£ã-¦zÙÆôfO~âæîmAõ¢ôäŒþ–ÚìtDqÈ9•3rÐÑÍËÒ51j軄Ei6Á»r¶S«².çnÿGòât²8ümLd„ä¨xÄEÏd×ô¹v·P¿ù¬9Eb@4Ûäè¾U›ŽQç 9aMü·“…“Ç DMÿG¶Ò5—¦f¢R½(šlGº}òývº„®sêýNé½H"ÊÅko^Ò@¯:sj\_ôíí¾ŵp?ýp`úd´JQv"Û43 ¢”y8ÕD¬ §¾Ë8y´šòOS_‹4GTÓ«Jf†]3÷˜Üõu}/8'îä![ËŸyMgx|ž\D±Œ‘ü¥ÿí2_·¢ý$féóŠŽ^}ÿp¹õR~𷙤ŽoKö´SËDöèiòðå¢@ÖtD™(ÍÒ5bèˆòVÇšßN}rþòéx{ñ7ÇÓ½ÖÑ%ÅУ“j0 ŸžEµŽ,'ËtS,ÌÄØ¿ëØÔ¥#¤-²#ÍÝØgˆ¾Ù©Év¸$š>î箩ÃqY]]Yß–h.ž ü,{Јbé²$óÅï½ÉÂtD±O¿”ÕµI\Í>0÷•»vna£?„úØ%O¥–ä¾ø?d•ÿàߢÃä78[§g4m ëX:gå¿òwk;WQ²kéBQR G2_º—C—0#JÀð·q±â—fy8gd›¥CTîËßÛØ»zvþ52ùpV_…­gæK·Ü¥j66¢z4ÓæÙœ›ÚEõš[D h¦.;~å&9O-Ø<]“RrñÊå=¢hôâZñe‚=·ˆç¢¼Z-yºëJñ\”½}âË‚Ñg‹(»ê© *Ë^¡†zÛ–ûIêÜ7¢ðœè‡Ç6K†·Ý›‹rj˜.ÑæÐé:öµÁÝMÔ#zçYIÉ…§èŽÓºK*sºó–ÂÔVª7‰Šº|à xrE×8Žü™?üjvú[OŸ"%]ÇÏ_>eý)ˆ¡F“ÓßË–9ˆÛFžÔÀ­£ûòYÓ%púûZ:¢\}_{îünÉLÖÙ"Šëzê ×WËÅ—Óâx^µÃȲçfª¥Õh_rôê‘7ò‡Ï~üÎDªwÍaR¸Õj 5ì7•N½TÐÑœîNoä÷ …,8.>—=ð²$¢8oø,wâiÿ)áììá\ôyʪl÷æ/‚¢ÆþîíáŸþâO3ÃÀlu\+ÿ²&GR-ûåÿ#$%£n%]B"JÞK^óaζ=–¢fD! ñ  ë[{wçN% ¡Û¿ö ˆŸøÞÎ%5÷…ÿ°òlÊ{Kúx´%n•Û‰ÁDW™Um¢“Ä ;êrºs‹(ÆÞT''íôÉ~ºð ©~›…ÖâÎrF§ï1rý† ²$>.sÙ¦³ÓWôJµW£Ÿ5[D¡/:¬oµî{9ÿÁ §é.ÊûF–®¡`zêÈžm-é)©™+6¿):剾<ñ[ˆ:©&m>v¤Ä6C¥.QÓ`VÓÕ8ö⋟|ogvr’·_XH¢®â)79Ó¯·'QˆÁ³¿;sztäÜLJ^Ì`Q0v’?ü›¶Ÿ!ÿ‰²QJ%ŃêÊ8¶k:¢8rÅÍ—éˆòéð>ª1Q(¾÷¬E4&DrÕc-Žû%Q{ˆzŠCÕ%êD G¯Üœ\â“üÆ…Ó§–úðâÕ«Æ¢"šúÖQy›‡^Ot‹·‹×o{‹¯öó,›CD±°õŒÚö}lþZ:¢8ä]Íh”LçðtZD¬ý'³‡ø1ã?:8º¹Õü1)w gÇk2œ­Õ‹ÒXH×±tJ%{±¶§zQÒk–Ó…$¢$/˰°ó‰ÿGtjµ)FD þ..fº%üœí;È‚ság)k*svì!Ë1ãÿ(ø(­|±ô!)ð#Цž%=Óãâµ%ç‚¶‰=T×ÄÜ"Š&ÛQr«“ý#‰taþô R¦.’¾2¸CnÛ™™Ó6DÇöióÊIºPqD!R‡OÑ%oñŨ÷(:¶}î® âL"íéû¢Ðèoh^¢£’Ë£YÓ5¹kwˆCÆ®ž’­ÀãöD#JØÐIÒ|¹xý³É…Þ,ª U@þöŸ»ö™äÞÏôü×=­éôÃÌê c:WÈ(o÷§é[L]ÿìü‡gèù!³E#êbD'÷уÝí2¨)+ï¿»•E5ûÌxsêu£‰B{ §{Iû4ß?LÝ-Nß² dsí꥾TM}ËÑ0˜W¦£Î³lN…¤‹¦Ü—¾¤#Š•ÛÆœþ?ïPj;®‹el§êØe¿ø×œñ÷,¨ÉôÇrÇþNOUŸa–:VžÕ¹/~ábaçíSòY–@`!š‹"Qèéò¶1/çî¼jcïÆŒ(¹gr¶íwpñ°t‰‹ü6q)5óÄÚoGÞ ·2ê©)1î Ê™ø)"(Xö¨fñ#Љ¿¸‹ãøÁ æZ«UôÚsçßÔœkD!ÖOO2F‹¯”å^*Î_ îo(ÍÄ/³nàåý§.O]ûôøé³£Ã}É!3®¯E?ñ¾E×8~ú¾ïŸ¤‰îî¢LD¡žh¸®qÛk‡ÏŸùðæ™ó—_}éÞÝå%¸ŽÕôÏN½N—hê™Ó»#¢¤ß =“ØåUÂW>wmêÚÍ3?ÜõÆ+Å+3$5€'à‰FÓÀaºMPd/ê'Ñ5¦o‹¶$™® k’tHT²sd¸küÐ%êžqǽ¥¦ËËDú:<™cT?Ì[|ªgf¶ˆBöÕy˜šsrø›{wžM—/š¾6×âýTcèâµßð¸Žâî/­RÂIRùêA{Çæúî×ÎQ‡±Áã^ é™5·ˆBxTü·äŠ^É=)ƒÊžø:µý€«hþ:4ü]f5¥ÄÒeYþk?‡1·9[§Œm©CΞøkrÓ½+z1# ÚÿMÒª\fD±°õô)<’>úUÖŽ?Æ5ZÙ‰öhýòÿÅÇG‘e»¸“ù¯üh+º:™2aDx<ш¢Íõ9/ºÖ§åôJJEwÅ„8Jêzçó{ðä¥O§.}øâÄ ÌE‡åF=³Ì³×>##ÁÒlÖˆ¢ÃÑ1ò/ïyåÝ©.|øÑÛo¾¶"•ê¡9.¦î|GßA‹íFO®]>}ñV›ØõÂ׎¼é“‹W?9xðí²Åâ+&=ã”(Ï8D€òD# Ì'ˆ(JBDx ˆ(0Gˆ(JBDx ˆ(0Gˆ(JBDx ˆ(0Gˆ(JBDx ˆ(0Gˆ(JBDx ˆ(0Gn^A¶NžÌ9H#oy£˜ïÌæÈÜÖ‰4¾™rFÞ"òF1ß=˜ " Ìi;ºù1Ûå@#oºP" Ì>×”4Á1⋉ßE·ˆù¾€‹‹QàaÐ#¾|ƒ"Aã»æ ½( BQÔŠžiXîÆÊ¶!¾p¼…ß·fÕ2K®!½*£c{¡­lý9aÛVtÊ™å*D×$·¬³cp‡GüòŸMûîá.<#²\À]çaìó,b[›Ó˜å>•-ýcËí-|ªÛÚ3+<äÕ1 ž9€ò%ÉÆFÎ1e$Þ4Öo´µ´4u‰#/y‰½¥Ìö*šªWÙÛ:[»Åö¶µ-aÝ/¢ج êèRË‹ù£ÂÉ\s²l›ÝÞÚº,õµµVzº¹™9úåW [›×QÛE”¦ê`ocž¡$¢øæ7ttV[‹fÚÈíEÑ5‰!¹nYZŒ¥¥“gä2²œîjuŸcÐ5ÚÒ7¾!3ÎÌÜÖÞ?“?4g6ãÃT" €zṆe.)ªkì' ʆ†úÄ/z‰(5…âïŵ CÈZž>—m_Ø5Ðo8=ºÉÈ·¬«¿GSÔfmiHe‰Ú÷[—ä„£=®žùBÁ PO+QÈv§gä»—÷W­}[¿ŒßT“.>$=Óªþqùec½¬ ¢ÈÝ~^çhy†]Èq pv²Ù¸LDéìÞª%j—Ïözé,D÷Æhê[’fŠÚîDvÇö¢PG™í»D¥xM7߹Λ;»+©'*Œ(šz­ÂÉ(SM[¾p{ÐæÍyÔ&®edSŠ›¦#‰I6âT©Í èš 31¡ãÇJ_ñ=:¢8¥Tt ô:‰ÈÉ(Ž+ºZ›Iö·¹6é>Ç oC¶“è ~3í½‚éž DPˆ(êIרÊ=<}M#iVf{X³DEÒÔÖæúÐÅ2±¹­}¹äY:†¡¤Üžk¨oQ@Á¤YŸÖ¾=ׯ¼¤w,ÕÂÔ2©¹¥ Ò¥«_ yºËÆ^:BD6o«Èº7Þ,¹mDnD)ŽßFAD‘»}‹è¤A¿µrkvv®»³Ì–é'JG”æ†Xzy¶×KÕïk—ë‘B_#cúaJ»œˆÂÒ5t ŒOÌ^±dý–êÞqe" ‘Ð2Rãl`µ²½c…±U[k>ÙWãàD´™‰žYv÷Єôˆ5òž¯q¶¢ãG°‰ø`HDéêïæ÷u‘Êa–âû~Ê(ÍÛ¶,§Sº¼S°Eñ1PÏZßA¢ZqqIrr’¹ì'?" ¨ˆ'Q ‚«ŒŸ6+þ¬ôK€ù©ø òKN~Õ™¿ÿI×$yéêU2…ñMÛ¶„²fN—ŸQ–I*Ó½+T¯…® i¶†™Y·RÓü*IÆk.³’Ž(÷ZöR"¶uD:¢$ÎQ$Ç#QÌ"$Eîö =K¯Ð¤‚¥EõíÂÉõ¹2—‰([©w€%Ž(r^ïƒF”ÔŠþ¶æº´ôL¿€`{÷ %#ŠUrssm¢Mf[ÕJ_£HÁà×,D™¥¸gl­«5?< Å&tDñ¶0 ßÔßÚ(þY+Q¼«;»·*>º¦™khlÖʵ•]áH’«•d ,DPO.¢h™zSá„Ùž˜§È/<ùµgž s¦cC‘þ¦3NØøæm5ë¨ér# ÇaC×@ozŽ»‘w yH·V#†+Ò ;ºJXT·F]KSFUÿx 1Õp¿oDqYßÝTM£è™TöÉè%Q¬¦ïaâYØ£0¢pÓr—zL·Úªù=õ2Ÿ-¢Ìöz(¢hóI7Q$ xn[”Œ(zf™]ýüè¦mËœIÓŸ»¥o-Ü€cfëŸÕ28©0¢p–òGk ¬­m¬©«ª{wtõo+)šqÑa¹…Ô/ï/Íð’QÓ€ìâ†~¾p¼yú¢Ã÷=«ˆ%å­Â.áxS»`i^†ÞÌ«9#¢€ŠxB](ðÌzä)ª€íJÍZ¡­ï[l/{Ñ-¹´ØzÓ£°@Õ ¢€ŠxBóãáÙUüóŒPw§]ýw;kM=c—ØÂ®þ£é©ð ¾Q@E<©ˆÂl·<3˜gÄ<à™²fkÛ`gÿöªêª0wêªÇ îQ@E ¢ë!Ù×}÷õw˜å~£?ÜøòÎÕ ßØVý•M™l¹˜gÌFÕ#ÊÒk·o}s›ÿŠ{…O+¢´ÿéÎù·¿±­øóŒ€Ù¨tD1/»õ»oï{á›?ýp÷M!•Ih5¢Xn¹5[DÙþgñ~Qà0ϘJG׎¿ùñnRå—M¼óûÏïõRQ\ÛüúûÛv¢ðàÕûw$vvÜ"Ëå·þüÃ]a+µ¼üí¯þùέïï|ôÿ(ê¡JÌDñc¼ý뱫?ý×ÿûtD‰zñÇ/¿½½ºåVûnßúñîWßÞ¹2s —}Ãß^ýøŸúö¼½ûèwöe÷?ë­_|ðÓ~uç‹[·œûÁe“ì ‡y†yFÀlT:¢,¾rûOÿûY{ù§¯¿¿ã]..WQ,Ê¿ú⇻ T$ȘºýÕ·w¯ÿ†,;5ý@¶àºéËàþþÕw·ëv|ÔúuűŸÈrüê‰$¢|ú·{_ù[DÓ½^ÿ‘þüÝÍÝ÷b ½_ID1ßtëð­;}ð}RÇW‰ÂoÏ}}÷Ò±oî{ ›>»ýŸŸþßúU(ÿoÇ¿¾sjÏ×Ò/ææ³Q݈b^vëú·wÏ좚ï¶ÕT$x­_<ÖKAD!:ÿtçôëÔ³H¢xíµŸþôrbÞþçÿø=Y˜øË îE‚ý·îœ|Y\ùƇâMÑŽç»ÿùþnÿȽf̈âÖù# 9>ÓÙÉoÛß¿úö¶ÅýŽaÇŸï\ØO…­ç›,8Á|Å<#`6ªQ\Û 1 ¤õ+·ê[Äñ¯ïüçÍoéUŠ#Jì¾þá÷ßY”ßúßîÖý„ §M_VýÏ3oP™á?ÜÝÞr/,þìöÍkTZ YâÄ â4B"Ê7?ÞýôÛ;7¾»ûž(#ј%r÷Ot?ŽRÉ•÷9†ð—ÿþ×ï^»ùm¿Ïï¾`¾bž0Õ(‹?¼MšûÒ¾þþ¶›¨¿BqDqløþ«oo»6ýðÅ_~$Ïs·­ñÖÍïî–×QÉD&¢,ºqûæuj $~Þ6#¢ M~úò?¾úîvÔfqåûFQyZå}ŽplúºìÍï_½òÓ?Ü=ü®¸Gæ+æ³QÕˆRvëê·w?8r¯íNbiý¿ÐC%Å…<—„wÿùñEêéë?¿}ùзþöO ÑÚÉ¿Ü9¿ï^ÇÈÞ/ïœzM<"K:¢ˆ§Ë—ÝÚý—;¿;'Þ3¢¸ñ©^^Ó½|‡©‰.Ve÷9†žw(¨?Åôýú'ÉñÀ¼Ä<#`6*Q\Ú¨Q^«jfLÒxóË;ŸBõºOD)ý²ü¿ï|ýÝÝ·DsWB^ø‰,K‰…¼DuŒTmÿÆ¿éëÒ÷¨éò‰ÓÓååD”Ò/Ý»øæÇ»Dsß™Å|Ó­ã·î\½ð}\ëW±ßžºuç’hf¼âcxõ/wn|ð}lëW¾-_w]½ý‡ßST`cž0( /ßþÓÿRC¤¤Åîû'IN›îQH$ "w+µLw¿¼#5ë}õ¾¯ýåÎWßßùÝç3.:,7¢Í7oÿá¿©Ñ\̈B–ÿöú'ÿüÓww¿¸uûÍcÔE‡ï{ Îíß¾óù?ÿò=uâãHªžqð0ÿ0ϘŠF€ù„yFÀlQ;æ³ÑØX\ŒˆðX1Ϙ zQ;æ³ADxì˜gÌà±cžÉÄÒÞÁÍÇÝ7@Å‘F iº0Û3 ¢ñÉ‹LͳçÊj±c3câ#Èr`r® ψùDx*”lÌ<éˆs¦ÌY•P^ÛÖ=¼“ Á‘ Ì:Š‘ˆäÊ6´¦¥ÃÑ·ñ´µ1cIEÈØÄ(æž¹…ç‘ë«­Çc!¢¨e3,D5¢ø¬6à™Óᤢ¶mñª"¢Bô’UÌú³!%Ìß–Y.1·ˆ¢¥ÏeÎ.<äFCß{«I iíÙæH p’ I!I)Ìú³™-¢d"=ÐKÇ0,&%/>-/&9GW—Ê vÞ‘¡q™±ÉYÁ!aFQrÐ5‰OË×ã9ùG¥»ZI6¥©g›–ï JšúÖ¤N˜¯xÎñÙ!žÖdÁÌ544>+.5',2ÆÊÔ˜^KâG¨·¥wTdrK*¢hºD¤äºÙ[rÝbSóâSs£âfôÒ5qô‹LÊ!‡Â3à)s Ô‹4° ‰Ï!O1N—~‹BSòœE{q‰Ïñ2uôÍ&oKT\²ƒ¨Ó‰0rôŽÍˆM͉ˆ‰·³2•Þ2À3EqcF@m(8«ƒ£º‡wÊä)$«Hæ*¹D½\ Í%ôD 2…5³ÅÜ?5:&ÒÔÌRßÈÊÞ7)6)N”[¨ˆâkei«o@¼’ 1 ÈÙ’,èš„“DD•ëŤæ9ñŒ ì¢âR2ì¬í ­l¼ããRÒy¢c %&&ÅßÛ“gDõ ÑE‹c’œëí,Î r{Q¬‚ÓcâbÈá±MìÜ#2£cCï{ ÒGK"J\rrXXˆ±©•¶.GAD‰Mʲ·¶Ñ10±ôLˆKI#…Z÷¸´\{[}®¹¹k,y-ÊôÃÌK 3ÒQÔ†‚³º¢¶­bö®²JùŽætù@{*(ˆ(šº¦±©y6÷Æ\ñÂSò<ŒŒéˆâ#¯ß€š1ãÉ%Š0ŸøTª+F›ë—šIZðî 9Áî’^®obn ƒ]96)F2ŒŠD#»€ÄœP/'É–™ESÏ<6-ßÑPœ:´ ìãÒòm8†ŠA²A–(¢b<²D”ð Ç齨‘§èëq©x“’A¨r]cKDxV)hÌHCDP Îêîá‹W1Ëid©À,—KÉ^,©ˆ¢Åq#Íñ˜¤ìèi$ø[™ÑÅŠô5“6Ï/.%]SÔ•áfh”œëÄ3â8'Ò™!:5Ïm:Q¦™!Ô®I–ˆŠq•”“ˆ™˜‘~ïâÎ̈¢ÍõŽOË“dw¾¦&ŠAš(fP]"4%ÐN<íGSߊŽ(,]SßØì¸¤t_ÿ;{'=:«<“4f¤!¢¨ gõ}#JkÏ6f¹\s‰(l'Ò7`6¾EÅtæ¯i†$`XsM¢SsÉÍ#2ƒ]-mb²èÞÙˆž*Ž(‘ân –(¢„øºis]cÓòLîÍWaD™ˆ˜”ëgf¢ø¤‘ˆ›|o¤œLD —Š(Öâù'÷" õÐÐÈÚÕÙ;,(6;61™´ð RИ‘†ˆ 6œÕЇr‘µ+ê™årÍ!¢°tx‘)y®Ó!ASÏ,0"¥(¢plc²B\Cc©ù3¶ñѱ^a)y–lªËÅ#!'ØíÞôzŸÄÜ Gñ@/™ˆBO—7÷O‹IˆÔ2#Цžy\Z¾ÃtæÑÔ·%mE}; ŽA3¢„ÙMo͆¼FEÏÒËÑ•zßDxI¹þrF¾< 4f¤!¢¨ gõ£.¯|D‰KNÒÖ¥ˆ±wrlR¢……µÏÒ1(-&6œz–ˆÂvHˆKÉ‹¡6%*–K¶6½*:.%ÝÖÊVŸgií'=]^nDÑÔ·ŒHÉóž¯Âœ.o’mbja`lã.ž.¯ø¤ÉDŽKblR¼‘¡‰6ÇÂ9$ã>Å,,.5ËÖÊFcjh퓚çðˆ¯ƒ  64f¤!¢¨ Åg5uÑányîÞF0ëÏFùˆ¢e`’'šeÎÒ1´_t838$ÄŽ% # =ƒÅÏ’îRà†§äE†Ý›õnîFm<7|æE‡åF‚ãL’LªWnDÑÔ5uòLÎKÉ]tX™c‰(šzfî!IÑÔ5—óƒý¼<rD²Yk¯ÈˆÄòFEÄ&:9Š»_žAŠ3ˆ(jCñYmÀ3—Ü«qÑÊ}'ÇÖžmäòùxH:lô‡<Å Dµ¡ÌY•@’L6VÔÓã»è+z!¥ÀÓ¥Lc†…ˆ F”<«åBJ€§NÉÆ " €ÚPò¬žÍ]zà‘S²1£¢%8*¡µ›@O#ËÊ_`¾Rò¬PMJ6fT4¢ÐÃè“3 hdù.I¤€®™öúêzÁH—p¬±¹-7-Fkú†nƒ‚Á!ÎÌ»ªqœ IFjª cnJ"¤i¸,ñÞ¯%ÏjÕ¤dcFE# I$™H’eR¬ö ´y~[ûÆ·n\híì·¸v`¢4/€^K"J×Ðdó½Æ^%}á$" ¨%ÏjÕ¤dcæÙŠ(!Í5K$Ý&„IP…`pÈPÔsB"JñÊîú2©ÛJèné_ºyTƒ›¡9³@õ‘f iÌ0Ë™ž¡ˆ¢©oÛ94™aKÝZº02>ÝšCÝýD”Ån]ýé £o‘ßÙSç¼®[Qc—–7v Ç›;º—ä%kŠ %EÓÀ~EóÈ–U)Te=Óè‚M[Zù½C›Š78›ˆï=0g&–öÖnÌrÕGš1¤1Ã,gR݈²±¢.9k,?ü•ˆôÍ‘ÍÒ&r‘ˆ’ke¶®{GºøþÐKùU«ý%EÇ(ªkh"9ÔßÄÌÎÎ7¹ep2Ó’ªIGM=‹¼ê¡Úâ|mQÂñ]-hm,õtu3±õˆ]ÞÖÙ]'3Ë`Ü|L,”:·TiÀ(Ù…Bhl,.VÁˆB]ÑKtKlñ½zÁ½Ø6%ÝC;˜åtDq\Ư^#ž²F°#ÍÚLQ´yÁáÑ÷†­ìXëBM\¡"J’grI_kó:}=*‡hêÛt'ÃͦßX]ãêþ‰…v3:pæ@—cBNok7Œøµ@-¤éB0¤Ã\+—Šö¢ÐÉø. }‹¥dk¡ýb×/‚R‚¨ûhbö¼:CDµ†ˆ¢6ž×20·°¤çŸ<’ñ]L :l¨Þ@vaffÎÒÁ•ˆÕ" ¨5Dµ¡­«?22òÖÞ·¨ùñŒtñ¨pÊ8ûì …ÔýRÇjÔ"ŠzX EÝŸñçŸÖ7ÓŸûõ»”ñ_l+6Ù‘÷žWSˆ( Ö”(‹‹Qž"6÷Ýwßíî§îÂÌkkxtøÀl6y$ úQ@­)QЋò=¯m°`Á‚ŸþÙ6ÂöÁî*»ð3ÌIDATÏ87×°‹¶#»{î¹çž×ÆýÕ" ¨5õŽ(ÁQ ­ÝÛº‡wÒÈ2)aVSw¿^ •››ûÎ;ïh'kËÆ ¹>ÑÐàkhÄihXkh<¯¡ñï–+54>eÔœ…v¼öáÇ333É®™Ç*ÔšzG”Öžm+ê“3 hd™¤fµÒ4,‰=¿¤¼¼ÄÝLÑËw\ÕÕP¡Ô[9ºzúûöí+X] 1.›%äKÓÿïÿÑÐx—QYžÛþoK×/ݳgž>®ë¥~Q@­©wD!ù$ÉC²LJ˜Õ‰(õ›Ìmœiv‘«;FÛ;Š™5%kDáò¨‰òÏë?¯ñ¥l–Ž(V«54Ê44ܤR OCã.£>Óÿjhr5ïÞ½khhÈ<Pqˆ( ÖQä ¥vc€t ϵ‚lÙ|öéã/¢,ÐÔ722ºqã'Bék ·jh•zø R)åcF}yØ¡ìÏ?ÿœÇãáº^jG}#ÊþË7.}ô&V2åV¡eo¿|áÚ§¾®ÎY»I½=Ȩ́(/µ}»ôˆ ÚW'fÍ9±â3 Ÿ&„å% ½ƒí=Cåå!ž’WJUöSW–±‡Y¨l¤¾íÝý«ç=¦±Ù…¿•­l¹*YØ9J2ÞÞž¹JÖÓþ¡+QêêêŸåˆÂ¶-êšàêsÉ2×-qÍ–¶æ¾±Æ¶ö¬$ñÛ'QäV`éšD-ÚTÓ5Ò58Z×Ô”îF—s\VWñ[ûÇš;ùiaâÊz¦Ñ›¶´ò{‡r2ÓüýüNœ8¡¡ÜD¹Æ¥"ÊïkåÑÕ>}ú´··÷oX:Òo¨¾¹E”0þqÒô—8sv’.YÞøÛ½ïŸúðwï¼½ke²?ó‰Ðl%wÿeRþVg¦ƒ=" <$¢Ô•¤Ú»øH³4•ýü™µÝu%‘Ìò§Å*´H0´#'5ÁÁÙÃÞ#$iyƒ`pÈÏšjL›º”wtoa>EÚ’®ÑõÎÌrÕG"JW¿@üóuõó‹[Ú&œ,Ëz<ËT>¢ð,#Ã;'¶.¿;á©ÿÐÕ>¢l¬¨KÎZD#Ë­=f.ŠTDᘺfV ëŠÓÈCÃæÁ‰üä( K{G¿”-}ã«bœYRe¶ ¦!•ü¾6W7#sGŸÄ2p;xtH… ™qfæ¶öþ™ü¡É8ÑŒßÕ‚ÖÆROW7[×Ð\òïÕW_e<Äå†Ë§ó [CÉk‚±òY¯¿þ:fÌ«£¹E”åï^9ùäo_ÛKo&…É’Ξ;Ò=0¹ïÒ§¯^[èñ¨¾b”c¶ˆRtô*)_ïFí Qª×†1ËçF¦ÏDÕ"Jl󶆊8éÒݲ(ˆý D~_‡t‰ÿæ¶Ö…3«Y+ѯrÿ.•(ÉÍü¾v÷¥]Ý5̵2à‡nâ([ò(¨wD¡®èÕ#uE¯žGsE/™éòDGg¥±5ÊË~Qgs]ª¤¦ELc{ç–TD™­Ï+.8ÈŽ.Ôâx’m:p 5õmÈB¢ƒ]nïlË£ ;„“áÓ³óÿý7Zååå===¿ªø3H(å„h¢<ýocí,~Uþ«ÞÞÞÒÒ²ÿ5Kòr@-Ì-¢Lžÿäàd–Lá†#T6XèJ}úXøm%ˇßX#]Á:x?°,;,"˯]§3Æ.i®ßô#ÖÆv +…»Ž0uõ“÷Þ;ܸi9OôÇÀ>þURŸ0=¯~dÏñCl©ˆÂ1óé?~ýâõ›3ü[O]—ôíŒÄûÈDÿ‚ªÉ·OŸ¾òé‰3g†º\,¬¹AS×?;ù,WTá•‹Ÿ’ú[¼\Èræ›ɲ ÒSú%Ȇ©K)yxòx#½Ö1õuÉîÄ5‡sÖöìzÿÒ§ÇOœl,Ê «™ºeuî3ÖWu´ô5µwæeˆ+¸-ëª^YÖÕM "XY@}V¸¯êèN „cM-k™Û*âZGšëI7²Í¼BÝÜL]JÚû'º‡'ÚûFÉg/Ï2hQissß¿o[UUe¨èÿ u¨kxgWÿŽÍË‚Í=ªÛ»Š% jÞœÀ¦¾žZXÜÜÔ³£½{°hÝJSÙxZäF”æº6•ÍJH Í6rUeçhªƒ½Ü×NätŽ®ð‰ÙØ:Ò=<ÙÔÖ™:ýÄØ1veEkSßXKg×ÂŒhªPQB½‹øÂ5uÕvvÌCzŠò:Fk‹£—’㌲½wlv%µ‚öÁ±ú††Ø@7öÌ:yhš_Ú8Ð)onëÈN ¥Ÿå¾J°uYpØÒ-}£Ì}=<õŽ(´G5¾KBfº¼½gd¡`GÕª ²Ê¯aX0¸½µg„ÖÖ;ÎïmfIE”Ù*Æ®aÑi‹óW•–6Ð…F¬ï·—$''Ù˜Sï°®I"YÛ6½…ø”̇Š(¯kh<7Oªkg‡ˆ¢¾æQ8fÞ®vø…‰=ï_>söÜØ`“›… )ï9ó;Ò(·6£"Ï"”,Ÿ;¿Wú‰\s¿³×?›ºt„,ÛǾ@‰Õ®N†¶©dáô©!RžÔùY>{öpwÿø[¢ÀðR]*U_Ôâ?õÞ1ªæÔ{lID1µ^7v–,K’H¡_j>ÿôGäaÇŠå!3z9¤ð/^ÿì╇„#“ïPiêøþnò7¸æ•j²í ­éCzqÕúøâõO=E/MBæ0îQÎðñÑýo¿tˆÚõõ›¹NdUï©ÈÃÑþþÁø‰«Ÿ]¸rÁ×rÆ^@ÕP½Š“m½¤ñŒ,­Ãkø}mtkžcâÔ48™íêhhÓ<8±8#ÉÞÉÓ#4»²bm’[QºúÇ×ç'[Y;¹D, üT­Å*´[S]mVVާ‡§tV‘îE Û2Ø\»ÞÍÕËÚÅ?¥¨¯­}].ùB}¶ˆ]-lª\íââaçUÒ3V–é'½÷§H4Ыkúçëí³¨upGª7õZHDá÷uVmÞàíãob<ëk'¥£w89<ÄÌÊ5lQK×@/‡úÅp)ë/_•çììé±°]8™MÞQDiâ×ùyz™Úùæ× 7×¥1éiáY†“ßq¼WБ(³P5³ ô"ÒZG¶äQgqPÅ@õÚ²Ò´M08ÚÖ3"Ö7ÁïmeÓÑ¥I<î”XݽCAD!Òóg´ÞæÐn{x–n!ñ KÛ„“[WRÓfÎE±ö OK]¸vùÆêšÞqå#Š}b)h²ºª&áb_oæNŸÖ —èed푼¡·½s+WQº¤¿´’ÿÚID)÷pÍ»EÅmEWkó½f½˜(¢„ÙLçŸfDa?½·"§c{SM¶™µáY+:TjÚL^çhY2Õ%(CòCm©\J ÷¢Y…Ô‘XÎE”–&jÈÓ#yó6¢<Ì]™…ë´E0(dQÓH¼ê&ЦX[ÚÚûg4 Ndº[³¤"Êl2Û¶o]–ÈæÛúænê#dn¢ÅñèN.O25·6w Y'ØQšF]éËuQ;¿§ÅßË‹|ú…/ÜjnnvãÆ n—$äûZC#l:Ÿhh\`TP'œƒ‹«©9D¢Žú⛦î©ë+Û›[ÛRÂcDMð^™Êæžõ¢F|ÆÑ+7_Xš¹ûâéÓë_¹xõš™ÕtD¹73¯UQ ¦#Ê>!5è‹FG”÷ßyù5xì=Gsª¯™={D¡úg¤"JxQv. ᘸ»róôÉrÇlpÉÝMÂUúæwÉÚJq„ÌaLG”&ú¡œˆ2]S:¢pL]–ljÙ}Tô.^¿¹)Ä]fG RD»¸†vþ¶±mÍÀD‚èò¬µC5ò*“ˆÒ\oú}# [ê;æ¹µÛæÂØ~Õ† IwÍ9«ßK}#Q²¶ ´µ4få䇄G»ùo½oD mÞFGÂØ)(*cÙŠÒ¦ö¡É‹¨\'ã)¼pFDaS_ÉÅ“cµ±¥zõR†¡ÍöÚID)Ï?‘D÷Õ‚–fÆ ®™Óåg‹(ì§ñVð,ÃR™¶9WÜVšàÍ|Šä‡'Q‚êè7‡D”¦ê{³¶d<ükœ%:)“úqô.ì~ˆë3#Šž)µ‹LO*lp\ÖnikéklíȈW“¾è°Ü ¶q…õ½Û·V׆zÚåWtõr«ˆ%å­Â.áxS»`i^†žu]c–®qTÁ¦Ê6ag¯°¬h­!÷¯ý‹eÀÒø«lOúîòNq3eÔgúBC‹§uçηnT?sˆ(Á-ozªOô­!×"hßå¯êmiã_Ö\ÓÜ•ìHý…vL!ï=ü{ßÒ8ÆŽG®Üœú€ºfq‰»“׺}$6¼sùƉ#ÔG×"èbK}j›¸,LDQ5ºz{÷î]´f‘Æ#KÈ%Q˜ÿ”ôõo#ÿ¶¬pÙîÝ»õôÙÌã7‡ˆbé¿õÂõÏ.^½²cü¥×ORSäߤf z,‰j¯Ÿ924±ûøjx¬Ô5@$V ¦¯H`mfeáÕzI4äé•é?Ï)ª•öôA~÷蛨!d/7¤³-~¶Ô½Lœ–N‰æÁGŠ‚ÍlÅ1­û5íƒþþ¡±ýÔP«ãû©‰Œd•׺ýôaÔø¸pL\HL"Ëï¿{ï/«„Ìap̼߯×_~ñÐÔ%jYqD1²Í †œ]½ÚÛÕ]ÕÒÿú•”J\™ûÕ!wº¼µè3‡ÈíØÞÚ²}KxÐ&×"¸ap¢ti¶““»[X^Óàd®?uŽ+ˆ(M5i\SU¹l†sV`p(;5ÅÅÝÇÁ#((qY‹prM"ZHD!x#S[Ž©[ûÐä¢è`#s§€´Á(¿¯“î¦^Â-‰ñášZ;,éò5²t ÎÝJZVt/ÊŠ®uEË]Ü­œ3ÊZ–0ᩘ9]ÞËÑ;²`«°£«’CO—ŸŽ( ^»ÜˆÂ1ó$©¯ty¶ƒ£»KHy3Ó=ÅÓ啌(OXvûöÆÊ{m Ë€rr´$ª¹.ìÚ‘mc甹¥k ‡ ù¡Ù¥v M.ËL´sðô‰]Ù.œÌñO—WQÒ|ˆ(,QJ ŽJ ë¢ɼ‰(¿^ •}èÐ!íD妣räHzzú¯ŸÇ\yõ3‡ˆBøæ×L¾}âÄå½{˜_Wl&¾9‰UzQ×î#çÏ]¹¾ïÍWMÇ•á±òmÒ(?}r€M}‚ûÓ“IîÝ¤ÙØ~QÕО㗧®}zôèÆE‡åD²œ½ã Y~gŒºÆñl…X\³sÿÙ³Wnœ:{vXÐàj!fêRtI4àÊETÒt’êoyi]¸d_ÌÃpΪ|íðù©+¿ùòPlΛ÷(ÔSRK¶½qôÄŸ\¼úÉ¡wl^)ÛתFîtùš âO ‡Ôò0DtsCš¹OzaUGëÀXS?'%’.œ-¢X®iîom¥>ÁT„oÒÊ’úÞö‰®5 YÉT/[4| »`pÔÜÄÊ1auUÇpg¯pSy±·KDU÷ަ:ê"¾+:…“›E£}¢–V6vï oNkcELQQL\“ k{HöîÁ’ëܬU%›ÉL— Žm­,ór]¾eæ@¯Ù^»ÜˆB–MÜ’Öl¥.BÝØÊÏN lSՈ³ ï\8ó&'çÆÁÉrѵלb——5ôt ŒÖÔ×FŠâ{æÝ6¼ ´i€Ï¸è0"Ê\t?ž»:>Ïküæ7¿ùùçŸm#m5~’Þ÷vÑvdwÏ=÷ÜóÚèEQ?s‹(J2²va^Ê àš·å1ÝÕñi1àp<(² üÒÃèù5ÏŒìÛ·Í_øÔ " ¨µyQæ™ZúççŸ6°0Ðø½l¨x”>×àÚpÉŽôõõq-/5…ˆj Emèèê ½½ÿmÎ&Žl®xtØ%ìôõ÷ëè0Ô" ¨5Dõ¡m`aaùóÏ?V.è\ÀLoAë‚âºb² 33s–f¡¨+DPkˆ(jE[? DˆÀäÀ_îú%3c<Œ_¼ú‹ô²q__?M ñRcˆ( ÖQÔŒ®>»°p á«Ã±ë̤17$ŸD­"›]³f­®¾ìNA½ ¢€ZCDQ?†Æ¦•••$N¥-èx#¾´. ûO***ŒŒÍ˜{õ‚ˆj E-™’P±¡z§Œ£ñ_²©CYŸkpJ8ôü“5kÖ’ðÃܨDPkˆ(êJWŸã@¢ÅþûÙVlÖ:–Æß Dï5XkX\î;ß¡çŸ`|×¼ˆj Eijë›™™ …B’1†G‡í¢í´ãµ5¶khü/#H|¡¡1¢¡§M*Œ'ö÷`~ü|‚ˆj EÝèèê°8@òÆáÇ—®_ªÉÕd‡²µCµYù¬_•ÿŠ ä!'œ£ÅÓZV¸ìÈ‘#¤ò¾}ûôõõE÷?Áõ…çDPkÊF®¡"ŠÊZ ¥Ïæðž{î¹ÌÌÌ={öܽ{÷óÏ??}úô믿Þ+úGÈCRxçÎÝ»w§§§“Êl÷Ÿ—Q@­!¢ÌÏk³½@KO߀ghÈãñ¼½½Ib)--#ÈyÈ£þêé³ý¼©ÌÜ̈( ÖQæ§Zú¿aéÄòï¿fd3¢L•›ë:{þÂ+;·¥…ÜçµÀ3¥{xgrft yH ™5áqS²1ƒˆ 6”<«¥i™2ÓÈlÏKaFc×$º¥3Á…<4 Ü|îÚg¯ß|ãõ]¯¦¢ËÙ³{yÔ6gD]ÃÍo\¤Öž>6öò¾S×n’eaI8Y¥i`ûÂùOÈéóçví?væÚgTÍPY¥gšvü*U󽃇^ÞûþÅëÔªžo²JÇ0øµ Ô³Žîß7ùæ ²pñêÕ•Þ÷{ó^pTBk÷6E H5æsá1Q²1ƒˆ 6”<«¥)îB1±Ô±3‘°†×/Q-­ô‹k¨`sñúMÉ1x61Çw1)ñ¥gº¬m{ksšLù#‰(Z¢ïéžAJ6fQÔ†’gµ4éLb¼ÂY’X˜ù„ÆÜ‚„Ìtym¶EÐ’Q:6ø뙦ÑË2Ξ{•53¢D½vžYw" {¦D£ÅŽyotìµQDÑÔ3[^?z@4 L¼å³ÇJ²<ɪI©Bi!ÆÆÌWÏŽ‡Œ(ž‹ÚJ—wË(µãsÊÚ{Fkk¶8ñŒH¡¾MøšªÎÖžm[««|íÍI‰žy~[ûbú)zfÙô²YdCEv`nY[Ua€×sÉ¦Ž–î‘¦¶Žä`Ù žéjøÃ­=#5Õ•ž¦ô_4^Њ:ÁpumMlZÛæ\ê s¿*NÉÆŒÆÆâbDµ äY-M:~hryI)³åå"ʽ¹(:†ÁtØho©Íõ¦—ÃMäéˆØó>Y~÷åTf5«„q²êÜÔ._{êÍÃ_¢¢ˆ(¢ˆé™zDæl¨ëýäGdÕù˧µt8­§¨åmQÎÌ À³Œ9ód6Ìçr]ò«–p¶È(‚Áa_[sòW)¼¸osžK׸¤g,?Ò[K—gº’ßצ¯Ç-¢tòƒÝí5u8®E½›sBÉ×9§£»YzÚ¼~õ'•ë‘Ý^[H ýJ[êWóØ<ëðú *¢ÈÛ¯ÌѪ%3èEPJžÕÒ¤z™–º‘ˆB—ËÍ'¤2s r" /€Ž% ÎVäa‡(*Œ®_Õ1¥éÅ—wï6S×#–Ž(fÁýT9ÿ–£h&½MÊ »ö¿´k¿¿±±oêÚûš¢n“Â×.H"JÎÎý{Þ96´9†Þ¸‘gó%j˜ÙÇzÜQæ9ür…Žh.ŠmrÙïÎ{éY+ðÌ"ÙC™¹(̈¢Åv.éâ;ð 9³D”æº8ñr5èKÏ<¯³{«¤ÂŠ®éf³E”–ñì|çõݵ l,-d¶OÑ3ᙘ±¨?µÖÞmMµÔ<ϘæmËDp Ÿ-$¢Èݯì¦TŒ’Dµ¡äY-Mfº©HS4¯žÝsèYÜ—hGf‹(5ëÅsQèy)lÛÒ¶Ö{Ø=M +£ÌQŽNQgÛÿ:;ßøÉiÿ4¨nO1ïcƒM­=B§èÖ÷úrî¼³­¹‘ÈŠÝÜ?#ÿmËO¾”åÝ·¦FUyC‰1?µ/‰(ÛÎκ…ñêb¶fØÒTòQrëVÜÎ7*’^佮÷E’ÄlÞøT ÖJ•F2S0è#„`ß´ˆR>Zz^%a"V•?ËIy·#mHð›xö [¦cyJó‘Ïwp±ESµìñ¼LVÊõäowID*M^»RоµµÞF š|£”ü¢Ì7Öv<’DDY!!ÖÜð7vür:CiXèÛÐI81`’ûuéü»{eëŠs”Éàâ§vç&óŽF"ÊÂÀ#R(ér†â'%zòšù*p2^úm1\°ï-u}`7j"¯ÀäUÞŸnb>Ö¹±('3ˆ(¢A9ª¯ÂÅkQF_Î…ÈÃÉÿ•“Cþø× éeÿk¶ì[D‘$UÈ!Ò€®ådæ7µ6@(G5d¸;“§ÓõФçúå²TÕÎHü½ùÛ®kÎ}‹wqqV—²HòCwî·¥m·ÈpƲšðÁ_$ФÝY˜<$•îÈ¡ÐWËâœÌ ¢ˆå¨NEm‰"$¨ÌZlÝ£)‡¤ò’=`pE('3ˆ(¢A9ª •RSÐÝ?b±zØëCH<ÜýWr2ƒˆ ”£ 3QNfQDƒrTd&ÊÉÌo³óóˆ(¢@9ª2åd«(¢A9ª2åd@4(G5@f¢œÌ ¢ˆå¨ÈL”“DÑ Õ™‰r2ƒˆ ”£ 3QNfQDƒrTd&ÊÉ " €hPŽj€ÌD9™AD ÊQ ™('3ˆ(¢A9ª2åd@4(G5@f¢œÌ ¢ˆå¨ÈL”“DÑ Õ™‰r2ƒˆ ”£ 3QNfQDƒrTd&ÊÉ " €hPŽj€ÌD9™AD 2ª M"…ˆð_C9ª2ådæÿÂP¤~ IEND®B`‚qtrvsim-0.9.8/docs/developer/build&deploy/media/obs-ci-step-2.png000066400000000000000000001615601467752164200246340ustar00rootroot00000000000000‰PNG  IHDR@4Éí¥€IDATx^ì݇[Y¢6ðût+959çœDÉJ”¬bŽcÎYÔ1 FQ‚äÑQQÉ™FPQœïî½»{ï·ûÍæÙÙÝ™ÝÙÙ{¿S}š¢éê†i¥÷y~OÕ©ÓÕí©¢û¼}NUÿOM@%ü·`zB€•*T ¨ P0 2`@e À€Ê@€•SÌÄÊÞÙÝÏË/( ç)dba§#0ã6ûØ>±ƒÂm–÷ñSnRnk¼§É5æ„ ÀÀ”ÑÔ5"]:ÂÊÞÍÔÊÒGä6ÔûÐÐL¬H7QMË€»•ëÓ;(hÒ©2å-É›xcN LÒ¥³söæö“~Ê”ÑG$t ÌH‘[Îõé4éTQRKò&Ò˜“ FÛm÷Ö§‘™¿N(ú!!ïw‘g[½—ì#­Â­)%¬à)åÿ+%ñÖ7§›\ÄÒ:ɤpÁò`îÙ­)ÌÖðxºÊ×õuZ^žñ˄¿'~sùíÜõ&£ÆÈ¢‹þ™yš»«OÏ —³W®éiêr7M+–þ@½¹wëÔÒ7¶´´sqpóuñš£‘~jßë%[Í ÉòL£¤ùy'Œ9ß5w[‰ïÆÒÀão’Ëþ'¹øk×Y.ìC”`¸ÿµéÀpÖþ㇘6œ(¾Žlö¯‰ˆÏ×r·N¹`Hœå W=#K5m·Â"û'ÏBž‹<#b L+ŸÀŒeP^QƒtÇû’û“<(hÒ©¢¼–ä)Ö˜“3­ŒÝŽŸ‘~g\ú3{Û‘ruCóèkñ¥ÿJ.ýÎÁÞš-÷ËùkbnäÃI€I.ý†»[MÏcLð(ýFSK¬zg}KžÅÎÈDªÚ ýx’^² èªË¹ß“j¾ æKÖÑpÞSôÏäŸiké‹wnâ¬i4ÅY“û_›‚Žd®õiÅñu‚i¢ˆ¿¼»uÊé-<å±ì"¡«=þ¨Ýä˜Y9Ú:yiëKŸBÊFž‘§PAÜÿÚ”QÌ¥¸‰âkY¼rÓL{Rý°fêï;ŽäEÎgå!ÏŽ ÓħԱ›BJí#ŽÛAü$ štª(µ%y 4æä(%À>yáDFÖšM»I\™$² d•’M$Ãp%ÅåŸH×ÍNîwüöŸM*ø¹Ú«™¡b*jW ­0F€±¹ôG6ÀðuC˜p’[+UÇýêŸSÊþe¢ÏÌãëú‰¹ Ü2ÓtKò kkñLžÈÂØ)dš®uäQV‘~Ǿù|s¡ËÙσ§nl›úEdö’Jÿ±ðò€{¸ì+pyÿµ™&ó=·ÕÆÜø&©èÛè }^‰›Õ4FuÄ Ì;6—ÿ×ä’Äeý,`ó%ý‘yM¹ßÇ]Zo™“ÏÌÇKÌûmжtÕVúL(ü!éÖïC÷æêË¿ÐHÏeÛ‰ÏsËyÌ\»P¯-\ùmRÁÂö—™˜6!Ï’”ßʾèH’—Ót®™¦«šZÖ‹K£¯4ËÕx 3GÌóIÚ³ëiaägQL‰ºYTzÐ顸[ß'·ðêÿ #c¶¾Ô2u›ût5<>ÌiCC|ñô¸¸…†­‚׿_ý:©ô‡¸¬¯üR·°ñX}cK['/n¹gZfzfÞ¹«Œ“ç.®]š¨1ú±t÷Ý7WªÐ80mÿjf·'®æ+r•y ˜KÓÁ§Ô±›BJí#ŽÛAü$ štª(µ%y 4æä(%À ²zã.K;W²'îæ’²J i°á>J_Ó6¡ô_IùBî&–†Cé†FïKäë̳¿%$ÿI·É‚¥§­ ?Àè‘<Ù¤£-ž÷åz‰ KöƦl²O9²rØ’|æ˜ðM§æcõ¹&*ûo‰×{|Wføl®§S×|þ")ÿͬÕ¼6>N,ýWJÙ¶œ l”ÌÿÚL“e‘·~ =ôÈ÷³;!éÌܶØã¹3‡{ÛºQHIRÞÏæn-ö^_xê?Éjµ 6}‘ÿ~Ò­—Éeÿ ÙUê¾,;ø*3{¸(¶øÇùû︧^ ¥ÇØã»¸/‰šµ÷Êæ@ƒN3ñ ˜¸ÂJÊ{¾°øGfA`ô¢kb®ý?º)¹ä1™ÿåjfΓ0æ©t!x–«šÙQº¼ðô&ö)¬N2Á•påOë̓’O'ÞsáWf†â+^ä˜ÄëÌÿzDÙ¿æ®o`.¸’( K ãþ%9¸ùÊœ9FÌÖPñy¨mê¹þüM!âU)c÷Yìay ä•pË>0ewìâJ:žÜJ¥ËæöóÚÞ¬¡«¶¾‡„ý/l¸ò^~éóÕâjR’žôfΛÅ-ŸZ ögè¸î¾R^Õþª¶îÉŽE³¹d·ƒø>%iéZ‚[>k—i9÷k»»žÕVß¹’–q&AÁ&¥Ô 7íØ¯®Àç)¥Ô&UÏŠ¡ξ·¬[kB¹Õ$™Ûuö¶rËǦxKš­½QÑØÔ;ðàÁÝQÜ 2Û˜“£”C§Š'2²f6´,UZN*p%i¦áÒ}Œ»4Òmåš¡Eê$dž¢«ÜyV²Œžº©ŸÃZfÎXȲ8¶\Û¿–”D¬ ) h %¡Q~l‰¦çqÚgî(ñÜom†õœhMÎ7À$ÞlÔNJÆk‡R˜îõÏ¢ú …Ì-˜%µIRÿ5Ï‹J)ûÞÁcøÎêÛµ/ÉN‚¢Ä;™}ãoÉÅÿW 72äbŸökRÁB îÓ“CV"‚è*_gN\ ó_ _–,.ÑtŒ(ü!¹è¿Ù=Œ¢aœv9ÏQOúÿN¸žýíúÇ}à½ÝuÕ]zË„”áÃì\Ö26Àˆ‚ë× Î¾ôótâ©é‹nœ\ô_3Ås½ô"èxN^ ¹N)FŽ„kO¬ýâ =ã–UÑýÄO_”`ˆÐ­YޱisN‰_3±ðÔ}—…<·öÐÕ¤¼&îÿ‘%ºç˜ìÉc’†°[}îÈNæ£èLf>HN\e–I€9v0"~Û©“¯ïÛ¿×Ýœy‘l€9z%ŽÀXÌ]²ëøåÏÏ^ذ6UGÖ`y%„€NÙ;÷„òÖÖºìšÕÙÝ_÷p;]µ®²¹á ÷!„ÿÞ§·EqËM§Y€‰»Ù*ìµkㆃ·:„ýo¢Lº÷̸ÄI'?Úm# Ü­òÌZ»¹>/ÐǓكrNË«³)óLÇ< ’ìldDP.›”tóöuv¿üJWÖ§§LSÛ¤ž~AGN_&͘ºf³dyêš-¤l"¸"¦þén¹\ÖnVJ 03´Ÿöµ6—¯X±ñ“>aÿëcqWvlã6æä(%À©«7“£Â¦Ь2Çoõfn})jf§H÷1öóî&_Ë™é¹^/¦«2 Û1•⟼tÔ®´½˜~sn[â˜ñÇ”²%21ÃÐß>ùjÀÑþxQwŸH.ý[ÈÞB ‰{ pLH°7»UÝæKR±jä{}5Ó£¤d~ò<É'’"ù_›)XIêGïJ•¬À×´#á*áÚEºj¼Á*`Ôéh°„I8ì ˜¨Â·’Óáf]ÿ+ù¿H^näpù“$wÂÒ±]wêÌzn9½¥[ ÓïoT~›Ði£m¥`€‰Þy},a(Š|„»%Ó;Ÿi¼›®F¬e¦&ªYdÑÕØc§u ÄËuõMŸõù^ËįP^€‰;”V˜¡ŸDK’ ÿ†¸ôèÉ“\òGö•pYÚ¹èÉÎ ’FÃÈmÍÙ[#H“`Ò3ó#|ùê®1ûNŸÝÆç ãÈ3O;›ó5M£÷_Ý&ãŠÑ}ÉFî†ðQL¨cGÙ8zÄ$.Û~à8í+“²J ¹5 +×ÅÂ!o{g²¼ ³¹t뺎ÞkkfSÊÝî»'šÙúìϺ_ÛÙ×ÔÙS’{ÑÉÖÉ!àreËë¶Ö–k{",CæW>ëxQYY¹9‰éU““—²åVUkÃó¾²g¬D»šr õÕõ/†j+–‘eMãDÒá.Ù:ò-êÆí Nâ P«ESf²ÀÝ*OÜÝî;GcØU¯eégŽDIî1"Õ–<í=±®èI÷µ…ò¤BMª¦]ùœ´$õ±LÚ™K'/\߸óiÉù±É´,URH6‘ Ã}”Ìcár(÷aMG_uͳ}«¢iáãÞ·ž‹ÏŸéÌ<²Èrv¨ŒÞ׸99Ê 0ì„1ÉB:©,8bdèCž™†Ÿ1]Ì‹¸›X3ô"R˜˜“tUv€‘ºòö{óŽô$—ýORÁÏl†¯Z¡ìEC&̬$¾–É3 ×2¥ž‘Å×°ø,wY~+üÊ7´›kocE7qL€ÝHŠS·, %!#ãn3v¤ ˜™†Kâ³,‡_¡äMÓƒ,Z°ì€MèFI¡ùÿH.ü»[Ó/w0p‰¶Ú䜚UÄŒZH˜Ä÷$+{eÿ%éÖkÉëK”`Ü6_Ø#£¯¬éþŒ&𤶯íM  0ì0EÛ‡ˆ\¿€¬êÅöÒUf¾_7$¾ô_´„ëÈÓÍ>ËŽ[xKN»’`,g.zav¢åAK2ϲšsão)L@•9QÌÁÍWÞ“I€9åæ™ËDî¹ ™W-Ö½oÊ 0§N‹‹È§×þK¹³©c½èô¾â+m4Lf{{XpŸ‘¼Ì"€nB;bö¼ôËé}GÏÒÙJd~-M6qëƒÇ|ÈÂå¶W©g[^íòó¢åÇ|ÜJ«Ï“>1é%¨éËŒ˜c*ñÝÿ†ÛÂòã묭Jf€YQÒùàÒ.{['çy«õ ®ñf†¹H€)»~ØÅÑ…N!3³ö8X.,<.ž¹7.[r¦®‡_@˜ƒ3¥È2ª”´çIq×wlã6æä(+ÀHN“$9©l |M{ÑT¢6î&–†}1ébFïM «2ŒÌ¨ö¬äqç¶KjzÞ#…ë™7 -¯‡d9d¾Ä´.u=¾†xØ(ê«eÌ„´¸ Çi‰ŒcË 0þ²Œ†ƒ8PìÐäM7œ¹7šLɥߊŸÅqMÀ©ÿH †$}yNpü7)Òæ.ûxâóR²Dn€Q×ßs‘édK—“×&~mA^£NÖX‰k`xãzokI7¿#å‰7*Ȳóe&1JhݹGC2˜ r’s†œ|ÅK^€™¿dxÝp€‰¿šÆîV‘ãâÅÜ¡N&©)d,™æø‘‘÷ŽÅgs¢M¤ŒË®Ë[æÉ¸âHʯàØPÇŽ~ M‹TV!«4ư_WKŠ+é¸s$ÆÒ9¾]XMúÇ¡çî¤ÅX8Åû_»Ú9Y8ú9»¸˜Z99x‡ì«ê-XÂLΡ]g3[¿öþ·ž¢Ñ"aÕfg[&À_˜‘2Þt2© £`z1U¬¨aK:…·‰;»kà]me"·׸Ä G¿Àùóc’é˜É-4ÉURH6É“œºãdVyeË«ÖÖ–«é'H>4•02 0E¸»’G‘&e…Ü~ÄC§Š'/\gs Y «´œTà>Jê˜æÖRSk׆¾wó]i…¨ë-äÁT`Öx1E`Ú×g5¶wÞ•ŒŽc›PKºN åÂÁ¦g7lÏqsr”`x¢ ·øðÉ Y «Š¤Š^Xïb-ï´ýÓË!ìŽ1ÝÖYÎâßÇQ<ÀðD1ƒ^DÁâkÚ.,þ‘v²mNý&¥ìŸ†óÇË™+Å=E÷Ë’¦a•Ä é¼`÷<é#äMÛ·™Ù§£Ü_âëП¦q]°\×TüÔúq/R¦(Àhš-9s~/·œÙ$Janð%~ÿ割(½ FÑùk¶Á’Wt“©¡S| 3Þ½絆UˆíÂsþGzDRDóÁèy2ÝŒšèUñ5-ϋŒhf¥¸‚ºþÞK¹žRÆvùÙ=KÄ猆IX¨œûŒñz> Å;vì™bR(5å†åžPÞøì€{BiõkȪƒÿùæÆt§Ð›ä_²jå–p®¨êiCKYùמõK+—E=-R{#æZ 8´(r= ›aO/¦Šõgêù0#0gèŒ)Y®¾íÆ5nQÁƒBrãÉ q—ZªcÍvÁÅñŒëòÆÇFsò ]üyiWíýƒ¦Fæ1"&+xœÆ—¤H“²>n€1žŒ'5ŠÅŽqqë›Ê!ùD8ð–M&s¶W=Î]d* 0þ¢ˆH*ÿ惬ƒÅÂÁ£Ñ̸–"&Ô’n‰«{‡jïe¹Êú"[¦qsr”`X›v!¸åcÓpÍNafõÜÕÐéÑ2S†Jþûy±éìKÌïÀܨâOêw`üo~—\ôŸR…VG™DädáF’LüÕQ7zÖôxœÂ\w±»+¾n˜è÷.s課ÌL“¢ü¨ßÓäi˜{¬ÌrOb 5Ý™' õ‘¬`Êd€) 0ö«Îí]êÉ-ç1· K¥I ñf {[g½È&Z(+ÀŒ ‚`f®¦›æ/~JØ›¶éFu[’N°?RÉ×qñ½þWZFP嘱§É 0û/å†Ú›‘—˜#äm‹½f¾§O]Ï9rÏ©Ó[xœk`4ÍÎ^øÜÞØ§a´`Ï•Má2fb L vì<ý‚H'xßѳl K&5sŒT Õ¤.q¶r]ÜÙÛ±¨¼+'‘¹ˆÅÌÖ§®÷uêŦûgãÈjRy×#+ÍE5£nµKs»€Î·Î÷)[ºçØGÉТH€1e˜ ¥Sûˆê¦kø`YÖ4]Dz¢å{úZjÜ¢‚…ˆMZ&sÂ)$›˜#1’À•×9¸Ñ—™ÚDÙúê>5•02 0Š4>K¡&öÑ ;aL²N*#MÊ­o*+À˜Z»6ö½ ‰¸ÖüåqñŒŸƒ8Àt½ÚX;y¥æ¶¶–X[Oíít<Öå0§åùmŠ·$OÆœ¥-=“‡Nd»ulö»˜ûÿƾmb52é_göéÄRÑä¨ÒoílGÆgH/?)¯Qòác˜€›ß§”~/U¨áOv»ðs½{ÈèÀ×tœ_ðéÐ{†EI^ûÎ×rp;ø+RÞ|qßQIF⿦çŸó·äâ¯mFvk¶„™ÆÉÌyÓt¯Na®B÷Î 5›äpÑ%éì}¢ß'Àlʸf"÷¾(Ìì0ÍxòŽã‚Í.ËoÓƒ•2*ÀøÓ’Ä›Oô,ÜéuócÓLœ~Ôc¶œýU™¨½Yæ>ÑçùaiQ¢Û”%¾£¿â¢¼£àEü£¶öð¹kÇÎß8¸9uûæÎ×$ÀÙšºú@ÆÉŒì={w81‰ˆ{2Û •{N\9~îòÆÕ‹eþ¤ .â€é@Á޽vYrì%íÌ%úí¾äͤ½úYêáƒÍsi6>}AVOú’å%žmˆ$ vsu ®b¦‡‘®óÝS É·=E‡VZX;ºFìnÞhkÃL!›h€™ûˆ‘¹­ÂþÁ£{÷ž¹Ý-J²ùM³1ŒÛATð ˜Ò`yá:74Žl͸N*ÈÜÊŠ8ó¬îþ• ?æ:%÷í7Zç®7•8 2ѧ`$'ŒË’e+ÇUe]¶“ˆâ0wYåóÁõ¾ÌÕ_’fø.dÎgêr>ShJž‚-©¦ïßÚÿ®«·sÓÖ=DbD_ÈŽkÜÆœ¥˜]‡NÒƒDÞ¬¸[Ç¡nê¼EtCÛ²FžnõßñeÀþ†¨›Ì}uEËo½æÜÎË#ë[ÒáöZtÂaž;-#Àþ:Ó£}½8O]ü“‹)e?t¥¿YW·ÛH{Æñ™oæí­œ½ínÀ¡öXÑožDí?Ç)#ÀHý×Ôíö,d~~ñ/Á»Ë½Vçœøy sIOôàkûEý@'à³,×EüvÔ%”|´÷¿IÏ[Ø0îIu£è³>çþš'k¦Éò¨¢ÒD%^¯)fJØÃS7 ·B¦¤ÈRV€Ñg¦ÀQ –üî'_Û7äúH¶Qöã¬0qU^€ã6ÊcSÓSè3iBpe˜ìØ1&cT€a»w$ɰ…L€É`âJ:ÚÚKØU¿„ƒô⻹‹jºžÔ4ç_LÙ\Ø*lpqs‰z€™©ëy ûASÏ`ÕãG;Sçr+È4nQÁƒB‘p"sà‹4;½fÖîëŽçV4õ¶÷6µ¶e_<ánÇö(ÈâäŒÛATð °È!Hç\}D¯YRìÒ—AµšTÒöýŸÜòE©-ÉS 1'G¹†þð B–ÎùY˜÷¥.°Yz][KÖÍÁ`:á˜O†¾±¥­“øÇy ~€é@ñŽí¶ã ¼‹øÉ&n7ZE)µ8nQñƒB†Ç¦_°AïBf:œjÈ&nýBµš”ENl’Û ™§ýG¡Ô–ä)И“£ÜCÌš"#‹ Ü­ðSð ÂÌÊqrɦ yvò¸åÞ„:v4Ãì•uå½òo£¬Š”ÚG·ƒ8¡ƒb:|Å9éa§®a~”<ùõ’udU´ þ“Nµš”EïNO{îÖB©-ÉS 1'GéàÓ0~ÊMÊm÷4¹ÆœP0 2`@e À€Ê@€•1õ&þìÝÚÆf;]}î&IúNYusËÇp´i ÆÔX²Ä:éluKçag nåÌrËc[#ñªº ä\·¡”ëêÍ-WD|é¿45õ¸å?S`ªzßZêŒÓÏækOI€‰«ê9åj)Y¢¦?Vpâ+-8]ýÆÃ\œ£Ô,Î…„xsëÉó—I–ðµL¹Õd2ö‰Ÿ¡Î®êó9>yS`ÖÝzØ1ðî^e®¾®SÜåÛ5õ½wï/pg:÷šf«Ÿíž0¯ª!‹ 0Ú6 ÷;;’Ü™2wÕÙ;5] í]WOïÔÑÐ%%ÆkoU¶45·fgì;ÛòR2À¸l+xÒ;T_U{ÀÉÂfÑÝrÑŽï_ Ÿ©ë¶óÚݧm½UUU[gÓÊ_v¿IL»ÝÔÖÛÔ\·dNàÁüª'm}÷Ë2 µFE¾Ž¯÷î…¹ŠJ:û¹©™ŸNÊïoÕ0‹)ú§¥À˜d/ qjr¸Â,®k\XücÜ¥¯\ÍÌI¡ÑƯŒôÌBTnĵ?,Ìú™ÿš} ó‡Ômò£r¾O¼ñŸI3v$dž¶\ý4&»‚¤š˜´åt‡j¦G“ ^ðÕuŒÞŒÊþ]|ÞÂ÷çkˆry MM=àΨ­éá×ÿwë¯á»?„^‰ÊüUBÂ|$ÿ#Ÿ¤)0Duï±–_Ã8¿sð𢀙êz®ñ':„Uºº$Àtõv¥¯ŽÐÔÐ¥FÝp^~Û‹ÏBÈçžniÌu53š©g·£¬«d÷Ü:.Ÿnˆðák‚·•w¿üJj&±ªç¸#H€imêJ˜ëÂWÓI(h¿wf®¦žÀ%þÁóÁdKff 0·vĵÂþhWs¾†Ù‰æ—gÜ­$wèøù×á+VÏT×ÕöLK.ú™‚·~ sÃÔm¯'\/á‰[¤ -dG`2®1õmÎ$ÝzifeÍ×¶uOûuráW<‰`’‹ë¿0‘<×Là ɅC|ÑèŠáê·‘›£gè-H*ú/‘1OÝÔ-ýwAþî<‰“tkÐÐЈ¯íQøC̾C3Ôu´g—'Þ¸#ùø$)+ÀèXïjm+b Ï·¼ÜakFLç󦙢ž: 0Ïö\¨é{|3Ö‰¼Ýu=Ò™.ëÙon8k<'ŸÔ¡%$o=`ê*Eƒê‚úC¾f„˜{¹±|מ(ÀÌ5d uíO6Õ¡[‹Û¯س{ãkÚ%•þS[K< Í"t³†¦žÙ¾_†Çû“U“]?[ÈìjìC’Ix‚¨þÞ_,H ¦ÕÔLÓd˜¢_ÐÐBÌËýÞÙ”½™{ó;'S3¾nHbñŸü£Ô$æ¼±&öX -ñ¸ö­·%Àfè'&å·²5>UÊ 0úÎY5;ÙÂÅOz/{X“ÓÚr–#xwzã¶ÞNw}R²¥¶¯®êÙ‡5TIY†í¢»OŠ¢Ød´ŽšBÆ`^ ' 3t\„oØëC×<¨ÌbÊI€qÕcžE×îxCõºu^Ѩ3C?.¹èç’û'4ìó®]á©é…åo¢oÈ/À¤¾²2d^¤õ¥?y‰ó_'˜`o>dŸÅpý»+Cg–&å6Ðý Áç~ž\òmØþ#O"ÀDï‹£uܯ}K'­‘WŽ?Ê 0:Ö»[Û ÙÂSÍ/÷Ø3#0-Í™´„˜ú§Ÿ‘…ÈËM.1C ñŸ_šmK·ÎÔqóò¶3öËm|¶[¼uAÅó·c˜ŠK¡´Z}ßÏðÌ쌆ò}syо–KrÙô‚fŸIgôt x1Eß ,Ó2ůœdoKq€ñ¹þW©ã{áÝdšö«K†G`LÈ07îÒ­L³ã‰9ezÑÏIŒá179ð2°·# 3îvk‡žZÃC€P^€ákvLœÍWÓuŒIëè®6ÐÔ“ 0ô"~5ƒ€êÞ×qV&‘ÙO³Møf«²[ŠvÌž©ç]Ý;¸6Ü“¯®?gm~×À»ñŒšNÒ­ö»'Wijèê9ÄTt.±fnó¥H€!\Ïý>tÉR¾ºŽ¦ë¾¤ÂWÝHÀúÄ×ÑG2|•¼õù߇'E“-ÏÃÉeÿÃK«)k™BÓýVRÁ€‰¹_ÓÊõðÈ50«ÃxœÃSÓŸ_ðy7¿³]o3Óä@RAŸ¡OMÏlÑËØã«y0Ê 0dAÏ%þêÚº¶ž{wK"=˜^¾ÌCxìxP{o?é¬Gl½r¯®»¶¹#ëÌ>z2Óy +[šÚ_äžßºäi¯"f¦®ûî¬{O[{ž<}º5‰¹…§p€™¡è{¤aîb.=wôq¢…šžRÊþa #ÕQ·Û~õ7q9L¸Öèžþ`Œ×w%Üü•OÊ gQ¢ ,RîD]ÿ&.÷W~ñi€ÑtËŒ»õûÀ”yœ£c¶÷‰7¶«ÅÞü&îÆo¹m¨Ï<5 ÀÔ˜Ÿ¾¶•į²Œƒ¯åA ¼˜˜¤[ƒÜr˜˜BÝÄÀ„¹¸Þ ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`T€¦ž1·¦ [ç}‡O–Ý«ê~ùAÈ*)äÖÂÜÆ98"><&e\¤©ÌÝpéš;¹ûÍ ‹%ÈYåÖø0ÈHÿ„Éw+ÀTùtŒEЪ …ë»^wô Ü»S²2Ò‹[g Λ*k+¸åyÓ']7Òa{!d”pkŽ«µÿíU]½/+î–¤Ør«±ô²Ú:ÊÉ mgò9·ÎG¥Ç×Ðã~LûŽœ¤Í{1+ÓŽýY %$Æpësiš-§õ‹Öùp·rÍÐi„£MäÁF†ÜjÓ9“}ýÃ휽ÇEª}ÚëXïaOo¢½»§ðÆ/cE[ƒ¯a6¹Ö#íÏç~ÆönÞl ôô "ØøG6‘ ÜGq©ÍÙQZÕÖßÑûòiMUÚ®•ZºÜjSâTóËËÖ̲:9“¥·~x³ƒ"l¥q©’3*ÕbÂ_6´‰,cœ¨3¦Ùû!OôiEN?rîda¢Yz§¢d#°›.¹­­7¸•àSò‰“ ÃýoÎïß2Ïß3 rÙ¾ëÂþ·›gÛpkÊ3Œ¹3íˆÐ ÃN/¤téÈÖ™ZÜGÉCÌ•°;'OÂmNÄÞ›m]½ívºúÜšÔ40äåM«Ï¤òûOH+‘Тgh!YNVIa·h4†û()n»ÅC7M §¹[¥¨éÍ&5[Û éêšìÒüÒ»^Óë0žÉÜr.RTæ–³h€™ëî-:ýü—g7¿l¨:Å­)›º`ÃÖ=6:î’Ü8Fwóƒ¡DT$ßÈYeƒ Yà>vuAzmMYF°ŸŸ¹‡_äÚ¼¶×÷Î%KW›"akwDš1]|Ÿsu•YáÜ ˜â'ä¸&`Ø6‘I^€¡ïÒ®zøDP©5Í*4B““ Ÿe<ѧ˜ÀD?™‰ŸŠRÀþmjš$¯Y—È­Ÿ’i`Ègíì ÉúñÌ­)…¯a\Ø9˜¿5X²0æzKcõaney¦C€¡6òvO3 Ob8ž"í£x†!挓%»ª¦çKÞëÏyXqkRŠM=¹)Hy¦U€¡c/ ‹Wp7Qd©@ªq7I:ßò’T«é ùÉopJ*À¨"¶¿hlaÏþ±““œmÂ~#®`€±ÔI F³²HÉ舮§3Þ7¸5MŒ"ᄆn¹$mËÍL49÷ }3„ý/õ5'íÆÆ×õe¼ÊîÇ“™fÆ{Ÿ~Ó?ÀH}H±í)U>IœŠò ×t½€÷7] ý¬•z£…ã~N뻜ö½0“èÊZ–qKV¬¢Ë–ó7å>lk{1ø¬ºjÇ2æ;!Ê{ù±¢Ê–ÖŽö›Ùgcv?aŒßò´ÂŠÆ–ÞþŠ»ÅK‚¥žNy4õŒÙ !lS°½::¯ø…R†¯m×5ðîêl[Úf{~ÖñwŸíæ`øZ¶¤ÐÔ&!ç^KɦY<9­¤¦ï{àÚíÇm/«ªÛžšÝþ:ÆÔXÞ3FsV^.}\ÛýºúÙ“½ë¢Å;øïϼWÝþ²¹­ãú¹CúšºúN›»ß Þ6 Œ´ô³–_º]ÛÐ=X[ßpd33Tõ!YØ2í³iÇ~î&ItfŒëa4M—0¤õFXn+YÈ]äÁnÒ0 <œ}·¶ëUK[{~ö3#zP¨®ÞNžÔ2uAÂŽ‹·k»;úkª«m^4SÙI@1©óàrÔÊsåõ݃u ‡ÖͧO¡eq2ïáÓ¶ÖŽ®ò²‚„9®œ4¶#™O|ýÉ1*ÈÄ 0úÎé¤ÄG Ðw¼ØTÌ*æÈõ¬Mɦ°Mé_6ôtô¾¼»(n“á%û…dyÅ‘œ;Õ]í]Ï‹s.ú™‹û :¶1gò+jº^×Õ×XIJVwu ¼ëì~Yr„ySòYv¨¤ª­µ÷e壻+¸/Ry${Š”d¤ÆmCBÛj;i‡Tç‘tÁײö £SwÔfÝ®lhji»p|§@KÜÚ6QÛnÞ©mî}õ¨âöâ@&p < š›.°; ¯|^ºc6Yð>Q{çH@ÌáO…ý¼á.¦÷‰ªÖ¾!aß«ê'ÇÕôfuô¿‹15¢Ôµß×õ¢Çtô›¹òp›Q&E>‰$Œç‘š{§"·Ü¨¼knm?³[|d¾q±Ýn’ñÖž+zÜöª¶¦red¼°ÿS(:Q£¼“r´·¿xYq· ÔÒ˜¼4 ™ï>Z…‡ÌùÆËf=lèiïî¹]œ`&nÌ€~*‘|0‘–˜ŽÊdÕN4w€†™±/æœè©(Õ’›ì·]zög›Îøo¾ÑÜ?ÔÑÝS˜yÒpøö_Ÿ~§¶§µ½õ膘 ­/é…ÌÓÓ´0c|<Œ±‰å²õQsÃYn9¥i–BÞ¼Îl^ä`ç¼(,ïM-3ô;"ì½yœ½OÜ®aß 0æ‘Ýu©‘!–¶ža«Ouô½Œµ2áîVIÈ[<÷ÿËöKü¸¥$Œ¦‘â´GÂþÁ #CyqB‘“]Uh.Èk¥]=µ÷®Îõñtœ³0«žéa`4Œ£k{ßYŸlgçì3ííî7—z’òäò®êâ47'g[ψ›¯ 60ׇŒŒÀ¨ HÍœíKll=çojï·ú Þðð‹ä̱‹YùÜ B*t9ã²ã1©ðå±@CßËd¡¡Zœˆø¦W›™æÛù7Og?$ -M·44ŒæÇo!Ë]•aQ¼Ñ&äD5Ynk{r6=ç^× Y.ÜÊ0ݯkÜ»zë1éN †bEóUÎ7½$ËYéOç4ô ‘Pä¤ü5™ùd*Œ®ÀÆ?íAO[{Ÿœ*Ž;„Uwo3k–®†®MÒÎÞ¶•QaVŽ~‹ŽÜîìmuÓ7 0 ÒëëgûùZ:Ï^}òq[ÛmÒ=âkÙt øÌÅÁÙ'zkSßÐÑèåÈ4³•]ýƒ«£ƒ,¬]#6•vö´è¾÷×íŠã¾H6#5n24ŒÎV½èê^Ø.)oï¼äãefï»ùVGmÅ6îËS:íY2·8 ßOÂÞE|Ly¢$>î·o?åÀHa__Un𣕙[T¹p07•ùˆ±ŠËêè®^4ׯ#äó{ÏÉ#`ä ˜ž>~€÷ãaÜ >gꪷpËÅ[O×ÕW|Yv­¹ö>32“\ÑýèÆ"¶üp}? 0{êû –3ïqTʃçwOJíS©¸Ÿ©Šlâ’¼ˆŸéÅ>oݱ„éRÈ‹Š˜Œ0ñH‹ÌVÒ4]BúÄìl÷´î1 ù˜¯­XÇîÄnÙýæ†3dáPÃ@éVq› f…ûy31ŒýLâk;½mðg3¯ ·ñ&_M­òûOHb‘,¡-̽†TãJ˜Ó¢”²ÁÆŒ¯mK"‰—΢Ob×%R^W)¤Z[ÑÞ,Xji"5…Œ 0Ì7‘ýCÂ=>FL;hYÆ‘^Ò­$ýi`šjOЙEÝdõZ€=yÆnf$§=ÀÛ…ôø×Ø{ää¥q+3Ÿ¼O€‘ÔTs'Öi`È*;%ïHã@évæÌÑ»Üö*?Õ“ 03´Zû‡[Š{*| £ŠçoºZšÌ»I²¢æp& 8‘sx)3D&ÑIºDr‘¥è*¾–Õ¼Ð(=M 0Ìß»Cü†´+%OZú™“ð‹[YÑž¢¿8çÓÏëÙ«¨µ-× ûߘkëÍËi©.n“èx"»p±…ñ¦µ­ˆž~<9Æ.õnSýç̲º~I×àq¿1HI5#ý¬‘ü¸÷Ó‡%`ZÛ Ø›=\o}ÆÉRÞm“:.ä›=íWÜ— 0ç‚Äã{f!¥ôMR²ïî}²¶¡zmd ã¹þAshå`¦–Áì ˆàˆxz iq¾ˆŸ¶-½’S‘ùÏ= 0Ý¢QYZaÞ­ö{瘩æúó‡?¿´­60ÇÅÚTÞ€éé#ú;îǃä»!—ëÎ*úž.‰¯almïFúp‹ŸöÞ>äÏ–›…–’²pµíUöpwœ'ú@¥†t_::û:^PÍ/†ªï|Сä1þ§clâ’¼ˆßÆÁ‰íŠÉ‹Š˜„á‹Me¶’¡OA{çý‘‡hÛw`"+{ºzûÙ4v½iï|Àc:4—Úû‡î•íÛ½sžøK;Ék`_®öõåådmÚ°ÊÅz¬i ÊÐÍ™?Ö=܇®¬iODä Ï"ãîÇ\fšD6ut?Su;–UöÕkQÌÖeë#²Ì~'Í’`t¬w‘…Æg{ؚǛ˜hgf<<…,Œ–û]j$«Ù¡ÌiŸöyF¢¹¡öüéã‘.RO§ 2ó‰äwÞ2+È4ú"~Okkk¶¿HLçóF¶f}ßÐû‘y)Áån,`Œ¦sµRÓðIHtô¿»>ßÉëXM}ÛM12áGÛþÊ“¾ŽÎæKégW,Š3øýÞ÷­`Ò†5C×fvôês·»Húõ2Ø$}I:‘l³4tô“† 56ÜÛ0êË jŒS[¹„-—`Ô #„CîúºöûH&ÔÿH9Í*ÜLmåH˧·¾¤ƒá2߸h›èXí$­­1|g6]»£’†¼‹Òr£Y…Ü£c»¬²ûMý“‡'ŽY8?¾¥|0ôz}ÚŒ’—­’z+zŽ›^$)x**`:ž7°»“ÕL 3 jk&.×0ê #0rLOŸB€x\â^£kÏ|ýï#,‘ 0Á$À‘…Ë$Àˆzr”è#‡ézw žv¹täÃã:Æ&.©k`XRqÂfÑ]Å ;º"³•ŒgµwÞ“xˆpà7À°Ïòe×ýs!R;¡tìü“Öí;•ýesÿPÖ^¦£#u¿_ÌêŸ_-«#‡~ãDn7÷þºå˜GÏZ 0Λ+ÙG±ê*7“M®;˜[“®|€9& 0‰Ã¦â3Œ7:Àð5-‚’7ÏüâÙó·¤ô · õ¨<ãæ“q+°¸×À°H€‘<¥LPIÇã¼6ÀhÇ3ûáÄu˜¹:RØNOô-‰OÄÒ­i ŸöµµUyèO ‹öžH×P*®èšKݵ–T =È1Ø,>~ôàÈe<ÑŸíãÞ·YÁ Ê[š.rr¨a 13%I*ÀD?îaLõ1l¹ÌC˳¢çf4Tå%IíY©ØóM*«ÐUE>›XRæÙý…ì&6Àðd½q‰ŒÍ>ÒGWÎ:¶‡% ûÆ+3À3õœæ/Útà\neçàÓÒ“ì×0Uf§¢BFø˜­?`tÛúßmgŒº ½_`x²LO9Àð8Ÿ\ãVàkZÞî~S¸Sü53y¹©µ9‡'š`Vÿx/[r¹©öÁZ²x¯ûÑõ‘Ò¦ª^`–UöÜ92Ò«^ãöySóC #¥Œ±‰kìã4ü¦œÙ4‰#³•´-· ÞÎMdbvèz¨[b†ûŒŽk4ÕÜ>ØekÎÕÓ xjzÛö Þ‰EDi{ÇfoßIêFQÛ÷b?¡£oµ?-_ýÿaÈœBÖØñ‚{Y?©F*s÷À$¹ûÅýüÒ»ùöž´±s7­ÚŠ]´æÚ»- /’ÍÅÍØÖ^JËG¦é¸03.^ôx‰™¦ÅBòñÜõ¢Ç@SO^€Ñ4[¼u÷¡5˘ßJâkš%^dÊiS©ØXò.d2+La€9Ú8P²ud Ù…ÖWËG¦ñ4Œžôíõgròç–U“ßbIã_²_fÏM¯È?Íô®ØN’IðÆMÅwDàiæv f ÏóùزH“Jþ¤ é/*rGëøòöÎû’“ßøZÖ¤AÎøØ0Î}/l‡ïê¦ï¼+ïÖ²^Ü^•?2¨r¦¢.ÍÓŠ˜Ö–ëÃ…º[_M(À¸l{\÷psI×à~å§hIìùFÎF©¶â^ 3¶qŒ¼7.Ú&jz~Ì¥2Ã71³K½«x€™³qÿÒñ¡×4‰%å÷òR*©)dôÏÖmRSÈ&q*N6Àèœm~™/º†Ç̹]Ý-šB&ïÀôôñ ö2Æ&I‘§ºú‡.Þèïà¸|n×ÀЮP¦?¡e‘ÚÚ?tbC’µ³Ò¡¦¾¡¢.ù¥‘Oˆ=©1VÖî 6f¶µ¼¦ÆxÎQaÿËmÉ1–V. >Ëîìmóþ€?µ!ó"þq7É$/Àð5Œj_ emŠÓ×3sŸ¿µþÅÐ$ŒœVÒ;[?P{碯‡›Ý¬è«Ïz茼gTÓ÷¯ê}›{h­³½£ç‚5½C»ý™ŸÚ<Õô²òê~GG3‡Ù›o´ÕVЗw|ikªëÏ!ýõs“­­mí¼£¯µ¾*ÜÌÜíƒá^ÄâÜ• ]įaG6uö´HþLÛÖg}¤0#Èò›m¯Éò›Ù'3+º™‹X²f¨1s–˜«ðû_mß¶•'`ÈrØé²ÜÚüè䙬;ÌEüE™Þ¡¼£n8¿‰dž¾çOÞ}$½¼yº®£.àQ†q¸2ŒÍâ<ÒÔKç™Ûú$,ïìmu}ÿÜ´'í•QAþfö¾Iº~*êé¸Üî~“—¶ÖÁÖÁ=l}Ý‹¡^¢‹ørã=Õ´õŒg_ìzѺ ÐÌÜÁ+rScßÐZö;]å#Y%|ôUÑá¢v•^]=î¯4’?ö¢ŽÁGyç™é¦^þ1{n¶¶¶~!ºá˜îÑ'/jÊNûy¹ÙxE_®øâó<¦û¸µ³ÿåŽE‘––Îár:Ÿ7:êéëXïö. öÖØ-Øš×=œ‡å˜³u5·—©i‹ßd4Í– †:ºëØ™®Ƹ'¤âÆ 0jrÞ¸Ø6Y’ß^{'ÝÓÅÉÙqQS'yƒå`b¬ÌÔÕuf§7´4æùx[ºDmÊïìifïµ¥lÜ‹øI{Ò‹ø%V‘‹ø'q*J6OâosÜc·¬€”GÎõµpwä‹úöþwë¬Må ˜ž¦E€áÉ *2 å±øìjYMS÷`GÏÀ½Û%+"™o—)눭ù•íí}ƒµ£o£¼j‚¹‡²n?n}ÙØÜr1m+{›5ç¤ý-=ý÷ï•$Ìÿí'ºù´W¬˜•rµyìctô™p°¾ú»)»ýueæ‡þÂ{ÜRqã² ó‹m“Ú[.Ý®é¸SVìFR7O~€!gõç·[:ûß°7Ÿ©ëq »¢Ž|ö {î”åÆ}À‰O’·Q¶wñáÞF™*xeÞdNÅ‘FàIümŽ`Èïü­W*šúŸ>~¸6؉|N1·‰“s€`zš.†'Š+R“"™ñ)¡6úC–R½·16MÚL=K%QÇê<ã‡1U?dùS£xqÜóžøšæR\åÐ/5$3 EÓ 1nQ´Œm&q_Óªª÷íVÇQÿ‘@ñRùt“—­u¾•¹YPAsc§ÎtDà ‹ý~þ s˧×Ä•á®â“M].²æ\ÓÜ4 0@‡ãéìv©«oÇØ4I˜OIùý'tFêÖÉd•Ž½È»úå§Lñþ¢²Œ®m"9F¾*~›T’UÈ»i({Ÿ™ZY «¤P*ÕLgÆ.ž ¶Ünï¼3‰äóžH[ùú‡“FSĸóñÞÓáê¾òC©úºúºVsÏ=ë+¹÷÷t'0µ¦çý~žŠô‹':K¥Ff>:Ÿ£Õõ•gmŒÕômVœ«¯{0Îp:LC0Ó ý6KfÿcŒMÓÖÉÏÓØ+/?=t†¸x-„‚,ÐŒ½È¤x‘ÎâîaJèÚö¿.ÊÜÇÞyYu‘ž"}g £.ô«î±¯–žnRo·Ö>y¸6X¹ñ@¦ÙAt|@2o;1…4ÍæŸ(¨ªí|ÕÐÜtáØöù»¨S…Î(c/⟶U|M˧‹«šûZ;Ÿädx«ðH,ÀO ÀäYØ:“¬BGcè¨ Y•yÝ ðD‰ì¥\c#ÕÆ¾ä÷=Íà”¨4M=cÒe$Ñå£L`±3ʦ՜1øô À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`à§îûãë`r¸  lÿfjåðSÆí—ƒ‚¸  l•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P0 2`@e À€Ê@€•*T ¨ P”‰•½³»Ÿ—_ °Hƒfá¶(  ŒOS׈ôÔ +{7S+G`‘¡-CšˆÛnïÃ2ò‹î—_q ûkkkŽï^¥©¡Ë}”Lš¦Kèc«¿ˆánP-00>ÒA·söævß"CšˆÛnïC^€aÝ9È}”L0ð)A€qЙcÜ^;Hšò¹dl€i¨ººu÷!jÛ¾cçKZh¹°ÐEÏ€û@.ø” ÀÀ80sLt.·õ& 0•Yá£6if¶½¢›;˜sÈ…Ÿ‡—_ ·¿\¤¡¸­7irŒšNRUÝ´ÏÞL\¨®´ì`öíº†îÁ¦–ö’¢œÅQþl}™f†¶S꾋%OÛ[zkj®_:ìi)ù,ñ‡¯–W6÷vô¿míê¹s§lÛªø™ê#fh;,Ý“Qò¸­¥÷m{w_Åý{û¶®héìdÌW0900} £.ÈjÝÍL!{éªO§é­¹ZG+KÊ9´”>„`fêz^­é“ª/ìëÛëF+è9­­ïâî³ä˜x| ³³U/¸ê*.ëˆï.0Ϋ˜œ)0ÉÏI¥lÇlºêy¤†¬6To§«z§ÉjG÷S>çòØ,ºKrçHg“Þg—*{Þ6Ôž#«¥ÂARÍR[âÛ_˜"0 RR€©|yÓŽýb;¾ÕHË ÇŠkÆäÐ’;ç÷úxû¸ûÇ+Ò’#A¸t`^@ _pÜîìfZry³"¯ `r¦8ÀмQûp]]ö´—¬v>o¢‰ÅaUÓ‹*_Ä} <òŒ¦ÙŠn& ÕmÚ˜ÀC€Q&ÅLhÞ÷qŸŸdWÍìÂRÊþέö8íýyDRĨB[ÿÐŒ_Åfš9$&¾å>äý))Àp Þ¤­^È~ °»ŽKéx^¯=|ce5ƒ@áÀ»n&üláq _Û¡¥Ÿ]©­ØÀ>Édx ÙzºÊ}×3¢nÓe-úðø\¦ZÕN²¼C4)ßßPàs®®£»F8ðîFŒ‹À3“Þ=È×¶íf&ôx»ðÕtר{ää#©ÿÝOÐDŒ™ãÒ¸¢¿x…ácÛn‡¸šÍ¬¤Ò­mýsþ:×Û×:²#ú³­IE¿$›|®|à/¹CyuìW¾^xl#­cæŸRú…µ 0 WÑB`¢?ËŽ+þ1,"„–pŒïµ?‡…ŠÿkVÕ‰ÙYf¶AI%±´qr;óÛÀÈêø‹‡M­Ü⊰³w‘|Uò|˜£&¦å­­7iÉÑÕ)ä¯C )žBÉ×0]·mߦû×®àq _˶Y4¿«®r»[ “(zŸ€Å¡öšf©´~Í]ñ_(_Ó¼¤‹ùë0‰›öÊ61Cš”Žm½qYkÛ-E^ÀäL}€Q„1]¥²„Øû–æLRâ{®¾³§Ù<¸˜”_an@´¼š¹ëv[ñ´17fJXíÃÞp€™%ºo8Àû™/wÛ;¿Ô].Ì“`œ6T’…²âÛ ÍÐqë ïe·ÝÌÜ›ôY6[kûjn§\k{ý8/Úã`5)ÜçlA*¤=ÇÜÜP{þôñȺ“Ÿ¸‰²`—Úžp¹„ 0ß%åýWÌåg98¸:lþ?Q«\Žÿ:À×/èæw®>±E·äÕqÚû‹¨µ‰lµ„’‘’³ðð*ZBLrñ׳×ö&fÝ3•p Ùá/_ZßÂ#=)¯–,̽þ—Ù^¾áy±vŒN*üÊÜíXâÍû’/i &Àп/¢­½L\s!“Ò‰ŠÌÃóæÌrôÛ–)¾ñµÌüIî]Èbn´Ò’³;V{¹{z¥\ªfò†°ÿM¢µ‰ÚðStö¶­NI ŒZr ¯‰–ö¢aɵÅ,gwm˜='ÀÝ/$qS:½F¿æö*E^ÀäL}€!®´½jmÉÉný¤h!Y5 ( ½–×™>“ø&­¢³ 0®Ì0H]åÞp€a§© ˜7×274ËûLücçrÌg¢3|ç:.ÝÌmЙ‡Øî'Ë÷Ïͯ}1”¿Ô3òvWKóååOz…}}ô×÷øšAÉ›Žg~ñì93½M80´ÅcÔOûý4M"À˜Z¹eý%4e 0¶É} ²—‘¸9-! >ù ™gCrÿfkçì|ð¿"’.'Þ(—Ú¡¼:ÌÌÑÏh3ûhò,6ÌLìÁ´˜Èå M­=Ãr¿ŽcvÅ 0¾×¾  xœxýYpøì]ÔÚ½‰7î‘åÜï}¿ŒÙ™*ù’ÆðaŒšž/-ïìm¾™Þæ›Ì¦”/¯ì¤¿;É 0jz~7‡/qa ÞžX#žT¶ã>seVWogfý]Þ Jûú®ëÉߑԺEC.‘VÆŠ¼*€ÉQJ€ñÏl"‘C8ð.‘é?-&—öþw­m…´‚×ñg¤äÞ ñYĉ~•‚¦™æÁ¥MóÅïH§^—"/À¸žíf¦]ÔM!³^È\*ÓðtO4³¿ºw¨£»–”|fcj¿²BØÿº²çmCõnæEš-ÞºûКe^LMM³Ä‹Ì¯m”¡Ÿ²I’=Ž%ÿŽsçM‰…ÿ×c.³§Ôº„Ë×™:6~ E¿MÌ}fÊ\â_—tó;zý(r꘻H*úµÛ¬9¦Öž[ßÅŸ?o*ºF2ÀЋø­BJ’ ú,mœ¹Æ6©51«ÒÖÑÕÌ1,ðÊŸ,c®x±ð¾‘\øû…G˜Kq\Ò~•˜÷÷y~³¥_•&ÀðÔtsE¿ÙB¤/r§…| £ˆuÇó*ZšzÞ46·ç¦F²÷Yæs×cÏ5iYwj…m}ƒÕµu9WÏ„xÛ±[gêyîÌ(}Øø¢¹©1ûÚ¥¹¶&îûŸÒÔU2,„ŽÓü]§sïT··ô v½x][Wõü‰ÙvôÞhã¿*€ÉQJ€1šuöu6ÛˆÆXÔ5½Ì—µ•ÙÌ}“uÈ'¢’‚ìkçr™”èx^ï!q¿T€¡WÇÝdÆpîŸeFuäò\gD“aªo¿PÐ,ºˆóðýÄR+™y/ÂþW-=]»4ú"‹7øŠ^Òü&R¹ïÅùS§wI/ýØùFWæË柸ÉÂu×°w!³Ìˆºò«„¼?FŸzä$ºªžð»ömÜIæR3Çå)åÿëïëÇݧ¼:ö ³¢3¿NÈûíÿgï>ࢺ¾ñó|v÷ÿÙ} Š”†Þ{ï½3tP@@Tì"*XAŠô^E¤5‰Æ^DD@±ûä}Þç}êî¾»I6Ù’MbÞÍÿܹÃ0Ì…G~ù|w?wΜ¹÷L¹ãùqιš7v2f€!†`´ lì“:–4uè?¶åêòŽhè}ôÿú’mÀî¸c3à]Qm*¦7ÀÀ„f$ÀÈ)ÛßyI’ƒÎè³lç­è-wû¯Š]\釗ºŸõ }ÔV'rå Œ‚fdï×$~éhN`¨ßËsÚUyìJߣþ¡Gg?ÿdm85¨B3Yyjwí2²½ˆeI_7i>ÿÂúÜÍõŸtÜ|:0üôÒ¥³;VR×7ƒ©˜yà˜‘ÒfŠ`Þx ˜)B€x`à5`¦à@€×@€™"€w^fŠ`Þx K[WSf„‘—ˆ¼PÌW¦ ¼†–)éš3»ì Œ¼Dä…b¾z0½`àõHïÜÄÒ‘Ùkyq0üðn ÀÀë)*k:æ’1Ñ3Çò1_7˜v00Uô\2WÀÌ1€w Þ0ï«øÒæDk}fùœÂÒO)©Ìb–Hà}…ó Àœ&Ïæ0 is(ÀÈsÉ3 y``z!ÀÌ9 õ*«h{oɪÞnIJ̸«·gW×ÌÜ›ámk@W 0 ~ñ;Ó êJ«v&o1SW£+°Íƒ7f”Õ¶•×mK\¯Åâe!yu߸í{KK«Óv§Xªñ++[oL+̯nÉ-,Š qi’²ù¶Òê"AJÑ_ZXX°Šl,->¸Þ5"­üPECköÞÝzý°Í¹äˆy…E\=Y˜n0s`’ò2ÝììÕ8*jÎIe5e>ÎŽêÚfvAÊê›]4Õe…ŒÃ†ò‚Üí6–êÖÜ5…%ÙlEeÙÅÊ;ªZSbC´´ ´M\Ö•6%•µ|³J+s¬ÍÌUu-ÃvÕægG“ÂÅ*îùumq¡¾Ú:F&ŽaiÕ­ëýÍÆ7Iw]{€ÿjÑ eÍ[¼Ldy¦¬ºÄÉÜ„¥eµ¾ôPYuk”[Eß/©ª¸t‹, L7€9‡0ëø#-QÅS¸cqÂs_ÞÕö²£f¡¢~q}»/ÒPäÕ2kÚ–jË*hø.QUâÏ@³ØZ•½úµMã5¥û—Óc)‹Um,m­É†ÑŠ’üìpÁ!´ýs‹J6 nò›Õ¶ÂŽ÷(¿Š†=¶Š,/À¤FS{ ö¼ª´°(ÞVÒÛ\VS*‹Ó `ΡŒÛèL0HJ«š *ùŠêÚs3=eGŒ¼z0©\8z/QÖОähHíGÉÀÁgIÄòkSöÕ·ÓFA;0«¦µ ?åª'{9^’qÌi,¯;(ØCaUkiU¾H«TÒŠËvÉòæíÏ]F’³ÅňÞ6ˆ)ÊË¢F(ê¬E€€™€0çÐÆFE•¾¹³ª5Á@›Y0‹U½IeõÑ‘E,óíe‡2v&†ØÚ:Ømª  uÛÐÞgiÌúÔ¬ªÖœ´õ‹äÙ¶™õ뙇¿C³Ò†v;UÕ„²æÎT@’E€€w`Î 0¾9é+÷%gÇØPK_øk`äÕrjÛ¢MtøU2Ú–žgÎQU±É(©Ø»pôQVÉÕt€1÷µã_»l±ª'9%GU'8¿¨hƒàúKvlZë"¸)œß”_^Pc4/!ÀÀ;†0爎åšòúCÞêšFaÛËjkŒ•©õ'‚Eü+ŠJ+÷;ÙÚªêX†$Uæo#…JúëËëêlŒôå9z–¾+÷×¶åe†ró åÅ%»­ÍÌ9šFN»Ëj«”•±m÷Õ¶m[¦§c`ä´4¯®-ÒŠº†Ç.Ø/8XÐ0Mï} íy{ÇVË ÀÀ;†0çˆÂÄõö}¼Ë(gexXëÒ…c—Q–Wóß™^X_RU¿39Ñ„ÿ@eï»s*–TlLˆÖ³^SPÛ¶%Ð|Ë4fkÞþêÖ²êÆôôTW þÞØæA›Ò ÷×´ä/ p¦ W—Ò9„&Çq" [Ãÿ¡!ÀÀ;†S¥¨[^×À¡®Ñ,zÀ»S¢odš^·o‡?ó.€w¦d_Eóžô43¡‰mï ¼7`à½ï xoÌ•Ã2ÚPÑx8?{‰p¡àg.L֗夺3õ–ä5–”×`–«:¯Ê*oÞ³Éi±Ši•œ¼h˜s%ÀئT—UÕ•×TSâ g+À„6íŠpZ¬¤Œ0§Ì#¯žYÓ¶Õ˱¨¾}­íØ|Ïh€YÄV,ÀÄ”ð‹0§Ì‰Ã2\_ÑÐf¤¬w /3TP.&À° 7–×ÕËËS¿αØEbF¼‘6Ù^¨¨S\ß©¯I¶í"Ó‹Ëêš32ö¸šëÐ$á$ÎÀ,69?7?R8Àèú$–ÖT:êjçÖ–5´—Õ4§'Ž›B&¯é–°«¨°¦µ°¼jmüRrè×¶AŽc»,)7·âPQymÒú•J øýr€·2'ŒÍ¶ªÂ¢µdCË/§¼®QE‘ßÑ`*êÕ·s5ÕɶéÆò²š¶ôvd[Q'쥠¬éµ«¬¶ÆßÅICÏÊkEvYmµ[E–`²2ª"ü<µµ5FÍqEqmƒ—ÙXÈQÐH*?”‘odhlh°£²e÷ §×¶ÁcO]îî}C-×­•-)aÂOÞÔ0òj5­ÛƒÌÉöbUoV[éÑw‰ 0DhaÓöêQ$o¬ææ­"Ûzû ò£ÉF\Ió®HëÑʜ凒ýÌèÊY[½ér:À°Í—ì¯k_ê`(Ø33À°Œ’HRQä¯ÏQuØQVS¹ðumˆ%mXjO?„mîlfJÏ€Äf?À° ֒யÏRÕ&¶V¶ä¦Òw‰0zK ò÷…òækµ¨«{•×7)*(ûæ5n¤EA}{Œ.5‘Œf³§.;ÅE–—4’½MéB`*Z²jfÕ¶m aàü¢5‚ t¹‘²Šø6hûm-mhß“¾'::ÆÊl, €df?ÀØl­"a@Xy]=›7‹L|€QЊ-«©`i¯,*I$7wUµkig×¶yªSsºH€Y&`¬Ój³w¸ÊòÂI’½]È 0íQî¦Z¾éeµUº,þË$fµ`or*î¤ÜDYE|[ø„mûŠêÛ7Ç8 ö˜í#¯º§¦uw¬­ D^#œdƒ溲¯ 0ä±$*,)Ù›èDn:gÖ§-[WV]²wïò’æ]K¬F++¯/?”ÂåO!0üEüòªkKš37ð§–1 ÛxKYm5gtqŽª] ¹¹H^|”#b¬UT釨9g–VîmHb–Œ’þj’TÕ„ ×–ÊIõ—}m€YÌöÌn(¯m[Ç[3£éC¶sÓ©R7}w—ÕVù:9¨i[¸Çe‘¼a8ºˆ‚³˜Í6[YÑÐâÂ[‘Ï 0² š[+Zö$Æéëè[û§T´ì^ÁNÓ†„Òæ¬¤x==U]ë°äšüì8º$3ËÆjKeQñ‘B½%eµ5Š Ê¯ 0šÞûHÀ°àP£ôÐͦ±µøÊŽK’ö”4•ÕÊÌwå  ˜^—ŸE­ÂŸ ÀP3ÖÜW§Õ¶•WÓ—Q~m” ü7e–—Ô‘‡ÔnK\g4:’™å0u0ðÞ@€€÷ ¼7`à½0w©ë[Ú[9¸ÀÁ1ÞAË|¼ì…Ì#§l+Èá4ÔÅ·A/„PÃ)41ÆÅ¿Üh¡¢.`då5¸Ñ!KœÜ Lè$0Ät&#A€¡¯DJè¬"W˜Õ¦@zˆùVzm€)¨<À,Ÿ$†eJ:ëJÌ®9/ÀhŒŸ<6J…Ä=eu¿ðò@-ïH7 }ÿ(z¤E4Àx-õöàoþ‡,/À¸;XÊ)[p#âLÕÇÖÉ0Œ½H€q ‰qÔTßa$ÀpCÇæà‰/¡ã¬Ç_÷2`¨›*ªzfvž®Ühnp(=`Ú‰é*LF‚ÃZ±°sÍ)©!0ãˆùV?IŒÜ»5u³|BÙÅŸ°X‹Ñ±PAÓÅ;ˆšp%.À° ü£Ü-<¸ÁÔº%ƒ@?®­gX¬‹®±Zæf9¶èß>8ÆÕ„?…L$ÀЋøµœ"üƒ|ñ ™f¡‚V@Dœñh"Z¨h@nðÆ…Ä´A3Àx¹ŽîMŸlOýJÒJ‚o%˜?$è* ÀLzú~hdœ²Êi¸ K?¥¢á³\€0&«K37òWÅl,?¡§)0r7/¿± fëËm2§ÌP&Ä&4¥º ?QQJ) õ‹ëÛ½4Õù•åÕ2kÚ–Žü€<[|=é[b.ÈòfŽ‘ŽéNóÞ©PTÖ ±avç’Ñ3ÇÒf §h– mZfŽ (j'½qà *:Æ*Êü)d$À(jÇ•Vå.\Ì^¬æOO'žB&¯eë•°usz)Ù› À(ÚßXZµŸÞ¿¼z0¹·°²©`TYC{’£!³UPסþÊbåàó5;ãÍgŽ1ÑsÉ\}fÅÛ̳HÉ„¤ˆ¥"à šEõí,õdGŒ¬öÌsAb0 õæP€Azyˆ|ì™ç‚Ä`@êÍ•£ä–ÁìÛÌÓ8— ¤Þ\ 0~yka`@êÍ•ƒUû0%ÿ–yFH¤Þœ 0Ì^À¼Á<#$ƒR`ö1ÏÉ À€ÔC€˜}Ì3B20 õ`fóŒ  H½÷5À$üçÿúêÕ7ßýD#Û¤„Y à½À<#$ƒRï} 0ÿõõ«Oÿ^rá/4²M2 ³Ú›JùϱPDüñÛWýO¾‹Ëù’YS ¢÷‡/ž~Ã,˜:æ!zïk€!é‚äÁM²MJ˜ÕÞ 0ÿòø[ϯiÁµßœýý«ßþþ;fMx{Ì3B20 õ`Æ!æÙП„Kl«þNöì±[´¦ ¼=æ!™¹`¢/Ý|ô/9væ"å*º~õ§{z¾8Y¢f¼ŠÔé¹UÇ|8À»^t°¢ñ°ˆ¦ÌšÑe«1 g“uК”œªâº¶¢Ê†Ô]»ÜmÏ”4U—Y5]6³ð} ï•#üþUÔ¬_£:Coš19„“®hù\²¼¤™42ÐȈy—¨Ù~Ó`Æa‹¢ïþô·ŸlvQÛ6Õßžþÿóê_ÿ燆Ïù¡E8ÀLXAkÇ—™×¿{ò‡W_þåÕ‹ÿø¾äÈ×t¹Uå·gÿå‡ÿúö§ÿó»ÛÎŽVÞùeÖõï†þûÇ?üéUßðß"³ÅÍ^©Á<#$ó6FÛ~çõÞûé¶¢ÑbzM`¬V&å]—Z×Ç8!ÀÀ¬#&;%ÜÈÜ^˜ŽÆëºòSc½©";ŇY>[t=¶•7Zdlfmdí²&§¼®ÁQêjk˜ï*®Hc>Dت²æÍÖfÌò¹˜²šrþûkáèPXß¾#ʉYsÌùÃÑñ)o<œS×¶gÍëû³þ¦¿ÇæÆÓïK/þ•F¶ÿëëéY#`Ì÷}]ÿ/¯^ S—0Èüæÿüå§¶Ï¿õÊû*¢éÏ÷¿ùéÌ1*ŠÌd\ÛÿþÇo~X[õµcîWkO~÷õ__Y“8´ã¤Âµ ߺå~rðÏøÛO¹¼•6ëû~øÏÿøneÕ×Î…_çÜúáÿ~ù½/;tcž’‘$À¨éÛ¹.ݸ÷Dÿ³ £Åôš,À8¥_&åG·ùm˜u$Àdnòd–KFd¼e®nþœÔáÒ=M[áÊš¦´ºX¸ÄiwmaÁòñÕtÕ¦0&óúáˆ9`ŒCóK«‹¬ÊJ*ö2ïñoºº‰hÉtx_ u²¯…®Böõô\…Ld?ñ»ßÿÝ)•º+äúÿþoc‡ð:þýoÿ7M¡3YÛúoSZ¾¢ uÓ¾&û Oÿ£ö®¯ÈFQ)€%´þ›À=TáïÿúÓî}üB­_>þö§ö" ÂH?æ! Œ²–3I Ìh¡¬íÚ7òòîý^eÞÍcTÎIã ÔD~>@¶Ë}lȶS|FûÙžžϺnßn(Ë1×Ö#…ªK©(ÒsÐfyî‘KƒËLŒ„LB]ZòWyVÞ4àÊÑe"FÇeUù‘K]ƒO{î|¸1ÄžúÆÌë!uÖ˜S_‹K>ë'ÛŸfpɶEìçdû\ãRá§ÀlÆÕ/H =O@Í0Vp8AMÏÄꋽ#½}wUìÕxíô :“˜ ÜÆìÁMŸ½õûv’ mÇ¥›3Š÷×´ä•Ä.åW°\]–¹Á/rGozRíºøPRhµ¾¸¤¾½¼¾%oÿ&æþgE@AS~ö á.¸¦­‡¥¥±†yJQM[Ec[Qu³¶º.GÇuÅöüüê–ÒêéÔ7p|ACYãᲚC»W»iYg•% vâš×¸;Ö™Eýißuyr~^å¡¢Šºm‰ë4ÔE0[& 0ùÙa,*¹¥•l4ðYŸ^Ònl4ás'–•4¯µ÷ßZÐTÑØžWXÎû‘P3á®K-È«nÙ_R¶|©UÈ 0¶ÁÛrkKëíÍÎt64d6iÅ7g%û©™$vúŒµÍÐ;>%«¼¨®e_N×Å’5þM'7õ=â¶çÖ–Ô·æG‡xвZ_¾gµ›gBZnu3óXoï} 0´éš9& ²ˆ?¤î›«_¾¹Cå“ÿþê뿼"I‰ößúéú^S(ÀLVpªú&ëì_Ûz¿»Í H$À´¾þë«®áïJOý™Ë~1Ìú–Üû?£{ ¾üÛOMüðRŒyFHF‚ÃRÓ·vô Ö]} ˆ"övQi!ÊÄHE/˜Ž%Rÿ®7÷=yf£­oV:0òràÁPC}SûÅaRáÆù öhèìì~Ù?ôt™‰± À8%¶“ˇ³UÔtt="7Ö÷›gÊwøÛ²‡KCÏÉÍcí­5G®Q{»wÓYÏÀ½ð:Ùns!uzŸPG¼Dý«ôá²]äa-Ü~f3ʇ#½½Z?½ñà%¹Ù”ðæ¯*¼ç¨)dÉ¡f¶Â8ª:z^{K« é¾>[Ý4¯®=ÚÂDEÏ?¿®måÒ#Skèôš¶M!ö,^€)«iݪ«gj¼ñ°¯_8×F`t=’HÛò²³¢¢–ÙXÛ'áÏ´ºü¬Í–¶zæNaÛª ‹ÖÓå‚?ÆO`ü2ëóÒ7˜›[Úø¦T¶ìˆt>ú,âM!+}íìýWÔ ·£ž 0¥Õ%»·ØÙ;©«MúÜI€)®j õr×Ôµð\±¿¬¶ŠM}0ÌwT¶îZkffcí½¼¨¾=š¼>¼“Wšíhc«aè—ݘŸÁlÒláèx‘Ï@¬¥)KUom=þÆ¢æDD–Ô·Ä…šØy,Ë,¯«7Ô¤þ@)xÓU B‹Ú×E‡›Ú9m ÛÑTG‚˜Âü²m«cÌ-m™‡{{0ã0×Àxûþ÷ ®B¶ê‹õŽ»‹&0“U>÷÷¯¾ý±½ã/Éíß„•þI`·ªor.þõâ *ÉW}eù ¹×…7àó óŒŒ$fTøÅ‰'w®9Trh uÐsm$'Ÿ]û| GÛ„–ž®JR!ë&•pòBÈ6[òé•(’­Lùy`äEb¨;ý/"`ªâsz¾ìºzÈP“?¸AO!ûx‹7kü2÷ÂN²}º,ž®¶¼µ—Ü<¶ÓWÇ¡„l\þ8NYÛ¥äåKû;H…âžG#Oéñf3Ęþv¼Q~›õgyƒBÂ{€ù`ÂEüVÚúÊZŽ¥ ‡x;ײM.­.æð‚Êþœ±/ £ýE¥I,^yIE¦ l«lYgN-ŽŸ0À,‰]Ã<")©6CôBb7¥g”PϺ¸¬bÕò(Þ7¤p€± Šv6âÿa^Û.C0Ñèµ&¾´yw ÿŸ'M{o[Ûq×B˜Å'.²ˆŸØŸ½Í\WŸÅ 0䦭µÍšü¹““Ÿ}ÇÑñ&Ñ×ÐÕqN/­.\ Àaýî!vt€YÏÁ tݲ鉰Y|)ŒBòËj«é6»ï©¼éŽ;ªó2"ÕVoßËå}øoºõÆŠ‚ü±º¤Tçï£ê“C^%zézŽR`Þæ7.™ƶúïô@ŠÏ‰ïÿçwÔ”0÷Üw{¨š‚3Y…ί_]jä¢è¥óŒ~Æ7UWþª³ƒ_9ñÉÿëù7š;¾üâÏ?5–ñçŒi§~uóÅ÷Ñ{D Ò‡yFHf†Œ¶í~r×…ƒK]öuô \ <ÜÛÛ÷‰¶})<™D*Üzør`ä‰`–°w 57¬}…+HeÁ®èC"?Žl”O`6tPã9»mømu]šÉÍëV³5¬º†_Þîm×¶£’ÌÆ˜ÏÈÿûÛ÷޼¼usÜ|Öh,n†øs»‡?Þ­ëü!¹yõDŒÈ@êM6…Œˆ(hJ‹¥†]Sk37QßZîyÊëš +›øªÛJ« Xt°É£¦Ñ6T`ˆ%qãúvôêÞžŽ¥{àòí…õí{ÖQŸÆ¯Ñ³ñŠ_¾iÍÖ̽U­S0FÁÛKÚ33öÆ-_é`7n„œ6[O\d ™ªžuè–ª¢’=ʼSVKý…nÔÄϘí\þƒ²–K/ÀX®-+ÈëôóñŒ§þh ²ßË 0¬Ù{)–ÌÛ­©gJ˜údñšJý!/¶¤yG(5œ(Bð¦s šÒ¨‰d4]÷lÚY¼³?šŒÇ4-ÏQ ÌÛüÆ%3ÀX—ÿýë¿ü¨E-_ùÓË?ÿt³óÏþùÔ²ûÿý—Ÿêk¨X"0“U¨ÿí«‡ÝßZ¦}éTô§æG?’oÍùR7íëßýõ§§¿uËùʳü›Ë|uû,µâÙþðõ÷›ê¿vÈÿºøÞÿý_â~‚¤óŒÌ ¶ºùõ/zºk7\}pãÂó˜“#/—ì¾Bê§ÛSõ{ƯJ*À^å.XR"Ø`ú®xFv²ž7ÐÌz]€I 0ÉÍבí­Ã#/Âv]¾{¿WÃd5)¯_J…™Ï²Æ-Ee ­l”Іn03Àjê:F€˜ŸÄÀœ¢Ò-,5ƒ½µmA¼ Î:g5ì¨2 0ùûƾ‘^`XBŸ–¬W' 5£õ[RC 4³¨¢Òª\Öø•V[¸?7jYœ»—Ÿ¥Óž×üt€!ÔL]}—®^»=¯¨¡}ë ê«^Ä,czØøEü“Öl¼Ïr¡DAÛÃ=ÛdÇ|ˆàM 0®Ùô‹CL^æØj1oÿßï³÷$`¸eã"Ç7oq…ef€1Þ÷gòðú:*ŠXU~{ñùÿñí«ÿõ??Ô|ʯ&|å +˜~{õß~üýŸ_ ñýκ¯Z¿øñËo$å~GþÚÿß?~ùןþíw?ïø³ÉNª2}Íåÿóêÿò.£‘)ÚBJÌ3B23`ˆM—‡HD¹pÿù±¾;IÍ }O ió.*šÍ›B–Lý‘†­aÞÈ[”²ÓÖœ™èS`gµú(ÙèºRFO®˜,À¸Qk]N—ÄÑ;t›Üü4úN´O¾@¶Ïõ=íêHc©é_zÑ}ù!ï¸ü´#ÀlÆÅûÔºz2º5”„ÂÄ޶Gyc»£ÝfA/Ö$¢ ¨x¬3j¶lwÒF_–D†ÅëÛIÜ«“LzMÛ–ñT³è¢âò],¡ÃÑõ!ÝM{Þô*uÑ‚Ì LqùnÁN6U´ðŒnÔŠõŽ£ÔóÊ.­¤¢Ó»âÌ£j°„oåÌdFÕ Š$róÈ¡æÊÃWÉFßý.Wú× ,vÑM:Áë¤\§Æjú h¨‹^4ŒÙŒ” T3n]?_{èÓë÷©ØƒÂ&\įgÀï}Æ,Ø0-žšHÆ¢®Öè–S×¶=!ÚÔÔÊÒ36¯®=ÆÉ‚%6ÀäíPÖ7è1‹Ì¢ö–×5D‡‡™[Ù[»º¯Þ_ß¾1˜Š4$À.¾ª†[ò¨¡}…Ÿ›ª–±©sDJysiu =޽ª´9Åß^YC—|{W4´º:¨êX¸Åì¡þŠÏY[v({Û3s+]3—¥;j÷ç¬b¶aVŒ_ÄokbN@ äc+IDATç¿§¾¸,M/â 0bžû„†­iC2áö5ÑÆ&VæîËÈ‹¹Ä†¿ˆŠæ‹.:˜›.\¢ã¼‹´Ö…9‹åe ‡¢ýô ­]#ÓÊj+M´x‹øGßtUÃðâ†öÕ‘Á†Æ6öÜuEõíËù‹øÅ˜·ô~M^†IþøÏ‚ ct\A€÷ óŒÌÌ ómƒ¼uðôúxú*Æ'z *8¯Ü{ø|oïƒç·z{Ës,Æ_FYPMø2Êæ1md»÷Χšêº“µÒquÅÇWºï=ë|pôðú2Ê5ƒs¼”"W+rÓ³üÙ¾qa»àXÌf¨[ÄÔœ¼Ñ=ôìÚÕsñë`@Ä„‹ø÷náé‡ï'7ÝyL¡iÙ/IÊ(.¨mÉ+,]æCN`t\6æW·l9è,rY—²¯ª¨¶­¬öÐޜܨPj‰Å[˜žVz°¼®YK]×$hCFqcIUýÎ]ÉvæÞ‡ò²©K8¬Í)©oßÍ›G䛞[qˆ¼8¹©þÛªé£nš”UIêUÔ¥lM´Ô›+ÉMdy]Ëžô¶ÆÔà¼È²Éžû„†l«[†lÜC]V;· 4:”7en®޶{yãáåãÔ…­n–[×¾‹w½8Sîš9•ŵÍ{÷eùð kü›nà¿=¯¶”qe˜7óÍÌüÆ%ÀÌaž’y›0-TõÌ™—Ÿ˜FR`fè7.fóŒ  H=) 0ïæ!z0³yFH¤ Àìcž’A€©‡0û˜g„d`@ê!ÀÌ>æ!zs&À$ÿ–Ù«˜’Ë<#$ƒRo®Õ•=¢½:€ù|ø™g„d`@êÍ•£ä–ÁìØÌäÃÏ<#$ƒRo®Y ÂÀ¼4Ã/²00Ì¡³HÃæò'{æ¹ 1zs(ÀДÜ2¨ƒ5ý Å’K>äÓ8sL¤Þœ 0 1z0Ò¤ €ô@€©‡ =`@ê!ÀHÉ(°Õå9 åY,R ȹI ™5aÖ!ÀH€©Säh-\ÌRTbsTTUÕÔ£¢¢vòþ#ä&)äpT”XÊ$Ï(q´˜{€Y =`¦B­®ÌQ]°`ALL̹sç~þùççÏŸwuu?~¼’÷Ù 7Iá?þñ3gÎDG/ûç^@‚1™¹@z Àˆ§ÈÑRPRVæp®\¹BrËÅ‹ã7Ä øÛ›-ç-'/û«Ô_dƒÜTöU–U’]±qÅåË—IåK—.±ÙÊŠ,eEŒÆÌ*é †ùŸŽnSSI#µµúÞúr¡r2­22”‘ùy‘i‘‘ –3ð1¨oª'lhh ;Q`«1÷ï €ô@€˜Œ’²ª››;I §ÏœVÔT”Ý*+ó#®ˆñ½Œl’¬’¶ÒÙógÉNœ]\Xd˜Ù =Èù¬V "´¬ü“·§’à‘˜–ÈÞÅ–ùwF>™¢“aïd'e$‘]mIÞ¡mÈ<Ì4éAÎg]¦ªmœ¹7‹D§ §å D3É›[P²À%Ô…ì0}Ï5æaF!ÀHŠj†Û’·“°á¹Öó—§ÉL#’ùå‰_zmð"»MÚ²UQ͈y\˜90Ò@Øb537wOzìeÓ í'~áæÊ[ã*¯nÎ<:Ìé °XÛA[×€^÷2-3ǘ/Ø’¹…BK[O^ÛÙ˜ 0Ò`Œ²VSÓÁÓgNS«öÙcº°w°Ï_8__ß ÀÑmÌ é@“Ó°Qæ¨üüóÏŠšŠ’_sl*þU†¥Ë"Rb±kØ0[Ó@z ÀÐØjºW®\©i¬¡~ï…™:¦•l¢lcsã… ØjzÌ–À´C€0„¼¶Ã‚üüóÏÞoök•’ùNÆÐÏî׿ù¼¶#³=0½`¤ ñK?&&öâÅ‹r¡r¢acB—‘©”‘‰•‘Ñ–ûo£Úääå®^½-ËÖg¶¦ €ô@€ («Ÿ;w.~C¼L«hÒ˜Øï„r‹à¿7 0ÿtðŸ6'œ:uJQYS´10Ý`¤ €‚®3GEíçŸþ@ñ™?Š&‰‘óÿÉÈØÉÈ$ÉÈ(H`È*/üé§ŸTÔ4íi† =`ä4¬UÕÔŸ?ÎöžòÕ“ÿŸŒÌ÷£Ûº˜ŸeX¬/¾ø‚£¢*‡k‘Í0é°PÅÔÑÑ©««KÎ{j `DH`ä<äzzzììíªš1[Ó@z À|À6ˆŠŠ>~ü¸l¼DP–4ÀÈÆÉ~úé§‘‘Q¤ÌVÁ4B€0ÿ¬ µsçÎÊÊÊ_¥þŠ3^OÒó«]¿ªªªÚ¾cÇ-f«`!ÀH©‡ =`0…Lê!ÀH€Ù]Äïäì¼egFEãa##¿réÊÍÌ÷nŠ`¤ €à2ÊʾÊ̘ñz’¶û‹/¾PQQ5¶´'ÿ"ƒÜÐè­©Ù$Æ91ßÁײB€V0º.µüã²J²2“J%7`FK>bTfú­Ì"΢W¯^©©k0ûë0¡¸µ›I†a¾}¯e… 5¬`t]•5Μ9³bã ™FÒ˜Œ˜ÿ¢•þ©éŸV'­>yò¤š†³§“Ùšš-Á\2+©a… ë"ËÖ^sùòe¹à)/ƒóߌ\€\GGÇÒÈH-]#f7&à –`Æ @jX!ÀèºÈk;üó‚?ÿü³Ì÷¢acúýEÆÐÏî׿þ…-Õ½†©«h<Ì|ųB€Vo`:†ý S›¿KQ×ÕÏ'Õ-¹ý¸Þ7€Y>¬’.ßìÈb–‡ž¼qïY¹7×(êL÷Í f ¤u=jŽ e–L %}7f¡‚®«¢ž+£Ð…eENC“7>£@@YM÷Ò¥KõMõ²I]LùM|°ñƒ¦–¦sçÎiëê3;è  À¼fõæFÃe‰¥G$ážp¡xˆÞ&ô \' 0!Û —Øx1Ëg„FQÏ«wäe7„­ç‚ï%£ð ‰–ÇG·{3ë+p·î)Ñ5˜ ÛÀÉiذ•9?ÿü³’¶’Ì¿‰FŽéô…Œ²¾29‹Å2±t`vÐA<€yÍêÍŒ€nÐÉþƒÂ%“˜wFÅÄmâcDú‚ÞædFÀïÈÝÃ"™åJFa…G¯w=¿sïÑ©ã[éÂo \ë}ÜÓÓʬ?-¢®äC€˜×¬¦;Àt|ž•÷ɵg·zÊöm§Ë÷÷ð§é¥Õ}ÞÝuïYg×íÜô$‘º–tßìȧ·}[î Œ<71¢ºtn é¸*¥Ôœê¸ûäÎàð‡­y„'NÛ»{lw¬P€q]U×Õuå#cc¯[ƒIÞÁÇ•>㦙.Ëm¿Øß;üìZggjRÂTÚ Ü``Z—¯ÞûagÏгk×olçwŽÙæñ¹­—:žô þÙñ¥ž~t¹{R屫ý·<¾pùâ†èá]V¨>Þq´§³»·8/C‘QazŒN@š,À臞¸Õݤk":Iͱä%£%.Ü Úö6ܪnÍD€Ñ I¯ÿ¬óúàÓŽë72v$’ëä+½w>T0_{®·ï4y7•-Wîk9wáöãîÞþê²"mÞÇIõ‰¼Ú~éÇo=|Ù7øàãC äcF2ä­Á'äC{{ðqŽÿóChº·Ýº÷b`äùH“jÙÝs=#s_íèÈ<ëUeÇ®u =9{òXXôÙ®Î<úáaÙ‡Ï÷öÞim(Yr˜:_èrÏ-5]èíztöì©ÕKù™\xç‚H½ÅÚÚºú?ÿüsRFÒ‚’Ììñö,HÎN&‡ÐÕÕ³°séš““Æõ£·mÜÃ÷º×ñÉf^˜µ“³PbNNÌ´ç깆5dfŸÕt˜þ#u{wZú;Æ—õ¼ŒáÍã=ƒÏeî2w u‰É½3òr“ƒ·ðÃ5ÝëÉ9zÔvQÏãÛ_f{ø“mÇìë]%d#®ínwçÉÀs¿5¹'îwuR 0ÍWÎÄF&™{LøþK=·NÛ™ROpÂÛ¤ËX–¾ÃÚ%2pC ÙÞøÚ6#æÎû‰q+µ-£ó.÷Ýë¡#GÔñk§]<#ŒÝb“šûº®Wñ—Þ?òlS|‚±cDDÚé»C}úãâÇ:åîÈ‹”ÕkMœ£3o ¿Üãâ+rD-Ö®Îá—®ã™qdÃ*¡ì“k}g®öž=s2ÄŇ¾×>£ódÑÊàìc}z‡_úXP/… ÀhzgvÞíô´¤þÐþñλφ^ë¹O´e/‚`˜ÇÚ×ý8Åq¬ÙŠþ}Ã9­ÙP :ôkÏ÷_ºÚÕÚR¿ºc˜0JF¡Ô¡{GDF`¬ÖUv­÷Ô•ž3çÏ.óâ÷éÏß—ÔPøóO:îï^Gêe¹r÷üµ;—/_\6š}ßè~ÙwwˆìüÊ«‚ÝFì=|¶»ÿêí¡ã²áõþI€é½{>$ëã³wovwm n†Žeb烹;S¬\ÂÝ–í%ŸðÚÍ‘Ë$òy µâ\líþ,/^Aϳºëñ‰Úb'¯ë€Åç\úú ’30.϶s]ØÐ÷ð%`8ÖÛº‡ŸelÚl¢c`ä%`ŒâZÈGwuÜjSçÈäFò~EóNLá‹´@ºÉ«™;»º‘€áêòË¿d&·ñ‹ã¿p_âNvîäìl`jÅìšï*0„·ºªÈÆîëÃÁ\ºp{'ûì½gÑYu uõ ÔäoÞOTã­3իɆ#7—œïYþd;¼ðú¥#‰VŽ^‰EG/ܺqëvSi¦½#UcÇPaìΣWîŒ ªìyD˜- ×/}Xä\y¡çqïÞ¶²•îQ'®_¤Œkdþ‡;ú†¯^»ž“¼‚”Tô<* $i—ûŒ´÷?+p£zÿt€Q4 !¬­¾\~å¥é!E.éb®³÷&]Ø;Ãb>¤º}º.›®=<š£d´„džmüþ¨²ùú¾‘—+m½épRÍÿ³1`¦À0+øÄ`ÓRjpI×6ä@۴۽ǘ»¢…Ô"ÙPµßx}ø…ðŒªm†H€¹8ôÌÖŒú¸jûç•S"NÝ{þiþÞö«CO¤ëlÏëk¸"ñI$2‘s$qUáå{â#„˧`&<–ýžk$òq,7÷Ý}V¨ãw´óÂ.æ®hM}O7;ðLj’oŒˆ0äíÎÛ±ÓÂvÜ»@̦Ñ=¤Ü©ð¡â1ËÄW™7†¦æPH¿§4f€ úlðÈÖhz[ÑÀOctæîÐ]:ãñ¦“]~ˆˆ%—ô?xÔu÷!ßÀó;ýÔðŽ}fg×µR²a´ìDOíÌ×]y6Vóî#ò[z’Ówÿ¶`‡Þ-wÞ(À´¯[Jo êÛì¼Úu}l´Ðqßu:À¬éþ$kl<¼\t€9{ÿE_ÿˆ a·†_vœ¦Þ}áÌCj:¦é{ö°á溠xæ’-(X@½¤îÞmdbÎì”ÓH€¹;ô¤÷>¥ÿá‹®Žxb²³ÕŸŸv>|èê)ØKxÏÐC'5Ÿ”o8zýb†•£wÇÐÓ 7ÏÔÎáC+Ãèjqwß,³â˜c»¢éB`Šò>&G_îÅ_~#`½o>xíÉ¿7®­÷ó•®áè]¿{Eíc;¢¹û{n(h“H†™bz±B€˜ç¬¦;À/âgÂÀ.=ÝÛ÷¹ø67Uaü"~á³óø@WÇùÔôÜ%q›\Â>tÄõ¼ÜãRw·}Ü1Ò{§Ó™7½M@Û7¿ëÁÓ†ê†ÕwzEö<`t]*zŸ„[{ë>sæ¾›¹w×ð3MW›íW¯ž{ Hß4ÜšŠvné‘a$Àôܹ2ôdרð‹Â”Ì„ÇÒå¿v:Ù|ÍùÖ %Ú6Ù¦vœØ?ö"‹8}ïùR^óˆØ+ü)d4f€ÑðØœÝxêRÿÓógNÅðÇñH€ ©µ²c¸)‚xñØRÝ~æÆÑSWžíÞ 3ÀÏÀAÞX0á50ëñëa‚ÎÜ?ÃË"¨aœ‘'æFn 燎¤PÉ8öì„+ˆ¨3Ø)¸ù¦Fð Ô·O¿&`övÒfSçCá³õ:?ÀxVê9îÀÜ9Àü¤¦c’´e+‰[2·°w°eþU4“LÕ2ì6½î%qóf1éÅjüŒ½÷ÒÒkÃGvP¹B8Àì 0‚ñ“ã ‘×õ0;ˆÛvç¡—ç²ÞÁŽþYä[ˆ”Wõ<Ê âïÊ‘[pûÎq+^€9´4ˆ.$æÖO²Nž©ÞD—ˆ×¥ýŸYˆÜ{éÃÖΡ·††\½ÖÝêªu:ÜyvWÀ΋ç¬n“ ÃL=½å üùSg… 5¬Þa€Q¶Ü”šSɑǮ|J­x¦fŸ×w¯{ýÕá2.é»»ž|ž›~ýÚ©Tj*ÎÒ¾‘—[F4³ÍW“›kìùSÈ„ ½FÙbC×ðËý˨Ø„ƽºçÆêoä´ ¦;×/ìße‹õd÷ȄÐ9A÷¡ –æ¤ì^ϬžgÛÝg"]gîñKñ/ù¥À{õʨ C…aeç[6™®<{påÎÞ¾S ÔßûÏŠøö޼´æ­Å§LWÈH€ù,o½~xõíÛŸë%Ã)˜ ¥b›Þ}³fõÅ!WsÏ#]§ý>ºÛÌÜíÐݧIŽüñ“Œ®Gâ Ÿž‡ÇÚ†Þ»çè›$Àl#oG™7—c¹ùîð°ŸUH,>ÀŸü8e½­dbíA5õŒMÊÕ[7nÚï9ÚPEMi#êî<©ŽŒ¿9üÜ‹÷ÁS³Ï'¡Ý˜?ò¦éQÔ~Œú â´ÝÀú»SÈV¾Oï¦Þkg¨SCz¿¼Oò§­»ôàdÑXÛrø\võ: À(PsÉŒœ]¨õ0ç/œgé²dee¾cä1þ"#»QVY_ù⥋ôº—ÉfŽ ˆ¬ Ù×qé0µ¸…˜Â~ê(¹õh*&¢øúçù©==-d»¡÷ñδ+g먅ødW‚÷˜#·º*­xæ`ÄX€I ô·÷Þrkèá o+F€±rôî~5:s¨çT 5Ï-çæÃÂÄ“ç›ÖÚ¸-ïí¿´ñܽòÑP$‰.o”^¬`æ9«w`ئË{¾¬ØbædÉMlê}òQ:ÿ"Hcô<ÎÝAºÂ.fTŸ/æÜýþ¡Í£œV|x·ëÚ§~Q¦Þ«²?ìêhQ 'ÌCxæuÞé¿ mà:a€QµK½ýðeÑ®sÇp¿µ•ÝÃ/ÓèåÚbÛ lÂCúÁ·¾ÌIX¡fâk±»õöã¾Áë¤7©ÜÖ?<´:v•¡mˆk\. W›Ç¯v)ìê¾Ñjeã£i¿$¡àóþ‘—íëÆV&0‘ú—õrH—½ëÒ¹W2©f˜¯éòãõémÖ}ÜÕÑHWž,ÀЋøãšïœ,ËN“‡ÂÛ½G7'<–¢ÏÝKgoR9'ìø@eŒ©w‘Ÿ œ,ÚB6´|v_{ n Û<áÃé˨9ïèí;M—“óIµNƒc³®ëÁò–©Ùï#ù“wÙ·øšËÂñÃÿøÀ‰Þ‚.½+ƒˆÖ[ÝòÖÀDUöœo¡^„7 0lÓ—†^´ìµs u‰Í!ÏbOÿY7èv×@Wgåhe×üއ×Nðò[bî—Xßõø³2ª1“˜0ò‰ŠràO‡Ðò8Bê«z*N` ¸‡ï>ý°(ÃÊ1Ìo}MWÏ“®k¹ ÔÛ—Þ;ü4uÝ#§è•%—¯>xA/ëÒ ©xød׺ͦá©ßêwã}ò…wî“”³z¶$À|#¯n®¥£W_ß@Hcs£¡Ÿ¡\ œÌA™ß1âŠÀoedšdääH妖&òÀºº:]]½ Wí‹8~÷ÉîÑYaV¼ñ×Îl!.ÞûlßZ²áŸ×7ü¼€7„rvði¨ À < `œƒ*ï ^úÊ?qGît÷>.á-²÷ßþy÷õÃ~ž^¶åW|”A­ÙÐqÿ ï^+*ÀŒlá-â«éêøtÙÊ fÙp$†jÏ–ÏúÏÖg:8z¸„$]|²=€ºH@hAçí[ĆíæÞGWïx¹ŒkÒtA€˜×¬Þa€!¶ë*wÞï{øüÚÍÛ%y9‚? ‹=s_ð÷uËÄK¤OæoÉÍ Ù`GíéŽþ'}÷†´»Œò„FÑ0äøà³2VL`³¸ý‡/ Ü~Ö9zå×¶AØ„†lÛlª>uóAoÿ½>jõöXûy³¤In+ Ž^ì}twøñÅ+W¶o^#²7–qdî‡7ï=»|õúÞäD¯â w†Ÿ®›¼÷oñùÀÃdž†Ô_ôö=¥^Ök*>ëì;}µ÷Ô‰ã~vü Zâ Ëhɱ'I\þ4¿É Ë$úÈ‘®ÛÔÕÉè+JOx¬CwŸž,Z©@ÍÊûl`ä¥áï2c³±ùâÀõî;GUEœ»ßÄ«ñ;ÚE_…l`ä}%4[Þ RdÎÇg¯Ý¦®Bvñâê0þØ 0k·6~|öÆ•;…©¼—TÏ-µ­óÊ¥«ÍGN.óYÒ~säÃü•ëZ>Y'»GzF®\»2ú‰Úwä\÷ÝKÝ÷Ž´4šó&½Q€!tÓ>ë¼qÿéÕΛi[GÙ¨!—ò‘8˜0}ÙæñûZÎ_ê}ÒÕs·¶x?¢& 0$ð~~÷îÈó,×±Ë(+P×NXûi÷Hÿþe”™†:´Ó†ê“]݃÷[›+=3:¯_áš/ÛìÊÀ­žÛ%›7u><¼‘¡j·$ê2Ê·‡=w*~ôµÞ9Ù¾~‰ Šóž3ÌOòÚö m%ûÂ… $\½z5asÂBå…,–œ‡œlœì¯výŠ ä&Û‹½ˆ³huÒꎎRùܹsŠJ,/ßs[K{·×:F_ÁM÷¸£½w/¸;¹;Gdïè¼u¿ûæ©ì ÷÷ù“{ÏãæI×½û`„쇺ËÁ+±èãóÝ÷:yW!³s *o¸z¿)<~`Å­‘-¾>dÃÚ%òÜàÓÔpnPÆåÓ«H‰[äg¶ðîŠÚøâÕÞû¼«­¤èXÚÿðEŒ‡ÙŽ?Ú×}³Z¸=â1SŠ0óšÕ[€YGŒ »m¶rebšàfЇwéD¤ÍM‰[=6¦GBo‘7)Œí¶[¬a£¬®÷ëßü&2*úÔ©S?ýôÓ_|ÑÓÓóé§ŸVñþ#ä&)|õêÕÉ“'—,üõ¯C²XÓ¦¬¾Ùe—€µ ×–—7æ!àC€™¦¨çµ¿ª•iÂA­7…ÃÄ2YvõÁ‹Ôøå7Ó ´ËC/’x+Çtüëúîßæz)xyoi½{ÿuýhÆÃç+Ñ®*ÀdäµdÙúŠÊ*jU;{ûÈȨí;vdƒÜ$…*ªêJMRT¦5]`Þo02ŒÊi½ØÛ}ÿIǵÎ=Éc³Úw5º~¯÷þ£3§O­œüâ ó†hÇT€ È©[/T1ý€¥¿@A‹ ä&)dÖ,­keöÅAb$òÎMæy=)éó#¢ ®ÀL*­kaöÂAb£æ 2  €ô@€€ù‡‘X^—[äÞNI-Ìt 0SÍ00Òæ Fb™<·u=Þ^qÍ! ;Wa9Fb`¦”d`¤ ÌŒŽ ¼[©ÙžAK™=xc²<㙞[Æ?y™g·èéχ =`@ÚM]$ -ÚŽûÿÛ»¸&î„ÿãÓWëS[ “p$ 7Èj½O<«ë}¢UQ¼oAñªn[ëY@OÅÛ®ÖZŸ½žÝÿ³W·Ý¶öqÛÕÊÿ7Éü’1“|y½·¯Éd2f¼æÓßÌ0ròÔÙ‹‚:ÄÙ¸`c¨z¡icfFòÒA£§êý73`=0`½êMªO+ðÊÌ[š>tÌ$ú˜xL'ÍðqS¬ÌÒŒPv›Ÿ1ë€kÔ„t¡Ž;Í`šOx¹KÖNž•’Ðk``x¬m 2ˆj~ÏhÒ¥{Ÿ!Óæ,NY‘©Žè©3fÍÍ €õ@À€Õ1\/¦Ò…_#ÆËÄÓ€¶fë;lœE©«³6Û¬5Yù¬¯‘º¾€•]°6{ kÃÖ´NáüåFMæ^ƒc¨a0ÖVÇìtá· -ü£ÏHxeêÆûŸêþÃ=B5èm4cØß ë€ëÒ”z¡»…>Æ2É#tyúÇì2=^êaFÉÐãÚxà `¬¬…ÎÁŠ^½P‡8üàúº…:&s¨b¼ýB ²@?kTCK†ã†&$²#}d €ÅAÀ€U0¯^ ¥‹yÑÒAË‘ã¦xúG{û…H\½Ò0žþ1ô6ÜhÒ_ü¡g0fÌÊ~à `¬¬BcêÅ@ºPÑBµJ8ÔKS/¡\½è4L4½e-½ª13†3¦ ƒ€°¾†Ö‹öl1ÃÝ¢-ô‘VË ól¥{Ño˜ò”ÞÆÜhâ1ž1U2ÚóÊÌj €õ@À€ðé ¿^xÿ–7ñb¸[ôsEçxËÁ-Ô%€­ó`ëEoî…×0dþÀq ¥ª†Š^É4`*`u0 pæ×‹±‰mºð£…Š“#‚€ðhi¢^j&Ô“4 …°CŒN½˜ÑϘLÅ `¬ „Œ®c£_/úéâÙ>" ,†ü>€&èXo½Ô6LÙ˜zy=È %CÕHÆP £0NkŠ€£¦!õâÞAâÕùuPzùчY`9È %C• X2lÉàmhà `¬«©õâèN†¼|ƒéC%°LdÀ’aËQÖ †AÀX –ñ€©«—hº^´W¼x¶ð ê@!€%#ÃVs.™öªºat~ `¬ËH½èO¿«G·°€°œ9 8dز“0ì%þFÆÐ$LHD<}d €ÅAÀ€0™3ýbª^ÜBÉ/@úØ,¼5w*3»a‚0VÂd¤^tF{ò˜þu/5÷GV"`„Š Ím—µ £=Œþ‰d+ƒ€jÄô ¿^”!ÒLÍŸŽá7Œ‘I €õ ¿T² ¦.ÏþëXý2<û¥{ö%Ò<ú®õè“êÑ{GïÕî½V¹÷\áþÞr·Kݺ/Vv[¤LXàÚu¾k—dEç9ŠŽ³äñI"ƒ— a2Ép&ƒš m2ÀÉ0'ƒ y2ðÙáßkùUÀþB ¿ú®ÕŒ„>ªÀâ_ôJq”´1Llç ËÅÎÞåÝÎ"ƒ— an,“AÍm‘N>õ«@ÂŒ#À* `@ø$FÆx½¼+BÀ0"gc Ó†mþoƒÚ€ipà `,„¤RKúE¿^0ÂU0ü†15 Ü!® À: `@ðøÝRËäôË;Á"ƒ÷cj¦&`~Àâ `@àŒ?fjúå–@ 4ãd¨aŒNÂÕLÃ`q0 pæŒé €pI €µBÀ€ÀÑé¢QßôË;m0BÅL'# S0úg‘qÃ6 @è0 ltº°t§_0ÖÆœ€áMÂÔL/ƒAÀX ?]è€Ñ9L§^0ÂU0z SÏYdë€!3rŒÓ/­0‚Eok~À˜„Ñ=‹L?`Ð0‹ƒ€!£Ò¥Ó Pš€iÛ°€ Õ.#`„ BF¥‹F]½èŒþôKãFáýÞÏ¿:j†vÍ…»+*¶Ñ[¶€•å÷¯\;Ä[éÓmiɕϯV'Ëew¾¼P6›~aƒèîÀBpCMÂð†m €õAÀ€ñÓEC§^ê.€áŸ?f­Ógÿ5òN:LÒL£»C a$`؆1v Àz `@Àøéb~À´mm×Ì#óˆZ²ùHYåo**«~½5;¦š¬ôî{Ùƒø¼´Uƒú¼Û£§®±íû~BÖ¬ïÓ­}pdTÿ]dyÇÐí eª¸«÷Ï6þØåË;ÉòÌ€´KŸ_<Ÿ*Qúž½óå¥ ™Ü– š4èÏLfv2D¢9…¬òÆÙÝW\¹vØË½¦ ž¸ÅņD0FöÖ9ë|ÕýÇa*uÑ­G>¼v¡l~»ŽìLÎ’È í7ÉÛ!Y ߪL³9»„<\Ú1”,ËU+î=>W<£fæÄt²Ò+º,4©3Yî’},÷Pûêî Ñ´£w™Éëø0Ö‚Õ{(SÀ4WÀ”׌{ðÈMûÎ^»ÿ˜lPYueÕ´÷¢æž¸Q;}Á9¸¬—îÞ–•ß¿t>£ÿ§×Š ‡dU|¾çW½.ß{|`IO¹ª ÙøÔÞáÜfþ‡i‘Á\ÀŒ hÏ­'sƒºy\uÿ‹aAþÜJ:`ŒíÍ;6‡,¬í6‰ü³g¯Ý•7ÏÅ-+«º{×»¶…è’…s'ÆqËÝ4³:Ú&ùèúÃKåÙ\À”AÖxEå£%µÓSh.†ÆÐuüÆÆÜ†AÀX •.¯>`¤á$Q** ¥š‡\ϰs&®^Á1]Ã#Ô]†N[väæ×n] Î^Ð’ȾPÙ^î¥j§»·ø5gªîÞÙråAaÿ¨~{¯]8±Ÿl?/;5ÅC"çžòè4>ç“ÒóU*o}~ìØ¡9cûj_%öé½bë¡3•Ÿ_¹výÓ=[uªçg€G¥‹FÝùcõŒ#@ 4ãhNÀ° ƒ€°2OÝ*Ƙ¾†ep?n&³Oyè·àê½ÇU÷¿4= cð˜ª{÷²—޳×l°\sé‡Ó»e{g÷Å'Ùí¯é&ÒeT›(U¥j);µâÑEóWáîÜò—)Á™Wn=¸x¥”›uQ'$O]¾²‡,·×ìáòåÜ{Oø¤ìâõc‡ç‘åèÔ3ä©Ó8:±Ou]|Š<¼x6“þàõ¡ë`06­câêR/dòOíÓW ˜ÏsWŽ#Ï:HB¸Y‘‹—̘³XököF7/dˆô&&“½+èåKÛ¹ÍfÌYR©yáê vܵu éØgįf,ÞÊMãTî'+=»íàÞñÄуKÎëÑ%ÎŹæ[¥ùë ÅiÜg/c³§êþ—ÚsÏÀÐõR_ÀèÜC \ü€a`30ºÅ¢œ¨íº^8ô´xñ;JTñc·sQéªtv¤­]W®îéL÷ýìÀ¦mé rvOÊ>R©9íôé3Ûw^e÷  {g +·—hN0«Ùó•ss††“§vë¬ÔÕI©¤ xMèzAÀX'g©›£‹ÜÞIÒÆÁ™ ä!YIo 6`Óš0ö29AÆX½˜0u×À´UtäRa–Ÿ—£,‚[îêf t&.ç öïL¤7óÞ{¸8?•½Ã²nÀxtÌe+åÚQÍõýbŸ*þäPqŒRµê4»Ù…L{Í”KÒþëÚ€¾§øÈ‰s Þãvîžzƒ=íØYÖISDe{SÚj®Q÷O'ï»çãÜÕ2`èz10µÅcÙœ¥n2¹«Ýˆ#ŠŠŠª««=zT^^¾oß¾ÍY ÉÊ—/_;vlذáï¾kG^‚9Ûa(`œ0¶¢ûˆŸkƒõâmÞEüºã áfC„š)­$ßý‡)ƒL]Ï-Ž®Œ°¹È=Å2™\~êÔ)Ò-'Nœ=et—6Ò©c‚£h´¨UJ+‚,‡²î2‘X4fꘓ'O’KKK¥R™‹Dæ‚Ù€€°i˜WzeQ[ù§Uìõ'¥{frkÎÞöYyÅíGçË/mËI÷cëEDýGYø¬u{J®Ü«¼y÷رÏf¬-[~ã!铳gÏe®ü@)®™P’IÛyü|ÕÃË•×?ýxÛ°¨KC׋рÑù#0 åLþçå]XXHj$oKžO‚cGfÃ|Í0ÕFüƒav2Ž}ÕÝÔù…ùä…d'ÎR%½°&†=‹ ` 0"jÆÓÓ/MC× F¨Ä2׎;‘9z쨋‡‹h–ˆù™Ê~bDI"±J|¼ø8ÙIl\œDކ±f›Ö¸€™¼™2ÇôÕ/MF× F”îªÙ³g“ð˜¾pºt¾”ù#Õ'fú=#'MZ’Dv•”4Ó̓ÿF`506­Ñ#29ƒ¹xõèzAÀ©—¥K—‘äˆéc—mÇo’†³Ë´‹ëGv¸hÑb7ýŽ`06­)#Ò\CZE;CÈCÓ×½4º^0#–¹rs/]&vyëè[t4Î[‡Þê:¥+7ƒsɬÀ¦51`^º^Z.`|üÃB#;FÅwƒFkÖ¥Knî¥ë…óæ¡7ãij×ÃÄÆáš~냀°i,º^Z"`”*_’.!âÕá*u4ŽG;oïvÜu/ÍræÍnÝÌ¥3É[xzªpoe+ƒ€°i,º^Z"`H½ø‡DÓGäÐ R¹²°°ðè±£ìUûT{4i²´¸¤8??ßE"£?J. €MCÀ€`ÑõòÊÆÇ?,¤C<}8 ¢ôTËåŠêêj—ÆßsÌ¿e$ÞòF‰ÄYæN  P›†€Á¢ëå•LhdGœ9Öt®n§NÊÝ’Ëþ½º:š•hºhËö-%%%2®„±›†€Á¢ëå•LT|7úpÄÃÛßήMuuµ:Aݰ¿VÙ8Ïß¾äíZ·~G¬À•0V`Ó0 Xt½ `@,s1rä‰'û;òcà‡ “Å0½¦ôa˜·Æ‹a&1ÌÔ–F8öv,++KLLtp’П)À¦!`@°èzAÀ€T¦(**=e4³‹_† b ýÜ¢66ämoŒ›1îÈ‘#b\Êo-06 ‚E׋¥Œw@÷Ÿuíî#âú½G§O›:¸3½Y£½ù(>0”^ÿ*ŒÈûh|d½¾±®®ÕÕÕm\Ú0_óKÃ0.`¼f Ã$3LˆNÃÈæµ=í¯Œ½ÌþÅ‹ä­éÏ„`Ó^cÀØ»´Û°eO‚]+׬Š÷õ¤·ä¬ÞüaZê z}³SÇv“8ËœÜbÂüUÚ•Ž²ˆ÷G„ÑkÉ‚‘ŸbB¸îÊ ëwdæ,§7nº˜Õ[Æû¨œÜúed%ÑÏ6£¹›’"Õôzc"WLR×ý{ãŒÎÚ«TÒ›ÏòúÙÝèõ`Ûèz±¬€‰ aú†õŸýqå3í|ë6ðò7š× €ñò­go¦Í:{wI|½^W}?N¥§Z©T>zôHš`öÝ“Óæ¬ÎÃ_¦NÃ< ¶7DÒYòäɹ\á,u£?V €M{íCŽïû'Ž&Ç-$3Ö=o±€Y°± ­“T=J»fÚ†Ù›óÙe'·.ï§,Í,\—7yì0gg™H7` =+V÷šºt}Zî®´õ¹“Ç&:8±;Œ:kÙº-Y¹[/^àe쵺¤á™3ÈBÇ•==Ø#~gá W®[’±]7`H?,™¥ûB0ik‡,ݘ/w©Ù§÷Àµ‹FM® gÏÓV¬É)LßP0wæd©æ}#W¼ßiÄòœÂÔœ-sgŒ%Õäì9*=ãWÜË=†Õ,z-/`flØÙÅ­¦O¦¾ï¯ùa5È6ä_rÔû V®›kpÿîW.Ýoêš-k7.[¶Ð_®—$`æöè?kõæôùsfMtË]#¬YÞŸ{Vì3žû×¥¥‘‡ œ»jSzÖ¦¤©£'¬ßA¦ÝÀµ F„s›yõMå–ɇÞyHòêì-é™Ùã†tãžUD ›»&/=§puzz¿X6#µãÙyrúºÅ*Icª¬]/–0^~áf|ád®JsÄýÎü¹c|}ƒÕ¡ïWÞºÜ#²ƒJÑè&Ü@y~m½H3ïc&%:pà@bb¢=®ã· ›f9㤠]™÷azÚD²ì72mCÁîá}ûtê?,,+Ò ƒÏŽÏÚžµqM÷÷úöIv;ÒÇSÚ~*YH;<6aàÌìYW{­VÀ´‹Ó¶eåä,\™¹¾`ùgw÷š*p‹[®0ÒÀ(_wÝ×’€Y»¦oÄÜMãCÛqkFenõÌŒkÄ´5¤¤mœ=¥nä-ÒëgdÍ÷”)ìÅ>ä8~¨—‡ÁÀ0øZ^ÀNÉž7 DÄXHf^žD'ÌÈ6$ 'ö‰oë$3¸0Ù›·Fû’êwù`“¶18$`²6­ ñò°—x˜—·tJgIPfÞf®ý‚¦fÏľ¯0öb¿e¹»úÆÛ;¹†YN>“º|ª«Tîì5sÃÎašŸ.iÃÎá¾dA:&3;ET0òÐak7¬ tuÕ}G°at½XVÀp×À\»û¸êþ£åãú¨4síÖeî\2/¿È°¨h² ë4|iÙ¹â *Mr|<­·“aÅ· â;çV\ʯÝm·±ÙÎ!3¡öº”ãÆO'#{Û9¸‹Š=‹,¢êþ—þ~lftHPxøãדöX+Ò ƒÏ†Fv i¯ ˆNµ–ì*)Rí±˜,,ÿ`zçŽñªÀHÿ('ïեê½fn¯ {±z]öÝõ¼€¡q#m?mõâ>ä¡£¼ãº¬Ù$¸€qzÉØ™ ™ØÝàª-ÜÉiäX_{ZTÄ ö¸ß``|-/`ÄêIééãÈ‚2vÑêE½u¿1²ÍúÜnJÊàþIÀ¤®¬y‰[üŠ¥Óct_Nfѯ"kvå>p}îz²0$cÛOò-ÍÎÙ£n0òééï׬tö Ÿ‰€áWsÍŒgÕ«—t' rw{òÿ±»O䨬Mé"MÀ,>š$î䨜ÏÖŽ®Ë í)d!]Ç¿ùpVÇ(rÄùÊn¥—_TrΧÅ啟=ž¿íŠ6` {Æs -¾I&|ðÁó'gðöO¦SPM´˜¸¦no¾áU÷p+ɹ€ <ÿÃãOž¹°g÷‡\À•]ƯÜ}¼âÚÝûŸìÞÚ[“+5ãN~¢£'Ωµ;w˜îÃÃk®^TM˜ Óº¶^–Rχ€±2›öÚ¦ö˜1ïMNy/<•™¿[¯m v·uª ƒÏ†%ÎMÍû0;¯pñòM\Àýž¶líæÉÃìüíI“†{­îw¾ o¸·‡³ÇˆÔ½t×›0"g÷e7Ë\dª^«ç'†jÆQ5fnêÊŒ É)‹'§jfjûšs½:,Ï70_Ë¿ÆÙ}UÞ‰¼ëòí‡l³n}rÍ> íŸÌòY53QäǤfV§öܲ½ØoCÁ‡dÁ{ÀÚ%£œÜ­Ëž¯»±¨6`<»­Z•R÷­IÙ¦N!Ó^#ñ™ÃÍÈõ’’ºiéʵS§ÏÓÌú¼Ü¾‰+ÓÓ’ ^«6‰® bBÙ§÷bø/ïâÖDŽ>páäúv®#´Ï~c”Px©|CínRÏWéGK£foÕÃ…‰Ý¹•…W€ñèѵ»½:¼ÛäÌsg>›¦Ò™)½ýè½0n{ÿN»DGèþ84mÃhëEÕÄSÈÒæ Mºn ž5 §Y €M{í£=…ÌAÚàÆÙ+ÐË7Ø^ìܱÿÄU[ÉÊŽnJúµÚïÇA¸peæºüÝ‹Vf.ÍÚ±Ž›/š¦}ÖÜ€i+š—;6¸]bƶ8¥R0‘)y)C»rGÞÁ³7™ ˜±Ü‰:‰ ƒ¯åL[iÇ¥ù;„­ÍÛ¢pÑ»>D0³¹eƒû¯7`މ¨ÝU_nΊ,df§¨‡g,ÕAwc‘v&8¥îê&'ÅÒÜÚ˜‘5Û·Ÿ¥ ˜áìÙkìJ„Uk–õl«è²>7ÛO3ç(‹ÐLr¿`‘“rÊúãâØ³Ë0G’ÌHî­{Ä3éø™Ï{±—øw[v êü‰é*Cãåß¹èæÃ9Ãz5ý9{t±ÊHÀ÷Ò­ ÿsìæ£‰ÙsØâG.¿zÿñøÈ¿èE•U'»²/Áƒ––•íg¯ì'“Ú)†,ŒÚuåhÞÂ@ÿ`ux¿íW¤tŽ10*MÃèÖ‹ªÑñÿÌ0ãk'^Z3ÌgÔõÁEüV`Ó,(`$ä!—(a“×gçoOìÝ;¶ç¨•y®œ7@¤0ô³ÒP0i©³;v0)µ ˜_õˆ ²0~ÈÀ¨Ž½Þ_Z¿M-UЯÕû®œUi9šÒælS{^‡ Œ„ºk`ا¦¯]19Cså†6`b–åÏîÁ^+âì;;gç]üE†ÆIÙg}n–§T!rö¸(Ÿ ƒ¯¥F³(#}cê þÚtÆàþë ’nöbUß9¹K&ÆsëÉw2Ó®„Úk„´¸€q­ÎÛÕ;*Pä$ê·€|:$`<º¬L]1º­IÇÉwÖ]³l²\,wrë0cÃŽqÑj'eo’I콜щ˸“Ö´ñËC'gå¬âîd6®Ë ˜«·j|Q^q%kÑD•æí¿w@·ì}Δ_:ttÿ¤Q‹ÏܸŸ1¸30d!¸÷Ì=Å®Þ:zàþáìi]Æà]ÈLL§éJ.U—žËOK™¶ûâù“ìÉ`ãÓ>*»r÷üå‡>Þþ^(;ßÒgýñKW+ÄEy$,.%½ -gó¬i£Ù{ hÖÏØ`ðÑÚ»)Â%¯Ú”±¡ðƒ)CR·’€!:aáúµë7gäå IÌÐL¿~S¥å¦gåLú7ÑÔuÜ’ÕYy W¤ ì;+£0ezŒîm”­Ü2g©¿É6ƒ®K 0A¡p}ùò¥H,bþÁÏ Ã¸?dÉ}0L/}W¨íiaäÏŸ?'oM¦ D›öŒ“¹È|£-{ïµ›·{šuáÆìŸG=IvöRéDÇrR ÌØ6ÖÇdÀèCÀ@Ðõ‚€±Ìmøðá'OžtìkÞe0MÇ^ާOŸ$R¬ð¤×X<º^0¯Ÿ³ÔM&wµ³³1bDQQQuuõ£GÊËË÷íÛ—£ù" ä!YùòåËcÇŽ 6üÝwíÈK0'ækhÀ8ËÜÕa+áæå×®}½ÀâÑõ‚€y\äžÎb™L.?uêé–'NŒž2ºKi‚Ô1ÁQ4ZÔ*¥AÈCYw™H,3uÌÉ“'ÉÆ¥¥¥R©ÌE"sÁl ˜¡¡ãéàêჀ°íC"ÝT~ôzËF× æµq&ÿóò.,,$5’·%Ï'ÁDZ¿#³‹a¾f˜j#þÁ0;ǾŽênêüÂ|ò‚‚²g©’Þ?€®ŒÂ½þô @ðœ¤n¤aÚµÁ¹d (t½ `^±ÌµcÇN¤@Ž;êâá"š%b~¦rÅ„ŸQ’H¬/>Nv'‘£aÀ3†áx´óoçê(vEÀX!7/?’1ä7€ ‰ìÈOuˆ#Ãc‰€°˜€ÐhÿÐ(òÛÌ/8Â7¨ƒ: ÜÇ?Ì»}ˆ—o°JèÑ.ÀÝ»½Råëê¡–»· EÀ4¥»jöìÙ$<¦/œ./eþHõ‰™~ÏHçI“–$‘]%%Ítóà¿€¼d“L†3Ôdh“N†9ìdÈ“O†?ù%àÝ>˜lÆ]Ä€€×ŽD¢˜EêeéÒe$9búÄØeÛñ›¤áì2íâúÇ‘.Z´ØÍCE¿#€Äìí50Ô/  ¼ü#’– õ°È°Ý£sûFo¶]>ƒƒç.˜Kb£ËÄ.o}‹®‘ÆyëÐ[]§tåæap.„€!â‘´LÀ(ƒüHº„mìî·>Þ{]”ÍRNhß©Gnî¥ë…óæ¡7ãij×ÃÄÆáš~ !`@ˆøG$-0¤^7t¡èmŠje¸wwÝK³œ9F³[g7séLòžž*Ü[x0 Dü#’ö̱Ýéz[#‹÷(Ü^xôØQöª}ª=š‹4YZ\RœŸŸï"‘ÑŸØ2 ÿˆ¤&l…­Ÿ9F¸§ËÝÕÕÕ..¿ç˜9~ËH¼%ä$‰³Ìþ8Àf!`@ˆøG$-0ѹ}éz[£ŒS*;•»%—ý{/tu4+ÑtÑ–í[JJJd \ u0 Dü#’–˜Í¶0ª•ávömª««Õ ê†ýµÊÆyÆøöð%o׺õ;b®„"þ ¦H†z3òĉŽýù±aÐ#†™Å0‘ #c˜ÿb˜Ö ãÁ0Cæ$µ¥޽ËÊÊœ$ô'¶ BÄ?"±¨€¹ýÓÏ¿üòâ…ÆÏ?}ûà·Çç´ôÅ3‡~|¶dsgÝ5A«ýðÍ"?¼üϿͧ_R/Y¨²¨¨hô”ÑÌ.~iökÆèWµ±!ol{cÜŒqGŽãR~¨…€!â‘XZÀ¬+¨¹Û²:§ßæ?}ý—ß/¦7ÓÕ.3†^ÙhÁ™ÑtÀô:óà·÷&“…FLz¤¢²ºººKæk~iöèf$ÃÌa˜†éË0oÔÌ;ìbüíieìeö/^¼P¸ºÒŸØ& ÿˆÄb†è|øæÓï÷…ôýðaa7nåªok–ÿû?ÏGž?ýÃÏÿúþÙ×G/ÍÐÝψû|rk"YÌß@Ê!wKW²<ðêW~ò÷º¸ùWÏþá‡ï¾}úç²ëiþ™ìösÿùÝî–Þüú›3öÔÌ¢{OþôU~øÖÿðôß?=ûóÅëã´£ÎNÜñÕ½¿?ûá¯ß|UP<–¬9ðôÙÞ=ÈBϲÏùåûÀÌh²œûÝÓ²½}Ýç+=Ý=z$M0ûîÉ/¨5 u&aþH=kˆ¤³äÉ“'r¹ÂYêF(`ƒ0 Dü#‹ õ†>ÿøõËã¼Ìÿ|±Hpá‚ç/ Õ4§ÃÎ#O¿ÿˆ,$Ýyöý¿ïI–×}ûCÉÇ}º•\~ú]YÏÜŽ~›óÃÕÓ#¼5ó÷oË ØÝr3îòõþïAnŸ½Ï=üê&›CÚ€Yô‡¿ÿî~VhVLäŽÿóüçeù]†Ýý××Ç“§æýõÛÿ}þ"½ K»Ì.ßþò¢ÿ†8Å¿èø˜òòrÇó.€áyÆ0w&¢¶^æ9µ!Ž+**"""ÚŠô‡6BÄ?"±´€yñâ矞³^V¿üþŸ§‚5 a,`–l®©G?ÿ§gv¬v?êõýž½xž=ãO_ï;|ö›¿¯õ^ÿ·ÿéµ!6ýÛÎZóýD|ö‡ïvxkæÖÉaÜJ0¿¾töeõ/ã6uäÖPÿ¯_~¹±æâœ±þüèêØ;q»ºóïo'Üÿã­ÒaA›žýxЬ‘Žô:bؾ}ûD£xåé:³.ÜW+†ÙKmf„h”èÀ‰‰‰ö¸Ž40 Dü#K í Œîà½ßüPY:ÔÛxÀ ȉãV>ÔbÛ÷?nÞšpéÙÓ¸#~úù¿7¯û¿‹ÈúÃ?>+ØšÀmT÷ìÙoMÀœÛÕ“[Iæé¿ÊsÿôõW·gqkx£Îü²ú¹Oíõ>ûðÏ_%ùdõùñÅw6Mûñû½‘»Kÿñ¿Ë{”ÞÿÝçSÉÎ}ÝçÍŸ—““Ó*¥¦ðÆaŽQÛ×j~«7&''·qp¦?°A"þ‰Å Ñ·ü‹?=f/n!³»6`>yú¬.`6 ˜A•O¾¨XñO“å’ÿûwjÙƒßÞe/ÄOÿö‡s{k¾Ÿ¨_ŸzúýnoMÀœÞñ·’̺-]ýs“Ÿ¾øqb.; CÏÀ|÷Ë/Ãkg`F?üÓ£kìynß=Ý}ä*‰õ†÷úé~ò_¾Ù·‹Ýgãæšævd›æ}†y«6cÌ» ƒ€ „ˆDbÉÓóôoþþÿæ‘…ä¿}ûy9;›»wã‹ê—æLháîçÿùæÏ_Í$Ëãžüå鳟?Ñ\dß½´òé¿J6Æùæ ÜÿÏ®ŸåM wÿ¸Û¿ûÛ²½ LÔ’?þã·÷Ò3£Ã¶%ÿá??¯ÒÜ$`À•Çÿ~úÓ©ûå³Ï~úëógqëÙ;¤5þ2]Ûjæ †y@=kN! ÿˆÄ’&æãó?ÿt/&+&|gÚ½ýó›¿ûñûë›ÿþ/s¦]f·¿üR¾¿YŽÛwù——Ï¢³¸.Ç/¨<÷ǾýæéŸÏTeÔÞ…Œuvâïÿó²uGuuõ˜ì¤ÍÄßý•»‹ÑÔ‹ø9_Õ £‰z .â ÿˆÄ¢Æ4uv÷öÔJ˧½²¬»ŒÎ Ãv2ÌúkÖêÌj{C¤]¥¸2èBÀ€ñH0B•¥ðV¾|ùR$1ÿàg†ao3L†¨ù+–s&V§^Þb˜ßQÛÓþÂ8Èž?®PàYB  ÿˆÓdánÇŽ3u ;µBÇímbÑýz“a¶SòFáã“Æ>|X,•ÓŸØ& ÿˆÓ¤Ã¼‡¿?âäÉ“Ž}Í» fà cÍ­“I´Ø3L(ÃÌf˜‡Ô–F8ör<}úôàÁCœ¤ô'¶ BÄ?"AÀ´ÕÊp;‘]uuµº›šù‰Íï)ãÛ×¼]ëÖ­Å OúÛ„€!â‘´DÀäÚzÀÊ8¯Ò“¥ù…ù¢¤&ÜLÙ¦·5òŽž[ Ž—Γò«£ùHæHJJKrss]$¸|ô `@ˆøG$õŒsÓF¢™„ ÜP÷*m“jUï`Ÿêêê¤%Iv™vt{4]šÝì³É[xªTb9®~=††æ°dü#:`ì^AÀ(ƒüHÄm´õsÉ”ýã»u$×?î­CoÑÒoî{³ÓàNdçQÑÑ.R\ý|¦Æ‰DÒ2ÃaÏ%[Ñ=:·oôfÛ¥N ù`;IÒuJ×7½IwHãzé>£;Ùí´iÓ¤r7ú_>„ˆDRÀˆš-`€ãæáµhÑbñâíÖ5ùdvivÜÜKJJŠ»§7ýŽ:`¸[!`À²ñH0¯…›‡*)i&IŽ™KgJ“¥ÌoùMb®'ŒtŽ”»îeÚ´iîžü7ÐBÀ€ñH8¦Fs¦¹É•±±q$<ŠKŠ%ÞÑtóŒêž2¢©"™ìDé 9¦éLÝ10üßx-øG$5Ì ˜¶˜fä,Uzª¼òóóIlپŷ‡¯coGfÃü•Ê­¿0L!ãØË‘l\¸³¼0//ÏS¥ÂUûP/MÀ°¹Þ€iƒ€‹Á?"AÀ¼^.rO‰L"‘”””)++7cœ½Ì^ÒYâØÙQ4JÔj~+‚,‡Ò®R¹Ãø¤ñ§OŸ&¹ˆÅ.9î˜ æ@À€ñH¨€ 'ö¸ój8ËÜå ·Ö­ßILzäÈ‘/^¬¾ `r¿ÍŒ::¡¦žI˜Övì¹dä¨(4ªX,2HÙ3Çè?ÿbdú–‰tRÃŒ€á&a¸†yÛΑõ.ë¿Þu`½Ã±oÅi­%ÒzË´·l="t莣ºÁ¥kÿÅÒŒ>ÍHäF%7Bkë…ž~10Ïc¦!ç‰0ÐÜŒ\cì,2#“0¦¦.cŒ” 4œ^·Ô¦‹Éz©úÅœóÇ0ð:™0F&aL6ÌÛ\ÃÔe U2z1c }Ð` è± OgéuK]ºÔ[/¦nÔ#`ÀRQÇ(5tÆø$ŒÉ†Ñɪd ô ˜AwñºE/]ŒÕ‹9Ó/ÆÎkà0" ¼üc”Z¦&aL6ŒÉŒáÇŒá°}ôxá+:]ÞæÒÅX½ð¦žé6`8ý"BÀÀ+`ì,2s&a¨†¡3F¿d ÄŒ1ôá€í G„!ܘ¢º…—.üziÂô ,u¤RK¦ ÃϽ’áW}ˆ`Ëx„>¼nÑI—FÕ‹©é—†Ÿ?&BÀÀ«Á?R©£0ì‰dF†Î%SOÒ€qô82Ü-¼t1R/¼“ÇŒL¿°Óðé^ê`¥{@cd¦¦ax÷%3‘1ú=c$i ~ì¢G–tÑ©Þu/ôô‹¦^ Lã¦_DxeøÇ+º £7 cªa fŒNÉéh$ÞàÒŒ8:]Ì©6`ŒÔ 0š~!`à•1~)¿#u"™¦aôÎ%3˜1:%£3TÏ@ãÕ +ݱV7ùéÂ;sÌì“Ç0`‘šÒ03F§dôcÆPÕ€Yèq¤-5Ýb0]Z¸^Dxµ¨c¼‹aê2F§aô2F¿dôc†‡>=vêÔ5íä¥KM½è§Km½˜êw…Ù0ðJ™œ„1Þ0TÆðKÆPÏÔ‹>D°ôˆ0Š7Ðèn©I—FÖ ,ÿ†0¦3¦¶d´èƒ-ãè5[@SxCŒ?¦Km½Pc\GëE„€€WÏô$ ÇàTL]Æ)#IG¯ÚÁh<]ê« DS†_2fô 4Þ 3Ø--\/" ´sFR_Æp¸)êèŠB‡/|ÚÆ€zÌI—6ÍW/" ´ 3Fb^Æðèo@ãÐ#Ë(3Ó¥M³Ö‹-Ëü†‘hŽQ2ð Õv‹YéÒ¦¹ëE„€€× †áÔ” bàµàF_ƒº…Óìõ"BÀÀë 9¦¡ŽuÌS{¥=¨¢¶ ÑtGVÝpãÃúÕ¦K3׋¯æ‡:îiÝ#-h z|5 7®_Eºp0ðz5WÃÀë÷JÓ…ƒ€€×®)g”€ExuçŒñ `ÀBÔd J@@tN{åéÂAÀ€¥©+Ä €ÒÏ–ì- X¬ÚÃ#” €Ж–î- …^Ï袴 qèñõÚ‹…ÖA÷0 ‡Y‚ñÿ¨ªj¹SšÉ6IEND®B`‚qtrvsim-0.9.8/docs/developer/build&deploy/media/obs-ci-step-3.png000066400000000000000000001265421467752164200246360ustar00rootroot00000000000000‰PNG  IHDRB•DKÙƒ€IDATx^ì݇_ÙÞðûÞ½÷¾»wž„Ð{ïEDAEDD°¢"X@QQºôÞ;R¬ëÚÛ²¢(½©îbyÿ›÷L&Œ1âˆÂyîçûÙ;9Ó’Iþžœ™É?”TµÈ?ØMß2ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b (ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b ¬3k{gO7O?øf‘7ˆ¼Mì÷n1_ë=ýÜý*!ÆÀrÓàé‘:•0³v24³…oyƒèwмeì÷qùÞSîûe ÆÀò"å©•½;»x…oy³È[Æ~—û=å²_b ,#ú¼#vÍ ß2ùgy-ß{*¿’c`}­óŽ`%Ñgy±ßÍå~OåïWÒ—Æe_ÓÛHxÄFq¡A&ÈCÒHf±—€UÅÍÓ]­Â·¼qìwsÞS9û•´ôCR /ÈÜ0Ó™N/ldY`ÉaÆ4èÎÄëÿcŸïì|‘s!JCÇ^K& Ãýôºwv°ç~Sâ+ZÊê¯J)ªlLJIݺу½übTëÉŠ‰û\س¾-êúvÎëLut˜i3¡húc×­¾mØíðí[Ö’–œ8±¬ï©œýJZbŒ!á„~‘,¶´$³XŒaÜ+ÜÍ^K&‹1u­‘1§%œ9v>¯¸î ‰%qaîìUdR”£n°—<Ïp}Ñô2½×̽ؾâ¦Ü¬Íìvøö-kÉ ËGNœXÖ÷TÎ~%-%ÆX"g†,¼„$ÃĘžöÚø é´3ÉÙ¥7èöñÙy¾ŒoîÙ+Æ”Ö6°Ûùa¥uWÈ,¾§1(E‰1zÞÉó4Ói]OjÚŠGMKàÙm=OÚcÔ²–¼°|äĉe}OåìWÒgÇîã0’–0&Ãʶ†Àf©ëÖ ýIϺhcÌ^‘í;ˆ1Ä΂K¤šÐ×eÏbS”cwº¢¸²€ž¶­(©*af­á{ŠMI.¤^5b €âúÂ’×ÂÖå@ô©¤¬bº$ á‘Fö’2½œ~G×Ô—àsïGÇZjò­ìØKþ]Š^·„øHNHºØ;w9Ü—½ƒ¼®ggvû—“'¾ð=•OÎ~%}vŒÑÞfÆN)\Ù[“cÑ£ªÞ>IÏJ¶67ª 6F¦5ÞíꙘï¾y£ißvfy™1FEËî@råÍçÃSó/:{.Uåû»šJîEÇe×ÅÚÛmýS#³oÇ&ïÝ»u&j×µ ¨hÙL,¿ùth`êíðÄÌãG“㣄šiMî³’INŒY—UOºîf‰£ãpèLNNySQyí…äDï¡…c”5L6ìŽMÈ­.ªiÉÌ/9r`)ÿ£qMsŸˆ“ié%õŵ­ù¥Õñ§O¹[KžßÅs 8—^ZPÕZ\u))%y³§äêŸÜ¾$rð×m Ž”4•ž§§QÓIdÂÅžJ§ª:~1§“ˆcñÔ( b €‚ZZÉ›_qÉÕsã–ˆürê;ÍØ„ôðƒ1™ I£_`{-6c®îßå¹!€â»5èPjçô»ß«÷±—ü»È1AgÒx»±×b Æpò¹§“IúÜSË1j†Ῠ<=ûÚQ@ŸTÆ®íbr6£)ý ½ ;Ƭá¹Ö¾˜‘Z~|f&>ĉ^€oÓ=ó!»3nf‹· ¬nTÜ>Í^ ëqµ¶øÞŸxV2-cxÇÊšKkõb’®×‘âº+%U•ÑÇãöD'$–R÷8¾Û›ž+c”Õ #/R)(=9eßÁãÑ ùeuWŠJ³mÎÊS7Ø’Ss™lÿĉS»÷ÇŠË,ª½RZSk³El#²Èêy9™ûEï9zöbUkYÝå`[ñhØ'·/…¾ f1©Ç?º™‰‹eˆ1 ki%/UÈ“³Ší\>ú‰òðlJ.™Å%ÉÓ¸ù£Õƒ/ ¶°—ü$»OßbØÈžÝ(ŸüóIˆ1\hz±ó‰LzgHh±‘l$«³·¹&Æt?­Ž;—"–^x­—n¿z1D¼äŽ&ºå^i’‡»‡³ÏŽìÛãtK†èöVìÔH]`3>÷.+v¿“£‡wPÌÑyÒ26=é)’=yE/{öئÀíA{ã½z#Z`BM4 c´ù ½Í'U©¾ü<ýC/4öÓ-Õ[í¹<+™dÅž¦¾ß¾Œ2êÿµt£²¦ÕÅêËEeÌ}½T´,ödÔ—ÕµzéQÃ5R1Æ|wyx|»8äÆ^‘¥uW2ÄÄ:¦”,°ÃÁ„YÀÀ'…´Äz˜SÕøY5—‹JÏ3w‡Ó0ÙAæf§lä¸}™T…›¨µ\¨a:UÁ2}B4-1@¡-­ä¥¿Ü$¼|·²çZغxCrÎ'Ï.cǘÀª¾þ¾ zÚa{|㽎îWó/»_f%D²W'rû_çûä_kù2ÕÄ6˜ÔrnÖâ¬âqøI_w™°ñ®è¯N¾>0û~ôÕÔ­– {KéóÖŒÌ]N]ÿcpvtúÏgO£·ÑíòcŒäIe»“êõM“ÕtçÐÖut#y>G‚b¯µ OÍÜ»wû`€¸=0¶à΋‘Áé?ÛŸý¾Aj³\ȉK{O9’³_IŸc¤bÉbè C$;I¶“ÕÙÛ\Œœ;•ϽÉ<ºSyaÉ ]Ô¸ÊÈ«n­…"[UÇo|îýN+±bŒ²–ÍÀ,5ÒÒùø³;_qê¸qŒ 8SRW\Õ˜—Ç,pºS:5rê@„»Ïö˜¢ÇdÚÏÎÁPczÇ{íÙå¾qçù¦žÑW}Öö®ñcsó§„¹®õß“ttjÈÚB:V}’œ8±´÷”#9û•ôy1†ävhY,ðï@ZØÛ\ŒœC uì°¤khþ (“ŒÏL?~ÞËòYQbÅm‹dúáÈȳü“â¡’ÎÇâû8+«ë9mÙs>%¿¦ùá³k:Æèy•2-cS“×.7:qt­3s¹È§Ÿ•L²n¸}6»¤îJqE‰§èÆÄ„ýÙ*ÒowlÚB_UBóÜFs2©É³†ç.Ї%&‚“jI;=úDSÖÐÓ·pvX»Ñ7h߉ìÆ1FU{KRh#w…îrvrÖ’¸ˆûö¥˜…KŸƒg¼=·¬î²Ìû°!Æ(´å+yϦäìvI’—øÓž¶¤Ð³6uuÿqžYÒ3öþjöHŒi¿|”ž–cH{€½#ÝrkôIÍn©í8îŠ=|@<®bb·ƒYžcŒ)è}7-x¡Ý¾qø¯¢¤D¶s-6n7²\÷äÕÛ¦_Ÿ&’sèçICÂÚ°F‡>INœXì= ?CÊ6ò_¦…¤ÍŒÂjBòÌ@öb’äìWÒçÅ©Xb˜å̵à˜ahìm.Fæµ1êB‹Ýíâàå %êô* ©¦¤ñÙ×J¬#°­d/Éèé8¥D wÄüÖûšnéïïomi.í?\¸#0/èTéÃ>q#£ýÁeOC=.ÏJ&Y'•Qt]’7;;mýÐCt¹¿Ly9Ô¹v’1FMw{1F ¾YFEÛ>ôxFA-õë4¥µ-ÙÑÇ©‹a˜£¬aì·;6qá¾a¥µ—NŒ¶E.Û—âáCåœÐÜÆ’ª:ó„dÖ—T•“‰µë}¥FŒPh‹•¼_nKHDrV1»]’Ô%þ;gôϼÏYOfí{656=×;:Cë;<ÞÎÞ‰17¢7ÓÓrbÌèd?³JPë;Æ®A‡ã’ j®þ&ºHû³bLïÌû\o¦=ôÁø³kÔ ÈvNy¸2í'^Î<* 5²ò¹ôbvdl¨¡®&îX”óÂþ,râÄbï)S2-tb)û8´°“$g¿’¾(Æèì³R’¸`æ“æËc ¡®¿›nïëʵðúD×â÷ug³7B“1O ÞËøpš–$euý[ãÔ¥2#c¿or …-Üí£6QX­ :œPpé~Ϙh¤…xq÷8—g%Ób1†H®j-*K£§Ec#ÆZ‹Þ2A2ƨ ¼ÉtÚ‰®›—žÕPVwù@h°…™9}昺>5¶ÃÄßÔÑ}ãÎýq¹eÔifI*jœ¶/¥Hôkž2•T—K-Œ Ð+yå#ùä“'ŒqÁ¾6æð³©?.E‰]'~—6‚oŒÐE]ïË †¢Ã\"cÖû‰1#ÌdÆÿ”Û£“…y9‡GmÞ:ñù1&G"Æì¼;öìÆ~CQŒ‰“ˆ1Ç^Î<È£î|`dî¸/.¥èÒ­—³ÃÃ/üEg }9qb±÷”=Ìbçâ™YTEüÍ£1ì“Êè«öɹd² {›‹Y,ƨ ýéöÁÁºåœèªò±jˆËzeuÃcg’ãÎ¥ÄÄPÃÒׯhZö‹Îøêj;ÇlVÝ`;}}›­5ŒˆɃPñ5ŒoŽQÁfb!ÆìŽK$ Ÿˆ;ÊlAÛr}s³Á¡k\ž•LrbÌ‘’æ’ª2zÚp35T²Ó⣼WnÝsÄÏNt·bÉkcÔ«/ç’Ú SÈá{•¨³ÂÜÈÂÙ©g ÃLŒQÕñ ;àëøá„W2¥œ:ŸÜ¾LÊšf¥uWÎm§R"9¼%uW΋®)bCŒPh‹•¼òq9aŒ vŒ ¾9òòÑ!2á}¶½¿·Ši÷M¹ÖT)ãFÌìãc+Ž¡ÍƒÜcÌÕÑùæ0ñ¥ö¦öaŸc û_ßIÙ¾ÐnW?ü×ÍSÔ¹dd;×®Ã1²\ûèÕÛêàõNaɉ‰ ¯ÅÜéÚè|ë®Ï¾Ê_NœXÚ{Ê‘œýJú¼#óæþcò3ŒñR/ñ—Š1jº}hø–xÉ­tË㺋¾ÞëlÝÎÔ‰ït\ØU‰cˆ̓tKñ¹£nή®÷TuP©c|öÍnsÕ…]ŒN ݳÛoûþÔË}t a-ºqÌSñàLñù^Þœ=7íŽ+£¯àq7ŠË³’INŒ9ZÚ\VÛLO“àQP{¥ à¼öÂкÞÎäÚ²º+Þ²îTæ(ºÙ~ÿ?#Ãw #É!+‰: kx®TNÈgæªh[îJ¤RÊéTŒQR dF~¸Ä_M7,§±¬®EWt‘Œüíˤa@Ý ÜÔ@‰ù 'Ó-eßÈ1@¡-­ä $€Ô­–É ¿†Y¶È‰I vŒ º2Ôóâœ!uÊÎçSo¯$øxûnÚ›Ü9ý.c‡7{ ’1ÆÈܹkæ]kÒ[÷{ÒzfÞs1ÝsOÊãíìœ]}wçݤ|"×R£(cÌÚã7IizrO˜«çÖ¨¼‡£S#.ñ}Õâê|®¡gxô{K;Ç Kc3“Ç÷îrvóÙ¼/¥oæýOy?>#“œ8±´÷”#9û•ôy1f±.“öOfz1ö6³XŒQå¯]ȃ 7+ãŸj¡n ,å~M]v³cŒ*ß³eáÒÆøÜÛ¼hñifçQ7\fŒMÖuÏÑÓ'ì©A ãñNÖc¢á— 3úBüO<+™äĘPÑu)Ôè‡è¡ÙÖ3$´——:³ëàÉ3ùÔÜ3ûÅ–HÅ-ë“…M¤%é|BØÞ¨ƒ'/“u+‹ìuÄ[ ýêK©“ÛBö„>RÑš|ö.Æy¯§NÜ™J]¯Ÿ“™qðptXäÉøê ‘âÝ}rûlú¾™dyQ Óó¦~à’ù)ˆ1 mi%¯…­K~Å¥¤¬b™·T&ñ†þU™%Äïø§cScôHˆýÖÓM÷^ôLοìêJ?µ—½ºáÇ1†ðŒ.|Ô;5>÷~ôUïÉÃ÷¸ÇߨËO‡§æ?~x4Ô/ÿñØè«1CÎ1ÆÐÌnOJã“þ™Ñ™¿Ú>¾árhtÞ½îÉáWSwn]ÿV¦}tþµgÃs£3ÔÍ“bÃ¥6Ë…œ8±´÷”#9û•ôy1†úùˬ¥þüeÖWúùKU^«è7^ˆ²½Ît£²ºÞ¶c9—ôM¾éíüõ×ÖÁ~Ì™Ù1F‰*ô]£3îuŽÍÌwtv5Õmr§êuÚ¾kBùo¿÷N÷÷õ6ÖW­·4pNyNo¤«l!´í¶œ/l½×1<09?6ýWgWwmiž—Õ‡½ä?+™äÄÛãe¤£fÄïdZŒ×P˜WÙRTVs>9uÛFñ¯Ê(±bŒ5ÀbxðLra]qMKFNQÌÑúî!Fæ†D§¤ÔUÔ&$¦l÷u#Ç9øtaQmkÚy*«(kšìOÊ«-ª¹\\u)95}ûæõ’¯EþöÙªŠ+ÄÙÇW–T³—¡!Æ(´%—¼~!Ô—¤²~þ2I4“YDÝ»•½â 0±]kõù÷þZ‚ ‰ßYarâÄ’ßS.äìWÒçÅB{›;¢pAVdo ¾o_Rò’$“_AºœMÍ ?xŒ8y.<$[B"èÁd¯õÝ0¶ö¼6:ßLÝWmåɉ_òž~’œýJúìC<ƺÐÿ“è°·ß·/,yIV ?Ã\ C&ÈC™gš}oÌÆçÞu´Ýaî(°Âäĉ/|O哳_IŸc”>ÿÔ²Ï= ¾ËZò~ߌ,Vâ¼µÅȉËúžÊÙ¯¤¥Ä¥Ï“Á8 Àj¶¬%/,9qbYßS9û•´Ä£$J2ÚÛÌä ËYdd€ÕlYK^X>râIJ¾§rö+ié1†FRЦ·‘ðˆ 38C&ÈCúÌìå`UYÖ’–œ8±¬ï©œýJúÒ ‡½³§™µ»Z…oyËÈÇ~7—û=•¿_Iˆ1°Œ ̬IaÊ.Xá[FÞ2òƱßÍå~OåïWb ,/R›ZÙ»³kVø6‘7ë“C"ËñžrÙ/1–—O”§Ëw&|-ô9]yËØïãò½§Ü÷Ë@Œ€•@Ÿ‰äæéß,îçt}Ý÷ôs÷«„ 1 b (ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b (ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b (ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b (ÄP0Ò1FUK¨Á7ÐÒ1ÒH`w›¯E×ÈÂÒÞÕÁÍ`5#©‹ØÅ’bŒ²€ô Ò;ØçK¨ië’îjbi¯)0`ÏXUHEDê"R‘‰=W¦1`1¤w°;Ï— ¾r0ü¼¯¾o¤:"5»]&qŒQÕ²K7`|ųËt,L,íÙí«©‘8ž]&Ž1Šï+ÈXÚ»â\26R#qÇvÑRØýgiܼ٠ĹRBŒàŠÝ–†cçX…8VJˆ1\±ûÏÒp윫ÇJ 1€+vÿYŽ`âX)!ÆpÅî?Kñs¬B+%Ä®Øýgi8vN€Uˆc¥„À»ÿ, ÇÎ ° q¬”¾ZŒÑ3²Š><9sïf£—‰µG¡é¾´†Ç=S#³oûk‹ÓŒõ¨gxs”¬[»> ½þÞ“'ûœ=!_Þ¡Ÿ¤UÐ òðiËö+‚ï»ÿ, ÇÎ ° q¬”–cN'eåU4®ó dÏ¢‘Ydø¤,ö,†ŽYHßÌ{ û^V”—7?6=ÞÔz«S´JÅW­…32ÞÛÐzh–ÚËÐì»›×oÞ Nc{ÚF–±?ø+µÙî'…¥u­Ô@Яgü´bLçýÉñ¹wÏÛö LƒI^ÒÅ­[ÔÜÔµöìWß1vÿYŽ`âX)-=Æ,6#‰“a·K² :Ýø „:™Pá¡íW_ ­OŘ‘W=&¢‘“ú!*–o¥¢‹ÛÙv2}/#@k!ÆD9Ùé-̓dú÷jüÄÀ)•L÷uçi¤ÒÂòú0kKꙄÜ"íwõbÌËû9–Ʀôó¼ð’ 9 ζZ:&÷&Þ½ F`•`÷Ÿ¥áØ9V!Ž•Ò׉1zFV!{3˜ɸÄšÀÌu}Ðþ)eFç©,q‹Ú²ü3Ð[A¯›Ñ;GFˆ¢ˆýÞ‡dú~έ…c¡O…õEÝdúÊ~OfõþžÑêÆþ‘ yu¿Þúc`D¥:î}ˆ1 ›\˜ghð>iyX°UÏö4™xÚŒ3ÊVvÿYŽ`âX)}CdžT;{]†Y@ttlBÄg¦ÅxmQµbŒpÑSF¯BǘÝV²cŒ¹dŒÙ+c|Òÿ ¢Ë­–¸ØØáפbL•‡óÄÆþÃsïš\OQ«àŒ²UˆÝ–†cçX…8VJ_3ÆÈo—É&ô7Q i4… Â>‚ºè¿§#™L?|K¦ýÍÌÉ´™ÉrƼþ×dz›è6×8Q¤Y$ƱϦHcíÀŸ8£lub÷Ÿ¥áØ9V!Ž•Òßc´õ][¨ßŠîij½Þ|«clîýøÜÛÄ-ÔÙ\ñLRy£«­ºùN×äìrĘÃ_QÑåîÕ¼ªëý3ÔàOçãZ‹Ä›]7'DWïàŒ²Õ‰Ý–†cçX…8VJsŒ!tÌý/”ÝxÒ;52û~hìÕ­›W{Ó³tí«îw÷M½yÙñû¾ñM–©ö¯ctm#ê÷LN߾ټݟºôlzŒ¬"3Æð ½Dw{I®Q žB¡T£oNÃ~öÂËDË4>'Ó÷£F5aQÝ•²…‹÷â7ÛHÎÕ[Ÿ‘z܃½ø\šf¾GÎçg•Öç—×9g£'þ$DÇ'³¦© 7GÝÄn‡Ï˜S_R{™(«»R*š ,y©Åäp¦³Ë$£gq¦ë¾ÁŠLmÍI>äÊ^à»q¬¬¹¸2št;ù ÉüUÔÛp,«¤&ÂŒë_H™c¾?+¥/Š1ñIYô­ÉÈ„dŒ‘lÏ« .ÖÿXŸ8_Dݬìqù.ö\X Øýgi8vÎÅSZÛ”[Q(ñ/%ÿlyc~í•OÆeVË'}VŒÙ”×l¨'Ù¢®ÎØyj}bE®ÔtT©ìbKU°¾¨ô‚š¶.MU'9÷«Äí¯ô—šî¹ŠÖ}þëÈÇRYCÏ%(¡°è<ýf‘ )½ðuƒ=ùù{Øí°d±å-[ >ꃒäð/1ʺìFÂ$87!ÔL¨8[šê³øÈÇ=T¨ë‡Wd‘·`‡©t,¡ ó’ù«è™]inÈÞÔbØc¾K+¥¥Ç¿-!$¢0_p&fÒíd‚i$ ÅØë*"ï¼£Ssî\ñ21cυՀݖ†cç\ cjjü.ÖíX¨4 #r³ÂHÌ cŒSHlZq}^ycZj’“èqR©'íÛ“]Ÿ[Ö˜––hŧ¾£%Å%„òjÅÓìu¥bŒS|åéÖôZfáÉGÜ™'f±?%«ærvv1©¢<²êwÙúŸÎ¬=jiä]Oï¨aâ›^–W\qtï¶ÄÊVÑùž{Ï_,­OMOÛ¼#ÿB¸µ)uƒÍG’ÓKês‹J·­£7Nö.\{0¥¤ÙD[Àw:}±,¯¼á¹Ӗ:¢ä¦nx45£¬!=#;hÓE©bKÓ8:/'X²E98éq»Ïd•7¥§%Z‹Ž¡†é†˜”"²‹äÔ7 êÉSõ_Ázuý0zšœóaëÂÏæ§œ\«Âs:x®áìü / ©½°¬Ì×ÎÞ¯¢Pø”Õµª©- jüC±ç´ø»sKë®$fQÖ-ìLvu~ycV~þ¶µ*Z6IÙµ¥5µgÏí’yxåRI2ÆH}œ$¸’¬Ï¤Œ#«g‘J:ÔHüÇÇ7§L«én#éÈmï…ŒÂ3ì-kšÆ¤7•” ¶7ÜœEƨhYíŒÍÌ,kÈÈ.ØîãHo-©ªÕz[|~E]^Yõµ=E`u¨8q¯‹Å¾¢ôØõt‹ä‘‘ü IÿU4Ù™˜Y}9/»8ÜÔ@U¸îHbé¹%•‡Â7Ò«kšùO-Î-«M8ÖNW(¹mÛà¸ÌJê §'»èËNŠ‹c¥´ô°Ú°ûÏÒp윋¡cŒŽÛ…´^t‹õá’ãžtŒYÃ_[\Un®KŠžcXAú)*J½´¦ÁúÎïsª’®˜Ù1FæºR1†g—›F¯YÒ´õãï™o IŒÉÊM°Ð§jqŒQãG—6¹Û(© =—Õ_%{ºŸÉ͈ækñ5M6dT_¦Ÿ˜Ý¡âôaZS#Yç‡È:°ì×.s¿Ò›ú†­ØoÜ}"¹¨¨¶%)9i“—ÝÎľž)©Ò”5õL]÷Ò§bŒ¼C ‹`bŒÌÓ‡“Êd}&Ù1FfÏ’cJªÊÅ dmY:ƨ rk®X/Ä]»eçècÖ‹º9q¾²õ«Œº"4ŒöFÓÓäh‡YPŸÛŽŒÜ£¦k¢Ib›š@ÇÌ5¹ªÕMG¨i]PtŒ^QYÓ|Ýz*2[8\Ò¼I(¾ü àûÀ±RBŒàŠÝ–†cç\ cÈ„f=©0ÔõBòrö)‰ }QŒÑ <”˜ZP™˜šqäxcÒãÄghè®K_<ÆÈX—}mÌæìú½VF¤a†ƒ’1&ÚB|Äè§µÌÏçå†Ò-ÊÔEtd‘%M[N€±§25#7æø9.1FÞ!…E01FæÇI"ÆÈøL²cŒÌž%3Æ–œ¯%kËR1FYÓ¢¬®•¹TÏhkýŠÄSQ7'-ÆØ/+­iÌ)­#òk¯\%U¥¢ws ÏEVŒ‘>¼r),Fb4FÆÇ‰9à2?“ì#³g‘nÎ|2ËšbŒ¸wËÜ2{4&¯öŠÕB7·)¥û¾Ç5ÄJ*{ÐÕ„[Jª+5Ôy’GFInŒ‰¯h r_]ÚL6E:BAáºEYÓ|몉· ¦cfMOe }Û ÔƒÌ.¾+%Ä®Øýgi8vÎÅ01FEË&¿<7º´‰.úé£ç“‘•¼S™škr¡&'ƒú2OfŒI©jÝ,*£vdСBæºì£*ð.©,,¬*ýp=÷òOìnQÑÃŽ1Jêú¤.ÙâbA*˜µ è=¤æ¤Gikð4 ½Ó+[éRÆ=¶")*DSƒ·F`w¬´y›hƒLŒ!Õp~eÅZ+S2m˜›¹ŸLXí+ÌN‰âkñU…ŽÇK›¤bŒÍ‘’Œøp-už²¦qPBõÙ0gɹ죤¦{¦¢%܇T %-ÅÝ’~!<ÿ¨ôœÒÚœªÖèðHvŒQ7Üx<½,¯¬.³ 8l«ûGO@Ö•ùÚeíWahÛlŽºP_Ù\TÝ”’–ºi-5HHìI­Ê-('ñfCdJVquâżàkã Ï÷Pá¹$•\JJ —yxåRXŒäÊØ'æ€ËüL²cŒÌž¥i¾íL^MNq}AAJÐÅ:©#sË<»C¹•uÇB$ïTf—•YZŸ™S¼AüÍ‚âÆ—øÊ¤È~Ç&º4óB€TŒaþB²cŒÑÆ#iE5©™EQ{‚7œ*ÉͤNEÓ¶ˆK/#ë’.ÄÛˆ¾`¶ ïs ± 6¯´6=#}ƒø*;€ïÇJ 1€+vÿYŽse¨ò—rÚÒöüƽ 'Dq¥®·ÿèIèT稼œCdBoCdˆ¯­h®~xþ¥¬³Ô¾=ŸxÎŽº«¶ Ïaÿ™ü ‹’³Š÷íÜÀ^å;¶š_;€+%qŒÑà°‹6`>Âî?Kñs~›´-ãòJJ÷سg|9Ž•’8ƨj Ùu0Ha÷Ÿ¥áØ9V!Ž•’8Æ(a@`q_q(F‰sçX…8VJbŒ²I€ô eÖ…¿ÇÎ ° q¬”>Äšª–a€FúÂW<—ŒÁ±s¬B+%éËcçX…8VJˆ1+cçX…8VJˆ1+cçX…8VJˆ1+cçX…8VJˆ1+cçX…8VJˆ1+cçäBƒ§'4034µ6±°#ÈyHÙK(Ž•b ÀJãØ9åSÓê[ õMÖ¨iüï?ý ú™PY£®k`Bf©-í¢–ÇJ 1`¥qìœrhðôL,ìH€ù§ÄÿþGô?2AòŒŠª:YÃ2°¢Ô„1­ºú&æÇ¦^wtt”æ¤:è#N¯-»Ø¼+mýÓ#Ó=oÿ#5nªšô2ŸËr[\ý®þÉ7ƒ£ãWš*ýíŒØË€[ðö]{ÕÕ¥Û€;Ž•b ÀJãØ9£¦%$åç_”ÿóŸÿüð¯˜CÒ‹äY€,&5&£¬n4ñúÿüõt¥¶©mž82ñ’½¯%ë˜zejÀn‡ïXhy'ùtãÓ¯û§ÞÑÓCÃOìø:ì…á«;w‚:ø³¶uŒŒÏ½'Ó·óv²ãNÇ%aD´þcoÈÄèäÀz]äRyT´ª_“c¥¯ÉgÏŽ8VJˆ1+cç\Œž±¥Šªú¿þõ/’aè’[Èÿ‘ÿ’Æ… C=PY£Nþhu5á‰øD mé_cà © èÒ9÷àÑ ßzã‘?&ß’–[ ^ìåáëÒ4Ž¡2ÌÜ›0gSòÐfW=iÌX»ˆGT.z~ý yCU´lÊú©êüAž{I |CŽÏ»Ñ5GxÄ€/Á±RBŒXi;§L¢kúM~øJ*$´üòóÏÿýïOÿú÷¿µµµ~ùåçüãT¬ùŸÐÿûçÿÒ7¶ârjÙwc‚’ }õÄßÛíL¼Õ>Ü7>sµ>×P‹*/T´’vÍv÷ö\8¢,ZLMwCÞ•ß;‡'ïüÖêkªOZ¬=¢‹ÆqsCö¾€g•MS‰ºÙùBuMÓµÂlªðÕqh%sGÆŸ2sËD_Z7Ù‹·`’ÓüðåÈë¡‘±[·®íÛäÀ,i|ªánWß«7äÍjm(ó2§ÞšÿÑœëO‡§þzÞñ"ëüqž:nWÖ09˜V{¿sbxæMOÿ@CEž›‘¸#È™¥¸ô=oƒ98ÐH?TÖ´ ßŽHSeMKzúðÖ·{çÆgçÛÛìÛ`ià{ãùØÐÔÌ£‡¿†®3go³vèO²V™«x–[ÎKò°»=Š~èu0ýò“þÁ©wƒc¯n^kÚµÁš½…Uåþ5`Å@Œø+%Ä€•ƱsÊ$40SQÓ åÿ÷ÕÔÕìm×{­]ëár`oØzïu?ÿüó?~øÏž¡¹kÀúÝg½ƒ‘U˜Õ%O*®;Twëy÷Äôí[7ömÍ£cŒ*ß‹ªDE…>a¾ë^ïË dÂáÜÓ¶†¨Ü_;:Çæ;_¼(L:¢"Þ ~dFÓ“þ™‘©×OÛÇ…¯¥Wdb ÏvoÛä|z„»ä«X&Û‹É ¡Ÿƒ¦É‘ÁWý›Ì”5•÷>Ì$~U½mõñú|†ñúšþ×Å[ìHãá;c7Rwk¨ëxÆ\íí(T¢J^]M¾>M×îpggƒæB¡ ’ÔõwÒ£1Ï®×ìÙµÃÆÒ‚N† ù1FÃ0øé5t32:ò°srB4’pØÑ„Ì2 *m¹§§§}xžL ¶Ñ#ŠžcÓWoÜo§ŠÈg×Óéo«êÍš¼y·­M´Öàà]õÞÉ™¥¸4Œ6mÝèA?TÕñ›Ó›ôu™CÞ ‘‰éQÑÁ›îŸ}Ç<™x¡Åú`{…‘m:,œè{i€,Ùq‡:QÍ$¨Z´Á·ü~¯ƒ~¿fwŠ’ÿªeå¼ÎÁÅÓÍ?ƒ>Úˆ1_‚c¥„°Ò8vN™ M­úù—_”•þç‡þ$‡ùñ§Ÿ´´4 ôœœ¢ïÞ°5xgàÞø€ÃYÛ¢²ü#ÎU˜Õ™£*ðúcòíõü8';§õ¡‰SóŸŒ1ã³ïï•'8Û;zŵM¾½CLf¡×IaèµÖÈÂ)0¦i|fFWô7c4Œ¶Þ›/=¶‘ýBä Ë-®&È{®$ Ã-e7_ôŽÎt÷%…3íjº›ôÞ¹::OÇûSm4ѳÔõw >VÕÐ1 ã*ŽçÚÛ·(kY ;±å ”¨eH^‚§Pò2^bÛØ^[êge “£…7Úú'»zºRm•XfUÛžq›N2´á‘Ñk—[bö­]h.?Æ4Q%rϳ">'øÔÃw‘Y Ñé»iÔ‡TäôAK¸ÓžkÏ uÎ~QÚQzÓç°%»P¹½M4]ºÞŠZKËúúËᎾ±8 êí“3ë{Á /é"¯±¿§QYtÐèwäNÆUm¡ûYúὬýä¡îºDúa°¡¼!)m˰ç¢ë27ROBÛ^‘éßk·Ó»‹¼ÙIŽaÓéuìWM“ôñDŒø+%Ä€•ƱsÊdba÷ÿÿõÓÏ?>¸×s­Û?þH] óÃ?þ¢ô_¥ŸÕÔÕ¬­,×¹»89Øî‹ŒvÝá²)‚¬Â¬ÎÄ«ƒ‡†cnd´.çå'cÌÈD§@CÜnóhpè*™Ðßx ,X¼}UÁz²®»Uú“ pÌasSÿë»éŸˆ"RòJjÈF*®d‚„ö2ŒW†n'†BMÝЋԦÎÑׯj‚óF£ÜÌH•LÇÇ„ö?š·Ñ«¨én%›%YKhbÍÜJèèݱÖC®F‡GÆÛ™çô½N¶þPÚn,oo¥ªjb}Þ˶šx_ÛbÓµÑù“ŽÔÕ@è»l9ŸYÔøÛÃ.êzq¹\²WéS1æ’(«4‹O0SÓß´}×Þ­A>jÂ@z#Û ÄE¶žÏN2Ë™Ž#õQŸž<ŸH£Ïýê¶jQÚ}5ÒP]~hßn+“§8Ê™õPÖ0)o§õD×K*¨31戨;(k‰Ò½CEÛ~n´èXŠOÌCÑS7 Åg”ùŠbçøìüÍ«-§Nuw´a¯µ:!Æ|+%Ä€•ƱsÊD2É?ÿùÏÿûߎö¶*Ê¿üãT6²÷±tÛÌÓ5PVUý÷ÿûŸŸ~Z£º&tǶ°Ý{ÌœÖËŒ1>­ƒ·B˜vCÝ'cLOÇ)fym³„ñ¹÷Ú¢³PL=!cž÷ÿÕÞûºã·xf­Ort£öîíGôE ò4²—¤iYQ_Þ« ìýH™µEŸªt]NÞú-ú’˜‰1Ú1C½.6êº6QåÔ Eô‹õzN–>éyÚ¨O2‰YÂàÐufãñ3%ö ùDMPÜ;³uá Š;óú⻽9§<ÇEÏ2 ,}ε ÑÅ.)éäÇú›þ|;é@È…F ŸI†ÑæßèYRÚ¯S#oBÏõw»™Ñ¡ñ¹w·Z éÈ™¥è4Í+ڦȋê{qÓ×BϘC©‡*Zö’YøqÕC³ïÇçÞ–žÛÜ(¨*ô¹Øð O4Fël»`ËÆc¾Ž•b ÀJãØ9e24µþñ§ŸH’!æß?þ,0µ·pÛbå±ÕfÝV{Ï­V.¾k´?þ÷Goϸ˜ÃÉçNÙ8ºË<©l}ó€dŒá[ËŒ1{HĘ8fy-Óx²˜@ƒç}ôUoVjÒ®]»Ü\}'$bÌíüÃZ¦û‡gߟr—qõ°¤Ê†+Í×ïm/úÿx9 9‹<$ôÜÊúËR+êmˆ¹ô ëç/›.ÕÓ1FÛ"²ãE¯˜C¸îIÿµ­¯½ý´è½¢ÑÒhœð`d¦2ãý=“jmLO ] ºÛųԄd ÷qoASÑç5÷]2ÞVqó~Ûõ[W%/‰Ñ¶H¡K:'Ž8ÆL¼`æÒ§‡Ñ1æÊ(uJÓÖ…Ñ]߀ ]þ›½Ôõ‚é-,äFáºmdÖz7S¡SÃuÌ=©g"IËÔ=øPBQËïôÕ5W¹r™¥ øŽ‘Ec&/Ò÷± }AŒáG–?'³F§†¢¶8±æj¯á[ø„M-»úB”B;ǰ—Ymc¾ Ž•b ÀJãØ9e¢.ñ_£öÿþ­Ê7зYgdç­oånæèmîèe`áÄ3°TªiòŒŒM,,, Œtôd^âo¹ïÁÐðMæ¤2Ç3O%c óCþu}'•½]·@µ[~04r‡L4üU·I|>‰ªpã„DŒ¡#D`YÏ@o“ü_‚ ‹;—BÐg”ñu©K2A’Fz.ûR™«£óq~â·jèOcLwüÚ?>G{?<1×zÌCYÃX¸Pk™ž  _ã­ùýý÷Ew§¥‘ònpfÞ’G_£ÿlê÷µ1¡7Gjn¨¥$º¸ÂUô2 mk/ûÕ}e3MË,Ž®Þ E5´ªŽýÑØ×ÈXÛ5m¾Mé„hèc‡M7ÄŽÌRùŽ1A׆'¨1„r!Uüñèkc:ní'•ôUQ¹Ÿ½W‰z,èðÓê¨*ð¤F Þ…»Po¢²¦ùÅëH”JÚ`EJɇO»´=³Yv;×5CÖº}Á[Î,ö‹R Êêz-¢sêž]K¤/Fú0k©1Æ|7•<Çgç#DGø5Á­¶NrO¯]¸‰Y •vz;“¥¶° !Æ|+%Ä€•ƱsʤÁÓÓ32×Ô3×µpåÚ ŒíøVCKC m¡‘–@_][GMK ¬ªþãÏ*ÿýE…,,yÃeÉKüÛ§Þ^Í9agmç±íÔcctŒ!ÅPçô»†¸PßÈyK|÷ô»—øÏ½»]rÚÞÚÎ}ˉǯ޶Æy’ö 3óëôŒüÓ® ’‡šSé…‰1ªüµL¾­9Àé«n’[zG¦+ë/›XÚd‚÷¦{hšþåÄñ¹·);©['¯á9ÓßÙ“²¸spv|öÏÑC:Æhš†Ós‡‡ï=ýŒãÌL¸èÚ$óÝUôf»;_¶ R•úàà=z´aSöSjÉéÉë×oÝë¥NQëzT-Ðà‘Ïy³(파]¿õàö3úw!gƒôåÌb¿"¢ã\B%)$œ,9Ƥõ̲7Øõt™ÑLuöñÙ×·ï>¼þ ‹¾ÝYÙ#6« b ÀWÁ±RBŒXi;çbôŒ-uŒ¬Ô&*ZzZBcuž®²:D¾Ð@ßÈLK[GiêQþñ§ŸÕ5ùR?)yÃe]¯¨†Û=“=k»»Íu;ó»1Vé÷º^‰îÍÚz“‰1Ýí‘sntNÌwu¾,I¦Grøö©ßŽ˜ypÿv„ŸýÅûÃ#ÃJÿnŒ]̲)öonÊäèæõÇKê›x‚Lȹ0†°Ù—ó¤wôqÛ‹ò´cû.uuµ]’œ+yRÙº˜âßû^={ù¢4㤚u4}*ãa‰¿5 ä[x­­½køöÍf×…ßœÑ6?OßÜŒ¡¢e{ºênûÐdGwwÚ ñÍ@IMàw(¹þöóîñ?Çf©Ÿdim¬ ñùpi–Q@ü•'½ýSó/;Úbw¹IýnŒÀewÁå'ÝãóƒÃ£7¯7l]kÁ¬è–Ðô w`êmWOocÙEý…H©&Øqªäö‹ñá鿞u¼ÈMŠe.qÑ0ò»P~ýIÏäÈÌ»¡‰©Û7/‡ûЇ åÌR\¶1O$?ÏŒ/ˆ1¼®é—¾0èCzÐÁäÊ[φ§ÞŽM½nk{tîˆøf€«b ÀWÁ±RBŒXi;çbÔ´„&vê|}euíŸ×hüôË%U U m=C -ÞOÿýåç_”~þå—5ªd1²°äºÊÆ 1F¾5|Sm‰†IŒél“>§kùô"?ÀÀ÷Šc¥„°Ò8vN94xz$¢hð„?+«þç¿¿(«ª«ªiðu„<¾ÎVúùç_4µ¢¤‚g¹›Ä˜µý '+c`ÕâX)!Ƭ4ŽS>5-¡ž±¥¾±…Žž¡ƒ“‹¹…•…¥•¥µ®¾‘¡‰%™%5Cð¬rÆgÿºQ—,õóê\˜G””â~\°ì8VJ_!ÆÕ]),9Ín§išÄ–Õ_=ŽŸ‡XÀ±sr¡ÁÓ˜šZ›XØd‚muêw¯™s°¸©¨<^@U°ž•¤HW:ÆÄ.üYdISQY™pß—ZÚBf•Õ]IIŒg~³ à»Ç±s¬B+¥%Æïìz’@,x%5cŠcIãfÑhŒP<M8³ÙV<sÈZQÝðbõåü‚Hms#s;¾¦Ž‰£oHt5nãkÍÞ Àw‰cçX…8VJKŒ1fá${¤žŠÝs"ŸL\<íKu=ãÉtú™èõþ¡§Š›Kkêíø:âkcjêCw„†Å–’é?kM“Cd"íøAw¯ûsÈô>;ö^¾K;'À*ıRZbŒQV7Úr(9³´©°¬æô‰#FÚâSÂ\w?Ÿ]UTÕ˜”šæçb¦´p§²”Ãq)Å—ŠJ+ŽìÞLÿôžGhlrA}ImkNQùÁð­ì]|¯8vN€Uˆc¥´ÄKƱs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•Ʊs¬B+%Ä€•fiïª)0`·¬r¤F"•» 1`¥éY˜XÚ³ÛV9R#‘J‰ÝΆð7°´wÕ5äÔEV RqŠQBŒø[¨ië’^jbi³ËHEDê"R‘‰=W&Ä€¿®õ•ƒƒ›7ÀjF¨Âí\2b (ÄP0ˆ1 `c@Á Æ€‚AŒƒ 1 b (ÄP0ˆ1 `c@Á|…£b à‡Zè±7.t#ÈyHÙK|¹/1$±Ðé…Ìb//“š¾W\AË£ž‰áé¿^t¾(Ì?ñúÿhãS>¾weÇ:sz–²ºáž¤ª{/'†gæ»úªK2m…BööÉŠ[ôõØí_Â>®­³-ŒLx”t=»±½Àâøçv:ò©˜Õ7w3nä\¾u1y¶-{òé 'Å?ñÎØôdÖ¹¸M}½÷¯è›}×pöC’ñÏx<úªïLÌO/¯€ÝIÝ#]Î ¡WÎ\m‹ã/ï]`ïÑÒcŒœqIŸ“Ih›ì¸•¦.ñ¥¾²†iNÇ̳ë1ôCcš‚>Ä!5Ý­¤>an¨¤Ê{1õ®v“ 3k Ïedö}¢µä×ó”%Æ52»qÁRc ¯¨ÿ5ód–#ƨ|œâ(Æh[Ōͽ;ác)Ùh~e|fÆŠG£¨a´Ÿ,åfÆÌUVׯúóvòúOÎ%òúçvëKnÔcŒŠ€X#ç: Ãý¤¢ÝÍ*.….¹ã³oD•.+Æl!«„‘UøÝÓï®õ–\Ñyý&[¾ôî¨]xîoišœº}ëZˆ›)Ý^6øºÈNógdz%êÌÀ i wÛúçú†*r„¢á2$"Ó~˜¼ûkÃ#=’aúÇ_“]ŽÏ]´1–Ü…o]WÛ9©ý’·Ãwóv mjknÙ/û:3¥0Ú~(<Üã“s Çsíòý¤ø{ ôM-lܼV3R‘ºˆ],ɱÄ#(FÓÛHÕ\—y(g@ÆhÓo#ìve Ó‘Ù÷Ù¶&J¢síP€¹µaí²ñ\ÓàË»¹ôbÅÏÆçÞ]oª9r`­…ô ƒÍÝc]û¶ø™9n8YÓ92Ñe.*‹e–õtŒyÑwËßÍI`êšô`¢óQi×õÌŸý+åP¨•µGèù«ã3ï¤bŒqP9Ùò M¦–®G Ff^‡˜H=Ûc¿?½Ì<”cÆgÿìl»ä³ÖÕÎ{GUÇLç£t%¹1ftb¾æÜ^#}Sçàä±¹÷¢p(9#óõJ‘c4 ÂGg߯í 05³s ˆ&éñ‚hÈëÃhŒºny÷ÜÝ’ ÎŽ6k·å?žlo9NÚ-÷ß}°ÑÃÍÈzí©k#Ï(->“Ù;÷ëɵR’޾˜–“CäÏU¢Eá@_%»ýo±FS‡tW}«_ÖhþÏ¿~XÍHEDê"R‘‰]8É´Ä#窒aÈä¿L‹œ+d¬>la·m“oëÖ[)}|‰?1>;~?s±ýîSùw;ÆßYÏÚîˆðaoŠÌjt¥§•5ÍN¼© ¤†Jd–õtŒ)õŸ«fàó+"OüѼ—ÙæÅîY©“Ø={õx/Äž'¯äIWÕ~¿Hæù1†LD˜Šƒ¶eyè«'”c‡®2gÁ]þ‹~i_%ƨénÛw€z±´ŠÁ?k×QÑ”‰1û‘WÝÌUIZ¦ÇÇgßkñÝó;{:רQêúë}6RCg‹Å˜Æá¿ZÃ>캠Ÿ´¡ÑO‰ä©Ã%Iþ\%ê „ŽḬ̈Ûÿ¤—j Ø}`Õ"Õ©‘Ø…“LKŒ1’¹ExĆI5ì Cco&yÉnWV7ž}Ÿk'ùpR™º®õ†ÃÓïr¶||Ê–ºžÝúÐsåIÉ›´ ?’Hã‘…<@|>u/ÓWi‘²žŽ1»¨“Ö¨v&6ÔýÙða§¤‚—Š1_½é™¦õO¿ë¸Â,O‹x6)Y©Ë1cÓ“çð{fÞ]´1–c:Û¨ÉhÌKû*1†Ð´ð NHÊ­j¸ÕIV”Š1á÷I¼d^{ÏÈ,Yf³¾®¶edÛÄ›îg¿çegìÜâ§*Ê3‹Å˜´ž¹{˜‡úÖÎô}ÎuÍÐOéÄËv2\ó2³¦>òçRÓ|²_C-j îï%Ð7Õ7±bw]€UŽÔHÏ.û 1F™Ç'H’Y,Ãȉ1F‘Tf`]£ã”9>÷Væµ1DàÑ—Â5£ K ¤VŒiŸz~s‡T#ÙÅa‰³ïùÔTjÐæ£²Þ(J2Æ0Wá3±¡šÄ˜ÍbŒ(6|c~›/tøÄAß|ìzŒøR âbÏÜÍxOɶådïšâóJ2Æð–lm$c‚ŸN21æå£Lû§cÌÂë•"3Æè¸Ä÷LýU[”·ß~ïuî¹ý¯¥bŒÉÖÛ‹¯µ†o·eo\jIkÛèüóßòר-c¼«zû{ËØ[hù‹~Jdwì«_œ.´]ÿä\%Ñ˜Òøì_ôÐÐßËÂÖç’°‘‰ã€ÌcŒäIezgìIŒ¡Ûef²0{ Œ¤ö©Ž›)ô÷ô4e Ó¬öéç7¨‹+”dŘÇ;î…iî%Õp°ÉG(æÙÔ“ªÉ%QŒi9°pR™†é½‰7%ÞÔˆ )ë+\Ä?AcàÛ$?Æì~8ñÇ¥ÃqíSR1&²m’¹“2q¼ùnª¯5óæœüLòé…>ï¸E]xÃp;×><úP‰ºA0uRÙî…» h[Ÿ{ç"Ð!ÏGâ&¼ÊÁ??+ư_¯™1Æ÷Æpûå]ÌÃÚ!é“Ê´LãÇg¦-E÷S¢Î1;ùZ ™ðŽM9¸I|4 BÈ7è ‹1š¦Q#sïS·}ô^›l¥†§è§¤e3>÷>F´kš²º~ÅàŸ«¶}r®u S˜Hó÷rpófwZ H¥Ä.ŸØ–c¤.ñ§“ŒÌ c,÷BÃdç½±ù¶«åa;w88­ )½?14ôØmá‡,%/ñ·°u÷ß—:8û>GtŸå7Fzîî Ùfkçâ°ÖÒÕñ™™PÖ…õ¤™èÜíïclçu¼òåðÈ#ú>ZGÛ§ž_O1Ñ×7qj]‰¡´xŒÑóÌŸý3ñÀ3sç­±uCIÅ}ï¬ñÙ×g"v˜š9l=Ù8:5ä¾ðÓ7 ¾uf_χ$—„áÙwÕ™g=×yÙºû…Æ÷;«ˆ¢†kèÓý¤ÎÓÅÉjí¶Šö™g×b©vóóã³óýݵ„V[ã/“e>cêGÆŸjié*/òz¥s=&>Ú4C׋/ú:+­Œ ¦NûÒnŒÍ½o §b¡Gq׋»‘ªZäeò²žM¿¸Uèéædá\Ý=w'w+YÀ«¬g ÷ÊF7}S‡íqWF'ûu5ùtŒÙaf¤Æñ¹ðys.ÄùûúØ{nÙw®®³çaV‡ø¤2"¨àÙèÔ`±(Oçõ;“›{G'ûÖ늳ü¹V‡µ5Iíño°˜å1_ë†Ë4 #ŸøÂËû&G¦_ÿÞö´,7Åv!Ã(}|‰ÿøÜ»¾þÞ‹ÇÅ#Êš’kn¿šy78öêæµ¦° Ò J¢ã‘rëåÄðÄ«›×›¬ évmë½ û‡fß‘`µG~Œ!ÖEåþÚ60<õúVk‘놛ì.{Df^Ò;89ûøá¯ád„7euý룳ÌÏ5f›b*{Þ31?:õúñû±û7Óí$Æ ôUîºÐðthn`` ¡2Ëdᢎðô–çCTéþ½aOm¿ü£& ¸Ý3365GòƒÌ×+…ÄæhÓ®r]ÃsÉhyÚ=1ßÞÞžì™yxæ¯HSƒY/Çç»;²ÉŠªÂõé wŸ¾îí¨ÌŒç‰.÷'+¦6>Ÿ¼w«5Ô‹>&¼ÿgï> £8ß#Š €„ !„@H9‹œsÎ9 ‰ $PÎ `²±±qŒ&Ùdl ξ÷í{o÷í{óöÍÌÎÆ¹³³»3³ï«.¹Ýt©›¢KjJêÿ9¿sOuUuUÓç~œïïê*ò>üúÑ‹_ööyé˲s3Ž|rçܽÿàpåÁÞAÁQ³Kvýq¿SÐÄõùï\~pï»ßî=zúö±ê1ýLŸPgmë†+϶öůþ샌°¤y3ÆKqAÆë—bô@¤Eh¨ùœšOüæ §V¦(׿®ÎaÑ¶Ýæaç?¯NøvpûV•ÏÔžÈKš=c¼¬>vYfý®Çäíß³úú§] ¿jƒÝL¨ºµb€..Åx‘1–Ù#c¼¬^“Ñÿu˜7Å¿Gb˜ûëP¢ã-þãEöGÆXb§Œñ2Ü'#ŠÅxeF,ˆ—¯¼pXd €%ö˯…Œ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtÊÎ3îÒÓ§?üùã‚AÊM-‹[ÀBñ‚Ý=”[@ë@Æ:EÆØ†ŒÀ1€N‘1¹(Ö˜ cpd  SÚ3FžÍ¯ ‹X™]÷É­Ïä•Cï;}éÞ½g?^ýâ‹}[–y¹ºËëÍ2Æ=xèîšs×|ÿá£wJjÙ5qò¯þ¿ÿ“X3=з_öu±póó9 ó>|ðâO÷=®ÎÝäíÞeEÉ»7ÿ$ŽYš¹ÊÝðg!cpd  SM•1Gë¿ÿûðé5±&aË9±üø»''OŸ»øXj†+§2äM3ÆÅ»ÿ{/o\8üÃ[Ò[ž·(¦‹Øä²HT„XsëÆÍ/ß—O‘7"\l ].–Ÿ|ÿëÇÿà‹o¤w½x>!ÈWlòß"ÞõäûßνwîìÕïĦû÷>‰ðô4ûÀƒªn‹Mw¾Ü+¿ ø–xyïþI±,gŒ8‚pËðÉ¥ÏðÅ q:ãË#ócœÈèTSeÌýûÍ™<¡rJ;˜[ÏkfGŠ­®.}û«x¹3&ÈéåŒé·ÿšX¾vnK;ÃÏ·Rv\–êâz®Xî³çÒýo¼|nµ³áiï?›.!–'^Žp¡r´áìîóÎ\ÿâÎÃÃk¥K+™_>›Ž-OËήv^~&^~˜•bö½#v‰õO^üÜÝC*œá'ç2¤wÉóèÛ¯„ø:¹vZs^:×£o¿N ñuvõÙpIª¦ŸNr"cp d  SM•1å) ¿ìêUñTºóÍŠu[dµ÷”rb¿”¦³÷ö ±üYU¶¼Ûº]ïIuñýoþn aÐ),nHÚœ¥›s.BèÊi)]ÖeˆŸÎ?¼vù¢~½ºË;·uï!ÿ6¬tÇù€'ˆ—woæ˜f¯w WŠ¥Ïì~ư<3Pºž#gÌ­ËKå=^^Y&¿Œ/øR¼üòÒ '2Ç@Æ:ÕT³:Ô_~ÙeÈ;ò3—Orz9cN<üI¹›Ø©£k§”‚sÒ¯Ôž¼øñÂ…ó‡¿.³ÈãÚqÀîšï.øÈn\|wXWÿö¾c•‡z*]&zWù™‹n8Å-`îSée§äõr·È¡¢|WpÃø’ŒÀ1€N5UƬiÈŸ^‡ÄËÏ)÷tz9crî~/–kS.§˜vTj˜«§¶xK¿ûtJúÝ—œ1²vž¡Éi‹v¿öLꙟ,iç-’ŸŽÊšñì¶ù©t'Ïõžó? ç2“äõd 0EÆ:ÕäãâÝÿžá>ûi½¥›õÛvÞ}êã3\Ü‘ÜÕéåŒI,‘.‰\=³ÙÕpoL蘱ÛÉÓÅÎíܶîrù0k˜“tù¥¯ü»/)c\<Ï^¸þñ¥ëëâ‚åÓÅî”}}»XÎ3tQýâdyÓØ¬Sâ€Õû¥ƒt–6jü”¡ƒÏ4ó8n¸tö¾ô¿³ºH¿(sRt €ƒ#cjòŒ†îûì©áö˜Ó§Þ=wûiêÿqyÇöÒsŠM3ÆÕgè…o¤›^n|~±þíK¿ÿÓ“?m!6%çKÁ ZèÓ Wo|óëW†§„]ÿXê‡i‡¥ 5_|öýN}tã‘á~˜âéQbSÀ}¿— ê£sïøTz¾ÙƒÇ_ ô›~!ÝîãâD㇌ˑå©ô«³ÓÆ•d 0EÆ:Õãäâ9~MþÙ/?øîÇ+W¿ÈÙ¾2ð÷»öÍþݯãsŽ|zóñO÷<|÷tíäÁ=äõmÝÃ7•pýÑW?¿´oõ¤^«.Òåy¤—WÛö]æî(={ùÞ½g¿>~öÃg>Þ¼@ºëF>vMý‡·¾úö×›·ïÔ—ìKm¸Ì¢Ì÷àUò'?·§áê“¢[Èè”öŒi¹>7<m¶áßœP"crÌŒéàæ1|ÇS“g”(‘1€N9fÆÔ?þ)¡fV´r+€ŒŒtÊ13fINEÎÁ¼…3Æ´Ul0"crÌŒPƒŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„ŒtŠŒ°„Œtª%fLÛ¡¥Õef+ýSWd—TÏèâ¹®|]ÿPå»´g,©* ]Fçd,ˆQî žk§¡K—Q®ü“öîY«\Þ2ЩfÍgÅš&àâíêÖHÆ :D,ôŸ³ç@'CÆÜ»¬“‡Gÿ>ëÊŽMëàâWR]ÖÍÇÛ©{ô”¼}ëãL®ÆÏ<¸w©ØßÕ§×¶Ê㩾Å÷VZS×/ÄÏÙÕgÐÆŠ3¤/¼Ad  S3&hÜ}ååvî‘eµG;¸º‹éøÁ¬áòJ¿„=–~(å²4?o–XØ\VÛkqñ¦Ô°ö~ ‹×;¹xåÖœ2^‹è¹ªlÇ邌Ș¾ÒuCÆT ^Q\\–iüÝšYÆtðŸ^T–n<×â’£|ÃæŠC¹x'åçNI“âÛ±ËÈìÝ+ú™}0YÔ¦Ší†ó nÓÌ2fQÉÑ¥ã‡øxÿqÁDdÌŒ®ÒÅ%!`ÈþœŒA"í:úJÉÅ+°ïÄÜ{“œL2fRÁ‘ÙÝ:ËûûÄ éÙÑ[úÞö“×ø'ó3Þ<2Ð)¾´dû¤žÆ—"?BÝ=Åt|ïº8yoÿÝ–¦ãÎí ÕyxÇ,ô [›“9$`pVæ’¾mÝBËêNû¤Ë¨ùh"c‚ ?ZS^:såäMǧFÊ»™eŒGÈÆüÜiÆs :P¿"¬³{Т¼Üi£·§Ïd}bפ}µsÂZÂLÿìºÕÑ]äåvQfãš²`SN~ÍñÝéƒ »‰ŒIèä-ïï¼A´Š³«Ï¨…Û÷T¤gî[ºªÜ,cÖ•Kò‘ªÌHº7fUCSqŸ z@Æ:¥1c¤«1®Æ´uë^VwÌÝp5FMÆãóOIØ™¹´O[÷ÅûûgÖÌêêïäâ•W{J¾£Fˆ\Q"ÿ,MdL ›‡t¢¡¥5Õ®.î¾ ë‹J¶¹nªiìjÌN㉔èëܾs^õ¡ÞkÊæuëì±qÿöé•oùvŽ©ÔsCùöÉ WcÚûŽ})c\¼B»KñæÜÞ72eQIe®“!c¦K¿£“öï¢UFo¬(~)c<²L”.ÂøDM+®Èv’ïÙ½ÄÛÍÃÕ7zMÙ±…ý‚ý“÷æìšà,^ÈÄíÕ³;ÉS°@,§í?±À«ƒ‡‹wäæŠcò½1d ºBÆ:¥1c„ ¤Y;T,­Þ¼qi†'•)3Fù¤2'éž“Yåõ§# ^¢7UäÌ—×·u ›²nviÝþƒùiîto,cÜ<ºN+©*òsó0Ë±à’²2³(·´.swF\XÃuà ‹ËwËË"6äg XÒkÌêÌ‚ºÜ²ªÙ#b²Ê œL~TÖ9yNz~M^iÍެ݃"œ 3vôÒ]¹•ùÅe‹¦ ‘ê¥CÈüm…9%Û3w&÷›SydV¯.íÅkο€Ð¸¤Á1ñ)‘½ããbœøÄW!¾ñµ(¿+в1€NiÍw1eê“ œÐ;2ñ…ˆ¯…_—ÐÒ‘1€Ni̘¨¾ 1ñ)Êy<Ä×"¾å7Z2Ð)Ó/1•ß’5J|-âËQ~c !cÒ˜1âíÊc&Ï\ >dd  S§Ú6dÌ×O8úö“g.”פMsâÝïúÈi2GCÆ:¥qªm[Æ,_»µ ¼V^s °rõÆrÆžýb2GCÆ:¥qªm[Æ„ÊaÒôy£'LûÜñRÎÑÙå_ÜyxîüÕÓïŸWfL~Y|ÓŒ™0uÎÓþŽiÆœzïSÑ$‡Þz[y:™t5æÓ+òrè¸[ž‰s‰·L½X^yõÖeÆÄ& ºÿíOQ}ä}>¸x͆Œq÷òS~i ¥ czS#Zå‹;?»~7!exøï³~kæé÷?ìß'>å.Õ7Ü1¢vÂ-dŒ¨“g?îÓÿÒõ¯¦Î^$ÖˆÊ7ÉÉ÷ÆÌ^¸"¢W¿»ÈI#ž[\-ÖÌœ¿LlUfŒxùö¹ Yy¥¢|&MŸ÷øÅo¯›1âÏØ­GŒòK-èԛʘpén“Ï~ü¹¼,gŒ¨—“g?ùòÞSÑ0‹Wn¼ñõÓ¹‹WOš1ÿÆWOD·(3&6aе»/Öˆ¹xí®è™FŸTvôísg>¸xëÁ³·?¸˜2tŒX9fâ ±|ûáw¿¸sê½OÍñ‘N¿^¼KÄ•8ÝëfŒ; Õ§sˆò{-è”3Æ®Éôæ×e´Dd  SdŒˆ’‰K"¾+@½¾ ùQ"¼qñd  OñdL³‰ì¯\ ¨#Ý$&bƳS€rè샌tŠŒô,:6Q”Œrè샌tŠŒt®O| ¿.€7…ŒtŠŒt.2&ž 2ð¦1€N‘1€þi§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€Niœ‘1€h§›‘1€NiœÙ#cbÃ'D¤èQ”,ˆñRZ©Üh¥4ŽS€ÍÈ@§4Nš=c'Èõ¢$ÅŒrËR†+W Óç.¹vç‘r½ÑÛç.¬Ù´S¹ÞþU–ÕU®7ŠèÕOP®·d瞃µÇÎ(×Co4ŽS€ÍÈ@§4Nš5c"v%*ëÅ”teFñ®F 3éÒ¯•ë…”¡c6lß­\oÔ‚2FìPP^§\o ÓRh§›‘1€Niœ5cÆX¾cê•×dⓆÎ]¼ú“Ë7-eÌ+‘1xã4ŽS€ÍÈ@§4Nš+cb•Åb‰õûd¶îÚÿÁ…/®Üºo)cLT6aÚÜ÷Ï_ýúéŸ|þå‚ekå•"c¶gæÔ÷Σçç¯Üš¿´a½©^}ˆ~¸ñõÓ«·fç—GöŽ+£ú$ä–T‹ƒß¼÷MÕᓱ ƒäßûärFVþå›÷ïûÓÛ\L2º¢î¸8¸X3uöb±ƒØ*råÈ©÷¾zò½X¹c÷ù¦3*mšx¯´Ã—÷VoÜ!Ödå•>zþ«ð·Ÿ‰—qICªŸºyÿÛ[žåW÷ˆŽ“߸xåñ§§«>rz~Ó"h§›‘1€Niœ5WÆX½11>|`Üóª 2Âòµ[^™1ɃG?üî—ô½¹©Ãǯݜ.–'NŸnȘÏ~Þ’ž5xÄx±õÉ÷6Íì •õ'ßÿôŠH‹Ù W\»ûx_n‰XYTyøÂÕÛiSçˆõg>¸xúýóòÎ"cDEL˜:gäø©"{DxˆÓ‰˜9þ·]ºnÈqQ>CGO5u÷ñ‹µ›w…›dLBÊpÑZ¢Ð ;gÑJ‘I —¯“w¯ÆDôê÷ÁÅkÒFM7yÖ¹óWE‰õ“¦Ï§Û°}÷à‘iâCг1-‚Æq °è”ÆéQ3eŒ•»b¤†;LŒÿcŠ;dÔdLVn©(ãú’ê·ä)¾XyäÔ{Æõ"6Š«Ž˜¡òPÑ"9ä—KWo9—,‚a’!„„¤Á£ŒûˆŒ‘£BÈ-©6~°yKVßzð,Ü1b!ªOCžmËÌ>åV¸IÆdf9õ¾¼U‰%¢EÞAΘÉ3Ü~ø|QHÝ%Î.>RÝñwËkßøáÅkdL‹ qœlFÆ:¥qzÔLóR·¬`¬eÃÈ”G0£&cêOœÝ{°Ø¸~Õ†í®ˆŒÙ–‘m\¿c÷3\4=¤óï}ó£éaĸ)¢Œ)"\»ûxîâUᆌ1Þl³;§ðÐ[§åå)³3æäÙo?y–(¢ˆ^ýŒ#ÞòàÙÏw=—‰³_ÿêq¸IƬݜþøÅoƾzòýÓþ½|3Ü1[wí7®ß–™}òì'¦G˜:{ñÝÇ/Lׄ7–1_Üy8éšpEÆTi$cN¼ûGÆŒ4S4IdïxcÆWËÆŒŒ³dÕFù÷if>ùüKñç2¾ÌÊ-%cZã`32Ð)Ó£fÊÓ•I¿ëûûúÆFì¬<‚5“•Wj¼}%ÜpgKí±w # ǸþèÛçrKªM”:R¾Ö!¿\¹~ûñw>Œ‰Kí!ß]#$)ªfؘIáê2ÆôGe[Ò³>»~7ÜäGe›wî;wþª¼Uص/OGÞAΘQiÓ<ûÙøPY –‹-jŽž1}ÖÙÛ\$cZã`32Ð)Ó£fʳ[üå’i´az4Ý-þ)CÇv²8Ú•[÷3³ Â¥»kŽ|zùæØI3‡™$Éx㚌]T^{ë͸üÊŒ9r꽃ÅUâhWo?Lß—Ñ«_øË\it惋â£^þòžñh“g.¸ñÕùÖqºªÃ§Äåd¼¶³xåÆ Wo‹ #z†Œi4ŽS€ÍÈ@§4Nš+c¢Ì/ÈX¢æRŒuÓç.5fŒNˆŒ¡.`Jã8ØŒŒtJãô¨3Æêc—ej.¢W¿ô½¹—¿¼§Üô‘10£qœlFÆ:¥qzÔ¬#±|MFûu˜pÃoº.ß¼¿nk†rÓ´tõæ]ûò”ëá°4ŽS€ÍÈ@§4Nš=c¢¤ûdD±üñOÇìJ”FÅý0jÈ÷œ:§qœlFÆ:¥qzdŒžÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéØÆq °è”ÆéQóeÌ€A#¶dääWÉ.ª^»uwï~Iòʽ¹eʛʴ¹K¯Þ,6îÈ•6ÝtÓúí{ÇLœ©|‹°bÃΉ3(×MEã8ØŒŒtJãô¨™2&¢W¿œâCÓç-ŽMŠì?{ÑêÌœb±ò fLâ ‘1q)Ê·„“1h~Ç)Àfd  S§GÍ”1}•ןŽê;@~)fýö½½ã’EÆìË+_°|ƒˆœ]û ‡Œš(¶ŠÔY·uw~ùáýUã¦ÌkDŠ,\±A,¤ #Ž“:|¼Xž·tíŠõ;LÏ"Þ¾û`iQõ±ý…Ur´XÉãÕñÒ³ *ßÚµ¿(iðèpCÆ,\¹1#»¸ âÈúm{¢cÅÊÔi{rËÄÁ3rŠ7=ðº4ŽS€ÍÈ@§4Nš)c„½¹e;÷å‹rèÕWª™H‘%Sç,Ës—¬Ý™U VmJ"{Ç' %B"!eøÈñÓäMbϪ£3ç¯ËÛv;i–é)rŠM˜>¿GtÜø©s³ò+ÃUdŒØYÄÒ¤™ EY¥M›'jJ¬“W^/ÎÕ'aó®ìek·…KŸ¿\ìУw¼8àš-™¦‡^—Æq °è”ÆéQóeŒH‚Y WíÚ_XRsBôLꈴpCƔ֞›ÄrbêHùfEUGcÉïZ¶n›xWTßEÕÇ"{÷ý°hå&Ñ$¢:DÏôŽK6=E_ûzÆô“[V®"c’‡ŒÙ_Xe\¹/¯bÐðqÒÕ˜å5ÉCF,© ;öæ-\¹Ñ쌀m4ŽS€ÍÈ@§4Nš/cŒzõMœ1¹¨—~‰ƒå•ÉëåûdDÒ”Õ2îY•±RsËê“Þ} ÔìȦÏ;ìÍ-ß°cŸÊŒ1nêö=¹Æ•[2rÄJ‘1Sf/–×DÇ&Šn¸—fó®ìâCÇ3²‹œ`z(àui§›‘1€Niœ5SƤM›'ÀtÍÎ}ùiSçšÞâo\.ª>&_WDÃÌ^´J,Ì[¶nñªÍ»”„K×LÊEœ,Z¹Éô€}ú!ßµbHU#])øãjŒøƒ†7\‘nÅ’RGåŠèÕ/yˆtÛLdïþâ˜Æôl£qœlFÆ:¥qzÔLÓ'~`Aå‘)³÷ê; Gt܈qSóËËWc”³zÓ®•vŠÝÄšüŠ#âÃ¥Û÷'ˆ¼Y¶NºMeÅúbyøØ)¦§»T¾Ý/I$Ç’Õ[ *Ž„«Èéޘª Óç‹5ã&Ï>P\Ù;^dLnY½ø*zÆôß”¾Áò òoØFO˜!Ýx3eŽÓC¯Kã8ØŒŒtJãô¨™2FèŸt…_—MH (1¬ÄàCL9îöAÆ:¥=cdÝzĈù–8€&!¿%€7.žŒô)¾‰2 õ!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"ch­‚ÃzÆÆLJ•<øõˆ·ˆ7Š·+i‰|.å¡Þˆ×ýðV1€N‘1´>n^¾b*7`pTŸ„ð¨Xˆ7Š·‹ƒˆC)oÊ]ó¹L‰Q®|]ÆïþªÿJd  Sd ­˜ÁÇÄ¥(ç÷¯KDJyüæ8—¬I2F¦æÃ¿è@+Ö3nÀ`å´Þ6âPV~ Õ´ç oÒŒ Õ‡WƒŒtŠŒ •‰Ø$¿ï’‰CY¹¦Ñ´ç oꌱþáÕ c"che’R›²q@åYdM[áM1á†*?¶zd  Sd ­Œ=K 9Î¥\©…•¯è@+Óh Ä' ;yNÚ´ùˆñÓL7‰—òz±ƒØMù^+%Ðè¹´hŽ*?¶zd  Sd ­L£% eؘ)‰©£„Ø„TÓM⥼^ì vS¾×J 4z.-TP¤—ÙŸÂ+^ 2Ð)2€V¦ÑH›6?ñU÷̈ÄnÊõVJ Ñsi¡ò€jþ82+^ 2Ð)2€V¦ÑP3ï'c”È@§ÈZ™FK@ͯ°Äf·ÍȬ”@£çÒBåÉÀÑ‘1´2*K@=+%ÐçR®T"cGGÆÐʨ,õ¬”€¥sŸ~f‰¥KCÍq@åÇVŒtŠŒ •±T6³R–Îe|ú™%=zÇ)ß%ŸK¹Ry@Ñ-Ư½ò€Ê­è@+c©lf¥šã\Ê•Jiü¨ ppd ­L£%À-þ¶!c"che-5ó~ùÇZÊõVJ Ñsi¡ò€jþ82+^ 2Ð)2€V¦ÑP3ï'c”È@§ÈZ™FK@º'~씤ÔтٯËÄKy½Øaìä9Ê÷Z)FÏ¥…ÊŠÏléž~3V>¼d  Sd ­L£%Ÿ4T$Šülb³`ŒÏ2;ˆÝ”ïµRžK‹æ8 òc«GÆ:EÆÐÊØ³šã\Ê•ZXùðj1€N‘1´2IênQOPyYsT‡r¥d Ð:‘1´2±ñ£ú$('ô¶‡Tž¥9ÎÞÔcýëAÆ:EÆÐʇõŒ0X9§·8”8 ò,Íq®ð¦Îë^ 2Ð)2€Ö'6~`L\ŠrZÿºÄA^y5£©Î%kÂŒQóá_‰ŒtŠŒ õqóò3ø¸ƒmþÅ—x£x»8ˆ8”òø¦Ü5ŸËT“dŒñû¿êÿè@kÖSLå“RG‰6x-â-â¯õs,ù\ÊC½¯ûá­ c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!c"c,!cŠŽàÙ©³rÐ881G3%åôI‰Œì-8¬gXdŒrÜ881G3%åôI‰ŒÞ€èØÁÝ•CÀa‰Ù‘ÊK1^d ðFtê"FiXd ¿.3"1/³#1GRNœEÆoLpXO1\㓇821#Rù[2#2@ CÆhaÈ-  …!c´0d €†ŒÐÂ1Z2@ CÆhaÈ-  …!c´0d €†ŒÐÂ1Z2xcºFD÷ŽKŠO àÈÄŒHÌ‹”“%+Èà ð ì*†kdï¸ÎÁÝ•[Š˜‰y‘˜‰9’rk£Èà þ“Cøëý'€ÖMÌŽÄI¹¾Qd `o]#¢#{Ç)×881GRùë22°·ÞqIü– @IÌ‘T^!cÄȬø-IDAT{‹Oª\ /Õ3%2°7•ƒÀ©œ)‘1€½©œHåL‰ŒìMåàp@*gJd `o*'€R9S"c{S98ʙ؛ÊÁ à€TΔÈÀÞTN¤r¦DÆö¦rp8 •3%2°7•ƒÀ©œ)‘1€½©œHåL‰ŒìMåàp@*gJd `o*'€R9S"c{S98ʙ؛ÊÁ à€TΔÈÀÞTN¤r¦DÆö¦rp8 •3%2°7•ƒÀ©œ)‘1€½©œHåL‰ŒìMåàp@*gJd `o*§iÇï=ýáÏ¡‰qÊ­fÂFO?yÖ°äžòË蟈7~u·R~Ù%vé‰+¼øõÊÇ3”ïUÉì¯KåL‰ŒìMåà|%o¿ˆKßþ*gÌÍK[•;˜I»ôØóÓÒ1òK³Œ™{AÚzÿÞå’ÂÑÊ÷ªdv €×¥r¦DÆö¦rp¾R×ArÃO^üÓ%X¹)óÆð êèäí×E~™sç{±õôÒ$åÕ3?ÀkR9S"c{S98_iúÙ‡¢¾<Ÿ~ûùob¡vò¿+‹ßqY¬¹}mK÷Ñ›½óèŒþé·^›G¾óÇÕßÐõ[3Î>þY¼¼t(oåJéjLÇ€Øuù'.Ü~öðůwï?“®Üú|»q«œ1÷¾~ëú3iŸ³†¯ÝYòõ†ì©Z»~¦—IÆxûEóC¸sc—غô̱üäùóO/]¿öTúéÚ½{g¼ Ÿ\tMÚôý¯W®Ü¼e(¨kïíë•§˜T}G¼|üÝ·g?¼té”I÷î}ìßpý@IåL‰ŒìMåà´®ûÈ#RK¼ø¹oPpÏéï–ËòV9c„£·3~@éˆõ{cÜ•~T&‚G,{ÄÜýæÇûßþ´°o„xé±P>ZrH¨o׉¿ÿ“XÞ1¾ŸØ=ûÁ éåÌéZÙ)ä[wʆÅŽÙçÌ×î>Þ- Q*gJd `o*§u ?yòTºr²_,û„Œ|lH‹úiñòÖ†«1÷®ŸÈÔgŒÌÛ?bÀˆ©sVl=pô–œ1CCCÃG½#>¹lÜmДySf-H UžâÐýÅËGß<<|¨bÙÂ91‘Ýïh”ʙ؛ÊÁiEÇÀþw ¿æ:³*E^³÷¶!·®¤Ë/¿7æ¥Ç—½VÆ ^[ö¥ái_ýõ©SRºÈ³ô¼ô®;å¦G¶tŠÐÁËk?¼õÄXO¥ß¡ýöþñ¢Ã4R9S"c{S98­ˆœô¶fž¼ø¹_Pˆ—É-þ¦ïRŸ1¾Ý¦<üþO¢:æ ½ì:A>¾È˜ˆqÒØ>þÌxؤ´ã'Ï,·Ñ'•ôL™ºlgññÏäKF§–izhÝTΔÈÀÞTN+Vþ­²ad‡gô÷²š1—_Zɘ ¾¥O¥(ú!ÚðçÁ>’.2Æ/l¦|u%s’t¢€^ ÷ÆLîþÇí7ò):G®ÿôòÍO.]5Þ±³ãæs±õÜ.­|Њ©œ)‘1€½©œ–ø –ËáÄËÿÆËÞ›ÒóŽo]Íð²1Cêî>•îT¹S^¾ÉËjÆø„Œºex Úƒ_ôÅÃ'ß5TÓ Ã}ü³«nJ‘óý/—.]¿iØíʉ†™žÂÛ/â˜áÞ˜‡OîŸyÿ“sWŸJïzñbªá R9S"c{S98-‰žûÔÏŸ¯rÈzÍ:k脟û…4š1þÓ_øúÞó_¾¸#ÇrÆH[§í<{õÁ½ÇÏœ:<¢O´üpçó¥c¥­~Ýfo/?wíñƒï~ºrõZîŽåÆg(›Â?bÔ®Š3oûðùo÷Ÿ>;wöäÜ‘}M?€•3%2°7•ƒÀ©œ)‘1€½©œHåL‰ŒìMåàp@*gJd `o*'€R9S"c{S98ʙ؛ÊÁ à€TΔÈÀÞTN¤r¦DÆö¦rp8 •3%2°7•ƒÀ©œ)‘1€½©œHåL‰ŒìMåàp@*gJd `o*§™Õ'ÊjO–JN((™™6H¹u1«J7‹Q®·M@Ï­¹9#•ëÕl5ò ›]X¼F¹¾™ø„Ž[¹j¬—ÝÏ ¬S9S"c{S98­3ª[WiÙ7(,arAí©a] / ¼ýÿX¶Do#>³wç^}ãû¼´R±Û+ø†tôU¬4ám²Õ¯ûü‚‚ùÒJ³óú)ßìFåL‰ŒìMåà´âŒ1XXrt]|Oß®“ļ³IÆ”ÕNéîå4|sÕ®¹ ^¾A«ËŽMNéëå:xYIyýieÆl_7§K t!¥‘³„Ž/¯;µtô±¦Çˆt‘4^&WcL3&wß²Î~]¢gˆS¬“ V&¯*Û»&E,ô[V’µ~v€¿î)Û*O’>ÞKŸ4 •3%2°7•ƒÓ ‘1¥‡Ž 5' J*çM‘(’ ´ºBþUU)yû· “wîWV{4 8©¬¦>ÀpiE—{ØRÆôZP´{y²¼Æ¯û”ÄÈ®CöÈÕpv¿°’Ú“!þAkÊŽMé&¯ì15Ï,cݪ<—ég6͘Üì4y·®ƒ÷ï]7Яû¼¢Ré“à<¼ÑŒþûÏê9KèøÒêrù'j>!cŠJ·xYȘuý{Joô -¯;éoø®‚öä¤K_ﮪIòe(ŸÀ^óŠv/K2ž4!•3%2Í˵ÚÃc€¿r½#S98­0ûQ™L$AQévy¹Ïª²3â›òjNõî1¥¸"˸&vS¥¥Œ‰O?´eäK÷¨DÍ-,.+ÏÈ.6êœuèdlPô>0&Ã,cݪ<—ég6͘¬M -èšš%2& Wz~ÞLy·D£ÓÃðùÆÏ:¾¨l§¼Æ'd”•ŒYÓ;BÚÍ7¤¼î˜¼pCƈ5õ§3M¾+J4-•3%2ͨÃï6ÿ«Óß;uØê­Üê°TN+,gŒ4A÷2\ÉÚüûÕ˜€¾åuǃ˜^š]gÌ_i¥·Ï2Cô^V’±(QÞͯûøqcûv“µyHÉ|ƒc⤠«L®·tsÀ,cݪ<—ég¶’1þáK»u ÚhÆ„4ÜšßÈY´gŒ!Ì¢»4”’_þ‘ÝBåeдTΔÈ4D§¿8‰Œ‘µ»ÚÞ³ggånHåà´â•ãÛ5­¸º*)*ÜË74uaáÁݳÄʹyG¶Ì%¦õÁ±“ kNʳ§úĸ>ÒÜ=~Z¶œþ=f—Tæõ ëêå×mbFͦ´XŸàáU•ƒb¤\õMÛ™—³H,Ä,,:¸geP@OhÿueGÍ2¦Ñ­Ês©Ì/¿°U'&$F‹ˆ´¸ÐzÆ4rKS¸Üô¼Ö3&eceæÊéý»t î·¶ìØ¤ß# 4-•3%2ÍŵÒÃØ02§¿vv›×I¹§£Q98­xeÆ=†.L?X[V³mËꈆ'•%/Ë(Ì«<’µgûÀ)yrÆô¿fiýÁ²cû6/Þ^Ùð°Þ£Wdä×ä–Ú¸j¡ŸáNØÀÙ;Tå•Õe¤oék¸EÄÛ/|Âê}9åÒ³¿Æ Zd–1nUžKmÆøô¿å@unAéüqCËjß2=—×ËÓÈY˘Ž]3KßÊ̘«2c¼;GMY·?»¬þ@QÙÜ)ƒÍ>h**gJd šQ‡­ÞNÿÇÉ¿´q9åæ ÜÙq¨œöäd¿k ¶œË¯Û¢U‚ý¥  °2?w™ù ¶œè€Ê™ƒæå1À¿í7.f—eœÿU;÷Q¾Ê„ÊÁ SÑãWî:P”‘S’ž±£_WîK ÕR9S"cÐüüÛ{¶ù/•ŒxÙ¾ÐSl2ßÙ¨œHåL‰Œ¸öuþßÛš]–iûÔÅ£¿Ã=ŽYåàp@*gJd ìÇ3$Àåm·6ÿòRÉ8ýW§›ëqÌ*'€R9S"c`on :9ý³Ùe™v—Û{F:Êã˜UN¤r¦DÆà ðŒêÜîZ{³’qúÿœÝfû(wn}TN¤r¦DÆàé°½±Ç1Ÿp÷ jåcV98Ê™ƒ7É#Ñ¿í3Åã˜ÿÜÎ}Dk~³ÊÁ à€TΔȼi]K=ÚüÏ—J¦ÍwjŸçéå§Ø¹UP98Ê™]pëëü(ÇüØÅ#¾>ŽYåàp@*gJd ôÂ34Àå]Åã˜ÿ‹S‡­íqÌ*'€R9S"c /n‹:9ý­âqÌ—:xöh=cV98ʙݑÇ|Cñ8æçì6³•<ŽYåàp@*gJd tªCº·Ó_^~ó?·q=êîÕ¥Å?ŽYåàp@*gJd ôË#ɯísÅã˜kç1ÜO¹s ¢rp8 •3%2úèZ®xó?:µ?Ø‚Ǭrp8 •3%2-€ûx_ç­xóCW~-òqÌ*'€R9S"cÐ2xv pyOñ8æÿìÔa}GåÎ:§rp8 •3%2-‰Û’NNÿ^ñ8æ‹<Ã[Òã˜UN¤r¦DÆ …ñŒîÜî–«YÉ8ýU[÷é-æqÌ*'€R9S"cÐ"µÏôrúÅ㘴ŒÇ1«œHåL‰ŒAKå‘â×ö…âqÌ¿¶óª÷Ç1«œHåL‰ŒAKèZåÑæŸ^*éqÌÙ^z~³ÊÁ à€TΔÈ´xî|ÿâqÌ÷\=buú8f•ƒÀ©œ)‘1h <»¸œS<Žù?9uX£ÇÇ1«œHåL‰ŒAëᶬ£Óß™?ŽÙåÓžÝõuß¿ÊÁ à€TΔÈ´*ž½;·»£xóÿÓÖ}ªŽǬrp8 •3%2­Žo`û=^mþ›âqÌõzy³ÊÁ à€TΔÈ´NýœhgvYÆùçvƒßüã˜UN¤r¦DÆ õ p=ÔØã˜³¼¼|;Û‘ÊÁ à€TΔÈ´rî“|œÿ­âqÌ_¹zöyccV98Ê™ƒÖÏ3,À壿cþÎn+ßÌã˜UN¤r¦DÆÀQ¸­èèô^~ó¿´qù¸ƒˆåÎÍJåà´bß¡“y9+L×øvT^:È¿‹rgP#0vüòyUÇKªŽìÝ·wâˆòú€¨ô¢²Êý ™¨œ)‘1p ž1Û~eþ8fçÛÖ}²]ǬrpZ!2FDË¢A½ŒkÈZt ’[srËâÙ½¢cºöŒKN[VP{jAªô—ŒOÈèñ“F)ßÍDåL‰Œƒñ l¿Ï«Í?¾ü8æjãZãáh§Ë2*§"cv,-(©Ì þ½[ÔgŒ·r%‘v°¸"ËtMìòÒ‚‚ÅÊ= ¹©œ)‘1pD©~Î?)Çüc;Aöx³ÊÁi…ȘEQQ«JŽîZ0H^cš1±×ì))Nÿ¯³Ùe™v_¶÷ìõŠÇ1«œHåL‰ŒlçѹÝgŠÇ1ÿ­³ÛbkcV98Ê™hÕaCG§ÿ¬xóY7ÏÐÆǬrp8 •3%2hqþm)Çü¶u×Èã˜UN¤r¦DÆMÄ/°}®g›ÿ®xs™‡Wç—öT98Ê™4%÷¾ÎR<Žù;Dã>*'€R9S"c€¦àzܽͿ¼T2Nqê°Ã[ÞAåàp@*gJd Ð,Üfù8ý;Å㘯·÷Œêl}pz†˜ý ÀqXŸ)‘1@sñìѹÝçíÍJÆéoœÃÓc”;7ð oi_ìi¾À11€.tØìíô_c>ãæÒÈã˜;lô–vøç6îi<â  Õ#c½ðˆ÷oûÄÅ첌˿i<§GxT¬Q×Q½œÿ¾áwhíþÊ%,1Æt+€# c=ñl_àÙæ¼T2âeûφ;aüÍR§Ý…^¾Šã´jd  ;î£|ÿ7Å㘿uñàß>ßÓl½ÐaSÃÃÍè‘gp€ÿ'Aæcþ§6ÿlÞ0Òú¿8™þƒ3­è”œns;9ýµùã˜Õö…‹W`#h•È@§äÁéÙ¹ÝóÇ17ʵÖCy€V‰ŒtÊtpºuWv‹’Û åqZ2Ð)ãàôŒêìô7ª~Zæô×Ξ=;+ÐÊ1€N5 NßÀv×Tý¨LÖîF{ž¿ Z=2Ð)ypvØî­lëÚïöR  5!cƒÓ#Ñ_zȲ"T^á<†ø)Ðj1€NÅ¥iûÜÅ®GÜÿÕË—hþ©û_Q,Uõ'E±|~ãë´©³Mß(^Š•b“ØAìf~XýQ9S"c{S98åÑß¿C†W»/Û·ùGé÷ßuºóóww~·iÇåÎ2±Iì bF,pà ÐhÈè ùå‡ËëO bA¼TʙØ›ÊÁi]ÜÐÔ’_jçþí’Q&¼2NÄù¥5ò 3ý“‡(w°ÁÔËߊîëÓC¹Éžü#VŠq÷ÖA妿½àqº²G(7iWøÕâàCCC;ĉ…>UîèM@ô¼;ç+×û‡Íÿ7žÖ͸&4uãíç¿U¬+–ß{ò³|ŸðäÙ>:5-µ—ò ô)¿âð¦ôìÉ3 bA”Œr-TΔÈÀÞTNëä_‹å•zeÃÈÄnbgùnåV1MŽŒÁ›7³èèG_<úáòçç—MhøjÇ€~kòß¾pûÙýGOTì‹2}‹·²/_|u·Ry4³Œé»àóo=–9S~)2æÌÊ 1ý’„¸ã3N>xøÍín_:8Ý*¯?-F^ â¥r-TΔÈÀÞTNëžn†‘³dÖ‚eÊLÍ^¸\~€üå6 cšƒ7¨SÐÀžþr$ãÿoïNœ¢¸ò8€ÿƒr(‚\Ðp® &ê%ˆ‘H\PÁDlp1ІàÁ!QAtˆ ÅŒr3÷á‹àŸ³ïõœñ‰V 5ߪOYݯi(žõûN¿×ýSÄú˜ÇoÌÆxÒžÕjìn.ýÕð·V1Л›¾ÔR³žµ{oø¶´±K14Ñ70xõB–·Ç*ûËf1æQñ±Â†n•y¼µ¥épbÛ´ON!gײÕZ=3¼ÒËÍ'‰,¨”·ã¼Ö©Wku–œ[án9ù¦ô+MÏôZƒ±ôìþ’yb Ï…¼§È“ÊÁRëjFqűè 7ßÝäOq§¿/ktõÙaŸÚ,ÄÂoó9•ªiÓvÇ1ÆÕû³JÅ‹G·²–»Ílµ‹1»ÈÎßZþ€ÅiÃg_°dó!;صœ•b €Ø8;§c,ư崃GØ$þÙcÌ‚Â"Ù(2²‰ìÀß9Ƹù=%‡ô´7ÝjPM‘"&ó³PÉtŒ1Œ¿îxP_Ýa$Ëje©Î]}¾TŒNÌÚ‚ü+·Ó èºj{Úé£7MÊ•Õu’eãø«ýk$î~uú ò)U·*òo6èÆ^ëÍjR¸»¸¯©ªüÖڻŕOÈ‚JqßÍm&Æ,óŒ©T¾0ŽŽÚLκÿ>iWö>*(¾YýŒþõ¿l"íÞÑÿ!ç4Ž K+»Ì¯´c¯YŒ!õÙÓáI½Ys1÷b~eÙ_~oŽ·î°c{­x&³\öèè®54P9Ž1Ʊ1µ¦»¢ª©dЬÞþödŸ}R²L~Ww¤ ró$ùešìb ç…¼§cÝ#-ç¶’…e«ff³x¦“?9v[†nZNþJ‹"h[¾*¶A?ö}tPHj›ƒ“¼¡D>¢3u{NGw†Ä˜ûé;CÖÇë7ì8]¥îi-°? 8'ÎJ 1@lœÓ1Ó¬#¦¾°ˆ2 5“‚½Óæédïc¼£KL4$”³»¡©5dµ_~F2cäu?“ewÿK}cdõRìZôÞ+!´ OÏÉÿíB‘»»í™YŒÑh›|„›$ ù½dUv=ÑÕ{kÁåy¹Øi¥Úÿ‘öí~>>qed¡¯ó,;ü¸L«4Ž°Ä˜+Yz~ΧÒx@DŸ¾BΓ"|¹´«ìÓÕœB–´ÓÄuó_1dÙoËEM4ÆDŸ–“åÚïÙ!¯R5LÖ/¡­XŒÑèZ}…Aüì²;Š$o‹1³!Ük5i_w˜þàϾ&Ë7Ô/Éòñ¸µdÙ'îŒI˜îlc8/ à=ÝÖ¼lÎ:WýD¥­T*sŽî¡ín>RÍKÙõSŸøû¯ Œ>zµ›üùUl#›~¬ÑÜ?»“,8Ž1÷eæ§ÕWzG¦J¿Û0{ëì)þ&šó'²Ñ©ÿ°È^—&ì¶Lr›mÃg_|¨eîJ 1@lœÓ1Ó›1†¡ï‘Ö²²€,Ø¿+æ]cLD½áÐ|Æòp³ež1dUgê“Lǘé‰0"…íIrÈã¡Iv ò'írÎl ;l©ü[Þ¯evùû²#+Kd‡{†Ò ì¦É#8áxηÿ­¡†HðóÊzJ2âm®Å`è¿c)ÁÖA)^[¿Í¼TV÷ S¡£w9ºþ¢1†¥‹h!Qôˆc¾z2Ä>k¶¢ˆà€mRëe—îŽd1¦Sj¿çšC/»çœäm1F­´<Åeu4‚äb–­ 7Ñ_f¯õgi ;›3ß…Yø êõ:SÏ7ÛâwŒ!:ªûÉ¿=i¢ â£ãÙž?¨üùØÑ])–ä ™Ž Ÿzy³ÝdC¯XŒI’Ñ»4ù~grªUìjŸÀÄ&ëeפÆXbÌérÎDcÌo’ésnýÜ1F¥¼ÍÚWGY.f¹W¼‰Æ˜nëÏR¥£±Í&ÆÌwaÖ£>ˆê—-ggþkÚÝjxÖHï2ËV.w£O-#?ü³FmíV6ü`1&Er)qó)è}^ʺÕfn ‘ô—¾çÑþÙ-°ef_ øÛ†³RBŒgçtÌ$JŒY}ÕD•Ý´|íº·Š¬<Ï‘X•ÕüD÷tó9ßCçŸ\Š Þ{2ëlnZ-h\ýbØ´õ¬PKqoÅbŒZSÏ&¬oË¥³>l÷ŽºCºZè k—!$f˜„ãÿ9FÒ+Ëf‡oW èF|âÏbŒZUåêxOHYñôí—ôs¿_…§‘†Å˜Œ.:‰èJýÒ×;&Ë4=¨ŒÅ°ú£–˜”ük^öù|’¾l.Û2¨LÛİícÓQB•¥¿ò/é \½âFé "1Fâê%n[ýôzkÅsýsÎá¼0€÷”Ò¬o/œÖuàñГ ×-ºy Ôò±€/¤º¡ò¿›ØšàO™ø#2µRJV½9ûÅæËžaéš±×yÓ÷[ìcÌÞcW[ÚìX„æ‹+óµ/ g¥„ 6ÎÎé˜I”CòIIÍ']­ ù7ê”Âÿ“[f¦ømõµÒ6z§EÑw—Ô7‰·L´Ð—ç]Èÿ½¸J1:¥V­õ´}‹1†¡©þ'm¥weÆñ׆ÓvßA'hûˆ©¤ø†T6Ì*ûä?à»Â³¶»•E·eôãz¥ËÞ|RYHÚ=²¬ººyì0ÑËn®¹|½V!$ŠžŽ}dŸÀ¤Rz~³¡üVÝÓáIú¹lŠÿêíró¤qt¤ðâÅ‚J!ö4çÙþ6¦c Ñßù°´ÚrÙ;„°uŠ>x@?¬.¿Sצz¡îD9Œ1ž eƒì²[÷›^çŠ1œðž¼"35fã±½‰ŸG%¤èÆ^~'ÜZüZªê{|=6"µùU߀âÚÅ3þo¾æa1F^_Ñ6¨yã²]V„ž.kïÑO(Ôƒ¿}·ù­ƒÊ$ô¹O‘…5m½C:ÓPÙÍ÷Àež xûÐeÔšGÛZ›öï˜~ý¥gtvyGáOŸÈò².³;Š?ƸxKÕ/Ÿ”ÿ ysŠ¿q|J¡Ì;‘jXlæ›3ßœ™…ᬔcÄÆÙ93 W¶o—8Œ1…Ð[%öíâc1¦%‡>àULa;’v}!ÌqñX«›Òêeö»€=ħÆÙ9˹PDb@s‡Üþ­—sƲٙB´?›ø>VŒI¨PÏ}V—Ÿ¸7ó&}\òÃâdûÝÀ^xÌ&’Xý”™œzÈŠ¬’F²É~ÿ…ᬔcÄÆÙ9ß*iOÚÓ)ÄoÞ¹7ûÙÊ61†>…ù4Bv&‡ØŸç£ÜUp§¦1÷ å5/¢qY¹>£¨¶S5j›ìè/ÉË´™— df_ ¡ÅÆœß/á®”cÄÆÙ99ežþï Ž>}Ëú¦KkŒ±¾“ì0ßD€E…³RBŒgçäGâ ›ô2 5§~—ÎbLÚÁ#d•4’M,Þ,~œ•b €Ø8;ç»Ú²=‰¤ö䆬ÚÏœXÌ8+%ıqvÎ…I;xäiŠ ö[9ÎJ 1@lœÀ qVJˆ1bãìœNˆ³RBŒgçpBœ•b €Ø8;'€⬔cÄÆÙ9œg¥„ 6ÎÎ à„8+%ıqvN'ÄY)!ƈ³s8!ÎJ 1@lœÀ qVJˆ1bãìœNˆ³RBŒgçpBœ•b €Ø8;'€⬔cÄÆÙ9œg¥„ 6ÎÎ à„8+%ı…EÆ®ð°opr¤F"•’}»=ıù†…EÚ·89R#‘JɾÝb ÀG뻆«‹8 RqÞŠ‘ Æ|nž¾¤—…Ebt©ˆH]Dª#R#Ùob ÀGãH¿rˆŠÛàÌè@¾±dVˆ1°Ä ÆÀƒK b ,1ˆ1°Ä ÆÀƒK b ,1ˆ1°Ä ÆÀƒK b ,1ˆ1°ÄüW–<6˾FaIEND®B`‚qtrvsim-0.9.8/docs/developer/build&deploy/release.md000066400000000000000000000036631467752164200225240ustar00rootroot00000000000000# Release process - Check version in root `CMakeLists.txt` - Update debian changelog - Make sure, CMake was configured with flag `-DDEV_MODE=true` to enable packaging tools. Without this flag, CMake will not try to do anything, that would require an external tool. - Run `make open_build_service_bundle`. - Deploy the contents of `/target/pkg` to Open Build Service (and Launchpad). ## Debian changelog Debian changelog has very strict (and little weird) format. Bash script `extras/packaging/add-to-changelog.sh ` generates a new entry in the changelog and opens it in `$EDITOR`. Edit CAREFULLY, the format is fragile. After that, changes are committed and git tag is updated. ### TODO - Decide, whether this should be replaced with CMake. - Get version from CMake ## `open_build_service_bundle` target At configure time, package related files are injected with up to date information from CMake (variables prefixed `PACKAGE_`) and copied to ``/`pkg`. This target bundles sources to `tar.xz` and updates hashes in the package files. ### Generate using GitHub Actions (CI) In the repository page at GitHub go to actions tab and choose release in the left menu. ![](./media/obs-ci-step-1.png) Click `run workflow` and select a branch. ![](./media/obs-ci-step-2.png) One the workflow has finished, the bundle is to be found in the artifacts section. Upload this bundle to OBS. ![](./media/obs-ci-step-3.png) ### TODO - Package signing ## Open Build Service The easiest way to deploy files to OBS is the `osc` cli tool. - Setup credentials. The first run of `osc` will lead you. - Download the repository: ```shell osc co home:jdupak qtrvsim ``` - Copy files to `home:jdupak`/`qtrvsim`. - Add files to tracking (in the `qtrvsim` directory): ```shell osc addremove * ``` - Commit changes and push: ```shell osc commit ``` - If something went wrong, delete th directory and start from th beginning. qtrvsim-0.9.8/docs/developer/coreview-graphics/000077500000000000000000000000001467752164200216115ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/coreview-graphics/media/000077500000000000000000000000001467752164200226705ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/coreview-graphics/media/data.png000066400000000000000000000435451467752164200243220ustar00rootroot00000000000000‰PNG  IHDR(ìwþÁíG,IDATx^íÝ|eâÿq¤(UQAÀ³Põàål(ØÅ†`9l§žŠb9ª4EQŠ¥©p‚À_@éMðð蒃ЂÒ!HOHæÿeŸãq˜ÝÙɆ|Þ¯}éÌ3uwçy¾óÌ Ù"ÂoéÒ¥úïÁƒW®\©ÿÚ„?Ÿyt´·Àq1ÿËÊÊÊÌÌ<ŒðX¶lÙqK·‚?áà’Sí-’"FAóGðh$###99ùÂC'ÝÇ-AÞ þ„ƒKNÝÿë-’"FAc²çHð(ˆT´wïÞmÛ¶ý†0X½zõqK·‚?áà’Så-LᢈQÐ(nþ<ê)Ž4!&&濃µk×·y+ø.9uQQÞÁ.Šâæ˜àQ(iòÿ O)\19¹ùÀ©#x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾"x¾ <ÑÑNtôáèèCQQ¿EE<€¼"xz<€°!x¾"x¾"x¾ <ééNJÊáýûÅÆ<€<"x6lpbb¯_Hå<ÕÈ[!‚ÇáR l"(xž}öÙ[o½Õ ýõ×EŠ-zÎ9çÔ¯_¿C‡{÷î=f Rµoß¾eË–fxâĉ:’×®]kF›4i2dÈ5kÖèØþÓQùË_þXøX?þø£­\¹r¶Ž3gμâŠ+ÌðŠ+öù矛Ñ=z<õÔSÌš½ñãÇ—,YÒl¢V­Z¦°sçÎ_|±J´þQ£F™ÂzõêéíØµ3v’[—.]233Íp³fÍÊ—/oV^»vícgÌÉYg•’’bGçÏŸ¯w÷ÁØ’Áƒ_~ùå]tQÕªUµEÓ~y¨ùºæškô5j¤Í¾ýöÛZD_Ê‚ Ž>‰èàùoÀÂ…  P³fÍÊ•+oܸñ˜e€ˆ¤<¸òÊ+Ͱš¹ ˜|¸Ú„uëÖix÷îÝ7ß|ó믿n—5~ÿýweÞ† œ@“bßã¼yóÔ¸Õ¨QƒàÉ/<^½ú½÷Þë.ò]||¼µ¶j.@h@ ¢†Õ_Wcmò`É’%êFh »ài×®Îâuz®¸R̸'mÙ²¥L™2ªîBQ›;fÌ'pÿú׿Ô;®„óÌ,M›6½)@-ïu×]çd<ÖêÕ«K•*eÞKvÁÓ©S§-Z<öØc·Ýv[ëÖ­Uy6l¨©ú<Á3kÖ¬¿þõ¯êá©#bCK!§½Òõç?ÿ¹_¿~¦Ð<¯½öÚˆ#^~ùe<ÕªUS_Ð ‹¨xñâž‹"Š­Ð kÿÕÅT³f§<ù¨ÀôìÙSgRæÐÑQ¨¸ø†|2xœ£y œ¨]»¶*Ôe—]æ.=óÌ3N xÔ^zÔ“O>©Â &( ÔXkþ|Ð<;v4ËztèÐáÕW_u ·cÇŽûî»O}%Ü%—\âÕEuG 7mÚ4'Ê.xÞÿýV­Z©™~饗4ªÎºò I“&Æ s²éñ¼þúëŸ}ö™V¸ƒ'33SðË/¿ØKíòUW]¥„3÷>ùä“Ï?ÿÜ&\Hjß•‹ 0£ûöíSh`ÕªU^x¡VèžY1P«V-Óʛޛ¤ ûý÷ß;ày÷Ýwmy—ÚÔoûÛßþvà 7hY¥‚R{^¢D‰[R€é´Ò9 þøã~ýú©©UËëd<}úô1Þà™>}º¹†f<÷Üs5TÔ:«S¢*óâ‹/j’ÓæÍ›+áÜ}u°Þzë-oi€bòÃ?ôÞtÓMcÇŽuñé^­:s¦­ï`ËsíØ_|a†ÕÁš7ož’[Á£,´ó&x”L*T0¦²eË–/_^©“ý¥¶/¿üÒ|2ž·¿qãÆR¥J¥§§Û‚'¤àÑIœŽ-ÕsO9¿*W®lNÉGmƒÇäZ73é?ÿù’C­§™2xÔ’fw©í±ÇSt¹æ=FÆ µr“pjñ«V­j.˜B+·OÉúõëM‹¼iÓ&íáäÉ“Àgeei`ñâÅê+˜>墶•˜˜è’U‘`®:x‚GIl»#žàQÿcΜ9Nà™Ug¸,©‰Ù܆ ̲ž§ÚWG¾ùæÏÃê_ºg6Ì“j4xàÖ­[»'<ù¨Ày¸à¾ûîs‘`̘1õë×â‰'ºuëfƒÇ \‰2·vD-{éÒ¥u›QÏãÔbÊÛµk§EÔ¸«·ÁW¦L™;v˜Ñ`šYõeÛ¶mfôŽ;î° ç¡Ž…æTWÃ<_ð /¨°k×®Ú /¼PM¹ír)ê¨*¯S§ŽyxÁ ¤ššoͦV»Aƒ&6œ àQ<\~ùåZ0øáÅÕõ×_ÿÔSOµlÙ²^½zf ÚsõÒ´ÈW\¡Ùºu«s¼à‘ÖªU뢋.Ò›íØ±£i¿<ž~úé*Uª\pÁ¯½öZZZš)TÏRïKݲŠ+f÷A!¬":xOSÿW'\ Ðæ~œzúôéª6ÜãÁéJÝÏÃÀi#¢ƒGÎ8ã uó¯½öZõÄÝ÷yª §7‚§±Á£þ($8 ìÙ³çȃb.Ÿ~ú©w&Àw!‚gãFgÆÃ11ü‘P@Þ ]jÀWÀWÀWrm×®]/¿ürÍš5ˈlª§ª­æ‡3"Áƒ\{î¹ç¼G7€¦:ë­ÆùŠàA®]zé¥:”ýõWïFõTµµzõêÞ ùŠàA®™s(o)"[ð_ÝE!–àA®EàqŒã"x ­ì*lûAÇüðRÈ’0!xkÁÇñÔ©SÝ•¹@kРA?@à¿J•*™¿[øõ×_{§åÁShWX'1æ•CIø<ȵàãxõêÕÿøÇ?Ü%'­N:=zôð–æ©øøxµÂK–,ñNèÚµë¤I“¼¥ùíOúÁƒ“\a wÒø™:Áã›2eÊŒ?Þ[Z0ewç‰|žÈDðà¤åPamÞø™:NÈà‰‰qÖ¯?¼~ý¡èhþHhž9]ƒgΜ9æBçRÛš5kTøÕW_ÕªU«\¹r?þxrr²™´oß¾Ç{ìüóÏ×gR¯^½ÿûߦ¼FfU–ûkРAÇŽßxãsÏ=W ¾ÿþû*ìß¿ÿå—_nç¹êª«>ûì3;Ú§OŸš5kžyæ™—]vÙ€Tòûï¿{6!Ê!3ÿ­·ÞjJ<—ÚvíÚõÈ#h£gŸ}ö“O>iÊl½K—.UªT©P¡Bð/F{dee]tÑEúLl‰¹úê«À©Þ /¼P­Z5ííÅ_ܹsg÷/„:¡‚Ç|Â;wî4£­Zµz衇Ìpbbâ+¯¼¢]:çœsš4ib~Š´ÁSXå<Žï}#Dðdd8©©‡ããmÝêkGÕ²wïÞ¦¥¸ð ß}÷]S¾}ûöæÍ›«ñRÍà6oÞlÊ?øà5FƒVEÕ$ÕÛôôôÏ?ÿ\u[m“Z(ó~äöÛoW=T“¡â¼óÎ{ï½÷l­Îyåj¹Ì£ÃÍš5Û¿¿™$“'O®_¿~É’%5Uûi'±X±b¼ûî»ÕBU¯^}ôèѦ\³Ùf®R¥Jv=Tðq|Ç4‹>ø`BB¶mÛôÉë“1“Z¶lyÝu×­^½Z âØ±cÍ![Ùõxôu\pÁjå÷îÝ«j‹NŽÁÓ·oß²eË2dÆ 3gÎlß¾½-çOð=µÝúº—.]:þ|åè3Ï“éÓ§+3ìÇeä*xó 6\´hÑúõëU/®¹æšŒŒ ‚§Ð ®°Võxœ|ºÔÖ¡Cµ× µªáæçr•FjÔN-\¸pÙ²e:'­]»¶ÙQÕXͯʦaÒ¤I¾çž{t*­Ùt¦\ºté‘#Gš5+xŠ/>|øp­-&&FAÕ«W¯ã®\ù÷úë¯'%%)rÔî¼öÚkfm³fÍRJ 4hãÆóæÍSCiì]Í2fñâÅZóˆ#ÔÛ_#öôxÌ©·š][R€ÇÙýM{5ÖÏ?ÿ¼Ö×ôÒK/ý1ë±rž›o¾ÙS˜Cð¨GÕ½{w;É-WÁ£Z ™m·L_™¾åƒ:­+ÛÔ¦›I—\r‰Ž1»`H:Ò´¸ùC?Z³²Á;S Eš6mê.9ñàY·n"Ðx©©©:’µ]‚§Ð ®°†;o|ΞH µï¥J•rÿ6»¡ÓaÕ"¥…U¥D‰¦W6¨§¢j3é¹çžSoÆv>}ôQó{òN xn¹å3ìÚ ó÷9¯\kSÊL0`ÀW\a†5jÔ¶m[3,sçÎU×Çt¡Ô¦ôìÙÓNRçæûï¿7ÞàÙ³g8áÚ’$ø8Î.xô‘šQ5‹?ü°þá‡4³ÞþÛo¿­ÿc™€‚çwÞñf<;vìpÇžG®‚Ç\K´—ãt´htåÊ•N`ëê Û9µuu‘íh½zõŠ4nÜØJÕªUuÖ¢må/ù‹-×Ú®¼òJKEî¼óÎ?–ÉMðŒ3ƬÁmÔ¨QEžÂ*¸Â:¡’&¸$|"%xÔáPÅˆŽŽö”ñÅ•+Wv—¨¡éÖ­›Ȇk¯½Ö–·k×îÆo´£o¼ñÆ<`†<¶¿"ê¦h[:iÍyåêåØrçž{î¹fX]+O­õ`œ@ð¸ˆRKÔ·o_3|ºÞã1² žàfÑP0¨}â‰'ô‰õîÝÛ–;9¹*åöù矻ƒG wžN4³½¯ã ž±glÙ²å¿[·nµ…òÞ{ï™PÑÑkûdãÆSý§Ÿ~Ò˜Fß|óMÏï^ÏÚµkÝŸð+¯¼bƒGçpês»gv¸ÇSˆWX#8c‚KÂ$R‚géÒ¥E² ž*Uª¸KTÕ?úè#çèm[Þ¾}û[o½ÕŽªê6iÒÄ «¿üòËvÒìÙ³‹ ž\¹‚çœsÎ1ÃeË– î™jFͽÃÝ<îà±^ýu÷·&×_½ù ÂÚ¶m›vlÆ fTG»ù„UgU®õ»gvžÂ꥗^ ®°ù.R‚'çKm7n4£æjØ„ œ lÈ9x®¹æ;©k×®^x¡“›•»ƒ§aÆžË VÁ£“?Ÿ¤‚ã\OÇŽÕ/ŒU|õÕWë›úc1ÇiÑ¢Åm·Ý¶k×®””÷“]!ƒÇÜϘ;w®y2EŸ¿ûá‚råÊ 6L߯fèܹ³{AêyèäÃ^›µ<Á#÷Þ{¯y¸@]¨ZµjiMùÉÔ¬YS3+bmÉàÁƒµK{öìÑð¨Q£”Lžàyê©§tà)¨ô‘šÞŒ>…n—.]4¬Sõ±Ÿð£>ªýÔ—²iÓ¦)S¦4mÚTï”à)„ÌÍÔà ›ï"%xœÀµ²³Ï>{È!j)t¾¦îˆ)o ’àûÿ'öØcÏ<óŒý„^{íµÊ•+ë-èmj8--­ÁSÈØGx Fð¨÷¿iÓá ­[çë¿ãQKñé§ŸV¯^]µK§r­[·6åêˆ4kÖ¬lÙ²ªù÷ß¿ç‰g»xÎÁóÖ[o½øâ‹Šõ<ÞyçóV^¹;xœ@ö¨(]º´Z¢zõêÙ[Ê9ÏŒ3ÔH魙ǩO³§ÚùžBÅýàhVØÁ“’â$%Ž‹;ëk'|<6Æpêþ8Žo»Í1¡«ÿ2l†þû³Z´½ˆ/ÃOááNîñä‚'os«K§vÍtì6Ã9Èn‘ð<…„'uœ‚Òãqä¨zõêåù!8 ò§ÎܹsËóCp8 ðÓ×@ÁbÿnH„<ùõ·ÚPPìÚµëÿøG5¼G7€S³fÍ–-[îÞ½Û[óUˆà‰‰qbbŽüuj•ûùT 0<—ÚaCð|Eð|Eð|Eð|Eðàd¼ àðVàüFð ×"ð8ƒH«³r-Òb9‹´:Kð ×"í ³H«³r-Òb9 YgÛš}Ü’0!xk!bÙ°aC‘"E¶lÙâ§|饗zKd/¸Î*cÌ+‡’ð!xkÁ±Að‘)du'Ÿ©ã<8 !b‡à"UvuÖæŸ©ã†àIOO÷áԸ℄„¿ýío¥K—Vô ü¾² åP“&MÊ”)S¥J•V­Z%%%Ù¥¦M›Ö Aƒ³Î:«råÊ/¾ø¢-ÿæ›ojÔ¨qæ™g^qÅãÆ³å:o¼ñFÍýõ×·nÝÚ<Ó§O¯W¯^É’%/»ì²þýûÛrVvÁãøÞ×1"(x¦Nzíµ×–*Uª|ùòjebccMùСCkÖ¬Y¢D‰jÕªÙ–%>>^mÜ’%Kìâ•*U1b„.V¬Xß¾}5jT¶lÙN:9•«¥SótÞyçÝwß}¦ÌÊÊêÑ£‡Z:•×®][²kCÜño¼QµjÕ_ýuþüùúšl𤤤¨üÕW_]·n¾&}ø-[¶4‹,_¾\_ò#**jÑ¢E/¼ð‚)_¼xqÑ¢EõÅ­_¿¾K—.Å‹‰‰1“êÖ­{Ï=÷¬]»vÔ¨QJ2ùämTíÎðáÃ5 òÉ“'«‘êÝ»· ¿üòK 9Ò9à¹ð çÍ›§hÑšg̘¡’6mÚ¨åZµjU¯^½ôî4[ÇŽ•:“&MÚ¼y³Þ¦oìØ±f *×Iº]9ÜìA¬W10hÐ 3úõ×_ÛàÑ—U«V-Í`&Í™3G߯mÖ¬™RÄ”»)7nlG¯¾úêwÞyÇ ’VkCèÙgŸµÁóÄO¸;L:ɹf  <î¼ñ9{"%xtƪÆ%::ÚS~ë­·>ùä“vTaP§Nç‚çƒ>°“6l¨ÆÎŽÉÉÉ¥K—ž>}º-éܹó]wÝe†›7oÞ³gO; nö Þ±c‡¾õuÌè²eËlð¨¯S$ÈÎ;5IôñÇÿo].ú®ß|óM;Ú¢E‹‡~X:Õ8묳l¹Îlð¨ŸêÙÄå—_nç`OpÒ—„O¤Î…›6mª$P[Ó¿ÓBIÅŠuîlg5jTÉ’%5óqƒgüøñvR¹rå `GåË—{Ú,QGÇ3‚ÙƒX_S×·°zõê"®àÉ®ó‘]ðèüàŸÿü§µÁc.¯Ùò~ýú¹ƒ§{÷îv€‚ƒÇ õ¯v‚KÂ$R‚ÇX´h‘º×]w]Ù²e.\è‚端¾²3Øà9xð »É“ *¸ƒgêÔ©v’ÖkÖ¬óÏ?ßܲž2eŠZ–>}ú¨ÅQ×Ç>\ Mš4iÚ´izzzbbb‹-Ô–e<Ó¦MS+¦–.*@k3têÔ©téÒýúõ[¿~ýÊ•+Õ+R«gÑ©tïÞ½íàæ>ˆÍ‡î¹çÖ®]û£>²Áã§~衇Î>ûì2eÊ(9ÜÏ:ÛÇ©+UªdÉ <ÁX½zõ%JÔªUËv¤D_âM‘£¥”@žÇ©ÿú׿šçï¸ãŽ3fØI@afSÇ!x²£ÖJgÇj†-ÕªUÓ ¯} Êý8µBÂ.Û¸qc57šªjÏ=wðÈĉëׯ¯•kþûï¿ß^úâ‹/Ôbª\Úí·ß®Ñ”óT["í àáN'òêl¤ H;ˆ¸¹S‡{<8MDÚA À N'òê,Áƒ\‹´ƒ€2uœÈ«³r-Òb9‹´:Kðàd¼ àðVàüFð|Eð|Eð|Eð|Eð|Eð|EðàdxŸÖÁ¼8¿<ȵ<Žä Òê,Áƒ\‹´ƒ@Î"­Î<ȵH;ˆä,Òê,Áƒ\‹´ƒ@ÎBÖÙöƒf·$LäZðA¼ÿþ{ï½·téÒEŠ™9s¦gj¾{òÉ'Ÿ}öYwÉÔ©SÏ:ë,w‰ŸRRRôA-X°À;!7X$Àý{¬n­[·¾û¥(”‚ë¬2Ƽr( ‚¹|ôÑGµk׎ÏÈÈðLÍwÁÁ³zõêüãî?¥§§k6nÜè{ƒÎ.xƌӳgOo) ¥à:ë›4~¦ŽQÁÓ¤I“7ß|Ó[ŠÈ|¿ð -Z´ðFŽàà9mä<€\g ›7~¦ŽCðà$¸âfÍš™ >–½Ô¶hÑ¢ œuÖYUªTéÒ¥KVV–]Jå;v|ã7Î=÷Ü2eʼÿþûÊϯÄKóæÍßzë- ôêÕëšk®)]ºôyç÷Ì3ÏÄÅÅÙy¦NZ¬X±_ýµnݺgžyfÕªU·oß®òü±F%K–|ì±Çyä%‡»DßÑ\ ¯I_å˜1cÔ6ÌNUðhªZÀ½{÷nÛ¶MßÚ_|ñ—¿üŵ‚#”"ZVJ¦qãÆmذaéÒ¥7ÜpƒRÁΣe‹-zóÍ7+çtÌL›6mÏž=;wîÔaÓ¶mÛuëÖµoß^ÉtÜ{<&x|ðÁ„„í’šæšIjîšaìØ±gŸ}vpCLïW²uëV凒ïÎ;ïtO ¾Çc‚çž{îQÚíÞ½[á×­[73I»qÑEMš4iÓ¦Mú””¾îT–þ«;Áà±a ~ÕóÏ?¯*×ádÊU˜]Cï¦àQ¬šáU«Vi î´È.x~ùå3Ú·o_»•Ê•+÷ÝwvÎ[o½µ{÷îv4·Á£/Å&ŠÎêTG4 xVé“7å©©©ê;.\¸Ð.ˆ‚.¸Î:Üã1r¾ÔÖ¦M›fÍš9SiÕŠ‘#GšrÕ"51&xtJ¨Úí^Pt ¬–Îs'-ø žN:Õ©SÇŽ4H}P;ª¯ãwÞ±£NàS›¨ÆnÈ!:{˜0a‚²A߬™:sæÌ›nºI'¦C¬ˆ² šàQ_Ç–8_›¿ë®»ìè}œÀcÞm)¢7þÇ’(à‚ëlpÒ—„ODú.—_~¹ª½© ×]w ×®]«aeŒíþûï7Á£sÛ¦M›–.]ZM†êØÎ;í<ÈCÁqpðtìØ±nݺv48xÔµ£F£Fô­=ñÄ:tP»ßµk×G}Tå:W}øá‡æÖÎøñã‹+f—2÷x쨡¦Y‡“ußã1² {Ìhzè! (?N.xLgBÔ{+rbÁc:èNà•;xrè|ä6xT¡ì¨‚GoÇ >a÷M8œf‚ë¬ê_í—„IäÏСCÏ?ÿü3f¨ÞjTÍ9ƒ6 DÈà1-ZÔ¹sg¥”9ƒ¶åÈ+Áqpð¨Ùõ\j«W¯ž2xÚ·oÿÌ3ϨeÔ±§ïúÁìÝ»·Ê'Mš¤¦ß6‹J ãO=®¼òJ;úç?ÿù¤ƒÇs©MGZv ½›‚Çvé~ýõW­aóæÍvjvÁ£wjFõ/¹ä3\©R¥O?ýÔÎé¡~É\à- 8ñàQ5×Ö/^üǬ8]˜gv‚ëlþŠ àQgåµ×^³£ªáî¶LSMðäp©ÍC­›y& y+ø žÄÄÄŠ+º.P§ÇN ¢rnöìÙÊûù|ñÅú(† ²qãF}:9ÓÙ˜]0&&FÎèÑ£µçª³¶ÜÉMðˆ>öZµjécÑ)Ý”)STÝÌ  4û¤hpÍ_<ÿ÷ÿ§nÊ–-[öîÝ«ÐIëe—]¶oß>'p)@acï¨QÐù ê§jy¸Àüc@µêë¨oß¾}Ö¬Yê0™ÆnÏž=7ÝtÓœ9sþØNAðA<2þü믿^_œÎÙ;tè™™i'… ž¸¸¸3Î8C-¬è²hÁÔÔT3Iߣšû‹.ºHߣ&7xdâĉ5jÔ¸ð yäõ‰mðhÓEŽõñÇ;9³n¸Aû£ã³]»vj My<;v¬]»¶–jܸ±½†¦0ðlÝdƒ ž~ýúU®\Y=EÏîÇ©ûöí[³fÍ%Jèí<þøãžyªðPPiqsÁÀ¤š‡ ¹‚'!!A§}ÚºòXÛÒ°{P¹ÿ}BpÍ_<±±±·Ür‹ù³+Ú®/«F]|ñÅ=öX›6mlð¨Óó÷¿ÿ]õSÑ¢†Àv•Z÷ÝwŸš9ÕöjÕªÙ;ÂSmy+Òb?)N<ÏF‡¤àQOË[š=<ñññÞ ÀIñü«¸H«³<'GçÑ:±5çÀ‘v‡ÛäÉ“ùå—ƒ*þô§?}óÍ7Þ9‚<ÈGîÔáOžYµj•º/êǬ[·N«º>ö)Xø Òâp6lXÕªUÕ®^½z÷îÝÝ× ³Cð ¿§Žyu¶@ÏŠ+êÔ©SºtéòåË7jÔhùòåÞ9N‘v0B¦Žyu¶@òW¤Äriu–àÁÉx@Áá­ÀùàøŠàøŠàøŠàøŠàøŠàøŠàøŠàøŠàøŠàøŠàø*"‚§k×®5kÖ¬ @iܸ±ù}ñ”™™¹ÿþ½ˆxúšNäç?NZD©D5zã7¼õ9{jÎ’““Óñô5éËò~y'"‚ÇÄÞR‘-·ùX§ÒÞ‘J_–÷ûË;€“DðœÆ‘ˆà9<"Ás+tÁóý÷ß¿{¬ž={ºf­]»vk×®õ–æžÝzëÖ­?þøã)S¦dddxg ¿ßÿ]ûœœìp<ݺuÓ‚7n´%³fÍúôÓO]³yƒà9ù<[·nUШÍÊÊŠˆàéÓ§Ïv—={ö¸fíä‚Ç„­›¶Þ·oßÝ»wïܹsáÂ…mÛ¶ýé§Ÿ<ó/•·´þS í³Þ‚¾KSBð LžÓ˜Á£ˆ9xð`ÏÀ]Óÿ £|þüùƒîСƒº#+W®4åæ4ßèÒ¥‹)ÔΫýU+¬©“&M²­dÞ¼y_~ùeûöí§OŸn -ÏÖõö?úè#'Ð|÷ë×oöìÙ~ø¡:C*ÑG6|øpí‰2oذaqqqf3çÌ™3µ ¦~óÍ7‰‰‰f’>ß¹sçvïÞ]{Õ£GÅ‹ÝÎ1{5aÂûvä_ÿú—æìܹ³;ðFŒñí·ßÚQKovüøñZ¿ýpÜÁ£4:t¨V¥­h'7lØ`Ô,Y²DSµì'Ÿ|²iÓ¦øøx}Ôzw½zõRÚ9•Êz¿ZC§Nô 8pÀNB¡BðœÆ|õxÔŠj[™™™‘Zr5àé‘<îó}3fŒ™¤£ü—_~±sªscÏë=Á£®ƒ_;ªówÈ›¦S+Q[l'yØàÑg±eËÔ÷ÝwN ùÖ9¾>#3ÛÆµcö»Qn+–ÌhNíŒ45ÜfN-«r÷¦\f̘¡.…öìUð¥6}ꎘá_ýU)²¹7Á£tìØ±£fsr¼ÔÖ¿3ØíViësæÌ1£ šŒWONK™rQ?R¨<³%(<"*xTet’§Ó)ï—“ÕЯ¾þúë‰'ª.xç³ÿüç?9¿©0 wðèü[gí&x”8<ž{<î³rí®³gÏžóæÍ3ÞàQÿà˜ì 0M§V’ÃÝ {¦Fi@m½¹P¦æ[Ý&;›ŽÓ²Ô¸ëøpsºŸ†PÚ)“¢¢¢Ô1òîлïª_bfóìUpð¨Dó(á4¬NÆÔ©Sí$7<PB«k¢üsVøÃ?¨gcÞLš4ÉLR‰vÒ ëÐ$›‘ZJ£Ú «ú¹vÿÔû4s¢P‰¨àÑqþÍ7ߘ ëvÔÉOLLŒê‘Z¡iÓ¦©‹Ÿ––æžA“Ü£yHkÖ¶žp ž.µé±£jßÿýï›aOð¨wbÏå=<+ñ0¨›²gÏžô£ýçè;šsð¸{ê—˜6Ýd‰ÖüÇ2.ž½ '7 %±&íÛ·Ï=ɲÁ£¾ˆ†§OŸîÞŸQ£Fé]ìØ±Ã¼5õ üñG3ɽÚçw]Æ™à1·y† 6|øpSŽB.r‚'!!aÈ!j¯”=+W®´åêúëÜôÛo¿ÕA»téRwðèDjìØ±:žÇ¿dÉ’‚gÆ fX ¥º>j+U2räÈ Œ3F‹k’굪’NËT®µÙ4Ò jˆ~úé'ð©-U%²kÖÚÆgYµj•)ÔÑ&–/_®™r*× ÚÉ‘z;ªÑzGv%jôTîÉÂ<îàÑ—«SŸ•«‚<;v´·@dÀ€ƒ ²£nÇ ž[÷¹Ôf[Ï¥6 ë4“6oÞüîÑKmmÛ¶5á̳WÊ-•””äšåHÚ}òÉ':Ðîr7<¢š¦<Öü6xÔÁZ´h‘Ö·Ü¥K—ÜŽûN:©˜I(Ì"'xV¬X¡t11£¶Þ–/\¸P£æoÄýòË/jLð¨zªAWD©Õ3w1<šsîܹڊZy•(ÔÑ7óhm >^­JD¹s`©µ5“rOj^Õ’ÚÇ©up¨ß£e;tè XÊ®‰÷8ñà1S+cB>Nmîÿ«Ñ×Qk§v½E”ÂCýavO‚÷J'h]»v}7ð8µ-Ô1§¾]ÿ¦Õš2eŠ*OnƒGÔÏÓ×n˜¯•î9ìNc€Â OÁåwðø© @a@ð ~ãûà ‚§!xœžÄŸà‰‹‹KJJJMM%x„ÁS€<N溊·…CäÑ×d->ÉÌÌTs¶O§æ÷šÃÄϾ}ûSRRxœFÀWÀW&x¶lÙ¢àIHHHNN.²{÷î;wþöÛo111ÑÑÑ …‡‡ acƒgï޽ʚ¤¤$‚FÀW6xöìÙsðàÁÄÄD‚F&x¶nÝŸššš‘‘q$xøëÔ€0 <>~éÒ¥&x¢££ @ óÎq‚‡ßã[ê"x[î‚OoÊû>R!¸í.è/½)ïûÌ;€óÌ3ëׯo·â žY³fÕ®][›ÓžüðÃîà™|¸b£iÓ¦/½ô’âÊLÒ§1bÄEïÍ7߬s‹ï¿ÿÞ”ëã}óÍ7ï¸ã…œ¾ñ¸¸8Sž§Á“|¯÷H=œétú!U+yåë[>aYÆbÿ{Ýáu;2c÷fõŸ™nÊퟬ9‡þ’® Ú´;kñæÌ§¿üßRGƒ'ùó™é›÷dÙU=?8%3Ëùû ?V~‚/‚…Kv¡â–Ý<6xt ÿç?ÿQ¥E‹NŽ—Úþú׿šÆúçŸV»¯@òÌÐ¥K—n¸Áަ¦¦*E”^N Ô,ÚI>ø NÞÀÍ3xð`S®H»úê«Õö9ÇOÇŽ«W¯ž™™ifSÇÅO£FÔ2å2wî\u}Ìœ·ØIC‡UbøãÁÁcRÇ}_Ç·àÑQ¸zK”ÓÓ¦MÛ·oß  Ì0a‚GaoâJÑÕ®];³È°aÃî½÷ÞÅ‹+ô1.[¶,)ðgÖBýúõÓâÊfu‚?úè#3^Oä“x-ØpxáÆÃØ´'ëÇe¶|ÂÒ ¥Å[ÿJÕðÓSö'9íÇ~´ß‘à™søþžGfµ ãHW)°È‘à‰:²ªf}“SÒ7G™_¯Ñ 3–nùß<¹z<(\² ·ìæ1+V¬hÑ¢hҤɞ={œcƒ'>>^ñpñÅk¶ÀƒEÔ;qíþ\à^›¡81³¹™ç¹Õnš{H†ú.:×€:FšÇÝT©½»óÎ;cƒG'û&E‹9muÆ”•б¤û{&íKÈê6áÈ&rû"xP¸d*nÙÍ£à©_¿¾z-¦í³åîàQsÓ AƒU«V™7nlÚñž={† 5gÙÝ8ñ<\ЪU«‡zÈ9<ëׯ·“<:gw‚‚Giaç1“Lº”-[6»‹fÁO4¤¥¥Mž<ùŸÿü祗^ªRÁ=ÕÃýp-qÿÓQ?.ȡǣ3†?üPA~Ï=÷¨ËrÝu×Í™3'éhðlÙ²Å̦~êÝw߸@§yÔu¯DÔ[ºé¦›š¥/H߸>ÿ¤< ž{{$æö5ü×´ø¤¬&= ?Ú?1ý°ÓkJª™4~iúì¨ ;çà9ik~ÏÔ@ó~‰ÚÜóƒ’ì¤ät§Íè ‚ç‹¼1"9)M1–Øy\Š6q/ï¦OäEð p9‘£“Ý<ž{<–;xjÔ¨a/‚¥§§«¯`‚'»Km;v¬P¡ÂÁƒ=åNPØà1—Ú†jÊÍ¥6ƒt©Mm¨]üÛo¿µÁ£|ÓC <–ªmñâÅüñGï„c?¾{÷îöêÜ×fX…žËn'áă§}ûö>ú¨vÛ]hîñ|üñÇê˜nß¾ÝêkÕ””}ð$zkÖ,uSöïßïe€ 'Ð'S¤ýôÓOöᵕαÁ£VµT©RÆ Ó°òæÊ+¯´Á£­-ZT+\¹r¥zNª†Z‰Y³g£j:¿üò˵k×nÛ¶MÅŠs÷fBRº 8Pã™S£*Ô¤¿cÒ‰>Ou_}õÕà§ÚÚµk×¹sg3ÛÈ‘#6Ç %½úFZ•¢KŸÆòåËU¨ÕªPÝGu¡Tn¾Y3žOB®^ïÿ¿äÌ,çõo“Z|‘h^íǹFúÊ0¥H‚‚G9ÔsrÊ}Ÿ&¼ý]²º5šªòæ}4OÔ¶Ãû<ñáÞ ?GgòéÈ Ç,L ÏÿÖßzê–=™™Î ƒƒ·~"/¿ƒ‡@Š|wÒ«íD‚GMOãÆ• ÕªUkÛ¶­Z%{ËäÀ/½ôRÅŠ•W\qŨQ£LùÆuÖ|î¹ç–,Y²V­ZÊÓ4çÓR¶íÏÔ¤%›?= ÁL Ï‘eÍë‘Ï)®Vývس‰<Â">>~Á‚ã4p*÷uÜr<EÎÁsÏ'‡òð5~IÚ´UéÁåÍú ž§$O ~í:Õý§äàò|< ’B<óðu4x¼åÍú¹ÑøÔ€CÁ“<¯O'&ïKȺ¿‡·üÄ_~Ã=§€à9Å×)Ïä#O+¼?6)xÒ‰¿Ia žîN³Á  )”Áš½I! ž»»ÇŸf/‚@ARƒçãý§Ù‹àPÊà9Ý^€‚dÓ¦Mûöíó¶Ü™ÞÎÆ½ïó¨»>Ž¿µ«·á.Ð/½;?>ò·9„àÇÒÒÒÔL¯;(Jsø±×Ø=‡ïøèȵ©ÓæuçGñ[öɃ0!x¾"x¾ <üÉ@ø„‡ l€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯€¯B?ŸÁãÐã„ ÁðUˆàIMMMJNŽ‹‹‹%xyË"FA£¸QèÉÈÈHMM‹?°uëV‚·Lð(b4Š…N‘ÌÌÌôôôƒ<€N… •y)ŠVÜ2Ð ÿꀲŒÜÍUAuõUòÓ=öœ—Q÷*Tæ±(r©ö©«H»J­«WeWQTEÑ‘Q7”g#£Jq=¡B…ʵSÜ2E`®.÷–Ç[ÉX!´‚ÜÜU.ªâç°ë–a/OŸS¡Bå ‹"÷KqXQ—yËî„õ%Ã’®Rh…Ú>Qe?‡ž>u ñ2ètR¡Bå ‹"ÈåsXVW%-FÚUŠ®<†wï± àÞ*Á–K‹ÆJÛW9†ª?¨¨««S¿TPÞ*¬ðͨ‘@P#Zþ„€†N ºÃ.liecñ9²” CÕß ‚XR@Ã'ƒ˜3£µ¨-J z®RØ ¾w…ª#A,) ¡càñã'ƒ\ZKAO4w°,ÀòGMPu ˆ%4ìï4 KË-JËbì„v°`!ìBð…ª ‚XR@C{_H ‘ö ÆÙ!ž¯Rƒ±`0x¬ÏØþº/Î|Ó)~òøÇ IðÉ?J,âßœ¿¨ë?!ˆâ?æ€ÞšÐð·Þ^ö‘â,>†zÆŒU¥Äà±ÆØ]úK8WL’4é«ñÕO%g22Î|u÷¡úÆ‚Û÷ípÏ þß7ÙÌ©Ì/.––å_ÈN?‘ŽGô4¥aS_àIz:¿eßãð³hù¹Œ[Ú¬tèDvé·ßUH8‘ÿÔúõ»/ø«ôìóF)Ÿ¸ðžfüâÂÅ"耯õØØ5‚˜   ÿ(`MÁ^uM7¶³·²üá\¼Jù2Vm,î)}Ôç%ãâ>{³¿n¿ýó2·Ú÷"ãúö™åvAFJbBâ±”³gÑŠ´Ë÷ÙA÷¯–v >IÎøâò(câg·Yƒí÷ÍyÆ´dlûĘ{½¦Þþé27OÒÝ~ó3ì‚|‘×3ðãOJ~ÂW?ÝÌý›;–bÌ»üÞ)’ójX½Öš’³¨ê±´³—K¾P>i­.0~’rŒßG’á³j‹_óÁCþ‘¶&×U-­º&ýõWþðIy\ÔØÎJÛÿµÉ?þ\~†Ýi®5«+„.ý´@½59úŒíX™´~{.95+ç«K—¾ÌJeiBVÅ¿ÄJ1wx„œ½59jcñ ž¾þ™Œm[¡Ü->šÌ²ßÄäÔO/”ÿ`kÄò€Ë¿à™ÝØ_‚XRôk‘iy¨-ÔˆjD ®Ïر¤è3¶™ ˆ%EŸ±ÃA,)d,A„úŒ%bI!c "”Ðg¬¡ ‚X\ÈX‚%ô+Fh‚ 2– B }ÆŠš ˆÅ…Œ%ˆPBŸ±b„&bq!c "”Ðg¬¡Uô÷÷×ÔÔd¡¤5@Ñ™×b~Œ…Þ\¹råþýûð³økjâÏ Hj€ ó"­>cÅ-S[[ }{J„ šˆæèg~Œ…¸?LÑ• ‚‚€&¢9úÑg¬¡e Y;H„? ‰hŽ~ÈX‚X$–ÀX1BË,²±žùÉù<âÛsÀY•m(µŠï†$Þ¶âS½K|›˜+öòŒ ³]|×ó wÖµõº«4ÍÑÏ‚›4ù¯ºÎ›àu¶5t9Åwƒ ;»F^د;ÖÓΚì”â.ñÝ¥dék0ùO±oœX¹²ã¸Cõ¯ûº«h Œ#´Œc½œ®R ³ô¯ÂâAÆ.`lrvSšßÙ¦8° seÆ?p‡ØXÑý,Œ±ÖRƒ¡†ÙÛUl0V Èo5ä¦ä6Œáÿ'ç–×›LÙÆ c®¹kLªàuZÊs3R’““ ÙÅ š•àËŠqì «ª ±CF~]ê±…†ä£GS @Fi—ë××g’“SÔõ½ Å&Z6•×—ËKÌe)e-Ãáù šÔÀÉNÌÎì»Ø`×å±VåC[)pÚúªüÆâùfs>Så@6Ôæúb|7†ÞÕeÎ7²>A+¯ƒC•Í[p2<Ö©t®¼K\0VÛo[arvyMinv¶Ñ‘]jÁ xóN–G°ðÔv!ŒV®¹·b-Ï0W•çcßËUJˆãçîªR. JY8>¼öúÂl>ê0¬ìíúB< ª)V,k+7pX³KëÍc5¶Šf[·K`¬¡ef1vÚ ?)÷(W½)%' –ÑÑ£F³¯Ìk7ÃRcSé…y3ä²a 32J­Âµ«5M9Ä cò!šŠFˆ1Ö˜œœ ÷/L^I®ï±â\8¡I½>W}{‘ô»Ç»º,]NœÔ3PŸ›’QÎ;8P•bªbýÆ·²ØùÙ›PÛ9€§ðÇÙöÀêÂwǬæl¹C¯ËÓVh0>pAç]m¥Gj}Á“M5ì@OWiŒ?k†:Ùh–ÜÄŽf›­8ÐŽÑPhñH÷Q~FïtÔË.šŸß`?¨nìQ¸;⩼¨Zq;Î?L¹àlÆÒ6l¯ÛËÚ±–ŽÂÚO4­8:£ØÂÂRœ÷M/Ú,v¸@~…,@ð•׈*áI¡›¬C¬µÒ¶1\o …ØÀÍc­¢Ù×ídÅâÑ2³Ë/™/l{¶DØß7ãcõ&¦!.ñ ³bL  ÄÏØ”B¾"X ¾2cáäR¼u°ú˜ ©–Þé«óƒfe˜?ðóë Þ£¸±]p9… v&å,àuå¿.p!Åw/ÞðS>]dš)FeùPK¡æBAS±u898dÀe.d2·©ßRÃö±~e2XXd1V¹qÂ0dó±ô[ô8œ¾nâ…1§ÀXÍdsüÆ_»pLÌÈ àe°Ûo^º%?™uˆµ¦?`Îcìtcµ«hëv Œ#´ÌìÆââa£…W+Ýuq¨|Ï£¼œi) †ƒT_Á?+VÆÅ¿= ÑØ@õY`2¨Oi78þÆBFWl2bªm€d òœ(u¡>`ÌZ_œ ©¤gÅõbÚŽñº ò7¥-¾öcÁeÈØleÈ™S| ° y¡R˜¡+Wk’ì æï¦–?àÁÖi1çcr Y¤œ¹ú`ûØ*»kL³Ö¼rsàw?¶Œý=ŒÕQU &”ÜW[ÄoüñFä»5ã kŽÂ5ß7¬lüø½D¹ ¹CÊmáÁÁžÕØ€³3ëº]‚¬Xë†0{ðž´A™æÙ›gˆ±¾.àh*1Öw#tJËП9;‡u»ÆŠZf.ƲôÁh4øÒ{¼+UoGä},l¿òëÙ.÷O]]â^±¸ |§ RŒïcØDy\ö6«¸Õ‹D}SwÁ‘RŒe7kÍ>Ö3Ð&¥•^WäBº yдܼNVÞ÷Ã^TÈjXº€·l¯!ß ÝýŒ•6Ü]ÒÕiíÂ>ÙÛøÞÛ6±,ÕeµXùÆÛc-W‡5NàgÅÁŒõí†iË#¹Çem³ãÁõ—”ïcq ÛÔ@ûXÕɼv)>~¸Ó„ÃØÛØ„o‹!»‚×hëßùÀ³3ûº]‚¬XólÄsùãÜàÆú?{9ó³b¨Œ #ÖR)ƲÑ.4²·óËÍ…JÜtµ•›ä9ÀÊcý;lvf[·K`¬¡e‚+À¾äñíÍ5Ëh%ß[| ‰ßb"–K‹GËÌÉXL Mê³âŒõ tñœÈc¯1ñMÒbCÆ.c–ÀX1BËÌj¬ÝlLN6À&OíçŠ3vÌR Ùh û*>Ð7è‹»ŒY‚¬Xþ6«{í°R×w *yñ1¼[÷gÕb/lÐãÈ=y¬aÇíÃQ<}ôew¶Û騿jƒ­ñÅ]‹‹\§ˆŒŒ\Çù²b¼œý)‡cqta`LÒUâYã¶â ®‰ÏЇÚf¹? H#ÃVA—°Å¸kЋô=[qHà€íñEJ2«ŒùVÕ˜kº§ÂV´}´ ]]“ÕÈú“‰ƒ'÷n†%¡ ïÉ56 6ì]$Žñú˜Ãפú²b\‡[•ÍN?v3j‘tԉܚÒÈ~¶Ý6Î2˜³åË<{;>R³ÛÄ÷ö€68=aa°µ00-æ,L1-ÿ¹1%*lõötiYàëù¶Õ¦ÇÀ4ÕòÚ‘a±éµ6Ün퉄e±ev4¦o—f;ÆÃ™-¸þø§>—oJpˆä½…›DÄöÃ(µ£åZ\T¤JjŽÃ¿>2†Öâžõëù6 îhQ‘±¦›ôÿXUYyé[ŸÛkkñ’Ù-â0»DmldœUº«@M¬¬_ìä¨ÍŠ8j‹Šn·;ð„pÒ%ó!ÜÏÇüZ|”4溧Æ×û7n©¶Û)Ûqбvð%w߸ubëÐøml¼…-œ¸•Þ)íŽ W½zÏ5©?68 îì•­Ñ×M;¾0¡¹¬ía[Ó¹½!‚>cÅ­P¶7<âàMÿ÷šS·…±EwÎÎðèìà[ ‰›ÖnÃ$Ç¿ú½„Ma,+¼º7bSj³ôvwvt˜œÒÝKÝ´§ W¶³}¬%냬’ׂMÖZ¹¯ƒO)B›á{ËÄà»|cÔšÁ“/Ø,­å)*´ ÉI;!l§!aP%aÐõ‡øÉ«6ElØ´víÞé\Jvך-ï0ü³âÖÌmÊøûk7ª–ÞnNÝÄ_ÀyT=îF¦g†¬/”5Žc. í( v@ î©ÁQ•²b>ت~ð¡º$„ábÀµ*ÛTÞ'>²âꜩ&¼±éàÕ{ÝB7ñä‹´/ód,LŒf·‰ï±Eƒ#ä±P_uæhX´HDx›+XuÒbd5r¤},¶¢Ú«–í•—¬yŽÑe °ðµÖÂRÀÅ KßgþÕ½¾•#÷dæJàâõQH\,¸mæ§„åá; \†°Ÿ†cðIœªk•‹ƒ¥¶Ê§›jåáS¼½Û6„‡GlÚ•ÀF7Vu9ÊÜÙÕò·±öÌÆÂíÚ†€S¶Kž¹@c {j|ÆÂø„oË”{ÇÜ›yI² ’ÿD®fM0–ݲ˔v[ËR÷FoˆذóPA³ü¶Ò‹DŸ±b„V˜u+e!˜[²ìSz…iV÷5Ï·E{T[ÈxVó”¨=+f}¼”ñá>6NÎþ°Š”›ù?i3<\´gõö,iƒ#÷ÿ_y§ÕÛ¥­¦Ë1¦F¸X¹ßv6ŽkÐmåtjZ`µg$¯rZ¦ývòèýëùàÏŠU—£ &ž1‡¡%+†Q„äSwöbûêX<˜¹Ò8 ¿oÔTÝS£ÊŠ!g÷Íöƒ¿ º$p!±U ¢‘=AÐVûïce-æø(eJfß>6™'cùúƒ Ý5Ü•:ZngíY¿ZþVlÆé‘ÇŽ= ásõ#¥Í(îòÔûØ(Þ¤£6e«´§²™b#÷Ë;?cå},_†°'ºffS9«±|ËöM°Åm•òlα5÷»rµl¿hÆà°ÃÖh¾&­zܘEÆf±ï»²Æ,h%¥ÖáûAµòZÌEæÖŽ Ö_®ÜA¹ñÙŒUïcƒìcñ 7©z®Æ—‹C(íèÕûØ@ÝS#îcù.Ÿ%¨ö±—„´M÷ßÇâ½-^º³ÛZn_ãƒÀXøqO¤|Ók¿]dn´Iëe»>`ÆG)÷„ÿäIŒÐ~ 6R¾V}4‚,&çÀ¶ ¶EGïÜ›°WJ5ሲCÑ›ØÛRE+ùvßÍÔ]›6lŠŽŽÞ›zh'K‰ íR}ë—ƒ÷rbVéÛÚM;ä°ôlÖ¬Ä3AšŽi_ªú{OLÀV…±ý¶L7¤^ÛÖ†ãI6lƒÚš Ò`ëÕC;7a/ ·‹Þ›] ‰7îål¿ƒ+ôewÍ9s²0Ÿ»ÊOÖZp€&b$æ³eÅ89¬>¶yÈ\$š³wñÁ9P6c»sÆM8æS˜KƒÊÞÇžoÛ›º+‚ VÀî©PícY?F³áY 3À[aIà:’'mì–Y3l÷´VžH锲âQõ÷±ÝW¥v°¡ƒRVìÿ},>Qeí¡À<»ü¾ˆn\»)õg=™ ¢Ù2¢5{ç6¼ÿ¤¯`旅ü.¢è3VŒÐKN»Ùd ðI¨™}[#e£‡gÚlÏ@‹™mt¤ýA,ÿN‡X:BÜX"(íEqQÒ¿غßÄöɯèÎþ5Ãêˆ(ß¿] –}ÆŠš ˆÅ…Œ%ˆPBŸ±b„&bq!c "”Ðg¬¡ ‚X\ÈX‚%ô+Fh‚ 2– B }ÆŠZÃO?ý”óåÅONI[‰Àuåä]ljj/[ŒÀ¥K—ŒF£xðŠ® ®nÖ•50— ]ņ±WÊþ–^òoǶüw×[‰}+¯ÀuÁÕý=ýë‚ââÅ3***Ìf³Õj}þü¹øwWp]===ü2Å‹g„ÖàzøTÐ ]†è3VŒÐ*ò._ÿÏãÚAY‘å/É7òŠÊ„(//¿{÷®¸ÆW(wîÜo…À5’k€Mh¹p9Ë“ù1¶îÞý¿¦•hb—ø´«÷îûþ³è†††o¾ùF\×+šÊÊJH€WÌ&tÙ¢ÏX1BË|žSÙ…vVpù÷c÷M¹—”€Ý$Ãâ¢^Ñ<|ø°°°pŬaB—-ócì?N ‰}Ë<–ÿ÷ßpÕÊÆ•ºw \ï§Ÿ~ºbÖ€0¡Ë}ÆŠZ&--M;+¾ÀU«G@\Ñ„ÐQhõå,[ÈØ×/d,»øè3VŒÐ23ÏÖæ³®jç«)ï+ËÍí§ ^Òž5y'S?î{+ið†ëEIަÂë¸jõˆËYÅ“Kï†ï«˜ß^8zϽ³&®V|wVFJv‡ï.ߊ0Ú!š¥¼îŒD_Ÿœ²º¢áç³£ž‰#Ib…×+êËY¶,†±4¿t4;7kÞ_¤¢›èøàºëƒtM…×-+ÏØéÎ[—nõ²Ÿ?Ú¸1Éâÿ©†75öugÄgìǃÇ+‡b5^¯¬@cÅ-3ãlõ§Zÿ°T>Ò¼¿`E¸ãúŒç"ä„ârV2Æú˜«±s[ó\|ÆÎkQ_βe¡}t¼í¥Û;=åy9äžÊ; þ fuz‡¼Ly^Xš‡c™]1•SSö±¼¶)›ëeÓ·O•L 'fúEáy©Ž›MRlÉs‹ Ú„¼õwÒ´wÛÜž’:O‡óÅPÛðÛIGš§à,n÷ïU7Ç,š¬øxçÍ£UößáŒCŽñã§¥¿3RïÂÞauçµ½p4 Îè3vwæ¥øëÂÃÂ×íHªå‰çHmæîwÖ­÷ÖlÙTû„WݽnDxت°Ý% údã¹}ïl\¾fãŽ*zy« Õ–¸Ìv¿³eã–jAÓ’øwÖa•w?ÊýH2vÄï^qkßš¹ì4üؤÝ;ààu[ö]êdU”¬øV<ôºµnݺûJؘ»±lŠŸ¶Mu8¼×TÉE¾¯š‘À`Kuúi‰õ›îMuÒtÈŠ“œ7Ü/ªëž7Ááî—¶ÎgûäwtÞh½óå,höÊÀ'tÙ¢ÏX1BËÌ8[êûèlÙ÷qßæô¡Î?luO6³ÙšözKòxþ#m¯:îâŽ÷Ãðü¥å¦CýfìEב³à¨èœQ‹çå0›ÍXõˆËY…ÿ>¶bŸ¤ï¤åRü»•2ÂÃÖ(úÔ~´eÝ»rôÄ\ɯTqMXØnÖf¶™R•ZP0I1¾SÞÇ7Vu,ØÎÕ cç¶Ø[]<z‹ïJàV+«©€3â}5äzáàÅýÊm}ÔXo Û@AÙWçj‚¹û åå´÷¥t¸ –Í+<¯¦{¼¨/gÙ²¸ÆBŒõ¾P†Õ/ƪe{’ª£íéæDÈp¼7&ù&ö­¤¡*÷Ëê’>µ¶¼ d,ÆØ&åY×Y¿s3VŒU€¸œU6Bۺݗ:y´…+LÈ›×mŒ¿å‹ÂOrß]³#ÓÂßx’»#<€±cãnɧ€$c™ƒÒÛøb u*wC˜Ó@1VSÁF|eîÆ¾WçåaYÛ%mYÆŠZfÆÙòÛÇo{5Ôùì=Í>ÖÏXf Ü\qRûÞo~1åe·dø(éiµÇËŸEm>íª÷Œ±}±7§ÜŽQöìáÑÍ/îcµÆ¾õ1ÜjÀX”"¾–½;R¿‘ÇØÉFPoÇ9‹\Á'¿û*˜H“–ÌwÆX¦ÝnþvÀëVIÏŠñNÇ쟄D;vt–Ùòÿv'Í™×éeþ^Zš‡ßcŽiŒåó÷;>[†P|eÂ=íÛ¢¼W9as¿°9¦,c%râêoì[IÇ›§.o‡cªºn¼cn1Ï•3ªzV<{V¬q9«l,˜õÑŽ·ìØñîî2ãxŒ… 檰pžÿâ“Ú8úŒ#´Ì̳Bå½JÃó~Ûºþxæ$ä„ârþ Œ€vˆ”2«³VX„¢¾œe ûú…Œ»±!QV ±b„– õÿšù5 ÿ •øsþípÕ+f ºl™cχøo yòïÇîž{QK—.õôôˆ‹zEóðáC¸ê³„ ]¶è3VŒÐ2?5ýí“þ­\¯QþþIqSS³2MMMâ¢^ÑܸqãÁƒ+f ü=ýjS“ïr–-óc,p±øÆ_’ohbE–}Éå…_W #`6›ïܹ#®ëÊ÷ßÿÍ7ß#ºk à„.Oô+Fhr Ëþëä×]À–@;(+ ÀuÁÕý5µøÂåâÅ3 ÌVVVBº¸R÷´p]puåååp{/žZk`Ö ]†Ì§±ÀݺÆ,S!þ‚Ãk×WWS?Óoµ…ô¸°°pÿ¸:õ¯)ÖBk`.ºÜÐg¬¡ ‚X\ÈX‚%ô+Fh‚ 2– B }ÆŠš ˆÅ…Œ%ˆPBŸ±b„&bq!c "”Ðg¬¡ ‚X\ÈX‚%ô+Fh‚ —y6¶¡¡áŸ þ±œþM)tæŸ_46†Ò¿%ˆ`è3VŒÐþ\)û[zÉ¿kXV¿‹:]ú{ú×Å7ÄD¨1oÆæ•ýçñ ­0˧ü%ùFþ•r±ßRè3VŒÐ2u÷îÿ5-~ÿ@|ÚÕ{÷)=&B˜ù1ö|ÎW!ñ;~BåwùD0ô+Fh™Pù=zü÷剽'ˆÐa~ŒM ßU› ¿“– ‚¡ÏX1BË„–±bï "tXc´Íô‡wçTTMW!c‰FŸ±b„–ÑklìÅgÇÏ÷kß×QÞÀX±÷:,±óPÈXâO‰>cÅ-3£±Ž# SÒŒsý^ÈS²bþw~3øßùuy²Î;Þ¿é±Ae·ZþÓrÇ;ÿèhqWÛïp¾p8ä¿Ø«66éqj3?Å+[ÛÈûìïy+”!Í‚»9ï¹Ã5~„ýQÖ·Oîc?¨öz«® lN|ôAƒwÊý¢©a(&©/æÊ¸Ã3q„¹ÆN»'ޤáÏïÝr;FßCKcû?l~á¶¾>~’Ñùr¨eèmM7”BÆ!>cÅ-3“±9c÷dÞÅÇÑI¾7ýb¬}$F©éõç2i¨Êã-dpŒu4 JYôãázïïy§UÆ&=­ö¨Òãón›{üCÕ¹„BY1Ò,¸±o%>z¿r¼ÉùrÊûÒÖéþPc}çW-[’ó†Û[rƬøæ€Ô˜ìæ¢ÊƦX¦ÿp»_8\¼¼tC@&c‰Š>cÅ-3£±RÙœ6˜e})ëfýÆ5;¥:iÏš„ QWŽÆs)”!Í‚»ùìÓãyoƒ‡IŽãm°ÉD÷ô;í™Ì:ß-|ØìÒîc[^ YG?à[åô'G.>¡},±RÑg¬¡ef26gRb·ä:¬¯›7T9°‘!ÇøqNýŸožTG×ßuÎl¬Ø{‚ÜØ7/`¬EÙǾq!c‰FŸ±b„– -cÅÞDè@ÆD(¡ÏX1BË,¨±ó[(+&Bšù1–þ‹v‚Xô+Fh™ó9ô[cb˜cïßoøð“¯µ†,·ò÷OŠ{O¡ƒ>cÅ­âbñ¿$ßÐJ²|ʾäò¯+Å~DH1oÆ_^.ÿ¯“_Cæ ÛE­0KU 3Ð¥¿¦ç]©{L¡†>cÅ­án]c–©À°œþŠtºTSO¿¦˜X ̳±A,(úŒ#4A‹ K¡„>cÅMÄâBÆD(¡ÏX1B±¸±Jè3VŒÐA,.d,A„úŒ#4A‹Âôô4ÿŒ%ˆåèš&ÿ&}ÆŠš ˆ†ëš&ÿ¶#2– –/‚®Ã²±]]==ÖÙõÕA, Š®ügþ¦ÚØßz{ûû‘±±ôºòFg2v<€±ªpMÄB¡N†ìcÛÛ;;}Æ<~âg쳑Ñáa—shˆŒ%ˆE`]‡ec»ºº­V[¯ÝÎ=ÑØçケ~a› ˆùF› +?ó  a{GGw÷Cnì#LŠUƺǞ“±±8Ì +ÿa”˿ڱÚlö¾> ;¨1ÖõlèéSÊŠ bá– k÷±¾¯vúûÁXöéÓUžçãã`ìȨŒ}ú«ªO@Ä|LÑ€ûXž+ŠŸ ‚ž’±cÏÇÁXþ¸˜²b‚Xr@Cþ¯ %æ›ØA§Ÿð(_Éò­,KKhÈ,þk'y z2cý·²÷‚X€®ê ›XÐsÕ„gR½•…Ę?1†*P±¿ÿG‚î£!±†ÝpGgg{GǯííX‚x˜G hrbø|˜EWP¯_ÚÁ:y€=ÑX11fÏŸ TPI )54ÔÓcåêBãp8/p>*T¨Ì±(âàOà)äÅ@4EWŸ8±,ˆ z² Òʉ1—ÖžæáÒ‚â—ápŸ·6´ËíU œ *s,jw¸M •â*èÒ9d]AFÓô\噜â‰1³êܘK Â2 M€ô >´Øk·CÖy3Q¡BEWQôá6¡¨ýÀ#tÕÁõ ¨'m_Y> b‚ž²±R˜Å¯yÀc.­‹¥Ç@K2x;ðÚRìU œŠ *ºŠÚ n)–Ç ­ >lr=㺂˜ çÿŒ(OçîûIEND®B`‚qtrvsim-0.9.8/docs/developer/coreview-graphics/using-drawio-diagram.md000066400000000000000000000075021467752164200261510ustar00rootroot00000000000000# Using .drawio diagram For easier manipulation the coreview diagrams are created i a diagramming tool [diagrams.net](https://app.diagrams.net), formerly known as __draw.io__. It is fully sufficient to use it in browser, but installable version is available as well. ## Prepare your workspace Before you begin and open the diagram, you have to enable some plugins in menu `Extra`/`Plugins...`. Tou will need `tags`. Choose it and reload the app. You will need to enable the tools `Tabs` and `Hidden Tabs` in the `Extras` menu. I also recommend enabling `Layers` tool in view. ## Export You have to export 3 SVG files. In the `Tags` window, empty the field and click `Hide`. Everything will disappear. Then type `simple` and click show. It will show only components tagged as simple. No hit `File`/`Export as...`/`SVG...`. Uncheck the `include a copy of diagram` option and git export. Save as `simple.svg` to `device` and move it to project directory (`src/gui/core`). Hit hide and repeat for other versions ( currently `simple`,`pipeline` and `forwarding`). ## Editing You can load the diagram from device or from GitHub. Device is preferred as it will not create many useless commits. All shapes I have used are on [my GitHub](https://github.com/jdupak/Diagrams.net-CPU-scheme-kit). You can open it in `File` /`Open library from`. If you need write access just open an issue. The editor itself is quite intuitive, so here are only special functions and highlights: - When using texts, make sure, that formatted text option is disabled. It would use SVG foreign objects, which are not supported in most simple renderers and parsers. The option is cca in the middle of the text tab on the right. - If you need to ensure that some elements are inside others in the resulting SVG, you have to use `Custom element`, otherwise the SVG is flattened. Currently, it is how cache works. In the style tab, you can see inspect it by the ` edit shape` button. Make sure to select the element and not some group. You can create new one in `Arrange`/`Insert`/`Shape...`. The language is similar to SVG but not the same, and it is documented here: [https://www.diagrams.net/doc/faq/shape-complex-create-edit](https://www. diagrams.net/doc/faq/shape-complex-create-edit) with complete language reference here: [https://jgraph.github. io/mxgraph/docs/stencils.xsd](https://jgraph.github.io/mxgraph/docs/stencils.xsd). This is the code of the cache: ```xml ``` - Components with dynamic values are created in `Edit data` in context menu (`CTRL+M`). Example (written here as a json): ```json { "component": "instruction-value", "source": "decode" } ``` Components are handled in `src/gui/coreview/scene.cpp`, defined in `src/gui/coreview/domponents` and data bindings (source attribute) are controlled in `src/gui/coreview/data.h`. ![](./media/data.png). - In context menu - `Edit link...` you can create hyperlinks, what will open some part of gui on doubleclick. The connect to `CoreViewScene` signals using table in `src/gui/coreview/data.h`. - To control in which variant the given element appears, you can use `tags` in `Edit data` of gui tool, which can be displayed in `Extras`/`Hidden tags...` ![](./media/tags.png). qtrvsim-0.9.8/docs/developer/debuging/000077500000000000000000000000001467752164200177545ustar00rootroot00000000000000qtrvsim-0.9.8/docs/developer/debuging/logging.md000066400000000000000000000033431467752164200217270ustar00rootroot00000000000000# Logging The project uses the Qt logging framework. For quick introduction see [this KDAB presentation](https://www.kdab.com/wp-content/uploads/stories/slides/Day2/KaiKoehne_Qt%20Logging%20Framework%2016_9_0.pdf) . To enable logging in a `cpp` file, add the following snippet. ```c++ #include "common/logging.h" LOG_CATEGORY("."); ``` This creates a category object in the scope and enables seamless use of logging macros `DEBUG` `LOG` `WARN` and `INFO`. If you need to use logging in a header file, call the `LOG_CATEGORY` macro only in a local scope to avoid interfering with log categories in source files. Debug logs are intended to provide fine level of information and should be hidden by default and enabled only for currently debugged category. Debug logs are removed from all `release` builds. ## Using the log Qt supports both C++ streams and `printf`-like interface. **In this project, only `printf` style logs should be used.** Logs are considered to be part of the documentation and stream are too hard to read. The only exception is compatibility with used libraries (curretly *svgscene*). To print any Qt type, just wrap it with `qPrintable` macro. **Example:** ``` QT_LOGGING_CONF=/data/Dev/school/QtRvSim/qtlogging.ini; ``` ```cpp DEBUG("Link triggered (href: %s).", qPrintable(getTargetName())); ``` ## Configuring the log To filter shown logs, modify `qtlogging.ini` file in the root of the project. If this config is not found automatically, use `QT_LOGGING_CONF`environment variable. **Example:** ```shell QT_LOGGING_CONF=/data/Dev/school/QtRvSim/qtlogging.ini ``` **Configuration example** (shows debug logs from `instruction.cpp` only): ```ini [Rules] *.debug=false machine.Instruction.debug=true ```qtrvsim-0.9.8/docs/developer/debuging/sanitizers.md000066400000000000000000000014171467752164200224740ustar00rootroot00000000000000# Runtime sanitizers ## Using sanitizers in this project All debug builds are by default built with address and undefined runtime sanitizers. To disable them (which is strongly discouraged) run cmake with options none. ```shell cmake -DSANITIZERS=none ``` To run other selection of sanitiser use, pass colon separated list to the command. ```shell cmake -DSANITIZERS=memory,undefined ``` NOTE: Some sanitizer cannot be used together, like address and memory. ### Sanitizer debug info and Clang If you are using sanitizers with clang and you don't files and line numbers, make sure that `llvm-symbolizer` is installed and if that does not help, add env `ASAN_SYMBOLIZER_PATH=` with path to your symbolizer executable. Most of the time, having it in `PATH` should be enough. qtrvsim-0.9.8/docs/developer/need-to-know.md000066400000000000000000000027271467752164200210310ustar00rootroot00000000000000# Need To Know **Critical information for every developer.** ## Modal Windows, Dialogues, Message Boxes In typical, native, Qt setting, modal windows allocated on stack and block upon opening. To manage the modal window, Qt spins up a second event loop. However, that is not technically possible in Web-Assembly environment. *(This might be solved in new Qt with “asyncify†build flag, but it does not work with currently used Qt 5.15.2)* [Read more](http://qtandeverything.blogspot.com/2019/05/exec-on-qt-webassembly.html) ### Broken API usage ```cpp QMessageBox msg; msg.exec(); ``` ```cpp QMessageBox::critical("Hello"); ``` The `.exec()` method and single line call are typical warning signs. Some parts of code employ special code for Web-Assembly (like HTML file selector) and the native part may use blocking solution. However, in performance non-critical parts (which most dialogs are), unified asynchronous solution is preferred. ### Solution The modal window object has to be allocated dynamically and started using asynchronous method `open`. Answer has to be obtained via `connect` callback. For ease of use, wrapper functions are prepared in `gui/helper/async_modal.h`. Free can be accomplished using special call `msg->setAttribute(Qt::WA_DeleteOnClose)` before opening. This method is automatically employed in `async_modal.h`. Docs: [WA_DeleteOnClose](https://doc.qt.io/qt-5/qt.html#WidgetAttribute-enum) , [QCloseEvent](https://doc.qt.io/qt-5/qcloseevent.html)qtrvsim-0.9.8/docs/user/000077500000000000000000000000001467752164200151615ustar00rootroot00000000000000qtrvsim-0.9.8/docs/user/environment-variable-options.md000066400000000000000000000006731467752164200233310ustar00rootroot00000000000000# Environment Variable Options ## Common ### Logging Logging is mainly intended for development purposes. See developer docs. ## GUI ### Portable application *The simulator GUI stores information about currently opened windows, last selected micro-architecture, etc. To make the simulator fully portable, you have to specify path to a `.ini` file to store this state.* `QTRVSIM_CONFIG_FILE` - path to `.ini` file with current GUI state.qtrvsim-0.9.8/docs/user/exec-formats-and-tools.md000066400000000000000000000241371467752164200220050ustar00rootroot00000000000000QtMips - Supported Executable Formats and Toolchains ==================================================== The simulator accepts ELF statically linked executables compiled for 32-bit big-endian MISP target. Optimal is selection of some basic/initial mips architecture and the use of plain mips-elf GCC toolchain. Then the next simple template can be used to compile assembly source codes. ``` #define zero $0 #define at $1 #define v0 $2 #define v1 $3 #define a0 $4 #define a1 $5 #define a2 $6 #define a3 $7 #define t0 $8 #define t1 $9 #define t2 $10 #define t3 $11 #define t4 $12 #define t5 $13 #define t6 $14 #define t7 $15 #define t8 $24 #define t9 $25 #define k0 $26 #define k1 $27 #define s0 $16 #define s1 $17 #define s2 $18 #define s3 $19 #define s4 $20 #define s5 $21 #define s6 $22 #define s7 $23 #define gp $28 #define sp $29 #define fp $30 #define ra $31 .globl _start .set noat .set noreorder .ent _start _start: // write the code there loop: break beq zero, zero, loop nop .end _start ``` The simulator recognizes 'break' instruction compiled into the program. When 'break' instruction is fetched, exception propagates through the pipeline. The simulator waits till the pipeline is empty and stops the continuous execution. PC is set to the next instruction in the program flow. When a single step or continuous execution is activated again then the program continues after the 'break' instruction. Another option is to set up "hardware" breakpoint for a given instruction address. When the instruction from address marked by breakpoint is fetched then the exception propagates through the pipeline, all externally visible effects of instruction marked by breakpoint are masked out in memory phase, all following instructions in the pipeline are discarded and execution stops. PC is set to the address of instruction causing the exception or to the branch instruction address if the exception occurs in delay slot. When the single step or continuous execution is requested again then the "hardware" breakpoint exception in the fetch stage is masked for the first executed instruction. But then CPU accepts breakpoint exceptions again. This is why it is not a good idea to set up breakpoint to address of an instruction in the delay slot. To compile simple assembly code programs invoke GCC with next options. ``` mips-elf-gcc -ggdb -c program.S -o program.o mips-elf-gcc -ggdb -nostdlib -nodefaultlibs -nostartfiles program.o -o program ``` Compile Executables with 'mips-linux-gnu' Toolchain --------------------------------------------------- The Linux targetting toolchains use a MIPS O32 ABI calling convention which allows building position-independent binaries (PIC, PIE) and overcome missing PC relative support in the basic MIPS instruction set. The ABI uses strictly convention equivalent to calling each function indirectly through 't9' register ('jalr t9'). The known value pointing to a start of called function allows computing Global Offset Table (GOT) and global data pointers values from known offset and 't9' register value. The startup code which conforms these requirements to call 'main()' function looks like this: ``` /* file crt0local.S - replacement of C library complete startup machinery */ .globl main .globl __start .set noat .set noreorder .ent __start .text __start: bal next nop next: .set noreorder .cpload $31 .set reorder addi $a0, $zero, 0 addi $a1, $zero, 0 jal main quit: addi $a0, $zero, 0 addi $v0, $zero, 4001 /* SYS_exit */ syscall loop: break beq $zero, $zero, loop nop .end __start ``` The sequence of relative jump and link to next instruction setups return address register 'ra' to the value of the next instruction after 'bal', and the delay slot. Actual translated code replaces pseudo-instruction '.cpload' by sequence adding offset into global data area from actual instruction address and stores result in the 'gp' ``` 00400500 <__start>: 400500: 04110001 bal 400508 400504: 00000000 nop 00400508 : .cpload $31 400508: 3c1c000a lui gp,0xa 40050c: 279c6238 addiu gp,gp,25144 400510: 039fe021 addu gp,gp,ra 400514: 20040000 addi a0,zero,0 400518: 20050000 addi a1,zero,0 40051c: 8f998018 lw t9,-32744(gp) 400520: 0411ffc6 bal 40043c
400524: 00000000 nop 00400528 : 400528: 20040000 addi a0,zero,0 40052c: 20020fa1 addi v0,zero,4001 400530: 0000000c syscall 00400534 : 400534: 0000000d break 400538: 1000fffe b 400534 40053c: 00000000 nop ``` It can be seen that assembler does not only expand '.cpload' but even marks 'jalr t9' instruction as a target for link time optimization. Because 'main' function is near (offset less than 128 kB) to the startup code, the 'jal' instruction is replaced by 'bal main' during linking phase. Then simple main function which outputs string to the serial port provided by QtMisp emulator can be implemented as: ``` /* serial-port-test.c */ #include #define SERIAL_PORT_BASE 0xffffc000 #define SERP_ST_REG_o 0x00 #define SERP_ST_REG_TX_BUSY_m 0x1 #define SERP_TX_REG_o 0x04 static inline void serp_write_reg(uint32_t base, uint32_t reg, uint32_t val) { *(volatile uint32_t *)(base + reg) = val; } static inline uint32_t serp_read_reg(uint32_t base, uint32_t reg) { return *(volatile uint32_t *)(base + reg); } void serp_tx_byte(int data) { while (serp_read_reg(SERIAL_PORT_BASE, SERP_ST_REG_o) & SERP_ST_REG_TX_BUSY_m); serp_write_reg(SERIAL_PORT_BASE, SERP_TX_REG_o, data); } int main(void) { const char *text = "Hello world.\nI am alive.\n"; const char *s; for (s = text; *s; s++) serp_tx_byte(*s); return 0; } ``` Compilation: ``` mips-linux-gnu-gcc -ggdb -fno-lto -c crt0local.S -o crt0local.o mips-linux-gnu-gcc -ggdb -O3 -fno-lto -c serial-port-test.c -o serial-port-test.o mips-linux-gnu-gcc -ggdb -nostartfiles -static -fno-lto crt0local.o serial-port-test.o -o serial-port-test ``` Simulator Compatability with Musl libc -------------------------------------- The 'mips-linux-gnu' toolchain can be alternativelly used with [musl libc](http://www.musl-libc.org/). The library can be built for the MIPS target by command ``` ../musl/configure CC=mips-linux-gnu-gcc LD=mips-linux-gnu-ld --target=mips-linux-gnu \ --prefix=/opt/musl/mips-linux-gnu --enable-debug --enable-optimize ``` User projects can be compiled and linked against 'musl libc' by specifying '-specs' option during C compiler invocation. ``` mips-linux-gnu-gcc -ggdb -O1 -march=mips2 -static -specs=/opt/musl/mips-linux-gnu/lib/musl-gcc.specs -c program.c -o program.o mips-linux-gnu-gcc -ggdb -march=mips2 -static -specs=/opt/musl/mips-linux-gnu/lib/musl-gcc.specs program.o -o program ``` The simulator implements 'rdhwr $rd, userlocal' instruction and allows code compiled agains [musl C library](http://www.musl-libc.org/). to start with libc provided 'crt0.o'. But there are multiple syscalls in the startup code which cause stop of continuous run mode and require to press run button again. It is better to use simple C library startup code replacement. It is enough to run 'printf()', 'sprintf()' and 'sscanf()' functions without complete C library initialization. Next variant supports both PIC/PIE and non-PIC environment. ``` /* minimal replacement of crt0.o which is else provided by C library */ /* this variant support both static and PIC/PIE environments */ .globl main .globl _start .globl __start .set noat .set noreorder .ent _start .text __start: _start: #if defined(__PIC__) || defined(__pic__) bal next nop next: .set noreorder .cpload $31 .set reorder #else la $gp, _gp #endif addi $a0, $zero, 0 addi $a1, $zero, 0 jal main nop quit: addi $a0, $zero, 0 addi $v0, $zero, 4001 /* SYS_exit */ syscall loop: break beq $zero, $zero, loop nop .end _start ``` Using of Make Utility with QtSim -------------------------------------- The invocation of the compiler and 'gcc' in the role of the linker can be automated. The 'make' utility is the standard solution. Next 'Makefile' provides a template for automation of these tasks ``` ARCH=mips-elf #ARCH=mips-linux-gnu SOURCES = crt0local.S qtmips_binrep.c TARGET_EXE = qtmips_binrep CC=$(ARCH)-gcc CXX=$(ARCH)-g++ AS=$(ARCH)-as LD=$(ARCH)-ld OBJCOPY=$(ARCH)-objcopy #ARCHFLAGS += -march=mips3 ARCHFLAGS += -fno-lto #ARCHFLAGS += -mno-shared CFLAGS += -ggdb -O3 -Wall CXXFLAGS+= -ggdb -O3 -Wall AFLAGS += -ggdb LDFLAGS += -ggdb LDFLAGS += -nostartfiles LDFLAGS += -static #LDFLAGS += -specs=/opt/musl/mips-linux-gnu/lib/musl-gcc.specs CFLAGS += $(ARCHFLAGS) CXXFLAGS+= $(ARCHFLAGS) AFLAGS += $(ARCHFLAGS) LDFLAGS += $(ARCHFLAGS) OBJECTS += $(filter %.o,$(SOURCES:%.S=%.o)) OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o)) OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o)) all : default .PHONY : default clean dep all %.o:%.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@ %.o:%.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ %.o:%.cpp $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< %.s:%.c $(CC) $(CFLAGS) $(CPPFLAGS) -S $< -o $@ default : $(TARGET_EXE) $(TARGET_EXE) : $(OBJECTS) $(CC) $(LDFLAGS) $^ -o $@ dep: depend depend: $(SOURCES) $(glob *.h) echo '# autogenerated dependencies' > depend ifneq ($(filter %.S,$(SOURCES)),) $(CC) -D__ASSEMBLY__ $(AFLAGS) -w -E -M $(filter %.S,$(SOURCES)) \ >> depend endif ifneq ($(filter %.c,$(SOURCES)),) $(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \ >> depend endif ifneq ($(filter %.cpp,$(SOURCES)),) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \ >> depend endif clean: rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) depend #mips-elf-objdump --source -M no-aliases,reg-names=numeric qtmips_binrep -include depend ``` The example provides defines which allow select compiler to be used ('mips-elf' or 'mips-linux-gnu') and enable build agains musl libc. qtrvsim-0.9.8/external/000077500000000000000000000000001467752164200150755ustar00rootroot00000000000000qtrvsim-0.9.8/external/compiler/000077500000000000000000000000001467752164200167075ustar00rootroot00000000000000qtrvsim-0.9.8/external/compiler/compile.sh000077500000000000000000000013231467752164200206750ustar00rootroot00000000000000#!/usr/bin/env bash # This script compiles compilation tools for mips to be used with qtmips set -e INST_PREFIX="$(pwd)" INST_CT_PREFIX="$INST_PREFIX/ct-ng" mkdir -p "$INST_CT_PREFIX" # First update git submodule pushd "$(dirname "$0")" >/dev/null git submodule update crosstool-ng pushd crosstool-ng >/dev/null # Now compile it # TODO don't compile it in place? ./bootstrap ./configure --prefix="$INST_CT_PREFIX" make make install # TODO do cleanups? popd >/dev/null popd >/dev/null # Copy configuration cp "$(dirname "$0")/config" ct-ng/.config pushd ct-ng >/dev/null # And compile ./bin/ct-ng oldconfig CT_PREFIX="$INST_PREFIX" ./bin/ct-ng build popd >/dev/null # Cleanup installed crosstool-ng rm -rf ct-ng qtrvsim-0.9.8/external/compiler/config000066400000000000000000000226741467752164200201120ustar00rootroot00000000000000# # Automatically generated file; DO NOT EDIT. # Crosstool-NG Configuration # CT_CONFIGURE_has_static_link=y CT_CONFIGURE_has_wget=y CT_CONFIGURE_has_curl=y CT_CONFIGURE_has_stat_flavor_GNU=y CT_CONFIGURE_has_make_3_81_or_newer=y CT_CONFIGURE_has_libtool_2_4_or_newer=y CT_CONFIGURE_has_libtoolize_2_4_or_newer=y CT_CONFIGURE_has_autoconf_2_63_or_newer=y CT_CONFIGURE_has_autoreconf_2_63_or_newer=y CT_CONFIGURE_has_automake_1_15_or_newer=y CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y CT_CONFIGURE_has_svn=y CT_CONFIGURE_has_git=y CT_MODULES=y # # Paths and misc options # # # crosstool-NG behavior # # CT_OBSOLETE is not set # CT_EXPERIMENTAL is not set # CT_DEBUG_CT is not set # # Paths # CT_LOCAL_TARBALLS_DIR="${HOME}/src" CT_SAVE_TARBALLS=y CT_WORK_DIR="${CT_TOP_DIR}/.build" CT_BUILD_TOP_DIR="${CT_WORK_DIR}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}" CT_PREFIX_DIR="${CT_PREFIX:-${HOME}/x-tools}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}" CT_RM_RF_PREFIX_DIR=y CT_REMOVE_DOCS=y CT_PREFIX_DIR_RO=y CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set # # Downloading # CT_DOWNLOAD_AGENT_WGET=y # CT_DOWNLOAD_AGENT_CURL is not set # CT_DOWNLOAD_AGENT_NONE is not set # CT_FORBID_DOWNLOAD is not set # CT_FORCE_DOWNLOAD is not set CT_CONNECT_TIMEOUT=10 CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary" # CT_ONLY_DOWNLOAD is not set # CT_USE_MIRROR is not set # # Extracting # # CT_FORCE_EXTRACT is not set CT_OVERRIDE_CONFIG_GUESS_SUB=y # CT_ONLY_EXTRACT is not set CT_PATCH_BUNDLED=y # CT_PATCH_LOCAL is not set # CT_PATCH_BUNDLED_LOCAL is not set # CT_PATCH_LOCAL_BUNDLED is not set # CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set # CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set # CT_PATCH_NONE is not set CT_PATCH_ORDER="bundled" # # Build behavior # CT_PARALLEL_JOBS=0 CT_LOAD="" CT_USE_PIPES=y CT_EXTRA_CFLAGS_FOR_BUILD="" CT_EXTRA_LDFLAGS_FOR_BUILD="" CT_EXTRA_CFLAGS_FOR_HOST="" CT_EXTRA_LDFLAGS_FOR_HOST="" # CT_CONFIG_SHELL_SH is not set # CT_CONFIG_SHELL_ASH is not set CT_CONFIG_SHELL_BASH=y # CT_CONFIG_SHELL_CUSTOM is not set CT_CONFIG_SHELL="${bash}" # # Logging # # CT_LOG_ERROR is not set # CT_LOG_WARN is not set # CT_LOG_INFO is not set CT_LOG_EXTRA=y # CT_LOG_ALL is not set # CT_LOG_DEBUG is not set CT_LOG_LEVEL_MAX="EXTRA" # CT_LOG_SEE_TOOLS_WARN is not set CT_LOG_PROGRESS_BAR=y CT_LOG_TO_FILE=y CT_LOG_FILE_COMPRESS=y # # Target options # CT_ARCH="mips" # CT_ARCH_alpha is not set # CT_ARCH_arm is not set # CT_ARCH_avr is not set # CT_ARCH_m68k is not set CT_ARCH_mips=y # CT_ARCH_nios2 is not set # CT_ARCH_powerpc is not set # CT_ARCH_s390 is not set # CT_ARCH_sh is not set # CT_ARCH_sparc is not set # CT_ARCH_x86 is not set # CT_ARCH_xtensa is not set CT_ARCH_alpha_AVAILABLE=y CT_ARCH_arm_AVAILABLE=y CT_ARCH_avr_AVAILABLE=y CT_ARCH_m68k_AVAILABLE=y CT_ARCH_microblaze_AVAILABLE=y CT_ARCH_mips_AVAILABLE=y CT_ARCH_nios2_AVAILABLE=y CT_ARCH_powerpc_AVAILABLE=y CT_ARCH_s390_AVAILABLE=y CT_ARCH_sh_AVAILABLE=y CT_ARCH_sparc_AVAILABLE=y CT_ARCH_x86_AVAILABLE=y CT_ARCH_xtensa_AVAILABLE=y CT_ARCH_SUFFIX="" # # Generic target options # # CT_MULTILIB is not set CT_DEMULTILIB=y CT_ARCH_USE_MMU=y CT_ARCH_SUPPORTS_BOTH_ENDIAN=y CT_ARCH_DEFAULT_BE=y CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_ENDIAN="big" CT_ARCH_SUPPORTS_32=y CT_ARCH_SUPPORTS_64=y CT_ARCH_DEFAULT_32=y CT_ARCH_BITNESS=32 CT_ARCH_32=y # CT_ARCH_64 is not set # # Target optimisations # CT_ARCH_SUPPORTS_WITH_ARCH=y CT_ARCH_SUPPORTS_WITH_TUNE=y CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_ARCH="" CT_ARCH_TUNE="" # CT_ARCH_FLOAT_AUTO is not set # CT_ARCH_FLOAT_HW is not set CT_ARCH_FLOAT_SW=y CT_TARGET_CFLAGS="" CT_TARGET_LDFLAGS="" CT_ARCH_FLOAT="soft" # # mips other options # CT_ARCH_mips_o32=y CT_ARCH_mips_ABI="32" # # Toolchain options # # # General toolchain options # CT_WANTS_STATIC_LINK=y CT_WANTS_STATIC_LINK_CXX=y CT_STATIC_TOOLCHAIN=y CT_TOOLCHAIN_PKGVERSION="" CT_TOOLCHAIN_BUGURL="" # # Tuple completion and aliasing # CT_TARGET_VENDOR="qtmips" CT_TARGET_ALIAS_SED_EXPR="" CT_TARGET_ALIAS="" # # Toolchain type # CT_CROSS=y # CT_CANADIAN is not set CT_TOOLCHAIN_TYPE="cross" # # Build system # CT_BUILD="" CT_BUILD_PREFIX="" CT_BUILD_SUFFIX="" # # Misc options # # CT_TOOLCHAIN_ENABLE_NLS is not set # # Operating System # CT_BARE_METAL=y CT_KERNEL="bare-metal" CT_KERNEL_bare_metal=y # CT_KERNEL_linux is not set CT_KERNEL_bare_metal_AVAILABLE=y CT_KERNEL_linux_AVAILABLE=y CT_KERNEL_windows_AVAILABLE=y # # Common kernel options # # # Binary utilities # CT_ARCH_BINFMT_ELF=y CT_BINUTILS="binutils" CT_BINUTILS_binutils=y # # GNU binutils # CT_BINUTILS_VERSION="2.28" # CT_BINUTILS_SHOW_LINARO is not set CT_BINUTILS_V_2_28=y # CT_BINUTILS_V_2_27 is not set # CT_BINUTILS_V_2_26 is not set CT_BINUTILS_2_27_or_later=y CT_BINUTILS_2_26_or_later=y CT_BINUTILS_2_25_1_or_later=y CT_BINUTILS_2_25_or_later=y CT_BINUTILS_2_24_or_later=y CT_BINUTILS_2_23_2_or_later=y CT_BINUTILS_HAS_HASH_STYLE=y CT_BINUTILS_HAS_GOLD=y CT_BINUTILS_HAS_PLUGINS=y CT_BINUTILS_HAS_PKGVERSION_BUGURL=y CT_BINUTILS_LINKER_LD=y CT_BINUTILS_LINKERS_LIST="ld" CT_BINUTILS_LINKER_DEFAULT="bfd" CT_BINUTILS_EXTRA_CONFIG_ARRAY="" # # binutils other options # # # C-library # CT_LIBC="newlib" CT_LIBC_VERSION="2.5.0.20170323" CT_LIBC_newlib=y # CT_LIBC_none is not set CT_LIBC_avr_libc_AVAILABLE=y CT_LIBC_glibc_AVAILABLE=y CT_THREADS="none" CT_LIBC_mingw_AVAILABLE=y CT_LIBC_musl_AVAILABLE=y CT_LIBC_newlib_AVAILABLE=y # CT_CC_NEWLIB_SHOW_LINARO is not set CT_LIBC_NEWLIB_V_2_5_0=y # CT_LIBC_NEWLIB_V_2_4_0 is not set # CT_LIBC_NEWLIB_V_2_3_0 is not set # CT_LIBC_NEWLIB_V_2_2_0 is not set # CT_LIBC_NEWLIB_V_2_1_0 is not set # CT_LIBC_NEWLIB_V_2_0_0 is not set # CT_LIBC_NEWLIB_V_1_20_0 is not set # CT_LIBC_NEWLIB_V_1_19_0 is not set # CT_LIBC_NEWLIB_V_1_18_0 is not set # CT_LIBC_NEWLIB_V_1_17_0 is not set CT_LIBC_NEWLIB_2_5=y CT_LIBC_NEWLIB_2_5_or_later=y CT_LIBC_NEWLIB_2_4_or_later=y CT_LIBC_NEWLIB_2_3_or_later=y CT_LIBC_NEWLIB_2_2_or_later=y CT_LIBC_NEWLIB_2_1_or_later=y CT_LIBC_NEWLIB_2_0_or_later=y CT_LIBC_NEWLIB_TARGET_CFLAGS="" CT_LIBC_none_AVAILABLE=y CT_LIBC_uClibc_AVAILABLE=y CT_LIBC_SUPPORT_THREADS_NONE=y CT_LIBC_PROVIDES_CXA_ATEXIT=y # # Common C library options # CT_THREADS_NONE=y # # newlib other options # # CT_LIBC_NEWLIB_IO_C99FMT is not set # CT_LIBC_NEWLIB_IO_LL is not set # CT_LIBC_NEWLIB_IO_FLOAT is not set # CT_LIBC_NEWLIB_IO_POS_ARGS is not set CT_LIBC_NEWLIB_FVWRITE_IN_STREAMIO=y CT_LIBC_NEWLIB_UNBUF_STREAM_OPT=y CT_LIBC_NEWLIB_FSEEK_OPTIMIZATION=y # CT_LIBC_NEWLIB_DISABLE_SUPPLIED_SYSCALLS is not set # CT_LIBC_NEWLIB_REGISTER_FINI is not set CT_LIBC_NEWLIB_ATEXIT_DYNAMIC_ALLOC=y # CT_LIBC_NEWLIB_GLOBAL_ATEXIT is not set # CT_LIBC_NEWLIB_LITE_EXIT is not set # CT_LIBC_NEWLIB_REENT_SMALL is not set CT_LIBC_NEWLIB_MULTITHREAD=y # CT_LIBC_NEWLIB_EXTRA_SECTIONS is not set CT_LIBC_NEWLIB_WIDE_ORIENT=y CT_LIBC_NEWLIB_ENABLE_TARGET_OPTSPACE=y # CT_LIBC_NEWLIB_NANO_MALLOC is not set # CT_LIBC_NEWLIB_NANO_FORMATTED_IO is not set CT_LIBC_NEWLIB_EXTRA_CONFIG_ARRAY="" # # C compiler # CT_CC="gcc" CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y CT_CC_GCC_VERSION="5.4.0" # CT_CC_GCC_SHOW_LINARO is not set # CT_CC_GCC_V_6_3_0 is not set CT_CC_GCC_V_5_4_0=y # CT_CC_GCC_V_4_9_4 is not set CT_CC_GCC_4_8_or_later=y CT_CC_GCC_4_9_or_later=y CT_CC_GCC_5=y CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_LIBMPX=y CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_CONFIG_ARRAY="" # CT_CC_GCC_TARGET_FINAL is not set CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set CT_CC_GCC_CONFIG_TLS=m # # Optimisation features # CT_CC_GCC_USE_GRAPHITE=y # # Settings for libraries running on target # CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y # CT_CC_GCC_LIBMUDFLAP is not set # CT_CC_GCC_LIBSSP is not set # CT_CC_GCC_LIBQUADMATH is not set # # Misc. obscure options. # CT_CC_CXA_ATEXIT=y # CT_CC_GCC_DISABLE_PCH is not set CT_CC_GCC_LDBL_128=m # CT_CC_GCC_BUILD_ID is not set CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y # CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set # CT_CC_GCC_LNK_HASH_STYLE_GNU is not set # CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set CT_CC_GCC_LNK_HASH_STYLE="" CT_CC_GCC_DEC_FLOAT_AUTO=y # CT_CC_GCC_DEC_FLOAT_BID is not set # CT_CC_GCC_DEC_FLOAT_DPD is not set # CT_CC_GCC_DEC_FLOATS_NO is not set CT_CC_GCC_HAS_ARCH_OPTIONS=y # # archictecture-specific options # CT_CC_GCC_mips_llsc=m CT_CC_GCC_mips_synci=m # CT_CC_GCC_mips_plt is not set CT_CC_SUPPORT_CXX=y CT_CC_SUPPORT_FORTRAN=y CT_CC_SUPPORT_JAVA=y CT_CC_SUPPORT_ADA=y CT_CC_SUPPORT_OBJC=y CT_CC_SUPPORT_OBJCXX=y CT_CC_SUPPORT_GOLANG=y # # Additional supported languages: # # CT_CC_LANG_CXX is not set # CT_CC_LANG_FORTRAN is not set # # Debug facilities # # CT_DEBUG_gdb is not set # CT_DEBUG_ltrace is not set # CT_DEBUG_strace is not set # # Companion libraries # CT_COMPLIBS_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y # CT_LIBICONV is not set # CT_GETTEXT is not set CT_GMP=y CT_MPFR=y CT_ISL=y CT_MPC=y # CT_ZLIB is not set CT_GMP_V_6_1_2=y CT_GMP_5_0_2_or_later=y CT_GMP_VERSION="6.1.2" CT_MPFR_V_3_1_5=y CT_MPFR_VERSION="3.1.5" CT_ISL_V_0_16_1=y # CT_ISL_V_0_15 is not set CT_ISL_V_0_16_or_later=y CT_ISL_V_0_15_or_later=y CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.16.1" CT_MPC_V_1_0_3=y CT_MPC_VERSION="1.0.3" # # Companion libraries common options # # CT_COMPLIBS_CHECK is not set # # Companion tools # # CT_COMP_TOOLS_FOR_HOST is not set # CT_COMP_TOOLS_autoconf is not set # CT_COMP_TOOLS_automake is not set # CT_COMP_TOOLS_libtool is not set # CT_COMP_TOOLS_m4 is not set # CT_COMP_TOOLS_make is not set qtrvsim-0.9.8/external/libelf/000077500000000000000000000000001467752164200163325ustar00rootroot00000000000000qtrvsim-0.9.8/external/libelf/32.fsize.c000066400000000000000000000117141467752164200200450ustar00rootroot00000000000000/* 32.fsize.c - implementation of the elf{32,64}_fsize(3) functions. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "ext_types.h" #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.fsize.c,v 1.13 2008/05/23 08:15:33 michael Exp $"; #endif /* lint */ const size_t _elf_fmsize[2][EV_CURRENT - EV_NONE][ELF_T_NUM][2] = { /* ELFCLASS32 */ { /* version 1 */ { { sizeof(unsigned char), sizeof(unsigned char) }, { sizeof(Elf32_Addr), sizeof(__ext_Elf32_Addr) }, { sizeof(Elf32_Dyn), sizeof(__ext_Elf32_Dyn) }, { sizeof(Elf32_Ehdr), sizeof(__ext_Elf32_Ehdr) }, { sizeof(Elf32_Half), sizeof(__ext_Elf32_Half) }, { sizeof(Elf32_Off), sizeof(__ext_Elf32_Off) }, { sizeof(Elf32_Phdr), sizeof(__ext_Elf32_Phdr) }, { sizeof(Elf32_Rela), sizeof(__ext_Elf32_Rela) }, { sizeof(Elf32_Rel), sizeof(__ext_Elf32_Rel) }, { sizeof(Elf32_Shdr), sizeof(__ext_Elf32_Shdr) }, { sizeof(Elf32_Sword), sizeof(__ext_Elf32_Sword) }, { sizeof(Elf32_Sym), sizeof(__ext_Elf32_Sym) }, { sizeof(Elf32_Word), sizeof(__ext_Elf32_Word) }, { 0, 0 }, /* there is no Elf32_Sxword */ { 0, 0 }, /* there is no Elf32_Xword */ /* XXX: check Solaris values */ { 0, 0 }, /* Elf32_Verdef/Verdaux size varies */ { 0, 0 }, /* Elf32_Verneed/Vernaux size varies */ }, }, #if __LIBELF64 /* ELFCLASS64 */ { /* version 1 */ { { sizeof(unsigned char), sizeof(unsigned char) }, { sizeof(Elf64_Addr), sizeof(__ext_Elf64_Addr) }, { sizeof(Elf64_Dyn), sizeof(__ext_Elf64_Dyn) }, { sizeof(Elf64_Ehdr), sizeof(__ext_Elf64_Ehdr) }, { sizeof(Elf64_Half), sizeof(__ext_Elf64_Half) }, { sizeof(Elf64_Off), sizeof(__ext_Elf64_Off) }, { sizeof(Elf64_Phdr), sizeof(__ext_Elf64_Phdr) }, { sizeof(Elf64_Rela), sizeof(__ext_Elf64_Rela) }, { sizeof(Elf64_Rel), sizeof(__ext_Elf64_Rel) }, { sizeof(Elf64_Shdr), sizeof(__ext_Elf64_Shdr) }, { sizeof(Elf64_Sword), sizeof(__ext_Elf64_Sword) }, { sizeof(Elf64_Sym), sizeof(__ext_Elf64_Sym) }, { sizeof(Elf64_Word), sizeof(__ext_Elf64_Word) }, { sizeof(Elf64_Sxword), sizeof(__ext_Elf64_Sxword) }, { sizeof(Elf64_Xword), sizeof(__ext_Elf64_Xword) }, /* XXX: check Solaris values */ { 0, 0 }, /* Elf64_Verdef/Verdaux size varies */ { 0, 0 }, /* Elf64_Verneed/Vernaux size varies */ }, }, #endif /* __LIBELF64 */ }; static size_t _elf_fsize(unsigned cls, Elf_Type type, unsigned ver) { size_t n = 0; if (!valid_version(ver)) { seterr(ERROR_UNKNOWN_VERSION); } else if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); } else if (!(n = _fsize(cls, ver, type))) { seterr(ERROR_UNKNOWN_TYPE); } return n; } size_t elf32_fsize(Elf_Type type, size_t count, unsigned ver) { return count * _elf_fsize(ELFCLASS32, type, ver); } #if __LIBELF64 size_t elf64_fsize(Elf_Type type, size_t count, unsigned ver) { return count * _elf_fsize(ELFCLASS64, type, ver); } size_t gelf_fsize(Elf *elf, Elf_Type type, size_t count, unsigned ver) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (valid_class(elf->e_class)) { return count * _elf_fsize(elf->e_class, type, ver); } else { seterr(ERROR_UNKNOWN_CLASS); } } return 0; } /* * Extension: report memory size */ size_t gelf_msize(Elf *elf, Elf_Type type, size_t count, unsigned ver) { size_t n; if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); } else if (!valid_version(ver)) { seterr(ERROR_UNKNOWN_VERSION); } else if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); } else if (!(n = _msize(elf->e_class, ver, type))) { seterr(ERROR_UNKNOWN_TYPE); } else { return count * n; } } return 0; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.getehdr.c000066400000000000000000000030561467752164200203470ustar00rootroot00000000000000/* 32.getehdr.c - implementation of the elf{32,64}_getehdr(3) functions. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.getehdr.c,v 1.9 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ char *_elf_getehdr(Elf *elf, unsigned cls) { if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class != cls) { seterr(ERROR_CLASSMISMATCH); } else if (elf->e_ehdr || _elf_cook(elf)) { return elf->e_ehdr; } return NULL; } Elf32_Ehdr *elf32_getehdr(Elf *elf) { return (Elf32_Ehdr *)_elf_getehdr(elf, ELFCLASS32); } #if __LIBELF64 Elf64_Ehdr *elf64_getehdr(Elf *elf) { return (Elf64_Ehdr *)_elf_getehdr(elf, ELFCLASS64); } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.getphdr.c000066400000000000000000000030571467752164200203630ustar00rootroot00000000000000/* 32.getphdr.c - implementation of the elf{32,64}_getphdr(3) functions. Copyright (C) 1995 - 2000 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.getphdr.c,v 1.11 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ char *_elf_getphdr(Elf *elf, unsigned cls) { if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class != cls) { seterr(ERROR_CLASSMISMATCH); } else if (elf->e_ehdr || _elf_cook(elf)) { return elf->e_phdr; } return NULL; } Elf32_Phdr *elf32_getphdr(Elf *elf) { return (Elf32_Phdr *)_elf_getphdr(elf, ELFCLASS32); } #if __LIBELF64 Elf64_Phdr *elf64_getphdr(Elf *elf) { return (Elf64_Phdr *)_elf_getphdr(elf, ELFCLASS64); } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.getshdr.c000066400000000000000000000032411467752164200203610ustar00rootroot00000000000000/* 32.getshdr.c - implementation of the elf{32,64}_getshdr(3) functions. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.getshdr.c,v 1.10 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ Elf32_Shdr *elf32_getshdr(Elf_Scn *scn) { if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (scn->s_elf->e_class == ELFCLASS32) { return &scn->s_shdr32; } seterr(ERROR_CLASSMISMATCH); return NULL; } #if __LIBELF64 Elf64_Shdr *elf64_getshdr(Elf_Scn *scn) { if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (scn->s_elf->e_class == ELFCLASS64) { return &scn->s_shdr64; } seterr(ERROR_CLASSMISMATCH); return NULL; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.newehdr.c000066400000000000000000000043641467752164200203640ustar00rootroot00000000000000/* * 32.newehdr.c - implementation of the elf{32,64}_newehdr(3) functions. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.newehdr.c,v 1.16 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ static char *_elf_newehdr(Elf *elf, unsigned cls) { size_t size; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_readable) { return _elf_getehdr(elf, cls); } else if (!elf->e_ehdr) { size = _msize(cls, _elf_version, ELF_T_EHDR); elf_assert(size); if ((elf->e_ehdr = (char *)malloc(size))) { memset(elf->e_ehdr, 0, size); elf->e_ehdr_flags |= ELF_F_DIRTY; elf->e_kind = ELF_K_ELF; elf->e_class = cls; return elf->e_ehdr; } seterr(ERROR_MEM_EHDR); } else if (elf->e_class != cls) { seterr(ERROR_CLASSMISMATCH); } else { elf_assert(elf->e_kind == ELF_K_ELF); return elf->e_ehdr; } return NULL; } Elf32_Ehdr *elf32_newehdr(Elf *elf) { return (Elf32_Ehdr *)_elf_newehdr(elf, ELFCLASS32); } #if __LIBELF64 Elf64_Ehdr *elf64_newehdr(Elf *elf) { return (Elf64_Ehdr *)_elf_newehdr(elf, ELFCLASS64); } unsigned long gelf_newehdr(Elf *elf, int cls) { if (!valid_class(cls) || !_msize(cls, _elf_version, ELF_T_EHDR)) { seterr(ERROR_UNKNOWN_CLASS); return 0; } return (unsigned long)_elf_newehdr(elf, cls); } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.newphdr.c000066400000000000000000000065341467752164200204000ustar00rootroot00000000000000/* * 32.newphdr.c - implementation of the elf{32,64}_newphdr(3) functions. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.newphdr.c,v 1.16 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ static char *_elf_newphdr(Elf *elf, size_t count, unsigned cls) { size_t extcount = 0; Elf_Scn *scn = NULL; char *phdr = NULL; size_t size; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_ehdr && !elf->e_readable) { seterr(ERROR_NOEHDR); } else if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class != cls) { seterr(ERROR_CLASSMISMATCH); } else if (elf->e_ehdr || _elf_cook(elf)) { size = _msize(cls, _elf_version, ELF_T_PHDR); elf_assert(size); if (!(scn = _elf_first_scn(elf))) { return NULL; } if (count) { if (!(phdr = (char *)malloc(count * size))) { seterr(ERROR_MEM_PHDR); return NULL; } memset(phdr, 0, count * size); } elf_assert(elf->e_ehdr); elf->e_phnum = count; if (count >= PN_XNUM) { /* * get NULL section (create it if necessary) */ extcount = count; count = PN_XNUM; } if (cls == ELFCLASS32) { ((Elf32_Ehdr *)elf->e_ehdr)->e_phnum = count; scn->s_shdr32.sh_info = extcount; } #if __LIBELF64 else if (cls == ELFCLASS64) { ((Elf64_Ehdr *)elf->e_ehdr)->e_phnum = count; scn->s_shdr64.sh_info = extcount; } #endif /* __LIBELF64 */ else { seterr(ERROR_UNIMPLEMENTED); if (phdr) { free(phdr); } return NULL; } if (elf->e_phdr) { free(elf->e_phdr); } elf->e_phdr = phdr; elf->e_phdr_flags |= ELF_F_DIRTY; elf->e_ehdr_flags |= ELF_F_DIRTY; scn->s_scn_flags |= ELF_F_DIRTY; return phdr; } return NULL; } Elf32_Phdr *elf32_newphdr(Elf *elf, size_t count) { return (Elf32_Phdr *)_elf_newphdr(elf, count, ELFCLASS32); } #if __LIBELF64 Elf64_Phdr *elf64_newphdr(Elf *elf, size_t count) { return (Elf64_Phdr *)_elf_newphdr(elf, count, ELFCLASS64); } unsigned long gelf_newphdr(Elf *elf, size_t phnum) { if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); return 0; } return (unsigned long)_elf_newphdr(elf, phnum, elf->e_class); } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/32.xlatetof.c000066400000000000000000000421701467752164200205530ustar00rootroot00000000000000/* * 32.xlatetof.c - implementation of the elf32_xlateto[fm](3) functions. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: 32.xlatetof.c,v 1.27 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ /* * Ugly, ugly */ #ifdef _WIN32 #define Cat2(a, b) a##b #define Cat3(a, b, c) a##b##c #define Ex1(m1, m2, a, b) m1##m2(a##b) #define Ex2(m1, m2, a, b, c) m1##m2(a, b##c) #else /* _WIN32 */ #define x #if defined /**/ x #define Cat2(a, b) a##b #define Cat3(a, b, c) a##b##c #define Ex1(m1, m2, a, b) m1##m2(a##b) #define Ex2(m1, m2, a, b, c) m1##m2(a, b##c) #else #define Cat2(a, b) a /**/ b #define Cat3(a, b, c) a /**/ b /**/ c #define Ex1(m1, m2, a, b) m1 /**/ m2(a /**/ b) #define Ex2(m1, m2, a, b, c) m1 /**/ m2(a, b /**/ c) #endif #undef x #endif /* _WIN32 */ /* * auxiliary macros for execution order reversal */ #define seq_forw(a, b) a b #define seq_back(a, b) b a /* * function instantiator */ #define copy_type_e_io(name, e, io, tfrom, tto, copy) \ static size_t Cat3(name, _, io)( \ unsigned char *dst, const unsigned char *src, size_t n) { \ n /= sizeof(tfrom); \ if (n && dst) { \ const tfrom *from = (const tfrom *)src; \ tto *to = (tto *)dst; \ size_t i; \ \ if (sizeof(tfrom) < sizeof(tto)) { \ from += n; \ to += n; \ for (i = 0; i < n; i++) { \ --from; \ --to; \ copy(e, io, seq_back) \ } \ } else { \ for (i = 0; i < n; i++) { \ copy(e, io, seq_forw) from++; \ to++; \ } \ } \ } \ return n * sizeof(tto); \ } #define copy_type_e(name, e, type, copy) \ copy_type_e_io(name, e, tom, Cat2(__ext_, type), type, copy) \ copy_type_e_io(name, e, tof, type, Cat2(__ext_, type), copy) /* * master function instantiator */ #define copy_type(name, version, type, copy) \ copy_type_e(Cat3(name, L, version), L, type, copy) \ copy_type_e(Cat3(name, M, version), M, type, copy) /* * scalar copying */ #define copy_scalar_tom(type) *to = Cat2(__load_, type)(*from); #define copy_scalar_tof(type) Cat2(__store_, type)(*to, *from); /* * structure member copying */ #define copy_tom(mb, type) to->mb = Cat2(__load_, type)(from->mb); #define copy_tof(mb, type) Cat2(__store_, type)(to->mb, from->mb); /* * structure member copying (direction independent) */ #define copy_byte(e, io, mb) to->mb = from->mb; #define copy_addr(e, io, mb) Ex2(copy_, io, mb, u32, e) #define copy_half(e, io, mb) Ex2(copy_, io, mb, u16, e) #define copy_off(e, io, mb) Ex2(copy_, io, mb, u32, e) #define copy_sword(e, io, mb) Ex2(copy_, io, mb, i32, e) #define copy_word(e, io, mb) Ex2(copy_, io, mb, u32, e) #define copy_arr(e, io, mb) \ array_copy(to->mb, sizeof(to->mb), from->mb, sizeof(from->mb)); /* * scalar copying (direction independent) * these macros are used as `copy' arguments to copy_type() */ #define copy_addr_11(e, io, seq) Ex1(copy_scalar_, io, u32, e) #define copy_half_11(e, io, seq) Ex1(copy_scalar_, io, u16, e) #define copy_off_11(e, io, seq) Ex1(copy_scalar_, io, u32, e) #define copy_sword_11(e, io, seq) Ex1(copy_scalar_, io, i32, e) #define copy_word_11(e, io, seq) Ex1(copy_scalar_, io, u32, e) /* * structure copying (direction independent) * these macros are used as `copy' arguments to copy_type() */ #define copy_dyn_11(e, io, seq) \ seq(copy_sword(e, io, d_tag), seq(copy_addr(e, io, d_un.d_ptr), nullcopy)) #define copy_ehdr_11(e, io, seq) \ seq(copy_arr(e, io, e_ident), \ seq(copy_half(e, io, e_type), \ seq(copy_half(e, io, e_machine), \ seq(copy_word(e, io, e_version), \ seq(copy_addr(e, io, e_entry), \ seq(copy_off(e, io, e_phoff), \ seq(copy_off(e, io, e_shoff), \ seq(copy_word(e, io, e_flags), \ seq(copy_half(e, io, e_ehsize), \ seq(copy_half(e, io, e_phentsize), \ seq(copy_half(e, io, e_phnum), \ seq(copy_half( \ e, io, e_shentsize), \ seq(copy_half( \ e, io, e_shnum), \ seq(copy_half( \ e, io, \ e_shstrndx), \ nullcopy)))))))))))))) #define copy_phdr_11(e, io, seq) \ seq(copy_word(e, io, p_type), \ seq(copy_off(e, io, p_offset), \ seq(copy_addr(e, io, p_vaddr), \ seq(copy_addr(e, io, p_paddr), \ seq(copy_word(e, io, p_filesz), \ seq(copy_word(e, io, p_memsz), \ seq(copy_word(e, io, p_flags), \ seq(copy_word(e, io, p_align), nullcopy)))))))) #define copy_rela_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), \ seq(copy_word(e, io, r_info), \ seq(copy_sword(e, io, r_addend), nullcopy))) #define copy_rel_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), seq(copy_word(e, io, r_info), nullcopy)) #define copy_shdr_11(e, io, seq) \ seq(copy_word(e, io, sh_name), \ seq(copy_word(e, io, sh_type), \ seq(copy_word(e, io, sh_flags), \ seq(copy_addr(e, io, sh_addr), \ seq(copy_off(e, io, sh_offset), \ seq(copy_word(e, io, sh_size), \ seq(copy_word(e, io, sh_link), \ seq(copy_word(e, io, sh_info), \ seq(copy_word(e, io, sh_addralign), \ seq(copy_word(e, io, sh_entsize), \ nullcopy)))))))))) #define copy_sym_11(e, io, seq) \ seq(copy_word(e, io, st_name), \ seq(copy_addr(e, io, st_value), \ seq(copy_word(e, io, st_size), \ seq(copy_byte(e, io, st_info), \ seq(copy_byte(e, io, st_other), \ seq(copy_half(e, io, st_shndx), nullcopy)))))) #define nullcopy /**/ static size_t byte_copy(unsigned char *dst, const unsigned char *src, size_t n) { if (n && dst && dst != src) { #if HAVE_BROKEN_MEMMOVE size_t i; if (dst >= src + n || dst + n <= src) { memcpy(dst, src, n); } else if (dst < src) { for (i = 0; i < n; i++) { dst[i] = src[i]; } } else { for (i = n; --i;) { dst[i] = src[i]; } } #else /* HAVE_BROKEN_MEMMOVE */ memmove(dst, src, n); #endif /* HAVE_BROKEN_MEMMOVE */ } return n; } static void array_copy( unsigned char *dst, size_t dlen, const unsigned char *src, size_t slen) { byte_copy(dst, src, dlen < slen ? dlen : slen); if (dlen > slen) { memset(dst + slen, 0, dlen - slen); } } /* * instantiate copy functions */ copy_type(addr_32, _, Elf32_Addr, copy_addr_11) copy_type( half_32, _, Elf32_Half, copy_half_11) copy_type(off_32, _, Elf32_Off, copy_off_11) copy_type(sword_32, _, Elf32_Sword, copy_sword_11) copy_type(word_32, _, Elf32_Word, copy_word_11) copy_type(dyn_32, 11, Elf32_Dyn, copy_dyn_11) copy_type(ehdr_32, 11, Elf32_Ehdr, copy_ehdr_11) copy_type(phdr_32, 11, Elf32_Phdr, copy_phdr_11) copy_type(rela_32, 11, Elf32_Rela, copy_rela_11) copy_type(rel_32, 11, Elf32_Rel, copy_rel_11) copy_type(shdr_32, 11, Elf32_Shdr, copy_shdr_11) copy_type(sym_32, 11, Elf32_Sym, copy_sym_11) typedef size_t (*xlator)( unsigned char *, const unsigned char *, size_t); typedef xlator xltab[ELF_T_NUM][2]; /* * translation table (32-bit, version 1 -> version 1) */ #if PIC static xltab #else /* PIC */ static const xltab #endif /* PIC */ xlate32_11[/*encoding*/] = { { { byte_copy, byte_copy }, { addr_32L__tom, addr_32L__tof }, { dyn_32L11_tom, dyn_32L11_tof }, { ehdr_32L11_tom, ehdr_32L11_tof }, { half_32L__tom, half_32L__tof }, { off_32L__tom, off_32L__tof }, { phdr_32L11_tom, phdr_32L11_tof }, { rela_32L11_tom, rela_32L11_tof }, { rel_32L11_tom, rel_32L11_tof }, { shdr_32L11_tom, shdr_32L11_tof }, { sword_32L__tom, sword_32L__tof }, { sym_32L11_tom, sym_32L11_tof }, { word_32L__tom, word_32L__tof }, { 0, 0 }, /* there is no Sxword */ { 0, 0 }, /* there is no Xword */ #if __LIBELF_SYMBOL_VERSIONS { _elf_verdef_32L11_tom, _elf_verdef_32L11_tof }, { _elf_verneed_32L11_tom, _elf_verneed_32L11_tof }, #else /* __LIBELF_SYMBOL_VERSIONS */ { 0, 0 }, { 0, 0 }, #endif /* __LIBELF_SYMBOL_VERSIONS */ }, { { byte_copy, byte_copy }, { addr_32M__tom, addr_32M__tof }, { dyn_32M11_tom, dyn_32M11_tof }, { ehdr_32M11_tom, ehdr_32M11_tof }, { half_32M__tom, half_32M__tof }, { off_32M__tom, off_32M__tof }, { phdr_32M11_tom, phdr_32M11_tof }, { rela_32M11_tom, rela_32M11_tof }, { rel_32M11_tom, rel_32M11_tof }, { shdr_32M11_tom, shdr_32M11_tof }, { sword_32M__tom, sword_32M__tof }, { sym_32M11_tom, sym_32M11_tof }, { word_32M__tom, word_32M__tof }, { 0, 0 }, /* there is no Sxword */ { 0, 0 }, /* there is no Xword */ #if __LIBELF_SYMBOL_VERSIONS { _elf_verdef_32M11_tom, _elf_verdef_32M11_tof }, { _elf_verneed_32M11_tom, _elf_verneed_32M11_tof }, #else /* __LIBELF_SYMBOL_VERSIONS */ { 0, 0 }, { 0, 0 }, #endif /* __LIBELF_SYMBOL_VERSIONS */ }, }; /* * main translation table (32-bit) */ #if PIC static xltab * #else /* PIC */ static const xltab *const #endif /* PIC */ xlate32[EV_CURRENT - EV_NONE][EV_CURRENT - EV_NONE] = { { xlate32_11, }, }; #define translator(sv, dv, enc, type, d) \ (xlate32[(sv)-EV_NONE - 1][(dv)-EV_NONE - 1][(enc)-ELFDATA2LSB] \ [(type)-ELF_T_BYTE][d]) /* * destination buffer size */ size_t _elf32_xltsize(const Elf_Data *src, unsigned dv, unsigned encode, int tof) { Elf_Type type = src->d_type; unsigned sv = src->d_version; xlator op; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return (size_t)-1; } if (tof) { /* * Encoding doesn't really matter (the translator only looks at * the source, which resides in memory), but we need a proper * encoding to select a translator... */ encode = ELFDATA2LSB; } else if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return (size_t)-1; } if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } if (!(op = translator(sv, dv, encode, type, tof))) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } return (*op)(NULL, src->d_buf, src->d_size); } /* * direction-independent translation */ static Elf_Data * elf32_xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) { Elf_Type type; int dv; int sv; size_t dsize; size_t tmp; xlator op; if (!src || !dst) { return NULL; } if (!src->d_buf || !dst->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return NULL; } sv = src->d_version; dv = dst->d_version; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return NULL; } type = src->d_type; if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } op = translator(sv, dv, encode, type, tof); if (!op) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } dsize = (*op)(NULL, src->d_buf, src->d_size); if (dsize == (size_t)-1) { return NULL; } if (dst->d_size < dsize) { seterr(ERROR_DST2SMALL); return NULL; } if (dsize) { tmp = (*op)(dst->d_buf, src->d_buf, src->d_size); if (tmp == (size_t)-1) { return NULL; } elf_assert(tmp == dsize); } dst->d_size = dsize; dst->d_type = type; return dst; } /* * finally, the "official" translation functions */ Elf_Data *elf32_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return elf32_xlate(dst, src, encode, 0); } Elf_Data *elf32_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return elf32_xlate(dst, src, encode, 1); } qtrvsim-0.9.8/external/libelf/64.xlatetof.c000066400000000000000000000512601467752164200205600ustar00rootroot00000000000000/* * 64.xlatetof.c - implementation of the elf64_xlateto[fm](3) functions. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: 64.xlatetof.c,v 1.27 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ /* * Ugly, ugly */ #ifdef _WIN32 #define Cat2(a, b) a##b #define Cat3(a, b, c) a##b##c #define Ex1(m1, m2, a, b) m1##m2(a##b) #define Ex2(m1, m2, a, b, c) m1##m2(a, b##c) #else /* _WIN32 */ #define x #if defined /**/ x #define Cat2(a, b) a##b #define Cat3(a, b, c) a##b##c #define Ex1(m1, m2, a, b) m1##m2(a##b) #define Ex2(m1, m2, a, b, c) m1##m2(a, b##c) #else #define Cat2(a, b) a /**/ b #define Cat3(a, b, c) a /**/ b /**/ c #define Ex1(m1, m2, a, b) m1 /**/ m2(a /**/ b) #define Ex2(m1, m2, a, b, c) m1 /**/ m2(a, b /**/ c) #endif #undef x #endif /* _WIN32 */ /* * auxiliary macros for execution order reversal */ #define seq_forw(a, b) a b #define seq_back(a, b) b a /* * function instantiator */ #define copy_type_e_io(name, e, io, tfrom, tto, copy) \ static size_t Cat3(name, _, io)( \ unsigned char *dst, const unsigned char *src, size_t n) { \ n /= sizeof(tfrom); \ if (n && dst) { \ const tfrom *from = (const tfrom *)src; \ tto *to = (tto *)dst; \ size_t i; \ \ if (sizeof(tfrom) < sizeof(tto)) { \ from += n; \ to += n; \ for (i = 0; i < n; i++) { \ --from; \ --to; \ copy(e, io, seq_back) \ } \ } else { \ for (i = 0; i < n; i++) { \ copy(e, io, seq_forw) from++; \ to++; \ } \ } \ } \ return n * sizeof(tto); \ } #define copy_type_e(name, e, type, copy) \ copy_type_e_io(name, e, tom, Cat2(__ext_, type), type, copy) \ copy_type_e_io(name, e, tof, type, Cat2(__ext_, type), copy) /* * master function instantiator */ #define copy_type(name, version, type, copy) \ copy_type_e(Cat3(name, L, version), L, type, copy) \ copy_type_e(Cat3(name, M, version), M, type, copy) /* * scalar copying */ #define copy_scalar_tom(type) *to = Cat2(__load_, type)(*from); #define copy_scalar_tof(type) Cat2(__store_, type)(*to, *from); /* * structure member copying */ #define copy_tom(mb, type) to->mb = Cat2(__load_, type)(from->mb); #define copy_tof(mb, type) Cat2(__store_, type)(to->mb, from->mb); /* * structure member copying (direction independent) */ #define copy_byte(e, io, mb) to->mb = from->mb; #define copy_addr(e, io, mb) Ex2(copy_, io, mb, u64, e) #define copy_half(e, io, mb) Ex2(copy_, io, mb, u16, e) #define copy_off(e, io, mb) Ex2(copy_, io, mb, u64, e) #define copy_sword(e, io, mb) Ex2(copy_, io, mb, i32, e) #define copy_word(e, io, mb) Ex2(copy_, io, mb, u32, e) #define copy_sxword(e, io, mb) Ex2(copy_, io, mb, i64, e) #define copy_xword(e, io, mb) Ex2(copy_, io, mb, u64, e) #define copy_arr(e, io, mb) \ array_copy(to->mb, sizeof(to->mb), from->mb, sizeof(from->mb)); /* * scalar copying (direction independent) * these macros are used as `copy' arguments to copy_type() */ #define copy_addr_11(e, io, seq) Ex1(copy_scalar_, io, u64, e) #define copy_half_11(e, io, seq) Ex1(copy_scalar_, io, u16, e) #define copy_off_11(e, io, seq) Ex1(copy_scalar_, io, u64, e) #define copy_sword_11(e, io, seq) Ex1(copy_scalar_, io, i32, e) #define copy_word_11(e, io, seq) Ex1(copy_scalar_, io, u32, e) #define copy_sxword_11(e, io, seq) Ex1(copy_scalar_, io, i64, e) #define copy_xword_11(e, io, seq) Ex1(copy_scalar_, io, u64, e) /* * structure copying (direction independent) * these macros are used as `copy' arguments to copy_type() */ #define copy_dyn_11(e, io, seq) \ seq(copy_xword(e, io, d_tag), \ seq(copy_addr(e, io, d_un.d_ptr), nullcopy)) #define copy_ehdr_11(e, io, seq) \ seq(copy_arr(e, io, e_ident), \ seq(copy_half(e, io, e_type), \ seq(copy_half(e, io, e_machine), \ seq(copy_word(e, io, e_version), \ seq(copy_addr(e, io, e_entry), \ seq(copy_off(e, io, e_phoff), \ seq(copy_off(e, io, e_shoff), \ seq(copy_word(e, io, e_flags), \ seq(copy_half(e, io, e_ehsize), \ seq(copy_half(e, io, e_phentsize), \ seq(copy_half(e, io, e_phnum), \ seq(copy_half( \ e, io, \ e_shentsize), \ seq(copy_half( \ e, io, e_shnum), \ seq(copy_half( \ e, io, \ e_shstrndx), \ nullcopy)))))))))))))) #define copy_phdr_11(e, io, seq) \ seq(copy_word(e, io, p_type), \ seq(copy_word(e, io, p_flags), \ seq(copy_off(e, io, p_offset), \ seq(copy_addr(e, io, p_vaddr), \ seq(copy_addr(e, io, p_paddr), \ seq(copy_xword(e, io, p_filesz), \ seq(copy_xword(e, io, p_memsz), \ seq(copy_xword(e, io, p_align), \ nullcopy)))))))) #if __LIBELF64_IRIX #define copy_rela_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), \ seq(copy_word(e, io, r_sym), \ seq(copy_byte(e, io, r_ssym), \ seq(copy_byte(e, io, r_type3), \ seq(copy_byte(e, io, r_type2), \ seq(copy_byte(e, io, r_type), \ seq(copy_sxword(e, io, r_addend), \ nullcopy))))))) #define copy_rel_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), \ seq(copy_word(e, io, r_sym), \ seq(copy_byte(e, io, r_ssym), \ seq(copy_byte(e, io, r_type3), \ seq(copy_byte(e, io, r_type2), \ seq(copy_byte(e, io, r_type), nullcopy)))))) #else /* __LIBELF64_IRIX */ #define copy_rela_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), \ seq(copy_xword(e, io, r_info), \ seq(copy_sxword(e, io, r_addend), nullcopy))) #define copy_rel_11(e, io, seq) \ seq(copy_addr(e, io, r_offset), \ seq(copy_xword(e, io, r_info), nullcopy)) #endif /* __LIBELF64_IRIX */ #define copy_shdr_11(e, io, seq) \ seq(copy_word(e, io, sh_name), \ seq(copy_word(e, io, sh_type), \ seq(copy_xword(e, io, sh_flags), \ seq(copy_addr(e, io, sh_addr), \ seq(copy_off(e, io, sh_offset), \ seq(copy_xword(e, io, sh_size), \ seq(copy_word(e, io, sh_link), \ seq(copy_word(e, io, sh_info), \ seq(copy_xword(e, io, sh_addralign), \ seq(copy_xword(e, io, sh_entsize), \ nullcopy)))))))))) #define copy_sym_11(e, io, seq) \ seq(copy_word(e, io, st_name), \ seq(copy_byte(e, io, st_info), \ seq(copy_byte(e, io, st_other), \ seq(copy_half(e, io, st_shndx), \ seq(copy_addr(e, io, st_value), \ seq(copy_xword(e, io, st_size), nullcopy)))))) #define nullcopy /**/ static size_t byte_copy(unsigned char *dst, const unsigned char *src, size_t n) { if (n && dst && dst != src) { #if HAVE_BROKEN_MEMMOVE size_t i; if (dst >= src + n || dst + n <= src) { memcpy(dst, src, n); } else if (dst < src) { for (i = 0; i < n; i++) { dst[i] = src[i]; } } else { for (i = n; --i;) { dst[i] = src[i]; } } #else /* HAVE_BROKEN_MEMMOVE */ memmove(dst, src, n); #endif /* HAVE_BROKEN_MEMMOVE */ } return n; } static void array_copy( unsigned char *dst, size_t dlen, const unsigned char *src, size_t slen) { byte_copy(dst, src, dlen < slen ? dlen : slen); if (dlen > slen) { memset(dst + slen, 0, dlen - slen); } } /* * instantiate copy functions */ copy_type(addr_64, _, Elf64_Addr, copy_addr_11) copy_type( half_64, _, Elf64_Half, copy_half_11) copy_type(off_64, _, Elf64_Off, copy_off_11) copy_type(sword_64, _, Elf64_Sword, copy_sword_11) copy_type( word_64, _, Elf64_Word, copy_word_11) copy_type(sxword_64, _, Elf64_Sxword, copy_sxword_11) copy_type(xword_64, _, Elf64_Xword, copy_xword_11) copy_type(dyn_64, 11, Elf64_Dyn, copy_dyn_11) copy_type(ehdr_64, 11, Elf64_Ehdr, copy_ehdr_11) copy_type(phdr_64, 11, Elf64_Phdr, copy_phdr_11) copy_type(rela_64, 11, Elf64_Rela, copy_rela_11) copy_type(rel_64, 11, Elf64_Rel, copy_rel_11) copy_type(shdr_64, 11, Elf64_Shdr, copy_shdr_11) copy_type(sym_64, 11, Elf64_Sym, copy_sym_11) typedef size_t (*xlator)( unsigned char *, const unsigned char *, size_t); typedef xlator xltab[ELF_T_NUM][2]; /* * translation table (64-bit, version 1 -> version 1) */ #if PIC static xltab #else /* PIC */ static const xltab #endif /* PIC */ xlate64_11[/*encoding*/] = { { { byte_copy, byte_copy }, { addr_64L__tom, addr_64L__tof }, { dyn_64L11_tom, dyn_64L11_tof }, { ehdr_64L11_tom, ehdr_64L11_tof }, { half_64L__tom, half_64L__tof }, { off_64L__tom, off_64L__tof }, { phdr_64L11_tom, phdr_64L11_tof }, { rela_64L11_tom, rela_64L11_tof }, { rel_64L11_tom, rel_64L11_tof }, { shdr_64L11_tom, shdr_64L11_tof }, { sword_64L__tom, sword_64L__tof }, { sym_64L11_tom, sym_64L11_tof }, { word_64L__tom, word_64L__tof }, { sxword_64L__tom, sxword_64L__tof }, { xword_64L__tom, xword_64L__tof }, #if __LIBELF_SYMBOL_VERSIONS { _elf_verdef_64L11_tom, _elf_verdef_64L11_tof }, { _elf_verneed_64L11_tom, _elf_verneed_64L11_tof }, #else /* __LIBELF_SYMBOL_VERSIONS */ { 0, 0 }, { 0, 0 }, #endif /* __LIBELF_SYMBOL_VERSIONS */ }, { { byte_copy, byte_copy }, { addr_64M__tom, addr_64M__tof }, { dyn_64M11_tom, dyn_64M11_tof }, { ehdr_64M11_tom, ehdr_64M11_tof }, { half_64M__tom, half_64M__tof }, { off_64M__tom, off_64M__tof }, { phdr_64M11_tom, phdr_64M11_tof }, { rela_64M11_tom, rela_64M11_tof }, { rel_64M11_tom, rel_64M11_tof }, { shdr_64M11_tom, shdr_64M11_tof }, { sword_64M__tom, sword_64M__tof }, { sym_64M11_tom, sym_64M11_tof }, { word_64M__tom, word_64M__tof }, { sxword_64M__tom, sxword_64M__tof }, { xword_64M__tom, xword_64M__tof }, #if __LIBELF_SYMBOL_VERSIONS { _elf_verdef_64M11_tom, _elf_verdef_64M11_tof }, { _elf_verneed_64M11_tom, _elf_verneed_64M11_tof }, #else /* __LIBELF_SYMBOL_VERSIONS */ { 0, 0 }, { 0, 0 }, #endif /* __LIBELF_SYMBOL_VERSIONS */ }, }; /* * main translation table (64-bit) */ #if PIC static xltab * #else /* PIC */ static const xltab *const #endif /* PIC */ xlate64[EV_CURRENT - EV_NONE][EV_CURRENT - EV_NONE] = { { xlate64_11, }, }; #define translator(sv, dv, enc, type, d) \ (xlate64[(sv)-EV_NONE - 1][(dv)-EV_NONE - 1][(enc)-ELFDATA2LSB] \ [(type)-ELF_T_BYTE][d]) /* * destination buffer size */ size_t _elf64_xltsize(const Elf_Data *src, unsigned dv, unsigned encode, int tof) { Elf_Type type = src->d_type; unsigned sv = src->d_version; xlator op; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return (size_t)-1; } if (tof) { /* * Encoding doesn't really matter (the translator only looks at * the source, which resides in memory), but we need a proper * encoding to select a translator... */ encode = ELFDATA2LSB; } else if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return (size_t)-1; } if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } if (!(op = translator(sv, dv, encode, type, tof))) { seterr(ERROR_UNKNOWN_TYPE); return (size_t)-1; } return (*op)(NULL, src->d_buf, src->d_size); } /* * direction-independent translation */ static Elf_Data * elf64_xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) { Elf_Type type; int dv; int sv; size_t dsize; size_t tmp; xlator op; if (!src || !dst) { return NULL; } if (!src->d_buf || !dst->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (!valid_encoding(encode)) { seterr(ERROR_UNKNOWN_ENCODING); return NULL; } sv = src->d_version; dv = dst->d_version; if (!valid_version(sv) || !valid_version(dv)) { seterr(ERROR_UNKNOWN_VERSION); return NULL; } type = src->d_type; if (!valid_type(type)) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } op = translator(sv, dv, encode, type, tof); if (!op) { seterr(ERROR_UNKNOWN_TYPE); return NULL; } dsize = (*op)(NULL, src->d_buf, src->d_size); if (dsize == (size_t)-1) { return NULL; } if (dst->d_size < dsize) { seterr(ERROR_DST2SMALL); return NULL; } if (dsize) { tmp = (*op)(dst->d_buf, src->d_buf, src->d_size); if (tmp == (size_t)-1) { return NULL; } elf_assert(tmp == dsize); } dst->d_size = dsize; dst->d_type = type; return dst; } /* * finally, the "official" translation functions */ Elf_Data *elf64_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return elf64_xlate(dst, src, encode, 0); } Elf_Data *elf64_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return elf64_xlate(dst, src, encode, 1); } Elf_Data * gelf_xlatetom(Elf *elf, Elf_Data *dst, const Elf_Data *src, unsigned encode) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class == ELFCLASS32) { return elf32_xlatetom(dst, src, encode); } else if (elf->e_class == ELFCLASS64) { return elf64_xlatetom(dst, src, encode); } else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } } return NULL; } Elf_Data * gelf_xlatetof(Elf *elf, Elf_Data *dst, const Elf_Data *src, unsigned encode) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class == ELFCLASS32) { return elf32_xlatetof(dst, src, encode); } else if (elf->e_class == ELFCLASS64) { return elf64_xlatetof(dst, src, encode); } else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } } return NULL; } #endif /* __LIBELF64__ */ qtrvsim-0.9.8/external/libelf/CMakeLists.txt000066400000000000000000000032141467752164200210720ustar00rootroot00000000000000project(libelf) set(libelf_SOURCES 32.fsize.c 32.getehdr.c 32.getphdr.c 32.getshdr.c 32.newehdr.c 32.newphdr.c 32.xlatetof.c 64.xlatetof.c assert.c begin.c checksum.c cntl.c cook.c data.c end.c errmsg.c errno.c fill.c flag.c gelfehdr.c gelfphdr.c gelfshdr.c gelftrans.c getarhdr.c getaroff.c getarsym.c getbase.c getdata.c getident.c getscn.c hash.c input.c kind.c ndxscn.c newdata.c newscn.c next.c nextscn.c nlist.c opt.delscn.c rand.c rawdata.c rawfile.c strptr.c swap64.c update.c verdef_32_tof.c verdef_32_tom.c verdef_64_tof.c verdef_64_tom.c version.c x.elfext.c x.movscn.c x.remscn.c ) set(libelf_HEADERS config.h byteswap.h elf_repl.h errors.h ext_types.h gelf.h libelf.h nlist.h private.h verdef.h verneed.h sys_elf.h ) add_library(libelf STATIC ${libelf_HEADERS} ${libelf_SOURCES}) # This is 3rd party code, I do not intend to fix it. target_compile_options(libelf PRIVATE -w) target_include_directories(libelf PUBLIC .) target_compile_definitions(libelf PUBLIC __LIBELF_INTERNAL__) target_compile_definitions(libelf PUBLIC HAVE_CONFIG_H=1) set_target_properties(libelf PROPERTIES LINKER_LANGUAGE C) qtrvsim-0.9.8/external/libelf/Makefile.in000066400000000000000000000175141467752164200204070ustar00rootroot00000000000000# lib/Makefile for libelf. # Copyright (C) 1995 - 2009 Michael Riepe # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # @(#) $Id: Makefile.in,v 1.40 2009/11/01 13:04:19 michael Exp $ instroot = prefix = @prefix@ exec_prefix = @exec_prefix@ libdir = @libdir@ includedir = @includedir@ installdirs = $(libdir) $(includedir) $(includedir)/libelf CC = @CC@ LD = @LD@ AR = ar MV = mv -f RM = rm -f LN_S = @LN_S@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ DEFS = -DHAVE_CONFIG_H LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ DEPSHLIBS = @DEPSHLIBS@ DO_SHLIB = @DO_SHLIB@ PICFLAGS = @PICFLAGS@ SHLIB_SFX = @SHLIB_SFX@ SHLINK_SFX = @SHLINK_SFX@ SONAME_SFX = @SONAME_SFX@ LINK_SHLIB = @LINK_SHLIB@ INSTALL_SHLIB = @INSTALL_SHLIB@ SHLIB = libelf$(SHLIB_SFX) SHLINK = libelf$(SHLINK_SFX) SONAME = libelf$(SONAME_SFX) # install includes in includedir? DO_COMPAT = @DO_COMPAT@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) # no user serviceable parts below PACKAGE = @PACKAGE@ VERSION = @VERSION@ MAJOR = @MAJOR@ SHELL = /bin/sh @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ topdir = .. subdir = lib .SUFFIXES: .SUFFIXES: .c .o .c.o: @$(RM) $@ $(@:.o=.os) if test -n "$(PICFLAGS)"; then \ $(COMPILE) $(PICFLAGS) $< && $(MV) $@ $(@:.o=.os); \ else true; fi $(COMPILE) $< INCLUDES = -I$(topdir) -I. -I$(srcdir) # generic sources SRCS1 = begin.c cntl.c end.c errmsg.c errno.c fill.c flag.c getarhdr.c \ getarsym.c getbase.c getdata.c getident.c getscn.c hash.c kind.c \ ndxscn.c newdata.c newscn.c next.c nextscn.c rand.c rawdata.c \ rawfile.c strptr.c update.c version.c checksum.c getaroff.c OBJS1 = begin.o cntl.o end.o errmsg.o errno.o fill.o flag.o getarhdr.o \ getarsym.o getbase.o getdata.o getident.o getscn.o hash.o kind.o \ ndxscn.o newdata.o newscn.o next.o nextscn.o rand.o rawdata.o \ rawfile.o strptr.o update.o version.o checksum.o getaroff.o # 32-bit sources SRCS2 = 32.fsize.c 32.getehdr.c 32.getphdr.c 32.getshdr.c 32.newehdr.c \ 32.newphdr.c 32.xlatetof.c OBJS2 = 32.fsize.o 32.getehdr.o 32.getphdr.o 32.getshdr.o 32.newehdr.o \ 32.newphdr.o 32.xlatetof.o # support SRCS3 = cook.c data.c input.c assert.c OBJS3 = cook.o data.o input.o assert.o # nlist SRCS4 = nlist.c OBJS4 = nlist.o # opt SRCS5 = opt.delscn.c x.remscn.c x.movscn.c x.elfext.c OBJS5 = opt.delscn.o x.remscn.o x.movscn.o x.elfext.o # 64-bit sources SRCS64 = 64.xlatetof.c gelfehdr.c gelfphdr.c gelfshdr.c gelftrans.c swap64.c OBJS64 = 64.xlatetof.o gelfehdr.o gelfphdr.o gelfshdr.o gelftrans.o swap64.o # Versioning sources SRCS_V = verdef_32_tof.c verdef_32_tom.c verdef_64_tof.c verdef_64_tom.c OBJS_V = verdef_32_tof.o verdef_32_tom.o verdef_64_tof.o verdef_64_tom.o HDRS_V = verdef.h verneed.h SRCS = $(SRCS1) $(SRCS2) $(SRCS3) $(SRCS4) $(SRCS5) $(SRCS64) $(SRCS_V) OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS64) $(OBJS_V) # missing functions LIBSRCS = memset.c LIBOBJS = @LIBOBJS@ # public header files HDRS = libelf.h nlist.h gelf.h # public header files (created by configure) AUXHDRS = sys_elf.h # private header files PRIVHDRS = byteswap.h errors.h ext_types.h private.h elf_repl.h \ $(HDRS_V) DISTFILES = $(SRCS) $(LIBSRCS) $(HDRS) $(PRIVHDRS) Makefile.in sys_elf.h.in \ Makefile.w32 build.bat config.h.w32 libelf.def sys_elf.h.w32 all: libelf.a shared-$(DO_SHLIB) check: shared-yes: $(SHLIB) shared-no: libelf.a: $(OBJS) $(LIBOBJS) @$(RM) $@ $(AR) rcv $@ $(OBJS) $(LIBOBJS) $(RANLIB) $@ $(SHLIB): libelf.a @$(RM) $(SHLIB) $(LINK_SHLIB) -o $(SHLIB) $(OBJS:.o=.os) $(LIBOBJS:.o=.os) $(DEPSHLIBS) if test "$(SONAME)" = "$(SHLIB)"; then true; else \ $(RM) $(SONAME) && $(LN_S) $(SHLIB) $(SONAME); \ fi if test "$(SHLINK)" = "$(SHLIB)"; then true; else \ $(RM) $(SHLINK) && $(LN_S) $(SHLIB) $(SHLINK); \ fi install: install-data \ install-shared-$(DO_SHLIB) install-compat-$(DO_COMPAT) installdirs: $(top_srcdir)/mkinstalldirs dirs="$(installdirs)"; for dir in $$dirs; do \ $(SHELL) $(top_srcdir)/mkinstalldirs $(instroot)$$dir; \ done install-data: all installdirs $(INSTALL_DATA) libelf.a $(instroot)$(libdir) -cd $(instroot)$(libdir) && $(RANLIB) libelf.a files="$(HDRS) $(AUXHDRS) elf_repl.h"; for file in $$files; do \ if test -r $$file; then \ $(INSTALL_DATA) $$file $(instroot)$(includedir)/libelf; \ else \ $(INSTALL_DATA) $(srcdir)/$$file $(instroot)$(includedir)/libelf; \ fi; \ done uninstall: uninstall-data \ uninstall-shared-$(DO_SHLIB) uninstall-compat-$(DO_COMPAT) uninstall-data: $(RM) $(instroot)$(libdir)/libelf.a $(RM) -r $(instroot)$(includedir)/libelf install-shared-yes: install-shared install-shared-no: install-shared: installdirs $(SHLIB) $(INSTALL_SHLIB) $(SHLIB) $(instroot)$(libdir) if test "$(SONAME)" = "$(SHLIB)"; then true; else \ cd $(instroot)$(libdir) && $(RM) $(SONAME) && $(LN_S) $(SHLIB) $(SONAME); \ fi if test "$(SHLINK)" = "$(SHLIB)"; then true; else \ cd $(instroot)$(libdir) && $(RM) $(SHLINK) && $(LN_S) $(SHLIB) $(SHLINK); \ fi uninstall-shared-yes: uninstall-shared uninstall-shared-no: uninstall-shared: cd $(instroot)$(libdir) && $(RM) $(SHLIB) $(SONAME) $(SHLINK) install-compat-yes: install-compat install-compat-no: install-compat: installdirs files="$(HDRS)"; for file in $$files; do \ if test -f $(instroot)$(includedir)/$$file; then true; else \ echo "#include " > $(instroot)$(includedir)/$$file; \ fi; \ done uninstall-compat-yes: uninstall-compat uninstall-compat-no: uninstall-compat: files="$(HDRS)"; for file in $$files; do \ if grep "^#include \$$" $(instroot)$(includedir)/$$file >/dev/null 2>&1; then \ $(RM) $(instroot)$(includedir)/$$file; \ else true; fi; \ done mostlyclean: $(RM) *.o *.a *.os $(SHLIB) $(SONAME) $(SHLINK) $(RM) *~ core a.out errlist clean: mostlyclean distclean: clean $(RM) stamp-h $(AUXHDRS) $(RM) Makefile maintainer-clean: distclean # maintainer only MAINT = @MAINT@ distdir = $(PACKAGE)-$(VERSION) distsubdir = $(topdir)/$(distdir)/$(subdir) $(MAINT)dist: $(DISTFILES) if test -d $(distsubdir); then true; else mkdir $(distsubdir); fi files="$(DISTFILES)"; for file in $$files; do \ ln $(srcdir)/$$file $(distsubdir) || \ cp -p $(srcdir)/$$file $(distsubdir) || exit 1; \ done # For the justification of the following Makefile rules, see node # `Automatic Remaking' in GNU Autoconf documentation. $(MAINT)Makefile: Makefile.in $(topdir)/config.status cd $(topdir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status $(MAINT)sys_elf.h: stamp-h $(MAINT)stamp-h: sys_elf.h.in $(topdir)/config.status cd $(topdir) && CONFIG_FILES= CONFIG_HEADERS=$(subdir)/sys_elf.h ./config.status $(RM) stamp-h && echo timestamp > stamp-h # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # dependencies $(OBJS): private.h $(topdir)/config.h libelf.h gelf.h errors.h $(AUXHDRS) 32.fsize.o: ext_types.h 32.xlatetof.o: byteswap.h ext_types.h 64.xlatetof.o: byteswap.h ext_types.h getarsym.o: byteswap.h memset.o: $(topdir)/config.h nlist.o: nlist.h swap64.o: byteswap.h $(OBJS_V): byteswap.h ext_types.h $(HDRS_V) qtrvsim-0.9.8/external/libelf/Makefile.w32000066400000000000000000000074041467752164200204110ustar00rootroot00000000000000# lib/Makefile.w32 - Makefile for W32 port. # Copyright (C) 1995 - 2009 Michael Riepe # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # @(#) $Id: Makefile.w32,v 1.3 2009/11/01 13:04:19 michael Exp $ instroot = prefix = exec_prefix = libdir = includedir = installdirs = $(libdir) $(includedir) $(includedir)/libelf CC = cl /nologo LD = link /nologo AR = MV = RM = del LN_S = RANLIB = INSTALL = INSTALL_DATA = INSTALL_PROGRAM = CFLAGS = /O2 /W2 /TC /MD CPPFLAGS = DEFS = /DHAVE_CONFIG_H LDFLAGS = LIBS = DEPSHLIBS = DO_SHLIB = PICFLAGS = SHLIB_SFX = .dll SHLINK_SFX = SONAME_SFX = LINK_SHLIB = $(LD) /DLL $(LDFLAGS) SHLIB = libelf$(SHLIB_SFX) SHLINK = libelf$(SHLINK_SFX) SONAME = libelf$(SONAME_SFX) # install includes in includedir? DO_COMPAT = INCLUDES = /I. COMPILE = $(CC) /c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) # no user serviceable parts below PACKAGE = libelf VERSION = 0.8.9 MAJOR = 0 SHELL = /bin/sh srcdir = . top_srcdir = .. topdir = .. subdir = lib .SUFFIXES: .SUFFIXES: .obj .c .c.obj: $(COMPILE) $< # generic sources SRCS1 = begin.c cntl.c end.c errmsg.c errno.c fill.c flag.c getarhdr.c \ getarsym.c getbase.c getdata.c getident.c getscn.c hash.c kind.c \ ndxscn.c newdata.c newscn.c next.c nextscn.c rand.c rawdata.c \ rawfile.c strptr.c update.c version.c checksum.c getaroff.c OBJS1 = $(SRCS1:.c=.obj) # 32-bit sources SRCS2 = 32.fsize.c 32.getehdr.c 32.getphdr.c 32.getshdr.c 32.newehdr.c \ 32.newphdr.c 32.xlatetof.c OBJS2 = $(SRCS2:.c=.obj) # support SRCS3 = cook.c data.c input.c assert.c OBJS3 = $(SRCS3:.c=.obj) # nlist SRCS4 = nlist.c OBJS4 = $(SRCS4:.c=.obj) # opt SRCS5 = opt.delscn.c x.remscn.c x.movscn.c x.elfext.c OBJS5 = $(SRCS5:.c=.obj) # 64-bit sources SRCS64 = 64.xlatetof.c gelfehdr.c gelfphdr.c gelfshdr.c gelftrans.c swap64.c OBJS64 = $(SRCS64:.c=.obj) # Versioning sources SRCS_V = verdef_32_tof.c verdef_32_tom.c verdef_64_tof.c verdef_64_tom.c OBJS_V = $(SRCS_V:.c=.obj) HDRS_V = verdef.h verneed.h SRCS = $(SRCS1) $(SRCS2) $(SRCS3) $(SRCS4) $(SRCS5) $(SRCS64) $(SRCS_V) OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS64) $(OBJS_V) # missing functions LIBSRCS = memset.c LIBOBJS = # public header files HDRS = libelf.h nlist.h gelf.h # public header files (created by configure) AUXHDRS = sys_elf.h # private header files PRIVHDRS = byteswap.h errors.h ext_types.h private.h elf_repl.h $(HDRS_V) DISTFILES = $(SRCS) $(LIBSRCS) $(HDRS) $(PRIVHDRS) Makefile.in sys_elf.h.in all: $(OBJS) $(SHLIB) check: $(SHLIB): libelf.def $(OBJS) $(LIBOBJS) -@$(RM) $(SHLIB) $(LINK_SHLIB) /OUT:"$(SHLIB)" /DEF:"libelf.def" $(OBJS) $(LIBOBJS) kernel32.lib install: mostlyclean: -$(RM) *.obj -$(RM) $(SHLIB) -$(RM) libelf.lib -$(RM) libelf.exp clean: mostlyclean distclean: clean -$(RM) $(AUXHDRS) maintainer-clean: distclean # dependencies $(OBJS): private.h config.h libelf.h gelf.h errors.h $(AUXHDRS) 32.fsize.obj: ext_types.h 32.xlatetof.obj: byteswap.h ext_types.h 64.xlatetof.obj: byteswap.h ext_types.h getarsym.obj: byteswap.h memset.obj: config.h nlist.obj: nlist.h swap64.obj: byteswap.h $(OBJS_V): byteswap.h ext_types.h $(HDRS_V) qtrvsim-0.9.8/external/libelf/assert.c000066400000000000000000000021361467752164200200010ustar00rootroot00000000000000/* assert.c - assert function for libelf. Copyright (C) 1999 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: assert.c,v 1.5 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #include void __elf_assert(const char *file, unsigned line, const char *cond) { fprintf(stderr, "%s:%u: libelf assertion failure: %s\n", file, line, cond); abort(); } qtrvsim-0.9.8/external/libelf/begin.c000066400000000000000000000275021467752164200175700ustar00rootroot00000000000000/* * begin.c - implementation of the elf_begin(3) and elf_memory(3) functions. * Copyright (C) 1995 - 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: begin.c,v 1.22 2009/11/01 13:04:19 michael Exp $"; #endif /* lint */ static const Elf _elf_init = INIT_ELF; static const char fmag[] = ARFMAG; static unsigned long getnum(const char *str, size_t len, int base, size_t *err) { unsigned long result = 0; while (len && *str == ' ') { str++; len--; } while (len && *str >= '0' && (*str - '0') < base) { result = base * result + *str++ - '0'; len--; } while (len && *str == ' ') { str++; len--; } if (len) { *err = len; } return result; } static void _elf_init_ar(Elf *elf) { struct ar_hdr *hdr; size_t offset; size_t size; size_t err = 0; elf->e_kind = ELF_K_AR; elf->e_idlen = SARMAG; elf->e_off = SARMAG; /* process special members */ offset = SARMAG; while (!elf->e_strtab && offset + sizeof(*hdr) <= elf->e_size) { hdr = (struct ar_hdr *)(elf->e_data + offset); if (memcmp(hdr->ar_fmag, fmag, sizeof(fmag) - 1)) { break; } if (hdr->ar_name[0] != '/') { break; } size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10, &err); if (err || !size) { break; } offset += sizeof(*hdr); if (offset + size > elf->e_size) { break; } if (hdr->ar_name[1] == '/' && hdr->ar_name[2] == ' ') { elf->e_strtab = elf->e_data + offset; elf->e_strlen = size; break; } if (hdr->ar_name[1] != ' ') { break; } /* * Windows (.lib) archives provide two symbol tables * The first one is the one we want. */ if (!elf->e_symtab) { elf->e_symtab = elf->e_data + offset; elf->e_symlen = size; } offset += size + (size & 1); } } static Elf_Arhdr *_elf_arhdr(Elf *arf) { struct ar_hdr *hdr; Elf_Arhdr *arhdr; size_t namelen; size_t tmp; char *name; size_t err = 0; if (arf->e_off == arf->e_size) { /* no error! */ return NULL; } if (arf->e_off < 0 || arf->e_off > arf->e_size) { seterr(ERROR_OUTSIDE); return NULL; } if (arf->e_off + sizeof(*hdr) > arf->e_size) { seterr(ERROR_TRUNC_ARHDR); return NULL; } elf_assert(arf->e_data != NULL); hdr = (struct ar_hdr *)(arf->e_data + arf->e_off); if (memcmp(hdr->ar_fmag, fmag, sizeof(fmag) - 1)) { seterr(ERROR_ARFMAG); return NULL; } name = hdr->ar_name; for (namelen = sizeof(hdr->ar_name); namelen > 0; namelen--) { if (name[namelen - 1] != ' ') { break; } } if (name[0] == '/') { if (name[1] >= '0' && name[1] <= '9') { if (!arf->e_strtab) { seterr(ERROR_ARSTRTAB); return NULL; } tmp = getnum(&name[1], namelen - 1, 10, &err); if (err) { seterr(ERROR_ARSPECIAL); return NULL; } if (tmp < 0 || tmp >= arf->e_strlen) { seterr(ERROR_ARSTRTAB); return NULL; } for (namelen = tmp; namelen < arf->e_strlen; namelen++) { if (arf->e_strtab[namelen] == '/') { break; } } if (namelen == arf->e_strlen) { seterr(ERROR_ARSTRTAB); return NULL; } name = arf->e_strtab + tmp; namelen -= tmp; } else if (namelen != 1 && !(namelen == 2 && name[1] == '/')) { seterr(ERROR_ARSPECIAL); return NULL; } } else if (namelen > 0 && name[namelen - 1] == '/') { namelen--; } /* XXX some broken software omits the trailing slash else { namelen = 0; } */ if (!(arhdr = (Elf_Arhdr *)malloc( sizeof(*arhdr) + sizeof(hdr->ar_name) + namelen + 2))) { seterr(ERROR_MEM_ARHDR); return NULL; } arhdr->ar_name = NULL; arhdr->ar_rawname = (char *)(arhdr + 1); arhdr->ar_date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10, &err); arhdr->ar_uid = getnum(hdr->ar_uid, sizeof(hdr->ar_uid), 10, &err); arhdr->ar_gid = getnum(hdr->ar_gid, sizeof(hdr->ar_gid), 10, &err); arhdr->ar_mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8, &err); arhdr->ar_size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10, &err); if (err) { free(arhdr); seterr(ERROR_ARHDR); return NULL; } if (arf->e_off + sizeof(struct ar_hdr) + arhdr->ar_size > arf->e_size) { free(arhdr); seterr(ERROR_TRUNC_MEMBER); return NULL; } memcpy(arhdr->ar_rawname, hdr->ar_name, sizeof(hdr->ar_name)); arhdr->ar_rawname[sizeof(hdr->ar_name)] = '\0'; if (namelen) { arhdr->ar_name = arhdr->ar_rawname + sizeof(hdr->ar_name) + 1; memcpy(arhdr->ar_name, name, namelen); arhdr->ar_name[namelen] = '\0'; } return arhdr; } static void _elf_check_type(Elf *elf, size_t size) { elf->e_idlen = size; if (size >= EI_NIDENT && !memcmp(elf->e_data, ELFMAG, SELFMAG)) { elf->e_kind = ELF_K_ELF; elf->e_idlen = EI_NIDENT; elf->e_class = elf->e_data[EI_CLASS]; elf->e_encoding = elf->e_data[EI_DATA]; elf->e_version = elf->e_data[EI_VERSION]; } else if (size >= SARMAG && !memcmp(elf->e_data, ARMAG, SARMAG)) { _elf_init_ar(elf); } } Elf *elf_begin(int fd, Elf_Cmd cmd, Elf *ref) { Elf_Arhdr *arhdr = NULL; size_t size = 0; off_t off; Elf *elf; elf_assert(_elf_init.e_magic == ELF_MAGIC); if (_elf_version == EV_NONE) { seterr(ERROR_VERSION_UNSET); return NULL; } else if (cmd == ELF_C_NULL) { return NULL; } else if (cmd == ELF_C_WRITE) { ref = NULL; } else if (cmd != ELF_C_READ && cmd != ELF_C_RDWR) { seterr(ERROR_INVALID_CMD); return NULL; } else if (ref) { elf_assert(ref->e_magic == ELF_MAGIC); if (!ref->e_readable || (cmd == ELF_C_RDWR && !ref->e_writable)) { seterr(ERROR_CMDMISMATCH); return NULL; } if (ref->e_kind != ELF_K_AR) { ref->e_count++; return ref; } if (cmd == ELF_C_RDWR) { seterr(ERROR_MEMBERWRITE); return NULL; } if (ref->e_memory) { fd = ref->e_fd; } else if (fd != ref->e_fd) { seterr(ERROR_FDMISMATCH); return NULL; } if (!(arhdr = _elf_arhdr(ref))) { return NULL; } size = arhdr->ar_size; } else if ( (off = lseek(fd, (off_t)0, SEEK_END)) == (off_t)-1 || (off_t)(size = off) != off) { seterr(ERROR_IO_GETSIZE); return NULL; } if (!(elf = (Elf *)malloc(sizeof(Elf)))) { seterr(ERROR_MEM_ELF); return NULL; } *elf = _elf_init; elf->e_fd = fd; elf->e_parent = ref; elf->e_size = elf->e_dsize = size; if (cmd != ELF_C_READ) { elf->e_writable = 1; } if (cmd != ELF_C_WRITE) { elf->e_readable = 1; } else { return elf; } if (ref) { size_t offset = ref->e_off + sizeof(struct ar_hdr); Elf *xelf; elf_assert(arhdr); elf->e_arhdr = arhdr; elf->e_base = ref->e_base + offset; /* * Share the archive's memory image. To avoid * multiple independent elf descriptors if the * same member is requested twice, scan the list * of open members for duplicates. * * I don't know how SVR4 handles this case. Don't rely on it. */ for (xelf = ref->e_members; xelf; xelf = xelf->e_link) { elf_assert(xelf->e_parent == ref); if (xelf->e_base == elf->e_base) { free(arhdr); free(elf); xelf->e_count++; return xelf; } } if (size == 0) { elf->e_data = NULL; } #if 1 else { /* * Archive members may be misaligned. Freezing them will * cause libelf to allocate buffers for translated data, * which should be properly aligned in all cases. */ elf_assert(!ref->e_cooked); elf->e_data = elf->e_rawdata = ref->e_data + offset; } #else else if (ref->e_data == ref->e_rawdata) { elf_assert(!ref->e_cooked); /* * archive is frozen - freeze member, too */ elf->e_data = elf->e_rawdata = ref->e_data + offset; } else { elf_assert(!ref->e_memory); elf->e_data = ref->e_data + offset; /* * The member's memory image may have been modified if * the member has been processed before. Since we need the * original image, we have to re-read the archive file. * Will fail if the archive's file descriptor is disabled. */ if (!ref->e_cooked) { ref->e_cooked = 1; } else if (!_elf_read(ref, elf->e_data, offset, size)) { free(arhdr); free(elf); return NULL; } } #endif elf->e_next = offset + size + (size & 1); elf->e_disabled = ref->e_disabled; elf->e_memory = ref->e_memory; /* parent/child linking */ elf->e_link = ref->e_members; ref->e_members = elf; ref->e_count++; /* Slowaris compatibility - do not rely on this! */ ref->e_off = elf->e_next; } else if (size) { #if HAVE_MMAP /* * Using mmap on writable files will interfere with elf_update */ if (!elf->e_writable && (elf->e_data = _elf_mmap(elf))) { elf->e_unmap_data = 1; } else #endif /* HAVE_MMAP */ if (!(elf->e_data = _elf_read(elf, NULL, 0, size))) { free(elf); return NULL; } } _elf_check_type(elf, size); return elf; } Elf *elf_memory(char *image, size_t size) { Elf *elf; elf_assert(_elf_init.e_magic == ELF_MAGIC); if (_elf_version == EV_NONE) { seterr(ERROR_VERSION_UNSET); return NULL; } else if (size == 0 || image == NULL) { /* TODO: set error code? */ return NULL; } if (!(elf = (Elf *)malloc(sizeof(Elf)))) { seterr(ERROR_MEM_ELF); return NULL; } *elf = _elf_init; elf->e_size = elf->e_dsize = size; elf->e_data = elf->e_rawdata = image; elf->e_readable = 1; elf->e_disabled = 1; elf->e_memory = 1; _elf_check_type(elf, size); return elf; } #if __LIBELF64 int gelf_getclass(Elf *elf) { if (elf && elf->e_kind == ELF_K_ELF && valid_class(elf->e_class)) { return elf->e_class; } return ELFCLASSNONE; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/build.bat000066400000000000000000000031611467752164200201220ustar00rootroot00000000000000@echo off rem lib/build.bat - build script for W32 port rem Copyright (C) 2004 - 2006 Michael Riepe rem rem This library is free software; you can redistribute it and/or rem modify it under the terms of the GNU Library General Public rem License as published by the Free Software Foundation; either rem version 2 of the License, or (at your option) any later version. rem rem This library is distributed in the hope that it will be useful, rem but WITHOUT ANY WARRANTY; without even the implied warranty of rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU rem Library General Public License for more details. rem rem You should have received a copy of the GNU Library General Public rem License along with this library; if not, write to the Free Software rem Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. rem @(#) $Id: build.bat,v 1.1 2006/08/21 18:03:48 michael Exp $ rem *** BEGIN EDIT HERE *** rem Please uncomment the line that suits your system: rem call "C:\Program Files\Microsoft Visual Studio\VC98\bin\vcvars32.bat" rem call "C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat" rem call "C:\Programme\Microsoft Visual Studio\VC98\bin\vcvars32.bat" rem call "C:\Programme\Microsoft Visual Studio 8\VC\bin\vcvars32.bat" rem OR, if you have to set the path to the compiler directly: rem set PATH="C:\PATH\TO\COMPILER\BINARY;%PATH%" rem Of course, you'll have to enter the correct path above. rem You may also have to change CC (default: cl.exe) in Makefile.w32. rem *** END EDIT HERE *** copy config.h.w32 config.h copy sys_elf.h.w32 sys_elf.h nmake /nologo /f Makefile.w32 %1 qtrvsim-0.9.8/external/libelf/byteswap.h000066400000000000000000000104741467752164200203470ustar00rootroot00000000000000/* byteswap.h - functions and macros for byte swapping. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: byteswap.h,v 1.7 2008/05/23 08:15:34 michael Exp $ */ #ifndef _BYTESWAP_H #define _BYTESWAP_H #include "config.h" #define lu(from, i, s) (((__libelf_u32_t)((unsigned char *)(from))[i]) << (s)) #define li(from, i, s) (((__libelf_i32_t)((signed char *)(from))[i]) << (s)) #define __load_u16L(from) ((__libelf_u32_t)(lu(from, 1, 8) | lu(from, 0, 0))) #define __load_u16M(from) ((__libelf_u32_t)(lu(from, 0, 8) | lu(from, 1, 0))) #define __load_i16L(from) ((__libelf_i32_t)(li(from, 1, 8) | lu(from, 0, 0))) #define __load_i16M(from) ((__libelf_i32_t)(li(from, 0, 8) | lu(from, 1, 0))) #define __load_u32L(from) \ ((__libelf_u32_t)( \ lu(from, 3, 24) | lu(from, 2, 16) | lu(from, 1, 8) | lu(from, 0, 0))) #define __load_u32M(from) \ ((__libelf_u32_t)( \ lu(from, 0, 24) | lu(from, 1, 16) | lu(from, 2, 8) | lu(from, 3, 0))) #define __load_i32L(from) \ ((__libelf_i32_t)( \ li(from, 3, 24) | lu(from, 2, 16) | lu(from, 1, 8) | lu(from, 0, 0))) #define __load_i32M(from) \ ((__libelf_i32_t)( \ li(from, 0, 24) | lu(from, 1, 16) | lu(from, 2, 8) | lu(from, 3, 0))) #define su(to, i, v, s) (((char *)(to))[i] = ((__libelf_u32_t)(v) >> (s))) #define si(to, i, v, s) (((char *)(to))[i] = ((__libelf_i32_t)(v) >> (s))) #define __store_u16L(to, v) (su(to, 1, v, 8), su(to, 0, v, 0)) #define __store_u16M(to, v) (su(to, 0, v, 8), su(to, 1, v, 0)) #define __store_i16L(to, v) (si(to, 1, v, 8), si(to, 0, v, 0)) #define __store_i16M(to, v) (si(to, 0, v, 8), si(to, 1, v, 0)) #define __store_u32L(to, v) \ (su(to, 3, v, 24), su(to, 2, v, 16), su(to, 1, v, 8), su(to, 0, v, 0)) #define __store_u32M(to, v) \ (su(to, 0, v, 24), su(to, 1, v, 16), su(to, 2, v, 8), su(to, 3, v, 0)) #define __store_i32L(to, v) \ (si(to, 3, v, 24), si(to, 2, v, 16), si(to, 1, v, 8), si(to, 0, v, 0)) #define __store_i32M(to, v) \ (si(to, 0, v, 24), si(to, 1, v, 16), si(to, 2, v, 8), si(to, 3, v, 0)) #if __LIBELF64 /* * conversion functions from swap64.c */ extern __libelf_u64_t _elf_load_u64L(const unsigned char *from); extern __libelf_u64_t _elf_load_u64M(const unsigned char *from); extern __libelf_i64_t _elf_load_i64L(const unsigned char *from); extern __libelf_i64_t _elf_load_i64M(const unsigned char *from); extern void _elf_store_u64L(unsigned char *to, __libelf_u64_t v); extern void _elf_store_u64M(unsigned char *to, __libelf_u64_t v); extern void _elf_store_i64L(unsigned char *to, __libelf_u64_t v); extern void _elf_store_i64M(unsigned char *to, __libelf_u64_t v); /* * aliases for existing conversion code */ #define __load_u64L _elf_load_u64L #define __load_u64M _elf_load_u64M #define __load_i64L _elf_load_i64L #define __load_i64M _elf_load_i64M #define __store_u64L _elf_store_u64L #define __store_u64M _elf_store_u64M #define __store_i64L _elf_store_i64L #define __store_i64M _elf_store_i64M #endif /* __LIBELF64 */ #endif /* _BYTESWAP_H */ qtrvsim-0.9.8/external/libelf/checksum.c000066400000000000000000000104101467752164200202740ustar00rootroot00000000000000/* checksum.c - implementation of the elf{32,64}_checksum(3) functions. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: checksum.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ /* * Compatibility note: * * The algorithm used in {elf32,elf64,gelf}_checksum() does not seem to * be documented. I hope I got it right. My implementation does the * following: * * - skip sections that do not have the SHF_ALLOC flag set * - skip sections of type SHT_NULL, SHT_NOBITS, SHT_DYNSYM and * SHT_DYNAMIC * - add all data bytes from the remaining sections, modulo 2**32 * - add upper and lower half of the result * - subtract 0xffff if the result is > 0xffff * - if any error occurs, return 0L */ static int skip_section(Elf_Scn *scn, unsigned cls) { if (cls == ELFCLASS32) { Elf32_Shdr *shdr = &scn->s_shdr32; if (!(shdr->sh_flags & SHF_ALLOC)) { return 1; } switch (shdr->sh_type) { case SHT_NULL: case SHT_NOBITS: /* Solaris seems to ignore these, too */ case SHT_DYNSYM: case SHT_DYNAMIC: return 1; } } #if __LIBELF64 else if (cls == ELFCLASS64) { Elf64_Shdr *shdr = &scn->s_shdr64; if (!(shdr->sh_flags & SHF_ALLOC)) { return 1; } switch (shdr->sh_type) { case SHT_NULL: case SHT_NOBITS: /* Solaris seems to ignore these, too */ case SHT_DYNSYM: case SHT_DYNAMIC: return 1; } } #endif /* __LIBELF64 */ else { seterr(ERROR_UNIMPLEMENTED); } return 0; } static long add_bytes(unsigned char *ptr, size_t len) { long csum = 0; while (len--) { csum += *ptr++; } return csum; } static long _elf_csum(Elf *elf) { long csum = 0; Elf_Data *data; Elf_Scn *scn; if (!elf->e_ehdr && !_elf_cook(elf)) { /* propagate errors from _elf_cook */ return 0L; } seterr(0); for (scn = elf->e_scn_1; scn; scn = scn->s_link) { if (scn->s_index == SHN_UNDEF || skip_section(scn, elf->e_class)) { continue; } data = NULL; while ((data = elf_getdata(scn, data))) { if (data->d_size) { if (data->d_buf == NULL) { seterr(ERROR_NULLBUF); return 0L; } csum += add_bytes(data->d_buf, data->d_size); } } } if (_elf_errno) { return 0L; } csum = (csum & 0xffff) + ((csum >> 16) & 0xffff); if (csum > 0xffff) { csum -= 0xffff; } return csum; } long elf32_checksum(Elf *elf) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class != ELFCLASS32) { seterr(ERROR_CLASSMISMATCH); } else { return _elf_csum(elf); } } return 0L; } #if __LIBELF64 long elf64_checksum(Elf *elf) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class != ELFCLASS64) { seterr(ERROR_CLASSMISMATCH); } else { return _elf_csum(elf); } } return 0L; } long gelf_checksum(Elf *elf) { if (elf) { if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); } else { return _elf_csum(elf); } } return 0L; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/cntl.c000066400000000000000000000040411467752164200174350ustar00rootroot00000000000000/* cntl.c - implementation of the elf_cntl(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: cntl.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ int elf_cntl(Elf *elf, Elf_Cmd cmd) { Elf_Scn *scn; Elf *child; if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (cmd == ELF_C_FDREAD) { if (!elf->e_readable) { seterr(ERROR_WRONLY); return -1; } } else if (cmd != ELF_C_FDDONE) { seterr(ERROR_INVALID_CMD); return -1; } if (elf->e_disabled) { return 0; } if (elf->e_kind == ELF_K_AR) { for (child = elf->e_members; child; child = child->e_link) { elf_assert(elf == child->e_parent); if (elf_cntl(child, cmd)) { return -1; } } } else if (elf->e_kind == ELF_K_ELF && cmd == ELF_C_FDREAD) { if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } for (scn = elf->e_scn_1; scn; scn = scn->s_link) { if (scn->s_index == SHN_UNDEF || scn->s_type == SHT_NULL) { continue; } else if (!elf_getdata(scn, NULL)) { return -1; } } } elf->e_disabled = 1; return 0; } qtrvsim-0.9.8/external/libelf/config.default.h000066400000000000000000000147121467752164200214000ustar00rootroot00000000000000#include /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* * acconfig.h - Special definitions for libelf, processed by autoheader. * Copyright (C) 1995 - 2001, 2004, 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: acconfig.h,v 1.16 2008/05/23 08:17:56 michael Exp $ */ /* Define if you want to include extra debugging code */ /* #undef ENABLE_DEBUG */ /* Define if you want to support extended ELF formats */ /* #undef ENABLE_EXTENDED_FORMAT */ /* Define if you want ELF format sanity checks by default */ #define ENABLE_SANITY_CHECKS 1 /* Define if memmove() does not copy overlapping arrays correctly */ #define HAVE_BROKEN_MEMMOVE 1 /* Define if you have the catgets function. */ /* #undef HAVE_CATGETS */ /* Define if you have the dgettext function. */ /* #undef HAVE_DGETTEXT */ /* Define if you have the memset function. */ #define HAVE_MEMSET 1 /* Define if struct nlist is declared in or */ /* #undef HAVE_STRUCT_NLIST_DECLARATION */ /* Define if Elf32_Dyn is declared in */ /* #undef __LIBELF_NEED_LINK_H */ /* Define if Elf32_Dyn is declared in */ /* #undef __LIBELF_NEED_SYS_LINK_H */ /* Define to `' or `' if one of them is present */ /* #undef __LIBELF_HEADER_ELF_H */ /* Define if you want 64-bit support (and your system supports it) */ #define __LIBELF64 1 /* Define if you want 64-bit support, and are running IRIX */ /* #undef __LIBELF64_IRIX */ /* Define if you want 64-bit support, and are running Linux */ /* #undef __LIBELF64_LINUX */ /* Define if you want symbol versioning (and your system supports it) */ #define __LIBELF_SYMBOL_VERSIONS 1 /* Define if symbol versioning uses Sun section type (SHT_SUNW_*) */ #define __LIBELF_SUN_SYMBOL_VERSIONS 1 /* Define if symbol versioning uses GNU section types (SHT_GNU_*) */ /* #undef __LIBELF_GNU_SYMBOL_VERSIONS */ /* Define to a 64-bit signed integer type if one exists */ #define __libelf_i64_t int64_t /* Define to a 64-bit unsigned integer type if one exists */ #define __libelf_u64_t uint64_t /* Define to a 32-bit signed integer type if one exists */ #define __libelf_i32_t int32_t /* Define to a 32-bit unsigned integer type if one exists */ #define __libelf_u32_t uint32_t /* Define to a 16-bit signed integer type if one exists */ #define __libelf_i16_t int16_t /* Define to a 16-bit unsigned integer type if one exists */ #define __libelf_u16_t uint16_t /* Define to 1 if you have the header file. */ /* #undef HAVE_AR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_ELF_H */ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_GELF_H */ /* Define to 1 if you have the `getpagesize' function. */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBELF_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINK_H */ /* Define to 1 if you have the `memcmp' function. */ #define HAVE_MEMCMP 1 /* Define to 1 if you have the `memcpy' function. */ #define HAVE_MEMCPY 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have a working `mmap' system call. */ /* #undef HAVE_MMAP */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ELF_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_LINK_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define PACKAGE_NAME "" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "" /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `long long', as computed by sizeof. */ #define SIZEOF_LONG_LONG 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `__int64', as computed by sizeof. */ #define SIZEOF___INT64 8 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `long int' if does not define. */ /* #undef off_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ qtrvsim-0.9.8/external/libelf/config.h000066400000000000000000000001661467752164200177530ustar00rootroot00000000000000#if defined(_WIN32) && !defined(__MINGW32__) #include "config.w32.h" #else #include "config.default.h" #endif qtrvsim-0.9.8/external/libelf/config.w32.h000066400000000000000000000111221467752164200203570ustar00rootroot00000000000000/* * lib/config.h.w32 - configuration file for W32 port * Copyright (C) 2004 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @(#) $Id: config.h.w32,v 1.2 2006/09/07 15:55:42 michael Exp $ */ /* Define to empty if the keyword does not work. */ #undef const /* Define if you have a working `mmap' system call. */ #undef HAVE_MMAP /* Define to `long' if doesn't define. */ #undef off_t /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you want to include extra debugging code */ #define ENABLE_DEBUG 1 /* Define if memmove() does not copy overlapping arrays correctly */ #undef HAVE_BROKEN_MEMMOVE /* Define if you have the catgets function. */ #undef HAVE_CATGETS /* Define if you have the dgettext function. */ #undef HAVE_DGETTEXT /* Define if you have the memset function. */ #define HAVE_MEMSET 1 /* Define if struct nlist is declared in or */ #undef HAVE_STRUCT_NLIST_DECLARATION /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_LINK_H /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_SYS_LINK_H /* Define to `' or `' if one of them is present */ #undef __LIBELF_HEADER_ELF_H /* Define if you want 64-bit support (and your system supports it) */ #define __LIBELF64 1 /* Define if you want 64-bit support, and are running IRIX */ #undef __LIBELF64_IRIX /* Define if you want 64-bit support, and are running Linux */ #undef __LIBELF64_LINUX /* Define if you want symbol versioning (and your system supports it) */ #define __LIBELF_SYMBOL_VERSIONS 1 /* Define if symbol versioning uses Sun section type (SHT_SUNW_*) */ #define __LIBELF_SUN_SYMBOL_VERSIONS 1 /* Define if symbol versioning uses GNU section types (SHT_GNU_*) */ #undef __LIBELF_GNU_SYMBOL_VERSIONS /* Define to a 64-bit signed integer type if one exists */ #define __libelf_i64_t __int64 /* Define to a 64-bit unsigned integer type if one exists */ #define __libelf_u64_t unsigned __int64 /* Define to a 32-bit signed integer type if one exists */ #define __libelf_i32_t int /* Define to a 32-bit unsigned integer type if one exists */ #define __libelf_u32_t unsigned int /* Define to a 16-bit signed integer type if one exists */ #define __libelf_i16_t short int /* Define to a 16-bit unsigned integer type if one exists */ #define __libelf_u16_t unsigned short int /* The number of bytes in a __int64. */ #define SIZEOF___INT64 8 /* The number of bytes in a int. */ #define SIZEOF_INT 4 /* The number of bytes in a long. */ #define SIZEOF_LONG 4 /* The number of bytes in a long long. */ #define SIZEOF_LONG_LONG 0 /* The number of bytes in a short. */ #define SIZEOF_SHORT 2 /* Define if you have the ftruncate function. */ #undef HAVE_FTRUNCATE /* Define if you have the getpagesize function. */ #undef HAVE_GETPAGESIZE /* Define if you have the memcmp function. */ #define HAVE_MEMCMP 1 /* Define if you have the memcpy function. */ #define HAVE_MEMCPY 1 /* Define if you have the memmove function. */ #define HAVE_MEMMOVE 1 /* Define if you have the memset function. */ #define HAVE_MEMSET 1 /* Define if you have the header file. */ #undef HAVE_AR_H /* Define if you have the header file. */ #undef HAVE_ELF_H /* Define if you have the header file. */ #undef HAVE_FCNTL_H /* Define if you have the header file. */ #undef HAVE_GELF_H /* Define if you have the header file. */ #undef HAVE_LIBELF_H /* Define if you have the header file. */ #undef HAVE_LINK_H /* Define if you have the header file. */ #undef HAVE_NLIST_H /* Define if you have the header file. */ #undef HAVE_SYS_ELF_H /* Define if you have the header file. */ #undef HAVE_SYS_LINK_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H qtrvsim-0.9.8/external/libelf/cook.c000066400000000000000000000367231467752164200174440ustar00rootroot00000000000000/* * cook.c - read and translate ELF files. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: cook.c,v 1.29 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ const Elf_Scn _elf_scn_init = INIT_SCN; const Scn_Data _elf_data_init = INIT_DATA; Elf_Type _elf_scn_type(unsigned t) { switch (t) { case SHT_DYNAMIC: return ELF_T_DYN; case SHT_DYNSYM: return ELF_T_SYM; case SHT_HASH: return ELF_T_WORD; case SHT_REL: return ELF_T_REL; case SHT_RELA: return ELF_T_RELA; case SHT_SYMTAB: return ELF_T_SYM; case SHT_SYMTAB_SHNDX: return ELF_T_WORD; /* XXX: really? */ #if __LIBELF_SYMBOL_VERSIONS #if __LIBELF_SUN_SYMBOL_VERSIONS case SHT_SUNW_verdef: return ELF_T_VDEF; case SHT_SUNW_verneed: return ELF_T_VNEED; case SHT_SUNW_versym: return ELF_T_HALF; #else /* __LIBELF_SUN_SYMBOL_VERSIONS */ case SHT_GNU_verdef: return ELF_T_VDEF; case SHT_GNU_verneed: return ELF_T_VNEED; case SHT_GNU_versym: return ELF_T_HALF; #endif /* __LIBELF_SUN_SYMBOL_VERSIONS */ #endif /* __LIBELF_SYMBOL_VERSIONS */ } return ELF_T_BYTE; } /* * Check for overflow on 32-bit systems */ #define overflow(a, b, t) (sizeof(a) < sizeof(t) && (t)(a) != (b)) #define truncerr(t) \ ((t) == ELF_T_EHDR \ ? ERROR_TRUNC_EHDR \ : ((t) == ELF_T_PHDR ? ERROR_TRUNC_PHDR : ERROR_INTERNAL)) #define memerr(t) \ ((t) == ELF_T_EHDR \ ? ERROR_MEM_EHDR \ : ((t) == ELF_T_PHDR ? ERROR_MEM_PHDR : ERROR_INTERNAL)) Elf_Data *_elf_xlatetom(const Elf *elf, Elf_Data *dst, const Elf_Data *src) { if (elf->e_class == ELFCLASS32) { return elf32_xlatetom(dst, src, elf->e_encoding); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { return elf64_xlatetom(dst, src, elf->e_encoding); } #endif /* __LIBELF64 */ seterr(ERROR_UNIMPLEMENTED); return NULL; } static char *_elf_item(void *buf, Elf *elf, Elf_Type type, size_t off) { Elf_Data src, dst; elf_assert(valid_type(type)); if (off < 0 || off > elf->e_size) { seterr(ERROR_OUTSIDE); return NULL; } src.d_type = type; src.d_version = elf->e_version; src.d_size = _fsize(elf->e_class, src.d_version, type); elf_assert(src.d_size); if ((elf->e_size - off) < src.d_size) { seterr(truncerr(type)); return NULL; } dst.d_version = _elf_version; dst.d_size = _msize(elf->e_class, dst.d_version, type); elf_assert(dst.d_size); if (!(dst.d_buf = buf) && !(dst.d_buf = malloc(dst.d_size))) { seterr(memerr(type)); return NULL; } elf_assert(elf->e_data); if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + off; } else { src.d_buf = elf->e_data + off; } if (_elf_xlatetom(elf, &dst, &src)) { return (char *)dst.d_buf; } if (dst.d_buf != buf) { free(dst.d_buf); } return NULL; } static int _elf_cook_phdr(Elf *elf) { size_t num, off, entsz; if (elf->e_class == ELFCLASS32) { num = ((Elf32_Ehdr *)elf->e_ehdr)->e_phnum; off = ((Elf32_Ehdr *)elf->e_ehdr)->e_phoff; entsz = ((Elf32_Ehdr *)elf->e_ehdr)->e_phentsize; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = ((Elf64_Ehdr *)elf->e_ehdr)->e_phnum; off = ((Elf64_Ehdr *)elf->e_ehdr)->e_phoff; entsz = ((Elf64_Ehdr *)elf->e_ehdr)->e_phentsize; /* * Check for overflow on 32-bit systems */ if (overflow(off, ((Elf64_Ehdr *)elf->e_ehdr)->e_phoff, Elf64_Off)) { seterr(ERROR_OUTSIDE); return 0; } } #endif /* __LIBELF64 */ else { seterr(ERROR_UNIMPLEMENTED); return 0; } if (off) { Elf_Scn *scn; size_t size; unsigned i; char *p; if (num == PN_XNUM) { /* * Overflow in ehdr->e_phnum. * Get real value from first SHDR. */ if (!(scn = elf->e_scn_1)) { seterr(ERROR_NOSUCHSCN); return 0; } if (elf->e_class == ELFCLASS32) { num = scn->s_shdr32.sh_info; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = scn->s_shdr64.sh_info; } #endif /* __LIBELF64 */ /* we already had this else { seterr(ERROR_UNIMPLEMENTED); return 0; } */ } size = _fsize(elf->e_class, elf->e_version, ELF_T_PHDR); elf_assert(size); #if ENABLE_EXTENDED_FORMAT if (entsz < size) { #else /* ENABLE_EXTENDED_FORMAT */ if (entsz != size) { #endif /* ENABLE_EXTENDED_FORMAT */ seterr(ERROR_EHDR_PHENTSIZE); return 0; } size = _msize(elf->e_class, _elf_version, ELF_T_PHDR); elf_assert(size); if (!(p = malloc(num * size))) { seterr(memerr(ELF_T_PHDR)); return 0; } for (i = 0; i < num; i++) { if (!_elf_item(p + i * size, elf, ELF_T_PHDR, off + i * entsz)) { free(p); return 0; } } elf->e_phdr = p; elf->e_phnum = num; } return 1; } static int _elf_cook_shdr(Elf *elf) { size_t num, off, entsz; if (elf->e_class == ELFCLASS32) { num = ((Elf32_Ehdr *)elf->e_ehdr)->e_shnum; off = ((Elf32_Ehdr *)elf->e_ehdr)->e_shoff; entsz = ((Elf32_Ehdr *)elf->e_ehdr)->e_shentsize; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = ((Elf64_Ehdr *)elf->e_ehdr)->e_shnum; off = ((Elf64_Ehdr *)elf->e_ehdr)->e_shoff; entsz = ((Elf64_Ehdr *)elf->e_ehdr)->e_shentsize; /* * Check for overflow on 32-bit systems */ if (overflow(off, ((Elf64_Ehdr *)elf->e_ehdr)->e_shoff, Elf64_Off)) { seterr(ERROR_OUTSIDE); return 0; } } #endif /* __LIBELF64 */ else { seterr(ERROR_UNIMPLEMENTED); return 0; } if (off) { struct tmp { Elf_Scn scn; Scn_Data data; } * head; Elf_Data src, dst; Elf_Scn *scn; Scn_Data *sd; unsigned i; if (off < 0 || off > elf->e_size) { seterr(ERROR_OUTSIDE); return 0; } src.d_type = ELF_T_SHDR; src.d_version = elf->e_version; src.d_size = _fsize(elf->e_class, src.d_version, ELF_T_SHDR); elf_assert(src.d_size); #if ENABLE_EXTENDED_FORMAT if (entsz < src.d_size) { #else /* ENABLE_EXTENDED_FORMAT */ if (entsz != src.d_size) { #endif /* ENABLE_EXTENDED_FORMAT */ seterr(ERROR_EHDR_SHENTSIZE); return 0; } dst.d_version = EV_CURRENT; if (num == 0) { union { Elf32_Shdr sh32; #if __LIBELF64 Elf64_Shdr sh64; #endif /* __LIBELF64 */ } u; /* * Overflow in ehdr->e_shnum. * Get real value from first SHDR. */ if (elf->e_size - off < entsz) { seterr(ERROR_TRUNC_SHDR); return 0; } if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + off; } else { src.d_buf = elf->e_data + off; } dst.d_buf = &u; dst.d_size = sizeof(u); if (!_elf_xlatetom(elf, &dst, &src)) { return 0; } elf_assert( dst.d_size == _msize(elf->e_class, EV_CURRENT, ELF_T_SHDR)); elf_assert(dst.d_type == ELF_T_SHDR); if (elf->e_class == ELFCLASS32) { num = u.sh32.sh_size; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = u.sh64.sh_size; /* * Check for overflow on 32-bit systems */ if (overflow(num, u.sh64.sh_size, Elf64_Xword)) { seterr(ERROR_OUTSIDE); return 0; } } #endif /* __LIBELF64 */ } if ((elf->e_size - off) / entsz < num) { seterr(ERROR_TRUNC_SHDR); return 0; } if (!(head = (struct tmp *)malloc(num * sizeof(struct tmp)))) { seterr(ERROR_MEM_SCN); return 0; } for (scn = NULL, i = num; i-- > 0;) { head[i].scn = _elf_scn_init; head[i].data = _elf_data_init; head[i].scn.s_link = scn; if (!scn) { elf->e_scn_n = &head[i].scn; } scn = &head[i].scn; sd = &head[i].data; if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + off + i * entsz; } else { src.d_buf = elf->e_data + off + i * entsz; } dst.d_buf = &scn->s_uhdr; dst.d_size = sizeof(scn->s_uhdr); if (!_elf_xlatetom(elf, &dst, &src)) { elf->e_scn_n = NULL; free(head); return 0; } elf_assert( dst.d_size == _msize(elf->e_class, EV_CURRENT, ELF_T_SHDR)); elf_assert(dst.d_type == ELF_T_SHDR); scn->s_elf = elf; scn->s_index = i; scn->s_data_1 = sd; scn->s_data_n = sd; sd->sd_scn = scn; if (elf->e_class == ELFCLASS32) { Elf32_Shdr *shdr = &scn->s_shdr32; scn->s_type = shdr->sh_type; scn->s_size = shdr->sh_size; scn->s_offset = shdr->sh_offset; sd->sd_data.d_align = shdr->sh_addralign; sd->sd_data.d_type = _elf_scn_type(scn->s_type); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { Elf64_Shdr *shdr = &scn->s_shdr64; scn->s_type = shdr->sh_type; scn->s_size = shdr->sh_size; scn->s_offset = shdr->sh_offset; sd->sd_data.d_align = shdr->sh_addralign; /* * Check for overflow on 32-bit systems */ if (overflow(scn->s_size, shdr->sh_size, Elf64_Xword) || overflow(scn->s_offset, shdr->sh_offset, Elf64_Off) || overflow( sd->sd_data.d_align, shdr->sh_addralign, Elf64_Xword)) { seterr(ERROR_OUTSIDE); return 0; } sd->sd_data.d_type = _elf_scn_type(scn->s_type); /* * QUIRKS MODE: * * Some 64-bit architectures use 64-bit entries in the * .hash section. This violates the ELF standard, and * should be fixed. It's mostly harmless as long as the * binary and the machine running your program have the * same byte order, but you're in trouble if they don't, * and if the entry size is wrong. * * As a workaround, I let libelf guess the right size * for the binary. This relies pretty much on the fact * that the binary provides correct data in the section * headers. If it doesn't, it's probably broken anyway. * Therefore, libelf uses a standard conforming value * when it's not absolutely sure. */ if (scn->s_type == SHT_HASH) { int override = 0; /* * sh_entsize must reflect the entry size */ if (shdr->sh_entsize == ELF64_FSZ_ADDR) { override++; } /* * sh_size must be a multiple of sh_entsize */ if (shdr->sh_size % ELF64_FSZ_ADDR == 0) { override++; } /* * There must be room for at least 2 entries */ if (shdr->sh_size >= 2 * ELF64_FSZ_ADDR) { override++; } /* * sh_addralign must be correctly set */ if (shdr->sh_addralign == ELF64_FSZ_ADDR) { override++; } /* * The section must be properly aligned */ if (shdr->sh_offset % ELF64_FSZ_ADDR == 0) { override++; } /* XXX: also look at the data? */ /* * Make a conservative decision... */ if (override >= 5) { sd->sd_data.d_type = ELF_T_ADDR; } } /* * END QUIRKS MODE. */ } #endif /* __LIBELF64 */ /* we already had this else { seterr(ERROR_UNIMPLEMENTED); return 0; } */ sd->sd_data.d_size = scn->s_size; sd->sd_data.d_version = _elf_version; } elf_assert(scn == &head[0].scn); elf->e_scn_1 = &head[0].scn; head[0].scn.s_freeme = 1; } return 1; } static int _elf_cook_file(Elf *elf) { elf->e_ehdr = _elf_item(NULL, elf, ELF_T_EHDR, 0); if (!elf->e_ehdr) { return 0; } /* * Note: _elf_cook_phdr may require the first section header! */ if (!_elf_cook_shdr(elf)) { return 0; } if (!_elf_cook_phdr(elf)) { return 0; } return 1; } int _elf_cook(Elf *elf) { elf_assert(_elf_scn_init.s_magic == SCN_MAGIC); elf_assert(_elf_data_init.sd_magic == DATA_MAGIC); elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(elf->e_kind == ELF_K_ELF); elf_assert(!elf->e_ehdr); if (!valid_version(elf->e_version)) { seterr(ERROR_UNKNOWN_VERSION); } else if (!valid_encoding(elf->e_encoding)) { seterr(ERROR_UNKNOWN_ENCODING); } else if (valid_class(elf->e_class)) { return _elf_cook_file(elf); } else { seterr(ERROR_UNKNOWN_CLASS); } return 0; } qtrvsim-0.9.8/external/libelf/data.c000066400000000000000000000022531467752164200174110ustar00rootroot00000000000000/* * data.c - libelf internal variables. * Copyright (C) 1995 - 1998, 2007 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: data.c,v 1.8 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ unsigned _elf_version = EV_NONE; int _elf_errno = 0; int _elf_fill = 0; #if ENABLE_SANITY_CHECKS #define SANITY_CHECKS -1 #else #define SANITY_CHECKS 0 #endif int _elf_sanity_checks = SANITY_CHECKS; qtrvsim-0.9.8/external/libelf/dummy-sigaltstack.c000066400000000000000000000001721467752164200221400ustar00rootroot00000000000000#ifdef __EMSCRIPTEN__ #include int sigaltstack(const stack_t *ss, stack_t *old_ss) { return -1; } #endif qtrvsim-0.9.8/external/libelf/elf_repl.h000066400000000000000000000600601467752164200202750ustar00rootroot00000000000000/* * elf_repl.h - public header file for systems that lack it. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: elf_repl.h,v 1.22 2009/11/01 13:04:19 michael Exp $ */ /* * NEVER INCLUDE THIS FILE DIRECTLY - USE INSTEAD! */ #ifndef _ELF_REPL_H #define _ELF_REPL_H #include "config.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Scalar data types */ typedef __libelf_u32_t Elf32_Addr; typedef __libelf_u16_t Elf32_Half; typedef __libelf_u32_t Elf32_Off; typedef __libelf_i32_t Elf32_Sword; typedef __libelf_u32_t Elf32_Word; #define ELF32_FSZ_ADDR 4 #define ELF32_FSZ_HALF 2 #define ELF32_FSZ_OFF 4 #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_WORD 4 #if __LIBELF64 typedef __libelf_u64_t Elf64_Addr; typedef __libelf_u16_t Elf64_Half; typedef __libelf_u64_t Elf64_Off; typedef __libelf_i32_t Elf64_Sword; typedef __libelf_u32_t Elf64_Word; typedef __libelf_i64_t Elf64_Sxword; typedef __libelf_u64_t Elf64_Xword; #define ELF64_FSZ_ADDR 8 #define ELF64_FSZ_HALF 2 #define ELF64_FSZ_OFF 8 #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_WORD 4 #define ELF64_FSZ_SXWORD 8 #define ELF64_FSZ_XWORD 8 /* * Blame Sun for this... */ typedef __libelf_u64_t Elf64_Lword; typedef __libelf_u64_t Elf32_Lword; #endif /* __LIBELF64 */ /* * ELF header */ #define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr; #if __LIBELF64 typedef struct { unsigned char e_ident[EI_NIDENT]; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } Elf64_Ehdr; #endif /* __LIBELF64 */ /* * e_ident */ #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define EI_PAD 9 #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' #define ELFMAG "\177ELF" #define SELFMAG 4 /* * e_ident[EI_CLASS] */ #define ELFCLASSNONE 0 #define ELFCLASS32 1 #define ELFCLASS64 2 #define ELFCLASSNUM 3 /* * e_ident[EI_DATA] */ #define ELFDATANONE 0 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 #define ELFDATANUM 3 /* * e_ident[EI_OSABI] */ #define ELFOSABI_NONE 0 /* No extensions or unspecified */ #define ELFOSABI_SYSV ELFOSABI_NONE #define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD */ #define ELFOSABI_LINUX 3 /* Linux */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris */ #define ELFOSABI_AIX 7 /* AIX */ #define ELFOSABI_IRIX 8 /* IRIX */ #define ELFOSABI_FREEBSD 9 /* FreeBSD */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */ #define ELFOSABI_MODESTO 11 /* Novell Modesto */ #define ELFOSABI_OPENBSD 12 /* Open BSD */ #define ELFOSABI_OPENVMS 13 /* Open VMS */ #define ELFOSABI_NSK 14 /* Hewlett-Packard Non-Stop Kernel */ #define ELFOSABI_AROS 15 /* Amiga Research OS */ /* these are probably obsolete: */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* standalone (embedded) application */ /* * e_type */ #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 #define ET_NUM 5 #define ET_LOOS 0xfe00 #define ET_HIOS 0xfeff #define ET_LOPROC 0xff00 #define ET_HIPROC 0xffff /* * e_machine */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #define EM_486 6 /* Intel i486 (DO NOT USE THIS ONE) */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS I Architecture */ #define EM_S370 9 /* IBM System/370 Processor */ #define EM_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ #define EM_SPARC64 11 /* SPARC 64-bit */ #define EM_PARISC 15 /* Hewlett-Packard PA-RISC */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* 64-bit PowerPC */ #define EM_S390 22 /* IBM System/390 Processor */ #define EM_V800 36 /* NEC V800 */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* Advanced RISC Machines ARM */ #define EM_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC Version 9 */ #define EM_TRICORE 44 /* Siemens TriCore embedded processor */ #define EM_ARC 45 /* Argonaut RISC Core, Argonaut Technologies Inc. */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel IA-64 processor architecture */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola ColdFire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embedded RISC processor */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Star*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronics ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ embedded processor family */ #define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_AMD64 EM_X86_64 #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ #define EM_ST7 68 /* STMicroelectronics ST7 8-bit microcontroller */ #define EM_68HC16 69 /* Motorola MC68HC16 Microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 Microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 Microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 Microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8-bit microcontroller */ #define EM_VAX 75 /* Digital VAX */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ #define EM_HUANY 81 /* Harvard University machine-independent object files */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi D10V */ #define EM_D30V 86 /* Mitsubishi D30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor */ #define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Processor */ #define EM_NS32K 97 /* National Semiconductor 32000 series */ #define EM_TPC 98 /* Tenor Network TPC processor */ #define EM_SNP1K 99 /* Trebia SNP 1000 processor */ #define EM_ST200 \ 100 /* STMicroelectronics (www.st.com) ST200 microcontroller \ */ #define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family */ #define EM_MAX 102 /* MAX Processor */ #define EM_CR 103 /* National Semiconductor CompactRISC microprocessor */ #define EM_F2MC16 104 /* Fujitsu F2MC16 */ #define EM_MSP430 105 /* Texas Instruments embedded microcontroller msp430 */ #define EM_BLACKFIN 106 /* Analog Devices Blackfin (DSP) processor */ #define EM_SE_C33 107 /* S1C33 Family of Seiko Epson processors */ #define EM_SEP 108 /* Sharp embedded microprocessor */ #define EM_ARCA 109 /* Arca RISC Microprocessor */ #define EM_UNICORE \ 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC of Peking \ University */ #define EM_NUM 111 #define EM_RISCV 243 /* RISC-V */ /* * e_ident[EI_VERSION], e_version */ #define EV_NONE 0 #define EV_CURRENT 1 #define EV_NUM 2 /* * Section header */ typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; #if __LIBELF64 typedef struct { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } Elf64_Shdr; #endif /* __LIBELF64 */ /* * Special section indices */ #define SHN_UNDEF 0 #define SHN_LORESERVE 0xff00 #define SHN_LOPROC 0xff00 #define SHN_HIPROC 0xff1f #define SHN_LOOS 0xff20 #define SHN_HIOS 0xff3f #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 #define SHN_XINDEX 0xffff #define SHN_HIRESERVE 0xffff /* * sh_type */ #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_INIT_ARRAY 14 #define SHT_FINI_ARRAY 15 #define SHT_PREINIT_ARRAY 16 #define SHT_GROUP 17 #define SHT_SYMTAB_SHNDX 18 #define SHT_NUM 19 #define SHT_LOOS 0x60000000 #define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xffffffff /* * Solaris extensions */ #define SHT_LOSUNW 0x6ffffff4 #define SHT_SUNW_dof 0x6ffffff4 #define SHT_SUNW_cap 0x6ffffff5 #define SHT_SUNW_SIGNATURE 0x6ffffff6 #define SHT_SUNW_ANNOTATE 0x6ffffff7 #define SHT_SUNW_DEBUGSTR 0x6ffffff8 #define SHT_SUNW_DEBUG 0x6ffffff9 #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_SUNW_verdef 0x6ffffffd #define SHT_SUNW_verneed 0x6ffffffe #define SHT_SUNW_versym 0x6fffffff #define SHT_HISUNW 0x6fffffff #define SHT_SPARC_GOTDATA 0x70000000 #define SHT_AMD64_UNWIND 0x70000001 /* * GNU extensions */ #define SHT_GNU_verdef 0x6ffffffd #define SHT_GNU_verneed 0x6ffffffe #define SHT_GNU_versym 0x6fffffff /* * sh_flags */ #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MERGE 0x10 #define SHF_STRINGS 0x20 #define SHF_INFO_LINK 0x40 #define SHF_LINK_ORDER 0x80 #define SHF_OS_NONCONFORMING 0x100 #define SHF_GROUP 0x200 #define SHF_TLS 0x400 #define SHF_MASKOS 0x0ff00000 #define SHF_MASKPROC 0xf0000000 /* * Solaris extensions */ #define SHF_AMD64_LARGE 0x10000000 #define SHF_ORDERED 0x40000000 #define SHF_EXCLUDE 0x80000000 /* * Section group flags */ #define GRP_COMDAT 0x1 #define GRP_MASKOS 0x0ff00000 #define GRP_MASKPROC 0xf0000000 /* * Symbol table */ typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; #if __LIBELF64 typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym; #endif /* __LIBELF64 */ /* * Special symbol indices */ #define STN_UNDEF 0 /* * Macros for manipulating st_info */ #define ELF32_ST_BIND(i) ((i) >> 4) #define ELF32_ST_TYPE(i) ((i)&0xf) #define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) #if __LIBELF64 #define ELF64_ST_BIND(i) ((i) >> 4) #define ELF64_ST_TYPE(i) ((i)&0xf) #define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) #endif /* __LIBELF64 */ /* * Symbol binding */ #define STB_LOCAL 0 #define STB_GLOBAL 1 #define STB_WEAK 2 #define STB_NUM 3 #define STB_LOOS 10 #define STB_HIOS 12 #define STB_LOPROC 13 #define STB_HIPROC 15 /* * Symbol types */ #define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 #define STT_COMMON 5 #define STT_TLS 6 #define STT_NUM 7 #define STT_LOOS 10 #define STT_HIOS 12 #define STT_LOPROC 13 #define STT_HIPROC 15 /* * Macros for manipulating st_other */ #define ELF32_ST_VISIBILITY(o) ((o)&0x3) #if __LIBELF64 #define ELF64_ST_VISIBILITY(o) ((o)&0x3) #endif /* __LIBELF64 */ /* * Symbol visibility */ #define STV_DEFAULT 0 #define STV_INTERNAL 1 #define STV_HIDDEN 2 #define STV_PROTECTED 3 /* * Relocation */ typedef struct { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel; typedef struct { Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } Elf32_Rela; #if __LIBELF64 typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; } Elf64_Rel; typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; #endif /* __LIBELF64 */ /* * Macros for manipulating r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char)(i)) #define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) #if __LIBELF64 #define ELF64_R_SYM(i) ((Elf64_Xword)(i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffffL) #define ELF64_R_INFO(s, t) (((Elf64_Xword)(s) << 32) + ((t)&0xffffffffL)) #endif /* __LIBELF64 */ /* * Note entry header */ typedef struct { Elf32_Word n_namesz; /* name size */ Elf32_Word n_descsz; /* descriptor size */ Elf32_Word n_type; /* descriptor type */ } Elf32_Nhdr; #if __LIBELF64 /* Solaris and GNU use this layout. Be compatible. */ /* XXX: Latest ELF specs say it's 64-bit!!! */ typedef struct { Elf64_Word n_namesz; /* name size */ Elf64_Word n_descsz; /* descriptor size */ Elf64_Word n_type; /* descriptor type */ } Elf64_Nhdr; #endif /* __LIBELF64 */ /* * Well-known descriptor types for ET_CORE files */ #define NT_PRSTATUS 1 #define NT_PRFPREG 2 #define NT_PRPSINFO 3 /* * Program header */ typedef struct { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr; #if __LIBELF64 typedef struct { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } Elf64_Phdr; #endif /* __LIBELF64 */ /* * Special numbers */ #define PN_XNUM 0xffff /* * p_type */ #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_TLS 7 #define PT_NUM 8 #define PT_LOOS 0x60000000 #define PT_HIOS 0x6fffffff #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff /* * Solaris extensions */ #define PT_SUNW_UNWIND 0x6464e550 #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa #define PT_SUNWSTACK 0x6ffffffb #define PT_SUNWDTRACE 0x6ffffffc #define PT_SUNWCAP 0x6ffffffd #define PT_HISUNW 0x6fffffff /* * p_flags */ #define PF_X 0x1 #define PF_W 0x2 #define PF_R 0x4 #define PF_MASKOS 0x0ff00000 #define PF_MASKPROC 0xf0000000 /* * Dynamic structure */ typedef struct { Elf32_Sword d_tag; union { Elf32_Word d_val; Elf32_Addr d_ptr; } d_un; } Elf32_Dyn; #if __LIBELF64 typedef struct { Elf64_Sxword d_tag; union { Elf64_Xword d_val; Elf64_Addr d_ptr; } d_un; } Elf64_Dyn; #endif /* __LIBELF64 */ /* * Dynamic array tags */ /* d_un exec shared */ #define DT_NULL 0 /* ign. mand. mand. */ #define DT_NEEDED 1 /* d_val opt. opt. */ #define DT_PLTRELSZ 2 /* d_val opt. opt. */ #define DT_PLTGOT 3 /* d_ptr opt. opt. */ #define DT_HASH 4 /* d_ptr mand. mand. */ #define DT_STRTAB 5 /* d_ptr mand. mand. */ #define DT_SYMTAB 6 /* d_ptr mand. mand. */ #define DT_RELA 7 /* d_ptr mand. opt. */ #define DT_RELASZ 8 /* d_val mand. opt. */ #define DT_RELAENT 9 /* d_val mand. opt. */ #define DT_STRSZ 10 /* d_val mand. mand. */ #define DT_SYMENT 11 /* d_val mand. mand. */ #define DT_INIT 12 /* d_ptr opt. opt. */ #define DT_FINI 13 /* d_ptr opt. opt. */ #define DT_SONAME 14 /* d_val ign. opt. */ #define DT_RPATH 15 /* d_val opt. ign. */ #define DT_SYMBOLIC 16 /* ign. ign. opt. */ #define DT_REL 17 /* d_ptr mand. opt. */ #define DT_RELSZ 18 /* d_val mand. opt. */ #define DT_RELENT 19 /* d_val mand. opt. */ #define DT_PLTREL 20 /* d_val opt. opt. */ #define DT_DEBUG 21 /* d_ptr opt. ign. */ #define DT_TEXTREL 22 /* ign. opt. opt. */ #define DT_JMPREL 23 /* d_ptr opt. opt. */ #define DT_BIND_NOW 24 /* ign. opt. opt. */ #define DT_INIT_ARRAY 25 /* d_ptr opt. opt. */ #define DT_FINI_ARRAY 26 /* d_ptr opt. opt. */ #define DT_INIT_ARRAYSZ 27 /* d_val opt. opt. */ #define DT_FINI_ARRAYSZ 28 /* d_val opt. opt. */ #define DT_RUNPATH 29 /* d_val opt. opt. */ #define DT_FLAGS 30 /* d_val opt. opt. */ #define DT_ENCODING 32 /* odd/even encoding rule starts here */ #define DT_PREINIT_ARRAY 32 /* d_ptr opt. ign. */ #define DT_PREINIT_ARRAYSZ 33 /* d_val opt. ign. */ #define DT_NUM 34 #define DT_LOOS 0x6000000D #define DT_HIOS 0x6ffff000 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff /* * DT_FLAGS values */ #define DF_ORIGIN 0x1 #define DF_SYMBOLIC 0x2 #define DF_TEXTREL 0x4 #define DF_BIND_NOW 0x8 #define DF_STATIC_TLS 0x10 /* * Solaris extensions */ #define DT_VALRNGLO 0x6ffffd00 #define DT_CHECKSUM 0x6ffffdf8 #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb #define DT_FEATURE_1 0x6ffffdfc #define DT_POSFLAG_1 0x6ffffdfd #define DT_SYMINSZ 0x6ffffdfe #define DT_SYMINENT 0x6ffffdff #define DT_VALRNGHI 0x6ffffdff #define DT_ADDRRNGLO 0x6ffffe00 #define DT_CONFIG 0x6ffffefa #define DT_DEPAUDIT 0x6ffffefb #define DT_AUDIT 0x6ffffefc #define DT_PLTPAD 0x6ffffefd #define DT_MOVETAB 0x6ffffefe #define DT_SYMINFO 0x6ffffeff #define DT_ADDRRNGHI 0x6ffffeff #define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa #define DT_FLAGS_1 0x6ffffffb #define DT_VERDEF 0x6ffffffc #define DT_VERDEFNUM 0x6ffffffd #define DT_VERNEED 0x6ffffffe #define DT_VERNEEDNUM 0x6fffffff #define DT_AUXILIARY 0x7ffffffd #define DT_USED 0x7ffffffe #define DT_FILTER 0x7fffffff /* * GNU extensions */ #define DT_VERSYM 0x6ffffff0 /* * DT_FEATURE_1 values */ #define DTF_1_PARINIT 0x1 #define DTF_1_CONFEXP 0x2 /* * DT_POSFLAG_1 values */ #define DF_P1_LAZYLOAD 0x1 #define DF_P1_GROUPPERM 0x2 /* * DT_FLAGS_1 values */ #define DF_1_NOW 0x00000001 #define DF_1_GLOBAL 0x00000002 #define DF_1_GROUP 0x00000004 #define DF_1_NODELETE 0x00000008 #define DF_1_LOADFLTR 0x00000010 #define DF_1_INITFIRST 0x00000020 #define DF_1_NOOPEN 0x00000040 #define DF_1_ORIGIN 0x00000080 #define DF_1_DIRECT 0x00000100 #define DF_1_TRANS 0x00000200 #define DF_1_INTERPOSE 0x00000400 #define DF_1_NODEFLIB 0x00000800 #define DF_1_NODUMP 0x00001000 #define DF_1_CONFALT 0x00002000 #define DF_1_ENDFILTEE 0x00004000 #define DF_1_DISPRELDNE 0x00008000 #define DF_1_DISPRELPND 0x00010000 /* * Syminfo structure */ typedef struct { Elf32_Half si_boundto; Elf32_Half si_flags; } Elf32_Syminfo; #if __LIBELF64 typedef struct { Elf64_Half si_boundto; Elf64_Half si_flags; } Elf64_Syminfo; #endif /* __LIBELF64 */ /* * Syminfo version (stored in unused first entry) */ #define SYMINFO_NONE 0 #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* * si_boundto special values */ #define SYMINFO_BT_LOWRESERVE 0xff00 #define SYMINFO_BT_PARENT 0xfffe /* bound to parent */ #define SYMINFO_BT_SELF 0xffff /* bound to self */ /* * si_flags */ #define SYMINFO_FLG_DIRECT 0x01 /* bound to an object */ #define SYMINFO_FLG_PASSTHRU 0x02 /* pass-thru symbol */ #define SYMINFO_FLG_COPY 0x04 /* result of a copy relocation */ #define SYMINFO_FLG_LAZYLOAD 0x08 /* bound to lazy-loaded object */ /* * Version definitions */ typedef struct { Elf32_Half vd_version; Elf32_Half vd_flags; Elf32_Half vd_ndx; Elf32_Half vd_cnt; Elf32_Word vd_hash; Elf32_Word vd_aux; Elf32_Word vd_next; } Elf32_Verdef; typedef struct { Elf32_Word vda_name; Elf32_Word vda_next; } Elf32_Verdaux; typedef struct { Elf32_Half vn_version; Elf32_Half vn_cnt; Elf32_Word vn_file; Elf32_Word vn_aux; Elf32_Word vn_next; } Elf32_Verneed; typedef struct { Elf32_Word vna_hash; Elf32_Half vna_flags; Elf32_Half vna_other; Elf32_Word vna_name; Elf32_Word vna_next; } Elf32_Vernaux; typedef Elf32_Half Elf32_Versym; #if __LIBELF64 typedef struct { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } Elf64_Verdef; typedef struct { Elf64_Word vda_name; Elf64_Word vda_next; } Elf64_Verdaux; typedef struct { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } Elf64_Verneed; typedef struct { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } Elf64_Vernaux; typedef Elf64_Half Elf64_Versym; #endif /* __LIBELF64 */ /* * vd_version */ #define VER_DEF_NONE 0 #define VER_DEF_CURRENT 1 #define VER_DEF_NUM 2 /* * vn_version */ #define VER_NEED_NONE 0 #define VER_NEED_CURRENT 1 #define VER_NEED_NUM 2 /* * vd_flags / vna_flags */ #define VER_FLG_BASE 0x1 /* vd_flags only */ #define VER_FLG_WEAK 0x2 /* * Elf*_Versym special values */ #define VER_NDX_LOCAL 0 #define VER_NDX_GLOBAL 1 /* * Solaris extensions */ /* * Move section */ #if __LIBELF64 typedef struct { Elf32_Lword m_value; Elf32_Word m_info; Elf32_Word m_poffset; Elf32_Half m_repeat; Elf32_Half m_stride; } Elf32_Move; typedef struct { Elf64_Lword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } Elf64_Move; #define ELF32_M_SYM(info) ((info) >> 8) #define ELF32_M_SIZE(info) ((unsigned char)(info)) #define ELF32_M_INFO(sym, sz) (((sym) << 8) + (unsigned char)(sz)) #define ELF64_M_SYM(info) ((Elf64_Xword)(info) >> 8) #define ELF64_M_SIZE(info) ((unsigned char)(info)) #define ELF64_M_INFO(sym, sz) \ (((Elf64_Xword)(sym) << 8) + (unsigned char)(sz)) #endif /* __LIBELF64 */ /* * Capabilities */ typedef struct { Elf32_Word c_tag; union { Elf32_Word c_val; Elf32_Addr c_ptr; } c_un; } Elf32_Cap; #if __LIBELF64 typedef struct { Elf64_Xword c_tag; union { Elf64_Xword c_val; Elf64_Addr c_ptr; } c_un; } Elf64_Cap; #endif /* __LIBELF64 */ #define CA_SUNW_NULL 0 /* c_un ignored */ #define CA_SUNW_HW_1 1 /* c_un.c_val */ #define CA_SUNW_SF_1 2 /* c_un.c_val */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _ELF_REPL_H */ qtrvsim-0.9.8/external/libelf/end.c000066400000000000000000000063041467752164200172470ustar00rootroot00000000000000/* * end.c - implementation of the elf_end(3) function. * Copyright (C) 1995 - 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: end.c,v 1.12 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #if HAVE_MMAP #include #endif /* HAVE_MMAP */ static void _elf_free(void *ptr) { if (ptr) { free(ptr); } } static void _elf_free_scns(Elf *elf, Elf_Scn *scn) { Scn_Data *sd, *tmp; Elf_Scn *freescn; for (freescn = NULL; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); for (sd = scn->s_data_1; sd; sd = tmp) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); tmp = sd->sd_link; if (sd->sd_free_data) { _elf_free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_free_data) { _elf_free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if (scn->s_freeme) { _elf_free(freescn); freescn = scn; } } _elf_free(freescn); } int elf_end(Elf *elf) { Elf **siblings; if (!elf) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); if (--elf->e_count) { return elf->e_count; } if (elf->e_parent) { elf_assert(elf->e_parent->e_magic == ELF_MAGIC); elf_assert(elf->e_parent->e_kind == ELF_K_AR); siblings = &elf->e_parent->e_members; while (*siblings) { if (*siblings == elf) { *siblings = elf->e_link; break; } siblings = &(*siblings)->e_link; } elf_end(elf->e_parent); _elf_free(elf->e_arhdr); } #if HAVE_MMAP else if (elf->e_unmap_data) { munmap(elf->e_data, elf->e_size); } #endif /* HAVE_MMAP */ else if (!elf->e_memory) { _elf_free(elf->e_data); } _elf_free_scns(elf, elf->e_scn_1); if (elf->e_rawdata != elf->e_data) { _elf_free(elf->e_rawdata); } if (elf->e_free_syms) { _elf_free(elf->e_symtab); } _elf_free(elf->e_ehdr); _elf_free(elf->e_phdr); free(elf); return 0; } qtrvsim-0.9.8/external/libelf/errmsg.c000066400000000000000000000042321467752164200177760ustar00rootroot00000000000000/* * errmsg.c - implementation of the elf_errmsg(3) function. * Copyright (C) 1995 - 1999, 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: errmsg.c,v 1.11 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #if HAVE_DGETTEXT #undef HAVE_CATGETS #include #else /* HAVE_DGETTEXT */ #define dgettext(dom, str) str #endif /* HAVE_DGETTEXT */ #if HAVE_CATGETS #include static nl_catd _libelf_cat = (nl_catd)0; #endif /* HAVE_CATGETS */ #if HAVE_DGETTEXT || HAVE_CATGETS static const char domain[] = "libelf"; #endif /* HAVE_DGETTEXT || HAVE_CATGETS */ #if PIC static const char *_messages[] = { #else /* PIC */ static const char *const _messages[] = { #endif /* PIC */ #define __err__(a, b) b, #include "errors.h" /* include string tables from errors.h */ #undef __err__ }; const char *elf_errmsg(int err) { if (err == 0) { err = _elf_errno; if (err == 0) { return NULL; } } else if (err == -1) { err = _elf_errno; } if (err < 0 || err >= ERROR_NUM || _messages[err] == NULL) { err = ERROR_UNKNOWN; } #if HAVE_CATGETS if (_libelf_cat == (nl_catd)0) { _libelf_cat = catopen(domain, 0); } if (_libelf_cat != (nl_catd)-1) { return catgets(_libelf_cat, 1, err + 1, _messages[err]); } #endif /* HAVE_CATGETS */ return dgettext(domain, _messages[err]); } qtrvsim-0.9.8/external/libelf/errno.c000066400000000000000000000020211467752164200176160ustar00rootroot00000000000000/* errno.c - implementation of the elf_errno(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: errno.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ int elf_errno(void) { int tmp = _elf_errno; _elf_errno = 0; return tmp; } qtrvsim-0.9.8/external/libelf/errors.h000066400000000000000000000353161467752164200200270ustar00rootroot00000000000000/* * errors.h - exhaustive list of all error codes and messages for libelf. * Copyright (C) 1995 - 2003, 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: errors.h,v 1.18 2008/05/23 08:15:34 michael Exp $ */ /* dummy for xgettext */ #define _(str) str __err__(ERROR_OK, _("no error")) __err__(ERROR_UNKNOWN, _("unknown error")) __err__(ERROR_INTERNAL, _("Internal error: unknown reason")) __err__( ERROR_UNIMPLEMENTED, _("Internal error: not implemented")) __err__(ERROR_WRONLY, _("Request error: cntl(ELF_C_FDREAD) on write-only file")) __err__(ERROR_INVALID_CMD, _("Request error: invalid ELF_C_* argument")) __err__( ERROR_FDDISABLED, _("Request error: file descriptor disabled")) __err__(ERROR_NOTARCHIVE, _("Request error: not an archive")) __err__(ERROR_BADOFF, _("Request error: offset out of range")) __err__(ERROR_UNKNOWN_VERSION, _("Request error: unknown ELF version")) __err__( ERROR_CMDMISMATCH, _("Request error: ELF_C_* argument does not match")) __err__(ERROR_MEMBERWRITE, _("Request error: archive member begin() for writing")) __err__(ERROR_FDMISMATCH, _("Request error: archive/member file descriptor mismatch")) __err__( ERROR_NOTELF, _("Request error: not an ELF file")) __err__(ERROR_CLASSMISMATCH, _("Request error: class file/memory mismatch")) __err__(ERROR_UNKNOWN_TYPE, _("Request error: invalid ELF_T_* argument")) __err__( ERROR_UNKNOWN_ENCODING, _("Request error: unknown data encoding")) __err__(ERROR_DST2SMALL, _("Request error: destination buffer too small")) __err__(ERROR_NULLBUF, _("Request error: d_buf is NULL")) __err__( ERROR_UNKNOWN_CLASS, _("Request error: unknown ELF class")) __err__(ERROR_ELFSCNMISMATCH, _("Request error: section does not belong to file")) __err__(ERROR_NOSUCHSCN, _("Request error: no section at index")) __err__( ERROR_NULLSCN, _("Request error: can't manipulate null section")) __err__(ERROR_SCNDATAMISMATCH, _("Request error: data does not belong to section")) __err__(ERROR_NOSTRTAB, _("Request error: no string table")) __err__( ERROR_BADSTROFF, _("Request error: string table offset out of " "range")) __err__(ERROR_RDONLY, _("Request error: update(ELF_C_WRITE) on read-only file")) __err__(ERROR_IO_SEEK, _("I/O error: seek")) __err__( ERROR_IO_2BIG, _("I/O error: file too big for memory")) __err__(ERROR_IO_READ, _("I/O error: raw read")) __err__( ERROR_IO_GETSIZE, _("I/O error: get file size")) __err__(ERROR_IO_WRITE, _("I/O error: output write")) __err__(ERROR_IO_TRUNC, _("I/O error: can't truncate output file")) __err__( ERROR_VERSION_UNSET, _("Sequence error: must set ELF " "version " "first")) __err__(ERROR_NOEHDR, _("Sequence error: must create ELF header first")) __err__(ERROR_OUTSIDE, _("Format error: reference outside file")) __err__( ERROR_TRUNC_ARHDR, _( "Format error: archive " "header " "truncated")) __err__(ERROR_ARFMAG, _("Format error: archive fmag")) __err__(ERROR_ARHDR, _("Format error: archive header")) __err__(ERROR_TRUNC_MEMBER, _("Format error: archive member truncated")) __err__( ERROR_SIZE_ARSYMTAB, _("Format error: archive " "symbol " "table size")) __err__(ERROR_ARSTRTAB, _("Format error: archive string table")) __err__(ERROR_ARSPECIAL, _("Format error: archive special name unknown")) __err__( ERROR_TRUNC_EHDR, _("Format error: ELF " "header " "truncated")) __err__(ERROR_TRUNC_PHDR, _("Format error: program header table truncated")) __err__(ERROR_TRUNC_SHDR, _("Format error: section header table truncated")) __err__( ERROR_TRUNC_SCN, _( "Format error: " "data " "region " "truncated")) __err__(ERROR_ALIGN_PHDR, _("Format error: program header table alignment")) __err__(ERROR_ALIGN_SHDR, _("Format error: section header table alignment")) __err__( ERROR_VERDEF_FORMAT, _("Format " "error: bad " "parameter " "in Verdef " "record")) __err__(ERROR_VERDEF_VERSION, _("Format error: unknown Verdef version")) __err__(ERROR_VERNEED_FORMAT, _("Format error: bad parameter in Verneed record")) __err__( ERROR_VERNEED_VERSION, _("Format " "error: " "unknown " "Verneed " "versio" "n")) __err__(ERROR_EHDR_SHNUM, _("Format error: bad e_shnum value")) __err__(ERROR_EHDR_SHENTSIZE, _("Format error: bad e_shentsize value")) __err__( ERROR_EHDR_PHENTSIZE, _("Form" "at " "erro" "r: " "bad " "e_" "phen" "tsiz" "e " "valu" "e")) __err__(ERROR_UNTERM, _("Format error: unterminated string in string table")) __err__(ERROR_SCN2SMALL, _("Layout error: section size too small for data")) __err__( ERROR_SCN_OVERLAP, _("Layout " "error: " "overlapp" "ing " "section" "s")) __err__(ERROR_MEM_ELF, _("Memory error: elf descriptor")) __err__(ERROR_MEM_ARSYMTAB, _("Memory error: archive symbol table")) __err__( ERROR_MEM_ARHDR, _("Memo" "ry " "erro" "r: " "arch" "ive " "memb" "er " "head" "er")) __err__(ERROR_MEM_EHDR, _("Memory error: ELF header")) __err__(ERROR_MEM_PHDR, _("Memory error: program header table")) __err__( ERROR_MEM_SHDR, _("Memory error: section header table")) __err__(ERROR_MEM_SCN, _("Memory error: section descriptor")) __err__( ERROR_MEM_SCNDATA, _("Memory error: section data")) __err__(ERROR_MEM_OUTBUF, _("Memory error: output file space")) __err__( ERROR_MEM_TEMPORARY, _("Memory error: temporary buffer")) __err__( ERROR_BADVALUE, _("GElf error: value out of range")) __err__( ERROR_BADINDEX, _("GElf error: index out of range")) __err__( ERROR_BADTYPE, _("GElf error: type mismatch")) __err__( ERROR_MEM_SYM, _("GElf error: not enough memory for GElf_Sym")) __err__( ERROR_MEM_DYN, _("GElf error: not enough memory for GElf_Dyn")) __err__( ERROR_MEM_RELA, _("GElf error: not enough memory for GElf_Rela")) __err__( ERROR_MEM_REL, _("GElf error: not enough memory for GElf_Rel")) qtrvsim-0.9.8/external/libelf/ext_types.h000066400000000000000000000177331467752164200205420ustar00rootroot00000000000000/* ext_types.h - external representation of ELF data types. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: ext_types.h,v 1.9 2008/05/23 08:15:34 michael Exp $ */ #ifndef _EXT_TYPES_H #define _EXT_TYPES_H #include "gelf.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Scalar data types */ typedef unsigned char __ext_Elf32_Addr[ELF32_FSZ_ADDR]; typedef unsigned char __ext_Elf32_Half[ELF32_FSZ_HALF]; typedef unsigned char __ext_Elf32_Off[ELF32_FSZ_OFF]; typedef unsigned char __ext_Elf32_Sword[ELF32_FSZ_SWORD]; typedef unsigned char __ext_Elf32_Word[ELF32_FSZ_WORD]; #if __LIBELF64 typedef unsigned char __ext_Elf32_Lword[8]; typedef unsigned char __ext_Elf64_Addr[ELF64_FSZ_ADDR]; typedef unsigned char __ext_Elf64_Half[ELF64_FSZ_HALF]; typedef unsigned char __ext_Elf64_Off[ELF64_FSZ_OFF]; typedef unsigned char __ext_Elf64_Sword[ELF64_FSZ_SWORD]; typedef unsigned char __ext_Elf64_Word[ELF64_FSZ_WORD]; typedef unsigned char __ext_Elf64_Sxword[ELF64_FSZ_SXWORD]; typedef unsigned char __ext_Elf64_Xword[ELF64_FSZ_XWORD]; typedef unsigned char __ext_Elf64_Lword[8]; #endif /* __LIBELF64 */ /* * ELF header */ typedef struct { unsigned char e_ident[EI_NIDENT]; __ext_Elf32_Half e_type; __ext_Elf32_Half e_machine; __ext_Elf32_Word e_version; __ext_Elf32_Addr e_entry; __ext_Elf32_Off e_phoff; __ext_Elf32_Off e_shoff; __ext_Elf32_Word e_flags; __ext_Elf32_Half e_ehsize; __ext_Elf32_Half e_phentsize; __ext_Elf32_Half e_phnum; __ext_Elf32_Half e_shentsize; __ext_Elf32_Half e_shnum; __ext_Elf32_Half e_shstrndx; } __ext_Elf32_Ehdr; #if __LIBELF64 typedef struct { unsigned char e_ident[EI_NIDENT]; __ext_Elf64_Half e_type; __ext_Elf64_Half e_machine; __ext_Elf64_Word e_version; __ext_Elf64_Addr e_entry; __ext_Elf64_Off e_phoff; __ext_Elf64_Off e_shoff; __ext_Elf64_Word e_flags; __ext_Elf64_Half e_ehsize; __ext_Elf64_Half e_phentsize; __ext_Elf64_Half e_phnum; __ext_Elf64_Half e_shentsize; __ext_Elf64_Half e_shnum; __ext_Elf64_Half e_shstrndx; } __ext_Elf64_Ehdr; #endif /* __LIBELF64 */ /* * Section header */ typedef struct { __ext_Elf32_Word sh_name; __ext_Elf32_Word sh_type; __ext_Elf32_Word sh_flags; __ext_Elf32_Addr sh_addr; __ext_Elf32_Off sh_offset; __ext_Elf32_Word sh_size; __ext_Elf32_Word sh_link; __ext_Elf32_Word sh_info; __ext_Elf32_Word sh_addralign; __ext_Elf32_Word sh_entsize; } __ext_Elf32_Shdr; #if __LIBELF64 typedef struct { __ext_Elf64_Word sh_name; __ext_Elf64_Word sh_type; __ext_Elf64_Xword sh_flags; __ext_Elf64_Addr sh_addr; __ext_Elf64_Off sh_offset; __ext_Elf64_Xword sh_size; __ext_Elf64_Word sh_link; __ext_Elf64_Word sh_info; __ext_Elf64_Xword sh_addralign; __ext_Elf64_Xword sh_entsize; } __ext_Elf64_Shdr; #endif /* __LIBELF64 */ /* * Symbol table */ typedef struct { __ext_Elf32_Word st_name; __ext_Elf32_Addr st_value; __ext_Elf32_Word st_size; unsigned char st_info; unsigned char st_other; __ext_Elf32_Half st_shndx; } __ext_Elf32_Sym; #if __LIBELF64 typedef struct { __ext_Elf64_Word st_name; unsigned char st_info; unsigned char st_other; __ext_Elf64_Half st_shndx; __ext_Elf64_Addr st_value; __ext_Elf64_Xword st_size; } __ext_Elf64_Sym; #endif /* __LIBELF64 */ /* * Relocation */ typedef struct { __ext_Elf32_Addr r_offset; __ext_Elf32_Word r_info; } __ext_Elf32_Rel; typedef struct { __ext_Elf32_Addr r_offset; __ext_Elf32_Word r_info; __ext_Elf32_Sword r_addend; } __ext_Elf32_Rela; #if __LIBELF64 typedef struct { __ext_Elf64_Addr r_offset; #if __LIBELF64_IRIX __ext_Elf64_Word r_sym; unsigned char r_ssym; unsigned char r_type3; unsigned char r_type2; unsigned char r_type; #else /* __LIBELF64_IRIX */ __ext_Elf64_Xword r_info; #endif /* __LIBELF64_IRIX */ } __ext_Elf64_Rel; typedef struct { __ext_Elf64_Addr r_offset; #if __LIBELF64_IRIX __ext_Elf64_Word r_sym; unsigned char r_ssym; unsigned char r_type3; unsigned char r_type2; unsigned char r_type; #else /* __LIBELF64_IRIX */ __ext_Elf64_Xword r_info; #endif /* __LIBELF64_IRIX */ __ext_Elf64_Sxword r_addend; } __ext_Elf64_Rela; #endif /* __LIBELF64 */ /* * Program header */ typedef struct { __ext_Elf32_Word p_type; __ext_Elf32_Off p_offset; __ext_Elf32_Addr p_vaddr; __ext_Elf32_Addr p_paddr; __ext_Elf32_Word p_filesz; __ext_Elf32_Word p_memsz; __ext_Elf32_Word p_flags; __ext_Elf32_Word p_align; } __ext_Elf32_Phdr; #if __LIBELF64 typedef struct { __ext_Elf64_Word p_type; __ext_Elf64_Word p_flags; __ext_Elf64_Off p_offset; __ext_Elf64_Addr p_vaddr; __ext_Elf64_Addr p_paddr; __ext_Elf64_Xword p_filesz; __ext_Elf64_Xword p_memsz; __ext_Elf64_Xword p_align; } __ext_Elf64_Phdr; #endif /* __LIBELF64 */ /* * Dynamic structure */ typedef struct { __ext_Elf32_Sword d_tag; union { __ext_Elf32_Word d_val; __ext_Elf32_Addr d_ptr; } d_un; } __ext_Elf32_Dyn; #if __LIBELF64 typedef struct { __ext_Elf64_Sxword d_tag; union { __ext_Elf64_Xword d_val; __ext_Elf64_Addr d_ptr; } d_un; } __ext_Elf64_Dyn; #endif /* __LIBELF64 */ /* * Version definitions */ typedef struct { __ext_Elf32_Half vd_version; __ext_Elf32_Half vd_flags; __ext_Elf32_Half vd_ndx; __ext_Elf32_Half vd_cnt; __ext_Elf32_Word vd_hash; __ext_Elf32_Word vd_aux; __ext_Elf32_Word vd_next; } __ext_Elf32_Verdef; typedef struct { __ext_Elf32_Word vda_name; __ext_Elf32_Word vda_next; } __ext_Elf32_Verdaux; typedef struct { __ext_Elf32_Half vn_version; __ext_Elf32_Half vn_cnt; __ext_Elf32_Word vn_file; __ext_Elf32_Word vn_aux; __ext_Elf32_Word vn_next; } __ext_Elf32_Verneed; typedef struct { __ext_Elf32_Word vna_hash; __ext_Elf32_Half vna_flags; __ext_Elf32_Half vna_other; __ext_Elf32_Word vna_name; __ext_Elf32_Word vna_next; } __ext_Elf32_Vernaux; #if __LIBELF64 typedef struct { __ext_Elf64_Half vd_version; __ext_Elf64_Half vd_flags; __ext_Elf64_Half vd_ndx; __ext_Elf64_Half vd_cnt; __ext_Elf64_Word vd_hash; __ext_Elf64_Word vd_aux; __ext_Elf64_Word vd_next; } __ext_Elf64_Verdef; typedef struct { __ext_Elf64_Word vda_name; __ext_Elf64_Word vda_next; } __ext_Elf64_Verdaux; typedef struct { __ext_Elf64_Half vn_version; __ext_Elf64_Half vn_cnt; __ext_Elf64_Word vn_file; __ext_Elf64_Word vn_aux; __ext_Elf64_Word vn_next; } __ext_Elf64_Verneed; typedef struct { __ext_Elf64_Word vna_hash; __ext_Elf64_Half vna_flags; __ext_Elf64_Half vna_other; __ext_Elf64_Word vna_name; __ext_Elf64_Word vna_next; } __ext_Elf64_Vernaux; #endif /* __LIBELF64 */ /* * Move section */ #if __LIBELF64 typedef struct { __ext_Elf32_Lword m_value; __ext_Elf32_Word m_info; __ext_Elf32_Word m_poffset; __ext_Elf32_Half m_repeat; __ext_Elf32_Half m_stride; } __ext_Elf32_Move; typedef struct { __ext_Elf64_Lword m_value; __ext_Elf64_Xword m_info; __ext_Elf64_Xword m_poffset; __ext_Elf64_Half m_repeat; __ext_Elf64_Half m_stride; } __ext_Elf64_Move; #endif /* __LIBELF64 */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _EXT_TYPES_H */ qtrvsim-0.9.8/external/libelf/fill.c000066400000000000000000000017511467752164200174300ustar00rootroot00000000000000/* fill.c - implementation of the elf_fill(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: fill.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ void elf_fill(int fill) { _elf_fill = fill; } qtrvsim-0.9.8/external/libelf/flag.c000066400000000000000000000046351467752164200174170ustar00rootroot00000000000000/* flag.c - implementation of the elf_flag*(3) functions. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: flag.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ static unsigned _elf_flag(unsigned *f, Elf_Cmd cmd, unsigned flags) { if (cmd == ELF_C_SET) { return *f |= flags; } if (cmd == ELF_C_CLR) { return *f &= ~flags; } seterr(ERROR_INVALID_CMD); return 0; } unsigned elf_flagdata(Elf_Data *data, Elf_Cmd cmd, unsigned flags) { Scn_Data *sd = (Scn_Data *)data; if (!sd) { return 0; } elf_assert(sd->sd_magic == DATA_MAGIC); return _elf_flag(&sd->sd_data_flags, cmd, flags); } unsigned elf_flagehdr(Elf *elf, Elf_Cmd cmd, unsigned flags) { if (!elf) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); return _elf_flag(&elf->e_ehdr_flags, cmd, flags); } unsigned elf_flagelf(Elf *elf, Elf_Cmd cmd, unsigned flags) { if (!elf) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); return _elf_flag(&elf->e_elf_flags, cmd, flags); } unsigned elf_flagphdr(Elf *elf, Elf_Cmd cmd, unsigned flags) { if (!elf) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); return _elf_flag(&elf->e_phdr_flags, cmd, flags); } unsigned elf_flagscn(Elf_Scn *scn, Elf_Cmd cmd, unsigned flags) { if (!scn) { return 0; } elf_assert(scn->s_magic == SCN_MAGIC); return _elf_flag(&scn->s_scn_flags, cmd, flags); } unsigned elf_flagshdr(Elf_Scn *scn, Elf_Cmd cmd, unsigned flags) { if (!scn) { return 0; } elf_assert(scn->s_magic == SCN_MAGIC); return _elf_flag(&scn->s_shdr_flags, cmd, flags); } qtrvsim-0.9.8/external/libelf/gelf.h000066400000000000000000000117371467752164200174310ustar00rootroot00000000000000/* * gelf.h - public header file for libelf. * Copyright (C) 2000 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: gelf.h,v 1.16 2008/05/23 08:15:34 michael Exp $ */ #ifndef _GELF_H #define _GELF_H #if __LIBELF_INTERNAL__ #include #else /* __LIBELF_INTERNAL__ */ #include #endif /* __LIBELF_INTERNAL__ */ #if __LIBELF_NEED_LINK_H #include #elif __LIBELF_NEED_SYS_LINK_H #include #endif /* __LIBELF_NEED_LINK_H */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef __P #if (__STDC__ + 0) || defined(__cplusplus) || defined(_WIN32) #define __P(args) args #else /* __STDC__ || defined(__cplusplus) */ #define __P(args) () #endif /* __STDC__ || defined(__cplusplus) */ #endif /* __P */ #if !__LIBELF64 #error "GElf is not supported on this system." #else /* __LIBELF64 */ typedef Elf64_Addr GElf_Addr; typedef Elf64_Half GElf_Half; typedef Elf64_Off GElf_Off; typedef Elf64_Sword GElf_Sword; typedef Elf64_Word GElf_Word; typedef Elf64_Sxword GElf_Sxword; typedef Elf64_Xword GElf_Xword; typedef Elf64_Ehdr GElf_Ehdr; typedef Elf64_Phdr GElf_Phdr; typedef Elf64_Shdr GElf_Shdr; typedef Elf64_Dyn GElf_Dyn; typedef Elf64_Rel GElf_Rel; typedef Elf64_Rela GElf_Rela; typedef Elf64_Sym GElf_Sym; /* * Symbol versioning */ #if __LIBELF_SYMBOL_VERSIONS typedef Elf64_Verdef GElf_Verdef; typedef Elf64_Verneed GElf_Verneed; typedef Elf64_Verdaux GElf_Verdaux; typedef Elf64_Vernaux GElf_Vernaux; #endif /* __LIBELF_SYMBOL_VERSIONS */ /* * These types aren't implemented (yet) * typedef Elf64_Move GElf_Move; typedef Elf64_Syminfo GElf_Syminfo; */ /* * Generic macros */ #define GELF_ST_BIND ELF64_ST_BIND #define GELF_ST_TYPE ELF64_ST_TYPE #define GELF_ST_INFO ELF64_ST_INFO #define GELF_R_TYPE ELF64_R_TYPE #define GELF_R_SYM ELF64_R_SYM #define GELF_R_INFO ELF64_R_INFO /* * Function declarations */ extern int gelf_getclass __P((Elf * __elf)); extern size_t gelf_fsize __P((Elf * __elf, Elf_Type __type, size_t __count, unsigned __ver)); extern Elf_Data *gelf_xlatetof __P( (Elf * __elf, Elf_Data *__dst, const Elf_Data *__src, unsigned __encode)); extern Elf_Data *gelf_xlatetom __P( (Elf * __elf, Elf_Data *__dst, const Elf_Data *__src, unsigned __encode)); extern GElf_Ehdr *gelf_getehdr __P((Elf * __elf, GElf_Ehdr *__dst)); extern int gelf_update_ehdr __P((Elf * __elf, GElf_Ehdr *__src)); extern unsigned long gelf_newehdr __P((Elf * __elf, int __elfclass)); extern GElf_Phdr *gelf_getphdr __P((Elf * __elf, int ndx, GElf_Phdr *__dst)); extern int gelf_update_phdr __P((Elf * __elf, int ndx, GElf_Phdr *__src)); extern unsigned long gelf_newphdr __P((Elf * __elf, size_t __phnum)); extern GElf_Shdr *gelf_getshdr __P((Elf_Scn * __scn, GElf_Shdr *__dst)); extern int gelf_update_shdr __P((Elf_Scn * __scn, GElf_Shdr *__src)); extern GElf_Dyn *gelf_getdyn __P((Elf_Data * __src, int __ndx, GElf_Dyn *__dst)); extern int gelf_update_dyn __P((Elf_Data * __dst, int __ndx, GElf_Dyn *__src)); extern GElf_Rel *gelf_getrel __P((Elf_Data * __src, int __ndx, GElf_Rel *__dst)); extern int gelf_update_rel __P((Elf_Data * __dst, int __ndx, GElf_Rel *__src)); extern GElf_Rela * gelf_getrela __P((Elf_Data * __src, int __ndx, GElf_Rela *__dst)); extern int gelf_update_rela __P((Elf_Data * __dst, int __ndx, GElf_Rela *__src)); extern GElf_Sym *gelf_getsym __P((Elf_Data * __src, int __ndx, GElf_Sym *__dst)); extern int gelf_update_sym __P((Elf_Data * __dst, int __ndx, GElf_Sym *__src)); extern long gelf_checksum __P((Elf * __elf)); /* * These functions aren't implemented (yet) * extern GElf_Move *gelf_getmove __P((Elf_Data *__src, int __ndx, GElf_Move *__src)); extern int gelf_update_move __P((Elf_Data *__dst, int __ndx, GElf_Move *__src)); * extern GElf_Syminfo* gelf_getsyminfo __P((Elf_Data *__src, int __ndx, GElf_Syminfo *__dst)); extern int gelf_update_syminfo __P((Elf_Data *__dst, int __ndx, GElf_Syminfo *__src)); */ /* * Extensions (not available in other versions of libelf) */ extern size_t gelf_msize __P((Elf * __elf, Elf_Type __type, size_t __count, unsigned __ver)); #endif /* __LIBELF64 */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _GELF_H */ qtrvsim-0.9.8/external/libelf/gelfehdr.c000066400000000000000000000113651467752164200202640ustar00rootroot00000000000000/* * gelfehdr.c - gelf_* translation functions. * Copyright (C) 2000 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: gelfehdr.c,v 1.9 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #define check_and_copy(type, d, s, name, eret) \ do { \ if (sizeof((d)->name) < sizeof((s)->name) \ && (type)(s)->name != (s)->name) { \ seterr(ERROR_BADVALUE); \ return (eret); \ } \ (d)->name = (type)(s)->name; \ } while (0) GElf_Ehdr *gelf_getehdr(Elf *elf, GElf_Ehdr *dst) { GElf_Ehdr buf; char *tmp; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getehdr(elf, elf->e_class); if (!tmp) { return NULL; } if (!dst) { dst = &buf; } if (elf->e_class == ELFCLASS64) { *dst = *(Elf64_Ehdr *)tmp; } else if (elf->e_class == ELFCLASS32) { Elf32_Ehdr *src = (Elf32_Ehdr *)tmp; memcpy(dst->e_ident, src->e_ident, EI_NIDENT); check_and_copy(GElf_Half, dst, src, e_type, NULL); check_and_copy(GElf_Half, dst, src, e_machine, NULL); check_and_copy(GElf_Word, dst, src, e_version, NULL); check_and_copy(GElf_Addr, dst, src, e_entry, NULL); check_and_copy(GElf_Off, dst, src, e_phoff, NULL); check_and_copy(GElf_Off, dst, src, e_shoff, NULL); check_and_copy(GElf_Word, dst, src, e_flags, NULL); check_and_copy(GElf_Half, dst, src, e_ehsize, NULL); check_and_copy(GElf_Half, dst, src, e_phentsize, NULL); check_and_copy(GElf_Half, dst, src, e_phnum, NULL); check_and_copy(GElf_Half, dst, src, e_shentsize, NULL); check_and_copy(GElf_Half, dst, src, e_shnum, NULL); check_and_copy(GElf_Half, dst, src, e_shstrndx, NULL); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return NULL; } if (dst == &buf) { dst = (GElf_Ehdr *)malloc(sizeof(GElf_Ehdr)); if (!dst) { seterr(ERROR_MEM_EHDR); return NULL; } *dst = buf; } return dst; } int gelf_update_ehdr(Elf *elf, GElf_Ehdr *src) { char *tmp; if (!elf || !src) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getehdr(elf, elf->e_class); if (!tmp) { return 0; } if (elf->e_class == ELFCLASS64) { *(Elf64_Ehdr *)tmp = *src; } else if (elf->e_class == ELFCLASS32) { Elf32_Ehdr *dst = (Elf32_Ehdr *)tmp; memcpy(dst->e_ident, src->e_ident, EI_NIDENT); check_and_copy(Elf32_Half, dst, src, e_type, 0); check_and_copy(Elf32_Half, dst, src, e_machine, 0); check_and_copy(Elf32_Word, dst, src, e_version, 0); check_and_copy(Elf32_Addr, dst, src, e_entry, 0); check_and_copy(Elf32_Off, dst, src, e_phoff, 0); check_and_copy(Elf32_Off, dst, src, e_shoff, 0); check_and_copy(Elf32_Word, dst, src, e_flags, 0); check_and_copy(Elf32_Half, dst, src, e_ehsize, 0); check_and_copy(Elf32_Half, dst, src, e_phentsize, 0); check_and_copy(Elf32_Half, dst, src, e_phnum, 0); check_and_copy(Elf32_Half, dst, src, e_shentsize, 0); check_and_copy(Elf32_Half, dst, src, e_shnum, 0); check_and_copy(Elf32_Half, dst, src, e_shstrndx, 0); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return 0; } return 1; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/gelfphdr.c000066400000000000000000000111301467752164200202650ustar00rootroot00000000000000/* * gelfphdr.c - gelf_* translation functions. * Copyright (C) 2000 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: gelfphdr.c,v 1.9 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #define check_and_copy(type, d, s, name, eret) \ do { \ if (sizeof((d)->name) < sizeof((s)->name) \ && (type)(s)->name != (s)->name) { \ seterr(ERROR_BADVALUE); \ return (eret); \ } \ (d)->name = (type)(s)->name; \ } while (0) GElf_Phdr *gelf_getphdr(Elf *elf, int ndx, GElf_Phdr *dst) { GElf_Phdr buf; char *tmp; size_t n; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getphdr(elf, elf->e_class); if (!tmp) { return NULL; } if (ndx < 0 || ndx >= elf->e_phnum) { seterr(ERROR_BADINDEX); return NULL; } n = _msize(elf->e_class, _elf_version, ELF_T_PHDR); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (!dst) { dst = &buf; } if (elf->e_class == ELFCLASS64) { *dst = *(Elf64_Phdr *)(tmp + ndx * n); } else if (elf->e_class == ELFCLASS32) { Elf32_Phdr *src = (Elf32_Phdr *)(tmp + ndx * n); check_and_copy(GElf_Word, dst, src, p_type, NULL); check_and_copy(GElf_Word, dst, src, p_flags, NULL); check_and_copy(GElf_Off, dst, src, p_offset, NULL); check_and_copy(GElf_Addr, dst, src, p_vaddr, NULL); check_and_copy(GElf_Addr, dst, src, p_paddr, NULL); check_and_copy(GElf_Xword, dst, src, p_filesz, NULL); check_and_copy(GElf_Xword, dst, src, p_memsz, NULL); check_and_copy(GElf_Xword, dst, src, p_align, NULL); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return NULL; } if (dst == &buf) { dst = (GElf_Phdr *)malloc(sizeof(GElf_Phdr)); if (!dst) { seterr(ERROR_MEM_PHDR); return NULL; } *dst = buf; } return dst; } int gelf_update_phdr(Elf *elf, int ndx, GElf_Phdr *src) { char *tmp; size_t n; if (!elf || !src) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); tmp = _elf_getphdr(elf, elf->e_class); if (!tmp) { return 0; } if (ndx < 0 || ndx >= elf->e_phnum) { seterr(ERROR_BADINDEX); return 0; } n = _msize(elf->e_class, _elf_version, ELF_T_PHDR); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return 0; } if (elf->e_class == ELFCLASS64) { *(Elf64_Phdr *)(tmp + ndx * n) = *src; } else if (elf->e_class == ELFCLASS32) { Elf32_Phdr *dst = (Elf32_Phdr *)(tmp + ndx * n); check_and_copy(Elf32_Word, dst, src, p_type, 0); check_and_copy(Elf32_Off, dst, src, p_offset, 0); check_and_copy(Elf32_Addr, dst, src, p_vaddr, 0); check_and_copy(Elf32_Addr, dst, src, p_paddr, 0); check_and_copy(Elf32_Word, dst, src, p_filesz, 0); check_and_copy(Elf32_Word, dst, src, p_memsz, 0); check_and_copy(Elf32_Word, dst, src, p_flags, 0); check_and_copy(Elf32_Word, dst, src, p_align, 0); } else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return 0; } return 1; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/gelfshdr.c000066400000000000000000000104321467752164200202740ustar00rootroot00000000000000/* * gelfshdr.c - gelf_* translation functions. * Copyright (C) 2000 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: gelfshdr.c,v 1.10 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #define check_and_copy(type, d, s, name, eret) \ do { \ if (sizeof((d)->name) < sizeof((s)->name) \ && (type)(s)->name != (s)->name) { \ seterr(ERROR_BADVALUE); \ return (eret); \ } \ (d)->name = (type)(s)->name; \ } while (0) GElf_Shdr *gelf_getshdr(Elf_Scn *scn, GElf_Shdr *dst) { GElf_Shdr buf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (!dst) { dst = &buf; } if (scn->s_elf->e_class == ELFCLASS64) { *dst = scn->s_shdr64; } else if (scn->s_elf->e_class == ELFCLASS32) { Elf32_Shdr *src = &scn->s_shdr32; check_and_copy(GElf_Word, dst, src, sh_name, NULL); check_and_copy(GElf_Word, dst, src, sh_type, NULL); check_and_copy(GElf_Xword, dst, src, sh_flags, NULL); check_and_copy(GElf_Addr, dst, src, sh_addr, NULL); check_and_copy(GElf_Off, dst, src, sh_offset, NULL); check_and_copy(GElf_Xword, dst, src, sh_size, NULL); check_and_copy(GElf_Word, dst, src, sh_link, NULL); check_and_copy(GElf_Word, dst, src, sh_info, NULL); check_and_copy(GElf_Xword, dst, src, sh_addralign, NULL); check_and_copy(GElf_Xword, dst, src, sh_entsize, NULL); } else { if (valid_class(scn->s_elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return NULL; } if (dst == &buf) { dst = (GElf_Shdr *)malloc(sizeof(GElf_Shdr)); if (!dst) { seterr(ERROR_MEM_SHDR); return NULL; } *dst = buf; } return dst; } int gelf_update_shdr(Elf_Scn *scn, GElf_Shdr *src) { if (!scn || !src) { return 0; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf); elf_assert(scn->s_elf->e_magic == ELF_MAGIC); if (scn->s_elf->e_class == ELFCLASS64) { scn->s_shdr64 = *src; } else if (scn->s_elf->e_class == ELFCLASS32) { Elf32_Shdr *dst = &scn->s_shdr32; check_and_copy(Elf32_Word, dst, src, sh_name, 0); check_and_copy(Elf32_Word, dst, src, sh_type, 0); check_and_copy(Elf32_Word, dst, src, sh_flags, 0); check_and_copy(Elf32_Addr, dst, src, sh_addr, 0); check_and_copy(Elf32_Off, dst, src, sh_offset, 0); check_and_copy(Elf32_Word, dst, src, sh_size, 0); check_and_copy(Elf32_Word, dst, src, sh_link, 0); check_and_copy(Elf32_Word, dst, src, sh_info, 0); check_and_copy(Elf32_Word, dst, src, sh_addralign, 0); check_and_copy(Elf32_Word, dst, src, sh_entsize, 0); } else { if (valid_class(scn->s_elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return 0; } return 1; } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/gelftrans.c000066400000000000000000000252731467752164200204740ustar00rootroot00000000000000/* gelftrans.c - gelf_* translation functions. Copyright (C) 2000 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: gelftrans.c,v 1.10 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ #define check_and_copy(type, d, s, name, eret) \ do { \ if (sizeof((d)->name) < sizeof((s)->name) \ && (type)(s)->name != (s)->name) { \ seterr(ERROR_BADVALUE); \ return (eret); \ } \ (d)->name = (type)(s)->name; \ } while (0) /* * These macros are missing on some Linux systems */ #if !defined(ELF32_R_SYM) || !defined(ELF32_R_TYPE) \ || !defined(ELF32_R_INFO) #undef ELF32_R_SYM #undef ELF32_R_TYPE #undef ELF32_R_INFO #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char)(i)) #define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) #endif /* !defined(...) */ #if !defined(ELF64_R_SYM) || !defined(ELF64_R_TYPE) \ || !defined(ELF64_R_INFO) #undef ELF64_R_SYM #undef ELF64_R_TYPE #undef ELF64_R_INFO #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffffL) #define ELF64_R_INFO(s, t) \ (((Elf64_Xword)(s) << 32) + ((t)&0xffffffffL)) #endif /* !defined(...) */ static char * get_addr_and_class(const Elf_Data *data, int ndx, Elf_Type type, unsigned *cls) { Scn_Data *sd = (Scn_Data *)data; Elf_Scn *scn; Elf *elf; size_t n; if (!sd) { return NULL; } elf_assert(sd->sd_magic == DATA_MAGIC); scn = sd->sd_scn; elf_assert(scn); elf_assert(scn->s_magic == SCN_MAGIC); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return NULL; } if (!valid_class(elf->e_class)) { seterr(ERROR_UNKNOWN_CLASS); return NULL; } if (data->d_type != type) { seterr(ERROR_BADTYPE); return NULL; } n = _msize(elf->e_class, data->d_version, type); if (n == 0) { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (ndx < 0 || data->d_size < (ndx + 1) * n) { seterr(ERROR_BADINDEX); return NULL; } if (!data->d_buf) { seterr(ERROR_NULLBUF); return NULL; } if (cls) { *cls = elf->e_class; } return (char *)data->d_buf + n * ndx; } GElf_Sym *gelf_getsym(Elf_Data *src, int ndx, GElf_Sym *dst) { GElf_Sym buf; unsigned cls; char *tmp; if (!dst) { dst = &buf; } tmp = get_addr_and_class(src, ndx, ELF_T_SYM, &cls); if (!tmp) { return NULL; } if (cls == ELFCLASS64) { *dst = *(Elf64_Sym *)tmp; } else if (cls == ELFCLASS32) { Elf32_Sym *src = (Elf32_Sym *)tmp; check_and_copy(GElf_Word, dst, src, st_name, NULL); check_and_copy(unsigned char, dst, src, st_info, NULL); check_and_copy(unsigned char, dst, src, st_other, NULL); check_and_copy(GElf_Half, dst, src, st_shndx, NULL); check_and_copy(GElf_Addr, dst, src, st_value, NULL); check_and_copy(GElf_Xword, dst, src, st_size, NULL); } else { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dst == &buf) { dst = (GElf_Sym *)malloc(sizeof(GElf_Sym)); if (!dst) { seterr(ERROR_MEM_SYM); return NULL; } *dst = buf; } return dst; } int gelf_update_sym(Elf_Data *dst, int ndx, GElf_Sym *src) { unsigned cls; char *tmp; tmp = get_addr_and_class(dst, ndx, ELF_T_SYM, &cls); if (!tmp) { return 0; } if (cls == ELFCLASS64) { *(Elf64_Sym *)tmp = *src; } else if (cls == ELFCLASS32) { Elf32_Sym *dst = (Elf32_Sym *)tmp; check_and_copy(Elf32_Word, dst, src, st_name, 0); check_and_copy(Elf32_Addr, dst, src, st_value, 0); check_and_copy(Elf32_Word, dst, src, st_size, 0); check_and_copy(unsigned char, dst, src, st_info, 0); check_and_copy(unsigned char, dst, src, st_other, 0); check_and_copy(Elf32_Half, dst, src, st_shndx, 0); } else { seterr(ERROR_UNIMPLEMENTED); return 0; } return 1; } GElf_Dyn *gelf_getdyn(Elf_Data *src, int ndx, GElf_Dyn *dst) { GElf_Dyn buf; unsigned cls; char *tmp; if (!dst) { dst = &buf; } tmp = get_addr_and_class(src, ndx, ELF_T_DYN, &cls); if (!tmp) { return NULL; } if (cls == ELFCLASS64) { *dst = *(Elf64_Dyn *)tmp; } else if (cls == ELFCLASS32) { Elf32_Dyn *src = (Elf32_Dyn *)tmp; check_and_copy(GElf_Sxword, dst, src, d_tag, NULL); check_and_copy(GElf_Xword, dst, src, d_un.d_val, NULL); } else { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dst == &buf) { dst = (GElf_Dyn *)malloc(sizeof(GElf_Dyn)); if (!dst) { seterr(ERROR_MEM_DYN); return NULL; } *dst = buf; } return dst; } int gelf_update_dyn(Elf_Data *dst, int ndx, GElf_Dyn *src) { unsigned cls; char *tmp; tmp = get_addr_and_class(dst, ndx, ELF_T_DYN, &cls); if (!tmp) { return 0; } if (cls == ELFCLASS64) { *(Elf64_Dyn *)tmp = *src; } else if (cls == ELFCLASS32) { Elf32_Dyn *dst = (Elf32_Dyn *)tmp; check_and_copy(Elf32_Sword, dst, src, d_tag, 0); check_and_copy(Elf32_Word, dst, src, d_un.d_val, 0); } else { seterr(ERROR_UNIMPLEMENTED); return 0; } return 1; } GElf_Rela *gelf_getrela(Elf_Data *src, int ndx, GElf_Rela *dst) { GElf_Rela buf; unsigned cls; char *tmp; if (!dst) { dst = &buf; } tmp = get_addr_and_class(src, ndx, ELF_T_RELA, &cls); if (!tmp) { return NULL; } if (cls == ELFCLASS64) { *dst = *(Elf64_Rela *)tmp; } else if (cls == ELFCLASS32) { Elf32_Rela *src = (Elf32_Rela *)tmp; check_and_copy(GElf_Addr, dst, src, r_offset, NULL); dst->r_info = ELF64_R_INFO( (Elf64_Xword)ELF32_R_SYM(src->r_info), (Elf64_Xword)ELF32_R_TYPE(src->r_info)); check_and_copy(GElf_Sxword, dst, src, r_addend, NULL); } else { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dst == &buf) { dst = (GElf_Rela *)malloc(sizeof(GElf_Rela)); if (!dst) { seterr(ERROR_MEM_RELA); return NULL; } *dst = buf; } return dst; } int gelf_update_rela(Elf_Data *dst, int ndx, GElf_Rela *src) { unsigned cls; char *tmp; tmp = get_addr_and_class(dst, ndx, ELF_T_RELA, &cls); if (!tmp) { return 0; } if (cls == ELFCLASS64) { *(Elf64_Rela *)tmp = *src; } else if (cls == ELFCLASS32) { Elf32_Rela *dst = (Elf32_Rela *)tmp; check_and_copy(Elf32_Addr, dst, src, r_offset, 0); if (ELF64_R_SYM(src->r_info) > 0xffffffUL || ELF64_R_TYPE(src->r_info) > 0xffUL) { seterr(ERROR_BADVALUE); return 0; } dst->r_info = ELF32_R_INFO( (Elf32_Word)ELF64_R_SYM(src->r_info), (Elf32_Word)ELF64_R_TYPE(src->r_info)); check_and_copy(Elf32_Sword, dst, src, r_addend, 0); } else { seterr(ERROR_UNIMPLEMENTED); return 0; } return 1; } GElf_Rel *gelf_getrel(Elf_Data *src, int ndx, GElf_Rel *dst) { GElf_Rel buf; unsigned cls; char *tmp; if (!dst) { dst = &buf; } tmp = get_addr_and_class(src, ndx, ELF_T_REL, &cls); if (!tmp) { return NULL; } if (cls == ELFCLASS64) { *dst = *(Elf64_Rel *)tmp; } else if (cls == ELFCLASS32) { Elf32_Rel *src = (Elf32_Rel *)tmp; check_and_copy(GElf_Addr, dst, src, r_offset, NULL); dst->r_info = ELF64_R_INFO( (Elf64_Xword)ELF32_R_SYM(src->r_info), (Elf64_Xword)ELF32_R_TYPE(src->r_info)); } else { seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dst == &buf) { dst = (GElf_Rel *)malloc(sizeof(GElf_Rel)); if (!dst) { seterr(ERROR_MEM_REL); return NULL; } *dst = buf; } return dst; } int gelf_update_rel(Elf_Data *dst, int ndx, GElf_Rel *src) { unsigned cls; char *tmp; tmp = get_addr_and_class(dst, ndx, ELF_T_REL, &cls); if (!tmp) { return 0; } if (cls == ELFCLASS64) { *(Elf64_Rel *)tmp = *src; } else if (cls == ELFCLASS32) { Elf32_Rel *dst = (Elf32_Rel *)tmp; check_and_copy(Elf32_Addr, dst, src, r_offset, 0); if (ELF64_R_SYM(src->r_info) > 0xffffffUL || ELF64_R_TYPE(src->r_info) > 0xffUL) { seterr(ERROR_BADVALUE); return 0; } dst->r_info = ELF32_R_INFO( (Elf32_Word)ELF64_R_SYM(src->r_info), (Elf32_Word)ELF64_R_TYPE(src->r_info)); } else { seterr(ERROR_UNIMPLEMENTED); return 0; } return 1; } #if 0 GElf_Syminfo* gelf_getsyminfo(Elf_Data *src, int ndx, GElf_Syminfo *dst) { seterr(ERROR_UNIMPLEMENTED); return NULL; } int gelf_update_syminfo(Elf_Data *dst, int ndx, GElf_Syminfo *src) { seterr(ERROR_UNIMPLEMENTED); return 0; } GElf_Move* gelf_getmove(Elf_Data *src, int ndx, GElf_Move *src) { seterr(ERROR_UNIMPLEMENTED); return NULL; } int gelf_update_move(Elf_Data *dst, int ndx, GElf_Move *src) { seterr(ERROR_UNIMPLEMENTED); return 0; } #endif #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/getarhdr.c000066400000000000000000000022511467752164200202760ustar00rootroot00000000000000/* getarhdr.c - implementation of the elf_getarhdr(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getarhdr.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ Elf_Arhdr *elf_getarhdr(Elf *elf) { if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_arhdr) { return elf->e_arhdr; } seterr(ERROR_NOTARCHIVE); return NULL; } qtrvsim-0.9.8/external/libelf/getaroff.c000066400000000000000000000025661467752164200203040ustar00rootroot00000000000000/* * getaroff.c - implementation of the elf_getaroff(3) function. * Copyright (C) 2009 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getaroff.c,v 1.1 2009/11/01 13:04:19 michael Exp $"; #endif /* lint */ off_t elf_getaroff(Elf *elf) { Elf *ref; if (!elf) { return (off_t)-1; } elf_assert(elf->e_magic == ELF_MAGIC); if (!(ref = elf->e_parent)) { return (off_t)-1; } elf_assert(ref->e_magic == ELF_MAGIC); elf_assert(elf->e_base >= ref->e_base + SARMAG + sizeof(struct ar_hdr)); return (off_t)(elf->e_base - ref->e_base - sizeof(struct ar_hdr)); } qtrvsim-0.9.8/external/libelf/getarsym.c000066400000000000000000000052521467752164200203350ustar00rootroot00000000000000/* * getarsym.c - implementation of the elf_getarsym(3) function. * Copyright (C) 1995 - 1998, 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getarsym.c,v 1.9 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ Elf_Arsym *elf_getarsym(Elf *elf, size_t *ptr) { Elf_Arsym *syms; size_t count; size_t tmp; size_t i; char *s; char *e; if (!ptr) { ptr = &tmp; } *ptr = 0; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_AR) { seterr(ERROR_NOTARCHIVE); return NULL; } if (elf->e_symtab && !elf->e_free_syms) { if (elf->e_symlen < 4) { seterr(ERROR_SIZE_ARSYMTAB); return NULL; } count = __load_u32M(elf->e_symtab); if (elf->e_symlen < 4 * (count + 1)) { seterr(ERROR_SIZE_ARSYMTAB); return NULL; } if (!(syms = (Elf_Arsym *)malloc((count + 1) * sizeof(*syms)))) { seterr(ERROR_MEM_ARSYMTAB); return NULL; } s = elf->e_symtab + 4 * (count + 1); e = elf->e_symtab + elf->e_symlen; for (i = 0; i < count; i++, s++) { syms[i].as_name = s; while (s < e && *s) { s++; } if (s >= e) { seterr(ERROR_SIZE_ARSYMTAB); free(syms); return NULL; } elf_assert(!*s); syms[i].as_hash = elf_hash((unsigned char *)syms[i].as_name); syms[i].as_off = __load_u32M(elf->e_symtab + 4 * (i + 1)); } syms[count].as_name = NULL; syms[count].as_hash = ~0UL; syms[count].as_off = 0; elf->e_symtab = (char *)syms; elf->e_symlen = count + 1; elf->e_free_syms = 1; } *ptr = elf->e_symlen; return (Elf_Arsym *)elf->e_symtab; } qtrvsim-0.9.8/external/libelf/getbase.c000066400000000000000000000021231467752164200201060ustar00rootroot00000000000000/* getbase.c - implementation of the elf_getbase(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getbase.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ off_t elf_getbase(Elf *elf) { if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); return (off_t)elf->e_base; } qtrvsim-0.9.8/external/libelf/getdata.c000066400000000000000000000102261467752164200201100ustar00rootroot00000000000000/* getdata.c - implementation of the elf_getdata(3) function. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getdata.c,v 1.13 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ static Elf_Data *_elf_cook_scn(Elf *elf, Elf_Scn *scn, Scn_Data *sd) { Elf_Data dst; Elf_Data src; int flag = 0; size_t dlen; elf_assert(elf->e_data); /* * Prepare source */ src = sd->sd_data; src.d_version = elf->e_version; if (elf->e_rawdata) { src.d_buf = elf->e_rawdata + scn->s_offset; } else { src.d_buf = elf->e_data + scn->s_offset; } /* * Prepare destination (needs prepared source!) */ dst = sd->sd_data; if (elf->e_class == ELFCLASS32) { dlen = _elf32_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { dlen = _elf64_xltsize(&src, dst.d_version, elf->e_encoding, 0); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return NULL; } if (dlen == (size_t)-1) { return NULL; } dst.d_size = dlen; if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) { dst.d_buf = elf->e_data + scn->s_offset; } else if (!(dst.d_buf = malloc(dst.d_size))) { seterr(ERROR_MEM_SCNDATA); return NULL; } else { flag = 1; } /* * Translate data */ if (_elf_xlatetom(elf, &dst, &src)) { sd->sd_memdata = (char *)dst.d_buf; sd->sd_data = dst; if (!(sd->sd_free_data = flag)) { elf->e_cooked = 1; } return &sd->sd_data; } if (flag) { free(dst.d_buf); } return NULL; } Elf_Data *elf_getdata(Elf_Scn *scn, Elf_Data *data) { Scn_Data *sd; Elf *elf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); if (scn->s_index == SHN_UNDEF) { seterr(ERROR_NULLSCN); } else if (data) { for (sd = scn->s_data_1; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (data == &sd->sd_data) { /* * sd_link allocated by elf_newdata(). */ return &sd->sd_link->sd_data; } } seterr(ERROR_SCNDATAMISMATCH); } else if ((sd = scn->s_data_1)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (sd->sd_freeme) { /* allocated by elf_newdata() */ return &sd->sd_data; } else if (scn->s_type == SHT_NULL) { seterr(ERROR_NULLSCN); } else if (sd->sd_memdata) { /* already cooked */ return &sd->sd_data; } else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) { seterr(ERROR_OUTSIDE); } else if (scn->s_type == SHT_NOBITS || !scn->s_size) { /* no data to read */ return &sd->sd_data; } else if (scn->s_offset + scn->s_size > elf->e_size) { seterr(ERROR_TRUNC_SCN); } else if (valid_class(elf->e_class)) { return _elf_cook_scn(elf, scn, sd); } else { seterr(ERROR_UNKNOWN_CLASS); } } return NULL; } qtrvsim-0.9.8/external/libelf/getident.c000066400000000000000000000025761467752164200203130ustar00rootroot00000000000000/* getident.c - implementation of the elf_getident(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getident.c,v 1.7 2008/05/23 08:15:34 michael Exp $"; #endif /* lint */ char *elf_getident(Elf *elf, size_t *ptr) { size_t tmp; if (!ptr) { ptr = &tmp; } if (!elf) { *ptr = 0; return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { *ptr = elf->e_idlen; return elf->e_data; } if (elf->e_ehdr || _elf_cook(elf)) { *ptr = elf->e_idlen; return elf->e_ehdr; } *ptr = 0; return NULL; } qtrvsim-0.9.8/external/libelf/getscn.c000066400000000000000000000027661467752164200177740ustar00rootroot00000000000000/* getscn.c - implementation of the elf_getscn(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: getscn.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Scn *elf_getscn(Elf *elf, size_t index) { Elf_Scn *scn; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_ehdr || _elf_cook(elf)) { for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); if (scn->s_index == index) { return scn; } } seterr(ERROR_NOSUCHSCN); } return NULL; } qtrvsim-0.9.8/external/libelf/hash.c000066400000000000000000000023341467752164200174230ustar00rootroot00000000000000/* hash.c - implementation of the elf_hash(3) function. Copyright (C) 1995 - 2002 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: hash.c,v 1.10 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ unsigned long elf_hash(const unsigned char *name) { unsigned long hash = 0; unsigned long tmp; while (*name) { hash = (hash << 4) + (unsigned char)*name++; if ((tmp = hash & 0xf0000000)) { hash ^= tmp | (tmp >> 24); } } return hash; } qtrvsim-0.9.8/external/libelf/input.c000066400000000000000000000053401467752164200176370ustar00rootroot00000000000000/* * input.c - low-level input for libelf. * Copyright (C) 1995 - 2001, 2005 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: input.c,v 1.11 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ #include #if HAVE_MMAP #include #endif /* HAVE_MMAP */ static int xread(int fd, char *buffer, size_t len) { size_t done = 0; size_t n; while (done < len) { n = read(fd, buffer + done, len - done); if (n == 0) { /* premature end of file */ return -1; } else if (n != (size_t)-1) { /* some bytes read, continue */ done += n; } else if (errno != EAGAIN && errno != EINTR) { /* real error */ return -1; } } return 0; } void *_elf_read(Elf *elf, void *buffer, size_t off, size_t len) { void *tmp; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(off >= 0 && off + len <= elf->e_size); if (elf->e_disabled) { seterr(ERROR_FDDISABLED); } else if (len) { off += elf->e_base; if (lseek(elf->e_fd, (off_t)off, SEEK_SET) != (off_t)off) { seterr(ERROR_IO_SEEK); } else if (!(tmp = buffer) && !(tmp = malloc(len))) { seterr(ERROR_IO_2BIG); } else if (xread(elf->e_fd, tmp, len)) { seterr(ERROR_IO_READ); if (tmp != buffer) { free(tmp); } } else { return tmp; } } return NULL; } void *_elf_mmap(Elf *elf) { #if HAVE_MMAP void *tmp; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(elf->e_base == 0); if (elf->e_disabled) { seterr(ERROR_FDDISABLED); } else if (elf->e_size) { tmp = (void *)mmap( 0, elf->e_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, elf->e_fd, 0); if (tmp != (void *)-1) { return tmp; } } #endif /* HAVE_MMAP */ return NULL; } qtrvsim-0.9.8/external/libelf/kind.c000066400000000000000000000021131467752164200174200ustar00rootroot00000000000000/* kind.c - implementation of the elf_kind(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: kind.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Kind elf_kind(Elf *elf) { if (!elf) { return ELF_K_NONE; } elf_assert(elf->e_magic == ELF_MAGIC); return elf->e_kind; } qtrvsim-0.9.8/external/libelf/libelf.def000066400000000000000000000021541467752164200202510ustar00rootroot00000000000000LIBRARY libelf VERSION 0.8 EXPORTS elf_begin elf_cntl elf_delscn elf_end elf_errmsg elf_errno elf_fill elf_flagdata elf_flagehdr elf_flagelf elf_flagphdr elf_flagscn elf_flagshdr elf_getarhdr elf_getarsym elf_getbase elf_getdata elf_getident elf_getscn elf_hash elf_kind elf_memory elf_ndxscn elf_newdata elf_newscn elf_next elf_nextscn elf_rand elf_rawdata elf_rawfile elf_strptr elf_update elf_version elf32_checksum elf32_fsize elf32_getehdr elf32_getphdr elf32_getshdr elf32_newehdr elf32_newphdr elf32_xlatetof elf32_xlatetom elf64_checksum elf64_fsize elf64_getehdr elf64_getphdr elf64_getshdr elf64_newehdr elf64_newphdr elf64_xlatetof elf64_xlatetom elfx_movscn elfx_remscn gelf_checksum gelf_fsize gelf_getclass gelf_getdyn gelf_getehdr gelf_getphdr gelf_getrel gelf_getrela gelf_getshdr gelf_getsym gelf_msize gelf_newehdr gelf_newphdr gelf_update_dyn gelf_update_ehdr gelf_update_phdr gelf_update_rel gelf_update_rela gelf_update_shdr gelf_update_sym gelf_xlatetof gelf_xlatetom elf_getphnum elf_getshnum elf_getshstrndx elfx_update_shstrndx qtrvsim-0.9.8/external/libelf/libelf.h000066400000000000000000000216551467752164200177510ustar00rootroot00000000000000/* * libelf.h - public header file for libelf. * Copyright (C) 1995 - 2008 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: libelf.h,v 1.29 2009/07/07 17:57:43 michael Exp $ */ #ifndef _LIBELF_H #define _LIBELF_H #include /* for size_t */ #include #if __LIBELF_INTERNAL__ #include #else /* __LIBELF_INTERNAL__ */ #include #endif /* __LIBELF_INTERNAL__ */ #if defined __GNUC__ && !defined __cplusplus #define DEPRECATED __attribute__((deprecated)) #else #define DEPRECATED /* nothing */ #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef __P #if (__STDC__ + 0) || defined(__cplusplus) || defined(_WIN32) #define __P(args) args #else /* __STDC__ || defined(__cplusplus) */ #define __P(args) () #endif /* __STDC__ || defined(__cplusplus) */ #endif /* __P */ /* * Commands */ typedef enum { ELF_C_NULL = 0, /* must be first, 0 */ ELF_C_READ, ELF_C_WRITE, ELF_C_CLR, ELF_C_SET, ELF_C_FDDONE, ELF_C_FDREAD, ELF_C_RDWR, ELF_C_NUM /* must be last */ } Elf_Cmd; /* * Flags */ #define ELF_F_DIRTY 0x1 #define ELF_F_LAYOUT 0x4 /* * Allow sections to overlap when ELF_F_LAYOUT is in effect. * Note that this flag ist NOT portable, and that it may render * the output file unusable. Use with extreme caution! */ #define ELF_F_LAYOUT_OVERLAP 0x10000000 /* * File types */ typedef enum { ELF_K_NONE = 0, /* must be first, 0 */ ELF_K_AR, ELF_K_COFF, ELF_K_ELF, ELF_K_NUM /* must be last */ } Elf_Kind; /* * Data types */ typedef enum { ELF_T_BYTE = 0, /* must be first, 0 */ ELF_T_ADDR, ELF_T_DYN, ELF_T_EHDR, ELF_T_HALF, ELF_T_OFF, ELF_T_PHDR, ELF_T_RELA, ELF_T_REL, ELF_T_SHDR, ELF_T_SWORD, ELF_T_SYM, ELF_T_WORD, /* * New stuff for 64-bit. * * Most implementations add ELF_T_SXWORD after ELF_T_SWORD * which breaks binary compatibility with earlier versions. * If this causes problems for you, contact me. */ ELF_T_SXWORD, ELF_T_XWORD, /* * Symbol versioning. Sun broke binary compatibility (again!), * but I won't. */ ELF_T_VDEF, ELF_T_VNEED, ELF_T_NUM /* must be last */ } Elf_Type; /* * Elf descriptor */ typedef struct Elf Elf; /* * Section descriptor */ typedef struct Elf_Scn Elf_Scn; /* * Archive member header */ typedef struct { char *ar_name; time_t ar_date; long ar_uid; long ar_gid; unsigned long ar_mode; off_t ar_size; char *ar_rawname; } Elf_Arhdr; /* * Archive symbol table */ typedef struct { char *as_name; size_t as_off; unsigned long as_hash; } Elf_Arsym; /* * Data descriptor */ typedef struct { void *d_buf; Elf_Type d_type; size_t d_size; off_t d_off; size_t d_align; unsigned d_version; } Elf_Data; /* * Function declarations */ extern Elf *elf_begin __P((int __fd, Elf_Cmd __cmd, Elf *__ref)); extern Elf *elf_memory __P((char *__image, size_t __size)); extern int elf_cntl __P((Elf * __elf, Elf_Cmd __cmd)); extern int elf_end __P((Elf * __elf)); extern const char *elf_errmsg __P((int __err)); extern int elf_errno __P((void)); extern void elf_fill __P((int __fill)); extern unsigned elf_flagdata __P((Elf_Data * __data, Elf_Cmd __cmd, unsigned __flags)); extern unsigned elf_flagehdr __P((Elf * __elf, Elf_Cmd __cmd, unsigned __flags)); extern unsigned elf_flagelf __P((Elf * __elf, Elf_Cmd __cmd, unsigned __flags)); extern unsigned elf_flagphdr __P((Elf * __elf, Elf_Cmd __cmd, unsigned __flags)); extern unsigned elf_flagscn __P((Elf_Scn * __scn, Elf_Cmd __cmd, unsigned __flags)); extern unsigned elf_flagshdr __P((Elf_Scn * __scn, Elf_Cmd __cmd, unsigned __flags)); extern size_t elf32_fsize __P((Elf_Type __type, size_t __count, unsigned __ver)); extern Elf_Arhdr *elf_getarhdr __P((Elf * __elf)); extern Elf_Arsym *elf_getarsym __P((Elf * __elf, size_t *__ptr)); extern off_t elf_getbase __P((Elf * __elf)); extern Elf_Data *elf_getdata __P((Elf_Scn * __scn, Elf_Data *__data)); extern Elf32_Ehdr *elf32_getehdr __P((Elf * __elf)); extern char *elf_getident __P((Elf * __elf, size_t *__ptr)); extern Elf32_Phdr *elf32_getphdr __P((Elf * __elf)); extern Elf_Scn *elf_getscn __P((Elf * __elf, size_t __index)); extern Elf32_Shdr *elf32_getshdr __P((Elf_Scn * __scn)); extern unsigned long elf_hash __P((const unsigned char *__name)); extern Elf_Kind elf_kind __P((Elf * __elf)); extern size_t elf_ndxscn __P((Elf_Scn * __scn)); extern Elf_Data *elf_newdata __P((Elf_Scn * __scn)); extern Elf32_Ehdr *elf32_newehdr __P((Elf * __elf)); extern Elf32_Phdr *elf32_newphdr __P((Elf * __elf, size_t __count)); extern Elf_Scn *elf_newscn __P((Elf * __elf)); extern Elf_Cmd elf_next __P((Elf * __elf)); extern Elf_Scn *elf_nextscn __P((Elf * __elf, Elf_Scn *__scn)); extern size_t elf_rand __P((Elf * __elf, size_t __offset)); extern Elf_Data *elf_rawdata __P((Elf_Scn * __scn, Elf_Data *__data)); extern char *elf_rawfile __P((Elf * __elf, size_t *__ptr)); extern char *elf_strptr __P((Elf * __elf, size_t __section, size_t __offset)); extern off_t elf_update __P((Elf * __elf, Elf_Cmd __cmd)); extern unsigned elf_version __P((unsigned __ver)); extern Elf_Data *elf32_xlatetof __P((Elf_Data * __dst, const Elf_Data *__src, unsigned __encode)); extern Elf_Data *elf32_xlatetom __P((Elf_Data * __dst, const Elf_Data *__src, unsigned __encode)); /* * Additional functions found on Solaris */ extern long elf32_checksum __P((Elf * __elf)); #if __LIBELF64 /* * 64-bit ELF functions * Not available on all platforms */ extern Elf64_Ehdr *elf64_getehdr __P((Elf * __elf)); extern Elf64_Ehdr *elf64_newehdr __P((Elf * __elf)); extern Elf64_Phdr *elf64_getphdr __P((Elf * __elf)); extern Elf64_Phdr *elf64_newphdr __P((Elf * __elf, size_t __count)); extern Elf64_Shdr *elf64_getshdr __P((Elf_Scn * __scn)); extern size_t elf64_fsize __P((Elf_Type __type, size_t __count, unsigned __ver)); extern Elf_Data *elf64_xlatetof __P((Elf_Data * __dst, const Elf_Data *__src, unsigned __encode)); extern Elf_Data *elf64_xlatetom __P((Elf_Data * __dst, const Elf_Data *__src, unsigned __encode)); /* * Additional functions found on Solaris */ extern long elf64_checksum __P((Elf * __elf)); #endif /* __LIBELF64 */ /* * ELF format extensions * * These functions return 0 on failure, 1 on success. Since other * implementations of libelf may behave differently (there was quite * some confusion about the correct values), they are now officially * deprecated and should be replaced with the three new functions below. */ DEPRECATED extern int elf_getphnum __P((Elf * __elf, size_t *__resultp)); DEPRECATED extern int elf_getshnum __P((Elf * __elf, size_t *__resultp)); DEPRECATED extern int elf_getshstrndx __P((Elf * __elf, size_t *__resultp)); /* * Replacement functions (return -1 on failure, 0 on success). */ extern int elf_getphdrnum __P((Elf * __elf, size_t *__resultp)); extern int elf_getshdrnum __P((Elf * __elf, size_t *__resultp)); extern int elf_getshdrstrndx __P((Elf * __elf, size_t *__resultp)); /* * Convenience functions * * elfx_update_shstrndx is elf_getshstrndx's counterpart. * It should be used to set the e_shstrndx member. * There is no update function for e_shnum or e_phnum * because libelf handles them internally. */ extern int elfx_update_shstrndx __P((Elf * __elf, size_t __index)); /* * Experimental extensions: * * elfx_movscn() moves section `__scn' directly after section `__after'. * elfx_remscn() removes section `__scn'. Both functions update * the section indices; elfx_remscn() also adjusts the ELF header's * e_shnum member. The application is responsible for updating other * data (in particular, e_shstrndx and the section headers' sh_link and * sh_info members). * * elfx_movscn() returns the new index of the moved section. * elfx_remscn() returns the original index of the removed section. * A return value of zero indicates an error. */ extern size_t elfx_movscn __P((Elf * __elf, Elf_Scn *__scn, Elf_Scn *__after)); extern size_t elfx_remscn __P((Elf * __elf, Elf_Scn *__scn)); /* * elf_delscn() is obsolete. Please use elfx_remscn() instead. */ extern size_t elf_delscn __P((Elf * __elf, Elf_Scn *__scn)); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _LIBELF_H */ qtrvsim-0.9.8/external/libelf/libelf.pro000066400000000000000000000023551467752164200203160ustar00rootroot00000000000000QT -= gui TARGET = elf CONFIG += c++11 TEMPLATE = lib CONFIG += staticlib INCLUDEPATH += $$PWD #LIBS += -lelf QMAKE_CXXFLAGS += -std=c++0x QMAKE_CXXFLAGS_DEBUG += -ggdb DEFINES += HAVE_CONFIG_H=1 SOURCES += \ 32.fsize.c \ 32.getehdr.c \ 32.getphdr.c \ 32.getshdr.c \ 32.newehdr.c \ 32.newphdr.c \ 32.xlatetof.c \ 64.xlatetof.c \ assert.c \ begin.c \ checksum.c \ cntl.c \ cook.c \ data.c \ end.c \ errmsg.c \ errno.c \ fill.c \ flag.c \ gelfehdr.c \ gelfphdr.c \ gelfshdr.c \ gelftrans.c \ getarhdr.c \ getaroff.c \ getarsym.c \ getbase.c \ getdata.c \ getident.c \ getscn.c \ hash.c \ input.c \ kind.c \ ndxscn.c \ newdata.c \ newscn.c \ next.c \ nextscn.c \ nlist.c \ opt.delscn.c \ rand.c \ rawdata.c \ rawfile.c \ strptr.c \ swap64.c \ update.c \ verdef_32_tof.c \ verdef_32_tom.c \ verdef_64_tof.c \ verdef_64_tom.c \ version.c \ x.elfext.c \ x.movscn.c \ x.remscn.c \ HEADERS += \ byteswap.h \ config.h \ elf_repl.h \ errors.h \ ext_types.h \ gelf.h \ libelf.h \ nlist.h \ private.h \ verdef.h \ verneed.h \ sys_elf.h \ qtrvsim-0.9.8/external/libelf/memset.c000066400000000000000000000031451467752164200177730ustar00rootroot00000000000000/* * memset.c - replacement for memset(3), using duff's device. * Copyright (C) 1995 - 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #if HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #ifndef lint static const char rcsid[] = "@(#) $Id: memset.c,v 1.11 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ #include /* for size_t */ #include void *_elf_memset(void *s, int c, size_t n) { char *t = (char *)s; if (n) { switch (n % 8u) { do { n -= 8; default: case 0: *t++ = (char)c; case 7: *t++ = (char)c; case 6: *t++ = (char)c; case 5: *t++ = (char)c; case 4: *t++ = (char)c; case 3: *t++ = (char)c; case 2: *t++ = (char)c; case 1: *t++ = (char)c; } while (n > 8); } } return s; } qtrvsim-0.9.8/external/libelf/ndxscn.c000066400000000000000000000021251467752164200177730ustar00rootroot00000000000000/* ndxscn.c - implementation of the elf_ndxscn(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: ndxscn.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ size_t elf_ndxscn(Elf_Scn *scn) { if (!scn) { return SHN_UNDEF; } elf_assert(scn->s_magic == SCN_MAGIC); return scn->s_index; } qtrvsim-0.9.8/external/libelf/newdata.c000066400000000000000000000031731467752164200201250ustar00rootroot00000000000000/* newdata.c - implementation of the elf_newdata(3) function. Copyright (C) 1995 - 2000 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: newdata.c,v 1.10 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Data *elf_newdata(Elf_Scn *scn) { Scn_Data *sd; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); if (scn->s_index == SHN_UNDEF) { seterr(ERROR_NULLSCN); } else if (!(sd = (Scn_Data *)malloc(sizeof(*sd)))) { seterr(ERROR_MEM_SCNDATA); } else { *sd = _elf_data_init; sd->sd_scn = scn; sd->sd_data_flags = ELF_F_DIRTY; sd->sd_freeme = 1; sd->sd_data.d_version = _elf_version; if (scn->s_data_n) { scn->s_data_n->sd_link = sd; } else { scn->s_data_1 = sd; } scn->s_data_n = sd; return &sd->sd_data; } return NULL; } qtrvsim-0.9.8/external/libelf/newscn.c000066400000000000000000000071421467752164200177770ustar00rootroot00000000000000/* * newscn.c - implementation of the elf_newscn(3) function. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: newscn.c,v 1.13 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ int _elf_update_shnum(Elf *elf, size_t shnum) { size_t extshnum = 0; Elf_Scn *scn; elf_assert(elf); elf_assert(elf->e_ehdr); scn = elf->e_scn_1; elf_assert(scn); elf_assert(scn->s_index == 0); if (shnum >= SHN_LORESERVE) { extshnum = shnum; shnum = 0; } if (elf->e_class == ELFCLASS32) { ((Elf32_Ehdr *)elf->e_ehdr)->e_shnum = shnum; scn->s_shdr32.sh_size = extshnum; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { ((Elf64_Ehdr *)elf->e_ehdr)->e_shnum = shnum; scn->s_shdr64.sh_size = extshnum; } #endif /* __LIBELF64 */ else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return -1; } elf->e_ehdr_flags |= ELF_F_DIRTY; scn->s_shdr_flags |= ELF_F_DIRTY; return 0; } static Elf_Scn *_makescn(Elf *elf, size_t index) { Elf_Scn *scn; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(elf->e_ehdr); elf_assert(_elf_scn_init.s_magic == SCN_MAGIC); if (!(scn = (Elf_Scn *)malloc(sizeof(*scn)))) { seterr(ERROR_MEM_SCN); return NULL; } *scn = _elf_scn_init; scn->s_elf = elf; scn->s_scn_flags = ELF_F_DIRTY; scn->s_shdr_flags = ELF_F_DIRTY; scn->s_freeme = 1; scn->s_index = index; return scn; } Elf_Scn *_elf_first_scn(Elf *elf) { Elf_Scn *scn; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if ((scn = elf->e_scn_1)) { return scn; } if ((scn = _makescn(elf, 0))) { elf->e_scn_1 = elf->e_scn_n = scn; if (_elf_update_shnum(elf, 1)) { free(scn); elf->e_scn_1 = elf->e_scn_n = scn = NULL; } } return scn; } static Elf_Scn *_buildscn(Elf *elf) { Elf_Scn *scn; if (!_elf_first_scn(elf)) { return NULL; } scn = elf->e_scn_n; elf_assert(scn); if (!(scn = _makescn(elf, scn->s_index + 1))) { return NULL; } if (_elf_update_shnum(elf, scn->s_index + 1)) { free(scn); return NULL; } elf->e_scn_n = elf->e_scn_n->s_link = scn; return scn; } Elf_Scn *elf_newscn(Elf *elf) { Elf_Scn *scn; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_readable && !elf->e_ehdr) { seterr(ERROR_NOEHDR); } else if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (!elf->e_ehdr && !_elf_cook(elf)) { return NULL; } else if ((scn = _buildscn(elf))) { return scn; } return NULL; } qtrvsim-0.9.8/external/libelf/next.c000066400000000000000000000025451467752164200174620ustar00rootroot00000000000000/* next.c - implementation of the elf_next(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: next.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Cmd elf_next(Elf *elf) { if (!elf) { return ELF_C_NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_parent) { return ELF_C_NULL; } elf_assert(elf->e_parent->e_magic == ELF_MAGIC); elf_assert(elf->e_parent->e_kind == ELF_K_AR); elf->e_parent->e_off = elf->e_next; if (elf->e_next == elf->e_parent->e_size) { return ELF_C_NULL; } return ELF_C_READ; } qtrvsim-0.9.8/external/libelf/nextscn.c000066400000000000000000000032721467752164200201640ustar00rootroot00000000000000/* nextscn.c - implementation of the elf_nextscn(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: nextscn.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Scn *elf_nextscn(Elf *elf, Elf_Scn *scn) { if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (scn) { elf_assert(scn->s_magic == SCN_MAGIC); if (scn->s_elf == elf) { return scn->s_link; } seterr(ERROR_ELFSCNMISMATCH); } else if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_ehdr || _elf_cook(elf)) { elf_assert(elf->e_ehdr); for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); if (scn->s_index == 1) { return scn; } } seterr(ERROR_NOSUCHSCN); } return NULL; } qtrvsim-0.9.8/external/libelf/nlist.c000066400000000000000000000145141467752164200176340ustar00rootroot00000000000000/* * nlist.c - implementation of the nlist(3) function. * Copyright (C) 1995 - 2004 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "nlist.h" #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: nlist.c,v 1.15 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ #if !defined(_WIN32) #if HAVE_FCNTL_H #include #else extern int open(); #endif /* HAVE_FCNTL_H */ #endif /* defined(_WIN32) */ #ifndef O_RDONLY #define O_RDONLY 0 #endif /* O_RDONLY */ #ifndef O_BINARY #define O_BINARY 0 #endif /* O_BINARY */ #define FILE_OPEN_MODE (O_RDONLY | O_BINARY) #define PRIME 217 struct hash { const char *name; unsigned long hash; unsigned next; }; static const char *symbol_name( Elf *elf, const void *syms, const char *names, size_t nlimit, size_t index) { size_t off; if (elf->e_class == ELFCLASS32) { off = ((Elf32_Sym *)syms)[index].st_name; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { off = ((Elf64_Sym *)syms)[index].st_name; } #endif /* __LIBELF64 */ else { return NULL; } if (off >= 0 && off < nlimit) { return &names[off]; } return NULL; } static void copy_symbol(Elf *elf, struct nlist *np, const void *syms, size_t index) { if (elf->e_class == ELFCLASS32) { np->n_value = ((Elf32_Sym *)syms)[index].st_value; np->n_scnum = ((Elf32_Sym *)syms)[index].st_shndx; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { np->n_value = ((Elf64_Sym *)syms)[index].st_value; np->n_scnum = ((Elf64_Sym *)syms)[index].st_shndx; } #endif /* __LIBELF64 */ /* * this needs more work */ np->n_type = 0; np->n_sclass = 0; np->n_numaux = 0; } static int _elf_nlist(Elf *elf, struct nlist *nl) { unsigned first[PRIME]; Elf_Scn *symtab = NULL; Elf_Scn *strtab = NULL; Elf_Data *symdata; Elf_Data *strdata; size_t symsize; size_t nsymbols; const char *name; struct hash *table; unsigned long hash; unsigned i; struct nlist *np; /* * Get and translate ELF header, section table and so on. * Must be class independent, so don't use elf32_get*(). */ if (elf->e_kind != ELF_K_ELF) { return -1; } if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } /* * Find symbol table. If there is none, try dynamic symbols. */ for (symtab = elf->e_scn_1; symtab; symtab = symtab->s_link) { if (symtab->s_type == SHT_SYMTAB) { break; } if (symtab->s_type == SHT_DYNSYM) { strtab = symtab; } } if (!symtab && !(symtab = strtab)) { return -1; } /* * Get associated string table. */ i = 0; if (elf->e_class == ELFCLASS32) { i = symtab->s_shdr32.sh_link; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { i = symtab->s_shdr64.sh_link; } #endif /* __LIBELF64 */ if (i == 0) { return -1; } for (strtab = elf->e_scn_1; strtab; strtab = strtab->s_link) { if (strtab->s_index == i) { break; } } if (!strtab || strtab->s_type != SHT_STRTAB) { return -1; } /* * Get and translate section data. */ symdata = elf_getdata(symtab, NULL); strdata = elf_getdata(strtab, NULL); if (!symdata || !strdata) { return -1; } symsize = _msize(elf->e_class, _elf_version, ELF_T_SYM); elf_assert(symsize); nsymbols = symdata->d_size / symsize; if (!symdata->d_buf || !strdata->d_buf || !nsymbols || !strdata->d_size) { return -1; } /* * Build a simple hash table. */ if (!(table = (struct hash *)malloc(nsymbols * sizeof(*table)))) { return -1; } for (i = 0; i < PRIME; i++) { first[i] = 0; } for (i = 0; i < nsymbols; i++) { table[i].name = NULL; table[i].hash = 0; table[i].next = 0; } for (i = 1; i < nsymbols; i++) { name = symbol_name( elf, symdata->d_buf, strdata->d_buf, strdata->d_size, i); if (name == NULL) { free(table); return -1; } if (*name != '\0') { table[i].name = name; table[i].hash = elf_hash((unsigned char *)name); hash = table[i].hash % PRIME; table[i].next = first[hash]; first[hash] = i; } } /* * Lookup symbols, one by one. */ for (np = nl; (name = np->n_name) && *name; np++) { hash = elf_hash((unsigned char *)name); for (i = first[hash % PRIME]; i; i = table[i].next) { if (table[i].hash == hash && !strcmp(table[i].name, name)) { break; } } if (i) { copy_symbol(elf, np, symdata->d_buf, i); } else { np->n_value = 0; np->n_scnum = 0; np->n_type = 0; np->n_sclass = 0; np->n_numaux = 0; } } free(table); return 0; } int nlist(const char *filename, struct nlist *nl) { int result = -1; unsigned oldver; Elf *elf; int fd; if ((oldver = elf_version(EV_CURRENT)) != EV_NONE) { if ((fd = open(filename, FILE_OPEN_MODE)) != -1) { if ((elf = elf_begin(fd, ELF_C_READ, NULL))) { result = _elf_nlist(elf, nl); elf_end(elf); } close(fd); } elf_version(oldver); } if (result) { while (nl->n_name && *nl->n_name) { nl->n_value = 0; nl++; } } return result; } qtrvsim-0.9.8/external/libelf/nlist.h000066400000000000000000000026441467752164200176420ustar00rootroot00000000000000/* * nlist.h - public header file for nlist(3). * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: nlist.h,v 1.10 2008/05/23 08:15:35 michael Exp $ */ #ifndef _NLIST_H #define _NLIST_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct nlist { char *n_name; long n_value; short n_scnum; unsigned short n_type; char n_sclass; char n_numaux; }; #if (__STDC__ + 0) || defined(__cplusplus) || defined(_WIN32) extern int nlist(const char *__filename, struct nlist *__nl); #else /* __STDC__ || defined(__cplusplus) */ extern int nlist(); #endif /* __STDC__ || defined(__cplusplus) */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _NLIST_H */ qtrvsim-0.9.8/external/libelf/opt.delscn.c000066400000000000000000000126431467752164200205550ustar00rootroot00000000000000/* opt.delscn.c - implementation of the elf_delscn(3) function. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: opt.delscn.c,v 1.12 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ static size_t _newindex(size_t old, size_t index) { return old == index ? SHN_UNDEF : (old > index ? old - 1 : old); } static void _elf32_update_shdr(Elf *elf, size_t index) { Elf32_Shdr *shdr; Elf_Scn *scn; ((Elf32_Ehdr *)elf->e_ehdr)->e_shnum = elf->e_scn_n->s_index + 1; for (scn = elf->e_scn_1; scn; scn = scn->s_link) { shdr = &scn->s_shdr32; switch (shdr->sh_type) { case SHT_REL: case SHT_RELA: shdr->sh_info = _newindex(shdr->sh_info, index); /* fall through */ case SHT_DYNSYM: case SHT_DYNAMIC: case SHT_HASH: case SHT_SYMTAB: #if __LIBELF_SYMBOL_VERSIONS #if __LIBELF_SUN_SYMBOL_VERSIONS case SHT_SUNW_verdef: case SHT_SUNW_verneed: case SHT_SUNW_versym: #else /* __LIBELF_SUN_SYMBOL_VERSIONS */ case SHT_GNU_verdef: case SHT_GNU_verneed: case SHT_GNU_versym: #endif /* __LIBELF_SUN_SYMBOL_VERSIONS */ #endif /* __LIBELF_SYMBOL_VERSIONS */ shdr->sh_link = _newindex(shdr->sh_link, index); /* fall through */ default: break; } } } #if __LIBELF64 static void _elf64_update_shdr(Elf *elf, size_t index) { Elf64_Shdr *shdr; Elf_Scn *scn; ((Elf64_Ehdr *)elf->e_ehdr)->e_shnum = elf->e_scn_n->s_index + 1; for (scn = elf->e_scn_1; scn; scn = scn->s_link) { shdr = &scn->s_shdr64; switch (shdr->sh_type) { case SHT_REL: case SHT_RELA: shdr->sh_info = _newindex(shdr->sh_info, index); /* fall through */ case SHT_DYNSYM: case SHT_DYNAMIC: case SHT_HASH: case SHT_SYMTAB: #if __LIBELF_SYMBOL_VERSIONS #if __LIBELF_SUN_SYMBOL_VERSIONS case SHT_SUNW_verdef: case SHT_SUNW_verneed: case SHT_SUNW_versym: #else /* __LIBELF_SUN_SYMBOL_VERSIONS */ case SHT_GNU_verdef: case SHT_GNU_verneed: case SHT_GNU_versym: #endif /* __LIBELF_SUN_SYMBOL_VERSIONS */ #endif /* __LIBELF_SYMBOL_VERSIONS */ shdr->sh_link = _newindex(shdr->sh_link, index); /* fall through */ default: break; } } } #endif /* __LIBELF64 */ size_t elf_delscn(Elf *elf, Elf_Scn *scn) { Elf_Scn *pscn; Scn_Data *sd; Scn_Data *tmp; size_t index; if (!elf || !scn) { return SHN_UNDEF; } elf_assert(elf->e_magic == ELF_MAGIC); elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(elf->e_ehdr); if (scn->s_elf != elf) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } elf_assert(elf->e_scn_1); if (scn == elf->e_scn_1) { seterr(ERROR_NULLSCN); return SHN_UNDEF; } /* * Find previous section. */ for (pscn = elf->e_scn_1; pscn->s_link; pscn = pscn->s_link) { if (pscn->s_link == scn) { break; } } if (pscn->s_link != scn) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } /* * Unlink section. */ if (elf->e_scn_n == scn) { elf->e_scn_n = pscn; } pscn->s_link = scn->s_link; index = scn->s_index; /* * Free section descriptor and data. */ for (sd = scn->s_data_1; sd; sd = tmp) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); tmp = sd->sd_link; if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if (scn->s_freeme) { elf_assert(scn->s_index > 0); free(scn); } /* * Adjust section indices. */ for (scn = pscn->s_link; scn; scn = scn->s_link) { elf_assert(scn->s_index > index); scn->s_index--; } /* * Adjust ELF header and well-known section headers. */ if (elf->e_class == ELFCLASS32) { _elf32_update_shdr(elf, index); return index; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { _elf64_update_shdr(elf, index); return index; } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return SHN_UNDEF; } qtrvsim-0.9.8/external/libelf/private.h000066400000000000000000000356501467752164200201660ustar00rootroot00000000000000/* * private.h - private definitions for libelf. * Copyright (C) 1995 - 2007 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: private.h,v 1.40 2009/11/01 13:04:19 michael Exp $ */ #ifndef _PRIVATE_H #define _PRIVATE_H #define __LIBELF_INTERNAL__ 1 #if HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ /* * Workaround for GLIBC bug: * include before */ #if HAVE_STDINT_H #include #endif #include #if STDC_HEADERS #include #include #else /* STDC_HEADERS */ extern void *malloc(), *realloc(); extern void free(), bcopy(), abort(); extern int strcmp(), strncmp(), memcmp(); extern void *memcpy(), *memmove(), *memset(); #endif /* STDC_HEADERS */ #if defined(_WIN32) #include #else #if HAVE_UNISTD_H #include #else /* HAVE_UNISTD_H */ extern int read(), write(), close(); extern off_t lseek(); #if HAVE_FTRUNCATE extern int ftruncate(); #endif /* HAVE_FTRUNCATE */ #endif /* HAVE_UNISTD_H */ #endif /* defined(_WIN32) */ #ifndef SEEK_SET #define SEEK_SET 0 #endif /* SEEK_SET */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif /* SEEK_CUR */ #ifndef SEEK_END #define SEEK_END 2 #endif /* SEEK_END */ #if !HAVE_MEMCMP #define memcmp strncmp #endif /* !HAVE_MEMCMP */ #if !HAVE_MEMCPY #define memcpy(d, s, n) bcopy(s, d, n) #endif /* !HAVE_MEMCPY */ #if !HAVE_MEMMOVE #define memmove(d, s, n) bcopy(s, d, n) #endif /* !HAVE_MEMMOVE */ #if !HAVE_MEMSET #define memset _elf_memset extern void *_elf_memset(); #endif /* !HAVE_MEMSET */ #if HAVE_STRUCT_NLIST_DECLARATION #define nlist __override_nlist_declaration #endif /* HAVE_STRUCT_NLIST_DECLARATION */ #if __LIBELF_NEED_LINK_H #include #elif __LIBELF_NEED_SYS_LINK_H #include #endif /* __LIBELF_NEED_LINK_H */ #if HAVE_AR_H #include #else /* HAVE_AR_H */ #define ARMAG "!\n" #define SARMAG 8 struct ar_hdr { char ar_name[16]; char ar_date[12]; char ar_uid[6]; char ar_gid[6]; char ar_mode[8]; char ar_size[10]; char ar_fmag[2]; }; #define ARFMAG "`\n" #endif /* HAVE_AR_H */ #include #if HAVE_STRUCT_NLIST_DECLARATION #undef nlist #endif /* HAVE_STRUCT_NLIST_DECLARATION */ #if __LIBELF64 #include #endif /* __LIBELF64 */ typedef struct Scn_Data Scn_Data; /* * ELF descriptor */ struct Elf { /* common */ size_t e_size; /* file/member size */ size_t e_dsize; /* size of memory image */ Elf_Kind e_kind; /* kind of file */ char *e_data; /* file/member data */ char *e_rawdata; /* file/member raw data */ size_t e_idlen; /* identifier size */ int e_fd; /* file descriptor */ unsigned e_count; /* activation count */ /* archive members (still common) */ Elf *e_parent; /* NULL if not an archive member */ size_t e_next; /* 0 if not an archive member */ size_t e_base; /* 0 if not an archive member */ Elf *e_link; /* next archive member or NULL */ Elf_Arhdr *e_arhdr; /* archive member header or NULL */ /* archives */ size_t e_off; /* current member offset (for elf_begin) */ Elf *e_members; /* linked list of active archive members */ char *e_symtab; /* archive symbol table */ size_t e_symlen; /* length of archive symbol table */ char *e_strtab; /* archive string table */ size_t e_strlen; /* length of archive string table */ /* ELF files */ unsigned e_class; /* ELF class */ unsigned e_encoding; /* ELF data encoding */ unsigned e_version; /* ELF version */ char *e_ehdr; /* ELF header */ char *e_phdr; /* ELF program header table */ size_t e_phnum; /* size of program header table */ Elf_Scn *e_scn_1; /* first section */ Elf_Scn *e_scn_n; /* last section */ unsigned e_elf_flags; /* elf flags (ELF_F_*) */ unsigned e_ehdr_flags; /* ehdr flags (ELF_F_*) */ unsigned e_phdr_flags; /* phdr flags (ELF_F_*) */ /* misc flags */ unsigned e_readable : 1; /* file is readable */ unsigned e_writable : 1; /* file is writable */ unsigned e_disabled : 1; /* e_fd has been disabled */ unsigned e_cooked : 1; /* e_data was modified */ unsigned e_free_syms : 1; /* e_symtab is malloc'ed */ unsigned e_unmap_data : 1; /* e_data is mmap'ed */ unsigned e_memory : 1; /* created by elf_memory() */ /* magic number for debugging */ long e_magic; }; #define ELF_MAGIC 0x012b649e #define INIT_ELF \ { \ /* e_size */ 0, /* e_dsize */ 0, /* e_kind */ ELF_K_NONE, \ /* e_data */ NULL, /* e_rawdata */ NULL, /* e_idlen */ 0, \ /* e_fd */ -1, /* e_count */ 1, /* e_parent */ NULL, \ /* e_next */ 0, /* e_base */ 0, /* e_link */ NULL, \ /* e_arhdr */ NULL, /* e_off */ 0, /* e_members */ NULL, \ /* e_symtab */ NULL, /* e_symlen */ 0, /* e_strtab */ NULL, \ /* e_strlen */ 0, /* e_class */ ELFCLASSNONE, \ /* e_encoding */ ELFDATANONE, /* e_version */ EV_NONE, \ /* e_ehdr */ NULL, /* e_phdr */ NULL, /* e_phnum */ 0, \ /* e_scn_1 */ NULL, /* e_scn_n */ NULL, /* e_elf_flags */ 0, \ /* e_ehdr_flags */ 0, /* e_phdr_flags */ 0, /* e_readable */ 0, \ /* e_writable */ 0, /* e_disabled */ 0, /* e_cooked */ 0, \ /* e_free_syms */ 0, /* e_unmap_data */ 0, /* e_memory */ 0, \ /* e_magic */ ELF_MAGIC \ } /* * Section descriptor */ struct Elf_Scn { Elf_Scn *s_link; /* pointer to next Elf_Scn */ Elf *s_elf; /* pointer to elf descriptor */ size_t s_index; /* number of this section */ unsigned s_scn_flags; /* section flags (ELF_F_*) */ unsigned s_shdr_flags; /* shdr flags (ELF_F_*) */ Scn_Data *s_data_1; /* first data buffer */ Scn_Data *s_data_n; /* last data buffer */ Scn_Data *s_rawdata; /* raw data buffer */ /* data copied from shdr */ unsigned s_type; /* section type */ size_t s_offset; /* section offset */ size_t s_size; /* section size */ /* misc flags */ unsigned s_freeme : 1; /* this Elf_Scn was malloc'ed */ /* section header */ union { #if __LIBELF64 Elf64_Shdr u_shdr64; #endif /* __LIBELF64 */ Elf32_Shdr u_shdr32; } s_uhdr; /* magic number for debugging */ long s_magic; }; #define s_shdr32 s_uhdr.u_shdr32 #define s_shdr64 s_uhdr.u_shdr64 #define SCN_MAGIC 0x012c747d #define INIT_SCN \ { \ /* s_link */ NULL, /* s_elf */ NULL, /* s_index */ 0, \ /* s_scn_flags */ 0, /* s_shdr_flags */ 0, /* s_data_1 */ NULL, \ /* s_data_n */ NULL, /* s_rawdata */ NULL, /* s_type */ SHT_NULL, \ /* s_offset */ 0, /* s_size */ 0, /* s_freeme */ 0, /* s_uhdr */ \ { { \ 0, \ } }, \ /* s_magic */ SCN_MAGIC \ } /* * Data descriptor */ struct Scn_Data { Elf_Data sd_data; /* must be first! */ Scn_Data *sd_link; /* pointer to next Scn_Data */ Elf_Scn *sd_scn; /* pointer to section */ char *sd_memdata; /* memory image of section */ unsigned sd_data_flags; /* data flags (ELF_F_*) */ /* misc flags */ unsigned sd_freeme : 1; /* this Scn_Data was malloc'ed */ unsigned sd_free_data : 1; /* sd_memdata is malloc'ed */ /* magic number for debugging */ long sd_magic; }; #define DATA_MAGIC 0x01072639 #define INIT_DATA \ { \ { /* d_buf */ NULL, /* d_type */ ELF_T_BYTE, \ /* d_size */ 0, /* d_off */ 0, \ /* d_align */ 0, /* d_version */ EV_NONE }, \ /* sd_link */ NULL, /* sd_scn */ NULL, /* sd_memdata */ NULL, \ /* sd_data_flags */ 0, /* sd_freeme */ 0, /* sd_free_data */ 0, \ /* sd_magic */ DATA_MAGIC \ } /* * Private status variables */ extern unsigned _elf_version; extern int _elf_errno; extern int _elf_fill; extern int _elf_sanity_checks; #define SANITY_CHECK_STRPTR (1u << 0) /* * Private functions */ extern void *_elf_read __P((Elf *, void *, size_t, size_t)); extern void *_elf_mmap __P((Elf *)); extern int _elf_cook __P((Elf *)); extern char *_elf_getehdr __P((Elf *, unsigned)); extern char *_elf_getphdr __P((Elf *, unsigned)); extern Elf_Data *_elf_xlatetom __P((const Elf *, Elf_Data *, const Elf_Data *)); extern Elf_Type _elf_scn_type __P((unsigned)); extern size_t _elf32_xltsize __P((const Elf_Data *__src, unsigned __dv, unsigned __encode, int __tof)); extern size_t _elf64_xltsize __P((const Elf_Data *__src, unsigned __dv, unsigned __encode, int __tof)); extern int _elf_update_shnum(Elf *__elf, size_t __shnum); extern Elf_Scn *_elf_first_scn(Elf *__elf); /* * Special translators */ extern size_t _elf_verdef_32L11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_32L11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_32M11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_32M11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_64L11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_64L11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_64M11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verdef_64M11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_32L11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_32L11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_32M11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_32M11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_64L11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_64L11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_64M11_tof __P((unsigned char *dst, const unsigned char *src, size_t n)); extern size_t _elf_verneed_64M11_tom __P((unsigned char *dst, const unsigned char *src, size_t n)); /* * Private data */ extern const Elf_Scn _elf_scn_init; extern const Scn_Data _elf_data_init; extern const size_t _elf_fmsize[2][EV_CURRENT - EV_NONE][ELF_T_NUM][2]; /* * Access macros for _elf_fmsize[] */ #define _fmsize(c, v, t, w) \ (_elf_fmsize[(c)-ELFCLASS32][(v)-EV_NONE - 1][(t)-ELF_T_BYTE][(w)]) #define _fsize(c, v, t) _fmsize((c), (v), (t), 1) #define _msize(c, v, t) _fmsize((c), (v), (t), 0) /* * Various checks */ #define valid_class(c) ((c) >= ELFCLASS32 && (c) <= ELFCLASS64) #define valid_encoding(e) ((e) >= ELFDATA2LSB && (e) <= ELFDATA2MSB) #define valid_version(v) ((v) > EV_NONE && (v) <= EV_CURRENT) #define valid_type(t) ((unsigned)(t) < ELF_T_NUM) /* * Error codes */ enum { #define __err__(a, b) a, #include "errors.h" /* include constants from errors.h */ #undef __err__ ERROR_NUM }; #define seterr(err) (_elf_errno = (err)) /* * Sizes of data types (external representation) * These definitions should be in , but... */ #ifndef ELF32_FSZ_ADDR #define ELF32_FSZ_ADDR 4 #define ELF32_FSZ_HALF 2 #define ELF32_FSZ_OFF 4 #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_WORD 4 #endif /* ELF32_FSZ_ADDR */ #ifndef ELF64_FSZ_ADDR #define ELF64_FSZ_ADDR 8 #define ELF64_FSZ_HALF 2 #define ELF64_FSZ_OFF 8 #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_SXWORD 8 #define ELF64_FSZ_WORD 4 #define ELF64_FSZ_XWORD 8 #endif /* ELF64_FSZ_ADDR */ /* * More missing pieces, in no particular order */ #ifndef SHT_SYMTAB_SHNDX #define SHT_SYMTAB_SHNDX 18 #endif /* SHT_SYMTAB_SHNDX */ #ifndef SHN_XINDEX #define SHN_XINDEX 0xffff #endif /* SHN_XINDEX */ #ifndef PN_XNUM #define PN_XNUM 0xffff #endif /* PN_XNUM */ /* * Debugging */ #if ENABLE_DEBUG extern void __elf_assert __P((const char *, unsigned, const char *)); #if (__STDC__ + 0) #define elf_assert(x) \ do { \ if (!(x)) \ __elf_assert(__FILE__, __LINE__, #x); \ } while (0) #else /* __STDC__ */ #define elf_assert(x) \ do { \ if (!(x)) \ __elf_assert(__FILE__, __LINE__, "x"); \ } while (0) #endif /* __STDC__ */ #else /* ENABLE_DEBUG */ #define elf_assert(x) \ do { \ } while (0) #endif /* ENABLE_DEBUG */ /* * Return values for certain functions */ #define LIBELF_SUCCESS 1 #define LIBELF_FAILURE 0 #endif /* _PRIVATE_H */ qtrvsim-0.9.8/external/libelf/rand.c000066400000000000000000000024451467752164200174270ustar00rootroot00000000000000/* rand.c - implementation of the elf_rand(3) function. Copyright (C) 1995 - 1998 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: rand.c,v 1.7 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ size_t elf_rand(Elf *elf, size_t offset) { if (!elf) { return 0; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_AR) { seterr(ERROR_NOTARCHIVE); } else if (offset <= 0 || offset > elf->e_size) { seterr(ERROR_BADOFF); } else { elf->e_off = offset; return offset; } return 0; } qtrvsim-0.9.8/external/libelf/rawdata.c000066400000000000000000000054611467752164200201270ustar00rootroot00000000000000/* rawdata.c - implementation of the elf_rawdata(3) function. Copyright (C) 1995 - 2000 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: rawdata.c,v 1.10 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ Elf_Data *elf_rawdata(Elf_Scn *scn, Elf_Data *data) { Scn_Data *sd; Elf *elf; if (!scn) { return NULL; } elf_assert(scn->s_magic == SCN_MAGIC); elf = scn->s_elf; elf_assert(elf); elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_readable) { return NULL; } else if (scn->s_index == SHN_UNDEF || scn->s_type == SHT_NULL) { seterr(ERROR_NULLSCN); } else if (data) { return NULL; } else if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); return &sd->sd_data; } else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) { seterr(ERROR_OUTSIDE); } else if ( scn->s_type != SHT_NOBITS && scn->s_offset + scn->s_size > elf->e_size) { seterr(ERROR_TRUNC_SCN); } else if (!(sd = (Scn_Data *)malloc(sizeof(*sd)))) { seterr(ERROR_MEM_SCNDATA); } else { *sd = _elf_data_init; sd->sd_scn = scn; sd->sd_freeme = 1; sd->sd_data.d_size = scn->s_size; sd->sd_data.d_version = _elf_version; if (scn->s_type != SHT_NOBITS && scn->s_size) { if (!(sd->sd_memdata = (char *)malloc(scn->s_size))) { seterr(ERROR_IO_2BIG); free(sd); return NULL; } else if (elf->e_rawdata) { memcpy( sd->sd_memdata, elf->e_rawdata + scn->s_offset, scn->s_size); } else if (!_elf_read( elf, sd->sd_memdata, scn->s_offset, scn->s_size)) { free(sd->sd_memdata); free(sd); return NULL; } sd->sd_data.d_buf = sd->sd_memdata; sd->sd_free_data = 1; } scn->s_rawdata = sd; return &sd->sd_data; } return NULL; } qtrvsim-0.9.8/external/libelf/rawfile.c000066400000000000000000000031731467752164200201330ustar00rootroot00000000000000/* * rawfile.c - implementation of the elf_rawfile(3) function. * Copyright (C) 1995 - 2009 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: rawfile.c,v 1.8 2009/05/22 17:07:46 michael Exp $"; #endif /* lint */ char *elf_rawfile(Elf *elf, size_t *ptr) { size_t tmp; if (!ptr) { ptr = &tmp; } *ptr = 0; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!elf->e_readable) { return NULL; } else if (elf->e_size) { if (!elf->e_rawdata) { elf_assert(elf->e_data); if (!elf->e_cooked) { elf->e_rawdata = elf->e_data; } else if (!(elf->e_rawdata = _elf_read(elf, NULL, 0, elf->e_size))) { return NULL; } } *ptr = elf->e_size; } return elf->e_rawdata; } qtrvsim-0.9.8/external/libelf/strptr.c000066400000000000000000000076121467752164200200420ustar00rootroot00000000000000/* * strptr.c - implementation of the elf_strptr(3) function. * Copyright (C) 1995 - 2007 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: strptr.c,v 1.12 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ char *elf_strptr(Elf *elf, size_t section, size_t offset) { Elf_Data *data; Elf_Scn *scn; size_t n; char *s; if (!elf) { return NULL; } elf_assert(elf->e_magic == ELF_MAGIC); if (!(scn = elf_getscn(elf, section))) { return NULL; } if (scn->s_index == SHN_UNDEF) { seterr(ERROR_NOSTRTAB); return NULL; } /* * checking the section header is more appropriate */ if (elf->e_class == ELFCLASS32) { if (scn->s_shdr32.sh_type != SHT_STRTAB) { seterr(ERROR_NOSTRTAB); return NULL; } } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { if (scn->s_shdr64.sh_type != SHT_STRTAB) { seterr(ERROR_NOSTRTAB); return NULL; } } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); return NULL; } else { seterr(ERROR_UNKNOWN_CLASS); return NULL; } /* * Find matching buffer */ n = 0; data = NULL; if (elf->e_elf_flags & ELF_F_LAYOUT) { /* * Programmer is responsible for d_off * Note: buffers may be in any order! */ while ((data = elf_getdata(scn, data))) { n = data->d_off; if (offset >= n && offset - n < data->d_size) { /* * Found it */ break; } } } else { /* * Calculate offsets myself */ while ((data = elf_getdata(scn, data))) { if (data->d_align > 1) { n += data->d_align - 1; n -= n % data->d_align; } if (offset < n) { /* * Invalid offset: points into a hole */ seterr(ERROR_BADSTROFF); return NULL; } if (offset - n < data->d_size) { /* * Found it */ break; } n += data->d_size; } } if (data == NULL) { /* * Not found */ seterr(ERROR_BADSTROFF); return NULL; } if (data->d_buf == NULL) { /* * Buffer is NULL (usually the programmers' fault) */ seterr(ERROR_NULLBUF); return NULL; } offset -= n; s = (char *)data->d_buf; if (!(_elf_sanity_checks & SANITY_CHECK_STRPTR)) { return s + offset; } /* * Perform extra sanity check */ for (n = offset; n < data->d_size; n++) { if (s[n] == '\0') { /* * Return properly NUL terminated string */ return s + offset; } } /* * String is not NUL terminated * Return error to avoid SEGV in application */ seterr(ERROR_UNTERM); return NULL; } qtrvsim-0.9.8/external/libelf/swap64.c000066400000000000000000000044351467752164200176300ustar00rootroot00000000000000/* swap64.c - 64-bit byte swapping functions. Copyright (C) 1995 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "private.h" #if __LIBELF64 #ifndef lint static const char rcsid[] = "@(#) $Id: swap64.c,v 1.6 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ __libelf_u64_t _elf_load_u64L(const unsigned char *from) { return ((__libelf_u64_t)__load_u32L(from + 4) << 32) | (__libelf_u64_t)__load_u32L(from); } __libelf_u64_t _elf_load_u64M(const unsigned char *from) { return ((__libelf_u64_t)__load_u32M(from) << 32) | (__libelf_u64_t)__load_u32M(from + 4); } __libelf_i64_t _elf_load_i64L(const unsigned char *from) { return ((__libelf_i64_t)__load_i32L(from + 4) << 32) | (__libelf_u64_t)__load_u32L(from); } __libelf_i64_t _elf_load_i64M(const unsigned char *from) { return ((__libelf_i64_t)__load_i32M(from) << 32) | (__libelf_u64_t)__load_u32M(from + 4); } void _elf_store_u64L(unsigned char *to, __libelf_u64_t v) { __store_u32L(to, (__libelf_u32_t)v); v >>= 32; __store_u32L(to + 4, (__libelf_u32_t)v); } void _elf_store_u64M(unsigned char *to, __libelf_u64_t v) { __store_u32M(to + 4, (__libelf_u32_t)v); v >>= 32; __store_u32M(to, (__libelf_u32_t)v); } void _elf_store_i64L(unsigned char *to, __libelf_u64_t v) { __store_u32L(to, (__libelf_u32_t)v); v >>= 32; __store_i32L(to + 4, (__libelf_u32_t)v); } void _elf_store_i64M(unsigned char *to, __libelf_u64_t v) { __store_u32M(to + 4, (__libelf_u32_t)v); v >>= 32; __store_i32M(to, (__libelf_u32_t)v); } #endif /* __LIBELF64 */ qtrvsim-0.9.8/external/libelf/sys_elf.default.h000066400000000000000000000103241467752164200215720ustar00rootroot00000000000000#include /* lib/sys_elf.h. Generated from sys_elf.h.in by configure. */ /* sys_elf.h.in - configure template for private "switch" file. Copyright (C) 1998 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: sys_elf.h.in,v 1.13 2008/05/23 08:57:07 michael Exp $ */ /* * DO NOT USE THIS IN APPLICATIONS - #include INSTEAD! */ /* Define to `' or `' if one of them is present */ /* #undef __LIBELF_HEADER_ELF_H */ /* Define if Elf32_Dyn is declared in */ /* #undef __LIBELF_NEED_LINK_H */ /* Define if Elf32_Dyn is declared in */ /* #undef __LIBELF_NEED_SYS_LINK_H */ /* Define if you want 64-bit support (and your system supports it) */ #define __LIBELF64 1 /* Define if you want 64-bit support, and are running IRIX */ /* #undef __LIBELF64_IRIX */ /* Define if you want 64-bit support, and are running Linux */ /* #undef __LIBELF64_LINUX */ /* Define if you want symbol versioning (and your system supports it) */ #define __LIBELF_SYMBOL_VERSIONS 1 /* Define to a 64-bit signed integer type if one exists */ #define __libelf_i64_t int64_t /* Define to a 64-bit unsigned integer type if one exists */ #define __libelf_u64_t uint64_t /* Define to a 32-bit signed integer type if one exists */ #define __libelf_i32_t int32_t /* Define to a 32-bit unsigned integer type if one exists */ #define __libelf_u32_t uint32_t /* Define to a 16-bit signed integer type if one exists */ #define __libelf_i16_t int16_t /* Define to a 16-bit unsigned integer type if one exists */ #define __libelf_u16_t uint16_t /* * Ok, now get the correct instance of elf.h... */ #ifdef __LIBELF_HEADER_ELF_H #include __LIBELF_HEADER_ELF_H #else /* __LIBELF_HEADER_ELF_H */ #if __LIBELF_INTERNAL__ #include #else /* __LIBELF_INTERNAL__ */ #include #endif /* __LIBELF_INTERNAL__ */ #endif /* __LIBELF_HEADER_ELF_H */ /* * On some systems, is severely broken. Try to fix it. */ #ifdef __LIBELF_HEADER_ELF_H #ifndef ELF32_FSZ_ADDR #define ELF32_FSZ_ADDR 4 #define ELF32_FSZ_HALF 2 #define ELF32_FSZ_OFF 4 #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_WORD 4 #endif /* ELF32_FSZ_ADDR */ #ifndef STN_UNDEF #define STN_UNDEF 0 #endif /* STN_UNDEF */ #if __LIBELF64 #ifndef ELF64_FSZ_ADDR #define ELF64_FSZ_ADDR 8 #define ELF64_FSZ_HALF 2 #define ELF64_FSZ_OFF 8 #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_WORD 4 #define ELF64_FSZ_SXWORD 8 #define ELF64_FSZ_XWORD 8 #endif /* ELF64_FSZ_ADDR */ #ifndef ELF64_ST_BIND #define ELF64_ST_BIND(i) ((i) >> 4) #define ELF64_ST_TYPE(i) ((i)&0xf) #define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) #endif /* ELF64_ST_BIND */ #ifndef ELF64_R_SYM #define ELF64_R_SYM(i) ((Elf64_Xword)(i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffffL) #define ELF64_R_INFO(s, t) \ (((Elf64_Xword)(s) << 32) + ((t)&0xffffffffL)) #endif /* ELF64_R_SYM */ #if __LIBELF64_LINUX typedef __libelf_u64_t Elf64_Addr; typedef __libelf_u16_t Elf64_Half; typedef __libelf_u64_t Elf64_Off; typedef __libelf_i32_t Elf64_Sword; typedef __libelf_u32_t Elf64_Word; typedef __libelf_i64_t Elf64_Sxword; typedef __libelf_u64_t Elf64_Xword; #endif /* __LIBELF64_LINUX */ #endif /* __LIBELF64 */ #endif /* __LIBELF_HEADER_ELF_H */ qtrvsim-0.9.8/external/libelf/sys_elf.h000066400000000000000000000001701467752164200201450ustar00rootroot00000000000000#if defined(_WIN32) && !defined(__MINGW32__) #include "sys_elf.w32.h" #else #include "sys_elf.default.h" #endif qtrvsim-0.9.8/external/libelf/sys_elf.h.in000066400000000000000000000100421467752164200205510ustar00rootroot00000000000000/* sys_elf.h.in - configure template for private "switch" file. Copyright (C) 1998 - 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* @(#) $Id: sys_elf.h.in,v 1.13 2008/05/23 08:57:07 michael Exp $ */ /* * DO NOT USE THIS IN APPLICATIONS - #include INSTEAD! */ /* Define to `' or `' if one of them is present */ #undef __LIBELF_HEADER_ELF_H /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_LINK_H /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_SYS_LINK_H /* Define if you want 64-bit support (and your system supports it) */ #undef __LIBELF64 /* Define if you want 64-bit support, and are running IRIX */ #undef __LIBELF64_IRIX /* Define if you want 64-bit support, and are running Linux */ #undef __LIBELF64_LINUX /* Define if you want symbol versioning (and your system supports it) */ #undef __LIBELF_SYMBOL_VERSIONS /* Define to a 64-bit signed integer type if one exists */ #undef __libelf_i64_t /* Define to a 64-bit unsigned integer type if one exists */ #undef __libelf_u64_t /* Define to a 32-bit signed integer type if one exists */ #undef __libelf_i32_t /* Define to a 32-bit unsigned integer type if one exists */ #undef __libelf_u32_t /* Define to a 16-bit signed integer type if one exists */ #undef __libelf_i16_t /* Define to a 16-bit unsigned integer type if one exists */ #undef __libelf_u16_t /* * Ok, now get the correct instance of elf.h... */ #ifdef __LIBELF_HEADER_ELF_H #include __LIBELF_HEADER_ELF_H #else /* __LIBELF_HEADER_ELF_H */ #if __LIBELF_INTERNAL__ #include #else /* __LIBELF_INTERNAL__ */ #include #endif /* __LIBELF_INTERNAL__ */ #endif /* __LIBELF_HEADER_ELF_H */ /* * On some systems, is severely broken. Try to fix it. */ #ifdef __LIBELF_HEADER_ELF_H #ifndef ELF32_FSZ_ADDR #define ELF32_FSZ_ADDR 4 #define ELF32_FSZ_HALF 2 #define ELF32_FSZ_OFF 4 #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_WORD 4 #endif /* ELF32_FSZ_ADDR */ #ifndef STN_UNDEF #define STN_UNDEF 0 #endif /* STN_UNDEF */ #if __LIBELF64 #ifndef ELF64_FSZ_ADDR #define ELF64_FSZ_ADDR 8 #define ELF64_FSZ_HALF 2 #define ELF64_FSZ_OFF 8 #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_WORD 4 #define ELF64_FSZ_SXWORD 8 #define ELF64_FSZ_XWORD 8 #endif /* ELF64_FSZ_ADDR */ #ifndef ELF64_ST_BIND #define ELF64_ST_BIND(i) ((i) >> 4) #define ELF64_ST_TYPE(i) ((i)&0xf) #define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) #endif /* ELF64_ST_BIND */ #ifndef ELF64_R_SYM #define ELF64_R_SYM(i) ((Elf64_Xword)(i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffffL) #define ELF64_R_INFO(s, t) \ (((Elf64_Xword)(s) << 32) + ((t)&0xffffffffL)) #endif /* ELF64_R_SYM */ #if __LIBELF64_LINUX typedef __libelf_u64_t Elf64_Addr; typedef __libelf_u16_t Elf64_Half; typedef __libelf_u64_t Elf64_Off; typedef __libelf_i32_t Elf64_Sword; typedef __libelf_u32_t Elf64_Word; typedef __libelf_i64_t Elf64_Sxword; typedef __libelf_u64_t Elf64_Xword; #endif /* __LIBELF64_LINUX */ #endif /* __LIBELF64 */ #endif /* __LIBELF_HEADER_ELF_H */ qtrvsim-0.9.8/external/libelf/sys_elf.w32.h000066400000000000000000000102361467752164200205630ustar00rootroot00000000000000/* * lib/sys_elf.h.w32 - internal configuration file for W32 port * Copyright (C) 2004 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @(#) $Id: sys_elf.h.w32,v 1.2 2006/09/07 15:55:42 michael Exp $ */ /* * DO NOT USE THIS IN APPLICATIONS - #include INSTEAD! */ /* Define to `' or `' if one of them is present */ #undef __LIBELF_HEADER_ELF_H /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_LINK_H /* Define if Elf32_Dyn is declared in */ #undef __LIBELF_NEED_SYS_LINK_H /* Define if you want 64-bit support (and your system supports it) */ #define __LIBELF64 1 /* Define if you want 64-bit support, and are running IRIX */ #undef __LIBELF64_IRIX /* Define if you want 64-bit support, and are running Linux */ #undef __LIBELF64_LINUX /* Define if you want symbol versioning (and your system supports it) */ #define __LIBELF_SYMBOL_VERSIONS 1 /* Define to a 64-bit signed integer type if one exists */ #define __libelf_i64_t __int64 /* Define to a 64-bit unsigned integer type if one exists */ #define __libelf_u64_t unsigned __int64 /* Define to a 32-bit signed integer type if one exists */ #define __libelf_i32_t int /* Define to a 32-bit unsigned integer type if one exists */ #define __libelf_u32_t unsigned int /* Define to a 16-bit signed integer type if one exists */ #define __libelf_i16_t short int /* Define to a 16-bit unsigned integer type if one exists */ #define __libelf_u16_t unsigned short int /* * Ok, now get the correct instance of elf.h... */ #ifdef __LIBELF_HEADER_ELF_H #include __LIBELF_HEADER_ELF_H #else /* __LIBELF_HEADER_ELF_H */ #if __LIBELF_INTERNAL__ #include #else /* __LIBELF_INTERNAL__ */ #include #endif /* __LIBELF_INTERNAL__ */ #endif /* __LIBELF_HEADER_ELF_H */ /* * On some systems, is severely broken. Try to fix it. */ #ifdef __LIBELF_HEADER_ELF_H #ifndef ELF32_FSZ_ADDR #define ELF32_FSZ_ADDR 4 #define ELF32_FSZ_HALF 2 #define ELF32_FSZ_OFF 4 #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_WORD 4 #endif /* ELF32_FSZ_ADDR */ #ifndef STN_UNDEF #define STN_UNDEF 0 #endif /* STN_UNDEF */ #if __LIBELF64 #ifndef ELF64_FSZ_ADDR #define ELF64_FSZ_ADDR 8 #define ELF64_FSZ_HALF 2 #define ELF64_FSZ_OFF 8 #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_WORD 4 #define ELF64_FSZ_SXWORD 8 #define ELF64_FSZ_XWORD 8 #endif /* ELF64_FSZ_ADDR */ #ifndef ELF64_ST_BIND #define ELF64_ST_BIND(i) ((i) >> 4) #define ELF64_ST_TYPE(i) ((i)&0xf) #define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) #endif /* ELF64_ST_BIND */ #ifndef ELF64_R_SYM #define ELF64_R_SYM(i) ((Elf64_Xword)(i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffffL) #define ELF64_R_INFO(s, t) \ (((Elf64_Xword)(s) << 32) + ((t)&0xffffffffL)) #endif /* ELF64_R_SYM */ #if __LIBELF64_LINUX typedef __libelf_u64_t Elf64_Addr; typedef __libelf_u16_t Elf64_Half; typedef __libelf_u64_t Elf64_Off; typedef __libelf_i32_t Elf64_Sword; typedef __libelf_u32_t Elf64_Word; typedef __libelf_i64_t Elf64_Sxword; typedef __libelf_u64_t Elf64_Xword; #endif /* __LIBELF64_LINUX */ #endif /* __LIBELF64 */ #endif /* __LIBELF_HEADER_ELF_H */ qtrvsim-0.9.8/external/libelf/update.c000066400000000000000000000754221467752164200177720ustar00rootroot00000000000000/* * update.c - implementation of the elf_update(3) function. * Copyright (C) 1995 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: update.c,v 1.34 2009/05/22 17:08:09 michael Exp $"; #endif /* lint */ #include #if HAVE_MMAP #include #endif /* HAVE_MMAP */ static const unsigned short __encoding = ELFDATA2LSB + (ELFDATA2MSB << 8); #define native_encoding (*(unsigned char *)&__encoding) #define rewrite(var, val, f) \ do { \ if ((var) != (val)) { \ (var) = (val); \ (f) |= ELF_F_DIRTY; \ } \ } while (0) #define align(var, val) \ do { \ if ((val) > 1) { \ (var) += (val)-1; \ (var) -= (var) % (val); \ } \ } while (0) #undef max #define max(a, b) ((a) > (b) ? (a) : (b)) static off_t scn_data_layout( Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) { Elf *elf = scn->s_elf; Elf_Data *data; int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; size_t scn_align = 1; size_t len = 0; Scn_Data *sd; size_t fsize; if (!(sd = scn->s_data_1)) { /* no data in section */ *algn = scn_align; return (off_t)len; } /* load data from file, if any */ if (!(data = elf_getdata(scn, NULL))) { return (off_t)-1; } elf_assert(data == &sd->sd_data); for (; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (!valid_version(sd->sd_data.d_version)) { return (off_t)-1; } fsize = sd->sd_data.d_size; if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) { if (elf->e_class == ELFCLASS32) { fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1); } #endif /* __LIBELF64 */ else { elf_assert(valid_class(elf->e_class)); seterr(ERROR_UNIMPLEMENTED); return (off_t)-1; } if (fsize == (size_t)-1) { return (off_t)-1; } } if (layout) { align(len, sd->sd_data.d_align); scn_align = max(scn_align, sd->sd_data.d_align); rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags); len += fsize; } else { len = max(len, sd->sd_data.d_off + fsize); } *flag |= sd->sd_data_flags; } *algn = scn_align; return (off_t)len; } static size_t scn_entsize(const Elf *elf, unsigned version, unsigned stype) { Elf_Type type; switch ((type = _elf_scn_type(stype))) { case ELF_T_BYTE: return 0; case ELF_T_VDEF: case ELF_T_VNEED: return 0; /* What else can I do? Thank you, Sun! */ default: return _fsize(elf->e_class, version, type); } } static off_t _elf32_layout(Elf *elf, unsigned *flag) { int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; int allow_overlap = (elf->e_elf_flags & ELF_F_LAYOUT_OVERLAP) != 0; Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elf->e_ehdr; size_t off = 0; unsigned version; unsigned encoding; size_t align_addr; size_t entsize; unsigned phnum; unsigned shnum; Elf_Scn *scn; *flag = elf->e_elf_flags | elf->e_phdr_flags; if ((version = ehdr->e_version) == EV_NONE) { version = EV_CURRENT; } if (!valid_version(version)) { seterr(ERROR_UNKNOWN_VERSION); return -1; } if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) { encoding = native_encoding; } if (!valid_encoding(encoding)) { seterr(ERROR_UNKNOWN_ENCODING); return -1; } entsize = _fsize(ELFCLASS32, version, ELF_T_EHDR); elf_assert(entsize); rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags); off = entsize; align_addr = _fsize(ELFCLASS32, version, ELF_T_ADDR); elf_assert(align_addr); if ((phnum = elf->e_phnum)) { entsize = _fsize(ELFCLASS32, version, ELF_T_PHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags); off += phnum * entsize; } else { off = max(off, ehdr->e_phoff + phnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags); } } if (phnum >= PN_XNUM) { Elf_Scn *scn = elf->e_scn_1; Elf32_Shdr *shdr = &scn->s_shdr32; elf_assert(scn); elf_assert(scn->s_index == 0); rewrite(shdr->sh_info, phnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; phnum = PN_XNUM; } rewrite(ehdr->e_phnum, phnum, elf->e_ehdr_flags); rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags); for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) { Elf32_Shdr *shdr = &scn->s_shdr32; size_t scn_align = 1; off_t len; elf_assert(scn->s_index == shnum); *flag |= scn->s_scn_flags; if (scn->s_index == SHN_UNDEF) { rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags); if (layout) { rewrite(shdr->sh_offset, 0, scn->s_shdr_flags); rewrite(shdr->sh_size, 0, scn->s_shdr_flags); rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags); } *flag |= scn->s_shdr_flags; continue; } if (shdr->sh_type == SHT_NULL) { *flag |= scn->s_shdr_flags; continue; } len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag); if (len == -1) { return -1; } /* * Never override the program's choice. */ if (shdr->sh_entsize == 0) { entsize = scn_entsize(elf, version, shdr->sh_type); if (entsize > 1) { rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags); } } if (layout) { align(off, scn_align); rewrite(shdr->sh_offset, off, scn->s_shdr_flags); rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags); rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags); if (shdr->sh_type != SHT_NOBITS) { off += (size_t)len; } } else if ((size_t)len > shdr->sh_size) { seterr(ERROR_SCN2SMALL); return -1; } else { Elf_Scn *scn2; size_t end1, end2; end1 = shdr->sh_offset; if (shdr->sh_type != SHT_NOBITS) { end1 += shdr->sh_size; } if (!allow_overlap && shdr->sh_offset < off) { /* * check for overlapping sections */ for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) { if (scn2 == scn) { break; } end2 = scn2->s_shdr32.sh_offset; if (scn2->s_shdr32.sh_type != SHT_NOBITS) { end2 += scn2->s_shdr32.sh_size; } if (end1 > scn2->s_shdr32.sh_offset && end2 > shdr->sh_offset) { seterr(ERROR_SCN_OVERLAP); return -1; } } } if (off < end1) { off = end1; } } *flag |= scn->s_shdr_flags; } if (shnum) { entsize = _fsize(ELFCLASS32, version, ELF_T_SHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags); off += shnum * entsize; } else { off = max(off, ehdr->e_shoff + shnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags); } } if (shnum >= SHN_LORESERVE) { Elf_Scn *scn = elf->e_scn_1; Elf32_Shdr *shdr = &scn->s_shdr32; elf_assert(scn->s_index == 0); rewrite(shdr->sh_size, shnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; shnum = 0; } rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags); rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS32, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags); rewrite(ehdr->e_version, version, elf->e_ehdr_flags); *flag |= elf->e_ehdr_flags; return off; } #if __LIBELF64 static off_t _elf64_layout(Elf *elf, unsigned *flag) { int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0; int allow_overlap = (elf->e_elf_flags & ELF_F_LAYOUT_OVERLAP) != 0; Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elf->e_ehdr; size_t off = 0; unsigned version; unsigned encoding; size_t align_addr; size_t entsize; unsigned phnum; unsigned shnum; Elf_Scn *scn; *flag = elf->e_elf_flags | elf->e_phdr_flags; if ((version = ehdr->e_version) == EV_NONE) { version = EV_CURRENT; } if (!valid_version(version)) { seterr(ERROR_UNKNOWN_VERSION); return -1; } if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) { encoding = native_encoding; } if (!valid_encoding(encoding)) { seterr(ERROR_UNKNOWN_ENCODING); return -1; } entsize = _fsize(ELFCLASS64, version, ELF_T_EHDR); elf_assert(entsize); rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags); off = entsize; align_addr = _fsize(ELFCLASS64, version, ELF_T_ADDR); elf_assert(align_addr); if ((phnum = elf->e_phnum)) { entsize = _fsize(ELFCLASS64, version, ELF_T_PHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags); off += phnum * entsize; } else { off = max(off, ehdr->e_phoff + phnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags); } } if (phnum >= PN_XNUM) { Elf_Scn *scn = elf->e_scn_1; Elf32_Shdr *shdr = &scn->s_shdr32; /* modify first section header, too! */ elf_assert(scn); elf_assert(scn->s_index == 0); rewrite(shdr->sh_info, phnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; phnum = PN_XNUM; } rewrite(ehdr->e_phnum, phnum, elf->e_ehdr_flags); rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags); for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) { Elf64_Shdr *shdr = &scn->s_shdr64; size_t scn_align = 1; off_t len; elf_assert(scn->s_index == shnum); *flag |= scn->s_scn_flags; if (scn->s_index == SHN_UNDEF) { rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags); if (layout) { rewrite(shdr->sh_offset, 0, scn->s_shdr_flags); rewrite(shdr->sh_size, 0, scn->s_shdr_flags); rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags); } *flag |= scn->s_shdr_flags; continue; } if (shdr->sh_type == SHT_NULL) { *flag |= scn->s_shdr_flags; continue; } len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag); if (len == -1) { return -1; } /* * Never override the program's choice. */ if (shdr->sh_entsize == 0) { entsize = scn_entsize(elf, version, shdr->sh_type); if (entsize > 1) { rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags); } } if (layout) { align(off, scn_align); rewrite(shdr->sh_offset, off, scn->s_shdr_flags); rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags); rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags); if (shdr->sh_type != SHT_NOBITS) { off += (size_t)len; } } else if ((size_t)len > shdr->sh_size) { seterr(ERROR_SCN2SMALL); return -1; } else { Elf_Scn *scn2; size_t end1, end2; end1 = shdr->sh_offset; if (shdr->sh_type != SHT_NOBITS) { end1 += shdr->sh_size; } if (!allow_overlap && shdr->sh_offset < off) { /* * check for overlapping sections */ for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) { if (scn2 == scn) { break; } end2 = scn2->s_shdr64.sh_offset; if (scn2->s_shdr64.sh_type != SHT_NOBITS) { end2 += scn2->s_shdr64.sh_size; } if (end1 > scn2->s_shdr64.sh_offset && end2 > shdr->sh_offset) { seterr(ERROR_SCN_OVERLAP); return -1; } } } if (off < end1) { off = end1; } } *flag |= scn->s_shdr_flags; } if (shnum) { entsize = _fsize(ELFCLASS64, version, ELF_T_SHDR); elf_assert(entsize); if (layout) { align(off, align_addr); rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags); off += shnum * entsize; } else { off = max(off, ehdr->e_shoff + shnum * entsize); } } else { entsize = 0; if (layout) { rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags); } } if (shnum >= SHN_LORESERVE) { Elf_Scn *scn = elf->e_scn_1; Elf64_Shdr *shdr = &scn->s_shdr64; elf_assert(scn->s_index == 0); rewrite(shdr->sh_size, shnum, scn->s_shdr_flags); *flag |= scn->s_shdr_flags; shnum = 0; } rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags); rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS64, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags); rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags); rewrite(ehdr->e_version, version, elf->e_ehdr_flags); *flag |= elf->e_ehdr_flags; return off; } #endif /* __LIBELF64 */ #define ptrinside(p, a, l) ((p) >= (a) && (p) < (a) + (l)) #define newptr(p, o, n) ((p) = ((p) - (o)) + (n)) static int _elf_update_pointers(Elf *elf, char *outbuf, size_t len) { Elf_Scn *scn; Scn_Data *sd; char *data, *rawdata; elf_assert(elf); elf_assert(elf->e_data); elf_assert(!elf->e_parent); elf_assert(!elf->e_unmap_data); elf_assert(elf->e_kind == ELF_K_ELF); elf_assert(len >= EI_NIDENT); /* resize memory images */ if (len <= elf->e_dsize) { /* don't shorten the memory image */ data = elf->e_data; } else if ((data = (char *)realloc(elf->e_data, len))) { elf->e_dsize = len; } else { seterr(ERROR_IO_2BIG); return -1; } if (elf->e_rawdata == elf->e_data) { /* update frozen raw image */ memcpy(data, outbuf, len); elf->e_data = elf->e_rawdata = data; /* cooked data is stored outside the raw image */ return 0; } if (elf->e_rawdata) { /* update raw image */ if (!(rawdata = (char *)realloc(elf->e_rawdata, len))) { seterr(ERROR_IO_2BIG); return -1; } memcpy(rawdata, outbuf, len); elf->e_rawdata = rawdata; } if (data == elf->e_data) { /* nothing more to do */ return 0; } /* adjust internal pointers */ for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); if ((sd = scn->s_data_1)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_memdata && !sd->sd_free_data) { elf_assert( ptrinside(sd->sd_memdata, elf->e_data, elf->e_dsize)); if (sd->sd_data.d_buf == sd->sd_memdata) { newptr(sd->sd_memdata, elf->e_data, data); sd->sd_data.d_buf = sd->sd_memdata; } else { newptr(sd->sd_memdata, elf->e_data, data); } } } if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_memdata && sd->sd_free_data) { size_t off, len; if (elf->e_class == ELFCLASS32) { off = scn->s_shdr32.sh_offset; len = scn->s_shdr32.sh_size; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { off = scn->s_shdr64.sh_offset; len = scn->s_shdr64.sh_size; } #endif /* __LIBELF64 */ else { seterr(ERROR_UNIMPLEMENTED); return -1; } if (!(rawdata = (char *)realloc(sd->sd_memdata, len))) { seterr(ERROR_IO_2BIG); return -1; } memcpy(rawdata, outbuf + off, len); if (sd->sd_data.d_buf == sd->sd_memdata) { sd->sd_data.d_buf = rawdata; } sd->sd_memdata = rawdata; } } } elf->e_data = data; return 0; } #undef ptrinside #undef newptr static off_t _elf32_write(Elf *elf, char *outbuf, size_t len) { Elf32_Ehdr *ehdr; Elf32_Shdr *shdr; Elf_Scn *scn; Scn_Data *sd; Elf_Data src; Elf_Data dst; unsigned encode; elf_assert(len); elf_assert(elf->e_ehdr); ehdr = (Elf32_Ehdr *)elf->e_ehdr; encode = ehdr->e_ident[EI_DATA]; src.d_buf = ehdr; src.d_type = ELF_T_EHDR; src.d_size = _msize(ELFCLASS32, _elf_version, ELF_T_EHDR); src.d_version = _elf_version; dst.d_buf = outbuf; dst.d_size = ehdr->e_ehsize; dst.d_version = ehdr->e_version; if (!elf32_xlatetof(&dst, &src, encode)) { return -1; } if (elf->e_phnum) { src.d_buf = elf->e_phdr; src.d_type = ELF_T_PHDR; src.d_size = elf->e_phnum * _msize(ELFCLASS32, _elf_version, ELF_T_PHDR); src.d_version = _elf_version; dst.d_buf = outbuf + ehdr->e_phoff; dst.d_size = elf->e_phnum * ehdr->e_phentsize; dst.d_version = ehdr->e_version; if (!elf32_xlatetof(&dst, &src, encode)) { return -1; } } for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); src.d_buf = &scn->s_uhdr; src.d_type = ELF_T_SHDR; src.d_size = _msize(ELFCLASS32, EV_CURRENT, ELF_T_SHDR); src.d_version = EV_CURRENT; dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize; dst.d_size = ehdr->e_shentsize; dst.d_version = ehdr->e_version; if (!elf32_xlatetof(&dst, &src, encode)) { return -1; } if (scn->s_index == SHN_UNDEF) { continue; } shdr = &scn->s_shdr32; if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) { continue; } /* XXX: this is probably no longer necessary */ if (scn->s_data_1 && !elf_getdata(scn, NULL)) { return -1; } for (sd = scn->s_data_1; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); src = sd->sd_data; if (!src.d_size) { continue; } if (!src.d_buf) { seterr(ERROR_NULLBUF); return -1; } dst.d_buf = outbuf + shdr->sh_offset + src.d_off; dst.d_size = src.d_size; dst.d_version = ehdr->e_version; if (valid_type(src.d_type)) { size_t tmp; tmp = _elf32_xltsize(&src, dst.d_version, ELFDATA2LSB, 1); if (tmp == (size_t)-1) { return -1; } dst.d_size = tmp; } else { src.d_type = ELF_T_BYTE; } if (!elf32_xlatetof(&dst, &src, encode)) { return -1; } } } /* cleanup */ if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) { return -1; } /* NOTE: ehdr is no longer valid! */ ehdr = (Elf32_Ehdr *)elf->e_ehdr; elf_assert(ehdr); elf->e_encoding = ehdr->e_ident[EI_DATA]; elf->e_version = ehdr->e_ident[EI_VERSION]; elf->e_elf_flags &= ~ELF_F_DIRTY; elf->e_ehdr_flags &= ~ELF_F_DIRTY; elf->e_phdr_flags &= ~ELF_F_DIRTY; for (scn = elf->e_scn_1; scn; scn = scn->s_link) { scn->s_scn_flags &= ~ELF_F_DIRTY; scn->s_shdr_flags &= ~ELF_F_DIRTY; for (sd = scn->s_data_1; sd; sd = sd->sd_link) { sd->sd_data_flags &= ~ELF_F_DIRTY; } if (elf->e_readable) { shdr = &scn->s_shdr32; scn->s_type = shdr->sh_type; scn->s_size = shdr->sh_size; scn->s_offset = shdr->sh_offset; } } elf->e_size = len; return len; } #if __LIBELF64 static off_t _elf64_write(Elf *elf, char *outbuf, size_t len) { Elf64_Ehdr *ehdr; Elf64_Shdr *shdr; Elf_Scn *scn; Scn_Data *sd; Elf_Data src; Elf_Data dst; unsigned encode; elf_assert(len); elf_assert(elf->e_ehdr); ehdr = (Elf64_Ehdr *)elf->e_ehdr; encode = ehdr->e_ident[EI_DATA]; src.d_buf = ehdr; src.d_type = ELF_T_EHDR; src.d_size = _msize(ELFCLASS64, _elf_version, ELF_T_EHDR); src.d_version = _elf_version; dst.d_buf = outbuf; dst.d_size = ehdr->e_ehsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } if (elf->e_phnum) { src.d_buf = elf->e_phdr; src.d_type = ELF_T_PHDR; src.d_size = elf->e_phnum * _msize(ELFCLASS64, _elf_version, ELF_T_PHDR); src.d_version = _elf_version; dst.d_buf = outbuf + ehdr->e_phoff; dst.d_size = elf->e_phnum * ehdr->e_phentsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } } for (scn = elf->e_scn_1; scn; scn = scn->s_link) { elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(scn->s_elf == elf); src.d_buf = &scn->s_uhdr; src.d_type = ELF_T_SHDR; src.d_size = _msize(ELFCLASS64, EV_CURRENT, ELF_T_SHDR); src.d_version = EV_CURRENT; dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize; dst.d_size = ehdr->e_shentsize; dst.d_version = ehdr->e_version; if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } if (scn->s_index == SHN_UNDEF) { continue; } shdr = &scn->s_shdr64; if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) { continue; } /* XXX: this is probably no longer necessary */ if (scn->s_data_1 && !elf_getdata(scn, NULL)) { return -1; } for (sd = scn->s_data_1; sd; sd = sd->sd_link) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); src = sd->sd_data; if (!src.d_size) { continue; } if (!src.d_buf) { seterr(ERROR_NULLBUF); return -1; } dst.d_buf = outbuf + shdr->sh_offset + src.d_off; dst.d_size = src.d_size; dst.d_version = ehdr->e_version; if (valid_type(src.d_type)) { size_t tmp; tmp = _elf64_xltsize(&src, dst.d_version, ELFDATA2LSB, 1); if (tmp == (size_t)-1) { return -1; } dst.d_size = tmp; } else { src.d_type = ELF_T_BYTE; } if (!elf64_xlatetof(&dst, &src, encode)) { return -1; } } } /* cleanup */ if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) { return -1; } /* NOTE: ehdr is no longer valid! */ ehdr = (Elf64_Ehdr *)elf->e_ehdr; elf_assert(ehdr); elf->e_encoding = ehdr->e_ident[EI_DATA]; elf->e_version = ehdr->e_ident[EI_VERSION]; elf->e_elf_flags &= ~ELF_F_DIRTY; elf->e_ehdr_flags &= ~ELF_F_DIRTY; elf->e_phdr_flags &= ~ELF_F_DIRTY; for (scn = elf->e_scn_1; scn; scn = scn->s_link) { scn->s_scn_flags &= ~ELF_F_DIRTY; scn->s_shdr_flags &= ~ELF_F_DIRTY; for (sd = scn->s_data_1; sd; sd = sd->sd_link) { sd->sd_data_flags &= ~ELF_F_DIRTY; } if (elf->e_readable) { shdr = &scn->s_shdr64; scn->s_type = shdr->sh_type; scn->s_size = shdr->sh_size; scn->s_offset = shdr->sh_offset; } } elf->e_size = len; return len; } #endif /* __LIBELF64 */ static int xwrite(int fd, char *buffer, size_t len) { size_t done = 0; size_t n; while (done < len) { n = write(fd, buffer + done, len - done); if (n == 0) { /* file system full */ return -1; } else if (n != (size_t)-1) { /* some bytes written, continue */ done += n; } else if (errno != EAGAIN && errno != EINTR) { /* real error */ return -1; } } return 0; } static off_t _elf_output( Elf *elf, int fd, size_t len, off_t (*_elf_write)(Elf *, char *, size_t)) { char *buf; off_t err; elf_assert(len); #if HAVE_FTRUNCATE ftruncate(fd, 0); #endif /* HAVE_FTRUNCATE */ #if HAVE_MMAP /* * Make sure the file is (at least) len bytes long */ #if HAVE_FTRUNCATE lseek(fd, (off_t)len, SEEK_SET); if (ftruncate(fd, len)) { #else /* HAVE_FTRUNCATE */ { #endif /* HAVE_FTRUNCATE */ if (lseek(fd, (off_t)len - 1, SEEK_SET) != (off_t)len - 1) { seterr(ERROR_IO_SEEK); return -1; } if (xwrite(fd, "", 1)) { seterr(ERROR_IO_WRITE); return -1; } } buf = (void *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf != (char *)-1) { if ((char)_elf_fill && !(elf->e_elf_flags & ELF_F_LAYOUT)) { memset(buf, _elf_fill, len); } err = _elf_write(elf, buf, len); munmap(buf, len); return err; } #endif /* HAVE_MMAP */ if (!(buf = (char *)malloc(len))) { seterr(ERROR_MEM_OUTBUF); return -1; } memset(buf, _elf_fill, len); err = _elf_write(elf, buf, len); if (err != -1 && (size_t)err == len) { if (lseek(fd, (off_t)0, SEEK_SET)) { seterr(ERROR_IO_SEEK); err = -1; } else if (xwrite(fd, buf, len)) { seterr(ERROR_IO_WRITE); err = -1; } } free(buf); return err; } off_t elf_update(Elf *elf, Elf_Cmd cmd) { unsigned flag; off_t len; if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (cmd == ELF_C_WRITE) { if (!elf->e_writable) { seterr(ERROR_RDONLY); return -1; } if (elf->e_disabled) { seterr(ERROR_FDDISABLED); return -1; } } else if (cmd != ELF_C_NULL) { seterr(ERROR_INVALID_CMD); return -1; } if (!elf->e_ehdr) { seterr(ERROR_NOEHDR); } else if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); } else if (elf->e_class == ELFCLASS32) { len = _elf32_layout(elf, &flag); if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) { len = _elf_output(elf, elf->e_fd, (size_t)len, _elf32_write); } return len; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { len = _elf64_layout(elf, &flag); if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) { len = _elf_output(elf, elf->e_fd, (size_t)len, _elf64_write); } return len; } #endif /* __LIBELF64 */ else if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return -1; } qtrvsim-0.9.8/external/libelf/verdef.h000066400000000000000000000170361467752164200177650ustar00rootroot00000000000000/* * verdef.h - copy versioning information. * Copyright (C) 2001 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef lint static const char verdef_h_rcsid[] = "@(#) $Id: verdef.h,v 1.13 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ #if VER_DEF_CURRENT != 1 #error libelf currently does not support VER_DEF_CURRENT != 1 #endif /* VER_DEF_CURRENT != 1 */ #if TOFILE static void __store_verdaux(verdaux_ftype *dst, const verdaux_mtype *src, unsigned enc) { if (enc == ELFDATA2LSB) { __store_u32L(dst->vda_name, src->vda_name); __store_u32L(dst->vda_next, src->vda_next); } else { __store_u32M(dst->vda_name, src->vda_name); __store_u32M(dst->vda_next, src->vda_next); } } static void __store_verdef(verdef_ftype *dst, const verdef_mtype *src, unsigned enc) { if (enc == ELFDATA2LSB) { __store_u16L(dst->vd_version, src->vd_version); __store_u16L(dst->vd_flags, src->vd_flags); __store_u16L(dst->vd_ndx, src->vd_ndx); __store_u16L(dst->vd_cnt, src->vd_cnt); __store_u32L(dst->vd_hash, src->vd_hash); __store_u32L(dst->vd_aux, src->vd_aux); __store_u32L(dst->vd_next, src->vd_next); } else { __store_u16M(dst->vd_version, src->vd_version); __store_u16M(dst->vd_flags, src->vd_flags); __store_u16M(dst->vd_ndx, src->vd_ndx); __store_u16M(dst->vd_cnt, src->vd_cnt); __store_u32M(dst->vd_hash, src->vd_hash); __store_u32M(dst->vd_aux, src->vd_aux); __store_u32M(dst->vd_next, src->vd_next); } } typedef verdaux_mtype verdaux_stype; typedef verdaux_ftype verdaux_dtype; typedef verdef_mtype verdef_stype; typedef verdef_ftype verdef_dtype; typedef align_mtype verdef_atype; #define copy_verdaux_srctotmp(d, s, e) (*(d) = *(s)) #define copy_verdaux_tmptodst(d, s, e) __store_verdaux((d), (s), (e)) #define copy_verdef_srctotmp(d, s, e) (*(d) = *(s)) #define copy_verdef_tmptodst(d, s, e) __store_verdef((d), (s), (e)) #define translator_suffix _tof #else /* TOFILE */ static void __load_verdaux(verdaux_mtype *dst, const verdaux_ftype *src, unsigned enc) { if (enc == ELFDATA2LSB) { dst->vda_name = __load_u32L(src->vda_name); dst->vda_next = __load_u32L(src->vda_next); } else { dst->vda_name = __load_u32M(src->vda_name); dst->vda_next = __load_u32M(src->vda_next); } } static void __load_verdef(verdef_mtype *dst, const verdef_ftype *src, unsigned enc) { if (enc == ELFDATA2LSB) { dst->vd_version = __load_u16L(src->vd_version); dst->vd_flags = __load_u16L(src->vd_flags); dst->vd_ndx = __load_u16L(src->vd_ndx); dst->vd_cnt = __load_u16L(src->vd_cnt); dst->vd_hash = __load_u32L(src->vd_hash); dst->vd_aux = __load_u32L(src->vd_aux); dst->vd_next = __load_u32L(src->vd_next); } else { dst->vd_version = __load_u16M(src->vd_version); dst->vd_flags = __load_u16M(src->vd_flags); dst->vd_ndx = __load_u16M(src->vd_ndx); dst->vd_cnt = __load_u16M(src->vd_cnt); dst->vd_hash = __load_u32M(src->vd_hash); dst->vd_aux = __load_u32M(src->vd_aux); dst->vd_next = __load_u32M(src->vd_next); } } typedef verdaux_ftype verdaux_stype; typedef verdaux_mtype verdaux_dtype; typedef verdef_ftype verdef_stype; typedef verdef_mtype verdef_dtype; typedef align_ftype verdef_atype; #define copy_verdaux_srctotmp(d, s, e) __load_verdaux((d), (s), (e)) #define copy_verdaux_tmptodst(d, s, e) (*(d) = *(s)) #define copy_verdef_srctotmp(d, s, e) __load_verdef((d), (s), (e)) #define copy_verdef_tmptodst(d, s, e) (*(d) = *(s)) #define translator_suffix _tom #endif /* TOFILE */ #define cat3(a, b, c) a##b##c #define xlt3(p, e, s) cat3(p, e, s) #define xltprefix(x) xlt3(x, _, class_suffix) #define translator(x, e) xlt3(xltprefix(_elf_##x), e, translator_suffix) static size_t xlt_verdef( unsigned char *dst, const unsigned char *src, size_t n, unsigned enc) { size_t off; if (sizeof(verdef_stype) != sizeof(verdef_dtype) || sizeof(verdaux_stype) != sizeof(verdaux_dtype)) { /* never happens for ELF v1 and Verneed v1 */ seterr(ERROR_UNIMPLEMENTED); return (size_t)-1; } /* size translation shortcut */ if (dst == NULL) { return n; } if (src == NULL) { seterr(ERROR_NULLBUF); return (size_t)-1; } off = 0; while (off + sizeof(verdef_stype) <= n) { const verdef_stype *svd; verdef_dtype *dvd; verdef_mtype vd; size_t acount; size_t aoff; /* * check for proper alignment */ if (off % sizeof(verdef_atype)) { seterr(ERROR_VERDEF_FORMAT); return (size_t)-1; } /* * copy and check src */ svd = (verdef_stype *)(src + off); dvd = (verdef_dtype *)(dst + off); copy_verdef_srctotmp(&vd, svd, enc); if (vd.vd_version < 1 || vd.vd_version > VER_DEF_CURRENT) { seterr(ERROR_VERDEF_VERSION); return (size_t)-1; } if (vd.vd_cnt < 1 || vd.vd_aux == 0) { seterr(ERROR_VERDEF_FORMAT); return (size_t)-1; } copy_verdef_tmptodst(dvd, &vd, enc); /* * copy aux array */ aoff = off + vd.vd_aux; for (acount = 0; acount < vd.vd_cnt; acount++) { const verdaux_stype *svda; verdaux_dtype *dvda; verdaux_mtype vda; /* * are we still inside the buffer limits? */ if (aoff + sizeof(verdaux_stype) > n) { break; } /* * check for proper alignment */ if (aoff % sizeof(verdef_atype)) { seterr(ERROR_VERDEF_FORMAT); return (size_t)-1; } /* * copy and check src */ svda = (verdaux_stype *)(src + aoff); dvda = (verdaux_dtype *)(dst + aoff); copy_verdaux_srctotmp(&vda, svda, enc); copy_verdaux_tmptodst(dvda, &vda, enc); /* * advance to next verdaux */ if (vda.vda_next == 0) { /* end of list */ break; } aoff += vda.vda_next; } /* * advance to next verdef */ if (vd.vd_next == 0) { /* end of list */ break; } off += vd.vd_next; } return n; } size_t translator( verdef, L11)(unsigned char *dst, const unsigned char *src, size_t n) { return xlt_verdef(dst, src, n, ELFDATA2LSB); } size_t translator( verdef, M11)(unsigned char *dst, const unsigned char *src, size_t n) { return xlt_verdef(dst, src, n, ELFDATA2MSB); } qtrvsim-0.9.8/external/libelf/verdef_32_tof.c000066400000000000000000000031301467752164200211220ustar00rootroot00000000000000/* verdef_32_tof.c - copy 32-bit versioning information. Copyright (C) 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #if __LIBELF_SYMBOL_VERSIONS #ifndef lint static const char rcsid[] = "@(#) $Id: verdef_32_tof.c,v 1.5 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ typedef Elf32_Verdaux verdaux_mtype; typedef Elf32_Verdef verdef_mtype; typedef Elf32_Vernaux vernaux_mtype; typedef Elf32_Verneed verneed_mtype; typedef Elf32_Word align_mtype; typedef __ext_Elf32_Verdaux verdaux_ftype; typedef __ext_Elf32_Verdef verdef_ftype; typedef __ext_Elf32_Vernaux vernaux_ftype; typedef __ext_Elf32_Verneed verneed_ftype; typedef __ext_Elf32_Word align_ftype; #define class_suffix 32 #undef TOFILE #define TOFILE 1 /* * Include shared code */ #include "verdef.h" #include "verneed.h" #endif /* __LIBELF_SYMBOL_VERSIONS */ qtrvsim-0.9.8/external/libelf/verdef_32_tom.c000066400000000000000000000031301467752164200211310ustar00rootroot00000000000000/* verdef_32_tom.c - copy 32-bit versioning information. Copyright (C) 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #if __LIBELF_SYMBOL_VERSIONS #ifndef lint static const char rcsid[] = "@(#) $Id: verdef_32_tom.c,v 1.5 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ typedef Elf32_Verdaux verdaux_mtype; typedef Elf32_Verdef verdef_mtype; typedef Elf32_Vernaux vernaux_mtype; typedef Elf32_Verneed verneed_mtype; typedef Elf32_Word align_mtype; typedef __ext_Elf32_Verdaux verdaux_ftype; typedef __ext_Elf32_Verdef verdef_ftype; typedef __ext_Elf32_Vernaux vernaux_ftype; typedef __ext_Elf32_Verneed verneed_ftype; typedef __ext_Elf32_Word align_ftype; #define class_suffix 32 #undef TOFILE #define TOFILE 0 /* * Include shared code */ #include "verdef.h" #include "verneed.h" #endif /* __LIBELF_SYMBOL_VERSIONS */ qtrvsim-0.9.8/external/libelf/verdef_64_tof.c000066400000000000000000000031641467752164200211360ustar00rootroot00000000000000/* verdef_64_tof.c - copy 64-bit versioning information. Copyright (C) 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #if __LIBELF64 && __LIBELF_SYMBOL_VERSIONS #ifndef lint static const char rcsid[] = "@(#) $Id: verdef_64_tof.c,v 1.5 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ typedef Elf64_Verdaux verdaux_mtype; typedef Elf64_Verdef verdef_mtype; typedef Elf64_Vernaux vernaux_mtype; typedef Elf64_Verneed verneed_mtype; typedef Elf64_Word align_mtype; typedef __ext_Elf64_Verdaux verdaux_ftype; typedef __ext_Elf64_Verdef verdef_ftype; typedef __ext_Elf64_Vernaux vernaux_ftype; typedef __ext_Elf64_Verneed verneed_ftype; typedef __ext_Elf64_Word align_ftype; #define class_suffix 64 #undef TOFILE #define TOFILE 1 /* * Include shared code */ #include "verdef.h" #include "verneed.h" #endif /* __LIBELF64 && __LIBELF_SYMBOL_VERSIONS */ qtrvsim-0.9.8/external/libelf/verdef_64_tom.c000066400000000000000000000031641467752164200211450ustar00rootroot00000000000000/* verdef_64_tom.c - copy 64-bit versioning information. Copyright (C) 2001 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "byteswap.h" #include "ext_types.h" #include "private.h" #if __LIBELF64 && __LIBELF_SYMBOL_VERSIONS #ifndef lint static const char rcsid[] = "@(#) $Id: verdef_64_tom.c,v 1.5 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ typedef Elf64_Verdaux verdaux_mtype; typedef Elf64_Verdef verdef_mtype; typedef Elf64_Vernaux vernaux_mtype; typedef Elf64_Verneed verneed_mtype; typedef Elf64_Word align_mtype; typedef __ext_Elf64_Verdaux verdaux_ftype; typedef __ext_Elf64_Verdef verdef_ftype; typedef __ext_Elf64_Vernaux vernaux_ftype; typedef __ext_Elf64_Verneed verneed_ftype; typedef __ext_Elf64_Word align_ftype; #define class_suffix 64 #undef TOFILE #define TOFILE 0 /* * Include shared code */ #include "verdef.h" #include "verneed.h" #endif /* __LIBELF64 && __LIBELF_SYMBOL_VERSIONS */ qtrvsim-0.9.8/external/libelf/verneed.h000066400000000000000000000175011467752164200201370ustar00rootroot00000000000000/* * verneed.h - copy versioning information. * Copyright (C) 2001 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef lint static const char verneed_h_rcsid[] = "@(#) $Id: verneed.h,v 1.13 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ #if VER_NEED_CURRENT != 1 #error libelf currently does not support VER_NEED_CURRENT != 1 #endif /* VER_NEED_CURRENT != 1 */ #if TOFILE static void __store_vernaux(vernaux_ftype *dst, const vernaux_mtype *src, unsigned enc) { if (enc == ELFDATA2LSB) { __store_u32L(dst->vna_hash, src->vna_hash); __store_u16L(dst->vna_flags, src->vna_flags); __store_u16L(dst->vna_other, src->vna_other); __store_u32L(dst->vna_name, src->vna_name); __store_u32L(dst->vna_next, src->vna_next); } else { __store_u32M(dst->vna_hash, src->vna_hash); __store_u16M(dst->vna_flags, src->vna_flags); __store_u16M(dst->vna_other, src->vna_other); __store_u32M(dst->vna_name, src->vna_name); __store_u32M(dst->vna_next, src->vna_next); } } static void __store_verneed(verneed_ftype *dst, const verneed_mtype *src, unsigned enc) { if (enc == ELFDATA2LSB) { __store_u16L(dst->vn_version, src->vn_version); __store_u16L(dst->vn_cnt, src->vn_cnt); __store_u32L(dst->vn_file, src->vn_file); __store_u32L(dst->vn_aux, src->vn_aux); __store_u32L(dst->vn_next, src->vn_next); } else { __store_u16M(dst->vn_version, src->vn_version); __store_u16M(dst->vn_cnt, src->vn_cnt); __store_u32M(dst->vn_file, src->vn_file); __store_u32M(dst->vn_aux, src->vn_aux); __store_u32M(dst->vn_next, src->vn_next); } } typedef vernaux_mtype vernaux_stype; typedef vernaux_ftype vernaux_dtype; typedef verneed_mtype verneed_stype; typedef verneed_ftype verneed_dtype; typedef align_mtype verneed_atype; #define copy_vernaux_srctotmp(d, s, e) (*(d) = *(s)) #define copy_vernaux_tmptodst(d, s, e) __store_vernaux((d), (s), (e)) #define copy_verneed_srctotmp(d, s, e) (*(d) = *(s)) #define copy_verneed_tmptodst(d, s, e) __store_verneed((d), (s), (e)) #define translator_suffix _tof #else /* TOFILE */ static void __load_vernaux(vernaux_mtype *dst, const vernaux_ftype *src, unsigned enc) { if (enc == ELFDATA2LSB) { dst->vna_hash = __load_u32L(src->vna_hash); dst->vna_flags = __load_u16L(src->vna_flags); dst->vna_other = __load_u16L(src->vna_other); dst->vna_name = __load_u32L(src->vna_name); dst->vna_next = __load_u32L(src->vna_next); } else { dst->vna_hash = __load_u32M(src->vna_hash); dst->vna_flags = __load_u16M(src->vna_flags); dst->vna_other = __load_u16M(src->vna_other); dst->vna_name = __load_u32M(src->vna_name); dst->vna_next = __load_u32M(src->vna_next); } } static void __load_verneed(verneed_mtype *dst, const verneed_ftype *src, unsigned enc) { if (enc == ELFDATA2LSB) { dst->vn_version = __load_u16L(src->vn_version); dst->vn_cnt = __load_u16L(src->vn_cnt); dst->vn_file = __load_u32L(src->vn_file); dst->vn_aux = __load_u32L(src->vn_aux); dst->vn_next = __load_u32L(src->vn_next); } else { dst->vn_version = __load_u16M(src->vn_version); dst->vn_cnt = __load_u16M(src->vn_cnt); dst->vn_file = __load_u32M(src->vn_file); dst->vn_aux = __load_u32M(src->vn_aux); dst->vn_next = __load_u32M(src->vn_next); } } typedef vernaux_ftype vernaux_stype; typedef vernaux_mtype vernaux_dtype; typedef verneed_ftype verneed_stype; typedef verneed_mtype verneed_dtype; typedef align_ftype verneed_atype; #define copy_vernaux_srctotmp(d, s, e) __load_vernaux((d), (s), (e)) #define copy_vernaux_tmptodst(d, s, e) (*(d) = *(s)) #define copy_verneed_srctotmp(d, s, e) __load_verneed((d), (s), (e)) #define copy_verneed_tmptodst(d, s, e) (*(d) = *(s)) #define translator_suffix _tom #endif /* TOFILE */ #define cat3(a, b, c) a##b##c #define xlt3(p, e, s) cat3(p, e, s) #define xltprefix(x) xlt3(x, _, class_suffix) #define translator(x, e) xlt3(xltprefix(_elf_##x), e, translator_suffix) static size_t xlt_verneed( unsigned char *dst, const unsigned char *src, size_t n, unsigned enc) { size_t off; if (sizeof(verneed_stype) != sizeof(verneed_dtype) || sizeof(vernaux_stype) != sizeof(vernaux_dtype)) { /* never happens for ELF v1 and Verneed v1 */ seterr(ERROR_UNIMPLEMENTED); return (size_t)-1; } /* size translation shortcut */ if (dst == NULL) { return n; } if (src == NULL) { seterr(ERROR_NULLBUF); return (size_t)-1; } off = 0; while (off + sizeof(verneed_stype) <= n) { const verneed_stype *svn; verneed_dtype *dvn; verneed_mtype vn; size_t acount; size_t aoff; /* * check for proper alignment */ if (off % sizeof(verneed_atype)) { seterr(ERROR_VERNEED_FORMAT); return (size_t)-1; } /* * copy and check src */ svn = (verneed_stype *)(src + off); dvn = (verneed_dtype *)(dst + off); copy_verneed_srctotmp(&vn, svn, enc); if (vn.vn_version < 1 || vn.vn_version > VER_NEED_CURRENT) { seterr(ERROR_VERNEED_VERSION); return (size_t)-1; } if (vn.vn_cnt < 1 || vn.vn_aux == 0) { seterr(ERROR_VERNEED_FORMAT); return (size_t)-1; } copy_verneed_tmptodst(dvn, &vn, enc); /* * copy aux array */ aoff = off + vn.vn_aux; for (acount = 0; acount < vn.vn_cnt; acount++) { const vernaux_stype *svna; vernaux_dtype *dvna; vernaux_mtype vna; /* * are we still inside the buffer limits? */ if (aoff + sizeof(vernaux_stype) > n) { break; } /* * check for proper alignment */ if (aoff % sizeof(verneed_atype)) { seterr(ERROR_VERNEED_FORMAT); return (size_t)-1; } /* * copy and check src */ svna = (vernaux_stype *)(src + aoff); dvna = (vernaux_dtype *)(dst + aoff); copy_vernaux_srctotmp(&vna, svna, enc); copy_vernaux_tmptodst(dvna, &vna, enc); /* * advance to next vernaux */ if (vna.vna_next == 0) { /* end of list */ break; } aoff += vna.vna_next; } /* * advance to next verneed */ if (vn.vn_next == 0) { /* end of list */ break; } off += vn.vn_next; } return n; } size_t translator( verneed, L11)(unsigned char *dst, const unsigned char *src, size_t n) { return xlt_verneed(dst, src, n, ELFDATA2LSB); } size_t translator( verneed, M11)(unsigned char *dst, const unsigned char *src, size_t n) { return xlt_verneed(dst, src, n, ELFDATA2MSB); } qtrvsim-0.9.8/external/libelf/version.c000066400000000000000000000026741467752164200201740ustar00rootroot00000000000000/* * version.c - implementation of the elf_version(3) function. * Copyright (C) 1995 - 1998, 2007 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: version.c,v 1.8 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ unsigned elf_version(unsigned ver) { const char *s; unsigned tmp; if ((s = getenv("LIBELF_SANITY_CHECKS"))) { _elf_sanity_checks = (int)strtol(s, (char **)NULL, 0); } if (ver == EV_NONE) { return EV_CURRENT; } if (!valid_version(ver)) { seterr(ERROR_UNKNOWN_VERSION); return EV_NONE; } tmp = _elf_version == EV_NONE ? EV_CURRENT : _elf_version; _elf_version = ver; return tmp; } qtrvsim-0.9.8/external/libelf/x.elfext.c000066400000000000000000000112251467752164200202340ustar00rootroot00000000000000/* * x.elfext.c -- handle ELF format extensions * Copyright (C) 2002 - 2006 Michael Riepe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: x.elfext.c,v 1.5 2009/07/07 17:57:43 michael Exp $"; #endif /* lint */ int elf_getphdrnum(Elf *elf, size_t *resultp) { if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return -1; } if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } if (resultp) { *resultp = elf->e_phnum; } return 0; } int elf_getshdrnum(Elf *elf, size_t *resultp) { size_t num = 0; Elf_Scn *scn; if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return -1; } if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } if ((scn = elf->e_scn_n)) { num = scn->s_index + 1; } if (resultp) { *resultp = num; } return 0; } int elf_getshdrstrndx(Elf *elf, size_t *resultp) { size_t num = 0; size_t dummy; Elf_Scn *scn; if (!elf) { return -1; } elf_assert(elf->e_magic == ELF_MAGIC); if (resultp == NULL) { resultp = &dummy; /* handle NULL pointer gracefully */ } if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return -1; } if (!elf->e_ehdr && !_elf_cook(elf)) { return -1; } if (elf->e_class == ELFCLASS32) { num = ((Elf32_Ehdr *)elf->e_ehdr)->e_shstrndx; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { num = ((Elf64_Ehdr *)elf->e_ehdr)->e_shstrndx; } #endif /* __LIBELF64 */ else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return -1; } if (num != SHN_XINDEX) { *resultp = num; return 0; } /* * look at first section header */ if (!(scn = elf->e_scn_1)) { seterr(ERROR_NOSUCHSCN); return -1; } elf_assert(scn->s_magic == SCN_MAGIC); #if __LIBELF64 if (elf->e_class == ELFCLASS64) { *resultp = scn->s_shdr64.sh_link; return 0; } #endif /* __LIBELF64 */ *resultp = scn->s_shdr32.sh_link; return 0; } int elf_getphnum(Elf *elf, size_t *resultp) { return elf_getphdrnum(elf, resultp) ? LIBELF_FAILURE : LIBELF_SUCCESS; } int elf_getshnum(Elf *elf, size_t *resultp) { return elf_getshdrnum(elf, resultp) ? LIBELF_FAILURE : LIBELF_SUCCESS; } int elf_getshstrndx(Elf *elf, size_t *resultp) { return elf_getshdrstrndx(elf, resultp) ? LIBELF_FAILURE : LIBELF_SUCCESS; } int elfx_update_shstrndx(Elf *elf, size_t value) { size_t extvalue = 0; Elf_Scn *scn; if (!elf) { return LIBELF_FAILURE; } elf_assert(elf->e_magic == ELF_MAGIC); if (value >= SHN_LORESERVE) { extvalue = value; value = SHN_XINDEX; } if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return LIBELF_FAILURE; } if (!elf->e_ehdr && !_elf_cook(elf)) { return LIBELF_FAILURE; } if (!(scn = _elf_first_scn(elf))) { return LIBELF_FAILURE; } elf_assert(scn->s_magic == SCN_MAGIC); if (elf->e_class == ELFCLASS32) { ((Elf32_Ehdr *)elf->e_ehdr)->e_shstrndx = value; scn->s_shdr32.sh_link = extvalue; } #if __LIBELF64 else if (elf->e_class == ELFCLASS64) { ((Elf64_Ehdr *)elf->e_ehdr)->e_shstrndx = value; scn->s_shdr64.sh_link = extvalue; } #endif /* __LIBELF64 */ else { if (valid_class(elf->e_class)) { seterr(ERROR_UNIMPLEMENTED); } else { seterr(ERROR_UNKNOWN_CLASS); } return LIBELF_FAILURE; } elf->e_ehdr_flags |= ELF_F_DIRTY; scn->s_shdr_flags |= ELF_F_DIRTY; return LIBELF_SUCCESS; } qtrvsim-0.9.8/external/libelf/x.movscn.c000066400000000000000000000055171467752164200202610ustar00rootroot00000000000000/* x.movscn.c - implementation of the elfx_movscn(3) function. Copyright (C) 1995 - 2001, 2003 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: x.movscn.c,v 1.14 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ size_t elfx_movscn(Elf *elf, Elf_Scn *scn, Elf_Scn *after) { Elf_Scn *prev; Elf_Scn *tmp; int off; if (!elf || !scn || !after) { return SHN_UNDEF; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return SHN_UNDEF; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(after->s_magic == SCN_MAGIC); if (scn->s_elf != elf || after->s_elf != elf) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } elf_assert(elf->e_scn_1); if (scn == elf->e_scn_1) { seterr(ERROR_NULLSCN); return SHN_UNDEF; } if (scn == after || scn == after->s_link) { /* nothing to do */ return scn->s_index; } /* * Find previous section. */ prev = NULL; for (tmp = elf->e_scn_1; tmp->s_link; tmp = tmp->s_link) { if (tmp->s_link == scn) { prev = tmp; break; } } elf_assert(prev != NULL); /* * Update section indices */ off = 0; for (tmp = elf->e_scn_1; tmp; tmp = tmp->s_link) { if (off) { tmp->s_index += off; } if (tmp == after) { off++; } else if (tmp == scn) { off--; } } elf_assert(off == 0); /* * Move section. */ prev->s_link = scn->s_link; scn->s_link = after->s_link; after->s_link = scn; scn->s_index = after->s_index + 1; if (elf->e_scn_n == scn) { elf->e_scn_n = prev; } else if (elf->e_scn_n == after) { elf->e_scn_n = scn; } #if ENABLE_DEBUG /* * Check section indices */ tmp = elf->e_scn_1; elf_assert(tmp->s_index == 0); while (tmp->s_link) { elf_assert(tmp->s_link->s_index == tmp->s_index + 1); tmp = tmp->s_link; } #endif /* ENABLE_DEBUG */ return scn->s_index; } qtrvsim-0.9.8/external/libelf/x.remscn.c000066400000000000000000000060571467752164200202430ustar00rootroot00000000000000/* x.remscn.c - implementation of the elfx_remscn(3) function. Copyright (C) 1995 - 2001, 2003 Michael Riepe This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "private.h" #ifndef lint static const char rcsid[] = "@(#) $Id: x.remscn.c,v 1.15 2008/05/23 08:15:35 michael Exp $"; #endif /* lint */ size_t elfx_remscn(Elf *elf, Elf_Scn *scn) { Elf_Scn *pscn; Scn_Data *sd; Scn_Data *tmp; size_t index; if (!elf || !scn) { return SHN_UNDEF; } elf_assert(elf->e_magic == ELF_MAGIC); if (elf->e_kind != ELF_K_ELF) { seterr(ERROR_NOTELF); return SHN_UNDEF; } elf_assert(scn->s_magic == SCN_MAGIC); elf_assert(elf->e_ehdr); if (scn->s_elf != elf) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } elf_assert(elf->e_scn_1); if (scn == elf->e_scn_1) { seterr(ERROR_NULLSCN); return SHN_UNDEF; } /* * Find previous section. */ for (pscn = elf->e_scn_1; pscn->s_link; pscn = pscn->s_link) { if (pscn->s_link == scn) { break; } } if (pscn->s_link != scn) { seterr(ERROR_ELFSCNMISMATCH); return SHN_UNDEF; } /* * Unlink section. */ if (elf->e_scn_n == scn) { elf->e_scn_n = pscn; } pscn->s_link = scn->s_link; index = scn->s_index; /* * Free section descriptor and data. */ for (sd = scn->s_data_1; sd; sd = tmp) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); tmp = sd->sd_link; if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if ((sd = scn->s_rawdata)) { elf_assert(sd->sd_magic == DATA_MAGIC); elf_assert(sd->sd_scn == scn); if (sd->sd_free_data && sd->sd_memdata) { free(sd->sd_memdata); } if (sd->sd_freeme) { free(sd); } } if (scn->s_freeme) { elf_assert(scn->s_index > 0); free(scn); } /* * Adjust section indices. */ for (scn = pscn->s_link; scn; scn = scn->s_link) { elf_assert(scn->s_index > index); scn->s_index--; } /* * Adjust section count in ELF header */ if (_elf_update_shnum(elf, elf->e_scn_n->s_index + 1)) { return SHN_UNDEF; } return index; } qtrvsim-0.9.8/external/svgscene/000077500000000000000000000000001467752164200167125ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/CMakeLists.txt000066400000000000000000000031771467752164200214620ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10) project(svgscene) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) # Normally, we would use variable Qt5 or Qt6 to reference the Qt library. Here we do that through # this variable based on detected version major of Qt. set(QtLib "Qt${QT_VERSION_MAJOR}") find_package(${QtLib} REQUIRED COMPONENTS Core Widgets Gui) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) add_library(svgscene STATIC src/svgscene/components/groupitem.cpp src/svgscene/components/groupitem.h src/svgscene/components/hyperlinkitem.cpp src/svgscene/components/hyperlinkitem.h src/svgscene/components/simpletextitem.cpp src/svgscene/components/simpletextitem.h src/svgscene/graphicsview/svggraphicsview.cpp src/svgscene/graphicsview/svggraphicsview.h src/svgscene/svgdocument.cpp src/svgscene/svgdocument.h src/svgscene/svggraphicsscene.cpp src/svgscene/svggraphicsscene.h src/svgscene/svghandler.cpp src/svgscene/svghandler.h src/svgscene/svgmetadata.cpp src/svgscene/svgmetadata.h src/svgscene/svgspec.h src/svgscene/polyfills/qt5/qwheelevent.h src/svgscene/polyfills/qt5/qstringview.h src/svgscene/utils/logging.h src/svgscene/utils/memory_ownership.h ) target_link_libraries(svgscene PRIVATE ${QtLib}::Core ${QtLib}::Gui ${QtLib}::Widgets) target_include_directories(svgscene PUBLIC src PRIVATE src/svgscene) add_executable(svgscene-example EXCLUDE_FROM_ALL src/example/main.cpp src/example/mainwindow.cpp src/example/mainwindow.h src/example/mainwindow.ui ) target_link_libraries(svgscene-example PRIVATE ${QtLib}::Core ${QtLib}::Gui ${QtLib}::Widgets svgscene)qtrvsim-0.9.8/external/svgscene/LICENSE000066400000000000000000001045051467752164200177240ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . qtrvsim-0.9.8/external/svgscene/README.md000066400000000000000000000010331467752164200201660ustar00rootroot00000000000000# Qt SVG DOM This tool parses an SVG file into Qt graphics objects and provides tools to lookup elements based on xml attributes in the SVG file. **WARNING** SVG support is extremely limited, but it is enough to render most static SVGs. ## Based on - [svgscene](https://github.com/fvacek/svgscene) - [libshv](https://github.com/silicon-heaven/libshv/) - [Qt SVG](https://github.com/qt/qtsvg) ## Roadmap - Parametrize xml attributes to save - Add default style attributes. - Store style in struct, not hashtable. Maybe parse to enums.qtrvsim-0.9.8/external/svgscene/src/000077500000000000000000000000001467752164200175015ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/example/000077500000000000000000000000001467752164200211345ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/example/main.cpp000066400000000000000000000004221467752164200225620ustar00rootroot00000000000000#include "mainwindow.h" #include "svgscene/utils/logging.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); w.openFile(QApplication::arguments().value(1)); return QApplication::exec(); } qtrvsim-0.9.8/external/svgscene/src/example/mainwindow.cpp000066400000000000000000000022411467752164200240130ustar00rootroot00000000000000#include "mainwindow.h" #include "svgscene/components/simpletextitem.h" #include "svgscene/graphicsview/svggraphicsview.h" #include "svgscene/svgdocument.h" #include "svgscene/svghandler.h" #include "ui_mainwindow.h" #include #include #include #include using namespace svgscene; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); m_scene = new QGraphicsScene(this); ui->graphicsView->setScene(m_scene); } MainWindow::~MainWindow() { delete ui; } void MainWindow::openFile(const QString &fn) { QString file_name = fn; if (file_name.isEmpty()) file_name = QFileDialog::getOpenFileName( this, tr("Open Image"), "", tr("SVG Image Files (*.svg)")); if (file_name.isEmpty()) return; QFile f(file_name); if (f.open(QFile::ReadOnly)) { m_scene->clear(); QXmlStreamReader rd(&f); SvgHandler h(m_scene); } } void MainWindow::on_action_Open_triggered() { openFile(); } void MainWindow::on_actionZoom_to_fit_triggered() { ui->graphicsView->zoomToFit(); } void MainWindow::inc() {} qtrvsim-0.9.8/external/svgscene/src/example/mainwindow.h000066400000000000000000000011601467752164200234570ustar00rootroot00000000000000#pragma once #include "svgscene/components/simpletextitem.h" #include #include class QGraphicsScene; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow() override; void openFile(const QString &fn = QString()); private: Q_SLOT void on_action_Open_triggered(); Q_SLOT void on_actionZoom_to_fit_triggered(); Q_SLOT void inc(); private: Ui::MainWindow *ui; QGraphicsScene *m_scene; QTimer test; svgscene::SimpleTextItem *label; int counter = 0; };qtrvsim-0.9.8/external/svgscene/src/example/mainwindow.ui000066400000000000000000000041101467752164200236430ustar00rootroot00000000000000 MainWindow 0 0 1000 693 MainWindow 0 0 1000 32 &File &View TopToolBarArea false &Open Z&oom to fit Ctrl+I true SvgGraphicsView QGraphicsView
svgscene/graphicsview/svggraphicsview.h
qtrvsim-0.9.8/external/svgscene/src/svgscene/000077500000000000000000000000001467752164200213165ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/components/000077500000000000000000000000001467752164200235035ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/components/groupitem.cpp000066400000000000000000000002331467752164200262200ustar00rootroot00000000000000#include "groupitem.h" #include namespace svgscene { GroupItem::GroupItem(QGraphicsItem *parent) : Super(parent) {} } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/components/groupitem.h000066400000000000000000000003551467752164200256720ustar00rootroot00000000000000#pragma once #include namespace svgscene { class GroupItem : public QGraphicsRectItem { using Super = QGraphicsRectItem; public: explicit GroupItem(QGraphicsItem *parent = nullptr); }; } // namespace svgsceneqtrvsim-0.9.8/external/svgscene/src/svgscene/components/hyperlinkitem.cpp000066400000000000000000000010761467752164200270770ustar00rootroot00000000000000#include "hyperlinkitem.h" #include "svgmetadata.h" #include "utils/logging.h" LOG_CATEGORY("svgscene.hyperlink"); namespace svgscene { HyperlinkItem::HyperlinkItem() = default; QString svgscene::HyperlinkItem::getTargetName() const { // href attribute is mandatory, therefore using default value return getXmlAttributeOr(this, "href", ""); } void HyperlinkItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); DEBUG("Link triggered (href: %s).", qPrintable(getTargetName())); emit triggered(); } } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/components/hyperlinkitem.h000066400000000000000000000011031467752164200265330ustar00rootroot00000000000000#pragma once #include "groupitem.h" namespace svgscene { /** * Represents SVG element . * * Works exactly as the group item but it adds emits event on doubleclick. * * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a * @see https://www.w3.org/TR/SVG11/linking.html#Links */ class HyperlinkItem : public QObject, public GroupItem { Q_OBJECT public: explicit HyperlinkItem(); QString getTargetName() const; void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; signals: void triggered(); }; } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/components/simpletextitem.cpp000066400000000000000000000023171467752164200272670ustar00rootroot00000000000000#include "simpletextitem.h" #include namespace svgscene { SimpleTextItem::SimpleTextItem(const CssAttributes &css, QGraphicsItem *parent) : Super(parent) { const QString anchor = css.value(QStringLiteral("text-anchor")); if (anchor == QLatin1String("middle")) m_alignment = Qt::AlignHCenter; else if (anchor == QLatin1String("end")) m_alignment = Qt::AlignRight; else m_alignment = Qt::AlignLeft; } void SimpleTextItem::setText(const QString &text) { if (!m_origTransformLoaded) { m_origTransformLoaded = true; m_origTransform = transform(); } Super::setText(text); if (m_alignment != Qt::AlignLeft) { qreal w = boundingRect().width(); QTransform t = m_origTransform; if (m_alignment == Qt::AlignHCenter) t.translate(-w / 2, 0); else if (m_alignment == Qt::AlignRight) t.translate(-w, 0); setTransform(t); } } void SimpleTextItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Super::paint(painter, option, widget); // painter->setPen(Qt::green); // painter->drawRect(boundingRect()); } } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/components/simpletextitem.h000066400000000000000000000011031467752164200267240ustar00rootroot00000000000000#pragma once #include "svgscene/svghandler.h" #include namespace svgscene { class SimpleTextItem : public QGraphicsSimpleTextItem { using Super = QGraphicsSimpleTextItem; public: explicit SimpleTextItem(const CssAttributes &css, QGraphicsItem *parent = nullptr); void setText(const QString &text); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; private: int m_alignment = Qt::AlignLeft; QTransform m_origTransform; bool m_origTransformLoaded = false; }; } // namespace svgsceneqtrvsim-0.9.8/external/svgscene/src/svgscene/graphicsview/000077500000000000000000000000001467752164200240115ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/graphicsview/svggraphicsview.cpp000066400000000000000000000051301467752164200277270ustar00rootroot00000000000000#include "svggraphicsview.h" #include "polyfills/qt5/qwheelevent.h" #include "utils/logging.h" #include LOG_CATEGORY("svgscene.view"); SvgGraphicsView::SvgGraphicsView(QWidget *parent) : Super(parent) {} void SvgGraphicsView::zoomToFit() { if (scene()) { QRectF sr = scene()->sceneRect(); fitInView(sr, Qt::KeepAspectRatio); } } void SvgGraphicsView::zoom(double delta, const QPointF &mouse_pos) { LOG() << "delta:" << delta << "center_pos:" << mouse_pos.x() << mouse_pos.y(); double factor = delta / 100; factor = 1 + factor; if (factor < 0) factor = 0.1; scale(factor, factor); QRect view_rect = QRect(viewport()->pos(), viewport()->size()); QPoint view_center = view_rect.center(); QSize view_d(view_center.x() - mouse_pos.x(), view_center.y() - mouse_pos.y()); view_d /= factor; view_center = QPoint(mouse_pos.x() + view_d.width(), mouse_pos.y() + view_d.height()); QPointF new_scene_center = mapToScene(view_center); centerOn(new_scene_center); } void SvgGraphicsView::paintEvent(QPaintEvent *event) { Super::paintEvent(event); } void SvgGraphicsView::wheelEvent(QWheelEvent *ev) { if (ev->angleDelta().y() != 0) { // vertical orientation if (ev->modifiers() == Qt::ControlModifier) { double delta = ev->angleDelta().y(); zoom(delta / 10, QWheelEvent_poly(ev).position()); ev->accept(); return; } } Super::wheelEvent(ev); } void SvgGraphicsView::mousePressEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton && ev->modifiers() == Qt::ControlModifier) { m_dragMouseStartPos = ev->pos(); setCursor(QCursor(Qt::ClosedHandCursor)); ev->accept(); return; } Super::mousePressEvent(ev); } void SvgGraphicsView::mouseReleaseEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton && ev->modifiers() == Qt::ControlModifier) { setCursor(QCursor()); } Super::mouseReleaseEvent(ev); } void SvgGraphicsView::mouseMoveEvent(QMouseEvent *ev) { if (ev->buttons() == Qt::LeftButton && ev->modifiers() == Qt::ControlModifier) { QPoint pos = ev->pos(); QRect view_rect = QRect(viewport()->pos(), viewport()->size()); QPoint view_center = view_rect.center(); QPoint d(pos.x() - m_dragMouseStartPos.x(), pos.y() - m_dragMouseStartPos.y()); view_center -= d; QPointF new_scene_center = mapToScene(view_center); centerOn(new_scene_center); m_dragMouseStartPos = pos; ev->accept(); return; } Super::mouseMoveEvent(ev); } qtrvsim-0.9.8/external/svgscene/src/svgscene/graphicsview/svggraphicsview.h000066400000000000000000000011521467752164200273740ustar00rootroot00000000000000#pragma once #include class SvgGraphicsView : public QGraphicsView { Q_OBJECT using Super = QGraphicsView; public: explicit SvgGraphicsView(QWidget *parent = nullptr); void zoomToFit(); protected: void zoom(double delta, const QPointF &mouse_pos); void paintEvent(QPaintEvent *event) override; void wheelEvent(QWheelEvent *ev) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *ev) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *ev) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *ev) Q_DECL_OVERRIDE; private: QPoint m_dragMouseStartPos; };qtrvsim-0.9.8/external/svgscene/src/svgscene/polyfills/000077500000000000000000000000001467752164200233335ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/polyfills/qt5/000077500000000000000000000000001467752164200240445ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/polyfills/qt5/qstringview.h000066400000000000000000000001421467752164200265740ustar00rootroot00000000000000#pragma once #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) using QStringView = QString; #endif qtrvsim-0.9.8/external/svgscene/src/svgscene/polyfills/qt5/qwheelevent.h000066400000000000000000000004441467752164200265460ustar00rootroot00000000000000#pragma once #include class QWheelEvent_poly final : public QWheelEvent { public: explicit QWheelEvent_poly(QWheelEvent *event) : QWheelEvent(*event) {} #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) QPointF position() const { return this->pos(); } #endif };qtrvsim-0.9.8/external/svgscene/src/svgscene/svgdocument.cpp000066400000000000000000000003241467752164200243570ustar00rootroot00000000000000#include "svgdocument.h" namespace svgscene { SvgDomTree SvgDocument::getRoot() const { return root; } SvgDocument::SvgDocument(QGraphicsItem *root) : root(root) {} } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svgdocument.h000066400000000000000000000120111467752164200240200ustar00rootroot00000000000000#pragma once #include "svgmetadata.h" #include namespace svgscene { template class SvgDomTree { public: explicit SvgDomTree(QGraphicsItem *root); TT *getElement() const; QString getAttrValueOr(const QString &attr_name, const QString &default_value = QString()); QString getCssValueOr(const QString &attr_name, const QString &default_value = QString()); template static SvgDomTree findFromParent( const QGraphicsItem *parent, const QString &attr_name = QString(), const QString &attr_value = QString()); template static QList> findAllFromParent( const QGraphicsItem *parent, const QString &attr_name = QString(), const QString &attr_value = QString()); template SvgDomTree find(const QString &attr_name = QString(), const QString &attr_value = QString()); template QList> findAll(const QString &attr_name = QString(), const QString &attr_value = QString()); protected: /** * WASM does not allows exception catching so we have to handle * recoverable errors in a different way - using nullptr. */ template static T *findFromParentRaw( const QGraphicsItem *parent, const QString &attr_name = QString(), const QString &attr_value = QString()); protected: TT *root; }; class SvgDocument { public: explicit SvgDocument(QGraphicsItem *root); SvgDomTree getRoot() const; protected: SvgDomTree root; }; template bool itemMatchesSelector( const QGraphicsItem *item, const QString &attr_name, const QString &attr_value) { if (item == nullptr) { throw std::out_of_range("Supplied item is nullptr."); } if (attr_name.isEmpty()) { return true; } auto attrs = getXmlAttributes(item); if (!attrs.contains(attr_name)) { return false; } return attr_value.isEmpty() || attrs.value(attr_name) == attr_value; } template SvgDomTree::SvgDomTree(QGraphicsItem *root) : root(dynamic_cast(root)) { if (this->root == nullptr) { throw std::out_of_range("Cannot build dom tree with nullptr item."); } } template TT *SvgDomTree::getElement() const { return root; } template QString SvgDomTree::getAttrValueOr(const QString &attr_name, const QString &default_value) { svgscene::XmlAttributes attrs = getXmlAttributes(root); return attrs.value(attr_name, default_value); } template QString SvgDomTree::getCssValueOr(const QString &attr_name, const QString &default_value) { return getCssAttributeOr(root, attr_name, default_value); } template template SvgDomTree SvgDomTree::findFromParent( const QGraphicsItem *parent, const QString &attr_name, const QString &attr_value) { if (!parent) { throw std::out_of_range("Current element is nullptr."); } for (QGraphicsItem *_child : parent->childItems()) { if (T *child = dynamic_cast(_child)) { if (itemMatchesSelector(child, attr_name, attr_value)) { return SvgDomTree(child); } } T *found = findFromParentRaw(_child, attr_name, attr_value); if (found != nullptr) { return SvgDomTree(found); } } throw std::out_of_range("Not found."); } template template T *SvgDomTree::findFromParentRaw( const QGraphicsItem *parent, const QString &attr_name, const QString &attr_value) { if (!parent) { return nullptr; } for (QGraphicsItem *_child : parent->childItems()) { if (T *child = dynamic_cast(_child)) { if (itemMatchesSelector(child, attr_name, attr_value)) { return child; } } T *found = findFromParentRaw(_child, attr_name, attr_value); if (found != nullptr) { return found; } } return nullptr; } template template QList> SvgDomTree::findAllFromParent( const QGraphicsItem *parent, const QString &attr_name, const QString &attr_value) { QList> ret; if (!parent) { return ret; } for (QGraphicsItem *_child : parent->childItems()) { if (T *child = dynamic_cast(_child)) { if (itemMatchesSelector(child, attr_name, attr_value)) { ret.append(SvgDomTree(child)); } } ret.append(findAllFromParent(_child, attr_name, attr_value)); } return ret; } template template SvgDomTree SvgDomTree::find(const QString &attr_name, const QString &attr_value) { return findFromParent(root, attr_name, attr_value); } template template QList> SvgDomTree::findAll(const QString &attr_name, const QString &attr_value) { return findAllFromParent(root, attr_name, attr_value); } } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svggraphicsscene.cpp000066400000000000000000000013061467752164200253600ustar00rootroot00000000000000#include "svggraphicsscene.h" #include "components/hyperlinkitem.h" #include #include namespace svgscene { void SvgGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { // Do not prevent default behavior. QGraphicsScene::mouseDoubleClickEvent(event); // Hyperlink will usually be obscured, but we need to propagate the click. QGraphicsItem *item = this->itemAt(event->pos(), {}); while (item != nullptr) { if (auto hyperlink = dynamic_cast(item)) { hyperlink->mouseDoubleClickEvent(event); break; } item = item->parentItem(); } } } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svggraphicsscene.h000066400000000000000000000010461467752164200250260ustar00rootroot00000000000000#pragma once #include namespace svgscene { /** * Graphics scene with extended support for SVG. * * Current support: * - hyperlinks (doubleclick) * Links in svg are parsed as groups and therefore they are always * obscured in qt scene. Therefore we have to travers the while tree up * and find the closest hyperlink element (if one exists). */ class SvgGraphicsScene : public QGraphicsScene { protected: virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; }; } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svghandler.cpp000066400000000000000000001376771467752164200242040ustar00rootroot00000000000000#include "svghandler.h" #include "components/groupitem.h" #include "components/hyperlinkitem.h" #include "components/simpletextitem.h" #include "polyfills/qt5/qstringview.h" #include "svgmetadata.h" #include "svgspec.h" #include "utils/logging.h" #include #include #include #include #include #include #include LOG_CATEGORY("svgscene.parsing"); namespace svgscene { SvgDocument parseFromFileName(QGraphicsScene *scene, const QString &filename) { QFile file(filename); file.open(QIODevice::ReadOnly); return parseFromFile(scene, &file); } SvgDocument parseFromFile(QGraphicsScene *scene, QFile *file) { QXmlStreamReader xml(file); SvgHandler handler(scene); handler.load(&xml); return handler.getDocument(); } // see: https://www.w3.org/TR/SVG11/ // '0' is 0x30 and '9' is 0x39 static inline bool isDigit(ushort ch) { static quint16 magic = 0x3ff; return ((ch >> 4) == 3) && (magic >> (ch & 15)); } static qreal toDouble(const QChar *&str) { const int maxLen = 255; // technically doubles can go til 308+ but whatever char temp[maxLen + 1]; int pos = 0; if (*str == QLatin1Char('-')) { temp[pos++] = '-'; ++str; } else if (*str == QLatin1Char('+')) { ++str; } while (isDigit(str->unicode()) && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } if (*str == QLatin1Char('.') && pos < maxLen) { temp[pos++] = '.'; ++str; } while (isDigit(str->unicode()) && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } bool exponent = false; if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) { exponent = true; temp[pos++] = 'e'; ++str; if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } while (isDigit(str->unicode()) && pos < maxLen) { temp[pos++] = str->toLatin1(); ++str; } } temp[pos] = '\0'; qreal val; if (!exponent && pos < 10) { int ival = 0; const char *t = temp; bool neg = false; if (*t == '-') { neg = true; ++t; } while (*t && *t != '.') { ival *= 10; ival += (*t) - '0'; ++t; } if (*t == '.') { ++t; int div = 1; while (*t) { ival *= 10; ival += (*t) - '0'; div *= 10; ++t; } val = ((qreal)ival) / ((qreal)div); } else { val = ival; } if (neg) val = -val; } else { val = QByteArray::fromRawData(temp, pos).toDouble(); } return val; } static qreal toDouble(const QString &str, bool *ok = nullptr) { const QChar *c = str.constData(); qreal res = toDouble(c); if (ok) { *ok = ((*c) == QLatin1Char('\0')); } return res; } /* static qreal toDouble(const QStringView &str, bool *ok = nullptr) { const QChar *c = str.constData(); qreal res = toDouble(c); if (ok) { *ok = (c == (str.constData() + str.length())); } return res; } */ static inline void parseNumbersArray(const QChar *&str, QVarLengthArray &points) { while (str->isSpace()) ++str; while (isDigit(str->unicode()) || *str == QLatin1Char('-') || *str == QLatin1Char('+') || *str == QLatin1Char('.')) { points.append(toDouble(str)); while (str->isSpace()) ++str; if (*str == QLatin1Char(',')) ++str; // eat the rest of space while (str->isSpace()) ++str; } } static QVector parseNumbersList(const QChar *&str) { QVector points; if (!str) return points; points.reserve(32); while (str->isSpace()) ++str; while (isDigit(str->unicode()) || *str == QLatin1Char('-') || *str == QLatin1Char('+') || *str == QLatin1Char('.')) { points.append(toDouble(str)); while (str->isSpace()) ++str; if (*str == QLatin1Char(',')) ++str; // eat the rest of space while (str->isSpace()) ++str; } return points; } static QVector parsePercentageList(const QChar *&str) { QVector points; if (!str) return points; while (str->isSpace()) ++str; while ((*str >= QLatin1Char('0') && *str <= QLatin1Char('9')) || *str == QLatin1Char('-') || *str == QLatin1Char('+') || *str == QLatin1Char('.')) { points.append(toDouble(str)); while (str->isSpace()) ++str; if (*str == QLatin1Char('%')) ++str; while (str->isSpace()) ++str; if (*str == QLatin1Char(',')) ++str; // eat the rest of space while (str->isSpace()) ++str; } return points; } static inline int qsvg_h2i(char hex) { if (hex >= '0' && hex <= '9') return hex - '0'; if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10; if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10; return -1; } static inline int qsvg_hex2int(const char *s) { return (qsvg_h2i(s[0]) << 4) | qsvg_h2i(s[1]); } static inline int qsvg_hex2int(char s) { int h = qsvg_h2i(s); return (h << 4) | h; } bool qsvg_get_hex_rgb(const char *name, QRgb *rgb) { if (name[0] != '#') return false; name++; int len = static_cast(qstrlen(name)); int r, g, b; if (len == 12) { r = qsvg_hex2int(name); g = qsvg_hex2int(name + 4); b = qsvg_hex2int(name + 8); } else if (len == 9) { r = qsvg_hex2int(name); g = qsvg_hex2int(name + 3); b = qsvg_hex2int(name + 6); } else if (len == 6) { r = qsvg_hex2int(name); g = qsvg_hex2int(name + 2); b = qsvg_hex2int(name + 4); } else if (len == 3) { r = qsvg_hex2int(name[0]); g = qsvg_hex2int(name[1]); b = qsvg_hex2int(name[2]); } else { r = g = b = -1; } if ((uint)r > 255 || (uint)g > 255 || (uint)b > 255) { *rgb = 0; return false; } *rgb = qRgb(r, g, b); return true; } bool qsvg_get_hex_rgb(const QByteArray &str, int len, QRgb *rgb) { if (len > 13) return false; char tmp[16]; for (int i = 0; i < len; ++i) tmp[i] = str[i]; tmp[len] = 0; return qsvg_get_hex_rgb(tmp, rgb); } static QColor parseColor(const QString &color, const QString &opacity) { QColor ret; { QStringView color_str = QStringView(color).trimmed(); if (color_str.isEmpty()) return ret; switch (color_str.at(0).unicode()) { case '#': { // #rrggbb is very very common, so let's tackle it here // rather than falling back to QColor QRgb rgb; bool ok = qsvg_get_hex_rgb(color_str.toUtf8(), color_str.length(), &rgb); if (ok) ret.setRgb(rgb); break; } case 'r': { // starts with "rgb(", ends with ")" and consists of at least 7 // characters "rgb(,,)" if (color_str.length() >= 7 && color_str.at(color_str.length() - 1) == QLatin1Char(')') && QStringView(color_str.cbegin(), 4) == QLatin1String("rgb(")) { const QChar *s = color_str.cbegin() + 4; QVector compo = parseNumbersList(s); // 1 means that it failed after reaching non-parsable // character which is going to be "%" if (compo.size() == 1) { s = color_str.cbegin() + 4; compo = parsePercentageList(s); for (double &i : compo) i *= (qreal)2.55; } if (compo.size() == 3) { ret = QColor(int(compo[0]), int(compo[1]), int(compo[2])); } } break; } case 'c': if (color_str == QLatin1String("currentColor")) { // color = handler->currentColor(); return ret; } break; case 'i': if (color_str == QLatin1String("inherit")) return ret; break; default: ret = QColor(QString(color_str.cbegin(), color_str.length())); break; } } if (!opacity.isEmpty() && ret.isValid()) { bool ok = true; qreal op = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity, &ok))); if (!ok) op = 1.0; ret.setAlphaF(op); } return ret; } static QTransform parseTransformationMatrix(const QStringView &value) { if (value.isEmpty()) return {}; QTransform matrix; const QChar *str = value.cbegin(); const QChar *end = str + value.length(); while (str < end) { if (str->isSpace() || *str == QLatin1Char(',')) { ++str; continue; } enum State { Matrix, Translate, Rotate, Scale, SkewX, SkewY }; State state = Matrix; if (*str == QLatin1Char('m')) { // matrix const char *ident = "atrix"; for (int i = 0; i < 5; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Matrix; } else if (*str == QLatin1Char('t')) { // translate const char *ident = "ranslate"; for (int i = 0; i < 8; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Translate; } else if (*str == QLatin1Char('r')) { // rotate const char *ident = "otate"; for (int i = 0; i < 5; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Rotate; } else if (*str == QLatin1Char('s')) { // scale, skewX, skewY ++str; if (*str == QLatin1Char('c')) { const char *ident = "ale"; for (int i = 0; i < 3; ++i) if (*(++str) != QLatin1Char(ident[i])) goto error; ++str; state = Scale; } else if (*str == QLatin1Char('k')) { if (*(++str) != QLatin1Char('e')) goto error; if (*(++str) != QLatin1Char('w')) goto error; ++str; if (*str == QLatin1Char('X')) state = SkewX; else if (*str == QLatin1Char('Y')) state = SkewY; else goto error; ++str; } else { goto error; } } else { goto error; } while (str < end && str->isSpace()) ++str; if (*str != QLatin1Char('(')) goto error; ++str; QVarLengthArray points; parseNumbersArray(str, points); if (*str != QLatin1Char(')')) goto error; ++str; if (state == Matrix) { if (points.count() != 6) goto error; matrix = QTransform(points[0], points[1], points[2], points[3], points[4], points[5]) * matrix; } else if (state == Translate) { if (points.count() == 1) matrix.translate(points[0], 0); else if (points.count() == 2) matrix.translate(points[0], points[1]); else goto error; } else if (state == Rotate) { if (points.count() == 1) { matrix.rotate(points[0]); } else if (points.count() == 3) { matrix.translate(points[1], points[2]); matrix.rotate(points[0]); matrix.translate(-points[1], -points[2]); } else { goto error; } } else if (state == Scale) { if (points.count() < 1 || points.count() > 2) goto error; qreal sx = points[0]; qreal sy = sx; if (points.count() == 2) sy = points[1]; matrix.scale(sx, sy); } else if (state == SkewX) { if (points.count() != 1) goto error; const auto deg2rad = qreal(0.017453292519943295769); matrix.shear(qTan(points[0] * deg2rad), 0); } else if (state == SkewY) { if (points.count() != 1) goto error; const auto deg2rad = qreal(0.017453292519943295769); matrix.shear(0, qTan(points[0] * deg2rad)); } } error: return matrix; } // the arc handling code underneath is from XSVG (BSD license) /* * Copyright 2002 USC/Information Sciences Institute * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * Information Sciences Institute not be used in advertising or * publicity pertaining to distribution of the software without * specific, written prior permission. Information Sciences Institute * makes no representations about the suitability of this software for * any purpose. It is provided "as is" without express or implied * warranty. * * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ static void pathArcSegment( QPainterPath &path, qreal xc, qreal yc, qreal th0, qreal th1, qreal rx, qreal ry, qreal xAxisRotation) { qreal sinTh, cosTh; qreal a00, a01, a10, a11; qreal x1, y1, x2, y2, x3, y3; qreal t; qreal thHalf; sinTh = qSin(xAxisRotation * (M_PI / 180.0)); cosTh = qCos(xAxisRotation * (M_PI / 180.0)); a00 = cosTh * rx; a01 = -sinTh * ry; a10 = sinTh * rx; a11 = cosTh * ry; thHalf = 0.5 * (th1 - th0); t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf); x1 = xc + qCos(th0) - t * qSin(th0); y1 = yc + qSin(th0) + t * qCos(th0); x3 = xc + qCos(th1); y3 = yc + qSin(th1); x2 = x3 + t * qSin(th1); y2 = y3 - t * qCos(th1); path.cubicTo( a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3); } static void pathArc( QPainterPath &path, qreal rx, qreal ry, qreal x_axis_rotation, int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx, qreal cury) { qreal sin_th, cos_th; qreal a00, a01, a10, a11; qreal x0, y0, x1, y1, xc, yc; qreal d, sfactor, sfactor_sq; qreal th0, th1, th_arc; int i, n_segs; qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check; rx = qAbs(rx); ry = qAbs(ry); sin_th = qSin(x_axis_rotation * (M_PI / 180.0)); cos_th = qCos(x_axis_rotation * (M_PI / 180.0)); dx = (curx - x) / 2.0; dy = (cury - y) / 2.0; dx1 = cos_th * dx + sin_th * dy; dy1 = -sin_th * dx + cos_th * dy; Pr1 = rx * rx; Pr2 = ry * ry; Px = dx1 * dx1; Py = dy1 * dy1; /* Spec : check if radii are large enough */ check = Px / Pr1 + Py / Pr2; if (check > 1) { rx = rx * qSqrt(check); ry = ry * qSqrt(check); } a00 = cos_th / rx; a01 = sin_th / rx; a10 = -sin_th / ry; a11 = cos_th / ry; x0 = a00 * curx + a01 * cury; y0 = a10 * curx + a11 * cury; x1 = a00 * x + a01 * y; y1 = a10 * x + a11 * y; /* (x0, y0) is current point in transformed coordinate space. (x1, y1) is new point in transformed coordinate space. The arc fits a unit-radius circle in this space. */ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); sfactor_sq = 1.0 / d - 0.25; if (sfactor_sq < 0) sfactor_sq = 0; sfactor = qSqrt(sfactor_sq); if (sweep_flag == large_arc_flag) sfactor = -sfactor; xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); /* (xc, yc) is center of the circle. */ th0 = qAtan2(y0 - yc, x0 - xc); th1 = qAtan2(y1 - yc, x1 - xc); th_arc = th1 - th0; if (th_arc < 0 && sweep_flag) th_arc += 2 * M_PI; else if (th_arc > 0 && !sweep_flag) th_arc -= 2 * M_PI; n_segs = qCeil(qAbs(th_arc / (M_PI * 0.5 + 0.001))); for (i = 0; i < n_segs; i++) { pathArcSegment( path, xc, yc, th0 + i * th_arc / n_segs, th0 + (i + 1) * th_arc / n_segs, rx, ry, x_axis_rotation); } } static bool parsePathDataFast(const QStringView &dataStr, QPainterPath &path) { qreal x0 = 0, y0 = 0; // starting point qreal x = 0, y = 0; // current point char lastMode = 0; QPointF ctrlPt; const QChar *str = dataStr.cbegin(); const QChar *end = str + dataStr.size(); while (str != end) { while (str->isSpace()) ++str; QChar pathElem = *str; ++str; QChar endc = *end; *const_cast(end) = QChar('\0'); // parseNumbersArray requires // 0-termination that QStringView cannot // guarantee QVarLengthArray arg; parseNumbersArray(str, arg); *const_cast(end) = endc; if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z')) arg.append(0); // dummy const qreal *num = arg.constData(); int count = arg.count(); while (count > 0) { qreal offsetX = x; // correction offsets qreal offsetY = y; // for relative commands switch (pathElem.unicode()) { case 'm': { if (count < 2) { num++; count--; break; } x = x0 = num[0] + offsetX; y = y0 = num[1] + offsetY; num += 2; count -= 2; path.moveTo(x0, y0); // As per 1.2 spec 8.3.2 The "moveto" commands // If a 'moveto' is followed by multiple pairs of coordinates // without explicit commands, the subsequent pairs shall be // treated as implicit 'lineto' commands. pathElem = QLatin1Char('l'); } break; case 'M': { if (count < 2) { num++; count--; break; } x = x0 = num[0]; y = y0 = num[1]; num += 2; count -= 2; path.moveTo(x0, y0); // As per 1.2 spec 8.3.2 The "moveto" commands // If a 'moveto' is followed by multiple pairs of coordinates // without explicit commands, the subsequent pairs shall be // treated as implicit 'lineto' commands. pathElem = QLatin1Char('L'); } break; case 'z': case 'Z': { x = x0; y = y0; count--; // skip dummy num++; path.closeSubpath(); } break; case 'l': { if (count < 2) { num++; count--; break; } x = num[0] + offsetX; y = num[1] + offsetY; num += 2; count -= 2; path.lineTo(x, y); } break; case 'L': { if (count < 2) { num++; count--; break; } x = num[0]; y = num[1]; num += 2; count -= 2; path.lineTo(x, y); } break; case 'h': { x = num[0] + offsetX; num++; count--; path.lineTo(x, y); } break; case 'H': { x = num[0]; num++; count--; path.lineTo(x, y); } break; case 'v': { y = num[0] + offsetY; num++; count--; path.lineTo(x, y); } break; case 'V': { y = num[0]; num++; count--; path.lineTo(x, y); } break; case 'c': { if (count < 6) { num += count; count = 0; break; } QPointF c1(num[0] + offsetX, num[1] + offsetY); QPointF c2(num[2] + offsetX, num[3] + offsetY); QPointF e(num[4] + offsetX, num[5] + offsetY); num += 6; count -= 6; path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 'C': { if (count < 6) { num += count; count = 0; break; } QPointF c1(num[0], num[1]); QPointF c2(num[2], num[3]); QPointF e(num[4], num[5]); num += 6; count -= 6; path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 's': { if (count < 4) { num += count; count = 0; break; } QPointF c1; if (lastMode == 'c' || lastMode == 'C' || lastMode == 's' || lastMode == 'S') c1 = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); else c1 = QPointF(x, y); QPointF c2(num[0] + offsetX, num[1] + offsetY); QPointF e(num[2] + offsetX, num[3] + offsetY); num += 4; count -= 4; path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 'S': { if (count < 4) { num += count; count = 0; break; } QPointF c1; if (lastMode == 'c' || lastMode == 'C' || lastMode == 's' || lastMode == 'S') c1 = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); else c1 = QPointF(x, y); QPointF c2(num[0], num[1]); QPointF e(num[2], num[3]); num += 4; count -= 4; path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 'q': { if (count < 4) { num += count; count = 0; break; } QPointF c(num[0] + offsetX, num[1] + offsetY); QPointF e(num[2] + offsetX, num[3] + offsetY); num += 4; count -= 4; path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 'Q': { if (count < 4) { num += count; count = 0; break; } QPointF c(num[0], num[1]); QPointF e(num[2], num[3]); num += 4; count -= 4; path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 't': { if (count < 2) { num += count; count = 0; break; } QPointF e(num[0] + offsetX, num[1] + offsetY); num += 2; count -= 2; QPointF c; if (lastMode == 'q' || lastMode == 'Q' || lastMode == 't' || lastMode == 'T') c = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); else c = QPointF(x, y); path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 'T': { if (count < 2) { num += count; count = 0; break; } QPointF e(num[0], num[1]); num += 2; count -= 2; QPointF c; if (lastMode == 'q' || lastMode == 'Q' || lastMode == 't' || lastMode == 'T') c = QPointF(2 * x - ctrlPt.x(), 2 * y - ctrlPt.y()); else c = QPointF(x, y); path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 'a': { if (count < 7) { num += count; count = 0; break; } qreal rx = (*num++); qreal ry = (*num++); qreal xAxisRotation = (*num++); qreal largeArcFlag = (*num++); qreal sweepFlag = (*num++); qreal ex = (*num++) + offsetX; qreal ey = (*num++) + offsetY; count -= 7; qreal curx = x; qreal cury = y; pathArc( path, rx, ry, xAxisRotation, int(largeArcFlag), int(sweepFlag), ex, ey, curx, cury); x = ex; y = ey; } break; case 'A': { if (count < 7) { num += count; count = 0; break; } qreal rx = (*num++); qreal ry = (*num++); qreal xAxisRotation = (*num++); qreal largeArcFlag = (*num++); qreal sweepFlag = (*num++); qreal ex = (*num++); qreal ey = (*num++); count -= 7; qreal curx = x; qreal cury = y; pathArc( path, rx, ry, xAxisRotation, int(largeArcFlag), int(sweepFlag), ex, ey, curx, cury); x = ex; y = ey; } break; default: return false; } lastMode = pathElem.toLatin1(); } } return true; } SvgHandler::SvgHandler(QGraphicsScene *scene) : m_scene(scene) {} SvgHandler::~SvgHandler() = default; void SvgHandler::load(QXmlStreamReader *data, bool skip_definitions) { m_skipDefinitions = skip_definitions; m_xml = data; m_defaultPen = QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin); m_defaultPen.setMiterLimit(4); parse(); /* QGraphicsRectItem *it = new QGraphicsRectItem(); it->setRect(m_scene->sceneRect()); it->setPen(QPen(Qt::blue)); m_scene->addItem(it); */ } void SvgHandler::parse() { m_xml->setNamespaceProcessing(false); bool done = false; m_elementStack.push(SvgElement::initial_element()); while (!m_xml->atEnd() && !done) { switch (m_xml->readNext()) { case QXmlStreamReader::StartElement: { SvgElement el(m_xml->name().toString()); if (el.name == QLatin1String("defs")) { if (m_skipDefinitions) { m_xml->skipCurrentElement(); } } el.styleAttributes = m_elementStack.last().styleAttributes; el.xmlAttributes = parseXmlAttributes(m_xml->attributes(), el.styleAttributes); DEBUG() << QString(m_elementStack.count(), '-') << ">" << "+ start element:" << el.name << "id:" << el.xmlAttributes.value("id"); mergeCSSAttributes(el.styleAttributes, QStringLiteral("style"), el.xmlAttributes); m_elementStack.push(el); bool is_item_created = startElement(); m_elementStack.last().itemCreated = is_item_created; break; } case QXmlStreamReader::EndElement: { SvgElement svg_element = m_elementStack.pop(); DEBUG() << QString(m_elementStack.count(), '-') << ">" << "- end element:" << m_xml->name() << "item created:" << svg_element.itemCreated; if (svg_element.itemCreated && m_topLevelItem) { // logSvgI() << "m_topLevelItem:" << m_topLevelItem << typeid // (*m_topLevelItem).name() << svg_element.name; installVisuController(m_topLevelItem, svg_element); m_topLevelItem = m_topLevelItem->parentItem(); } break; } case QXmlStreamReader::Characters: { DEBUG() << "characters element:" << m_xml->text(); // << typeid // (*m_topLevelItem).name(); if (auto *text_item = dynamic_cast(m_topLevelItem)) { QString text = text_item->text(); if (!text.isEmpty()) text += '\n'; DEBUG() << text_item->text() << "+" << m_xml->text().toString(); text_item->setText(text + m_xml->text().toString()); } else if (auto *text_item = dynamic_cast(m_topLevelItem)) { QString text = text_item->toPlainText(); if (!text.isEmpty()) text += '\n'; text += m_xml->text(); text_item->setPlainText(text); // nInfo() << text_item->toPlainText(); } else { DEBUG() << "characters are not part of text item, will be ignored"; // nWarning() << "top:" << m_topLevelItem << (m_topLevelItem? // typeid (*m_topLevelItem).name(): "NULL"); } break; } case QXmlStreamReader::ProcessingInstruction: DEBUG() << "ProcessingInstruction:" << m_xml->processingInstructionTarget() << m_xml->processingInstructionData(); // processingInstruction(xml->processingInstructionTarget().toString(), // xml->processingInstructionData().toString()); break; default: break; } } } bool SvgHandler::startElement() { const SvgElement &el = m_elementStack.last(); if (!m_topLevelItem) { if (el.name == QLatin1String("svg")) { m_topLevelItem = new QGraphicsRectItem(); m_scene->addItem(m_topLevelItem); root = m_topLevelItem; return true; } else { WARN() << "unsupported root element:" << el.name; } return false; } else { if (el.name == QLatin1String("g")) { QGraphicsItem *item = createGroupItem(el); if (item) { setXmlAttributes(item, el); if (auto *rect_item = dynamic_cast(item)) { setStyle(rect_item, el.xmlAttributes); } setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } return false; } else if (el.name == QLatin1String("a")) { QGraphicsItem *item = createHyperlinkItem(el); if (item) { setXmlAttributes(item, el); if (auto *rect_item = dynamic_cast(item)) { setStyle(rect_item, el.xmlAttributes); } setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } return false; } else if (el.name == QLatin1String("rect")) { qreal x = el.xmlAttributes.value(QStringLiteral("x")).toDouble(); qreal y = el.xmlAttributes.value(QStringLiteral("y")).toDouble(); qreal w = el.xmlAttributes.value(QStringLiteral("width")).toDouble(); qreal h = el.xmlAttributes.value(QStringLiteral("height")).toDouble(); if (auto *text_item = dynamic_cast(m_topLevelItem)) { QTransform t; t.translate(x, y); text_item->setTransform(t, true); text_item->setTextWidth(w); return false; } else { auto *item = new QGraphicsRectItem(); setXmlAttributes(item, el); item->setRect(QRectF(x, y, w, h)); setStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } } else if (el.name == QLatin1String("circle")) { auto *item = new QGraphicsEllipseItem(); setXmlAttributes(item, el); qreal cx = toDouble(el.xmlAttributes.value(QStringLiteral("cx"))); qreal cy = toDouble(el.xmlAttributes.value(QStringLiteral("cy"))); qreal rx = toDouble(el.xmlAttributes.value(QStringLiteral("r"))); QRectF r(0, 0, 2 * rx, 2 * rx); r.translate(cx - rx, cy - rx); item->setRect(r); setStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } else if (el.name == QLatin1String("ellipse")) { auto *item = new QGraphicsEllipseItem(); setXmlAttributes(item, el); qreal cx = toDouble(el.xmlAttributes.value(QStringLiteral("cx"))); qreal cy = toDouble(el.xmlAttributes.value(QStringLiteral("cy"))); qreal rx = toDouble(el.xmlAttributes.value(QStringLiteral("rx"))); qreal ry = toDouble(el.xmlAttributes.value(QStringLiteral("ry"))); QRectF r(0, 0, 2 * rx, 2 * ry); r.translate(cx - rx, cy - ry); item->setRect(r); setStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } else if (el.name == QLatin1String("path")) { auto *item = new QGraphicsPathItem(); setXmlAttributes(item, el); QString data = el.xmlAttributes.value(QStringLiteral("d")); QPainterPath p; parsePathDataFast(QStringView(data), p); setStyle(item, el.styleAttributes); static auto FILL_RULE = QStringLiteral("fill-rule"); if (el.styleAttributes.value(FILL_RULE) == QLatin1String("evenodd")) p.setFillRule(Qt::OddEvenFill); else p.setFillRule(Qt::WindingFill); item->setPath(p); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } else if (el.name == QLatin1String("text")) { auto *item = new SimpleTextItem(el.styleAttributes); setXmlAttributes(item, el); qreal x = toDouble(el.xmlAttributes.value(QStringLiteral("x"))); qreal y = toDouble(el.xmlAttributes.value(QStringLiteral("y"))); // item->setPos(x, y); setStyle(item, el.styleAttributes); setTextStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); QFontMetricsF fm(item->font()); QTransform t; t.translate(x, y - fm.ascent()); item->setTransform(t, true); addItem(item); return true; } else if (el.name == QLatin1String("tspan")) { auto *item = new SimpleTextItem(el.styleAttributes); setXmlAttributes(item, el); qreal x = toDouble(el.xmlAttributes.value(QStringLiteral("x"))); qreal y = toDouble(el.xmlAttributes.value(QStringLiteral("y"))); // text->setPos(x, y); setStyle(item, el.styleAttributes); setTextStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); QFontMetricsF fm(item->font()); QTransform t; t.translate(x, y - fm.ascent()); item->setTransform(t, true); addItem(item); return true; } else if (el.name == QLatin1String("flowRoot")) { auto *item = new QGraphicsTextItem(); setXmlAttributes(item, el); // nWarning() << "FlowRoot:" << (QGraphicsItem*)item; setTextStyle(item, el.styleAttributes); setTransform(item, el.xmlAttributes.value(QStringLiteral("transform"))); addItem(item); return true; } else { LOG() << "unsupported element:" << el.name; } return false; } } QGraphicsItem *SvgHandler::createGroupItem(const SvgHandler::SvgElement &el) { Q_UNUSED(el) QGraphicsItem *item = new GroupItem(); return item; } QGraphicsItem *SvgHandler::createHyperlinkItem(const SvgHandler::SvgElement &el) { Q_UNUSED(el) QGraphicsItem *item = new HyperlinkItem(); return item; } void SvgHandler::installVisuController(QGraphicsItem *it, const SvgHandler::SvgElement &el) { Q_UNUSED(it) Q_UNUSED(el) } void SvgHandler::setXmlAttributes(QGraphicsItem *git, const SvgHandler::SvgElement &el) { git->setData( static_cast(MetadataType::XmlAttributes), QVariant::fromValue(el.xmlAttributes)); git->setData( static_cast(MetadataType::CssAttributes), QVariant::fromValue(el.styleAttributes)); } void SvgHandler::setTransform(QGraphicsItem *it, const QString &str_val) { QStringView transform(str_val); QTransform mx = parseTransformationMatrix(transform.trimmed()); if (!mx.isIdentity()) { QTransform t(mx); // logSvgI() << typeid (*it).name() << "setting matrix:" << t.dx() << // t.dy(); it->setTransform(t); } } CssAttributes SvgHandler::parseXmlAttributes(const QXmlStreamAttributes &attributes, CssAttributes &css) { XmlAttributes xml; for (const QXmlStreamAttribute &attr : attributes) { const auto name = attr.name().toString(); const auto value = attr.value().toString(); xml[name] = value; /* * """ * The presentation attributes thus will participate in the CSS2 cascade * as if they were replaced by corresponding CSS style rules placed at * the start of the author style sheet with a specificity of zero. In * general, this means that the presentation attributes have lower * priority than other CSS style rules specified in author style sheets * or ‘style’ attributes. * """ * https://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes */ if (svgspec::presentation_attributes.contains(name)) { css[name] = value; } } return xml; } void SvgHandler::mergeCSSAttributes( CssAttributes &css_attributes, const QString &attr_name, const XmlAttributes &xml_attributes) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) QStringList css = xml_attributes.value(attr_name).split(';', QString::SkipEmptyParts); #else QStringList css = xml_attributes.value(attr_name).split(';', Qt::SkipEmptyParts); #endif for (const QString &ss : css) { int ix = ss.indexOf(':'); if (ix > 0) { css_attributes[ss.mid(0, ix).trimmed()] = ss.mid(ix + 1).trimmed(); } } } void SvgHandler::setStyle(QAbstractGraphicsShapeItem *it, const CssAttributes &attributes) { QString fill = attributes.value(QStringLiteral("fill")); if (fill.isEmpty()) { // default fill } else if (fill == QLatin1String("none")) { it->setBrush(Qt::NoBrush); } else { QString opacity = attributes.value(QStringLiteral("fill-opacity")); it->setBrush(parseColor(fill, opacity)); } QString stroke = attributes.value(QStringLiteral("stroke")); if (stroke.isEmpty() || stroke == QLatin1String("none")) { it->setPen(Qt::NoPen); } else { QString opacity = attributes.value(QStringLiteral("stroke-opacity")); QPen pen(parseColor(stroke, opacity)); pen.setWidthF(toDouble(attributes.value(QStringLiteral("stroke-width")))); QString linecap = attributes.value(QStringLiteral("stroke-linecap")); if (linecap == QLatin1String("round")) pen.setCapStyle(Qt::RoundCap); else if (linecap == QLatin1String("square")) pen.setCapStyle(Qt::SquareCap); else // if(linecap == QLatin1String("butt")) pen.setCapStyle(Qt::FlatCap); QString join = attributes.value(QStringLiteral("stroke-linejoin")); if (join == QLatin1String("round")) pen.setJoinStyle(Qt::RoundJoin); else if (join == QLatin1String("bevel")) pen.setJoinStyle(Qt::BevelJoin); else // if( join == QLatin1String("miter")) pen.setJoinStyle(Qt::MiterJoin); QString dash_pattern = attributes.value(QStringLiteral("stroke-dasharray")); if (!(dash_pattern.isEmpty() || dash_pattern == QLatin1String("none"))) { QStringList array = dash_pattern.split(','); QVector arr; for (const auto &s : array) { bool ok; double d = s.toDouble(&ok); if (!ok) { LOG() << "Invalid stroke dash definition:" << dash_pattern; arr.clear(); break; } arr << d; } if (!arr.isEmpty()) { pen.setDashPattern(arr); } } QString dash_offset = attributes.value(QStringLiteral("stroke-dashoffset")); if (!(dash_offset.isEmpty() || dash_offset == QLatin1String("none"))) { bool ok; double d = dash_offset.toDouble(&ok); if (ok) { pen.setDashOffset(d); } else { LOG() << "Invalid stroke dash offset:" << dash_offset; } } it->setPen(pen); } } void SvgHandler::setTextStyle(QFont &font, const CssAttributes &attributes) { DEBUG() << "orig font" << font.toString(); // font.setStyleName(QString()); font.setStyleName(QStringLiteral("Normal")); QString font_size = attributes.value(QStringLiteral("font-size")); if (!font_size.isEmpty()) { DEBUG() << "font_size:" << font_size; if (font_size.endsWith(QLatin1String("px"))) font.setPixelSize((int)toDouble(font_size.mid(0, font_size.size() - 2))); else if (font_size.endsWith(QLatin1String("pt"))) font.setPointSizeF(toDouble(font_size.mid(0, font_size.size() - 2))); } QString font_family = attributes.value(QStringLiteral("font-family")); if (!font_family.isEmpty()) { DEBUG() << "font_family:" << font_family; font.setFamily(font_family); } font.setWeight(QFont::Normal); QString font_weight = attributes.value(QStringLiteral("font-weight")); if (!font_weight.isEmpty()) { DEBUG() << "font_weight:" << font_weight; if (font_weight == QLatin1String("thin")) font.setWeight(QFont::Thin); else if (font_weight == QLatin1String("light")) font.setWeight(QFont::Light); else if (font_weight == QLatin1String("normal")) font.setWeight(QFont::Normal); else if (font_weight == QLatin1String("medium")) font.setWeight(QFont::Medium); else if (font_weight == QLatin1String("bold")) font.setWeight(QFont::Bold); else if (font_weight == QLatin1String("black")) font.setWeight(QFont::Black); } font.setStretch(QFont::Unstretched); QString font_stretch = attributes.value(QStringLiteral("font-stretch")); if (!font_stretch.isEmpty()) { DEBUG() << "font_stretch:" << font_stretch; if (font_stretch == QLatin1String("ultra-condensed")) font.setStretch(QFont::UltraCondensed); else if (font_stretch == QLatin1String("extra-condensed")) font.setStretch(QFont::ExtraCondensed); else if (font_stretch == QLatin1String("condensed")) font.setStretch(QFont::Condensed); else if (font_stretch == QLatin1String("semi-condensed")) font.setStretch(QFont::SemiCondensed); else if (font_stretch == QLatin1String("semi-expanded")) font.setStretch(QFont::SemiExpanded); else if (font_stretch == QLatin1String("expanded")) font.setStretch(QFont::Expanded); else if (font_stretch == QLatin1String("extra-expanded")) font.setStretch(QFont::ExtraExpanded); else if (font_stretch == QLatin1String("ultra-expanded")) font.setStretch(QFont::UltraExpanded); else // if(font_stretch == QLatin1String("normal")) font.setStretch(QFont::Unstretched); } font.setStyle(QFont::StyleNormal); QString font_style = attributes.value(QStringLiteral("font-style")); if (!font_style.isEmpty()) { if (font_style == QLatin1String("normal")) font.setStyle(QFont::StyleNormal); else if (font_style == QLatin1String("italic")) font.setStyle(QFont::StyleItalic); else if (font_style == QLatin1String("oblique")) font.setStyle(QFont::StyleOblique); } DEBUG() << "font" << "px size:" << font.pixelSize() << "pt size:" << font.pointSize() << "stretch:" << font.stretch() << "weight:" << font.weight(); DEBUG() << "new font" << font.toString(); } void SvgHandler::setTextStyle(QGraphicsSimpleTextItem *text, const CssAttributes &attributes) { QFont f = text->font(); setTextStyle(f, attributes); text->setFont(f); } void SvgHandler::setTextStyle(QGraphicsTextItem *text, const CssAttributes &attributes) { QFont f = text->font(); setTextStyle(f, attributes); text->setFont(f); static auto FILL = QStringLiteral("fill"); QString fill = attributes.value(FILL); if (fill.isEmpty() || fill == QLatin1String("none")) { // it->setBrush(Qt::NoBrush); } else { static auto FILL_OPACITY = QStringLiteral("fill-opacity"); QString opacity = attributes.value(FILL_OPACITY); text->setDefaultTextColor(parseColor(fill, opacity)); } } QString SvgHandler::point2str(QPointF r) { auto ret = QStringLiteral("Point(%1, %2)"); return ret.arg(r.x()).arg(r.y()); } QString SvgHandler::rect2str(QRectF r) { auto ret = QStringLiteral("Rect(%1, %2 %3 x %4)"); return ret.arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); } void SvgHandler::addItem(QGraphicsItem *it) { if (!m_topLevelItem) return; DEBUG() << "adding item:" << typeid(*it).name() << "pos:" << point2str(it->pos()) << "bounding rect:" << rect2str(it->boundingRect()); if (auto *grp = dynamic_cast(m_topLevelItem)) { grp->addToGroup(it); } else { it->setParentItem(m_topLevelItem); } m_topLevelItem = it; } SvgDocument SvgHandler::getDocument() const { return SvgDocument(root); } SvgHandler::SvgElement SvgHandler::SvgElement::initial_element() { auto el = SvgHandler::SvgElement(); el.styleAttributes = { // TODO Choose some reasonable set. { "stroke-width", "1" }, }; return el; } } // namespace svgsceneqtrvsim-0.9.8/external/svgscene/src/svgscene/svghandler.h000066400000000000000000000050361467752164200236300ustar00rootroot00000000000000#pragma once #include "svgdocument.h" #include "svgmetadata.h" #include #include #include #include #include class QXmlStreamReader; class QXmlStreamAttributes; class QGraphicsScene; class QGraphicsItem; class QGraphicsSimpleTextItem; class QGraphicsTextItem; class QAbstractGraphicsShapeItem; namespace svgscene { SvgDocument parseFromFileName(QGraphicsScene *scene, const QString &filename); SvgDocument parseFromFile(QGraphicsScene *scene, QFile *file); class SvgHandler { public: struct SvgElement { QString name; XmlAttributes xmlAttributes; CssAttributes styleAttributes; bool itemCreated = false; SvgElement() = default; explicit SvgElement(QString n, bool created = false) : name(std::move(n)) , itemCreated(created) {} static SvgElement initial_element(); }; public: explicit SvgHandler(QGraphicsScene *scene); virtual ~SvgHandler(); void load(QXmlStreamReader *data, bool is_skip_definitions = false); static QString point2str(QPointF r); static QString rect2str(QRectF r); SvgDocument getDocument() const; protected: virtual QGraphicsItem *createGroupItem(const SvgElement &el); QGraphicsItem *createHyperlinkItem(const SvgElement &el); virtual void installVisuController(QGraphicsItem *it, const SvgElement &el); virtual void setXmlAttributes(QGraphicsItem *git, const SvgElement &el); QGraphicsScene *m_scene; private: void parse(); static CssAttributes parseXmlAttributes(const QXmlStreamAttributes &attributes, CssAttributes &css); static void mergeCSSAttributes( CssAttributes &css_attributes, const QString &attr_name, const XmlAttributes &xml_attributes); static void setTransform(QGraphicsItem *it, const QString &str_val); static void setStyle(QAbstractGraphicsShapeItem *it, const CssAttributes &attributes); static void setTextStyle(QFont &font, const CssAttributes &attributes); static void setTextStyle(QGraphicsSimpleTextItem *text, const CssAttributes &attributes); static void setTextStyle(QGraphicsTextItem *text, const CssAttributes &attributes); bool startElement(); void addItem(QGraphicsItem *it); private: QGraphicsItem *root = nullptr; QStack m_elementStack; QGraphicsItem *m_topLevelItem = nullptr; QXmlStreamReader *m_xml = nullptr; QPen m_defaultPen; bool m_skipDefinitions = false; }; } // namespace svgscene Q_DECLARE_METATYPE(svgscene::XmlAttributes) qtrvsim-0.9.8/external/svgscene/src/svgscene/svgmetadata.cpp000066400000000000000000000036661467752164200243350ustar00rootroot00000000000000#include "svgmetadata.h" namespace svgscene { XmlAttributes getXmlAttributes(const QGraphicsItem *element) { QVariant raw = element->data(static_cast(MetadataType::XmlAttributes)); if (!raw.isValid() || !raw.canConvert()) { throw std::out_of_range("XmlAttributes not present in the object.\n" "Check whether the object was created by the svgscene parser."); } return qvariant_cast(raw); } QString getXmlAttribute(const QGraphicsItem *element, const QString &name) { XmlAttributes attrs = getXmlAttributes(element); if (!attrs.contains(name)) { throw std::out_of_range("Element does not contain requested XML attribute."); } return attrs.value(name); } QString getXmlAttributeOr( const QGraphicsItem *element, const QString &name, const QString &defaultValue) noexcept { XmlAttributes attrs = getXmlAttributes(element); return attrs.value(name, defaultValue); } CssAttributes getCssAttributes(const QGraphicsItem *element) { QVariant raw = element->data(static_cast(MetadataType::CssAttributes)); if (!raw.isValid() || !raw.canConvert()) { throw std::out_of_range("CssAttributes not present in the object.\n" "Check whether the object was created by the svgscene parser."); } return qvariant_cast(raw); } QString getCssAttribute(const QGraphicsItem *element, const QString &name) { CssAttributes attrs = getCssAttributes(element); if (!attrs.contains(name)) { throw std::out_of_range("Element does not contain requested XML attribute."); } return attrs.value(name); } QString getCssAttributeOr( const QGraphicsItem *element, const QString &name, const QString &defaultValue) noexcept { CssAttributes attrs = getCssAttributes(element); return attrs.value(name, defaultValue); } } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svgmetadata.h000066400000000000000000000017731467752164200237770ustar00rootroot00000000000000#pragma once #include #include #include namespace svgscene { /* * Fields that can be found on SVG related `QGraphicsItem`s using the `data` * method. * Data are stored using QVariant. */ enum class MetadataType { XmlAttributes = 1, CssAttributes, }; constexpr MetadataType LAST_VALUE = MetadataType::CssAttributes; using XmlAttributes = QMap; XmlAttributes getXmlAttributes(const QGraphicsItem *element); QString getXmlAttribute(const QGraphicsItem *element, const QString &name); QString getXmlAttributeOr( const QGraphicsItem *element, const QString &name, const QString &defaultValue) noexcept; using CssAttributes = QMap; CssAttributes getCssAttributes(const QGraphicsItem *element); QString getCssAttribute(const QGraphicsItem *element, const QString &name); QString getCssAttributeOr( const QGraphicsItem *element, const QString &name, const QString &defaultValue) noexcept; } // namespace svgscene qtrvsim-0.9.8/external/svgscene/src/svgscene/svgspec.h000066400000000000000000000030021467752164200231340ustar00rootroot00000000000000 #ifndef SVGSCENE_SVG_SPEC_H #define SVGSCENE_SVG_SPEC_H #include namespace svgspec { /** * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute */ static const QSet presentation_attributes { "alignment-baseline", "baseline-shift", "clip", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cursor", "direction", "display", "dominant-baseline", "enable-background", "fill", "fill-opacity", "fill-rule", "filter", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "glyph-orientation-horizontal", "glyph-orientation-vertical", "image-rendering", "kerning", "letter-spacing", "lighting-color", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "overflow", "pointer-events", "shape-rendering", "stop-color", "stop-opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-anchor", "text-decoration", "text-rendering", "transform", "transform-origin", "unicode-bidi", "vector-effect", "visibility", "word-spacing", "writing-mode", }; } // namespace svgspec #endif // SVGSCENE_SVG_SPEC_H qtrvsim-0.9.8/external/svgscene/src/svgscene/utils/000077500000000000000000000000001467752164200224565ustar00rootroot00000000000000qtrvsim-0.9.8/external/svgscene/src/svgscene/utils/logging.h000066400000000000000000000023071467752164200242570ustar00rootroot00000000000000#pragma once /** * Wrapper for QT logging library. * * Each source file is expected to declare a log category name what is * implicitly used for all logging macros. When logging in header files take * precaution not to pollute global scope. Either log manually or declare the * log within class scope. * Log categories can be structured using dots in name: `machine.core * .decode`. * * @see * https://www.kdab.com/wp-content/uploads/stories/slides/Day2/KaiKoehne_Qt%20Logging%20Framework%2016_9_0.pdf */ #include #define LOG_CATEGORY(NAME) static QLoggingCategory _loging_category_(NAME) #if !defined(QT_NO_QDEBUG_MACRO) #define QT_NO_QDEBUG_MACRO \ while (false) \ QMessageLogger().noDebug #endif #if defined(QT_NO_DEBUG_OUTPUT) #define DEBUG QT_NO_QDEBUG_MACRO #else #define DEBUG(...) qCDebug(_loging_category_, __VA_ARGS__) #endif #define LOG(...) qCInfo(_loging_category_, __VA_ARGS__) #define WARN(...) qCWarning(_loging_category_, __VA_ARGS__) #define ERROR(...) qCCritical(_loging_category_, __VA_ARGS__) qtrvsim-0.9.8/external/svgscene/src/svgscene/utils/memory_ownership.h000066400000000000000000000006331467752164200262370ustar00rootroot00000000000000/** * Manual memory ownership toolkit. */ #pragma once #include /** * Tag for pointer owned by someone else. It is recommended to mention owner * in comment to make lifetimes manually verifiable. */ #define BORROWED /** * Pointer with static lifetime. */ #define STATIC /** * Owned pointer deallocated by automatic destructor. */ template using Box = QScopedPointer;qtrvsim-0.9.8/extras/000077500000000000000000000000001467752164200145615ustar00rootroot00000000000000qtrvsim-0.9.8/extras/building/000077500000000000000000000000001467752164200163565ustar00rootroot00000000000000qtrvsim-0.9.8/extras/building/build-wasm.sh000066400000000000000000000007731467752164200207650ustar00rootroot00000000000000#!/usr/bin/env bash set -eu EMSCRIPTEN_VERSION=$1 QT_WASM=$2 EMSDK_PATH=$3 # If you know how to do this better, please, let me know. [ "$(stat -c '%a' "$EMSDK_PATH")" -ne 777 ] && sudo chmod 777 -R $EMSDK_PATH emsdk install $EMSCRIPTEN_VERSION emsdk activate $EMSCRIPTEN_VERSION source $EMSDK_PATH/emsdk_env.sh mkdir -p build/wasm pushd build/wasm emcmake cmake ../.. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="$QT_WASM" \ -DCMAKE_FIND_ROOT_PATH="$QT_WASM" \ -Wno-dev -G Ninja ninja popdqtrvsim-0.9.8/extras/core_graphics/000077500000000000000000000000001467752164200173715ustar00rootroot00000000000000qtrvsim-0.9.8/extras/core_graphics/diagram.drawio000066400000000000000000005160171467752164200222160ustar00rootroot00000000000000 qtrvsim-0.9.8/extras/crosscompiling/000077500000000000000000000000001467752164200176145ustar00rootroot00000000000000qtrvsim-0.9.8/extras/crosscompiling/shell-mips-elf.nix000066400000000000000000000003001467752164200231460ustar00rootroot00000000000000# Provides shell with a crosscompiler for code to simulate with import { crossSystem = { config = "mips-elf"; }; }; mkShell { buildInputs = [ ]; # your dependencies here }qtrvsim-0.9.8/extras/packaging/000077500000000000000000000000001467752164200165055ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/_tools/000077500000000000000000000000001467752164200200045ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/_tools/add-to-changelog.sh000066400000000000000000000023341467752164200234370ustar00rootroot00000000000000#!/usr/bin/env bash CHANGELOG_FILE="extras/packaging/deb/debian/changelog" if [ $# -lt 1 ]; then echo "Version has to be specified" exit 1 fi V_TXT="$1" cd "$(dirname "$0")/../.." V_DATE_MDY="$(date '+%m/%d/%Y')" V_DATE_YMD="$(date '+%Y-%m-%d')" V_DATE_RFC="$(date -R)" V_USER_NAME="$(git config user.name)" V_USER_EMAIL="$(git config user.email)" if grep -q "qtrvsim ($V_TXT)" $CHANGELOG_FILE; then sed --in-place \ -e '1,/^ -- .*$/s/^ -- .*$/'" -- $V_USER_NAME <$V_USER_EMAIL> $V_DATE_RFC/" \ $CHANGELOG_FILE else cat >$CHANGELOG_FILE.tmp < $V_DATE_RFC EOF cat $CHANGELOG_FILE >> $CHANGELOG_FILE.tmp mv $CHANGELOG_FILE.tmp $CHANGELOG_FILE fi $EDITOR $CHANGELOG_FILE echo Press enter to continue read x git add $CHANGELOG_FILE echo >.git/GITGUI_MSG "Version updated to $V_TXT" git gui git tag -d v$V_TXT git tag -s v$V_TXT # TODO #if [ -x /usr/lib/obs-build/changelog2spec ]; then # /usr/lib/obs-build/changelog2spec debian/changelog >../qtrvsim.changes #elif [ -x /usr/lib/build/changelog2spec ]; then # /usr/lib/build/changelog2spec debian/changelog >../qtrvsim.changes #fi qtrvsim-0.9.8/extras/packaging/_tools/git-archive-submodules.sh000066400000000000000000000034471467752164200247320ustar00rootroot00000000000000#!/usr/bin/env bash set -eu # Tool to crate source archive including submodules # based on (MIT): https://github.com/nzanepro/git-archive-submodules # Parameters: project-root destination file_name module-prefix version [git-command] [tar-command] [xz-command] export TMPDIR=`realpath ${2}`/pack/ export SOURCE=`realpath ${1}` export DESTINATION=`realpath ${2}/${3}` export TARMODULE=${4} export TARVERSION=${5} export TARPREFIX="${TARMODULE}-${TARVERSION}" export GIT=${6:-"git"} export TAR=${7:-"tar"} export XZ=${8:-"xz"} mkdir -p ${TMPDIR} pushd ${SOURCE} || exit # create module archive ${GIT} archive --prefix=${TARPREFIX}/ -o ${TMPDIR}${TARPREFIX}.tar HEAD if [[ ! -f "${TMPDIR}${TARPREFIX}.tar" ]]; then echo "ERROR: base sourcecode archive was not created. check git output in log above." exit 1 fi # Makefile is only helper for development and should be excluded in release. # The command is allowed to fail if Makefile is not found. ${TAR} -f "${TMPDIR}${TARPREFIX}.tar" --delete ${TARPREFIX}/Makefile 2>/dev/null || true # force init submodules ${GIT} submodule update --init --recursive # tar each submodule recursively ${GIT} submodule foreach --recursive 'git archive --prefix=${TARPREFIX}/${displaypath}/ HEAD > ${TMPDIR}tmp.tar && ${TAR} --concatenate --file=${TMPDIR}${TARPREFIX}.tar ${TMPDIR}tmp.tar' popd || exit # compress tar file ${XZ} ${TMPDIR}${TARPREFIX}.tar if [[ ! -f "${TMPDIR}${TARPREFIX}.tar.xz" ]]; then echo "ERROR: xzipped archive was not created. check git output in log above." exit 1 fi cp ${TMPDIR}${TARPREFIX}.tar.xz ${DESTINATION} if [[ -f "${TMPDIR}${TARPREFIX}.tar.xz" ]]; then rm ${TMPDIR}${TARPREFIX}.tar.xz echo "created ${DESTINATION}" else echo "ERROR copying ${TMPDIR}${TARPREFIX}.tar.xz to ${DESTINATION}" usage exit 1 fi # cleanup rm -r ${TMPDIR} qtrvsim-0.9.8/extras/packaging/add-to-changelog.sh000066400000000000000000000023341467752164200221400ustar00rootroot00000000000000#!/usr/bin/env bash CHANGELOG_FILE="extras/packaging/deb/debian/changelog" if [ $# -lt 1 ]; then echo "Version has to be specified" exit 1 fi V_TXT="$1" cd "$(dirname "$0")/../.." V_DATE_MDY="$(date '+%m/%d/%Y')" V_DATE_YMD="$(date '+%Y-%m-%d')" V_DATE_RFC="$(date -R)" V_USER_NAME="$(git config user.name)" V_USER_EMAIL="$(git config user.email)" if grep -q "qtrvsim ($V_TXT)" $CHANGELOG_FILE; then sed --in-place \ -e '1,/^ -- .*$/s/^ -- .*$/'" -- $V_USER_NAME <$V_USER_EMAIL> $V_DATE_RFC/" \ $CHANGELOG_FILE else cat >$CHANGELOG_FILE.tmp < $V_DATE_RFC EOF cat $CHANGELOG_FILE >> $CHANGELOG_FILE.tmp mv $CHANGELOG_FILE.tmp $CHANGELOG_FILE fi $EDITOR $CHANGELOG_FILE echo Press enter to continue read x git add $CHANGELOG_FILE echo >.git/GITGUI_MSG "Version updated to $V_TXT" git gui git tag -d v$V_TXT git tag -s v$V_TXT # TODO #if [ -x /usr/lib/obs-build/changelog2spec ]; then # /usr/lib/obs-build/changelog2spec debian/changelog >../qtrvsim.changes #elif [ -x /usr/lib/build/changelog2spec ]; then # /usr/lib/build/changelog2spec debian/changelog >../qtrvsim.changes #fi qtrvsim-0.9.8/extras/packaging/appimage/000077500000000000000000000000001467752164200202705ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/appimage/appimage.yml.in000066400000000000000000000012371467752164200232060ustar00rootroot00000000000000app: @PACKAGE_NAME@ build: packages: - linuxdeployqt - pkgconfig(Qt5Core) - pkgconfig(Qt5Widgets) - pkgconfig(Qt5Test) - pkgconfig(Qt5PrintSupport) - libelf-devel script: - cd $BUILD_SOURCE_DIR - tar xf @PACKAGE_SOURCE_ARCHIVE_FILE@ - cd @PACKAGE_TOPLEVEL_DIR@ - mkdir build - cd build - export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) - cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr - cmake --build . - DESTDIR="$BUILD_APPDIR" cmake --install . - unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH - linuxdeployqt $BUILD_APPDIR/usr/share/applications/*.desktop -bundle-non-qt-libs -verbose=2 -no-stripqtrvsim-0.9.8/extras/packaging/arch/000077500000000000000000000000001467752164200174225ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/arch/PKGBUILD.in000066400000000000000000000012261467752164200211540ustar00rootroot00000000000000# Maintainer: @PACKAGE_MAINTAINER@ pkgname=@PACKAGE_NAME@ pkgver=@PROJECT_VERSION@ pkgrel=1 pkgdesc="@PACKAGE_DESCRIPTION@" arch=("any") url="@PACKAGE_URL@" license=('@PACKAGE_LICENCE@') depends=("qt5-base") makedepends=("cmake" "elfutils") source=("@PACKAGE_SOURCE_ARCHIVE_FILE@") md5sums=("@FILE_MD5@") prepare() { export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) cd "$srcdir/@PACKAGE_TOPLEVEL_DIR@" mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr } build() { cd "$srcdir/@PACKAGE_TOPLEVEL_DIR@/build" cmake --build . } package() { cd "$srcdir/@PACKAGE_TOPLEVEL_DIR@/build" DESTDIR="$pkgdir" cmake --install . }qtrvsim-0.9.8/extras/packaging/deb/000077500000000000000000000000001467752164200172375ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/deb/debian/000077500000000000000000000000001467752164200204615ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/deb/debian/changelog000066400000000000000000000332171467752164200223410ustar00rootroot00000000000000qtrvsim (0.9.8-1) unstable; urgency=medium * Machine: aclintmtimer fix count type * GUI: fix a crash on nonexistent include * Use win32 config of libelf when compiling natively for Windows * CI: Add Windows Clang debug build and macos ARM * CLI: reporter dump to json * Machine: instruction parsing refactor * GUI: make printer settings persistent and scale to fit PDF page size * Assembler: fix immediate parsing * Assembler: implement GAS modifiers - PC rel still basic only * Machine: fix zext.w/h inst parse and fix tokenized for inst.xxx * Machine: fix parse_csr_address and CSR::RegisterMapByName key type * Machine and GUI: Pseudo LRU cache policy * Add 25x speed for teaching convenience * Machien and GUI: Include Jiri Stefan's work on branch predictor * Machien and GUI: BTB, BHT and BHR are implemented * Project: Explicit cmake qt major version option * Packaging: add Keywords entry into desktop file * Machine: add peripherals high/top address aliases for XLEN=64 * GUI: switch "New" dialog page selection to tree widget, polishing required -- Pavel Pisa Tue, 01 Oct 2024 20:45:22 +0200 qtrvsim (0.9.7-1) unstable; urgency=medium * GUI: fix examples button crashes on Windows and sometimes other platforms * GUI: fix crash when no tab is selected * CI: add windows libs to artifacts and use more cores available * CI: Make pack QT with Win artifact * Project: Use the include directory for LibElf on macOS, Homebrew misses RISC-V * Machine: set SXL and UXL to 64-bit XLEN for RV64 -- Pavel Pisa Thu, 15 Feb 2024 20:57:12 +0100 qtrvsim (0.9.6-1) unstable; urgency=medium * GUI: add reset widows menu entry to restore default windows layout * Machine: extend CSR support to pass rv32mi-p-mcsr and rv64mi-p-mcsr official test * Machine: serial port interrupts reworked for RISC-V as platform irq 16 and 17 * GUI: RISC-V ACLINT MTIMER mapping added into resources/samples/template.S * Machine: implemented RISC-V A extension for RV32IMA/RV64IMA support * GUI: the XLEN, atomic and multiply options available in new simulation dialog * GUI: update registers and CSR views for bare RV64IMA support * Machine and GUI: simple level 2 cache implementation * GUI: increase cache set count limit to 1024 * CLI: add isa-variant, cycle-limit and l2-cache options * CLI: dump-ranges allows to use symbols even from internal assembly * Memory: correctly propagate external/DMA changes to GUI * Machine: where possible, re-implement pseudo instructions by aliase tables * os_emulation: resolve problem with write and read from/to stack area on RV32 * GUI: fix double free of children widgets in control register widget * GUI: refactor gui source file to tree structure * GUI: program view - collapse address and breakpoint if space is limited * GUI: split central widget tabs to coreview and editor * GUI: editor line numbers and highlight error in the editor on message click * GUI: editor toggle comment (ctrl+/) * GUI: ensure that all lines of external make process output are processed * os_emulation: correct ftruncate syscall arguments for 64 and 32-bit ABI * Update README.md to document interrupt, trap, ACLINT+MTIMER and AMO support * CI: drop support for Ubuntu 18 * Project: bump to c++17 -- Pavel Pisa Mon, 11 Dec 2023 11:12:15 +0100 qtrvsim (0.9.5-1) unstable; urgency=medium * Machine: use cvector in instruction args to spedup decoding * Machine: move controlstate to csr and prepare BitArg to be usd there * Machine: use method for CSR writes to enable mutual register dependencies * Machine: CSR: define mie register. * Machine: CSR: fix conditions for register write and add mie to the list. * Machine: fix range for branch instructions B-encoding * CLI: add simple tracer for memory reads and writes. * CLI: initial support to enable OS emulation even for CLI version * GUI: update coreview graphics by Michal Stepanosvky * GUI: fix wrong svg label connection and reset all to zero -- Pavel Pisa Mon, 16 Jan 2023 11:22:08 +0200 qtrvsim (0.9.4-1) unstable; urgency=medium * GUI: Async modal library to overcome WebAssembly/Emscripten limitations * Wasm: support and build improved * os_emulation: correct open flags O_xxx values to match RISC-V Linux ABI. * packaging: fix Fedora build according to Jan Grulich advice. * README.md: add reference to Embedded World Conference 2022 article. * qtrvsim_tester: Tomas Veznik implemented testing against official RISC/V ISA tests. * CI: speedup by using common build of official tests * Machine: initial support for CSR instructions by Jakub Dupak * GUI: CSR: syntax highlight CSR reg names * Machine: CSR: disassemble CSR register based on the mnemonic register settings * GUI: save mnemonic registers settings * Machine: add support for 64-bit RV64IM target and related 32-bit/word limited instructions * README.md: update information about basic 64-bit support. -- Pavel Pisa Mon, 24 Oct 2022 23:07:19 +0200 qtrvsim (0.9.3-1) unstable; urgency=medium * Debian package updated to version 0.9.3. * Machine: fix LCD display endianness. * Machine: correct memory stall cycles computation. * Machine: correct unaligned and partial (lb, sb, lh, sh) to peripheral registers. * Packaging: flatpak support kindly provided by David Heidelberg * Machine and GUI: switch to RISC-V CSR names and remove references to MIPS COP0. * Machine: correct parsing of registers s10 and s11 names. * Machine: fix null pointer usage in cache * GUI: fix null pointer usage in cache * Machine: correct cache graphics visualization for byte accesses. * Machine: LFU cache policy incorrect use of sets count instead of degree of associativity. -- Pavel Pisa Thu, 21 Apr 2022 09:40:37 +0200 qtrvsim (0.9.2-1) unstable; urgency=medium * Debian package updated to version 0.9.2. * GUI: rework of coreview graphics to correspond to Mr. Stepanovsky slides * CI: downgrade runner os to win2019 to prevent failing builds * WASM: fix exception support * LRU cache policy fix (check was incoorect only for flush, i.e. fence instruction) * Machine: basic RV32M support (no specific GUI provided, considered as part of ALU) * README.md update, document RV32M support * Machine: RISC-V ABI places stack pointer into x2 register. * Machine: rewrite all core_alu_forward and complex memory tests for RISC-V. * Machine: RISC-V is by default little endian, even when ELF file is not loaded -- Pavel Pisa Tue, 12 Mar 2022 20:45:12 +0200 qtrvsim (0.9.1-1) unstable; urgency=medium * Debian package updated to version 0.9.1. * Recognize FENCE and FENCE.I instructions, they flush whole cache for now. * Corrected register numbers visualization. * Corrected negative numbers in disassembler. * Bugfixes and cleanup. -- Pavel Pisa Tue, 1 Mar 2022 19:15:22 +0200 qtrvsim (0.9.0-1) unstable; urgency=medium * Debian package updated to version 0.9.0. * JALR. * Basic pseudoinstruction support. * Partial recreation of testing. * Bugfixes and cleanup. -- Jakub Dupak Tue, 15 Feb 2022 03:32:50 +0200 qtrvsim (0.8.1-1) unstable; urgency=medium * Debian package updated to version 0.8.1-1. * Fixes visualization of stalls. * Moves jump evaluation from EX to MEM as initially intended and as shown in the cpu diagram. * Fixes WASM build - keyboard handling. * Adds Qt6 support. -- Jakub Dupak Wed, 15 Dec 2021 18:55:55 +0100 qtrvsim (0.8.0) unstable; urgency=medium * Debian package updated to version 0.8.0. -- Jakub Dupak Mon, 17 May 2021 15:27:10 +0200 qtrvsim (0.8.0-1) unstable; urgency=medium * Debian package updated to version 0.8.0. * Switch to RISC-V simulator -- Jakub Dupak Tue, 04 May 2021 23:01:01 +0200 qtmips (0.7.5) unstable; urgency=medium * Debian package updated to version 0.7.5. * Improve UI compatbility with dark color schemes (by Michal Maly, MadCatX) * prepare-release: document alternative Debian package preparation in quilt mode. * Enable dock widows nesting to enable show cache + memory simultaneously (by Frantisek Vacek) * AppImage build run (by Frantisek Vacek) * qtmips_cli: add option to connect serial port input and output to file. * samples: template-os.S template.S fixed SPILED_REG_BASE definition. * README: add documentation how to modify comprocessor 0 regs (by Jan Kaisrlik) * EADME.md: fix reference to uart rx interrupt mask (by Jan Kaisrlik) * Fix open of ELF files using national alphabets in the path names on Windows. * qtmips_gui: fix response to user decision to save modified file when make is invoked. -- Pavel Pisa Sun, 06 Sep 2020 13:16:34 +0200 qtmips (0.7.4) unstable; urgency=medium * Debian package updated to version 0.7.4. * debian packaging: add git attribute to merge changelog. * debian packaging: add watch file for GitHub QtMips repository. -- Pavel Pisa Sun, 15 Sep 2019 20:32:41 +0200 qtmips (0.7.3) unstable; urgency=medium * Debian package updated to version 0.7.3. * Implemented SKIP/SPACE assembler directives. * Add OpenHub statistic page link. * Provide support for include directive in simple assembler. * In include, use content from editor if file is already open. * Add #pragma processing to integrated assembler and its usage to control windows. * Use #pragma in examples to lower initial learning curve. * samples: simple-lw-sw-ia.S: place data section to 0x2000 address. -- Pavel Pisa Thu, 12 Sep 2019 11:47:46 +0200 qtmips (0.7.2) unstable; urgency=medium * Debian package updated to version 0.7.2. * More changes to use dialog open instead of exec (Emscripten does not support exec). * Updates to RPM packaging and spec file to better follow Suse rules. * Move fixmatheval and assembly compiler to separate library independent on Qt GUI API. * Implemented message window to report compilation errors. * Store operator text description in the fixmatheval operators tree. * Simple assembler moved to separate class which is independent on Qt GUI API. * Do not open editor twice for same filename. * Enable CLI version to use simple assembler. * Update editor search algorithm to prefer current editor for unnamed buffers. * Add config option to reset machine before internal assembler starts. * Include C language syntax highlighter for alternative sources editing. * Action to execute external make command and ask for unsaved sources. * Ask to save modified files on exit. * Ask for modified source close and handle unnamed sources close. * Replace shortcuts to not hide Ctrl+C and some others. * Implemented ASCII and ASCIZ operations. * Include actions New source and Close source on toolbar. * Make program and memory window visible when address requested from symbol dialog. * Add embedded examples menu and resources. -- Pavel Pisa Wed, 21 Aug 2019 00:13:06 +0200 qtmips (0.7.1) unstable; urgency=medium * Debian package updated to version 0.7.1. * Add option to parse and show symbolic registers names. * Implemented simple integrated assembler - it is not recommended for advanced users. * Updated instructions parsing to be usable for integrated assembler. * Change instruction parsing to allow multiple words pseudo-operations. * Implemented simple expressions and labels/symbols evaluation. * Simple highlighter for assembly language added. * Include simple text editor in QtMips emulator. * Fix memory leakages which repeat during program operation. * Externally caused address-space changes (i.e. from peripherals) update memory view. * Provide option to hide coreview to speedup simulation. -- Pavel Pisa Wed, 03 Jul 2019 12:18:15 +0200 qtmips (0.7.0) unstable; urgency=medium * Debian package updated to version 0.7.0. * Include simple LCD frame-buffer and display implementation. * Simulate push of dial buttons by check box. * Allow to create simulator without loaded executable. * Printing/export to PDF file reduces print area/page to actual image size. * Disable text elide for memory and program views (fix for MAC OS). * Implement standard zoom handling by mouse wheel and keys. -- Pavel Pisa Fri, 28 Jun 2019 15:38:52 +0200 qtmips (0.6.8) unstable; urgency=medium * Debian package updated to version 0.6.8. * Coreview multiplexers updated and added for branch compare forward. * qtmips_gui: set application window icon. * Set gray background to stalled instructions/idled stages. * Setting background color dial * qtmips_cli: start report in decimal mode. -- Pavel Pisa Mon, 01 Apr 2019 15:26:46 +0200 qtmips (0.6.7) unstable; urgency=medium * Debian package updated to version 0.6.7. * Change single cycle core with delay slot to use separate fetch stage. * Program listing and stages use color background. * Correct write through spelling. Reported by Richard Susta. * qtmips_cli can be used for cache statistic and result memory tests. -- Pavel Pisa Wed, 27 Mar 2019 00:38:24 +0100 qtmips (0.6.6) unstable; urgency=medium * Corrected row and column output in cache address fields. * Highlight cache read and write acesses. * Highlight registers and coprocessor 0 read and writes. -- Pavel Pisa Sun, 17 Mar 2019 20:51:55 +0100 qtmips (0.6.5) unstable; urgency=medium * Initial Debian packaging. -- Pavel Pisa Wed, 13 Mar 2019 19:38:33 +0100 qtrvsim-0.9.8/extras/packaging/deb/debian/compat000066400000000000000000000000021467752164200216570ustar00rootroot000000000000009 qtrvsim-0.9.8/extras/packaging/deb/debian/control.in000066400000000000000000000006231467752164200224720ustar00rootroot00000000000000Source: @PACKAGE_NAME@ Section: devel Priority: optional Maintainer: @PACKAGE_MAINTAINER@ Build-Depends: debhelper (>= 9), qtbase5-dev, libelf-dev, cmake Standards-Version: 3.9.8 Homepage: @PACKAGE_URL@ Vcs-Git: @PACKAGE_GIT@ Vcs-Browser: @PACKAGE_URL@ Package: @PACKAGE_NAME@ Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: @PACKAGE_DESCRIPTION@ @PACKAGE_LONG_DESCRIPTION@ qtrvsim-0.9.8/extras/packaging/deb/debian/copyright000066400000000000000000000017561467752164200224250ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: qtrvsim Source: https://github.com/cvut/qtrvsim/ Files: * Copyright: 2017-2019 Karel Koci 2019-2022 Pavel Pisa 2020-2022 Jakub Dupak 2020-2021 Max Hollmann License: GPL-3.0+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . qtrvsim-0.9.8/extras/packaging/deb/debian/docs000066400000000000000000000000161467752164200213310ustar00rootroot00000000000000README.md docsqtrvsim-0.9.8/extras/packaging/deb/debian/rules000066400000000000000000000003421467752164200215350ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- export DH_VERBOSE = 1 export DEB_BUILD_MAINT_OPTIONS=hardening=+all export DEB_LDFLAGS_MAINT_APPEND=-Wl,--as-needed export QT_SELECT := qt5 # --parallel %: dh $@ --buildsystem=cmake qtrvsim-0.9.8/extras/packaging/deb/debian/source/000077500000000000000000000000001467752164200217615ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/deb/debian/source/format000066400000000000000000000000141467752164200231670ustar00rootroot000000000000003.0 (quilt) qtrvsim-0.9.8/extras/packaging/deb/dsc.in000066400000000000000000000013501467752164200203370ustar00rootroot00000000000000Format: 3.0 (quilt) Source: @PACKAGE_NAME@ Binary: @PACKAGE_NAME@ Architecture: any Version: @PACKAGE_VERSION@-@PACKAGE_RELEASE@ Maintainer: @PACKAGE_MAINTAINER@ Homepage: @PACKAGE_URL@ Standards-Version: 3.9.8 Vcs-Browser: @PACKAGE_URL@ Vcs-Git: @PACKAGE_GIT@ Build-Depends: debhelper (>= 9), qtbase5-dev, libelf-dev, cmake Package-List: @PACKAGE_NAME@ deb devel optional arch=any Checksums-Sha1: @DEBIAN_SHA1@ @DEBIAN_SIZE@ @DEBIAN_ARCHIVE_FILE@ @FILE_SHA1@ @FILE_SIZE@ @PACKAGE_SOURCE_ARCHIVE_FILE@ Checksums-Sha256: @DEBIAN_SHA256@ @DEBIAN_SIZE@ @DEBIAN_ARCHIVE_FILE@ @FILE_SHA256@ @FILE_SIZE@ @PACKAGE_SOURCE_ARCHIVE_FILE@ Files: @DEBIAN_MD5@ @DEBIAN_SIZE@ @DEBIAN_ARCHIVE_FILE@ @FILE_MD5@ @FILE_SIZE@ @PACKAGE_SOURCE_ARCHIVE_FILE@ qtrvsim-0.9.8/extras/packaging/flatpak/000077500000000000000000000000001467752164200201275ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/flatpak/cz.cvut.edu.comparch.qtrvsim.json000066400000000000000000000015301467752164200264700ustar00rootroot00000000000000{ "app-id" : "cz.cvut.edu.comparch.qtrvsim", "runtime" : "org.kde.Platform", "runtime-version" : "6.2", "sdk" : "org.kde.Sdk", "tags" : [ "nightly" ], "command" : "qtrvsim_gui", "rename-desktop-file" : "qtrvsim.desktop", "rename-icon" : "qtrvsim_gui", "finish-args" : [ "--device=dri", "--share=ipc", "--socket=fallback-x11", "--socket=wayland" ], "modules" : [ { "name" : "qtrvsim", "buildsystem" : "cmake-ninja", "builddir" : true, "config-opts" : [ "-DCMAKE_BUILD_TYPE=RelWithDebInfo" ], "sources" : [ { "type" : "git", "url" : "https://github.com/cvut/qtrvsim/" } ] } ] } qtrvsim-0.9.8/extras/packaging/mingw/000077500000000000000000000000001467752164200176265ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/mingw/cmake-i686-w64-mingw32.conf000066400000000000000000000012241467752164200241500ustar00rootroot00000000000000# cmake -DCMAKE_TOOLCHAIN_FILE=cmake-i686-w64-mingw32.conf -DCMAKE_BUILD_TYPE=Release ../qtrvsim set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_PROCESSOR x86) set(CMAKE_SYSROOT /usr/i686-w64-mingw32) set(CMAKE_STAGING_PREFIX /home/devel/stage) set(tools /usr) set(CMAKE_C_COMPILER ${tools}/bin/i686-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER ${tools}/bin/i686-w64-mingw32-g++) set(Qt5_DIR /usr/i686-w64-mingw32/qt/lib/cmake/Qt5) set(QT_DIR /usr/i686-w64-mingw32/qt/lib/cmake/Qt5) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) qtrvsim-0.9.8/extras/packaging/nix/000077500000000000000000000000001467752164200173035ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/nix/qtrvsim.nix000066400000000000000000000012371467752164200215330ustar00rootroot00000000000000{ lib, stdenv, cmake, wrapQtAppsHook, qtbase, qtsvg }: stdenv.mkDerivation { name = "QtRVSim"; src = builtins.fetchGit ../../..; nativeBuildInputs = [ cmake wrapQtAppsHook ]; buildInputs = [ qtbase qtsvg ]; meta = { description = "RISC-V CPU simulator for education purposes."; longDescription = '' RISC-V CPU simulator for education purposes with pipeline and cache visualization. Developed at FEE CTU for computer architecture classes. ''; homepage = "https://github.com/cvut/qtrvsim"; license = lib.licenses.gpl3Plus; maintainers = [ "Jakub Dupak " ]; }; }qtrvsim-0.9.8/extras/packaging/rpm/000077500000000000000000000000001467752164200173035ustar00rootroot00000000000000qtrvsim-0.9.8/extras/packaging/rpm/spec.in000066400000000000000000000044361467752164200205740ustar00rootroot00000000000000# # spec file for package @PACKAGE_NAME@ # @COPYRIGHT_HASH_COMMENT@ # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # You should have received a copy of the GNU General Public License along with # this program. If not, see # # Please submit bugfixes or comments via # @PROJECT_HOME_PAGE@ # issues tracker. # Name: @PACKAGE_NAME@ Version: @PACKAGE_VERSION@ Release: @PACKAGE_RELEASE@ Summary: @PACKAGE_DESCRIPTION@ License: @PACKAGE_LICENCE@ Group: System/Emulators/Other URL: @PACKAGE_URL@ Source: @PACKAGE_SOURCE_ARCHIVE_FILE@ BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: pkgconfig BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(Qt5Widgets) BuildRequires: pkgconfig(Qt5Test) BuildRequires: pkgconfig(Qt5PrintSupport) BuildRequires: hicolor-icon-theme %if ! 0%{?suse_version} BuildRequires: pkgconfig(libelf) BuildRequires: desktop-file-utils %endif %if 0%{?suse_version} BuildRequires: libelf-devel BuildRequires: update-desktop-files %endif %description @PACKAGE_LONG_DESCRIPTION@ %prep %setup -q %build %if 0%{?suse_version} %cmake -DCMAKE_CXX_FLAGS="-Wno-error" -DCMAKE_C_FLAGS="-Wno-error" %else %cmake %endif %cmake_build %install %cmake_install #desktop icon %if 0%{?suse_version} %suse_update_desktop_file -r -i @PACKAGE_NAME@ 'System Emulator' %endif %if 0%{?fedora} || 0%{?rhel} || 0%{?centos} desktop-file-validate %{buildroot}/usr/share/applications/@PACKAGE_NAME@.desktop %endif # TODO: this should be generated from CMake %files /usr/bin/qtrvsim_gui /usr/bin/qtrvsim_cli /usr/share/icons/hicolor/scalable/apps/qtrvsim_gui.svg /usr/share/icons/hicolor/48x48/apps/qtrvsim_gui.png /usr/share/applications/qtrvsim.desktop /usr/share/metainfo/cz.cvut.edu.comparch.qtrvsim.metainfo.xml %license LICENSE %doc README.md %changelog qtrvsim-0.9.8/qtlogging.ini000066400000000000000000000000251467752164200157440ustar00rootroot00000000000000[Rules] *.debug=falseqtrvsim-0.9.8/src/000077500000000000000000000000001467752164200140425ustar00rootroot00000000000000qtrvsim-0.9.8/src/assembler/000077500000000000000000000000001467752164200160175ustar00rootroot00000000000000qtrvsim-0.9.8/src/assembler/CMakeLists.txt000066400000000000000000000006551467752164200205650ustar00rootroot00000000000000project(assembler DESCRIPTION "Simple assembler library to use in the UI.") set(CMAKE_AUTOMOC ON) set(assembler_SOURCES fixmatheval.cpp simpleasm.cpp ) set(assembler_HEADERS fixmatheval.h messagetype.h simpleasm.h ) add_library(assembler STATIC ${assembler_SOURCES} ${assembler_HEADERS}) target_link_libraries(assembler PRIVATE ${QtLib}::Core) qtrvsim-0.9.8/src/assembler/fixmatheval.cpp000066400000000000000000000262171467752164200210430ustar00rootroot00000000000000#include "fixmatheval.h" #include "common/math/bit_ops.h" #include "memory/address.h" #include #include using namespace fixmatheval; // Consumes part of string that is a valid symbol name, returns it and removes it from the input // string. QStringView tokenize_symbol(QStringView &expression) { QStringView symbol = expression; int i = 0; for (QChar ch : expression) { if (!(ch.isLetterOrNumber() || (ch == '_'))) { break; } i++; } expression = expression.mid(i); return symbol; } FmeSymbolDb::~FmeSymbolDb() = default; bool FmeSymbolDb::getValue(FmeValue &value, QString name) { (void)value; (void)name; return false; } FmeNode::FmeNode(int priority) { prio = priority; } FmeNode::~FmeNode() = default; int FmeNode::priority() const { return prio; } bool FmeNode::insert(FmeNode *node) { (void)node; return false; } FmeNode *FmeNode::child() { return nullptr; } FmeNode *FmeNode::find_last_child() { FmeNode *current = this; FmeNode *child = this->child(); while (child != nullptr) { current = child; child = child->child(); } return current; } FmeNodeConstant::FmeNodeConstant(FmeValue value) : FmeNode(INT_MAX) { this->value = value; } FmeNodeConstant::~FmeNodeConstant() = default; bool FmeNodeConstant::eval( FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) { std::ignore = symdb; std::ignore = error; std::ignore = inst_addr; value = this->value; return true; } QString FmeNodeConstant::dump() { return QString::number(value); } FmeNodeSymbol::FmeNodeSymbol(QString &name) : FmeNode(INT_MAX) { this->name = name; } FmeNodeSymbol::~FmeNodeSymbol() = default; bool FmeNodeSymbol::eval( FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) { std::ignore = inst_addr; if (!symdb) { error = QString("no symbol table to find value for %1").arg(name); return false; } bool ok = symdb->getValue(value, name); if (!ok) { error = QString("value for symbol \"%1\" not found").arg(name); } return ok; } QString FmeNodeSymbol::dump() { return name; } FmeNodeUnaryOp::FmeNodeUnaryOp( int priority, FmeValue (*op)(FmeValue &a, machine::Address inst_addr), QString description) : FmeNode(priority) { this->operand_a = nullptr; this->op = op; this->description = std::move(description); } FmeNodeUnaryOp::~FmeNodeUnaryOp() { delete operand_a; } bool FmeNodeUnaryOp::FmeNodeUnaryOp::eval( FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) { FmeValue value_a; if (!operand_a) { return false; } if (!operand_a->eval(value_a, symdb, error, inst_addr)) { return false; } value = op(value_a, inst_addr); return true; } FmeNode *FmeNodeUnaryOp::child() { return operand_a; } bool FmeNodeUnaryOp::insert(FmeNode *node) { operand_a = node; return true; } QString FmeNodeUnaryOp::dump() { return "(" + description + " " + (operand_a ? operand_a->dump() : "nullptr") + ")"; } FmeNodeBinaryOp::FmeNodeBinaryOp( int priority, FmeValue (*op)(FmeValue &a, FmeValue &b), FmeNode *left, QString description) : FmeNode(priority) { this->operand_a = left; this->operand_b = nullptr; this->op = op; this->description = std::move(description); } FmeNodeBinaryOp::~FmeNodeBinaryOp() { delete operand_a; delete operand_b; } bool FmeNodeBinaryOp::eval( FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) { FmeValue value_a; FmeValue value_b; if (!operand_a || !operand_b) { return false; } if (!operand_a->eval(value_a, symdb, error, inst_addr) || !operand_b->eval(value_b, symdb, error, inst_addr)) { return false; } value = op(value_a, value_b); return true; } FmeNode *FmeNodeBinaryOp::child() { return operand_b; } bool FmeNodeBinaryOp::insert(FmeNode *node) { operand_b = node; return true; } QString FmeNodeBinaryOp::dump() { return "(" + (operand_a ? operand_a->dump() : "nullptr") + " " + description + " " + (operand_b ? operand_b->dump() : "nullptr") + ")"; } FmeExpression::FmeExpression() : FmeNode(0) { root = nullptr; } bool FmeExpression::parse(const QString &expression, QString &error) { delete root; int base_prio = 100; root = nullptr; bool ok = true; int i; int word_start = 0; bool in_word = false; bool is_unary = true; QString optxtx; for (i = 0; true; i++) { QChar ch {}; if (i < expression.size()) { ch = expression.at(i); } if (!(ch.isLetterOrNumber() || (ch == '_')) || (i >= expression.size())) { if (ch.isSpace()) { continue; } if (in_word) { FmeNode *new_node = nullptr; QString word = expression.mid(word_start, i - word_start); if (word.at(0).isDigit()) { new_node = new FmeNodeConstant(word.toLongLong(&ok, 0)); if (!ok) { error = QString("cannot convert \"%1\" to number").arg(word); delete new_node; break; } } else { new_node = new FmeNodeSymbol(word); } FmeNode *node = this->find_last_child(); ok = node->insert(new_node); if (!ok) { error = QString("parse stuck at \"%1\"").arg(word); break; } in_word = false; is_unary = false; } if (i >= expression.size()) { break; } FmeValue (*binary_op)(FmeValue &a, FmeValue &b) = nullptr; FmeValue (*unary_op)(FmeValue &a, machine::Address inst_addr) = nullptr; int prio = base_prio; optxtx = ch; if (ch == '%') { // `%` MODIFIER `(` SYMBOL `)` // MODIFIER := `hi` | `lo` | `pcrel_hi` | `pcrel_lo` prio += 90; // The opening parenthesis is peeked and asserted but not consumed. QStringView expr = QStringView(expression).mid(i + 1); if (expr.startsWith(QStringLiteral("hi("))) { i += 2; optxtx = QStringLiteral("%hi"); unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return get_bits(a, 31, 12); }; } else if (expr.startsWith(QStringLiteral("lo("))) { i += 2; optxtx = QStringLiteral("%lo"); unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return sign_extend(get_bits(a, 11, 0), 12); }; } else if (expr.startsWith(QStringLiteral("pcrel_hi("))) { i += 8; optxtx = QStringLiteral("%pcrel_hi"); unary_op = [](FmeValue &a, machine::Address inst_addr) -> FmeValue { return get_bits(a - inst_addr.get_raw(), 31, 12) + get_bit(a - inst_addr.get_raw(), 11); }; } else if (expr.startsWith(QStringLiteral("pcrel_lo("))) { i += 8; optxtx = QStringLiteral("%pcrel_lo"); unary_op = [](FmeValue &a, machine::Address inst_addr) -> FmeValue { return sign_extend(get_bits(a - inst_addr.get_raw() + 4, 11, 0), 12); }; } else { auto modifier = tokenize_symbol(expr); error = QString("Unknown modifier \"%1\"").arg(modifier); ok = false; break; } } else if (ch == '~') { prio += 90; unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return ~a; }; } else if (ch == '-') { if (is_unary) { prio += 90; unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return -a; }; } else { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a - b; }; prio += 20; } } else if (ch == '+') { if (is_unary) { continue; } binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a + b; }; prio += 20; } else if (ch == '*') { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a * b; }; prio += 30; } else if (ch == '/') { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a / b; }; prio += 30; } else if (ch == '|') { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a | b; }; prio += 10; } else if (ch == '&') { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a & b; }; prio += 15; } else if (ch == '^') { binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a ^ b; }; prio += 15; } else if (ch == '(') { base_prio += 100; } else if (ch == ')') { base_prio -= 100; if (base_prio <= 0) { ok = false; error = QString("Unbalanced brackets."); break; } } else { error = QString("Unknow character \"%1\" in expression.").arg(ch); ok = false; break; } if ((binary_op != nullptr) || (unary_op != nullptr)) { FmeNode *node; FmeNode *child; for (node = this; (child = node->child()) != nullptr; node = child) { if (child->priority() >= prio) { break; } } if (binary_op != nullptr) { ok = node->insert(new FmeNodeBinaryOp(prio, binary_op, child, optxtx)); is_unary = true; } else { ok = node->insert(new FmeNodeUnaryOp(prio, unary_op, optxtx)); } if (!ok) { error = QString("parse stuck at \"%1\"").arg(QString(ch)); break; } } } else { if (!in_word) { word_start = i; } in_word = true; } } return ok; } FmeExpression::~FmeExpression() { delete root; root = nullptr; } bool FmeExpression::eval( FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) { if (!root) { return false; } return root->eval(value, symdb, error, inst_addr); } bool FmeExpression::insert(FmeNode *node) { root = node; return true; } FmeNode *FmeExpression::child() { return root; } QString FmeExpression::dump() { return "(" + (root ? root->dump() : "nullptr") + ")"; } qtrvsim-0.9.8/src/assembler/fixmatheval.h000066400000000000000000000054571467752164200205130ustar00rootroot00000000000000#ifndef FIXMATHEVAL_H #define FIXMATHEVAL_H #include "memory/address.h" #include namespace fixmatheval { typedef int64_t FmeValue; class FmeSymbolDb { public: virtual ~FmeSymbolDb(); virtual bool getValue(FmeValue &value, QString name) = 0; }; class FmeNode { public: explicit FmeNode(int priority); virtual ~FmeNode(); virtual bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) = 0; virtual bool insert(FmeNode *node); virtual FmeNode *child(); virtual QString dump() = 0; FmeNode *find_last_child(); [[nodiscard]] int priority() const; private: int prio; }; class FmeNodeConstant : public FmeNode { public: explicit FmeNodeConstant(FmeValue value); ~FmeNodeConstant() override; bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) override; QString dump() override; private: FmeValue value; }; class FmeNodeSymbol : public FmeNode { public: explicit FmeNodeSymbol(QString &name); ~FmeNodeSymbol() override; bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) override; QString dump() override; private: QString name; }; class FmeNodeUnaryOp : public FmeNode { public: FmeNodeUnaryOp( int priority, FmeValue (*op)(FmeValue &a, machine::Address inst_addr), QString description = "??"); ~FmeNodeUnaryOp() override; bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) override; bool insert(FmeNode *node) override; FmeNode *child() override; QString dump() override; private: FmeValue (*op)(FmeValue &a, machine::Address inst_addr); FmeNode *operand_a; QString description; }; class FmeNodeBinaryOp : public FmeNode { public: FmeNodeBinaryOp( int priority, FmeValue (*op)(FmeValue &a, FmeValue &b), FmeNode *left, QString description = "??"); ~FmeNodeBinaryOp() override; bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) override; bool insert(FmeNode *node) override; FmeNode *child() override; QString dump() override; private: FmeValue (*op)(FmeValue &a, FmeValue &b); FmeNode *operand_a; FmeNode *operand_b; QString description; }; class FmeExpression : public FmeNode { public: FmeExpression(); ~FmeExpression() override; virtual bool parse(const QString &expression, QString &error); bool eval(FmeValue &value, FmeSymbolDb *symdb, QString &error, machine::Address inst_addr) override; bool insert(FmeNode *node) override; FmeNode *child() override; QString dump() override; private: FmeNode *root; }; } // namespace fixmatheval #endif /*FIXMATHEVAL_H*/ qtrvsim-0.9.8/src/assembler/messagetype.h000066400000000000000000000002751467752164200205220ustar00rootroot00000000000000#ifndef MESSAGETYPE_H #define MESSAGETYPE_H namespace messagetype { enum Type { MSG_START, MSG_FINISH, MSG_INFO, MSG_WARNING, MSG_ERROR, }; } #endif /*MESSAGETYPE*/ qtrvsim-0.9.8/src/assembler/simpleasm.cpp000066400000000000000000000571631467752164200205310ustar00rootroot00000000000000#include "simpleasm.h" #include "machine/memory/address.h" #include "machine/memory/memory_utils.h" #include #include #include #include #include using namespace fixmatheval; using machine::Address; using ae = machine::AccessEffects; // For enum values, type is obvious from // context. SymbolTableDb::SymbolTableDb(machine::SymbolTable *symbol_table) { this->symbol_table = symbol_table; } bool SymbolTableDb::getValue(fixmatheval::FmeValue &value, QString name) { SymbolValue val; if (!symbol_table->name_to_value(val, name)) { return false; } value = val; return true; } void SymbolTableDb::setSymbol( const QString &name, SymbolValue value, SymbolSize size, SymbolInfo info, SymbolOther other) { symbol_table->set_symbol(name, value, size, info, other); } uint64_t SimpleAsm::string_to_uint64(const QString &str, int base, int *chars_taken) { int i; int64_t val; char *p, *r; char cstr[str.count() + 1]; for (i = 0; i < str.count(); i++) { cstr[i] = str.at(i).toLatin1(); } cstr[i] = 0; p = cstr; val = std::strtoll(p, &r, base); if (chars_taken != nullptr) { *chars_taken = r - p; } return val; } SimpleAsm::SimpleAsm(QObject *parent) : Super(parent) { clear(); } SimpleAsm::~SimpleAsm() { clear(); } void SimpleAsm::clear() { symtab = nullptr; mem = nullptr; while (!reloc.isEmpty()) { delete reloc.takeFirst(); } error_occured = false; fatal_occured = false; } void SimpleAsm::setup( machine::FrontendMemory *mem, SymbolTableDb *symtab, machine::Address address, machine::Xlen xlen) { this->mem = mem; this->symtab = symtab; this->address = address; this->symtab->setSymbol("XLEN", static_cast(xlen), sizeof(uint64_t)); } static const machine::BitArg wordArg = { { { 32, 0 } }, 0 }; bool SimpleAsm::process_line( const QString &line, const QString &filename, int line_number, QString *error_ptr) { QString error; QString label = ""; QString op = ""; QStringList operands; int pos; bool in_quotes = false; bool backslash = false; bool maybe_label = true; bool final = false; bool separator; bool space_separated = false; int token_beg = -1; int token_last = -1; int operand_num = -1; for (pos = 0; pos <= line.count(); pos++) { QChar ch = ' '; if (pos >= line.count()) { final = true; } if (!final) { ch = line.at(pos); } if (!in_quotes) { if (ch == '#') { if (line.mid(pos).startsWith("#include")) { if ((line.count() > pos + 8) && !line.at(pos + 8).isSpace()) { final = true; } } else if (line.mid(pos).startsWith("#pragma")) { if ((line.count() > pos + 7) && !line.at(pos + 7).isSpace()) { final = true; } else { space_separated = true; } } else { final = true; } } if (ch == ';') { final = true; } if (ch == '/') { if (pos + 1 < line.count()) { if (line.at(pos + 1) == '/') { final = true; } } } separator = final || (maybe_label && (ch == ':')) || ((operand_num >= 0) && ((ch == ',') || (space_separated && ch.isSpace() && (token_beg != -1)))); if (maybe_label && (ch == ':')) { maybe_label = false; if (token_beg == -1) { error = "empty label"; emit report_message( messagetype::MSG_ERROR, filename, line_number, pos, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } label = line.mid(token_beg, token_last - token_beg + 1); token_beg = -1; } else if ( ((!ch.isSpace() && (token_beg >= 0) && (token_last < pos - 1)) || final) && (operand_num == -1)) { maybe_label = false; if (token_beg != -1) { op = line.mid(token_beg, token_last - token_beg + 1).toLower(); } token_beg = -1; operand_num = 0; if (ch == ',') { error = "empty first operand"; emit report_message( messagetype::MSG_ERROR, filename, line_number, pos, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } } else if (separator || final) { if (token_beg == -1) { error = "empty operand"; emit report_message( messagetype::MSG_ERROR, filename, line_number, pos, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } operands.append(line.mid(token_beg, token_last - token_beg + 1)); token_beg = -1; operand_num++; } if (final) { break; } if (!ch.isSpace() && !separator) { if (token_beg == -1) { token_beg = pos; } token_last = pos; } backslash = false; if (ch == '"') { if (operand_num == -1) { error = "unexpected quoted text"; emit report_message( messagetype::MSG_ERROR, filename, line_number, pos, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } in_quotes = true; } } else { token_last = pos; if (final) { error = "unterminated quoted text"; emit report_message(messagetype::MSG_ERROR, filename, line_number, pos, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } if ((ch == '"') && !backslash) { in_quotes = false; } if ((ch == '\\') && !backslash) { backslash = true; } else { backslash = false; } } } if (!label.isEmpty()) { symtab->setSymbol(label, address.get_raw(), 4); } if (op.isEmpty()) { if (operands.count() != 0) { error = "operands for empty operation"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } return true; } if (op == "#pragma") { return process_pragma(operands, filename, line_number, error_ptr); } if (op == "#include") { bool res = true; QString incname; if ((operands.count() != 1) || operands.at(0).isEmpty()) { error = "the single file has to be specified for include"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } incname = operands.at(0); if (incname.at(0) == '"') { incname = incname.mid(1, incname.count() - 2); } QFileInfo fi(QFileInfo(filename).dir(), incname); incname = fi.filePath(); include_stack.append(filename); if (include_stack.contains(incname)) { error = QString("recursive include of file: \"%1\"").arg(incname); res = false; } else { if (!process_file(incname, error_ptr)) { res = false; error = QString("error in included file: \"%1\"").arg(incname); } } if (!res) { emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { if (error_ptr->isEmpty()) { *error_ptr = error; } } } include_stack.removeLast(); return res; } if ((op == ".text") || (op == ".data") || (op == ".bss") || (op == ".globl") || (op == ".end") || (op == ".ent") || (op == ".option")) { return true; } if (op == ".org") { bool ok; fixmatheval::FmeExpression expression; fixmatheval::FmeValue value; if (operands.count() != 1) { error = ".org unexpected number of operands"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } ok = expression.parse(operands.at(0), error); if (!ok) { fatal_occured = true; error = tr(".orig %1 parse error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } ok = expression.eval(value, symtab, error, address); if (!ok) { fatal_occured = true; error = tr(".orig %1 evaluation error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } address = machine::Address(value); return true; } if ((op == ".space") || (op == ".skip")) { bool ok; fixmatheval::FmeExpression expression; fixmatheval::FmeValue value; fixmatheval::FmeValue fill = 0; if ((operands.count() != 1) && (operands.count() != 2)) { error = ".space/.skip unexpected number of operands"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } if (operands.count() > 1) { ok = expression.parse(operands.at(1), error); if (!ok) { fatal_occured = true; error = tr(".space/.skip %1 parse error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } ok = expression.eval(fill, symtab, error, address); if (!ok) { fatal_occured = true; error = tr(".space/.skip %1 evaluation error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } } ok = expression.parse(operands.at(0), error); if (!ok) { fatal_occured = true; error = tr(".space/.skip %1 parse error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } ok = expression.eval(value, symtab, error, address); if (!ok) { fatal_occured = true; error = tr(".space/.skip %1 evaluation error.").arg(line); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } while (value-- > 0) { if (!fatal_occured) { mem->write_u8(address, (uint8_t)fill, ae::INTERNAL); } address += 1; } return true; } if ((op == ".equ") || (op == ".set")) { if ((operands.count() > 2) || (operands.count() < 1)) { error = tr(".set or .equ incorrect arguments number."); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } QString name = operands.at(0).trimmed(); if ((name == "noat") || (name == "noreored")) { return true; } bool ok; fixmatheval::FmeValue value = 1; if (operands.count() > 1) { fixmatheval::FmeExpression expression; ok = expression.parse(operands.at(1), error); if (ok) { ok = expression.eval(value, symtab, error, address); } if (!ok) { error = tr(".set or .equ %1 parse error.").arg(operands.at(1)); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } } symtab->setSymbol(name, value, 0); return true; } if ((op == ".ascii") || (op == ".asciz")) { bool append_zero = op == ".asciz"; for (QString s : operands) { if (s.count() < 2) { error = "ascii empty string"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } if ((s.at(0) != '"') || (s.at(s.count() - 1) != '"')) { error = "ascii missing quotes"; emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } s = s.mid(1, s.count() - 2); for (pos = 0; pos < s.count(); pos++) { // target byte is in ASCII encoding uint8_t target_byte = 0x00; QChar host_char = s.at(pos); if (host_char == '\\') { // if the host encoding recognizes this as a backslash (escape char) // handle end of the string check if (pos + 1 >= s.count()) { error = "ascii - invalid escape sequence at the end of the string"; emit report_message( messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } // compare the host_char in host encoding but emit byte in ASCII encoding host_char = s.at(++pos); if (host_char == '0') { target_byte = 0x00; } else if (host_char == 'b') { target_byte = 0x08; } else if (host_char == 't') { target_byte = 0x09; } else if (host_char == 'n') { target_byte = 0x0A; } else if (host_char == 'r') { target_byte = 0x0D; } else if (host_char == '"') { target_byte = 0x22; } else if (host_char == '\\') { target_byte = 0x5C; } else { error = QString("ascii - incorrect escape sequence '\\") + host_char + "'"; emit report_message( messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } } else { // otherwise convert it to ASCII and write it as-is target_byte = host_char.toLatin1(); } if (!fatal_occured) { mem->write_u8(address, target_byte, ae::INTERNAL); } address += 1; } if (append_zero) { if (!fatal_occured) { mem->write_u8(address, 0, ae::INTERNAL); } address += 1; } } return true; } if (op == ".byte") { bool ok; for (const QString &s : operands) { uint32_t val = 0; int chars_taken; val = string_to_uint64(s, 0, &chars_taken); if (chars_taken != s.size()) { fixmatheval::FmeExpression expression; fixmatheval::FmeValue value; ok = expression.parse(s, error); if (!ok) { fatal_occured = true; error = tr(".byte %1 parse error.").arg(line); emit report_message( messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } ok = expression.eval(value, symtab, error, address); if (!ok) { fatal_occured = true; error = tr(".byte %1 evaluation error.").arg(line); emit report_message( messagetype::MSG_ERROR, filename, line_number, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } val = (uint8_t)value; } if (!fatal_occured) { mem->write_u8(address, (uint8_t)val, ae::INTERNAL); } address += 1; } return true; } while (address.get_raw() & 3) { if (!fatal_occured) { mem->write_u8(address, 0, ae::INTERNAL); } address += 1; } if (op == ".word") { for (QString s : operands) { s = s.simplified(); uint32_t val = 0; int chars_taken; val = string_to_uint64(s, 0, &chars_taken); if (chars_taken != s.size()) { val = 0; reloc.append(new machine::RelocExpression( address, s, 0, -0xffffffff, 0xffffffff, &wordArg, filename, line_number)); } if (!fatal_occured) { mem->write_u32(address, val, ae::INTERNAL); } address += 4; } return true; } uint32_t inst[2] = { 0, 0 }; size_t size = 0; try { machine::TokenizedInstruction inst_tok { op, operands, address, filename, static_cast(line_number) }; size = machine::Instruction::code_from_tokens(inst, 8, inst_tok, &reloc); } catch (machine::Instruction::ParseError &e) { error = tr("instruction %1 parse error - %2.").arg(line, e.message); emit report_message(messagetype::MSG_ERROR, filename, line_number, 0, e.message, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } uint32_t *p = inst; for (size_t l = 0; l < size; l += 4) { if (!fatal_occured) { mem->write_u32(address, *(p++), ae::INTERNAL); } address += 4; } return true; } bool SimpleAsm::process_file(const QString &filename, QString *error_ptr) { QString error; bool res = true; QFile srcfile(filename); if (!srcfile.open(QFile::ReadOnly | QFile::Text)) { error = QString("cannot open file: \"%1\"").arg(filename); emit report_message(messagetype::MSG_ERROR, "", 0, 0, error, ""); error_occured = true; if (error_ptr != nullptr) { *error_ptr = error; } return false; } for (int ln = 1; !srcfile.atEnd(); ln++) { QString line = srcfile.readLine(); if ((line.count() > 0) && (line.at(line.count() - 1) == '\n')) { line.truncate(line.count() - 1); } if (!process_line(line, filename, ln, error_ptr)) { res = false; } } srcfile.close(); return res; } bool SimpleAsm::finish(QString *error_ptr) { bool error_reported = false; for (machine::RelocExpression *r : reloc) { QString error; fixmatheval::FmeExpression expression; if (!expression.parse(r->expression, error)) { error = tr("expression parse error %1 at line %2, expression %3.") .arg(error, QString::number(r->line), expression.dump()); emit report_message(messagetype::MSG_ERROR, r->filename, r->line, 0, error, ""); if (error_ptr != nullptr && !error_reported) { *error_ptr = error; } error_occured = true; error_reported = true; } else { fixmatheval::FmeValue value; if (!expression.eval(value, symtab, error, r->location)) { error = tr("expression evalution error %1 at line %2 , " "expression %3.") .arg(error, QString::number(r->line), expression.dump()); emit report_message(messagetype::MSG_ERROR, r->filename, r->line, 0, error, ""); if (error_ptr != nullptr && !error_reported) { *error_ptr = error; } error_occured = true; error_reported = true; } else { if (false) { emit report_message( messagetype::MSG_INFO, r->filename, r->line, 0, expression.dump() + " -> " + QString::number(value), ""); } machine::Instruction inst(mem->read_u32(r->location, ae::INTERNAL)); if (!inst.update(value, r)) { error = tr("instruction update error %1 at line %2, " "expression %3 -> value %4.") .arg( error, QString::number(r->line), expression.dump(), QString::number(value)); emit report_message(messagetype::MSG_ERROR, r->filename, r->line, 0, error, ""); if (error_ptr != nullptr && !error_reported) { *error_ptr = error; } error_occured = true; error_reported = true; // Remove address } if (!fatal_occured) { mem->write_u32(Address(r->location), inst.data(), ae::INTERNAL); } } } } while (!reloc.isEmpty()) { delete reloc.takeFirst(); } emit mem->external_change_notify(mem, Address::null(), Address(0xffffffff), ae::INTERNAL); return !error_occured; } bool SimpleAsm::process_pragma( QStringList &operands, const QString &filename, int line_number, QString *error_ptr) { (void)operands; (void)filename; (void)line_number; (void)error_ptr; return true; } qtrvsim-0.9.8/src/assembler/simpleasm.h000066400000000000000000000040441467752164200201640ustar00rootroot00000000000000#ifndef SIMPLEASM_H #define SIMPLEASM_H #include "fixmatheval.h" #include "machine/machine.h" #include "machine/memory/frontend_memory.h" #include "messagetype.h" #include #include using machine::SymbolInfo; using machine::SymbolOther; using machine::SymbolSize; using machine::SymbolValue; class SymbolTableDb : public fixmatheval::FmeSymbolDb { public: explicit SymbolTableDb(machine::SymbolTable *symbol_table); bool getValue(fixmatheval::FmeValue &value, QString name) override; void setSymbol( const QString &name, SymbolValue value, SymbolSize size, SymbolInfo info = 0, SymbolOther other = 0); private: machine::SymbolTable *symbol_table; }; class SimpleAsm : public QObject { Q_OBJECT using Super = QObject; signals: void report_message( messagetype::Type type, QString file, int line, int column, QString text, QString hint); public: explicit SimpleAsm(QObject *parent = nullptr); ~SimpleAsm() override; public: static uint64_t string_to_uint64(const QString &str, int base, int *chars_taken = nullptr); void clear(); void setup( machine::FrontendMemory *mem, SymbolTableDb *symtab, machine::Address address, machine::Xlen xlen); bool process_line( const QString &line, const QString &filename = "", int line_number = 0, QString *error_ptr = nullptr); virtual bool process_file(const QString &filename, QString *error_ptr = nullptr); bool finish(QString *error_ptr = nullptr); protected: virtual bool process_pragma( QStringList &operands, const QString &filename = "", int line_number = 0, QString *error_ptr = nullptr); bool error_occured {}; bool fatal_occured {}; SymbolTableDb *symtab {}; machine::Address address {}; private: QStringList include_stack; machine::FrontendMemory *mem {}; machine::RelocExpressionList reloc; }; #endif /*SIMPLEASM_H*/ qtrvsim-0.9.8/src/cli/000077500000000000000000000000001467752164200146115ustar00rootroot00000000000000qtrvsim-0.9.8/src/cli/CMakeLists.txt000066400000000000000000000042161467752164200173540ustar00rootroot00000000000000project(cli LANGUAGES C CXX VERSION ${MAIN_PROJECT_VERSION} DESCRIPTION "Simulator command-line UI.") set(CMAKE_AUTOMOC ON) set(cli_SOURCES chariohandler.cpp main.cpp msgreport.cpp reporter.cpp tracer.cpp ) set(cli_HEADERS chariohandler.h msgreport.h reporter.h tracer.h ) add_executable(cli ${cli_SOURCES} ${cli_HEADERS}) target_link_libraries(cli PRIVATE ${QtLib}::Core machine os_emulation assembler) target_compile_definitions(cli PRIVATE APP_ORGANIZATION=\"${MAIN_PROJECT_ORGANIZATION}\" APP_ORGANIZATION_DOMAIN=\"${MAIN_PROJECT_HOMEPAGE_URL}\" APP_NAME=\"${MAIN_PROJECT_NAME}\" APP_VERSION=\"${PROJECT_VERSION}\" ENV_CONFIG_FILE_NAME=\"${MAIN_PROJECT_NAME_UPPER}_CONFIG_FILE\") set_target_properties(cli PROPERTIES OUTPUT_NAME "${MAIN_PROJECT_NAME_LOWER}_${PROJECT_NAME}") # ============================================================================= # Installation # ============================================================================= # Prior to CMake version 3.13, installation must be performed in the subdirectory, # there the target was created. Therefore executable installation is to be found # in corresponding CMakeLists.txt. install(TARGETS cli RUNTIME DESTINATION bin) include(../../cmake/TestingTools.cmake) enable_testing() add_cli_test( NAME stalls ARGS --asm "${CMAKE_SOURCE_DIR}/tests/cli/stalls/program.S" --dump-registers EXPECTED_OUTPUT "tests/cli/stalls/stdout.txt" ) add_cli_test( NAME asm_error ARGS --asm "${CMAKE_SOURCE_DIR}/tests/cli/asm-error/program.S" ) set_tests_properties(cli_asm_error PROPERTIES WILL_FAIL TRUE) add_cli_test( NAME modifiers ARGS --asm "${CMAKE_SOURCE_DIR}/tests/cli/modifiers/program.S" EXPECTED_OUTPUT "tests/cli/modifiers/stdout.txt" ) add_cli_test( NAME modifiers-pcrel ARGS --asm "${CMAKE_SOURCE_DIR}/tests/cli/modifiers-pcrel/program.S" EXPECTED_OUTPUT "tests/cli/modifiers-pcrel/stdout.txt" ) qtrvsim-0.9.8/src/cli/chariohandler.cpp000066400000000000000000000061031467752164200201200ustar00rootroot00000000000000#include "chariohandler.h" CharIOHandler::CharIOHandler(QIODevice *iodev, QObject *parent) : QIODevice(parent) , fd_list() { this->iodev = iodev; if (!iodev->parent()) { iodev->setParent(this); } fd_specific = false; if (iodev->isOpen()) { Super::open(iodev->openMode()); } connect(iodev, &Super::aboutToClose, this, &CharIOHandler::aboutToClose); connect(iodev, &Super::bytesWritten, this, &CharIOHandler::bytesWritten); connect( iodev, &Super::channelBytesWritten, this, &CharIOHandler::channelBytesWritten); connect( iodev, &Super::channelReadyRead, this, &CharIOHandler::channelReadyRead); connect( iodev, &Super::readChannelFinished, this, &CharIOHandler::readChannelFinished); connect(iodev, &Super::readyRead, this, &CharIOHandler::readyRead); } CharIOHandler::~CharIOHandler() { if (iodev->parent() == this) delete iodev; } void CharIOHandler::writeByte(unsigned int data) { char ch = (char)data; write(&ch, 1); } void CharIOHandler::writeByte(int fd, unsigned int data) { if (!fd_specific || fd_list.contains(fd)) writeByte(data); } void CharIOHandler::readBytePoll(int fd, unsigned int &data, bool &available) { char ch; qint64 res; if (!fd_specific || fd_list.contains(fd)) { if (bytesAvailable() > 0) { res = read(&ch, 1); if (res > 0) { data = ch & 0xff; available = true; } } } } void CharIOHandler::insertFd(const int &fd) { fd_list.insert(fd); } void CharIOHandler::removeFd(const int &fd) { fd_list.remove(fd); } bool CharIOHandler::isSequential() const { return iodev->isSequential(); } bool CharIOHandler::open(OpenMode mode) { if (!iodev->open(mode)) { return false; } Super::open(mode); return true; } void CharIOHandler::close() { Super::close(); iodev->close(); } qint64 CharIOHandler::pos() const { return iodev->pos(); } qint64 CharIOHandler::size() const { return iodev->size(); } bool CharIOHandler::seek(qint64 pos) { return iodev->seek(pos); } bool CharIOHandler::atEnd() const { return iodev->atEnd(); } bool CharIOHandler::reset() { return iodev->reset(); } qint64 CharIOHandler::bytesAvailable() const { return iodev->bytesAvailable() + Super::bytesAvailable(); } qint64 CharIOHandler::bytesToWrite() const { return iodev->bytesToWrite() + Super::bytesToWrite(); } bool CharIOHandler::canReadLine() const { return iodev->canReadLine(); } bool CharIOHandler::waitForReadyRead(int msecs) { return iodev->waitForReadyRead(msecs); } bool CharIOHandler::waitForBytesWritten(int msecs) { return iodev->waitForBytesWritten(msecs); } qint64 CharIOHandler::readData(char *data, qint64 maxSize) { return iodev->read(data, maxSize); } qint64 CharIOHandler::readLineData(char *data, qint64 maxSize) { return iodev->readLine(data, maxSize); } qint64 CharIOHandler::writeData(const char *data, qint64 maxSize) { return iodev->write(data, maxSize); } qtrvsim-0.9.8/src/cli/chariohandler.h000066400000000000000000000026431467752164200175720ustar00rootroot00000000000000#ifndef CHARIOHANDLER_H #define CHARIOHANDLER_H #include #include #include class CharIOHandler : public QIODevice { Q_OBJECT using Super = QIODevice; public: explicit CharIOHandler(QIODevice *iodev, QObject *parent = nullptr); ~CharIOHandler() override; public slots: void writeByte(unsigned int data); void writeByte(int fd, unsigned int data); void readBytePoll(int fd, unsigned int &data, bool &available); public: void insertFd(const int &fd); void removeFd(const int &fd); [[nodiscard]] bool isSequential() const override; bool open(OpenMode mode) override; void close() override; [[nodiscard]] qint64 pos() const override; [[nodiscard]] qint64 size() const override; bool seek(qint64 pos) override; [[nodiscard]] bool atEnd() const override; bool reset() override; [[nodiscard]] qint64 bytesAvailable() const override; [[nodiscard]] qint64 bytesToWrite() const override; [[nodiscard]] bool canReadLine() const override; bool waitForReadyRead(int msecs) override; bool waitForBytesWritten(int msecs) override; protected: qint64 readData(char *data, qint64 maxSize) override; qint64 readLineData(char *data, qint64 maxSize) override; qint64 writeData(const char *data, qint64 maxSize) override; private: QIODevice *iodev; bool fd_specific; QSet fd_list; }; #endif // CHARIOHANDLER_H qtrvsim-0.9.8/src/cli/main.cpp000066400000000000000000000522711467752164200162500ustar00rootroot00000000000000#include "assembler/simpleasm.h" #include "chariohandler.h" #include "common/logging.h" #include "common/logging_format_colors.h" #include "machine/machineconfig.h" #include "os_emulation/ossyscall.h" #include "msgreport.h" #include "reporter.h" #include "tracer.h" #include #include #include #include #include #include using namespace machine; using namespace std; using ae = machine::AccessEffects; // For enum values, type is obvious from // context. void create_parser(QCommandLineParser &p) { p.setApplicationDescription("QtRvSim CLI machine simulator"); p.addHelpOption(); p.addVersionOption(); p.addPositionalArgument("FILE", "Input ELF executable file or assembler source"); // p.addOptions({}); available only from Qt 5.4+ p.addOption({ "asm", "Treat provided file argument as assembler source." }); p.addOption({ "pipelined", "Configure CPU to use five stage pipeline." }); p.addOption({ "no-delay-slot", "Disable jump delay slot." }); p.addOption( { "hazard-unit", "Specify hazard unit implementation [none|stall|forward].", "HUKIND" }); p.addOption({ { "trace-fetch", "tr-fetch" }, "Trace fetched instruction (for both pipelined and not core)." }); p.addOption({ { "trace-decode", "tr-decode" }, "Trace instruction in decode stage. (only for pipelined core)" }); p.addOption({ { "trace-execute", "tr-execute" }, "Trace instruction in execute stage. (only for pipelined core)" }); p.addOption({ { "trace-memory", "tr-memory" }, "Trace instruction in memory stage. (only for pipelined core)" }); p.addOption({ { "trace-writeback", "tr-writeback" }, "Trace instruction in write back stage. (only for pipelined core)" }); p.addOption({ { "trace-pc", "tr-pc" }, "Print program counter register changes." }); p.addOption({ { "trace-wrmem", "tr-wr" }, "Trace writes into memory." }); p.addOption({ { "trace-rdmem", "tr-rd" }, "Trace reads from memory." }); p.addOption({ { "trace-gp", "tr-gp" }, "Print general purpose register changes. You can use * for " "all registers.", "REG" }); p.addOption({ "dump-to-json", "Configure reportor dump to json file.", "FNAME" }); p.addOption({ { "dump-registers", "d-regs" }, "Dump registers state at program exit." }); p.addOption({ "dump-cache-stats", "Dump cache statistics at program exit." }); p.addOption({ "dump-cycles", "Dump number of CPU cycles till program end." }); p.addOption({ "dump-range", "Dump memory range.", "START,LENGTH,FNAME" }); p.addOption({ "load-range", "Load memory range.", "START,FNAME" }); p.addOption({ "expect-fail", "Expect that program causes CPU trap and fail if it doesn't." }); p.addOption({ "fail-match", "Program should exit with exactly this CPU TRAP. Possible values are " "I(unsupported Instruction), A(Unsupported ALU operation), " "O(Overflow/underflow) and J(Unaligned Jump). You can freely combine " "them. Using this implies expect-fail option.", "TRAP" }); p.addOption({ "d-cache", "Data cache. Format policy,sets,words_in_blocks,associativity where " "policy is random/lru/lfu", "DCACHE" }); p.addOption({ "i-cache", "Instruction cache. Format policy,sets,words_in_blocks,associativity " "where policy is random/lru/lfu", "ICACHE" }); p.addOption({ "l2-cache", "L2 cache. Format policy,sets,words_in_blocks,associativity where " "policy is random/lru/lfu", "L2CACHE" }); p.addOption({ "read-time", "Memory read access time (cycles).", "RTIME" }); p.addOption({ "write-time", "Memory read access time (cycles).", "WTIME" }); p.addOption({ "burst-time", "Memory read access time (cycles).", "BTIME" }); p.addOption({ { "serial-in", "serin" }, "File connected to the serial port input.", "FNAME" }); p.addOption( { { "serial-out", "serout" }, "File connected to the serial port output.", "FNAME" }); p.addOption({ { "os-emulation", "osemu" }, "Operating system emulation." }); p.addOption({ { "std-out", "stdout" }, "File connected to the syscall standard output.", "FNAME" }); p.addOption({ { "os-fs-root", "osfsroot" }, "Emulated system root/prefix for opened files", "DIR" }); p.addOption({ { "isa-variant", "isavariant" }, "Instruction set to emulate (default RV32IMA)", "STR" }); p.addOption({ "cycle-limit", "Limit execution to specified maximum clock cycles", "NUMBER" }); } void configure_cache(CacheConfig &cacheconf, const QStringList &cachearg, const QString &which) { if (cachearg.empty()) { return; } cacheconf.set_enabled(true); QStringList pieces = cachearg.at(cachearg.size() - 1).split(","); if (pieces.size() < 3) { fprintf( stderr, "Parameters %s cache incorrect (correct lru,4,2,2,wb).\n", qPrintable(which)); exit(EXIT_FAILURE); } if (pieces.at(0).size() < 1) { fprintf(stderr, "Policy for %s cache is incorrect.\n", qPrintable(which)); exit(EXIT_FAILURE); } if (!pieces.at(0).at(0).isDigit()) { if (pieces.at(0).toLower() == "random") { cacheconf.set_replacement_policy(CacheConfig::RP_RAND); } else if (pieces.at(0).toLower() == "lru") { cacheconf.set_replacement_policy(CacheConfig::RP_LRU); } else if (pieces.at(0).toLower() == "lfu") { cacheconf.set_replacement_policy(CacheConfig::RP_LFU); } else { fprintf(stderr, "Policy for %s cache is incorrect.\n", qPrintable(which)); exit(EXIT_FAILURE); } pieces.removeFirst(); } if (pieces.size() < 3) { fprintf( stderr, "Parameters for %s cache incorrect (correct lru,4,2,2,wb). \n", qPrintable(which)); exit(EXIT_FAILURE); } cacheconf.set_set_count(pieces.at(0).toLong()); cacheconf.set_block_size(pieces.at(1).toLong()); cacheconf.set_associativity(pieces.at(2).toLong()); if (cacheconf.set_count() == 0 || cacheconf.block_size() == 0 || cacheconf.associativity() == 0) { fprintf( stderr, "Parameters for %s cache cannot have zero component. \n", qPrintable(which)); exit(EXIT_FAILURE); } if (pieces.size() > 3) { if (pieces.at(3).toLower() == "wb") { cacheconf.set_write_policy(CacheConfig::WP_BACK); } else if (pieces.at(3).toLower() == "wt" || pieces.at(3).toLower() == "wtna") { cacheconf.set_write_policy(CacheConfig::WP_THROUGH_NOALLOC); } else if (pieces.at(3).toLower() == "wta") { cacheconf.set_write_policy(CacheConfig::WP_THROUGH_ALLOC); } else { fprintf( stderr, "Write policy for %s cache is incorrect (correct wb/wt/wtna/wta). \n", qPrintable(which)); exit(EXIT_FAILURE); } } } void parse_u32_option( QCommandLineParser &parser, const QString &option_name, MachineConfig &config, void (MachineConfig::*setter)(uint32_t value)) { auto values = parser.values(option_name); if (!values.empty()) { bool ok = true; // Try to parse supplied value. uint32_t value = values.last().toUInt(&ok); if (ok) { // Set the value if successfully parsed. (config.*setter)(value); } else { fprintf( stderr, "Value of option %s is not a valid unsigned integer.", qPrintable(option_name)); exit(EXIT_FAILURE); } } } void configure_machine(QCommandLineParser &parser, MachineConfig &config) { QStringList arguments = parser.positionalArguments(); if (arguments.size() != 1) { fprintf(stderr, "Single ELF file has to be specified\n"); parser.showHelp(); } config.set_elf(arguments[0]); config.set_delay_slot(!parser.isSet("no-delay-slot")); config.set_pipelined(parser.isSet("pipelined")); auto hazard_unit_values = parser.values("hazard-unit"); if (!hazard_unit_values.empty()) { if (!config.set_hazard_unit(hazard_unit_values.last().toLower())) { fprintf(stderr, "Unknown kind of hazard unit specified\n"); exit(EXIT_FAILURE); } } parse_u32_option(parser, "read-time", config, &MachineConfig::set_memory_access_time_read); parse_u32_option(parser, "write-time", config, &MachineConfig::set_memory_access_time_write); parse_u32_option(parser, "burst-time", config, &MachineConfig::set_memory_access_time_burst); if (!parser.values("burst-time").empty()) config.set_memory_access_enable_burst(true); configure_cache(*config.access_cache_data(), parser.values("d-cache"), "data"); configure_cache(*config.access_cache_program(), parser.values("i-cache"), "instruction"); configure_cache(*config.access_cache_level2(), parser.values("l2-cache"), "level2"); config.set_osemu_enable(parser.isSet("os-emulation")); config.set_osemu_known_syscall_stop(false); int siz = parser.values("os-fs-root").size(); if (siz >= 1) { QString osemu_fs_root = parser.values("os-fs-root").at(siz - 1); if (osemu_fs_root.length() > 0) config.set_osemu_fs_root(osemu_fs_root); } siz = parser.values("isa-variant").size(); for (int i = 0; i < siz; i++) { int pos = 0; bool first = true; bool subtract = false; QString isa_str = parser.values("isa-variant").at(i).toUpper(); if (isa_str.startsWith ("RV32")) { config.set_simulated_xlen(machine::Xlen::_32); pos = 4; } else if (isa_str.startsWith ("RV64")) { config.set_simulated_xlen(machine::Xlen::_64); pos = 4; } for (; pos < isa_str.size(); pos++, first = false) { char ch = isa_str.at(pos).toLatin1(); if (ch == '+') { subtract = false; continue; } else if (ch == '-') { subtract = true; continue; } auto flag = machine::ConfigIsaWord::byChar(ch); if (flag.isEmpty()) continue; if (first) config.modify_isa_word(~machine::ConfigIsaWord::empty(), machine::ConfigIsaWord::empty()); if (subtract) config.modify_isa_word(flag, machine::ConfigIsaWord::empty()); else config.modify_isa_word(flag, flag); } } } void configure_tracer(QCommandLineParser &p, Tracer &tr) { if (p.isSet("trace-fetch")) { tr.trace_fetch = true; } if (p.isSet("pipelined")) { // Following are added only if we have stages if (p.isSet("trace-decode")) { tr.trace_decode = true; } if (p.isSet("trace-execute")) { tr.trace_execute = true; } if (p.isSet("trace-memory")) { tr.trace_memory = true; } if (p.isSet("trace-writeback")) { tr.trace_writeback = true; } } if (p.isSet("trace-pc")) { tr.trace_pc = true; } if (p.isSet("trace-gp")) { tr.trace_regs_gp = true; } QStringList gps = p.values("trace-gp"); for (const auto & gp : gps) { if (gp == "*") { tr.regs_to_trace.fill(true); } else { bool res; size_t num = gp.toInt(&res); if (res && num <= machine::REGISTER_COUNT) { tr.regs_to_trace.at(num) = true; } else { fprintf( stderr, "Unknown register number given for trace-gp: %s\n", qPrintable(gp)); exit(EXIT_FAILURE); } } } if (p.isSet("trace-rdmem")) { tr.trace_rdmem = true; } if (p.isSet("trace-wrmem")) { tr.trace_wrmem = true; } QStringList clim = p.values("cycle-limit"); if (!clim.empty()) { bool ok; tr.cycle_limit = clim.at(clim.size() - 1).toLong(&ok); if (!ok) { fprintf( stderr, "Cycle limit parse error\n"); exit(EXIT_FAILURE); } } // TODO } void configure_reporter(QCommandLineParser &p, Reporter &r, const SymbolTable *symtab) { if (p.isSet("dump-to-json")) { r.dump_format = (DumpFormat)(r.dump_format | DumpFormat::JSON); r.dump_file_json = p.value("dump-to-json"); } if (p.isSet("dump-registers")) { r.enable_regs_reporting(); } if (p.isSet("dump-cache-stats")) { r.enable_cache_stats(); } if (p.isSet("dump-cycles")) { r.enable_cycles_reporting(); } QStringList fail = p.values("fail-match"); for (const auto & i : fail) { for (int y = 0; y < i.length(); y++) { enum Reporter::FailReason reason; switch (tolower(i.toStdString()[y])) { case 'i': reason = Reporter::FR_UNSUPPORTED_INSTR; break; default: fprintf(stderr, "Unknown fail condition: %c\n", qPrintable(i)[y]); exit(EXIT_FAILURE); } r.expect_fail(reason); } } if (p.isSet("expect-fail") && !p.isSet("fail-match")) { r.expect_fail(Reporter::FailAny); } foreach (QString range_arg, p.values("dump-range")) { uint64_t len; bool ok1 = true; bool ok2 = true; QString str; int comma1 = range_arg.indexOf(","); if (comma1 < 0) { fprintf(stderr, "Range start missing\n"); exit(EXIT_FAILURE); } int comma2 = range_arg.indexOf(",", comma1 + 1); if (comma2 < 0) { fprintf(stderr, "Range length/name missing\n"); exit(EXIT_FAILURE); } str = range_arg.mid(0, comma1); Address start; if (str.size() >= 1 && !str.at(0).isDigit() && symtab != nullptr) { SymbolValue _start; ok1 = symtab->name_to_value(_start, str); start = Address(_start); } else { start = Address(str.toULong(&ok1, 0)); } str = range_arg.mid(comma1 + 1, comma2 - comma1 - 1); if (str.size() >= 1 && !str.at(0).isDigit() && symtab != nullptr) { ok2 = symtab->name_to_value(len, str); } else { len = str.toULong(&ok2, 0); } if (!ok1 || !ok2) { fprintf(stderr, "Range start/length specification error.\n"); exit(EXIT_FAILURE); } r.add_dump_range(start, len, range_arg.mid(comma2 + 1)); } // TODO } void configure_serial_port(QCommandLineParser &p, SerialPort *ser_port) { CharIOHandler *ser_in = nullptr; CharIOHandler *ser_out = nullptr; int siz; if (!ser_port) { return; } siz = p.values("serial-in").size(); if (siz >= 1) { QIODevice::OpenMode mode = QFile::ReadOnly; auto *qf = new QFile(p.values("serial-in").at(siz - 1)); ser_in = new CharIOHandler(qf, ser_port); siz = p.values("serial-out").size(); if (siz) { if (p.values("serial-in").at(siz - 1) == p.values("serial-out").at(siz - 1)) { mode = QFile::ReadWrite; ser_out = ser_in; } } if (!ser_in->open(mode)) { fprintf(stderr, "Serial port input file cannot be open for read.\n"); exit(EXIT_FAILURE); } } if (!ser_out) { siz = p.values("serial-out").size(); if (siz >= 1) { auto *qf = new QFile(p.values("serial-out").at(siz - 1)); ser_out = new CharIOHandler(qf, ser_port); if (!ser_out->open(QFile::WriteOnly)) { fprintf(stderr, "Serial port output file cannot be open for write.\n"); exit(EXIT_FAILURE); } } } if (ser_in) { QObject::connect(ser_in, &QIODevice::readyRead, ser_port, &SerialPort::rx_queue_check); QObject::connect(ser_port, &SerialPort::rx_byte_pool, ser_in, &CharIOHandler::readBytePoll); if (ser_in->bytesAvailable()) { ser_port->rx_queue_check(); } } if (ser_out) { QObject::connect( ser_port, &SerialPort::tx_byte, ser_out, QOverload::of(&CharIOHandler::writeByte)); } } void configure_osemu(QCommandLineParser &p, MachineConfig &config, Machine *machine) { CharIOHandler *std_out = nullptr; int siz; siz = p.values("std-out").size(); if (siz >= 1) { auto *qf = new QFile(p.values("std-out").at(siz - 1)); std_out = new CharIOHandler(qf, machine); if (!std_out->open(QFile::WriteOnly)) { fprintf(stderr, "Emulated system standard output file cannot be open for write.\n"); exit(EXIT_FAILURE); } } const static machine::ExceptionCause ecall_variats[] = {machine::EXCAUSE_ECALL_ANY, machine::EXCAUSE_ECALL_M, machine::EXCAUSE_ECALL_S, machine::EXCAUSE_ECALL_U}; if (config.osemu_enable()) { auto *osemu_handler = new osemu::OsSyscallExceptionHandler( config.osemu_known_syscall_stop(), config.osemu_unknown_syscall_stop(), config.osemu_fs_root()); if (std_out) { machine::Machine::connect( osemu_handler, &osemu::OsSyscallExceptionHandler::char_written, std_out, QOverload::of(&CharIOHandler::writeByte)); } /*connect( osemu_handler, &osemu::OsSyscallExceptionHandler::rx_byte_pool, terminal, &TerminalDock::rx_byte_pool);*/ for (auto ecall_variat : ecall_variats) { machine->register_exception_handler(ecall_variat, osemu_handler); machine->set_step_over_exception(ecall_variat, true); machine->set_stop_on_exception(ecall_variat, false); } } else { for (auto ecall_variat : ecall_variats) { machine->set_step_over_exception(ecall_variat, false); machine->set_stop_on_exception(ecall_variat, config.osemu_exception_stop()); } } } void load_ranges(Machine &machine, const QStringList &ranges) { for (const QString &range_arg : ranges) { bool ok = true; QString str; int comma1 = range_arg.indexOf(","); if (comma1 < 0) { fprintf(stderr, "Range start missing\n"); exit(EXIT_FAILURE); } str = range_arg.mid(0, comma1); Address start; if (str.size() >= 1 && !str.at(0).isDigit() && machine.symbol_table() != nullptr) { SymbolValue _start; ok = machine.symbol_table()->name_to_value(_start, str); start = Address(_start); } else { start = Address(str.toULong(&ok, 0)); } if (!ok) { fprintf(stderr, "Range start/length specification error.\n"); exit(EXIT_FAILURE); } ifstream in; in.open(range_arg.mid(comma1 + 1).toLocal8Bit().data(), ios::in); Address addr = start; for (std::string line; getline(in, line);) { size_t end_pos = line.find_last_not_of(" \t\n"); if (std::string::npos == end_pos) { continue; } size_t start_pos = line.find_first_not_of(" \t\n"); line = line.substr(0, end_pos + 1); line = line.substr(start_pos); size_t idx; uint32_t val = stoul(line, &idx, 0); if (idx != line.size()) { fprintf(stderr, "cannot parse load range data.\n"); exit(EXIT_FAILURE); } machine.memory_data_bus_rw()->write_u32(addr, val, ae::INTERNAL); addr += 4; } in.close(); } } bool assemble(Machine &machine, MsgReport &msgrep, const QString &filename) { SymbolTableDb symbol_table_db(machine.symbol_table_rw(true)); machine::FrontendMemory *mem = machine.memory_data_bus_rw(); if (mem == nullptr) { return false; } machine.cache_sync(); SimpleAsm assembler; SimpleAsm::connect(&assembler, &SimpleAsm::report_message, &msgrep, &MsgReport::report_message); assembler.setup(mem, &symbol_table_db, 0x00000200_addr, machine.core()->get_xlen()); if (!assembler.process_file(filename)) { return false; } return assembler.finish(); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(APP_NAME); QCoreApplication::setApplicationVersion(APP_VERSION); set_default_log_pattern(); QCommandLineParser p; create_parser(p); p.process(app); MachineConfig config; configure_machine(p, config); bool asm_source = p.isSet("asm"); Machine machine(config, !asm_source, !asm_source); Tracer tr(&machine); configure_tracer(p, tr); configure_serial_port(p, machine.serial_port()); configure_osemu(p, config, &machine); if (asm_source) { MsgReport msg_report(&app); if (!assemble(machine, msg_report, p.positionalArguments()[0])) { exit(EXIT_FAILURE); } } Reporter r(&app, &machine); configure_reporter(p, r, machine.symbol_table()); QObject::connect(&tr, &Tracer::cycle_limit_reached, &r, &Reporter::cycle_limit_reached); load_ranges(machine, p.values("load-range")); machine.play(); return QCoreApplication::exec(); } qtrvsim-0.9.8/src/cli/msgreport.cpp000066400000000000000000000013731467752164200173430ustar00rootroot00000000000000#include "msgreport.h" #include using namespace std; MsgReport::MsgReport(QCoreApplication *app) : Super(app) {} void MsgReport::report_message( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint) { (void)hint; QString typestr = "error"; switch (type) { case messagetype::MSG_ERROR: typestr = "error"; break; case messagetype::MSG_WARNING: typestr = "warning"; break; case messagetype::MSG_INFO: typestr = "info"; break; default: return; } printf("%s:", qPrintable(file)); if (line != 0) { printf("%d:", line); } if (column != 0) { printf("%d:", column); } printf("%s:%s\n", qPrintable(typestr), qPrintable(text)); } qtrvsim-0.9.8/src/cli/msgreport.h000066400000000000000000000010161467752164200170020ustar00rootroot00000000000000#ifndef MSGREPORT_H #define MSGREPORT_H #include "assembler/messagetype.h" #include #include #include #include class MsgReport : public QObject { Q_OBJECT using Super = QObject; public: explicit MsgReport(QCoreApplication *app); public slots: static void report_message( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint); }; #endif // MSGREPORT_H qtrvsim-0.9.8/src/cli/reporter.cpp000066400000000000000000000204661467752164200171670ustar00rootroot00000000000000#include "reporter.h" #include using namespace machine; using namespace std; Reporter::Reporter(QCoreApplication *app, Machine *machine) : QObject() , app(app) , machine(machine) { connect(machine, &Machine::program_exit, this, &Reporter::machine_exit); connect(machine, &Machine::program_trap, this, &Reporter::machine_trap); connect( machine->core(), &Core::stop_on_exception_reached, this, &Reporter::machine_exception_reached); } void Reporter::add_dump_range(Address start, size_t len, const QString &path_to_write) { dump_ranges.append({ start, len, path_to_write }); } void Reporter::machine_exit() { report(); if (e_fail != 0) { printf("Machine was expected to fail but it didn't.\n"); QCoreApplication::exit(1); } else { QCoreApplication::exit(); } } /* TODO: Decide whether this should be moved to machine to avoid duplication or kept aside as a visualization concern */ constexpr const char *get_exception_name(ExceptionCause exception_cause) { switch (exception_cause) { case EXCAUSE_NONE: return "NONE"; case EXCAUSE_INSN_FAULT: return "INSN_FAULT"; case EXCAUSE_INSN_ILLEGAL: return "INSN_ILLEGAL"; case EXCAUSE_BREAK: return "BREAK"; case EXCAUSE_LOAD_MISALIGNED: return "LOAD_MISALIGNED"; case EXCAUSE_LOAD_FAULT: return "LOAD_FAULT"; case EXCAUSE_STORE_MISALIGNED: return "STORE_MISALIGNED"; case EXCAUSE_STORE_FAULT: return "STORE_FAULT"; case EXCAUSE_ECALL_U: return "ECALL_U"; case EXCAUSE_ECALL_S: return "ECALL_S"; case EXCAUSE_RESERVED_10: return "RESERVED_10"; case EXCAUSE_ECALL_M: return "ECALL_M"; case EXCAUSE_INSN_PAGE_FAULT: return "INSN_PAGE_FAULT"; case EXCAUSE_LOAD_PAGE_FAULT: return "LOAD_PAGE_FAULT"; case EXCAUSE_RESERVED_14: return "RESERVED_14"; case EXCAUSE_STORE_PAGE_FAULT: return "STORE_PAGE_FAULT"; // Simulator specific exception cause codes, alliases case EXCAUSE_HWBREAK: return "HWBREAK"; case EXCAUSE_ECALL_ANY: return "ECALL_ANY"; case EXCAUSE_INT: return "INT"; default: UNREACHABLE } } void Reporter::machine_exception_reached() { ExceptionCause excause = machine->get_exception_cause(); printf("Machine stopped on %s exception.\n", get_exception_name(excause)); report(); QCoreApplication::exit(); } void Reporter::cycle_limit_reached() { printf("Specified cycle limit reached\n"); report(); QCoreApplication::exit(); } void Reporter::machine_trap(SimulatorException &e) { report(); bool expected = false; if (typeid(e) == typeid(SimulatorExceptionUnsupportedInstruction)) { expected = e_fail & FR_UNSUPPORTED_INSTR; } printf("Machine trapped: %s\n", qPrintable(e.msg(false))); QCoreApplication::exit(expected ? 0 : 1); } void Reporter::report() { if (e_regs | e_cycles | e_cycles | e_fail) { printf("Machine state report:\n"); } if (e_regs) { report_regs(); } if (e_cache_stats) { report_caches(); } if (e_cycles) { QString cycle_count = QString::asprintf("%" PRIu32, machine->core()->get_cycle_count()); QString stall_count = QString::asprintf("%" PRIu32, machine->core()->get_stall_count()); if (dump_format & DumpFormat::JSON) { QJsonObject temp = {}; temp["cycles"] = cycle_count; temp["stalls"] = stall_count; dump_data_json["cycles"] = temp; } if (dump_format & DumpFormat::CONSOLE) { printf("cycles: %s\n", qPrintable(cycle_count)); printf("stalls: %s\n", qPrintable(stall_count)); } } for (const DumpRange &range : dump_ranges) { report_range(range); } if (dump_format & DumpFormat::JSON) { QFile file(dump_file_json); QByteArray bytes = QJsonDocument(dump_data_json).toJson(QJsonDocument::Indented); if (file.open(QIODevice::WriteOnly)) { file.write(bytes); file.close(); printf("JSON object written to file"); } else { printf("Could not open file for writing"); } } } void Reporter::report_regs() { if (dump_format & DumpFormat::JSON) { dump_data_json["regs"] = {}; } report_pc(); for (unsigned i = 0; i < REGISTER_COUNT; i++) { report_gp_reg(i, (i == REGISTER_COUNT - 1)); } for (size_t i = 0; i < CSR::REGISTERS.size(); i++) { report_csr_reg(i, (i == CSR::REGISTERS.size() - 1)); } } void Reporter::report_pc() { QString value = QString::asprintf("0x%08" PRIx64, machine->registers()->read_pc().get_raw()); if (dump_format & DumpFormat::JSON) { QJsonObject regs = dump_data_json["regs"].toObject(); regs["PC"] = value; dump_data_json["regs"] = regs; } if (dump_format & DumpFormat::CONSOLE) { printf("PC:%s\n", qPrintable(value)); } } void Reporter::report_gp_reg(unsigned int i, bool last) { QString key = QString::asprintf("R%u", i); QString value = QString::asprintf("0x%08" PRIx64, machine->registers()->read_gp(i).as_u64()); if (dump_format & DumpFormat::JSON) { QJsonObject regs = dump_data_json["regs"].toObject(); regs[key] = value; dump_data_json["regs"] = regs; } if (dump_format & DumpFormat::CONSOLE) { printf("%s:%s%s", qPrintable(key), qPrintable(value), (last) ? "\n" : " "); } } void Reporter::report_csr_reg(size_t internal_id, bool last) { QString key = QString::asprintf("%s", CSR::REGISTERS[internal_id].name); QString value = QString::asprintf( "0x%08" PRIx64, machine->control_state()->read_internal(internal_id).as_u64()); if (dump_format & DumpFormat::JSON) { QJsonObject regs = dump_data_json["regs"].toObject(); regs[key] = value; dump_data_json["regs"] = regs; } if (dump_format & DumpFormat::CONSOLE) { printf("%s: %s%s", qPrintable(key), qPrintable(value), (last) ? "\n" : " "); } } void Reporter::report_caches() { if (dump_format & DumpFormat::JSON) { dump_data_json["caches"] = {}; } printf("Cache statistics report:\n"); report_cache("i-cache", *machine->cache_program()); report_cache("d-cache", *machine->cache_data()); if (machine->config().cache_level2().enabled()) { report_cache("l2-cache", *machine->cache_level2()); } } void Reporter::report_cache(const char *cache_name, const Cache &cache) { if (dump_format & DumpFormat::JSON) { QJsonObject caches = dump_data_json["caches"].toObject(); QJsonObject temp = {}; temp["reads"] = QString::asprintf("%" PRIu32, cache.get_read_count()); temp["hit"] = QString::asprintf("%" PRIu32, cache.get_hit_count()); temp["miss"] = QString::asprintf("%" PRIu32, cache.get_miss_count()); temp["hit_rate"] = QString::asprintf("%.3lf", cache.get_hit_rate()); temp["stalled_cycles"] = QString::asprintf("%" PRIu32, cache.get_stall_count()); temp["improved_speed"] = QString::asprintf("%.3lf", cache.get_speed_improvement()); caches[cache_name] = temp; dump_data_json["caches"] = caches; } if (dump_format & DumpFormat::CONSOLE) { printf("%s:reads: %" PRIu32 "\n", cache_name, cache.get_read_count()); printf("%s:hit: %" PRIu32 "\n", cache_name, cache.get_hit_count()); printf("%s:miss: %" PRIu32 "\n", cache_name, cache.get_miss_count()); printf("%s:hit-rate: %.3lf\n", cache_name, cache.get_hit_rate()); printf("%s:stalled-cycles: %" PRIu32 "\n", cache_name, cache.get_stall_count()); printf("%s:improved-speed: %.3lf\n", cache_name, cache.get_speed_improvement()); } } void Reporter::report_range(const Reporter::DumpRange &range) { FILE *out = fopen(range.path_to_write.toLocal8Bit().data(), "w"); if (out == nullptr) { fprintf( stderr, "Failed to open %s for writing\n", range.path_to_write.toLocal8Bit().data()); return; } Address start = range.start & ~3; Address end = range.start + range.len; if (end < start) { end = 0xffffffff_addr; } // TODO: report also cached memory? const MemoryDataBus *mem = machine->memory_data_bus(); for (Address addr = start; addr < end; addr += 4) { fprintf(out, "0x%08" PRIx32 "\n", mem->read_u32(addr, ae::INTERNAL)); } if (fclose(out)) { fprintf(stderr, "Failure closing %s\n", range.path_to_write.toLocal8Bit().data()); } } qtrvsim-0.9.8/src/cli/reporter.h000066400000000000000000000041231467752164200166240ustar00rootroot00000000000000#ifndef REPORTER_H #define REPORTER_H #include "common/memory_ownership.h" #include "machine/machine.h" #include #include #include #include #include #include using machine::Address; enum DumpFormat { CONSOLE = 1 << 0, JSON = 1 << 1, }; /** * Watches for special events in the machine (e.g. stop, exception, trap) and prints related * information. */ class Reporter : public QObject { Q_OBJECT public: Reporter(QCoreApplication *app, machine::Machine *machine); void enable_regs_reporting() { e_regs = true; }; void enable_cache_stats() { e_cache_stats = true; }; void enable_cycles_reporting() { e_cycles = true; }; enum FailReason { FR_NONE = 0, FR_UNSUPPORTED_INSTR = (1 << 0), }; static const enum FailReason FailAny = FR_UNSUPPORTED_INSTR; void expect_fail(enum FailReason reason) { e_fail = (FailReason)(e_fail | reason); }; struct DumpRange { Address start; size_t len; /** Path to file, where this range will be dumped. */ QString path_to_write; }; void add_dump_range(Address start, size_t len, const QString &path_to_write); public slots: void cycle_limit_reached(); private slots: void machine_exit(); void machine_trap(machine::SimulatorException &e); void machine_exception_reached(); private: BORROWED QCoreApplication *const app; BORROWED machine::Machine *const machine; QVector dump_ranges; bool e_regs = false; bool e_cache_stats = false; bool e_cycles = false; FailReason e_fail = FR_NONE; void report(); void report_pc(); void report_regs(); void report_caches(); void report_range(const DumpRange &range); void report_csr_reg(size_t internal_id, bool last); void report_gp_reg(unsigned int i, bool last); void report_cache(const char *cache_name, const machine::Cache &cache); public: DumpFormat dump_format = DumpFormat::CONSOLE; QString dump_file_json; QJsonObject dump_data_json = {}; }; #endif // REPORTER_H qtrvsim-0.9.8/src/cli/tracer.cpp000066400000000000000000000041341467752164200165770ustar00rootroot00000000000000#include "tracer.h" #include using namespace machine; Tracer::Tracer(Machine *machine) : core_state(machine->core()->get_state()) { cycle_limit = 0; connect(machine->core(), &Core::step_done, this, &Tracer::step_output); } template void trace_instruction_in_stage( const char *stage_name, const StageStruct &stage, const WritebackInternalState &wb) { printf( "%s: %s%s\n", stage_name, (stage.excause != EXCAUSE_NONE) ? "!" : "", qPrintable(wb.inst.to_str(stage.inst_addr))); } void Tracer::step_output() { const auto &if_id = core_state.pipeline.fetch.final; const auto &id_ex = core_state.pipeline.decode.final; const auto &ex_mem = core_state.pipeline.execute.final; const auto &mem = core_state.pipeline.memory.internal; const auto &mem_wb = core_state.pipeline.memory.final; const auto &wb = core_state.pipeline.writeback.internal; if (trace_fetch) { trace_instruction_in_stage("Fetch", if_id, wb); } if (trace_decode) { trace_instruction_in_stage("Decode", id_ex, wb); } if (trace_execute) { trace_instruction_in_stage("Execute", ex_mem, wb); } if (trace_memory) { trace_instruction_in_stage("Memory", mem_wb, wb); } if (trace_writeback) { // All exceptions are resolved in memory, therefore there is no excause field in WB. printf("Writeback: %s\n", qPrintable(wb.inst.to_str(wb.inst_addr))); } if (trace_pc) { printf("PC: %" PRIx64 "\n", if_id.inst_addr.get_raw()); } if (trace_regs_gp && wb.regwrite && regs_to_trace.at(wb.num_rd)) { printf("GP %zu: %" PRIx64 "\n", size_t(wb.num_rd), wb.value.as_u64()); } if (trace_rdmem && mem_wb.memtoreg) { printf("MEM[%" PRIx64 "]: RD %" PRIx64 "\n", mem_wb.mem_addr.get_raw(), mem_wb.towrite_val.as_u64()); } if (trace_wrmem && mem.memwrite) { printf("MEM[%" PRIx64 "]: WR %" PRIx64 "\n", mem_wb.mem_addr.get_raw(), mem.mem_write_val.as_u64()); } if ((cycle_limit != 0) && (core_state.cycle_count >= cycle_limit)) { emit cycle_limit_reached(); } } qtrvsim-0.9.8/src/cli/tracer.h000066400000000000000000000015361467752164200162470ustar00rootroot00000000000000#ifndef TRACER_H #define TRACER_H #include "machine/instruction.h" #include "machine/machine.h" #include "machine/memory/address.h" #include "machine/registers.h" #include /** * Watches the step by step execution of the machine and prints requested state. */ class Tracer final : public QObject { Q_OBJECT public: explicit Tracer(machine::Machine *machine); signals: void cycle_limit_reached(); private slots: void step_output(); private: const machine::CoreState &core_state; public: std::array regs_to_trace = {}; bool trace_fetch = false, trace_decode = false, trace_execute = false, trace_memory = false, trace_writeback = false, trace_pc = false, trace_wrmem = false, trace_rdmem = false, trace_regs_gp = false; quint64 cycle_limit; }; #endif // TRACER_H qtrvsim-0.9.8/src/common/000077500000000000000000000000001467752164200153325ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/CMakeLists.txt000066400000000000000000000017511467752164200200760ustar00rootroot00000000000000project(common DESCRIPTION "Utils shared between multiple subprojects.") add_subdirectory(polyfills) set(common_HEADERS endian.h string_utils.h logging.h logging_format_colors.h containers/cvector.h math/bit_ops.h memory_ownership.h type_utils/lens.h ) # ============================================================================= # Target for usage of this header library # - this is header only library and it is implicitly available in the whole # project # ============================================================================= # ============================================================================= # Tests # - It is highly recommended to run these tests anytime you use a different # compiler or platform as this code is platform/compiler specific. # ============================================================================= enable_testing() set(CMAKE_AUTOMOC ON) # Put tests here... add_custom_target(common_unit_tests DEPENDS mulh64_test) qtrvsim-0.9.8/src/common/containers/000077500000000000000000000000001467752164200174775ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/containers/cvector.h000066400000000000000000000057341467752164200213260ustar00rootroot00000000000000/* * Based on: * Frozen * Copyright 2016 QuarksLab * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef QTRVSIM_CVECTOR_H #define QTRVSIM_CVECTOR_H #include #include #include #include /** Constexpr vector with inline storage */ template class cvector { T data[N]; // Uninitialized storage cannot be used in constexpr. std::size_t dsize = 0; public: // Container typdefs using value_type = T; using reference = value_type &; using const_reference = const value_type &; using pointer = value_type *; using const_pointer = const value_type *; using iterator = pointer; using const_iterator = const_pointer; using size_type = std::size_t; using difference_type = std::ptrdiff_t; // Constructors constexpr cvector() = default; constexpr cvector(size_type count, const T &value) : dsize(count) { for (std::size_t i = 0; i < N; ++i) data[i] = value; } constexpr cvector(std::initializer_list initializer_list) { for (auto item : initializer_list) { push_back(item); } } // Iterators constexpr iterator begin() noexcept { return data; } constexpr const_iterator begin() const noexcept { return data; } constexpr const_iterator cbegin() const noexcept { return data; } constexpr iterator end() noexcept { return data + dsize; } constexpr const_iterator end() const noexcept { return data + dsize; } constexpr const_iterator cend() const noexcept { return data + dsize; } // Capacity [[nodiscard]] constexpr size_type size() const { return dsize; } // Element access constexpr reference operator[](std::size_t index) { return data[index]; } constexpr const_reference operator[](std::size_t index) const { return data[index]; } constexpr reference back() { return data[dsize - 1]; } constexpr const_reference back() const { return data[dsize - 1]; } // Modifiers constexpr void push_back(const T &a) { data[dsize++] = a; } constexpr void push_back(T &&a) { data[dsize++] = std::move(a); } constexpr void pop_back() { --dsize; } constexpr void clear() { dsize = 0; } }; #endif // QTRVSIM_CVECTOR_H qtrvsim-0.9.8/src/common/endian.h000066400000000000000000000036741467752164200167530ustar00rootroot00000000000000#ifndef ENDIAN_H #define ENDIAN_H #include "polyfills/byteswap.h" #include "polyfills/endian_detection.h" #include "utils.h" #include #include #include #include #include #include #include /** * Memory endian type (used for bot simulator and host machine). * Standard enum is not available until c++20. */ enum Endian { LITTLE, BIG }; inline const char *to_string(Endian val) { switch (val) { case LITTLE: return "LITTLE"; case BIG: return "BIG"; } UNREACHABLE; } inline constexpr Endian get_native_endian() { #if (defined(__BIG_ENDIAN__)) return BIG; #elif (defined(__LITTLE_ENDIAN__)) return LITTLE; #else static_assert( false, "Could not detect endian or endian is neither big nor little."); #endif } constexpr Endian NATIVE_ENDIAN = get_native_endian(); /** * Full generic byteswap. Used in generic functions. * Optimized specializations are provided bellow. */ template inline T byteswap(T val) { static_assert( sizeof(T) <= 8, "Byteswap of large types is implementation dependant."); union U { T val; std::array raw; } src, dst; src.val = val; std::reverse_copy(src.raw.begin(), src.raw.end(), dst.raw.begin()); return dst.val; } template<> inline uint8_t byteswap(uint8_t val) { // NOP for single byte return val; } template<> inline uint16_t byteswap(uint16_t val) { return bswap16(val); } template<> inline uint32_t byteswap(uint32_t val) { return bswap32(val); } template<> inline uint64_t byteswap(uint64_t val) { return bswap64(val); } /** * Conditionally byteswap value. Condition if usually mismatch of endian on * interface of two memory levels or memory and core. */ template T byteswap_if(T value, bool condition) { return (condition) ? byteswap(value) : value; } Q_DECLARE_METATYPE(Endian) #endif // ENDIAN_H qtrvsim-0.9.8/src/common/logging.h000066400000000000000000000023451467752164200171350ustar00rootroot00000000000000/** * Wrapper for QT logging library. * * Each source file is expected to declare a log category name what is * implicitly used for all logging macros. When logging in header files take * precaution not to pollute global scope. Either log manually or declare the * log within class scope. * Log categories can be structured using dots in name: `machine.core * .decode`. * * @see * https://www.kdab.com/wp-content/uploads/stories/slides/Day2/KaiKoehne_Qt%20Logging%20Framework%2016_9_0.pdf */ #ifndef LOGGING_H #define LOGGING_H #include #define LOG_CATEGORY(NAME) static QLoggingCategory _loging_category_(NAME) #if !defined(QT_NO_QDEBUG_MACRO) #define QT_NO_QDEBUG_MACRO \ while (false) \ QMessageLogger().noDebug #endif #if defined(QT_NO_DEBUG_OUTPUT) #define DEBUG QT_NO_QDEBUG_MACRO #else #define DEBUG(...) qCDebug(_loging_category_, __VA_ARGS__) #endif #define LOG(...) qCInfo(_loging_category_, __VA_ARGS__) #define WARN(...) qCWarning(_loging_category_, __VA_ARGS__) #define ERROR(...) qCCritical(_loging_category_, __VA_ARGS__) #endif qtrvsim-0.9.8/src/common/logging_format_colors.h000066400000000000000000000011111467752164200220540ustar00rootroot00000000000000#ifndef LOGGING_FORMAT_COLORS_H #define LOGGING_FORMAT_COLORS_H #include static void set_default_log_pattern() { qSetMessagePattern("%{if-info}\033[34m[INFO] %{endif}" "%{if-debug}\033[37m[DEBUG] %{endif}" "%{if-warning}\033[33m[WARN] %{endif}" "%{if-critical}\033[31m[ERROR] %{endif}" "%{if-fatal}\033[31m[FATAL ERROR] %{endif}" "%{if-category}%{category}:%{endif}" "\033[0m\t%{message}"); } #endif // LOGGING_FORMAT_COLORS_H qtrvsim-0.9.8/src/common/math/000077500000000000000000000000001467752164200162635ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/math/bit_ops.h000066400000000000000000000026341467752164200201000ustar00rootroot00000000000000/** * Bit manipulation library * * @file */ #ifndef QTRVSIM_BIT_OPS_H #define QTRVSIM_BIT_OPS_H #include #include #include using std::size_t; /** * Get value of single bit as lowest bit * * Corresponds to instruction notation `SYMBOL[]`. */ template constexpr inline T get_bit(T val, size_t bit_index) { return (val >> bit_index) & 1; } /** * Generates a bitmask to mask a range of bits. */ template constexpr inline T get_bitmask(size_t start, size_t end) { const size_t len = start - end + 1; return ((1 << len) - 1) << end; } /** * Mask a range of bits in an integer-like value. */ template constexpr inline T mask_bits(T val, size_t start, size_t end) { return val & get_bitmask(start, end); } /** * Extracts range of bits from an integer-like value. * * Corresponds to instruction notation `SYMBOL[start:end]`. */ template constexpr inline T get_bits(T val, size_t start, size_t end) { assert(start >= end); return mask_bits(val >> end, start - end, 0); } /** * Sign extend arbitrary bit range. */ template constexpr inline T sign_extend(T val, size_t size) { size_t T_size = std::numeric_limits::digits; if (std::numeric_limits::is_signed) T_size += 1; size_t shift = T_size - size; return ((int64_t)val << shift) >> shift; } #endif // QTRVSIM_BIT_OPS_H qtrvsim-0.9.8/src/common/memory_ownership.h000066400000000000000000000010741467752164200211130ustar00rootroot00000000000000/** * Manual memory ownership toolkit. */ #ifndef QTRVSIM_MEMORY_OWNERSHIP_H #define QTRVSIM_MEMORY_OWNERSHIP_H #include /** * Tag for pointer owned by someone else. It is recommended to mention owner * in comment to make lifetimes manually verifiable. */ #define BORROWED /** * Pointer with static lifetime. */ #define STATIC /** * Pointer is owned and managed by Qt. */ #define QT_OWNED /** * Owned pointer deallocated by automatic destructor. */ template using Box = QScopedPointer; #endif // QTRVSIM_MEMORY_OWNERSHIP_H qtrvsim-0.9.8/src/common/polyfills/000077500000000000000000000000001467752164200173475ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/polyfills/CMakeLists.txt000066400000000000000000000021661467752164200221140ustar00rootroot00000000000000project(polyfills DESCRIPTION "Helper code to unify access to compiler intrinsics and provide fallback implementations.") set(polyfills_HEADERS endian_detection.h mulh64.h clz32.h byteswap.h qstring_hash.h qt5/qfontmetrics.h qt5/qlinef.h qt5/qtableview.h ) # ============================================================================= # Target for usage of this header library # - this is header only library and it is implicitly available in the whole # project # ============================================================================= # ============================================================================= # Tests # - It is highly recommended to run these tests anytime you use a different # compiler or platform as this code is platform/compiler specific. # ============================================================================= if(NOT "${WASM}") set(CMAKE_AUTOMOC ON) add_executable(mulh64_test mulh64.h mulh64.test.h mulh64.test.cpp ) target_link_libraries(mulh64_test PRIVATE ${QtLib}::Test) add_test(NAME mulh64 COMMAND mulh64_test) endif() qtrvsim-0.9.8/src/common/polyfills/byteswap.h000066400000000000000000000032111467752164200213530ustar00rootroot00000000000000#ifndef BYTESWAP_H #define BYTESWAP_H /* Define byte-swap functions, using fast processor-native built-ins where * possible */ #if defined(_MSC_VER) // needs to be first because msvc doesn't short-circuit // after failing defined(__has_builtin) #define bswap16(x) _byteswap_ushort((x)) #define bswap32(x) _byteswap_ulong((x)) #define bswap64(x) _byteswap_uint64((x)) #elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) #define bswap16(x) __builtin_bswap16((x)) #define bswap32(x) __builtin_bswap32((x)) #define bswap64(x) __builtin_bswap64((x)) #elif defined(__has_builtin) \ && __has_builtin(__builtin_bswap64) /* for clang; gcc 5 fails on this and \ && short circuit fails; must be \ after GCC check */ #define bswap16(x) __builtin_bswap16((x)) #define bswap32(x) __builtin_bswap32((x)) #define bswap64(x) __builtin_bswap64((x)) #else /* even in this case, compilers often optimize by using native instructions */ static inline uint16_t bswap16(uint16_t x) { return (val << 8) | (val >> 8); } static inline uint32_t bswap32(uint32_t x) { val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF); return (val << 16) | (val >> 16); } static inline uint64_t bswap64(uint64_t x) { val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL); val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL); return (val << 32) | (val >> 32); } #endif #endif // BYTESWAP_H qtrvsim-0.9.8/src/common/polyfills/clz32.h000066400000000000000000000013721467752164200204600ustar00rootroot00000000000000#ifndef CLZ32_H #define CLZ32_H #if defined(__GNUC__) && __GNUC__ >= 4 static inline uint32_t clz32(uint32_t n) { int intbits = sizeof(int) * CHAR_BIT; if (n == 0) { return 32; } return __builtin_clz(n) - (intbits - 32); } #else /* Fallback for generic compiler */ // see https://en.wikipedia.org/wiki/Find_first_set#CLZ static const uint8_t sig_table_4bit[16] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; static inline uint32_t clz32(uint32_t n) { int len = 32; if (n & 0xFFFF0000) { len -= 16; n >>= 16; } if (n & 0xFF00) { len -= 8; n >>= 8; } if (n & 0xF0) { len -= 4; n >>= 4; } len -= sig_table_4bit[n]; return len; } #endif #endif // CLZ32_H qtrvsim-0.9.8/src/common/polyfills/endian_detection.h000066400000000000000000000070001467752164200230110ustar00rootroot00000000000000#ifndef ENDIAN_DETECTION_H #define ENDIAN_DETECTION_H /** * Including this file ensures that GCC macros `__LITTLE_ENDIAN__` or * `__BIG_ENDIAN__` are defined regardless of OS and compiler. If used * system/compiler is not supported, it will stop the compilation using a * static assert. Precisely one of the given macros is always guaranteed to be * defined. * * @file */ // Cross-platform endian detection source // https://gist.github.com/jtbr/7a43e6281e6cca353b33ee501421860c (MIT license) #ifdef __has_include // C++17, supported as extension to C++11 in clang, GCC 5+, // vs2015 #if __has_include() #include // gnu libc normally provides, linux #elif __has_include() #include //open bsd, macos #elif __has_include() #include // mingw, some bsd (not open/macos) #elif __has_include() #include // solaris #endif #endif #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \ || (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) \ || (defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN) \ || (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) \ || (defined(__sun) && defined(__SVR4) && defined(_BIG_ENDIAN)) \ || defined(__ARMEB__) || defined(__THUMBEB__) \ || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) \ || defined(__MIBSEB__) || defined(_M_PPC) #define __BIG_ENDIAN__ #elif ( \ defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ || /* gcc */ \ (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) /* linux \ header \ */ \ || (defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN) \ || (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) /* mingw \ header */ \ || (defined(__sun) && defined(__SVR4) && defined(_LITTLE_ENDIAN)) \ || /* solaris */ \ defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) \ || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) \ || defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64) \ || /* msvc for intel processors */ \ defined(_M_ARM) /* msvc code on arm executes in little endian mode */ #define __LITTLE_ENDIAN__ #endif #endif #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) static_assert( false, "Current compiler/system is not supported by the endian " "detection polyfill code or it uses unsupported endian.\n" "Supported endians are: BIG | LITTLE."); #endif #if defined(__LITTLE_ENDIAN__) && defined(__BIG_ENDIAN__) static_assert( false, "Both endianness macros are defined. This is a bug of endian " "detection. Please report it via a github issue."); #endif #endif // ENDIAN_DETECTION_H qtrvsim-0.9.8/src/common/polyfills/mulh64.h000066400000000000000000000105521467752164200206420ustar00rootroot00000000000000/** * Provides set of functions to calculate high bits of 64 bit multiplication. * Naming reflects RISC-V specs. * * `mulh64` = signed x signed * `mulhu64` = unsigned x unsigned * `mulhsu64` = signed x unsigned * * @file */ #ifndef MULH64_H #define MULH64_H #include /** * Get high bits of 64 bit unsigned multiplication. * * Source (BSD-3 in the referred project): * https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication */ static inline constexpr uint64_t mulhu64_fallback(uint64_t a, uint64_t b) { const uint64_t a_lower = (uint32_t)a; const uint64_t a_upper = (uint32_t)(a >> 32); const uint64_t b_lower = (uint32_t)b; const uint64_t b_upper = (uint32_t)(b >> 32); const uint64_t p11 = a_upper * b_upper, p01 = a_lower * b_upper; const uint64_t p10 = a_upper * b_lower, p00 = a_lower * b_lower; /* This is implementing schoolbook multiplication: x1 x0 X y1 y0 ------------- 00 LOW PART ------------- 00 10 10 MIDDLE PART + 01 ------------- 01 + 11 11 HIGH PART ------------- */ const uint64_t middle = p10 + (p00 >> 32) + (uint32_t)p01; return p11 + (middle >> 32) + (p01 >> 32); } /** * mulhu64_fallback modified for signed multiplication * * SIGN marks show where sign extension has been added. * `*_upper` variables are considered signed and everything multiplied with them * is also signed. * * We use the fact, that in most compilers right shift of signed value is done * by arithmetic shift. */ static inline constexpr uint64_t mulh64_fallback(int64_t a, int64_t b) { const uint64_t a_lower = (uint32_t)a; const int64_t a_upper = (int32_t)(a >> 32); // SIGN const uint64_t b_lower = (uint32_t)b; const int64_t b_upper = (int32_t)(b >> 32); // SIGN const int64_t p11 = a_upper * b_upper; const int64_t p01 = a_lower * b_upper; const int64_t p10 = a_upper * b_lower; const uint64_t p00 = a_lower * b_lower; const int64_t middle = p10 + (p00 >> 32) + (uint32_t)p01; return p11 + (middle >> 32) + (p01 >> 32); // SIGN } /** * mulh64_fallback modified for mixed sign multiplication * * SIGN marks show where sign extension has been added. * `a_upper` is considered signed and everything multiplied with it is also * signed. * * We use the fact, that in most compilers right shift of signed value is done * by arithmetic shift. */ static inline constexpr uint64_t mulhsu64_fallback(int64_t a, uint64_t b) { const uint64_t a_lower = (uint32_t)a; const int64_t a_upper = (int32_t)(a >> 32); // SIGN const uint64_t b_lower = (uint32_t)b; const uint64_t b_upper = (uint32_t)(b >> 32); const int64_t p11 = a_upper * b_upper; const uint64_t p01 = a_lower * b_upper; const int64_t p10 = a_upper * b_lower; const uint64_t p00 = a_lower * b_lower; const int64_t middle = p10 + (p00 >> 32) + (uint32_t)p01; return p11 + (middle >> 32) + (p01 >> 32); // SIGN } #if defined(__SIZEOF_INT128__) // GNU C static inline constexpr uint64_t mulh64(int64_t a, int64_t b) { unsigned __int128 prod = (unsigned __int128)a * (unsigned __int128)b; return (uint64_t)(prod >> 64); } static inline constexpr uint64_t mulhu64(uint64_t a, uint64_t b) { unsigned __int128 prod = (unsigned __int128)a * (unsigned __int128)b; return (uint64_t)(prod >> 64); } static inline constexpr uint64_t mulhsu64(int64_t a, uint64_t b) { unsigned __int128 prod = (unsigned __int128)a * (unsigned __int128)b; return (uint64_t)(prod >> 64); } #elif defined(_M_X64) || defined(_M_ARM64) // MSVC // MSVC for x86-64 or AArch64 // possibly also || defined(_M_IA64) || defined(_WIN64) // but the docs only guarantee x86-64! Don't use *just* _WIN64; it doesn't // include AArch64 Android / Linux // https://docs.microsoft.com/en-gb/cpp/intrinsics/arm64-intrinsics #include // https://docs.microsoft.com/en-gb/cpp/intrinsics/umulh #define mulhu64 __umulh // https://docs.microsoft.com/en-gb/cpp/intrinsics/mulh #define mulh64 __mulh // Not provided by MVSC #define mulhsu64 mulhsu64_fallback #else #define mulh64 mulh64_fallback #define mulhu64 mulhu64_fallback #define mulhsu64 mulhsu64_fallback #endif #endif // MULH64_H qtrvsim-0.9.8/src/common/polyfills/mulh64.test.cpp000066400000000000000000000032711467752164200221530ustar00rootroot00000000000000#include "mulh64.h" #include "mulh64.test.h" void TestMULH64::test_mulh64() { QCOMPARE(mulh64(15, 10), (uint64_t)0); QCOMPARE(mulh64(15, -10), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulh64(-10, 15), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulh64(-15, -10), (uint64_t)0); } void TestMULH64::test_mulhu64() { QCOMPARE(mulhu64(15, 10), (uint64_t)0); QCOMPARE(mulhu64(15, -10), (uint64_t)14); QCOMPARE(mulhu64(-10, 15), (uint64_t)14); QCOMPARE(mulhu64(-10, -15), (uint64_t)0xffffffffffffffe7ULL); } void TestMULH64::test_mulhsu64() { QCOMPARE(mulhsu64(15, 10), (uint64_t)0); QCOMPARE(mulhsu64(15, -10), (uint64_t)14); QCOMPARE(mulhsu64(-10, 15), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulhsu64(-15, -10), (uint64_t)0xfffffffffffffff1ULL); } void TestMULH64::test_mulh64_fallback() { QCOMPARE(mulh64_fallback(15, 10), (uint64_t)0); QCOMPARE(mulh64_fallback(15, -10), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulh64_fallback(-10, 15), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulh64_fallback(-15, -10), (uint64_t)0); } void TestMULH64::test_mulhu64_fallback() { QCOMPARE(mulhu64_fallback(15, 10), (uint64_t)0); QCOMPARE(mulhu64_fallback(15, -10), (uint64_t)14); QCOMPARE(mulhu64_fallback(-10, 15), (uint64_t)14); QCOMPARE(mulhu64_fallback(-10, -15), (uint64_t)0xffffffffffffffe7ULL); } void TestMULH64::test_mulhsu64_fallback() { QCOMPARE(mulhsu64_fallback(15, 10), (uint64_t)0); QCOMPARE(mulhsu64_fallback(15, -10), (uint64_t)14); QCOMPARE(mulhsu64_fallback(-10, 15), (uint64_t)0xffffffffffffffffULL); QCOMPARE(mulhsu64_fallback(-15, -10), (uint64_t)0xfffffffffffffff1ULL); } QTEST_APPLESS_MAIN(TestMULH64) qtrvsim-0.9.8/src/common/polyfills/mulh64.test.h000066400000000000000000000006201467752164200216130ustar00rootroot00000000000000#ifndef MULH64_TEST_H #define MULH64_TEST_H #include #include class TestMULH64 : public QObject { Q_OBJECT private slots: static void test_mulh64(); static void test_mulhu64(); static void test_mulhsu64(); static void test_mulh64_fallback(); static void test_mulhu64_fallback(); static void test_mulhsu64_fallback(); }; #endif // MULH64_TEST_H qtrvsim-0.9.8/src/common/polyfills/qstring_hash.h000066400000000000000000000012341467752164200222120ustar00rootroot00000000000000#ifndef QTRVSIM_QSTRING_HASH_H #define QTRVSIM_QSTRING_HASH_H #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) namespace std { template<> struct hash { std::size_t operator()(const QString &s) const noexcept { return qHash(s); } }; #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) template<> struct hash { std::size_t operator()(const QStringView &s) const noexcept { return qHash(s); } }; #endif } // namespace std #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // Supported since Qt5.10 using QStringView = QString; #endif #endif #endif // QTRVSIM_QSTRING_HASH_H qtrvsim-0.9.8/src/common/polyfills/qt5/000077500000000000000000000000001467752164200200605ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/polyfills/qt5/qfontmetrics.h000066400000000000000000000005171467752164200227520ustar00rootroot00000000000000#ifndef POLYFILLS_QFONTMETRICS_H #define POLYFILLS_QFONTMETRICS_H int QFontMetrics_horizontalAdvance(const QFontMetrics &self, const QString &str, int len = -1) { #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) return self.horizontalAdvance(str, len); #else return self.width(str, len); #endif } #endif // QTMIPS_QFONTMETRICS_H qtrvsim-0.9.8/src/common/polyfills/qt5/qlinef.h000066400000000000000000000005521467752164200215110ustar00rootroot00000000000000#ifndef POLYFILLS_QLINEF_H #define POLYFILLS_QLINEF_H #include QLineF::IntersectType QLineF_intersect(const QLineF &l1, const QLineF &l2, QPointF *intersectionPoint) { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) return l1.intersects(l2, intersectionPoint); #else return l1.intersect(l2, intersectionPoint); #endif } #endif // QTMIPS_QLINEF_H qtrvsim-0.9.8/src/common/polyfills/qt5/qtableview.h000066400000000000000000000010301467752164200223660ustar00rootroot00000000000000#ifndef POLYFILLS_QTABLEVIEW_H #define POLYFILLS_QTABLEVIEW_H #include /** * QTableView polyfill * * initViewItemOption is protected, therefore the whole class needs to be wrapped. */ class Poly_QTableView : public QTableView { public: explicit Poly_QTableView(QWidget *parent) : QTableView(parent) {} #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) protected: void initViewItemOption(QStyleOptionViewItem *viewOpts) { *viewOpts = QTableView::viewOptions(); } #endif }; #endif // QTMIPS_QTABLEVIEW_H qtrvsim-0.9.8/src/common/string_utils.h000066400000000000000000000005301467752164200202270ustar00rootroot00000000000000#ifndef QTRVSIM_STRING_UTILS_H #define QTRVSIM_STRING_UTILS_H #include namespace str { template QString asHex(T number) { if (number < 0) { return QString::asprintf("-0x%x", -number); } else { return QString::asprintf("0x%x", number); } } } // namespace str #endif // QTRVSIM_STRING_UTILS_H qtrvsim-0.9.8/src/common/type_utils/000077500000000000000000000000001467752164200175335ustar00rootroot00000000000000qtrvsim-0.9.8/src/common/type_utils/lens.h000066400000000000000000000032131467752164200206440ustar00rootroot00000000000000/** * Tiny lenses library * * TL;DR: Getter function which works on nested structs. * * Example: * ``` * struct A { * int b, * struct { * int d; * } c; * } * * Lens lens = LENS(A, c.d); * ``` * `Lens` is a function pointer to a function with a signature * `const A& -> const int&` * int`, i.e., it takes a reference to an instance of type A and "shows" you * something somewhere inside the object -- the integer `d`. * * In functional programming, the term lens is used and a generalized and * more flexible form of getter method. First, it is a function. Second, it * works on arbitrarily nested structures and it hides the inner structure. * * @file */ #ifndef QTRVSIM_LENS_H #define QTRVSIM_LENS_H template using Lens = const FIELD_TYPE &(*const)(const BASE &); #define LENS(BASE_TYPE, MEMBER) \ ([](const BASE_TYPE &base) -> const auto & { \ return base.MEMBER; \ }) template using LensPair = std::pair (*const)(const BASE &); #define LENS_PAIR(BASE_TYPE, MEMBER_A, MEMBER_B) \ [](const BASE_TYPE &base) -> std::pair { \ return { base.MEMBER_A, base.MEMBER_B }; \ } #endif // QTRVSIM_LENS_H qtrvsim-0.9.8/src/gui/000077500000000000000000000000001467752164200146265ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/CMakeLists.txt000066400000000000000000000140641467752164200173730ustar00rootroot00000000000000project(gui LANGUAGES C CXX VERSION ${MAIN_PROJECT_VERSION} DESCRIPTION "Graphical UI for the simulator") set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) set(gui_SOURCES dialogs/about/aboutdialog.cpp windows/cache/cachedock.cpp windows/cache/cacheview.cpp windows/csr/csrdock.cpp windows/coreview/scene.cpp extprocess.cpp fontsize.cpp dialogs/gotosymbol/gotosymboldialog.cpp graphicsview.cpp windows/memory/memorydock.cpp windows/memory/memorymodel.cpp windows/memory/memorytableview.cpp windows/messages/messagesdock.cpp windows/messages/messagesmodel.cpp windows/messages/messagesview.cpp dialogs/new/newdialog.cpp ui/hexlineedit.cpp windows/editor/highlighterasm.cpp windows/editor/highlighterc.cpp windows/editor/linenumberarea.cpp windows/editor/editordock.cpp windows/editor/editortab.cpp hinttabledelegate.cpp windows/lcd/lcddisplaydock.cpp windows/lcd/lcddisplayview.cpp main.cpp mainwindow/mainwindow.cpp windows/peripherals/peripheralsdock.cpp windows/peripherals/peripheralsview.cpp windows/program/programdock.cpp windows/program/programmodel.cpp windows/program/programtableview.cpp windows/registers/registersdock.cpp dialogs/savechanged/savechangeddialog.cpp windows/editor/srceditor.cpp statictable.cpp windows/terminal/terminaldock.cpp textsignalaction.cpp windows/coreview/components/value_handlers.cpp windows/coreview/components/cache.cpp widgets/hidingtabwidget.cpp windows/predictor/predictor_btb_dock.cpp windows/predictor/predictor_bht_dock.cpp windows/predictor/predictor_info_dock.cpp ) set(gui_HEADERS dialogs/about/aboutdialog.h windows/cache/cachedock.h windows/cache/cacheview.h windows/csr/csrdock.h windows/coreview/scene.h extprocess.h fontsize.h dialogs/gotosymbol/gotosymboldialog.h graphicsview.h windows/memory/memorydock.h windows/memory/memorymodel.h windows/memory/memorytableview.h windows/messages/messagesdock.h windows/messages/messagesmodel.h windows/messages/messagesview.h dialogs/new/newdialog.h ui/hexlineedit.h windows/editor/highlighterasm.h windows/editor/highlighterc.h windows/editor/linenumberarea.h windows/editor/editordock.h hinttabledelegate.h windows/lcd/lcddisplaydock.h windows/lcd/lcddisplayview.h mainwindow/mainwindow.h windows/peripherals/peripheralsdock.h windows/peripherals/peripheralsview.h windows/program/programdock.h windows/program/programmodel.h windows/program/programtableview.h windows/registers/registersdock.h dialogs/savechanged/savechangeddialog.h windows/editor/srceditor.h statictable.h windows/terminal/terminaldock.h textsignalaction.h windows/coreview/components/value_handlers.h windows/coreview/data.h windows/coreview/components/cache.h helper/async_modal.h widgets/hidingtabwidget.h windows/predictor/predictor_btb_dock.h windows/predictor/predictor_bht_dock.h windows/predictor/predictor_info_dock.h ) set(gui_UI dialogs/gotosymbol/gotosymboldialog.ui dialogs/new/NewDialog.ui windows/peripherals/peripheralsview.ui mainwindow/MainWindow.ui dialogs/new/NewDialogCache.ui ) set(gui_RESOURCES resources/icons/icons.qrc resources/samples/samples.qrc windows/coreview/schemas/schemas.qrc ) if ("${WASM}") message(STATUS "gui :: Including WASM only files.") list(APPEND gui_SOURCES qhtml5file_html5.cpp) list(APPEND gui_HEADERS qhtml5file.h) endif () # MACOS set(ICON_NAME gui) set(ICON_PATH ${CMAKE_SOURCE_DIR}/data/icons/macos/${ICON_NAME}.icns) # END MACOS add_executable(gui ${ICON_PATH} ${gui_SOURCES} ${gui_HEADERS} ${gui_UI} ${gui_RESOURCES}) target_include_directories(gui PUBLIC . windows/coreview) target_link_libraries(gui PRIVATE ${QtLib}::Core ${QtLib}::Widgets ${QtLib}::Gui PRIVATE machine os_emulation assembler svgscene) target_compile_definitions(gui PRIVATE APP_ORGANIZATION=\"${MAIN_PROJECT_ORGANIZATION}\" APP_ORGANIZATION_DOMAIN=\"${MAIN_PROJECT_HOMEPAGE_URL}\" APP_GIT=\"${MAIN_PROJECT_HOMEPAGE_URL}\" APP_NAME=\"${MAIN_PROJECT_NAME}\" APP_VERSION=\"${MAIN_PROJECT_VERSION}\" ENV_CONFIG_FILE_NAME=\"${MAIN_PROJECT_NAME_UPPER}_CONFIG_FILE\") set_target_properties(gui PROPERTIES OUTPUT_NAME "${MAIN_PROJECT_NAME_LOWER}_${PROJECT_NAME}") if (${${QtLib}PrintSupport_FOUND} AND NOT ${WASM}) target_link_libraries(gui PRIVATE ${QtLib}::PrintSupport) target_compile_definitions(gui PRIVATE WITH_PRINTING=1) endif () # MACOS set_property(SOURCE ${ICON_PATH} PROPERTY MACOSX_PACKAGE_LOCATION Resources) set_target_properties(gui PROPERTIES MACOSX_BUNDLE true MACOSX_BUNDLE_GUI_IDENTIFIER cz.cvut.fel.${MAIN_PROJECT_ORGANIZATION}.gui MACOSX_BUNDLE_BUNDLE_NAME ${MAIN_PROJECT_NAME} MACOSX_BUNDLE_BUNDLE_VERSION "${MAIN_PROJECT_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${MAIN_PROJECT_VERSION}" MACOSX_BUNDLE_ICONFILE ${ICON_NAME} ) # END MACOS # ============================================================================= # Installation # ============================================================================= # Prior to CMake version 3.13, installation must be performed in the subdirectory, # there the target was created. Therefore executable installation is to be found # in corresponding CMakeLists.txt. install(TARGETS gui RUNTIME DESTINATION bin BUNDLE DESTINATION ${EXECUTABLE_OUTPUT_PATH} ) qtrvsim-0.9.8/src/gui/dialogs/000077500000000000000000000000001467752164200162505ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/dialogs/about/000077500000000000000000000000001467752164200173625ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/dialogs/about/aboutdialog.cpp000066400000000000000000000054451467752164200223700ustar00rootroot00000000000000#include "aboutdialog.h" #include "project_info.h" #include #include #include #include #include #include #include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) { QLabel *lbl; setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_ShowModal); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setWindowTitle(tr("About " APP_NAME)); all = new QVBoxLayout(this); auto *hbox = new QWidget(); auto *hl = new QHBoxLayout(hbox); hl->setContentsMargins(0, 0, 0, 0); all->addWidget(hbox); auto *vbox = new QWidget(); auto *vl = new QVBoxLayout(vbox); hl->addWidget(vbox); QString versionText; versionText = "Version " APP_VERSION "\n"; vl->addWidget(new QLabel("" APP_NAME " " "- RISC-V Architecture Simulator")); lbl = new QLabel(versionText); lbl->setAlignment(Qt::AlignHCenter); lbl->setOpenExternalLinks(true); vl->addWidget(lbl); vl->addWidget(new QLabel(COPYRIGHT_HTML)); QString supportText; supportText = "Home Page : " APP_GIT "
" "Implemented for Computer Architectures and Advanced Computer Architectures courses " "at Czech Technical " "University in Prague" " Faculty of Electrical " "Engineering
" "QtRvSim on-line version and links to course materials at
" "https://comparch.edu.cvut.cz/
"; auto *supportBrowser = new QTextBrowser; supportBrowser->setOpenExternalLinks(true); supportBrowser->setHtml(supportText); vl->addWidget(supportBrowser); auto *licenseBrowser = new QTextBrowser; licenseBrowser->setOpenExternalLinks(true); licenseBrowser->setHtml(LICENCE_HTML); vl->addWidget(licenseBrowser); auto *hbBtn = new QWidget(); auto *hlBtn = new QHBoxLayout(hbBtn); hlBtn->setContentsMargins(0, 0, 0, 0); vl->addWidget(hbBtn); auto *okButton = new QPushButton(tr("&OK"), parent); okButton->setFocus(); connect(okButton, &QAbstractButton::clicked, this, &QWidget::close); hlBtn->addStretch(); hlBtn->addWidget(okButton); setMinimumSize(480, 500); // the first Tab is selected by default } qtrvsim-0.9.8/src/gui/dialogs/about/aboutdialog.h000066400000000000000000000004721467752164200220300ustar00rootroot00000000000000#ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include #include #include #include class QString; class QTextBrowser; class AboutDialog : public QDialog { Q_OBJECT public: explicit AboutDialog(QWidget *parent = nullptr); private: QVBoxLayout *all; }; #endif qtrvsim-0.9.8/src/gui/dialogs/gotosymbol/000077500000000000000000000000001467752164200204465ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/dialogs/gotosymbol/gotosymboldialog.cpp000066400000000000000000000017401467752164200245320ustar00rootroot00000000000000#include "gotosymboldialog.h" #include "ui_gotosymboldialog.h" GoToSymbolDialog::GoToSymbolDialog( QWidget *parent, const QStringList &symbol_names) : QDialog(parent) , ui(new Ui::GoToSymbolDialog) { ui->setupUi(this); connect( ui->pushShowProg, &QAbstractButton::clicked, this, &GoToSymbolDialog::show_prog); connect( ui->pushShowMem, &QAbstractButton::clicked, this, &GoToSymbolDialog::show_mem); connect(ui->pushClose, &QAbstractButton::clicked, this, &QWidget::close); ui->listSymbols->addItems(symbol_names); } void GoToSymbolDialog::show_prog() { uint64_t address = 0; emit obtain_value_for_name(address, ui->listSymbols->currentItem()->text()); emit program_focus_addr(machine::Address(address)); } void GoToSymbolDialog::show_mem() { uint64_t address = 0; emit obtain_value_for_name(address, ui->listSymbols->currentItem()->text()); emit memory_focus_addr(machine::Address(address)); } qtrvsim-0.9.8/src/gui/dialogs/gotosymbol/gotosymboldialog.h000066400000000000000000000012411467752164200241730ustar00rootroot00000000000000#ifndef GOTOSYMBOLDIALOG_H #define GOTOSYMBOLDIALOG_H #include "common/memory_ownership.h" #include "machine/memory/address.h" #include "ui_gotosymboldialog.h" #include #include #include class GoToSymbolDialog : public QDialog { Q_OBJECT public: GoToSymbolDialog(QWidget *parent, const QStringList &symbol_names); signals: void program_focus_addr(machine::Address); void memory_focus_addr(machine::Address); bool obtain_value_for_name(uint64_t &value, const QString &name) const; public slots: void show_prog(); void show_mem(); private: Box ui {}; }; #endif // GOTOSYMBOLDIALOG_H qtrvsim-0.9.8/src/gui/dialogs/gotosymbol/gotosymboldialog.ui000066400000000000000000000043671467752164200243750ustar00rootroot00000000000000 GoToSymbolDialog 0 0 400 331 Go To Symbol DIalog QLayout::SetMaximumSize Show program Qt::Horizontal 40 20 Show memory Qt::Horizontal 40 20 Close listSymbols pushShowProg pushShowMem pushClose qtrvsim-0.9.8/src/gui/dialogs/new/000077500000000000000000000000001467752164200170415ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/dialogs/new/NewDialog.ui000066400000000000000000001024351467752164200212560ustar00rootroot00000000000000 NewDialog 0 0 745 472 Dialog true 0 0 0 135 0 Config Pages 0 0 4 0 Page Name Presets and ELF File Preset No pipeline no cache No pipeline with cache Pipelined without hazard unit and without cache Pipelined with hazard unit and cache Custom Reset at compile time (reload after make) Qt::Vertical 20 40 Qt::Horizontal Elf executable: Browse Core ISA and Hazards Pipelined XLEN 64-bit Atomic (A) Delay slot Multiply (M) Hazard unit true false Stall when hazard is detected Stall or forward when hazard is detected true Qt::Vertical 20 40 Branch Predictor Branch Predictor true true 0 Predictor type: 0 Initial state: Branch Target Buffer (BTB) false Qt::Horizontal 40 0 0 Qt::AlignCenter PC - Program Counter register Bits from PC address: 8 Qt::Horizontal false QSlider::TicksBothSides 140 0 Number of entries: 40 0 1 Qt::AlignCenter Qt::Horizontal 40 20 Qt::Vertical 140 0 Number of bits: 40 0 0 Qt::AlignCenter Branch History Table (BHT) 40 0 0 Qt::AlignCenter 40 0 0 Qt::AlignCenter 8 Qt::Horizontal QSlider::TicksBothSides 8 Qt::Horizontal QSlider::TicksBothSides 140 0 BHR - Branch History Register Bits in BHR: Qt::Horizontal 140 0 PC - Program Counter register Bits from PC address: 140 0 Number of entries: 40 0 1 Qt::AlignCenter Qt::Horizontal 40 20 Qt::Vertical 140 0 Number of bits: 40 0 0 Qt::AlignCenter Qt::Vertical 20 40 Memory Timings Program memory write protection Data memory executable protection Access time (in cycles) Read: 1 999999999 Write: 1 999999999 Burst enable: false Burst: 0 999999999 L2 Access: 0 999999999 Qt::Vertical 20 40 L1 Program Cache L1 Data Cache L2 Cache System Emulation and IRQ Enable emulation of operating system services true Stop on known system call true Stop on unknown system call true Stop on interrupt entry true Stop and step over exceptions (overflow, etc.) true Filesystem root: Browse Qt::Vertical 21 40 9 0 9 0 Qt::Horizontal 40 20 Example Start empty Load machine true Cancel qtrvsim-0.9.8/src/gui/dialogs/new/NewDialogCache.ui000066400000000000000000000075671467752164200222140ustar00rootroot00000000000000 NewDialogCache 0 0 435 204 Form Enable cache true Number of sets: 1 1024 Block size: 1 Degree of associativity: 1 Replacement policy: Random Least Recently Used (LRU) Least Frequently Used (LFU) Pseudo Least Recently Used (PLRU) Writeback policy: Write through - noallocate Write through - write allocate Write back Qt::Vertical 20 40 qtrvsim-0.9.8/src/gui/dialogs/new/newdialog.cpp000066400000000000000000000666521467752164200215350ustar00rootroot00000000000000#include "newdialog.h" #include "helper/async_modal.h" #include "machine/simulator_exception.h" #include "mainwindow/mainwindow.h" #include #ifdef __EMSCRIPTEN__ #include "qhtml5file.h" #include #endif NewDialog::NewDialog(QWidget *parent, QSettings *settings) : QDialog(parent) { setWindowTitle("New machine"); this->settings = settings; config.reset(); ui.reset(new Ui::NewDialog()); ui->setupUi(this); ui_cache_p.reset(new Ui::NewDialogCache()); ui_cache_p->setupUi(ui->tab_cache_program); ui_cache_p->writeback_policy->hide(); ui_cache_p->label_writeback->hide(); ui_cache_d.reset(new Ui::NewDialogCache()); ui_cache_d->setupUi(ui->tab_cache_data); ui_cache_l2.reset(new Ui::NewDialogCache()); ui_cache_l2->setupUi(ui->tab_cache_level2); QList config_pages_items; for (int i = 0; i < ui->config_pages->count(); ++i) { QString page_id = ui->config_pages->widget(i)->objectName(); QString page_name = ui->config_pages->widget(i)->accessibleName(); config_pages_items.append(new QTreeWidgetItem(static_cast(nullptr), QStringList{page_name, page_id})); } ui->page_select_tree->insertTopLevelItems(0, config_pages_items); connect( ui->page_select_tree, &QTreeWidget::currentItemChanged, this, &NewDialog::switch2page); connect( ui->pushButton_example, &QAbstractButton::clicked, this, &NewDialog::create_example); connect( ui->pushButton_start_empty, &QAbstractButton::clicked, this, &NewDialog::create_empty); connect( ui->pushButton_load, &QAbstractButton::clicked, this, &NewDialog::create); connect( ui->pushButton_cancel, &QAbstractButton::clicked, this, &NewDialog::cancel); connect( ui->pushButton_browse, &QAbstractButton::clicked, this, &NewDialog::browse_elf); connect( ui->elf_file, &QLineEdit::textChanged, this, &NewDialog::elf_change); connect( ui->preset_no_pipeline, &QAbstractButton::toggled, this, &NewDialog::set_preset); connect( ui->preset_no_pipeline_cache, &QAbstractButton::toggled, this, &NewDialog::set_preset); connect( ui->preset_pipelined_bare, &QAbstractButton::toggled, this, &NewDialog::set_preset); connect( ui->preset_pipelined, &QAbstractButton::toggled, this, &NewDialog::set_preset); connect( ui->reset_at_compile, &QAbstractButton::clicked, this, &NewDialog::reset_at_compile_change); connect( ui->xlen_64bit, &QAbstractButton::clicked, this, &NewDialog::xlen_64bit_change); connect( ui->isa_atomic, &QAbstractButton::clicked, this, &NewDialog::isa_atomic_change); connect( ui->isa_multiply, &QAbstractButton::clicked, this, &NewDialog::isa_multiply_change); connect( ui->pipelined, &QAbstractButton::clicked, this, &NewDialog::pipelined_change); connect( ui->delay_slot, &QAbstractButton::clicked, this, &NewDialog::delay_slot_change); connect( ui->hazard_unit, &QGroupBox::clicked, this, &NewDialog::hazard_unit_change); connect( ui->hazard_stall, &QAbstractButton::clicked, this, &NewDialog::hazard_unit_change); connect( ui->hazard_stall_forward, &QAbstractButton::clicked, this, &NewDialog::hazard_unit_change); connect( ui->mem_protec_exec, &QAbstractButton::clicked, this, &NewDialog::mem_protec_exec_change); connect( ui->mem_protec_write, &QAbstractButton::clicked, this, &NewDialog::mem_protec_write_change); connect( ui->mem_time_read, QOverload::of(&QSpinBox::valueChanged), this, &NewDialog::mem_time_read_change); connect( ui->mem_time_write, QOverload::of(&QSpinBox::valueChanged), this, &NewDialog::mem_time_write_change); connect( ui->mem_enable_burst, &QAbstractButton::clicked, this, &NewDialog::mem_enable_burst_change); connect( ui->mem_time_burst, QOverload::of(&QSpinBox::valueChanged), this, &NewDialog::mem_time_burst_change); connect( ui->mem_time_level2, QOverload::of(&QSpinBox::valueChanged), this, &NewDialog::mem_time_level2_change); connect( ui->osemu_enable, &QAbstractButton::clicked, this, &NewDialog::osemu_enable_change); connect( ui->osemu_known_syscall_stop, &QAbstractButton::clicked, this, &NewDialog::osemu_known_syscall_stop_change); connect( ui->osemu_unknown_syscall_stop, &QAbstractButton::clicked, this, &NewDialog::osemu_unknown_syscall_stop_change); connect( ui->osemu_interrupt_stop, &QAbstractButton::clicked, this, &NewDialog::osemu_interrupt_stop_change); connect( ui->osemu_exception_stop, &QAbstractButton::clicked, this, &NewDialog::osemu_exception_stop_change); connect( ui->osemu_fs_root_browse, &QAbstractButton::clicked, this, &NewDialog::browse_osemu_fs_root); connect(ui->osemu_fs_root, &QLineEdit::textChanged, this, &NewDialog::osemu_fs_root_change); // Branch predictor connect( ui->group_bp, QOverload::of(&QGroupBox::toggled), this, &NewDialog::bp_enabled_change); connect( ui->select_bp_type, QOverload::of(&QComboBox::activated), this, &NewDialog::bp_type_change); connect( ui->select_bp_init_state, QOverload::of(&QComboBox::activated), this, &NewDialog::bp_init_state_change); connect( ui->slider_bp_btb_addr_bits, &QAbstractSlider::valueChanged, this, &NewDialog::bp_btb_addr_bits_change); connect( ui->slider_bp_bht_bhr_bits, &QAbstractSlider::valueChanged, this, &NewDialog::bp_bht_bhr_bits_change); connect(ui->slider_bp_bht_addr_bits, &QAbstractSlider::valueChanged, this, &NewDialog::bp_bht_addr_bits_change); cache_handler_d = new NewDialogCacheHandler(this, ui_cache_d.data()); cache_handler_p = new NewDialogCacheHandler(this, ui_cache_p.data()); cache_handler_l2 = new NewDialogCacheHandler(this, ui_cache_l2.data()); // TODO remove this block when protections are implemented ui->mem_protec_exec->setVisible(false); ui->mem_protec_write->setVisible(false); load_settings(); // Also configures gui ui->config_page_title->setStyleSheet("font-weight: bold"); switch2page(config_pages_items.at(0)); } void NewDialog::switch2page(QTreeWidgetItem *current, QTreeWidgetItem *previous) { (void)previous; QWidget *page = ui->config_pages->findChild(current->text(1), Qt::FindDirectChildrenOnly); if (page != nullptr) { ui->config_pages->setCurrentWidget(page); ui->config_page_title->setText(current->text(0)); } } void NewDialog::switch2custom() { if (!ui->preset_custom->isChecked()) { ui->preset_custom->setChecked(true); config_gui(); } } void NewDialog::closeEvent(QCloseEvent *) { load_settings(); // Reset from settings // Close the main window if not already configured auto *prnt = (MainWindow *)parent(); if (!prnt->configured()) { prnt->close(); } } void NewDialog::cancel() { this->close(); } void NewDialog::create() { auto *p_window = (MainWindow *)parent(); try { p_window->create_core(*config, true, false); } catch (const machine::SimulatorExceptionInput &e) { showAsyncCriticalBox( this, "Error while initializing new machine", e.msg(false), e.msg(true), "Please check that ELF executable really exists and is in correct format."); return; } store_settings(); // Save to settings this->close(); } void NewDialog::create_empty() { auto *p_window = (MainWindow *)parent(); p_window->create_core(*config, false, true); store_settings(); // Save to settings this->close(); } void NewDialog::create_example() { auto *p_window = (MainWindow *)parent(); QString example(":/samples/template.S"); p_window->create_core(*config, false, true); store_settings(); // Save to settings p_window->close_source_by_name(example, false); p_window->example_source(example); p_window->show_program(); p_window->compile_source(); this->close(); } void NewDialog::browse_elf() { #ifndef __EMSCRIPTEN__ QFileDialog elf_dialog(this); elf_dialog.setFileMode(QFileDialog::ExistingFile); if (elf_dialog.exec()) { QString path = elf_dialog.selectedFiles()[0]; ui->elf_file->setText(path); config->set_elf(path); } // Elf shouldn't have any other effect, so we skip config_gui here #else QHtml5File::load("*", [&](const QByteArray &content, const QString &fileName) { QFileInfo fi(fileName); QString elf_name = fi.fileName(); QFile file(elf_name); file.open(QIODevice::WriteOnly | QIODevice::Truncate); file.write(content); file.close(); ui->elf_file->setText(elf_name); config->set_elf(elf_name); }); #endif } void NewDialog::elf_change(QString val) { config->set_elf(std::move(val)); } void NewDialog::set_preset() { unsigned pres_n = preset_number(); if (pres_n > 0) { config->preset((enum machine::ConfigPresets)(pres_n - 1)); config_gui(); } } void NewDialog::xlen_64bit_change(bool val) { if (val) config->set_simulated_xlen(machine::Xlen::_64); else config->set_simulated_xlen(machine::Xlen::_32); switch2custom(); } void NewDialog::isa_atomic_change(bool val) { auto isa_mask = machine::ConfigIsaWord::byChar('A'); if (val) config->modify_isa_word(isa_mask, isa_mask); else config->modify_isa_word(isa_mask, machine::ConfigIsaWord::empty()); switch2custom(); } void NewDialog::isa_multiply_change(bool val) { auto isa_mask = machine::ConfigIsaWord::byChar('M'); if (val) config->modify_isa_word(isa_mask, isa_mask); else config->modify_isa_word(isa_mask, machine::ConfigIsaWord::empty()); switch2custom(); } void NewDialog::pipelined_change(bool val) { config->set_pipelined(val); ui->hazard_unit->setEnabled(config->pipelined()); switch2custom(); } void NewDialog::delay_slot_change(bool val) { config->set_delay_slot(val); switch2custom(); } void NewDialog::hazard_unit_change() { if (ui->hazard_unit->isChecked()) { config->set_hazard_unit( ui->hazard_stall->isChecked() ? machine::MachineConfig::HU_STALL : machine::MachineConfig::HU_STALL_FORWARD); } else { config->set_hazard_unit(machine::MachineConfig::HU_NONE); } switch2custom(); } void NewDialog::mem_protec_exec_change(bool v) { config->set_memory_execute_protection(v); switch2custom(); } void NewDialog::mem_protec_write_change(bool v) { config->set_memory_write_protection(v); switch2custom(); } void NewDialog::mem_time_read_change(int v) { if (config->memory_access_time_read() != (unsigned)v) { config->set_memory_access_time_read(v); switch2custom(); } } void NewDialog::mem_time_write_change(int v) { if (config->memory_access_time_write() != (unsigned)v) { config->set_memory_access_time_write(v); switch2custom(); } } void NewDialog::mem_enable_burst_change(bool v) { if (config->memory_access_enable_burst() != v) { config->set_memory_access_enable_burst(v); switch2custom(); } } void NewDialog::mem_time_burst_change(int v) { if (config->memory_access_time_burst() != (unsigned)v) { config->set_memory_access_time_burst(v); switch2custom(); } } void NewDialog::mem_time_level2_change(int v) { if (config->memory_access_time_level2() != (unsigned)v) { config->set_memory_access_time_level2(v); switch2custom(); } } void NewDialog::osemu_enable_change(bool v) { config->set_osemu_enable(v); } void NewDialog::osemu_known_syscall_stop_change(bool v) { config->set_osemu_known_syscall_stop(v); } void NewDialog::osemu_unknown_syscall_stop_change(bool v) { config->set_osemu_unknown_syscall_stop(v); } void NewDialog::osemu_interrupt_stop_change(bool v) { config->set_osemu_interrupt_stop(v); } void NewDialog::osemu_exception_stop_change(bool v) { config->set_osemu_exception_stop(v); } void NewDialog::browse_osemu_fs_root() { auto osemu_fs_root_dialog = new QFileDialog(this); osemu_fs_root_dialog->setFileMode(QFileDialog::Directory); osemu_fs_root_dialog->setOption(QFileDialog::ShowDirsOnly, true); QFileDialog::connect(osemu_fs_root_dialog, &QFileDialog::finished, [=](int result) { if (result > 0) { QString path = osemu_fs_root_dialog->selectedFiles()[0]; ui->osemu_fs_root->setText(path); config->set_osemu_fs_root(path); delete osemu_fs_root_dialog; } }); osemu_fs_root_dialog->open(); } void NewDialog::osemu_fs_root_change(QString val) { config->set_osemu_fs_root(std::move(val)); } void NewDialog::reset_at_compile_change(bool v) { config->set_reset_at_compile(v); } void NewDialog::bp_toggle_widgets() { // Enables or disables all branch predictor widgets // depending on the setting const machine::PredictorType predictor_type { config->get_bp_type() }; const bool is_predictor_dynamic { machine::is_predictor_type_dynamic(predictor_type) }; const bool is_predictor_enabled { config->get_bp_enabled() }; ui->group_bp_bht->setEnabled(is_predictor_enabled && is_predictor_dynamic); ui->text_bp_init_state->setEnabled(is_predictor_enabled && is_predictor_dynamic); ui->select_bp_init_state->setEnabled(is_predictor_enabled && is_predictor_dynamic); } void NewDialog::bp_type_change() { // Read branch predictor type from GUI and store it in the config const machine::PredictorType predictor_type { ui->select_bp_type->currentData().value() }; bool need_switch2custom = (config->get_bp_type() != predictor_type); config->set_bp_type(predictor_type); // Remove all items from init state list ui->select_bp_init_state->clear(); // Configure GUI based on predictor selection switch (predictor_type) { case machine::PredictorType::SMITH_1_BIT: { // Add items to the combo box ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::NOT_TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::NOT_TAKEN)); ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::TAKEN)); // Set selected value, or set default if not found const int index { ui->select_bp_init_state->findData( QVariant::fromValue(config->get_bp_init_state())) }; if (index >= 0) { ui->select_bp_init_state->setCurrentIndex(index); } else { ui->select_bp_init_state->setCurrentIndex(ui->select_bp_init_state->findData( QVariant::fromValue(machine::PredictorState::NOT_TAKEN))); config->set_bp_init_state(machine::PredictorState::NOT_TAKEN); } } break; case machine::PredictorType::SMITH_2_BIT: case machine::PredictorType::SMITH_2_BIT_HYSTERESIS: { // Add items to the combo box ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::STRONGLY_NOT_TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::STRONGLY_NOT_TAKEN)); ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::WEAKLY_NOT_TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::WEAKLY_NOT_TAKEN)); ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::WEAKLY_TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::WEAKLY_TAKEN)); ui->select_bp_init_state->addItem( predictor_state_to_string(machine::PredictorState::STRONGLY_TAKEN, false).toString(), QVariant::fromValue(machine::PredictorState::STRONGLY_TAKEN)); // Set selected value, or set default if not found const int index { ui->select_bp_init_state->findData( QVariant::fromValue(config->get_bp_init_state())) }; if (index >= 0) { ui->select_bp_init_state->setCurrentIndex(index); } else { ui->select_bp_init_state->setCurrentIndex(ui->select_bp_init_state->findData( QVariant::fromValue(machine::PredictorState::WEAKLY_NOT_TAKEN))); config->set_bp_init_state(machine::PredictorState::WEAKLY_NOT_TAKEN); } } break; default: break; } bp_toggle_widgets(); if (need_switch2custom) switch2custom(); } void NewDialog::bp_enabled_change(bool v) { if (config->get_bp_enabled() != v) { config->set_bp_enabled(v); bp_toggle_widgets(); switch2custom(); } } void NewDialog::bp_init_state_change(void) { auto v = ui->select_bp_init_state->currentData().value(); if (v != config->get_bp_init_state()) { config->set_bp_init_state(v); switch2custom(); } } void NewDialog::bp_btb_addr_bits_change(int v) { if (config->get_bp_btb_bits() != v) { config->set_bp_btb_bits((uint8_t)v); switch2custom(); } ui->text_bp_btb_addr_bits_number->setText(QString::number(config->get_bp_btb_bits())); ui->text_bp_btb_bits_number->setText(QString::number(config->get_bp_btb_bits())); ui->text_bp_btb_entries_number->setText(QString::number(qPow(2, config->get_bp_btb_bits()))); } void NewDialog::bp_bht_bits_texts_update(void) { ui->text_bp_bht_bhr_bits_number->setText(QString::number(config->get_bp_bhr_bits())); ui->text_bp_bht_addr_bits_number->setText(QString::number(config->get_bp_bht_addr_bits())); ui->text_bp_bht_bits_number->setText(QString::number(config->get_bp_bht_bits())); ui->text_bp_bht_entries_number->setText(QString::number(qPow(2, config->get_bp_bht_bits()))); } void NewDialog::bp_bht_bhr_bits_change(int v) { if (config->get_bp_bhr_bits() != v) { config->set_bp_bhr_bits((uint8_t)v); switch2custom(); } bp_bht_bits_texts_update(); } void NewDialog::bp_bht_addr_bits_change(int v) { if (config->get_bp_bht_addr_bits() != v) { config->set_bp_bht_addr_bits((uint8_t)v); switch2custom(); } bp_bht_bits_texts_update(); } void NewDialog::config_gui() { // Basic ui->elf_file->setText(config->elf()); ui->reset_at_compile->setChecked(config->reset_at_compile()); // Core ui->xlen_64bit->setChecked(config->get_simulated_xlen() == machine::Xlen::_64); ui->isa_multiply->setChecked(config->get_isa_word().contains('M')); ui->isa_atomic->setChecked(config->get_isa_word().contains('A')); ui->pipelined->setChecked(config->pipelined()); ui->delay_slot->setChecked(config->delay_slot()); ui->hazard_unit->setChecked(config->hazard_unit() != machine::MachineConfig::HU_NONE); ui->hazard_stall->setChecked(config->hazard_unit() == machine::MachineConfig::HU_STALL); ui->hazard_stall_forward->setChecked( config->hazard_unit() == machine::MachineConfig::HU_STALL_FORWARD); // Branch predictor ui->group_bp->setChecked(config->get_bp_enabled()); ui->select_bp_type->clear(); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::ALWAYS_NOT_TAKEN).toString(), QVariant::fromValue(machine::PredictorType::ALWAYS_NOT_TAKEN)); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::ALWAYS_TAKEN).toString(), QVariant::fromValue(machine::PredictorType::ALWAYS_TAKEN)); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::BTFNT).toString(), QVariant::fromValue(machine::PredictorType::BTFNT)); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::SMITH_1_BIT).toString(), QVariant::fromValue(machine::PredictorType::SMITH_1_BIT)); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::SMITH_2_BIT).toString(), QVariant::fromValue(machine::PredictorType::SMITH_2_BIT)); ui->select_bp_type->addItem( predictor_type_to_string(machine::PredictorType::SMITH_2_BIT_HYSTERESIS).toString(), QVariant::fromValue(machine::PredictorType::SMITH_2_BIT_HYSTERESIS)); const int index { ui->select_bp_type->findData(QVariant::fromValue(config->get_bp_type())) }; if (index >= 0) { ui->select_bp_type->setCurrentIndex(index); } else { ui->select_bp_type->setCurrentIndex( ui->select_bp_type->findData(QVariant::fromValue(machine::PredictorType::SMITH_1_BIT))); config->set_bp_type(machine::PredictorType::SMITH_1_BIT); } ui->slider_bp_btb_addr_bits->setMaximum(BP_MAX_BTB_BITS); ui->slider_bp_btb_addr_bits->setValue(config->get_bp_btb_bits()); ui->text_bp_btb_addr_bits_number->setText(QString::number(config->get_bp_btb_bits())); ui->text_bp_btb_bits_number->setText(QString::number(config->get_bp_btb_bits())); ui->text_bp_btb_entries_number->setText(QString::number(qPow(2, config->get_bp_btb_bits()))); ui->slider_bp_bht_bhr_bits->setMaximum(BP_MAX_BHR_BITS); ui->slider_bp_bht_bhr_bits->setValue(config->get_bp_bhr_bits()); ui->text_bp_bht_bhr_bits_number->setText(QString::number(config->get_bp_bhr_bits())); ui->slider_bp_bht_addr_bits->setMaximum(BP_MAX_BHT_ADDR_BITS); ui->slider_bp_bht_addr_bits->setValue(config->get_bp_bht_addr_bits()); ui->text_bp_bht_addr_bits_number->setText(QString::number(config->get_bp_bht_addr_bits())); ui->text_bp_bht_bits_number->setText(QString::number(config->get_bp_bht_bits())); ui->text_bp_bht_entries_number->setText(QString::number(qPow(2, config->get_bp_bht_bits()))); bp_type_change(); // Memory ui->mem_protec_exec->setChecked(config->memory_execute_protection()); ui->mem_protec_write->setChecked(config->memory_write_protection()); ui->mem_time_read->setValue((int)config->memory_access_time_read()); ui->mem_time_write->setValue((int)config->memory_access_time_write()); ui->mem_time_burst->setValue((int)config->memory_access_time_burst()); ui->mem_time_level2->setValue((int)config->memory_access_time_level2()); ui->mem_enable_burst->setChecked((int)config->memory_access_enable_burst()); // Cache cache_handler_d->config_gui(); cache_handler_p->config_gui(); cache_handler_l2->config_gui(); // Operating system and exceptions ui->osemu_enable->setChecked(config->osemu_enable()); ui->osemu_known_syscall_stop->setChecked(config->osemu_known_syscall_stop()); ui->osemu_unknown_syscall_stop->setChecked(config->osemu_unknown_syscall_stop()); ui->osemu_interrupt_stop->setChecked(config->osemu_interrupt_stop()); ui->osemu_exception_stop->setChecked(config->osemu_exception_stop()); ui->osemu_fs_root->setText(config->osemu_fs_root()); // Disable various sections according to configuration ui->delay_slot->setEnabled(false); ui->hazard_unit->setEnabled(config->pipelined()); } unsigned NewDialog::preset_number() { enum machine::ConfigPresets preset; if (ui->preset_no_pipeline->isChecked()) preset = machine::CP_SINGLE; else if (ui->preset_no_pipeline_cache->isChecked()) preset = machine::CP_SINGLE_CACHE; else if (ui->preset_pipelined_bare->isChecked()) preset = machine::CP_PIPE_NO_HAZARD; else if (ui->preset_pipelined->isChecked()) preset = machine::CP_PIPE; else return 0; return (unsigned)preset + 1; } void NewDialog::load_settings() { // Load config config.reset(new machine::MachineConfig(settings)); cache_handler_d->set_config(config->access_cache_data()); cache_handler_p->set_config(config->access_cache_program()); cache_handler_l2->set_config(config->access_cache_level2()); // Load preset unsigned preset = settings->value("Preset", 1).toUInt(); if (preset != 0) { auto p = (enum machine::ConfigPresets)(preset - 1); config->preset(p); switch (p) { case machine::CP_SINGLE: ui->preset_no_pipeline->setChecked(true); break; case machine::CP_SINGLE_CACHE: ui->preset_no_pipeline_cache->setChecked(true); break; case machine::CP_PIPE_NO_HAZARD: ui->preset_pipelined_bare->setChecked(true); break; case machine::CP_PIPE: ui->preset_pipelined->setChecked(true); break; } } else { ui->preset_custom->setChecked(true); } config_gui(); } void NewDialog::store_settings() { config->store(settings); // Presets are not stored in settings, so we have to store them explicitly if (ui->preset_custom->isChecked()) { settings->setValue("Preset", 0); } else { settings->setValue("Preset", preset_number()); } } NewDialogCacheHandler::NewDialogCacheHandler(NewDialog *nd, Ui::NewDialogCache *cui) : Super(nd) { this->nd = nd; this->ui = cui; this->config = nullptr; connect( ui->enabled, &QGroupBox::clicked, this, &NewDialogCacheHandler::enabled); connect( ui->number_of_sets, &QAbstractSpinBox::editingFinished, this, &NewDialogCacheHandler::numsets); connect( ui->block_size, &QAbstractSpinBox::editingFinished, this, &NewDialogCacheHandler::blocksize); connect( ui->degree_of_associativity, &QAbstractSpinBox::editingFinished, this, &NewDialogCacheHandler::degreeassociativity); connect( ui->replacement_policy, QOverload::of(&QComboBox::activated), this, &NewDialogCacheHandler::replacement); connect( ui->writeback_policy, QOverload::of(&QComboBox::activated), this, &NewDialogCacheHandler::writeback); } void NewDialogCacheHandler::set_config(machine::CacheConfig *cache_config) { this->config = cache_config; } void NewDialogCacheHandler::config_gui() { ui->enabled->setChecked(config->enabled()); ui->number_of_sets->setValue((int)config->set_count()); ui->block_size->setValue((int)config->block_size()); ui->degree_of_associativity->setValue((int)config->associativity()); ui->replacement_policy->setCurrentIndex((int)config->replacement_policy()); ui->writeback_policy->setCurrentIndex((int)config->write_policy()); } void NewDialogCacheHandler::enabled(bool val) { config->set_enabled(val); nd->switch2custom(); } void NewDialogCacheHandler::numsets() { config->set_set_count(ui->number_of_sets->value()); nd->switch2custom(); } void NewDialogCacheHandler::blocksize() { config->set_block_size(ui->block_size->value()); nd->switch2custom(); } void NewDialogCacheHandler::degreeassociativity() { config->set_associativity(ui->degree_of_associativity->value()); nd->switch2custom(); } void NewDialogCacheHandler::replacement(int val) { config->set_replacement_policy( (enum machine::CacheConfig::ReplacementPolicy)val); nd->switch2custom(); } void NewDialogCacheHandler::writeback(int val) { config->set_write_policy((enum machine::CacheConfig::WritePolicy)val); nd->switch2custom(); } qtrvsim-0.9.8/src/gui/dialogs/new/newdialog.h000066400000000000000000000054351467752164200211720ustar00rootroot00000000000000#ifndef NEWDIALOG_H #define NEWDIALOG_H #include "common/memory_ownership.h" #include "machine/machineconfig.h" #include "predictor_types.h" #include "ui_NewDialog.h" #include "ui_NewDialogCache.h" #include #include #include #include class NewDialogCacheHandler; class NewDialog : public QDialog { Q_OBJECT public: NewDialog(QWidget *parent, QSettings *settings); void switch2custom(); protected: void closeEvent(QCloseEvent *) override; private slots: void cancel(); void create(); void create_empty(); void create_example(); void browse_elf(); void elf_change(QString val); void set_preset(); void xlen_64bit_change(bool); void isa_atomic_change(bool); void isa_multiply_change(bool); void pipelined_change(bool); void delay_slot_change(bool); void hazard_unit_change(); void mem_protec_exec_change(bool); void mem_protec_write_change(bool); void mem_time_read_change(int); void mem_time_write_change(int); void mem_enable_burst_change(bool); void mem_time_burst_change(int); void mem_time_level2_change(int); void osemu_enable_change(bool); void osemu_known_syscall_stop_change(bool); void osemu_unknown_syscall_stop_change(bool); void osemu_interrupt_stop_change(bool); void osemu_exception_stop_change(bool); void browse_osemu_fs_root(); void osemu_fs_root_change(QString val); void reset_at_compile_change(bool); void switch2page(QTreeWidgetItem *current, QTreeWidgetItem *previous = nullptr); // Branch Predictor void bp_toggle_widgets(); void bp_enabled_change(bool); void bp_type_change(void); void bp_init_state_change(void); void bp_btb_addr_bits_change(int); void bp_bht_bhr_bits_change(int); void bp_bht_addr_bits_change(int); private: Box ui {}; Box ui_cache_p {}, ui_cache_d {}, ui_cache_l2 {}; QSettings *settings; Box config; void config_gui(); // Apply configuration to gui void bp_bht_bits_texts_update(void); unsigned preset_number(); void load_settings(); void store_settings(); NewDialogCacheHandler *cache_handler_p {}, *cache_handler_d {}, *cache_handler_l2 {}; }; class NewDialogCacheHandler : public QObject { Q_OBJECT using Super = QObject; public: NewDialogCacheHandler(NewDialog *nd, Ui::NewDialogCache *ui); void set_config(machine::CacheConfig *cache_config); void config_gui(); private slots: void enabled(bool); void numsets(); void blocksize(); void degreeassociativity(); void replacement(int); void writeback(int); private: NewDialog *nd; Ui::NewDialogCache *ui {}; machine::CacheConfig *config; }; #endif // NEWDIALOG_H qtrvsim-0.9.8/src/gui/dialogs/savechanged/000077500000000000000000000000001467752164200205205ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/dialogs/savechanged/savechangeddialog.cpp000066400000000000000000000051711467752164200246600ustar00rootroot00000000000000#include "savechangeddialog.h" #include #include #include #include #include #include #include SaveChangedDialog::SaveChangedDialog(QStringList &changedlist, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_ShowModal); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setWindowTitle(tr("Save next modified files?")); model = new QStandardItemModel(this); bool unknown_inserted = false; for (const auto &fname : changedlist) { int row = model->rowCount(); auto *item = new QStandardItem(); item->setData(fname, Qt::UserRole); if (!fname.isEmpty()) { item->setText(fname); } else { if (!unknown_inserted) { item->setText("Unknown"); unknown_inserted = true; } } item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setCheckState(Qt::Checked); model->setItem(row, 0, item); } auto *all = new QVBoxLayout(this); auto *listview = new QListView(this); listview->setModel(model); listview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); all->addWidget(listview); auto *hbBtn = new QWidget(); auto *hlBtn = new QHBoxLayout(hbBtn); auto *cancelButton = new QPushButton(tr("&Cancel"), parent); auto *ignoreButton = new QPushButton(tr("&Ignore"), parent); auto *saveButton = new QPushButton(tr("&Save"), parent); saveButton->setFocus(); connect(cancelButton, &QAbstractButton::clicked, this, &SaveChangedDialog::cancel_clicked); connect(ignoreButton, &QAbstractButton::clicked, this, &SaveChangedDialog::ignore_clicked); connect(saveButton, &QAbstractButton::clicked, this, &SaveChangedDialog::save_clicked); hlBtn->addWidget(cancelButton); hlBtn->addStretch(); hlBtn->addWidget(ignoreButton); hlBtn->addStretch(); hlBtn->addWidget(saveButton); all->addWidget(hbBtn); setMinimumSize(400, 300); } void SaveChangedDialog::cancel_clicked() { QStringList list; emit user_decision(true, list); close(); } void SaveChangedDialog::ignore_clicked() { QStringList list; emit user_decision(false, list); close(); } void SaveChangedDialog::save_clicked() { QStringList list; for (int r = 0; r < model->rowCount(); ++r) { if (model->item(r)->checkState() == Qt::Checked) { list.append(model->item(r)->data(Qt::UserRole).toString()); } } emit user_decision(false, list); close(); } qtrvsim-0.9.8/src/gui/dialogs/savechanged/savechangeddialog.h000066400000000000000000000010061467752164200243160ustar00rootroot00000000000000#ifndef SAVECHANGED_H #define SAVECHANGED_H #include #include #include #include class SaveChangedDialog : public QDialog { Q_OBJECT public: explicit SaveChangedDialog(QStringList &changedlist, QWidget *parent = nullptr); signals: void user_decision(bool cancel, QStringList tosavelist); private slots: void cancel_clicked(); void ignore_clicked(); void save_clicked(); private: QStandardItemModel *model; }; #endif // SAVECHANGED_H qtrvsim-0.9.8/src/gui/extprocess.cpp000066400000000000000000000052121467752164200175310ustar00rootroot00000000000000#include "extprocess.h" #include #include using namespace std; ExtProcess::ExtProcess(QObject *parent) : Super(parent) { setProcessChannelMode(QProcess::MergedChannels); connect( this, &QProcess::readyReadStandardOutput, this, &ExtProcess::process_output); connect( this, QOverload::of(&QProcess::finished), this, &ExtProcess::report_finished); connect(this, &QProcess::started, this, &ExtProcess::report_started); } void ExtProcess::report_finished(int exitCode, QProcess::ExitStatus exitStatus) { if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) { report_message( messagetype::MSG_FINISH, "", 0, 0, program() + ": failed - exit code " + QString::number(exitCode), ""); } else { report_message( messagetype::MSG_FINISH, "", 0, 0, program() + ": finished", ""); } deleteLater(); } void ExtProcess::report_started() { report_message( messagetype::MSG_START, "", 0, 0, program() + ": started", ""); } void ExtProcess::process_output() { QString file = ""; int ln = 0; int col = 0; messagetype::Type type = messagetype::MSG_INFO; while (canReadLine()) { QString line = QString::fromLocal8Bit(readLine()); while (line.count() > 0) { if (line.at(line.count() - 1) != '\n' && line.at(line.count() - 1) != '\r') { break; } line.truncate(line.count() - 1); } int pos = line.indexOf(':'); if (pos >= 0) { QFileInfo fi(QDir(workingDirectory()), line.mid(0, pos)); line = line.mid(pos + 1); file = fi.absoluteFilePath(); } for (pos = 0; line.count() > pos && line.at(pos).isDigit(); pos++) {} if ((pos < line.count()) && (line.at(pos) == ':')) { ln = line.mid(0, pos).toInt(); line = line.mid(pos + 1); } for (pos = 0; line.count() > pos && line.at(pos).isDigit(); pos++) {} if ((pos < line.count()) && (line.at(pos) == ':')) { col = line.mid(0, pos).toInt(); line = line.mid(pos + 1); } if (line.startsWith(' ')) { line = line.mid(1); } if (line.startsWith('\t')) { line = line.mid(1); } if (line.startsWith("error:", Qt::CaseInsensitive)) { type = messagetype::MSG_ERROR; } else if (line.startsWith("warning:", Qt::CaseInsensitive)) { type = messagetype::MSG_WARNING; } report_message(type, file, ln, col, line, ""); } } qtrvsim-0.9.8/src/gui/extprocess.h000066400000000000000000000011751467752164200172020ustar00rootroot00000000000000#ifndef MSGREPORT_H #define MSGREPORT_H #include "assembler/messagetype.h" #include #include class ExtProcess : public QProcess { Q_OBJECT using Super = QProcess; public: explicit ExtProcess(QObject *parent = nullptr); signals: void report_message( messagetype::Type type, QString file, int line, int column, QString text, QString hint); protected slots: void process_output(); void report_started(); void report_finished(int exitCode, QProcess::ExitStatus exitStatus); protected: QByteArray m_buffer; }; #endif // MSGREPORT_H qtrvsim-0.9.8/src/gui/fontsize.cpp000066400000000000000000000010031467752164200171650ustar00rootroot00000000000000#include "fontsize.h" #include #include #include #include "common/logging.h" LOG_CATEGORY("gui.font"); int FontSize::SIZE5 = 5; int FontSize::SIZE6 = 6; int FontSize::SIZE7 = 7; int FontSize::SIZE8 = 8; void FontSize::init() { int h = QFontMetrics(QApplication::font()).height(); LOG() << "Font size:" << h; h /= 3; int d = h / 4 + 1; FontSize::SIZE5 = h - 2 * d; FontSize::SIZE6 = h - d; FontSize::SIZE7 = h; FontSize::SIZE8 = h + d / 2; } qtrvsim-0.9.8/src/gui/fontsize.h000066400000000000000000000003061467752164200166370ustar00rootroot00000000000000#ifndef FONTSIZES_H #define FONTSIZES_H struct FontSize { static int SIZE5; static int SIZE6; static int SIZE7; static int SIZE8; static void init(); }; #endif // FONTSIZES_H qtrvsim-0.9.8/src/gui/graphicsview.cpp000066400000000000000000000041121467752164200200230ustar00rootroot00000000000000#include "graphicsview.h" GraphicsView::GraphicsView(QWidget *parent) : Super(parent) { prev_height = 0; prev_width = 0; setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); } void GraphicsView::setScene(QGraphicsScene *scene) { Super::setScene(scene); update_scale(); } void GraphicsView::resizeEvent(QResizeEvent *event) { Super::resizeEvent(event); if ((width() != prev_height) || (height() != prev_width)) { update_scale(); } } void GraphicsView::update_scale() { if (scene() == nullptr) { return; // Skip if we have no scene } // Note: there is somehow a three-pixel error when viewing, so we have to // always compensate const int w = scene()->width() + 3; const int h = scene()->height() + 3; prev_height = width(); prev_width = height(); qreal scale = 1; if (height() > h && width() > w) { if (height() > width()) { scale = (qreal)width() / w; } else { scale = (qreal)height() / h; } } QTransform t; t.scale(scale, scale); setTransform(t, false); } void GraphicsView::wheelEvent(QWheelEvent *event) { if (event->modifiers() & Qt::ControlModifier) { // zoom const ViewportAnchor anchor = transformationAnchor(); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); int angle = event->angleDelta().y(); qreal factor; if (angle > 0) { factor = 1.1; } else { factor = 0.9; } scale(factor, factor); setTransformationAnchor(anchor); } else { Super::wheelEvent(event); } } void GraphicsView::keyPressEvent(QKeyEvent *event) { qreal factor = 1.1; if (event->matches(QKeySequence::ZoomIn) || (event->key() == Qt::Key_Equal) || (event->key() == Qt::Key_Plus)) { scale(factor, factor); } else if ( event->matches(QKeySequence::ZoomOut) || (event->key() == Qt::Key_Minus)) { scale(1 / factor, 1 / factor); } else { Super::keyPressEvent(event); } } qtrvsim-0.9.8/src/gui/graphicsview.h000066400000000000000000000011561467752164200174750ustar00rootroot00000000000000#ifndef GRAPHICSVIEW_H #define GRAPHICSVIEW_H #include #include #include #include #include class GraphicsView : public QGraphicsView { Q_OBJECT using Super = QGraphicsView; public: explicit GraphicsView(QWidget *parent); void setScene(QGraphicsScene *scene); protected: void resizeEvent(QResizeEvent *event) override; void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *event) override; private: void update_scale(); int prev_height; int prev_width; }; #endif // GRAPHICSVIEW_H qtrvsim-0.9.8/src/gui/helper/000077500000000000000000000000001467752164200161055ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/helper/async_modal.h000066400000000000000000000026031467752164200205500ustar00rootroot00000000000000/** * This file provides API for modal windows (dialogs, message boxes) which runs asynchronously * and therefore is safe in WASM, where blocking will cause the app to freeze! * * None of these classes shall be used directly, unless special callback is required. In such * cases, high caution needs to be applied. * * NOTE: This code could be optimized by adding async behavior only to emscripten, however modals * are typically not performance sensitive and an special case would complicate debugging. * * @file */ #ifndef ASYNC_MODAL_H #define ASYNC_MODAL_H #include inline void showAsyncMessageBox( QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, const QString &detailed_text = QString(), const QString &tooltip_text = QString()) { auto msg = new QMessageBox(icon, title, text, QMessageBox::Ok, parent); msg->setDetailedText(detailed_text); msg->setToolTip(tooltip_text); // This is necessary as WASM does not support blocking APIs. msg->setAttribute(Qt::WA_DeleteOnClose); msg->open(); } inline void showAsyncCriticalBox( QWidget *parent, const QString &title, const QString &text, const QString &detailed_text = QString(), const QString &tooltip_text = QString()) { showAsyncMessageBox(parent, QMessageBox::Critical, title, text, detailed_text, tooltip_text); } #endifqtrvsim-0.9.8/src/gui/hinttabledelegate.cpp000066400000000000000000000010561467752164200210010ustar00rootroot00000000000000#include "hinttabledelegate.h" #include QSize HintTableDelegate::sizeHintForText( const QStyleOptionViewItem &option, const QModelIndex &index, const QString &str) const { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); opt.features |= QStyleOptionViewItem::HasDisplay; opt.text = str; return style->sizeFromContents( QStyle::CT_ItemViewItem, &opt, QSize(), widget); } qtrvsim-0.9.8/src/gui/hinttabledelegate.h000066400000000000000000000007531467752164200204510ustar00rootroot00000000000000#ifndef HINTTABLEDELEGATE_H #define HINTTABLEDELEGATE_H #include #include class HintTableDelegate : public QStyledItemDelegate { Q_OBJECT using Super = QStyledItemDelegate; public: explicit HintTableDelegate(QWidget *parent = nullptr) : Super(parent) {} [[nodiscard]] QSize sizeHintForText( const QStyleOptionViewItem &option, const QModelIndex &index, const QString &str) const; }; #endif // HINTTABLEDELEGATE_H qtrvsim-0.9.8/src/gui/main.cpp000066400000000000000000000025231467752164200162600ustar00rootroot00000000000000#include "common/logging.h" #include "common/logging_format_colors.h" #include "mainwindow/mainwindow.h" #include LOG_CATEGORY("gui.main"); int main(int argc, char *argv[]) { QApplication app(argc, argv); set_default_log_pattern(); // There constants are set in CMake. QApplication::setApplicationName(APP_NAME); QApplication::setOrganizationName(APP_ORGANIZATION); QApplication::setOrganizationDomain(APP_ORGANIZATION_DOMAIN); QApplication::setApplicationVersion(APP_VERSION); LOG("Started %s version %s.", APP_NAME, APP_VERSION); LOG("Developed at %s (%s).", APP_ORGANIZATION, APP_ORGANIZATION_DOMAIN); /* * If environment variable specified in define ENV_CONFIG_FILE_NAME is * present, the app should behave in a portable manner and use ini file on the * specified location. Otherwise, Qt defaults are used. */ auto env = QProcessEnvironment::systemEnvironment(); QSettings *settings; if (env.contains(ENV_CONFIG_FILE_NAME)) { // Behave as a portable app. settings = new QSettings(env.value(ENV_CONFIG_FILE_NAME), QSettings::IniFormat); } else { // Qt defaults settings = new QSettings(APP_ORGANIZATION, APP_NAME); } MainWindow w(settings); // Moving settings ownership. w.start(); return QApplication::exec(); } qtrvsim-0.9.8/src/gui/mainwindow/000077500000000000000000000000001467752164200170025ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/mainwindow/MainWindow.ui000066400000000000000000000437661467752164200214350ustar00rootroot00000000000000 MainWindow 0 0 900 600 MainWindow :/icons/gui.png :/icons/gui.png false true 0 0 0 0 0 0 0 900 20 &File &Examples &Windows M&achine &Help Options toolBar false Qt::TopToolBarArea TopToolBarArea false :/icons/document-import.png:/icons/document-import.png &New simulation... Ctrl+N R&estart :/icons/new.png:/icons/new.png Ne&w source New source Ctrl+F :/icons/open.png:/icons/open.png &Open source Open source Ctrl+O false :/icons/save.png:/icons/save.png &Save source Save source Ctrl+S false Save source &as Save source as false :/icons/closetab.png:/icons/closetab.png &Close source Close source Ctrl+W false :/icons/compfile-256.png:/icons/compfile-256.png &Compile Source Compile source and update memory Ctrl+E true :/icons/build-256.png:/icons/build-256.png &Build Executable Build executable by external make Ctrl+B :/icons/application-exit.png:/icons/application-exit.png E&xit Exit program Ctrl+Q :/icons/play.png:/icons/play.png &Run Ctrl+R :/icons/next.png:/icons/next.png &Step Ctrl+T :/icons/pause.png:/icons/pause.png &Pause Ctrl+P true &1 instruction per second 1x Run CPU in speed of single instruction per second Ctrl+1 true &5 instructions per second 5x Run CPU in speed of 5 instructions per second Ctrl+5 true 1&0 instructions per second 10x Run CPU in speed of 10 instructions per second Ctrl+0 true 2&5 instructions per second 25x Run CPU in speed of 25 instructions per second Ctrl+F5 true &Unlimited Run CPU without any clock constrains Ctrl+U &Memory Data memory view Ctrl+M &Program Program memory view Ctrl+P &Registers Ctrl+D C&ontrol and Status Registers Ctrl+I :/icons/reload.png:/icons/reload.png &Reload simulation Ctrl+Shift+R &Print Ctrl+Alt+P Pro&gram Cache Ctrl+Shift+P &Data Cache Ctrl+Shift+M L2 Cache Reset Windows true &2 instructions per second 2x Run CPU in speed of two instructions per second Ctrl+2 About Qt&RVSim true &Max Run at maximal speed, skip visualization for 100 msec Ctrl+A About &Qt P&eripherals &Terminal &LCD display Sh&ow Symbol Show Symbol true true &Core View Me&ssages Show compile/build messages true false M&nemonics Registers true true Show &Line Numbers Show line number in the code editor. Branch Predictor (History table) Branch Predictor (Target table) Branch Predictor (Info) qtrvsim-0.9.8/src/gui/mainwindow/mainwindow.cpp000066400000000000000000001023651467752164200216710ustar00rootroot00000000000000#include "windows/editor/editordock.h" #include "windows/editor/editortab.h" #include #include #include #include #include "assembler/fixmatheval.h" #include "assembler/simpleasm.h" #include "dialogs/about/aboutdialog.h" #include "dialogs/gotosymbol/gotosymboldialog.h" #include "dialogs/savechanged/savechangeddialog.h" #include "extprocess.h" #include "helper/async_modal.h" #include "mainwindow.h" #include "os_emulation/ossyscall.h" #include "textsignalaction.h" #include "common/logging.h" #include #include #include #include LOG_CATEGORY("gui.mainwindow"); #ifdef __EMSCRIPTEN__ #include "qhtml5file.h" #include constexpr bool WEB_ASSEMBLY = true; #else constexpr bool WEB_ASSEMBLY = false; #endif MainWindow::MainWindow(QSettings *settings, QWidget *parent) : QMainWindow(parent) , settings(settings) { machine.reset(); corescene.reset(); ui.reset(new Ui::MainWindow()); ui->setupUi(this); setWindowTitle(APP_NAME); setDockNestingEnabled(true); // Setup central widget central_widget_tabs.reset(new HidingTabWidget(this)); central_widget_tabs->setTabBarAutoHide(true); this->setCentralWidget(central_widget_tabs.data()); coreview.reset(new GraphicsView(this)); coreview->setWindowTitle("&Core"); central_widget_tabs->addTab(coreview.data(), coreview->windowTitle()); // Setup editor editor_tabs.reset(new EditorDock(this->settings, central_widget_tabs.data())); editor_tabs->setTabBarAutoHide(true); editor_tabs->setWindowTitle("&Editor"); ui->actionBuildExe->setEnabled(false); connect(ui->actionNew, &QAction::triggered, editor_tabs.data(), &EditorDock::create_empty_tab); connect(ui->actionOpen, &QAction::triggered, editor_tabs.data(), &EditorDock::open_file_dialog); connect(ui->actionSave, &QAction::triggered, editor_tabs.data(), &EditorDock::save_current_tab); connect( ui->actionSaveAs, &QAction::triggered, editor_tabs.data(), &EditorDock::save_current_tab_as); connect( ui->actionClose, &QAction::triggered, editor_tabs.data(), &EditorDock::close_current_tab); connect( editor_tabs.data(), &EditorDock::requestAddRemoveTab, central_widget_tabs.data(), &HidingTabWidget::addRemoveTabRequested); connect( editor_tabs.data(), &EditorDock::editor_available_changed, this, [this](bool available) { ui->actionSave->setEnabled(available); ui->actionSaveAs->setEnabled(available); ui->actionClose->setEnabled(available); ui->actionCompileSource->setEnabled(available); }); if constexpr (!WEB_ASSEMBLY) { // Only enable build action if we know there to look for the Makefile. connect(editor_tabs.data(), &EditorDock::currentChanged, this, [this](int index) { bool has_elf_file = machine != nullptr && !machine->config().elf().isEmpty(); bool current_tab_is_file = (index >= 0) && !editor_tabs->get_tab(index)->get_editor()->filename().isEmpty(); ui->actionBuildExe->setEnabled(has_elf_file || current_tab_is_file); }); } connect( ui->actionEditorShowLineNumbers, &QAction::triggered, editor_tabs.data(), &EditorDock::set_show_line_numbers); bool line_numbers_visible = settings->value("EditorShowLineNumbers", true).toBool(); editor_tabs->set_show_line_numbers(line_numbers_visible); ui->actionEditorShowLineNumbers->setChecked(line_numbers_visible); // Create/prepare other widgets ndialog.reset(new NewDialog(this, settings)); registers.reset(new RegistersDock(this, machine::Xlen::_32)); registers->hide(); program.reset(new ProgramDock(this, settings)); addDockWidget(Qt::LeftDockWidgetArea, program.data()); program->show(); memory.reset(new MemoryDock(this, settings)); memory->hide(); cache_program.reset(new CacheDock(this, "Program")); cache_program->hide(); cache_data.reset(new CacheDock(this, "Data")); cache_data->hide(); cache_level2.reset(new CacheDock(this, "L2")); cache_level2->hide(); bp_btb.reset(new DockPredictorBTB(this)); bp_btb->hide(); bp_bht.reset(new DockPredictorBHT(this)); bp_bht->hide(); bp_info.reset(new DockPredictorInfo(this)); bp_info->hide(); peripherals.reset(new PeripheralsDock(this, settings)); peripherals->hide(); terminal.reset(new TerminalDock(this, settings)); terminal->hide(); lcd_display.reset(new LcdDisplayDock(this, settings)); lcd_display->hide(); csrdock = new CsrDock(this); csrdock->hide(); messages = new MessagesDock(this, settings); messages->hide(); // Execution speed actions speed_group = new QActionGroup(this); speed_group->addAction(ui->ips1); speed_group->addAction(ui->ips2); speed_group->addAction(ui->ips5); speed_group->addAction(ui->ips10); speed_group->addAction(ui->ips25); speed_group->addAction(ui->ipsUnlimited); speed_group->addAction(ui->ipsMax); ui->ips1->setChecked(true); // Connect signals from menu connect(ui->actionExit, &QAction::triggered, this, &QWidget::close); connect(ui->actionNewMachine, &QAction::triggered, this, &MainWindow::new_machine); connect(ui->actionReload, &QAction::triggered, this, [this] { machine_reload(false, false); }); connect(ui->actionPrint, &QAction::triggered, this, &MainWindow::print_action); connect( ui->actionMnemonicRegisters, &QAction::triggered, this, &MainWindow::view_mnemonics_registers); connect(ui->actionCompileSource, &QAction::triggered, this, &MainWindow::compile_source); connect(ui->actionBuildExe, &QAction::triggered, this, &MainWindow::build_execute); connect(ui->actionShow_Symbol, &QAction::triggered, this, &MainWindow::show_symbol_dialog); connect(ui->actionRegisters, &QAction::triggered, this, &MainWindow::show_registers); connect(ui->actionProgram_memory, &QAction::triggered, this, &MainWindow::show_program); connect(ui->actionMemory, &QAction::triggered, this, &MainWindow::show_memory); connect(ui->actionProgram_Cache, &QAction::triggered, this, &MainWindow::show_cache_program); connect(ui->actionData_Cache, &QAction::triggered, this, &MainWindow::show_cache_data); connect(ui->actionL2_Cache, &QAction::triggered, this, &MainWindow::show_cache_level2); // Branch predictor connect( ui->actionBranch_Predictor_History_table, &QAction::triggered, this, &MainWindow::show_bp_bht); connect( ui->actionBranch_Predictor_Target_table, &QAction::triggered, this, &MainWindow::show_bp_btb); connect( ui->actionBranch_Predictor_Info, &QAction::triggered, this, &MainWindow::show_bp_info); connect(ui->actionPeripherals, &QAction::triggered, this, &MainWindow::show_peripherals); connect(ui->actionTerminal, &QAction::triggered, this, &MainWindow::show_terminal); connect(ui->actionLcdDisplay, &QAction::triggered, this, &MainWindow::show_lcd_display); connect(ui->actionCsrShow, &QAction::triggered, this, &MainWindow::show_csrdock); connect(ui->actionCore_View_show, &QAction::triggered, this, &MainWindow::show_hide_coreview); connect(ui->actionMessages, &QAction::triggered, this, &MainWindow::show_messages); connect(ui->actionResetWindows, &QAction::triggered, this, &MainWindow::reset_windows); connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::about_program); connect(ui->actionAboutQt, &QAction::triggered, this, &MainWindow::about_qt); connect(ui->ips1, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ips2, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ips5, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ips10, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ips25, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ipsUnlimited, &QAction::toggled, this, &MainWindow::set_speed); connect(ui->ipsMax, &QAction::toggled, this, &MainWindow::set_speed); connect(this, &MainWindow::report_message, messages, &MessagesDock::insert_line); connect(this, &MainWindow::clear_messages, messages, &MessagesDock::clear_messages); connect(messages, &MessagesDock::message_selected, this, &MainWindow::message_selected); // Restore application state from settings restoreState(settings->value("windowState").toByteArray()); restoreGeometry(settings->value("windowGeometry").toByteArray()); if (settings->value("viewMnemonicRegisters").toBool()) { ui->actionMnemonicRegisters->trigger(); } for (const QString &file_name : settings->value("openSrcFiles").toStringList()) { editor_tabs->open_file(file_name); } QDir samples_dir(":/samples"); for (const QString &fname : samples_dir.entryList(QDir::Files)) { auto *textsigac = new TextSignalAction(fname, ":/samples/" + fname, ui->menuExamples); ui->menuExamples->addAction(textsigac); connect(textsigac, &TextSignalAction::activated, this, &MainWindow::example_source); } } MainWindow::~MainWindow() { settings->sync(); } void MainWindow::start() { this->show(); ndialog->show(); } void MainWindow::show_hide_coreview(bool show) { coreview_shown = show; if (!show) { if (corescene == nullptr) { } else { central_widget_tabs->removeTab(central_widget_tabs->indexOf(coreview.data())); corescene.reset(); if (coreview != nullptr) { coreview->setScene(corescene.data()); } } return; } if (machine == nullptr) { return; } if (corescene != nullptr) { return; } if (machine->config().pipelined()) { corescene.reset(new CoreViewScenePipelined(machine.data())); } else { corescene.reset(new CoreViewSceneSimple(machine.data())); } central_widget_tabs->insertTab(0, coreview.data(), coreview->windowTitle()); // Ensures correct zoom. coreview->setScene(corescene.data()); this->setCentralWidget(central_widget_tabs.data()); // Connect scene signals to actions connect(corescene.data(), &CoreViewScene::request_registers, this, &MainWindow::show_registers); connect( corescene.data(), &CoreViewScene::request_program_memory, this, &MainWindow::show_program); connect(corescene.data(), &CoreViewScene::request_data_memory, this, &MainWindow::show_memory); connect( corescene.data(), &CoreViewScene::request_jump_to_program_counter, program.data(), &ProgramDock::jump_to_pc); connect( corescene.data(), &CoreViewScene::request_cache_program, this, &MainWindow::show_cache_program); connect( corescene.data(), &CoreViewScene::request_cache_data, this, &MainWindow::show_cache_data); connect( corescene.data(), &CoreViewScene::request_peripherals, this, &MainWindow::show_peripherals); connect(corescene.data(), &CoreViewScene::request_terminal, this, &MainWindow::show_terminal); coreview->setScene(corescene.data()); } void MainWindow::create_core( const machine::MachineConfig &config, bool load_executable, bool keep_memory) { // Create machine auto *new_machine = new machine::Machine(config, true, load_executable); if (keep_memory && (machine != nullptr)) { new_machine->memory_rw()->reset(*machine->memory()); } // Remove old machine machine.reset(new_machine); // Create machine view auto focused_index = central_widget_tabs->currentIndex(); corescene.reset(); show_hide_coreview(coreview_shown); central_widget_tabs->setCurrentIndex(focused_index); set_speed(); // Update machine speed to current settings const static machine::ExceptionCause ecall_variats[] = {machine::EXCAUSE_ECALL_ANY, machine::EXCAUSE_ECALL_M, machine::EXCAUSE_ECALL_S, machine::EXCAUSE_ECALL_U}; if (config.osemu_enable()) { auto *osemu_handler = new osemu::OsSyscallExceptionHandler( config.osemu_known_syscall_stop(), config.osemu_unknown_syscall_stop(), config.osemu_fs_root()); osemu_handler->setParent(new_machine); connect( osemu_handler, &osemu::OsSyscallExceptionHandler::char_written, terminal.data(), QOverload::of(&TerminalDock::tx_byte)); connect( osemu_handler, &osemu::OsSyscallExceptionHandler::rx_byte_pool, terminal.data(), &TerminalDock::rx_byte_pool); for (auto ecall_variat : ecall_variats) { machine->register_exception_handler(ecall_variat, osemu_handler); machine->set_step_over_exception(ecall_variat, true); machine->set_stop_on_exception(ecall_variat, false); } } else { for (auto ecall_variat : ecall_variats) { machine->set_step_over_exception(ecall_variat, false); machine->set_stop_on_exception(ecall_variat, config.osemu_exception_stop()); } } // Connect machine signals and slots connect(ui->actionRun, &QAction::triggered, machine.data(), &machine::Machine::play); connect(ui->actionPause, &QAction::triggered, machine.data(), &machine::Machine::pause); connect(ui->actionStep, &QAction::triggered, machine.data(), &machine::Machine::step); connect(ui->actionRestart, &QAction::triggered, machine.data(), &machine::Machine::restart); connect(machine.data(), &machine::Machine::status_change, this, &MainWindow::machine_status); connect(machine.data(), &machine::Machine::program_exit, this, &MainWindow::machine_exit); connect(machine.data(), &machine::Machine::program_trap, this, &MainWindow::machine_trap); // Connect signal from break to machine pause connect( machine->core(), &machine::Core::stop_on_exception_reached, machine.data(), &machine::Machine::pause); // Setup docks registers->connectToMachine(machine.data()); program->setup(machine.data()); memory->setup(machine.data()); cache_program->setup(machine->cache_program()); cache_data->setup(machine->cache_data()); bool cache_after_cache = config.cache_data().enabled() || config.cache_program().enabled(); cache_level2->setup(machine->cache_level2(), cache_after_cache); // Branch predictor bp_btb->setup(machine->core()->get_predictor(), machine->core()); bp_bht->setup(machine->core()->get_predictor(), machine->core()); bp_info->setup(machine->core()->get_predictor(), machine->core()); terminal->setup(machine->serial_port()); peripherals->setup(machine->peripheral_spi_led()); lcd_display->setup(machine->peripheral_lcd_display()); csrdock->setup(machine.data()); connect( machine->core(), &machine::Core::step_done, program.data(), &ProgramDock::update_pipeline_addrs); // Set status to ready machine_status(machine::Machine::ST_READY); } bool MainWindow::configured() { return (machine != nullptr); } void MainWindow::new_machine() { ndialog->show(); } void MainWindow::machine_reload(bool force_memory_reset, bool force_elf_load) { if (machine == nullptr) { return new_machine(); } bool load_executable = force_elf_load || machine->executable_loaded(); machine::MachineConfig cnf(&machine->config()); // We have to make local copy as create_core // will delete the current machine try { create_core(cnf, load_executable, !load_executable && !force_memory_reset); } catch (const machine::SimulatorExceptionInput &e) { showAsyncCriticalBox( this, "Error while initializing new machine", e.msg(false), e.msg(true)); } } void MainWindow::print_action() { #ifdef WITH_PRINTING printer.setColorMode(QPrinter::Color); if (print_dialog.exec() == QDialog::Accepted) { // This vector pre-drawing step is required because Qt fallbacks to // bitmap and produces extremely large and slow to render files. // (https://forum.qt.io/topic/21330/printing-widgets-not-as-bitmap-but-in-a-vector-based-format/3) QPicture scene_as_vector; { QPainter painter(&scene_as_vector); corescene->render(&painter); painter.end(); } // Prepare printer for PDF printing with appropriate resize. QRectF scene_rect = corescene->sceneRect(); if (printer.outputFormat() == QPrinter::PdfFormat && (scene_rect.height() != 0)) { QPageLayout layout = printer.pageLayout(); layout.setOrientation(QPageLayout::Portrait); QPageSize pagesize = layout.pageSize(); QRectF paint_rect = layout.paintRect(QPageLayout::Point); QSize pointsize = pagesize.sizePoints(); qreal ratio = scene_rect.width() / scene_rect.height(); // Cut off the excess if (paint_rect.height() * ratio > paint_rect.width()) { pointsize.setHeight( pointsize.height() - paint_rect.height() + paint_rect.width() / ratio); } else { pointsize.setWidth( pointsize.width() - paint_rect.width() + paint_rect.height() * ratio); } pagesize = QPageSize(pointsize, "custom", QPageSize::ExactMatch); layout.setPageSize(pagesize, layout.margins()); printer.setPageLayout(layout); } QPainter painter(&printer); // scale to fit paint size QRectF paint_rect = printer.pageLayout().paintRect(QPageLayout::Millimeter); double xscale = paint_rect.width() / scene_as_vector.widthMM(); double yscale = paint_rect.height() / scene_as_vector.heightMM(); double scale = qMin(xscale, yscale); painter.scale(scale, scale); painter.drawPicture(0, 0, scene_as_vector); painter.end(); } #else showAsyncMessageBox( this, QMessageBox::Information, "Printing is not supported.", "The simulator was compiled without printing support.\n" "If you compiled the simulator yourself, make sure that the Qt " "print support library is present.\n" "Otherwise report this to the executable provider (probably your " "teacher)."); #endif // WITH_PRINTING } #define SHOW_HANDLER(NAME, DEFAULT_AREA, DEFAULT_VISIBLE) \ void MainWindow::show_##NAME() { \ show_dockwidget(&*NAME, DEFAULT_AREA, true, false); \ } \ void MainWindow::reset_state_##NAME() { \ show_dockwidget(&*NAME, DEFAULT_AREA, DEFAULT_VISIBLE, true); \ } SHOW_HANDLER(registers, Qt::TopDockWidgetArea, true) SHOW_HANDLER(program, Qt::LeftDockWidgetArea, true) SHOW_HANDLER(memory, Qt::RightDockWidgetArea, true ) SHOW_HANDLER(cache_program, Qt::RightDockWidgetArea, false) SHOW_HANDLER(cache_data, Qt::RightDockWidgetArea, false) SHOW_HANDLER(cache_level2, Qt::RightDockWidgetArea, false) SHOW_HANDLER(bp_btb, Qt::RightDockWidgetArea, false) SHOW_HANDLER(bp_bht, Qt::RightDockWidgetArea, false) SHOW_HANDLER(bp_info, Qt::RightDockWidgetArea, false) SHOW_HANDLER(peripherals, Qt::RightDockWidgetArea, false) SHOW_HANDLER(terminal, Qt::RightDockWidgetArea, false) SHOW_HANDLER(lcd_display, Qt::RightDockWidgetArea, false) SHOW_HANDLER(csrdock, Qt::TopDockWidgetArea, false) SHOW_HANDLER(messages, Qt::BottomDockWidgetArea, false) #undef SHOW_HANDLER void MainWindow::reset_windows() { reset_state_registers(); reset_state_program(); reset_state_memory(); reset_state_cache_program(); reset_state_cache_data(); reset_state_cache_level2(); reset_state_bp_btb(); reset_state_bp_bht(); reset_state_bp_info(); reset_state_peripherals(); reset_state_terminal(); reset_state_lcd_display(); reset_state_csrdock(); reset_state_messages(); } void MainWindow::show_symbol_dialog() { if (machine == nullptr || machine->symbol_table() == nullptr) { return; } QStringList symbol_names = machine->symbol_table()->names(); auto *gotosyboldialog = new GoToSymbolDialog(this, symbol_names); connect( gotosyboldialog, &GoToSymbolDialog::program_focus_addr, program.data(), &ProgramDock::focus_addr_with_save); connect( gotosyboldialog, &GoToSymbolDialog::program_focus_addr, this, &MainWindow::show_program); connect( gotosyboldialog, &GoToSymbolDialog::memory_focus_addr, memory.data(), &MemoryDock::focus_addr); connect(gotosyboldialog, &GoToSymbolDialog::memory_focus_addr, this, &MainWindow::show_memory); connect( gotosyboldialog, &GoToSymbolDialog::obtain_value_for_name, machine->symbol_table(), &machine::SymbolTable::name_to_value); gotosyboldialog->setAttribute(Qt::WA_DeleteOnClose); gotosyboldialog->open(); } void MainWindow::about_program() { auto *aboutdialog = new AboutDialog(this); aboutdialog->show(); } void MainWindow::about_qt() { QMessageBox::aboutQt(this); } void MainWindow::set_speed() { if (machine == nullptr) { return; // just ignore } if (ui->ips1->isChecked()) { machine->set_speed(1000); } else if (ui->ips2->isChecked()) { machine->set_speed(500); } else if (ui->ips5->isChecked()) { machine->set_speed(200); } else if (ui->ips10->isChecked()) { machine->set_speed(100); } else if (ui->ips25->isChecked()) { machine->set_speed(40); } else if (ui->ipsMax->isChecked()) { machine->set_speed(0, 100); } else { machine->set_speed(0); } } void MainWindow::view_mnemonics_registers(bool enable) { machine::Instruction::set_symbolic_registers(enable); settings->setValue("viewMnemonicRegisters", enable); if (program == nullptr) { return; } program->request_update_all(); } void MainWindow::closeEvent(QCloseEvent *event) { settings->setValue("windowGeometry", saveGeometry()); settings->setValue("windowState", saveState()); settings->setValue("openSrcFiles", editor_tabs->get_open_file_list()); settings->sync(); QStringList list; if (!ignore_unsaved && editor_tabs->get_modified_tab_filenames(list, true)) { event->ignore(); auto *dialog = new SaveChangedDialog(list, this); if (!QMetaType::isRegistered(qMetaTypeId())) { qRegisterMetaType(); } connect( dialog, &SaveChangedDialog::user_decision, this, [this](bool cancel, const QStringList &tabs_to_save) { if (cancel) return; for (const auto &name : tabs_to_save) { auto tab_id = editor_tabs->find_tab_id_by_filename(name); if (tab_id.has_value()) editor_tabs->save_tab(tab_id.value()); } ignore_unsaved = true; close(); }, Qt::QueuedConnection); dialog->open(); } } void MainWindow::show_dockwidget(QDockWidget *dw, Qt::DockWidgetArea area, bool defaultVisible, bool resetState) { if (dw == nullptr) { return; } if (resetState) { if (dw->isFloating()) { dw->hide(); dw->setFloating(false); } addDockWidget(area, dw); if (defaultVisible) { dw->show(); } else { dw->hide(); } } else if (dw->isHidden()) { dw->show(); addDockWidget(area, dw); } else { dw->raise(); dw->setFocus(); } } void MainWindow::machine_status(enum machine::Machine::Status st) { QString status; switch (st) { case machine::Machine::ST_READY: ui->actionPause->setEnabled(false); ui->actionRun->setEnabled(true); ui->actionStep->setEnabled(true); status = "Ready"; break; case machine::Machine::ST_RUNNING: ui->actionPause->setEnabled(true); ui->actionRun->setEnabled(false); ui->actionStep->setEnabled(false); status = "Running"; break; case machine::Machine::ST_BUSY: // Busy is not interesting (in such case we should just be running return; case machine::Machine::ST_EXIT: // machine_exit is called, so we disable controls in that status = "Exited"; break; case machine::Machine::ST_TRAPPED: // machine_trap is called, so we disable controls in that status = "Trapped"; break; default: status = "Unknown"; break; } ui->statusBar->showMessage(status); } void MainWindow::machine_exit() { ui->actionPause->setEnabled(false); ui->actionRun->setEnabled(false); ui->actionStep->setEnabled(false); } void MainWindow::machine_trap(machine::SimulatorException &e) { machine_exit(); showAsyncCriticalBox(this, "Machine trapped", e.msg(false), e.msg(true)); } void MainWindow::close_source_by_name(QString &filename, bool ask) { editor_tabs->close_tab_by_name(filename, ask); } void MainWindow::example_source(const QString &source_file) { if (!editor_tabs->open_file(source_file, true)) { showAsyncCriticalBox( this, "Simulator Error", tr("Cannot open example file '%1' for reading.").arg(source_file)); } } void MainWindow::message_selected( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint) { (void)type; (void)column; (void)text; (void)hint; if (file.isEmpty()) { return; } central_widget_tabs->setCurrentWidget(editor_tabs.data()); if (!editor_tabs->set_cursor_to(file, line, column)) { editor_tabs->open_file_if_not_open(file, false); if (!editor_tabs->set_cursor_to(file, line, column)) return; } // Highlight the line auto editor = editor_tabs->get_current_editor(); QTextEdit::ExtraSelection selection; selection.format.setBackground(QColor(Qt::red).lighter(160)); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = editor->textCursor(); selection.cursor.clearSelection(); editor->setExtraSelections({ selection }); } bool SimpleAsmWithEditorCheck::process_file(const QString &filename, QString *error_ptr) { EditorTab* tab = mainwindow->editor_tabs->find_tab_by_filename(filename); if (tab == nullptr) { return Super::process_file(filename, error_ptr); } SrcEditor *editor = tab->get_editor(); QTextDocument *doc = editor->document(); int ln = 1; for (QTextBlock block = doc->begin(); block.isValid(); block = block.next(), ln++) { QString line = block.text(); process_line(line, filename, ln); } return !error_occured; } bool SimpleAsmWithEditorCheck::process_pragma( QStringList &operands, const QString &filename, int line_number, QString *error_ptr) { (void)error_ptr; #if 0 static const QMap pragma_how_map = { {QString("registers"), static_cast(&MainWindow::registers)}, }; #endif if (operands.count() < 2 || (QString::compare(operands.at(0), "qtrvsim", Qt::CaseInsensitive) && QString::compare(operands.at(0), "qtmips", Qt::CaseInsensitive))) { return true; } QString op = operands.at(1).toLower(); if (op == "show") { if (operands.count() < 3) { return true; } QString show_method = "show_" + operands.at(2); QString show_method_sig = show_method + "()"; if (mainwindow->metaObject()->indexOfMethod(show_method_sig.toLatin1().data()) == -1) { emit report_message( messagetype::MSG_WARNING, filename, line_number, 0, "#pragma qtrvsim show - unknown object " + operands.at(2), ""); return true; } QMetaObject::invokeMethod(mainwindow, show_method.toLatin1().data()); return true; } if (op == "tab") { if ((operands.count() < 3) || error_occured) { return true; } if (!QString::compare(operands.at(2), "core", Qt::CaseInsensitive) && (mainwindow->editor_tabs != nullptr) && (mainwindow->coreview != nullptr)) { mainwindow->editor_tabs->setCurrentWidget(mainwindow->coreview.data()); } return true; } if (op == "focus") { bool ok; if (operands.count() < 4) { return true; } fixmatheval::FmeExpression expression; fixmatheval::FmeValue value; QString error; ok = expression.parse(operands.at(3), error); if (!ok) { emit report_message( messagetype::MSG_WARNING, filename, line_number, 0, "expression parse error " + error, ""); return true; } ok = expression.eval(value, symtab, error, address); if (!ok) { emit report_message( messagetype::MSG_WARNING, filename, line_number, 0, "expression evaluation error " + error, ""); return true; } if (!QString::compare(operands.at(2), "memory", Qt::CaseInsensitive) && (mainwindow->memory != nullptr)) { mainwindow->memory->focus_addr(machine::Address(value)); return true; } if (!QString::compare(operands.at(2), "program", Qt::CaseInsensitive) && (mainwindow->program != nullptr)) { mainwindow->program->focus_addr(machine::Address(value)); return true; } emit report_message( messagetype::MSG_WARNING, filename, line_number, 0, "unknown #pragma qtrvsim focus unknown object " + operands.at(2), ""); return true; } emit report_message( messagetype::MSG_WARNING, filename, line_number, 0, "unknown #pragma qtrvsim " + op, ""); return true; } void MainWindow::compile_source() { bool error_occured = false; if (machine != nullptr) { if (machine->config().reset_at_compile()) { machine_reload(true); } } if (machine == nullptr) { showAsyncCriticalBox(this, "Simulator Error", tr("No machine to store program.")); return; } SymbolTableDb symtab(machine->symbol_table_rw(true)); machine::FrontendMemory *mem = machine->memory_data_bus_rw(); if (mem == nullptr) { showAsyncCriticalBox( this, "Simulator Error", tr("No physical addresspace to store program.")); return; } machine->cache_sync(); auto editor = editor_tabs->get_current_editor(); auto filename = editor->filename().isEmpty() ? "Unknown" : editor->filename(); auto content = editor->document(); emit clear_messages(); SimpleAsmWithEditorCheck sasm(this); connect(&sasm, &SimpleAsm::report_message, this, &MainWindow::report_message); sasm.setup(mem, &symtab, machine::Address(0x00000200), machine->core()->get_xlen()); int ln = 1; for (QTextBlock block = content->begin(); block.isValid(); block = block.next(), ln++) { QString line = block.text(); if (!sasm.process_line(line, filename, ln)) { error_occured = true; } } if (!sasm.finish()) { error_occured = true; } if (error_occured) { show_messages(); } } void MainWindow::build_execute() { QStringList list; if (editor_tabs->get_modified_tab_filenames(list, false)) { auto *dialog = new SaveChangedDialog(list, this); connect( dialog, &SaveChangedDialog::user_decision, this, &MainWindow::build_execute_with_save); dialog->open(); } else { build_execute_no_check(); } } void MainWindow::build_execute_with_save( bool cancel, QStringList tosavelist) { // NOLINT(performance-unnecessary-value-param) if (cancel) { return; } for (const auto &filename : tosavelist) { editor_tabs->find_tab_by_filename(filename)->get_editor()->saveFile(); } build_execute_no_check(); } void MainWindow::build_execute_no_check() { QString work_dir = ""; ExtProcess *proc; ExtProcess *procptr = build_process; if (procptr != nullptr) { procptr->close(); procptr->deleteLater(); } emit clear_messages(); show_messages(); proc = new ExtProcess(this); build_process = procptr; connect(proc, &ExtProcess::report_message, this, &MainWindow::report_message); connect( proc, QOverload::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) { if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) { return; } if (machine != nullptr) { if (machine->config().reset_at_compile()) { machine_reload(true, true); } } }); auto current_srceditor = editor_tabs->get_current_editor(); if (current_srceditor != nullptr && !current_srceditor->filename().isEmpty()) { QFileInfo fi(current_srceditor->filename()); work_dir = fi.dir().path(); } if (work_dir.isEmpty() && (machine != nullptr)) { if (!machine->config().elf().isEmpty()) { QFileInfo fi(machine->config().elf()); work_dir = fi.dir().path(); } } if (!work_dir.isEmpty()) { proc->setWorkingDirectory(work_dir); proc->start("make", {}, QProcess::Unbuffered | QProcess::ReadOnly); } } qtrvsim-0.9.8/src/gui/mainwindow/mainwindow.h000066400000000000000000000126531467752164200213360ustar00rootroot00000000000000#ifndef MAINWINDOW_H #define MAINWINDOW_H #ifdef WITH_PRINTING #include #include #endif #include "assembler/simpleasm.h" #include "dialogs/new/newdialog.h" #include "extprocess.h" #include "machine/machine.h" #include "machine/machineconfig.h" #include "scene.h" #include "ui_MainWindow.h" #include "widgets/hidingtabwidget.h" #include "windows/cache/cachedock.h" #include "windows/csr/csrdock.h" #include "windows/editor/editordock.h" #include "windows/editor/editortab.h" #include "windows/editor/srceditor.h" #include "windows/lcd/lcddisplaydock.h" #include "windows/memory/memorydock.h" #include "windows/messages/messagesdock.h" #include "windows/peripherals/peripheralsdock.h" #include "windows/predictor/predictor_bht_dock.h" #include "windows/predictor/predictor_btb_dock.h" #include "windows/predictor/predictor_info_dock.h" #include "windows/program/programdock.h" #include "windows/registers/registersdock.h" #include "windows/terminal/terminaldock.h" #include #include #include #include class MainWindow : public QMainWindow { Q_OBJECT friend class SimpleAsmWithEditorCheck; public: explicit MainWindow(OWNED QSettings *settings, QWidget *parent = nullptr); ~MainWindow() override; void start(); void create_core( const machine::MachineConfig &config, bool load_executable = true, bool keep_memory = false); bool configured(); signals: void report_message( messagetype::Type type, QString file, int line, int column, QString text, QString hint); void clear_messages(); public slots: // Actions signals void new_machine(); void machine_reload(bool force_memory_reset = false, bool force_elf_load = false); void print_action(); void close_source_by_name(QString &filename, bool ask = false); void example_source(const QString &source_file); void compile_source(); void build_execute(); void build_execute_no_check(); void build_execute_with_save(bool cancel, QStringList tosavelist); void reset_state_registers(); void reset_state_program(); void reset_state_memory(); void reset_state_cache_program(); void reset_state_cache_data(); void reset_state_cache_level2(); void reset_state_peripherals(); void reset_state_terminal(); void reset_state_lcd_display(); void reset_state_csrdock(); void reset_state_messages(); void show_registers(); void show_program(); void show_memory(); void show_cache_data(); void show_cache_program(); void show_cache_level2(); void show_peripherals(); void show_terminal(); void show_lcd_display(); void show_csrdock(); void show_hide_coreview(bool show); void show_messages(); void reset_windows(); void show_symbol_dialog(); // Branch predictor void show_bp_btb(); void show_bp_bht(); void show_bp_info(); void reset_state_bp_btb(); void reset_state_bp_bht(); void reset_state_bp_info(); // Actions - help void about_program(); void about_qt(); // Actions - execution speed void set_speed(); // Machine signals void machine_status(enum machine::Machine::Status st); void machine_exit(); void machine_trap(machine::SimulatorException &e); void view_mnemonics_registers(bool enable); void message_selected( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint); protected: void closeEvent(QCloseEvent *cancel) override; private: Box ui {}; Box ndialog {}; Box central_widget_tabs {}; Box editor_tabs {}; Box coreview {}; Box corescene; Box registers {}; Box program {}; Box memory {}; Box cache_program {}, cache_data {}, cache_level2 {}; // Branch predictor Box bp_btb {}; Box bp_bht {}; Box bp_info {}; Box peripherals {}; Box terminal {}; Box lcd_display {}; CsrDock *csrdock {}; MessagesDock *messages {}; bool coreview_shown = true; QActionGroup *speed_group {}; QSharedPointer settings; Box machine; // Current simulated machine void show_dockwidget( QDockWidget *w, Qt::DockWidgetArea area = Qt::RightDockWidgetArea, bool defaultVisible = false, bool resetState = false); QPointer build_process; bool ignore_unsaved = false; #ifdef WITH_PRINTING QPrinter printer { QPrinter::HighResolution }; QPrintDialog print_dialog { &printer, this }; #endif }; class SimpleAsmWithEditorCheck : public SimpleAsm { Q_OBJECT using Super = SimpleAsm; public: explicit SimpleAsmWithEditorCheck(MainWindow *a_mainwindow, QObject *parent = nullptr) : Super(parent) , mainwindow(a_mainwindow) {} bool process_file(const QString &filename, QString *error_ptr = nullptr) override; protected: bool process_pragma( QStringList &operands, const QString &filename = "", int line_number = 0, QString *error_ptr = nullptr) override; private: MainWindow *mainwindow; }; #endif // MAINWINDOW_H qtrvsim-0.9.8/src/gui/qhtml5file.h000066400000000000000000000044221467752164200170530ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QHTML5FILE_H #define QHTML5FILE_H #include #include #include QT_BEGIN_NAMESPACE namespace QHtml5File { void load( const QString &accept, std::function fileDataReady); void save(const QByteArray &contents, const QString &fileNameHint); } // namespace QHtml5File QT_END_NAMESPACE #endif qtrvsim-0.9.8/src/gui/qhtml5file_html5.cpp000066400000000000000000000220171467752164200205170ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qhtml5file.h" #include #include #include // // This file implements file loading via the HTML file input element and file save via // browser download. // // Global user file data ready callback and C helper function. JavaScript will // call this function when the file data is ready; the helper then forwards // the call to the current handler function. This means there can be only one // file open in proress at a given time. std::function g_qtFileDataReadyCallback; extern "C" EMSCRIPTEN_KEEPALIVE void qt_callFileDataReady(char *content, size_t contentSize, const char *fileName) { if (g_qtFileDataReadyCallback == nullptr) { return; } g_qtFileDataReadyCallback(content, contentSize, fileName); g_qtFileDataReadyCallback = nullptr; } namespace { void loadFile( const char *accept, std::function fileDataReady) { if (::g_qtFileDataReadyCallback) { puts("Warning: Concurrent loadFile() calls are not supported. " "Cancelling earlier call"); } // Call qt_callFileDataReady to make sure the emscripten linker does not // optimize it away, which may happen if the function is called from // JavaScript only. Set g_qtFileDataReadyCallback to null to make it a a // no-op. ::g_qtFileDataReadyCallback = nullptr; ::qt_callFileDataReady(nullptr, 0, nullptr); ::g_qtFileDataReadyCallback = fileDataReady; EM_ASM_( { const accept = UTF8ToString($0); // Crate file file input which whil display the native file dialog var fileElement = document.createElement("input"); document.body.appendChild(fileElement); fileElement.type = "file"; fileElement.style = "display:none"; fileElement.accept = accept; fileElement.onchange = function(event) { const files = event.target.files; // Read files for (var i = 0; i < files.length; i++) { const file = files[i]; var reader = new FileReader(); reader.onload = function() { const name = file.name; var contentArray = new Uint8Array(reader.result); const contentSize = reader.result.byteLength; // Copy the file file content to the C++ heap. // Note: this could be simplified by passing the content // as an "array" type to ccall and then let it copy to // C++ memory. However, this built-in solution does not // handle files larger than ~15M (Chrome). Instead, // allocate memory manually and pass a pointer to the // C++ side (which will free() it when done). // TODO: consider slice()ing the file to read it // picewise and then assembling it in a QByteArray on // the C++ side. const heapPointer = _malloc(contentSize); const heapBytes = new Uint8Array( Module.HEAPU8.buffer, heapPointer, contentSize); heapBytes.set(contentArray); // Null out the first data copy to enable GC reader = null; contentArray = null; // Call the C++ file data ready callback ccall( "qt_callFileDataReady", null, [ "number", "number", "string" ], [ heapPointer, contentSize, name ]); }; reader.readAsArrayBuffer(file); } // Clean up document document.body.removeChild(fileElement); }; // onchange callback // Trigger file dialog open fileElement.click(); }, accept); } void saveFile( const char *contentPointer, size_t contentLength, const char *fileNameHint) { EM_ASM_( { // Make the file contents and file name hint accessible to // Javascript: convert the char * to a JavaScript string and create // a subarray view into the C heap. const contentPointer = $0; const contentLength = $1; const fileNameHint = UTF8ToString($2); const fileContent = Module.HEAPU8.subarray( contentPointer, contentPointer + contentLength); // Create a hidden download link and click it programatically const fileblob = new Blob([fileContent], { type: "application/octet-stream" }); var link = document.createElement("a"); document.body.appendChild(link); link.download = fileNameHint; link.href = window.URL.createObjectURL(fileblob); link.style = "display:none"; link.click(); document.body.removeChild(link); }, contentPointer, contentLength, fileNameHint); } } // namespace /*! \brief Read local file via file dialog. Call this function to make the browser display an open-file dialog. This function returns immediately, and \a fileDataReady is called when the user has selected a file and the file contents has been read. \a The accept argument specifies which file types to accept, and must follow the html standard formatting, for example ".png, .jpg, .jpeg". This function is implemented on Qt for WebAssembly only. A nonfunctional cross- platform stub is provided so that code that uses it can compile on all platforms. */ void QHtml5File::load( const QString &accept, std::function fileDataReady) { loadFile( accept.toUtf8().constData(), [=](char *content, size_t size, const char *fileName) { // Copy file data into QByteArray and free buffer that was allocated // on the JavaScript side. We could have used // QByteArray::fromRawData() to avoid the copy here, but that would // make memory management awkward. QByteArray qtFileContent(content, size); free(content); // Call user-supplied data ready callback fileDataReady(qtFileContent, QString::fromUtf8(fileName)); }); } /*! \brief Write local file via browser download Call this function to make the browser start a file download. The file will contains the given \a content, with a suggested \a fileNameHint. This function is implemented on Qt for WebAssembly only. A nonfunctional cross- platform stub is provided so that code that uses it can compile on all platforms. */ void QHtml5File::save(const QByteArray &content, const QString &fileNameHint) { // Convert to C types and save saveFile( content.constData(), content.size(), fileNameHint.toUtf8().constData()); } qtrvsim-0.9.8/src/gui/resources/000077500000000000000000000000001467752164200166405ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/resources/icons/000077500000000000000000000000001467752164200177535ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/resources/icons/application-exit.png000066400000000000000000000047351467752164200237440ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î< ZIDAThÕšMlUÇÇgî{nLbÛØiÀM¤l¢¶RªÊRª$›w×.º¬‹æCŠíàV¤›|¢J­`_©Ë.’lZÅd“¦J*, Àh) 6Û)16~÷œ.fæÞ¹ï=;‰bštÄpç^îÜùÿÏ÷ÌCÌŒÿçæ¾i_·ÕÒÉ€@ƒo9nKf–LJÙðãþ-}¿òûÛûzÞÕµ¹¿:_@þGP­ø«h7n|þéÅ+3oL>ñ¹bfËbfQò[ÿöË‘ý?ºÓýªù¯SèµÐq,Åmµ}Uv¶Ê­U „±ëî¡6ô|¦þÙ_þ¹¸jfy4“M@ÿÝwŒ.|Ÿæü5A5Aq¨ø«Ièd˜¤Ý}Ş̥œŸ®å×EhÎ_céäû<Ð}Ç(Ð0&TzîüìêÖ[¹ˆg.Æ‚ kÕÄz4i‘¼)Et4ÀÌ¿¤ÆŸ]Ý ôS°!_¹…Z4ÁyàΈÏýŸõ!a¼˜k,¦^òÏó•[æ‚€¢_/Á›¸Ü!‘@èëšA,€Ç‚–#pJªV¤%ŒZÓ0D/usxd¤ÔÎ:Y‘Eéºùï[4-ÇÖ¬Š-%àÔÔ›P4 u«hÀ>PÈâk¡ßˆÀ4â1L¢V<15…$GU5 LQ0)¾4â0‰öX¥“b›€‹7'ÿÀÓP­LO ˆæŠª .DÌb³„Ptßus)C¿áMÈœD¦~mLÍ5ÒJUà47Ô]Ê8ïã÷‹w 7˜ïêáÆž`EIæwî+ 7~øs]=äÉs ¨È=–Ž¥üFn·¤ õÄy°^EˆNºðß=ø&C¿;ÄÒÈ(M­¾“ö¦ÂÒÈ(C/⾃o2ßÕS‚/ƒPX[ÂÚI*H0¶j¯E•¤{ï¯>U#W˜ßÜÃöƒo°©il`è…׸92ÊJÞ>g%‡›#£ ½ðÒØÀ¦þA¶|ƒ¹Í=äá›­süÚR}žW¸ª\Ké¯"E f²Ðu7Û½ÎƾTU…zƒ¡‰,좩†™ïM5–Gv14qêâý}ì8ô: ]wǼµúºSÞYpªV±Iµ •ÄÛ¼1×ÕS€ c—Fƒ{°42ÊŠz›_eÇÞH£Ñöþƾ¶zù®ò°†_+];ñ#-|ÀAkjªOdÅ“`ø1‰±h0Û;Ì6Wcã*»9©7Þ»Ÿ á߇÷îGê VÛýÝt5fz‡©]¿Êa-3@CbUŠ«6«Q¨J@ ^#éU}þ_õeajì)žü㟸ëž{:‚¢Þ`hïþb¼ø¹ÙY?Ž—OSßàŠõM"ÉU´sB"Km±°ÉRåÎ`°á¸÷Ò)¦Æws}v¦Í,b§Þ(Àwê×gg˜ßͽ—N1Øp¸–µ:bY3 5[£Pç.ÛꃟfêùÝ\›¹R8æ—í×f®0õün?>Ͷz†tŒvzs(”:±F'ŽU„¹à\‘ÄÀÅ3LíYS%?¶‡‹gªà£ã8’õ«Nܦ‰5 ]Öaœ^ ‡1Pw ^:ÍÔØ>ŸŸûBðŸÏÏ15¶‡ÁK§¨;-&Óv­Ž“<ÐVNûZ('ÖS3,8qqSqôfŽž;©Õê«:klµZ‡wî¤öÉY/ùôõ"ÝR>yyOK-T­Fs+¼½½Ç•ÄCIðØ(þæUø26mâÁß¾Êyæßß"«l'ã¸ÄÑvͫ߯ìÈò…ªaÔÏ‹ûärÜ }lß›|Ëj É/hYû'_áœZ(¿ Þl:)Ãh*™[iJ¼ørìñ]ìœ|™ÜeÞ ¿Js÷O¾ÌGúÎ[dRšO™ÈÀBY¯²J"óÐr­šRfáB4BØã?eçäËè’Ÿ¿: À–­“eµ@°wÞò»ôVjIh‰´•Ó.™¸-”&áuEÅGexò%4ËV6s³3L?ÍÔøÓÌ­b5Ëž|‰ÅGe% ãÚ!„äºf5jX¨?Škˆ~l,çÆ¹ãǘ>~ U]ü¶ gØváÌš$T•éãÇ8wü˹ ´¬`jqâ <ï¤T"Ð@\ZäÄ‹ãœýàH‰¹ÙO<™Ä3Òx^Ú¹|øzø­pÚÒ”’q‡ÖæÄ¦æ¥l% ¢à¡¬ên‹lu"PbZõT"=“OIDàqözý0ÐÊÁR3JˆÄgÇÊ è§* ½Jw˜ÿ&!‘<»m-1•VðWT  v‘À2°ðžÚô/êG¬Ùô‡D±Ý&á·ƒ.øuCj5ÞËuX˜ ‹ÀÅ¿®4ßmRßü“›îȲïˆsà’e¾Çû¤Ó6Î’ûÀVý¾ûº Þ§ãÊ}žcyùî'yþŸ,ߺ4µÒ|ÿ å"PüÐ-@/ðð0°¢)}kÚø‡À)`ÆÌL¢ÊDÄw}xðoçªížÄ`ÎÌo~¥ÕæD¤†7­oãöhšY3}ø_Å1…ÀÞfÝ¿IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/build-256.png000066400000000000000000000454031467752164200221000ustar00rootroot00000000000000‰PNG  IHDR\r¨fbKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEã 2xŽ W IDATxÚíwœÕ•ï¿·º{rRš$‘$¡`@€1Ù`ÀpÀÆáÙ8ì:‡uZð:›uö®ÃÚüö9­ßóÚØ,Æ8€É9ƒ$ÊšQ˜ÑäÔ]÷ýq»gª«oUÝê<3u>ŸÑŒºº«»«îùÝs~'ňd:Ëà4ÀŽD—#’Hf¶Ä€WÿldúÇ~ÔD—(’Hfž´Ÿv8”^÷s°0º\‘D2säÍÀÞÅwþì^]¶H"™ÞR ü&„â;F÷E—0’H¦§àú<•ßùó㈈$’é'ôSì¦òÕ‹…üʉ–|Ó2÷G¼@$~;M$Õ% `;°Ä}`n ¼óX‹W,ÔÆ¦¿³Kò½-6c)ÏsîÞ<]ÞH"¨n9 xÄýà™ W­µhŒë_ô€äšM6]#žç>üŸèG’‘Xt ªN.^ï| 9?xiŒzŸ»5·VðŠ…Ûúa¿âÀeiwà ]êH¬èTŒký[­%ßXoqÅ2ß'¸3â"‰ :åE÷°åˆ4»¡Þ·Ââsë¬,žÀíQgD—;r"©.Ù|hp>ØZëç™S6Ë›/›/xì°d0©}J3p%p ‘DIˆÖ'fùø5‚ó:Ãq¶s2¼À€'/Kó‹€[#^ r"©9è~`8OÕlIÀ7N¶¸b¹ð ù¼?Í ,Š.}‘TVš€7ºì¨+à& xßñЍó¶ùÎKó‘DI¤•¼Ì}`íœÂS6Îëüॠë=Ÿ²0m | ºIyåDà6T"P–4'àS«-âE€ë95‚ Z¼àÏ \ ,&ʈ ’’Ë\àËÀOvÝ>ºÊbUkñ’6kcpA§`†-Þ}„N^Ü ôE·)€HŠoîø-p!*S/G.^$¸òX«è9ÛB¨°âÒFÁ£‡%Iéé¼xØݲ")\_~\xÒ{¯Y,ø»Õ±Vl,oœ¾@ð¸¾À;€C(’0’$Q1Pù®óy(rírjôk,øØ*‹W..ß혀oeUZé¯$Dþ|m ^Þ)¸t±`eqýCcðÌÉ3}’gûÔn=”4D,+[TaÑ ­‰¢ð£Ò—#^`À À9Àj`p<°œì¸öð,Š@úpÓ/ì-í÷¾‹uôË›—,\¸Px¶ôò“þ ØÔ#ÙÐ#ÙØ#Ù3\œ/TcÁ¥G Þ¶Ü¢5 wð=Ý’ï>m3â}׺€+PÃI"™Á0?mî¾ÚêÈãû€ÿ~†qU­2x]zw»-¶k,8·C)þš¶ð—yÿל€ó;/¬h ·Ûw¨¶ÞwuI¶ÊŠ/ˆ¥ðÕ“c~ƒØ~±ÍæZ^à‘´å´'R³éWGqJ™äT—šûÓ?Å"˜êPqúÓQµïç¥Ýšp¨!à”yJéÏ\.„×3÷¤•þ™>_% ü 1‘}m@J¥¤ùž·­®9Éâ„¢òÞnÉ?ûóÝi«ñÞHÕ¦ü#*WÝX¬h,k‚Å ‚Å j%ŒÙÊŸÝÜ+¹ï€d`"ïϺØ’þy. Ýi·Áiˆ£ò×€¥(–~Ь\Ö¬wÊQpÑ"•°3¿ÖüuCI¥0wvI6õJì<´3& nA<­ø’)E·ÓJo;þ.Dj-¸z­Å9þ °cPò•M6û¼]–‰4/ðo‘ºM8,zá1Í‚3ÀIs«Úµ;à„ ÷ܼW²¡W"åô¸HË›ç´ÃÙ‚£›ÌM|)aC¯ä¶} üFóˆ{ÔX韘òU2 .]Ê®b,Ž÷®l3nÊ ü<Í ŒFjWÝЃ"ýrdn-\¾ÔâìÁ¢úÂÞxÒ÷í–l¨>$8®YpN‡àœvÁ’Æp¯Ý9(¹e¿äŽý’ÃcáoHm êc‚K•íÚRf)øäßs_Å’·,üÍñþ%ÉRÂÏ_°¹öň˜îð4*¦Ÿ#q >¿Îâ¬öâæíRæñÇ$[ûeQ¯11ƒum‚õóg¶ _L'ý ÐnÝ'y®_æõþ qA½¥îŠœTd™«ðÅ×YÅ”W-|ò+0k1â¦?< ¼ÔϽz­Åù¥I"쟀ÇK6õH¶‘ì¦$®BSNhœÐ*X7V·†ÏÅOJxôä–} ¼’vx?»1¡’ƒ2æ½”nß^æøúNe—n@)0ôµG >º*ø"E¼À Pìó'W«–RË`¶öIv®!É®!è•ôލpBÀœ˜_«vôeM‚e*V¿¸1ÿ4Èmj§¿£KÒ2ɹƂ¦„ 1¦,*éPzçîî©ü~ŠïˆRQŸZmñ*ƒ>ƒðÍÍ6òý$¿@…™#^`:@æ…]eqÙQ•«'êWýòGSS»oÌRþs­¥¦é«›Î`îÜ/¹i¯d[HÎ"&T¶]sBõžTxôÛ“€ sÍ~²Ã|^n@©¤>¿<'XCá~ñ‚ÍoüyGQMR"^`:@æÅï[añ¦e3³¨P¢Â—7í•ÜÛ-³Ã]؆8´$¦òÿ½Þm8w­òãr4.A)åÊcTŸBSy(Ý_À§`éªÎâŽH%Ë+ºŒ·÷¡úÖÉã‡%ãv¸¹uÕ.½ãð§Ý’ïn±¹n§dû ¤ •ª6¦FuwÔ ZS¼‚[áÝH3 Žãî¿Ý¿3܈.!¸(„û·¤Qpv»Å†IŸ>¤x;*—ãþH-§<}„iR*òñ§ÏK~øŒªïŸ0U•øÔ^'˜W+¨³¦L+é8ÿ¤Bkvþ, Hïþ9À §Î•%ôûuÖÍ–†cL[jàÂ…»†UÔGG-¡Ò±Gµ"ŸˆÔ³ô/Ö‰®Ý!NÙ|t•5­ºŒ NÀM{%Øms`4œ4¦Mü†¸ú¿vWv)kÎÿ5@ 5Ê­}$pN)ea}~w¸!_>Ñâ·;$?Ûf{Y+oG…¡/§|õ Cþ¸[’²m>n/®´ì†ßï²¹u_¸ ½„­ Uéç$mE¡3ÏuÿÏæd®Å ÝùËtí S&P‰EË-¾åÍ œŒ"ß Ü©i•»Ny~ö Ãí«Ê@@z$ÿþ¬ä?ž³ÙÚ‡Q½šã*œ8¯VPW!F÷N¬Û…½¬©µd. swzÏße@€–\µÖ2n+æË tòÿ+⦼8{†àÌ*”„[÷K¾³YrÝNÉ^ÃZû Újóë a<›OúX:¿Þ­ün¥÷"Ñ<¯Ô¾ÿ'WW †“‹Ìx/Pº{êã0`œ>_ðÅ-j*ÔíVJ¸÷€äÛlã–€†˜ÊÐË89/Rk#5–€Ö——»¿o^€W¶`éÃøð*‹×• ïCB/°!⦜6Oð¥“,£jÁbÊæ#’=#yѰÉF\L¥å ¦~2WH\44;°§% ÝîC¶òÛ~Àö×c¥ú||µÅ¥5ç>(ýxPù/Pí.€SöÀæ#pn{yúÞ'á‡ÏØüÇV•.lbæ7' ¥FLY*BïËg޹Íqò{úì2w×=Ÿ cû$ Î5(¶Û,øÖú'Î-½/ñ3ŒÂ†8§C¥Â–Jv ÁgŸHñxOðskcÊmˆ«Ý@:ìûIÅ 2ù=”/r"20"€ôê,ŒbJ] Þv´àêµmµå[/0Ã\§×"øæzË(<¬<Ó'ùÌã¶oH/Sk_—n®!í´2‹ô„Îìþ.¥w[Y&¿Î%Ð-Í8bˆ%ࢅ‚wg…êxT!^`#ð†ˆ˜&°¬¾}JŒ¹E\\{‡á¤¼ÌÆIS¿Æ¥øBó7Nÿé…Á…óÜý']z¦ò×dssÅ3Ûï9ÎbYcõ,P^à0ªŽ âªÕpJß”ÚR¡}v}÷ßÒϾá|m÷ÎÃø¸H|wÿ¶xËr‹Ï®S½›Óc¡&,e©ÔÆ{=¿ø:àààH¤ÞU ¸·[rê|A[M~a¦G¡]µe ¯mÜCñÝQ€œôÞ"À­œ^¡@t¦¾Ô¹ÙþØQ¼ç8‹¿_kqòÜÒFcJi®®mSÃW=¤ÊÐ5Ò‰Óþ°=Rñ*€‘”ÊÖ;ež`NmxØ7Ô›ÞB·ÛXn¥—»¿4ØùñPl/À–jšj˜„!T6æWZ|d¥ÅÊV1òœÎ²¤ApV0/ðvÔh²ˆ¨FÀ-MqøúúðyæûGà]÷¥|•Àrùø^Q'¹‘¬‹fú1=Êuu$ Û°Q}ÃfùµÕ¨.¾—,¶è¨ÿ¾wö+eíŸj®b Õj¾£^°¤!|û¶ˆ˜A*åôO²Bg}~ƒóIá/Ò/féÀ¾<€ã¯f¥Oå1ÝgÝÁeKg·›.S¤„]ÃðlŸäÙ>ɶ~Ø3,ýBx“RƒÕmjÌÚæÜDˆ|Ë#•¯b•¨sÍIëC€ÀöAÉG²}K{M,€œ<]TÀqÂB‚píúR¶yë±I[7.TŠ¿¬©üöýî!ØØ#ÙУFž !/¯Æ‚W/¼í‹¹†aɇI¾ý”Í ¾À[Û"µ¯bÅø~á%g,0_Ð×ï’üx«øeMÌ}B÷E ]”þ'£ôÉ<Øüãš—.œ¿PP_FB/iÓ½’J:(é.aCïú8|x…Å+›­ƒ½Ãð•)vy>%|øv¤úU  w>·ÎâlÃ)Døç§U‡rLø‚—ÿ´û Åwúùɴ§òPúæ\C~|Kùvûq[ @¹«KòèaÉp²¼káœÁ'N°h6p "^`†@†$úô‹‹š-ö”„¯>ióÀiôŃøðN2åR2û'ŸkpÊ\ÁÅ‹Ã!/DRRuOº«Krÿ3?¾”2¿®9Ñ2¾ˆ˜!Q€Ož`n&m5©öÞ  / rl9Eॠ(Ò9ºI™÷aÇ"xúˆRú{º%GÆó?WLLe^Jǵ)¤oA] >»ÎÜ5|ää[/0½ ó!?´ÒâõKÍ-yÆææ½Òøüa¢Â± !»Tyùõp~§àüNÁò2z/ ¨1gwwÉP‘ݼM\€e©ä’R .µ|p…ùZˆx™úþo 1…è÷»$ÿùœJ1ÝJ¯Û&‹Ù€££NUáש•–Kí{ÆáŽýj°éŽA™—"ÖZбwÎ8´5“‹J1·ðŠå‚÷oÖ‚~$ ÿô´Í}þVáo€¿m¼À´€Œ¼e¹ào7w„ŸíSãªw UÏwXÖ/[ 8}`M[ù”~ÜVY“·í“'Íœ2OpÚ|QpdXÙÒ§”þ®nÉ`È8}¦IjC\µLË™^¬Uî²J9¸ôÔy‚¯œdÞxÖxpkU,—¥gÕ‡Ù=ûÆáº6ÝWÁeBV­h¬£üÚÊŸƒpnÛ/¹u¿Íž¡ü”¾1>U4”Û…Èr±2[^:_€é5Þ; _Ùd³ÓÛõ™5¼À´€×,||Uø)DI[5%yð€ä‰Éá±ü?Cm –6 –7)¥_Ó G7‹¢%#céªÛöI6ôÊPÊ–™fÜ”4Äô½ rv×4—BÞ¸LðæVáHRåÜÌ ¼Š Jå‚NÁUk­‚nÏì’ì†î•Î:”T†3YvM eÊ·×¼ZÁ¼:8ªQ°°ŽŠAÛÚ¯F˜ßÕ>I§.Í AS\íü~JïÜý½æhŸâ€^ ùû/µX¢˜,âfœ×!øÌ:kF”ºšÊàÜÖ%¹yd{H?.Ô´Þæ¸J, jNjãîO(sBkþ—ØÿwËéó_=9|¦Ôlæfœ¾@ðÅ—Tn Q9D¢òðoÚ+¹¯Û³!†çnJLM36êC€®±ôìLì§ø² PkÁÄò²ÈBðß¡|sX##•šBTjéƒ[öKnÞk³/d”º>¦†ž4ÅU94x—"›4'õÝýÑO+*µÿï”ÿ>'Æüºü^;’‚Þ<»x jâ¿v’E}|úߜͽ’ëw©Ê»01û¸-qµÛ;M|0oM¦³ÝßË%(5$,¸þüXA€!/ðdšØ@ÊÊÁ7Ö›UU›$m¸«[)þ¶~êF6Æ&¾FéÝŠ¯‚ å7Rªs J-«Û?8­8æß£‡$ßôçzPuÓš¨xOÀRÈá1x¢Îîϱ/—ôÃõ;%ßÜlsÛ~Iah23Â|A ¹&·ZPº ¨M¹§€Çèré:×4¤2ȇWZ,m,¼¸ApN‡Å†^uotÞjÁð@dT¡”b Q±e×JNºc¿9©'€Æ„bñkcy¶' ˜O bjûƒZ·  “‹3rf»à+'Ÿü1ä®EÕ EPe²¤Q ™_e Ð=¿Þ¡*MÍãK¥äfbö^%Êžàa ø‚éoe0ÿ×Í|ýd«dÖÞLæf<@ñ¦C“ð‹m6ÞcFì TRS:fï,YvßÀÐó eî´á,0p)¿×t"2°TòòNÁ§W[e™sðè!å¢ùÔSô òn‰8€*’Ì¢—-¨,1xW—äKl6ö›Ä–P©¹m5‚ú˜Àr4(0n4§@z 9ɉH_.±eh~—Bj-øè*‹¿=Þ*[äÅ ‚sÚ-6öâUK2íxYaddn |뫬Í6&lø?ÏÛܰ+X&KnãSó Üãʽ”„1iAp/3ºÜ+2Pl9y®àc«,–ThŠñH*]GÐ=ýyY †f|k½Å1ÍåÑüÃã6[úü5!nA½¥bÙÞó 4@àSåÏ ¢_jt¹Ïi€÷oqf{ås¾g /0ëÔ¢o¬·XÕZÚ…”’ðå6ø -‰ UQ!æ"ý`Ø&¥ú)E2Û¡ü~Š_¬äŸùµðŽc-^¹¨2U–3™( òø)—ŒÛpO·dÝA{]éÞùÖý’ëvJÏëSc)å·|4Yº—:3> A1÷Ü£2ç\^yî˜äªü ëá]é¦'´¦y*“éÎ Å0 G ŸÅ˜³Peðó &’ò˜Bd*¶„¿¹?ž=Áçdô3»½åaúçÌ+Иý9ßÀa!L)° °ôu^í[4”ÿ½;¾Eðæe‚s:ªSé à~ üM5ñy€—ïi:1Çx‡ÊÚ­JùL!2‘îQ¸òÞ”öÚÅ,󥺶å`6±(.Àxb±Òçãû T{¯+– Nš;=ëº3¼ÀÏ·Ù~ägUñ¡À}·2Yœ9æn !ì"ÙÒ'ùÄ#¶v÷w+¹%Ìß$ PHB%á›OÓ¸P±ü+– Žnš =œ®#˜¼€0¹H£¶;XæXÖ(n÷óœ‹ÙMxyð8ž‹nl—(N7[ªVZõ¢hÑÑ”àÆÝRn"0}Ù<‘ýºÐI>!­¬œ~“2aòï÷?·._&øÌÚ-Ì©™9Ý\¦/`ddÛÈ ù™ÿž‹T[²HVAØ)DAßá­w§è÷¾ð9;¿ÁàRÐÏ-t_Ý=šÿhIEƒ2á” ?Â\'ÎU“ŒÏh3¾ƒ“!/p#p%Ð_µ€%¦~r¬á²ð°„Ï—€Ëp‘d~å«´”4׈‚C„HÂæ#†ì² ¤F‹éó.ŸÞ+:T&ìÙ”­&'ípcÏšâpéÁUkb¼q™cnÍ‚öm ÎíÔÆ›z¥×õZ™ænU¥àœóæÇ@í@…Z^;•—Ïê6eÃ\”°Sˆt2”„wߟò*'Íõñ½ˆ@· #󰾤Ÿ%à ô’i¥{W¶¨æ/ïeÉÕ#=ãð|Ÿä¹~É®aè#ª©êXšºiJ¨ìÑåMjóË–å™}hÀ ô§-«âÂcáy,:¡y'a¸=w(/5ÀlÍ®<ÖâÊc GK¾°Á7[ÌØü×'ùRF ë¾¶“J/çòÖÆ©wÙÁŠ–êÙæ&`cäñɆÒý#ùgy“àò¥‚W, ?©yß0\³ÉæEテÕs𳔩‚ÄÓƒÁÀ ÁoÊ Öº@v ‘N~ó¢J5¹Zk€Ü¨€Ž?Ô¹>Âðú¢ô«Z/R»}S•´c;8ª2õ<$yü$YD•꬇Ÿ`qʼp+|$ß}Úæž*ጠ!‚ž§`àøTyYnpд½2•×%øHÈ)Dnùñs6×ï”á@ó<ß ¡¿¶"/)ó+Ù[£æó]¼HùõÕ ½ãªêòŽ.És}²äÛèE ï_iÑ¢ÊÔ0_àÙ47ðlÅ aeg®y)½ð0õ‹’$ƒ-/ò*(£ÍDòBäü?Þjóû]f €Æpg †å2¬}Fñó‘Kõß¿p‘à¥ó«#7܆ûº%·wIžÈcèi¡2§F呜2Éx'ð‡Š@Mz ´çŽãSšê5f[x(»ùDºÍ{? ðJp ’  ®ZSØ¢_¾`ó«íf;“—â›\{[æÆéóKÀú¹‚ó;gµç6­”ì‚?ïµ¹eŸšæ”¯Qx9&à=ÇY\±<Ü´ç}#pÍF#^àséÛYȰ¸ù2Ñy¥©ºÿ/ýãÖ~Šïç „ó:ŸY[Ø¢»º$ßÝb3– £„ð÷í‹Ug XÓ¦òñÏëÌ©©¥OJÕÜåO{$›z›ø–˜Šje.Z¾ÉL:9«]põšpmé y?ï(6/`µ1ÕÅSñüмÍfécšÿ^;}P¹«Ÿc ÑŽAÉ?=-y¾¿z†ÌÔXpò<ÁY g,´ÖTÍGãÐܾ_rãn›ƒ£á^i+½†m—Ò»›˜*Kàš“b"dhÈ l^_L^ÀêbþiÅ´Âå°{AP~»Ÿc QJÂu;%×¾èÛ¾¤ÒQ§Ìœ:OpÊ<19 µDJxøÚí=nÚqÂR›VM:+Í=ª\º P7É-M øüºðQ‚ÇÒ¼À@™x#¨s€NñuJŸ] ’Ÿ ]f€‰`¢øàßÜÂÙîÊOŠ5…h`~·Ã榽’¾‰Ò*Uk ¬n¬O+ü’ªN†’pó^µÛ‡‰×OµSľ³ ½@ ˜ðé5. ·þËÉ @}„$@h^¾©±Öü’Z!¬5mª%u1ˆ± 8(¹§K²¡Wú±ÃFR‡¥‚ͰªM°ºU°¸ ÞIêý~·Ímû$#!ø‘º4ÆÕÛ5ÁX7ª<Ç(aûr|fÅá@`4]G`À \ ô•âÐËfM³vZT‰‚|Ë‚¥4 ,x4¼ô» Ç·¾¹Þ¢¥ˆ‡m Û$/ ÀžaÉž!U[0<#é8WÜ‚º˜ZøíuªÂn~­`Q,o´×—·ÓR¾VÞc‡$7ì’ö"8gɼÂaÚ`7%à'—~ Q%e[¿2óïé6¯¹Ï >mŒyz¸1eÒwD¹ôpd™ Xæ¿[Æmø—-6·î÷ýM“„}y@&Æ- ;Ô#58TQG“ÐÀ‚ ØvUb^c¾~²Åê¶™{$¿zQå˜NÍ ¥øî:Š|î£-õ÷ÐkHiÎï2ùÿ§Í\s’U²&¨ø]zN¡ÏwÞü)4´¦À¯9…0ìäS?À´/ {Á€iæŸ =ø" ÔÇàO¶8qÎôM=’ÿÚ.ÙÜk¦91‡¯+¥öÌí0­êtÄýCƒ@‰à„VÁ·O±¨+CÅã‡%ßð¯#œî@ܺûÔ±@Hº^7ÉÛIWç 3g>ƒtþ?³8ÄžŽE#„1µ€p¶æÿVæq”ë#)øÂ6_>ÉâÔyÓ6õJ~ù‚ä)CÅOXjóhŽ;\éoéõvÐwP ±"ðçŽJ!çv¨þåhˆš´UÅdS?¨^l ÃIIs\·rw}¿Þõ¾V€0Â,“’¨Ùä}N4@NE œÊžuçµì¿˜<™åx~žåþJ-G¤ÀÆl5-øó/±8sÁô'ÓŠÿ¤¡â×Zé0^<˜i×Uzzq8¸oε¢u%<,ÇbKÜ‚wkñ–ÍAò‘‘Ü´GrÝ.›Cf—Á  øà"÷ƒ5,¬W&œ{× cø¥Ò8,£¬5+½\w .TÈyÕ Û$?~N²ÑÐǯCK\d5 ëËúòAÜÛVjóÿè&ÁÕkÇ–8òÓ7Øeó‡Ý¡»!-öúY?ÕÀ¸ ]#’E b2ƒaÁ¬¿ „„ÆOdïî¾ù•íåØí…Ãü·5Ö€•v œÇ²Ì}—K± ÙéÖWRÂ7Ÿ²·-.ZX} Ð7¿xA•'›(HC\…ŠN3_d_RSå÷êú6Œëå”Êü¯ÁÛ–«–` «t÷æÀ(\·Óææ½’ÑTáçóº?_®Ñ¨‹ÁâzU¥uß7ÐSáƒv‰€ñ`þ¾£ièOj³I&ƒ<|h•Å몸÷€ä‡[l£¾õ1hJ¨_¦ƒcó%y§î¯ôhîgPh°P9³]ð¡õ¥»/û†á†Ý6Þ#Ò¨M-¿•÷uTöÆ/iH3ºù„}HÁ0;„1i„CP› „ ©Í ð MXaqù²Ê‚ÀX þå›Ûö«D]Líúq1UFÿÆÕó.â‘FÀnhþ)-1í³ÞB€þø°î`S–6 ï 6^„ ëC¥ûÌ 4m¯µt€ %þ @@—mf°ãc Q>dÒÇNÑåÓz+.Ô®·‚'™v…2‹ H­‹&¿#(‹3ÔÖÙï:ÆâÜQ”±ô9ß=ÝñWÛ%[C4‹M&›¢8¿£G±P è¾M?ïý9ñ„$ì’,mÁu³0Ì5t‡3Îà|,ú27þ?u‚tx©¼7ñ'E:Ü—.,²¥ÔæXŽü!s[®Ý!IÙO!2•”„¯=i{*¿H“[™nº™k'Ò×ÔÛÏÜß)bVº"¬ÂLùJ)¸ûXxèÈÁÊß^Wcqá¢Ò BIÚpg·ä×ÛÍ›£¨{£G¥ðrr“ÊX&_2nÊ·»öOÀîá4`>¼"l‰pVøÞYÔ§IrçH7ûOv"­³ŸËú+p*¸åÊÈ(»û·s…NnÜ-II›¿+` ‘©ÜÓíÆJñ'?wæÞºò(²ª4=¢4ÎÝ<€A½‡‘°Ä_{¼i¹Å%‹KÃì$áæ}’ßî°9Ãè¿a©šÏWŠºüÑÜ´WrÝNó¨q × æ× ß5¥]s†@”pd¼<°¸X£;x\³`Q½wX0Ÿf@hPÜØÑüÓ6* ?™&Lnz1§ÙpÕc6Ϙ«ž.˜7ˆ5ûI?½“!'÷ `ý<ÁåK§Î/MM~ßܘ.Çí7 åÕÆàèF‹Ö„Ð+ràîï^—ÒóxÒ†ž2@;p7°JwpEK×=ØÄ/ôòû 3Ìø A¤`¾ÝiJƒÀü"€À‘q¸ê±”‘éêg„iï%¥Oå1®»%¯\$¸d‰U²™ =ãðûJñMËqãp|KŒ¦˜×:’¡-N'€èŽKè+/dN~7pŒnáœÐ&è¨+Ž ë$ãÙ $Àü7µÂ”ÛxO¨õRþ°™jõjIg}q@àž°Ùn8ÀCçàá ø¹z™œu;dÌÞ)«[—%8·C=\š‘|ÊqÛj'4[ÔÆM”Z†Œ:åZN+b\¡ÑòÀRà`™nѬitÔ{…Eà‡’­7- Îwpð¶ ¤ñ”Ú|ºÔs ÑP¾ú¤Í‡Ã×€àº?…öãŸ[,\´HptSõ”ã `A`u«EB‡Rûøö!€`†€ã»€Eî–P!­µ¹%¤a>PnŒX†ofÐþ;8ôÄðËÐ#ªÃ*ÆÜøö)ËŠ ) ÿû9›?ì’¡>ƒ™+‹4…§Æ‚3.\$8už(ištØr\KÀ¢z‹µ­VºÞC†0ãõ9%f»¿û¸ªqº+ ÆÝ tè.ÖIs j…çÂ1JÑ&É¢[F à;xB¦¶]ÇÃ(L[ |ë‹cŠ´>tPò½-ž£§Ê& Kzç¶ ÎhWªJ%ù”ãÆ„"öNhµ&“%s|û<\J/—ÀŒ—’Œ§`…T â;€yº wÊ\Á¼º\³?Ÿ0‘._<«ž¼@ À?ôç]ÿÄx)>+Š=…hp~þ‚ò{Ë1<3#õ18y®àìÁ %·>YŽû¢ÍÃ~+[,V´XkGš‡øB¼Þöà°2¥`߈]q8•'0G§Í·˜Wãm> ? ³ñ`^ÓŠúócúsX¨ð…ά+Å¢=Cð»ª]Xýè<݇£›§ÎƒSç Ö¶©ô¥–L9îïvØ2,Ç­‹ÁKÚ,Ži²B*u$_È׌ٰg¸:à Ô|²f÷¸/›oÑVÎ šhÚI6ìÔÓ_}ÈO†Rþ|ÇVÕÅàš“¬¢·ôÃ}$÷vKž:’?4ÄáøfÁê6ÅàŸÐ&Š–Ødñ[ŽÛœ>?Æ¢ú|}sßÞH©e¨÷KÁî*€³›QåÄ9~Þ™ ,Zø™ù×ÈPýã‚@ (í7×*Æ<@!Í+kcðåK7…(iöÉóýª]|Ï8ôŽgß¤š˜šŠ;§F1ãKUÉùµTDò)Ç[#8§=ÆÜa”€ÌÜË<ø};:¿Íj̆CÕ æ ÜÔå,X ÎjÏNqÍ)šìö_æú Çþûó&®@¡Ókã|~ÅYí³c<¹—„-Ç@g½àåí1š‡¹—y’t…“|AVĘ /V¼ ¸5§,g×:·ÝšEn j2´Ð_Ø´_W ßZ]Äåª5¯X8û@ l9®%`y£à‚Ž8µ±ÂH:3Ùз'|öàh ¶W)\\‹¦!I} Îë°&™_áÁdxøeù„þ¤øÚ®€—ï¯sòO­¶¸xÑÌ|ÊqcV·Z¼¼#–Õ )¯L¼°$ÒhÍ…%Glxa zà àר>ƒ.Â^ÞiQ3»áÚh@¨:žõ÷%ûLÃ|ÒXù c/€¯²xÝQ3ò)Ç­±àÔy1ΘK7à(<Ç+,Wl’/È MÁó¯à=û]šü)ôLÂ]]6tZÔÅ}ºùôôjêì h;^l9æzuôÍùMºÍ—Ìîžëlêì(\¯q¶ÔšvÛBóx¾óì$ðïÏÚ¤ìÊO!*¦dÊqÿg§ÍÃr܆8œ» Æú¹±,¥U 5Á2 çž®—H?–{‚0ïãgešyz½§ûõd>‡˜|çÌg2¢Æ*|ÿ6ûPMF³Ve&•qiƒÈH«%=­8§KMVw ýßY+2)Ébê~¿Ñ<7ëoáḒäuǵÓtФ³–!xÉœé ýðÛ6ß|Êæþ’¡dðkÚj¯]ç²Åq7XSkŽkAx¬ïã"à¸ßëEÎú5{OõZçñ¤„CújÀïÕOGÒä`ºwJ–5©vÈ¡ì®4®‰5~Ýlȹ¸þ €¢ë”U 8¹ÏõÈöù»Ð¤¼M½’q[¥ØN7é‡ëÒŠÿØaŒÂyu‚7/MpQgŒùµ"ëÒ{+˜©€ÎãBû¼Éã¾çy¾gfýª×'íéƒÀÅ:88ªÚÇD®à´²tÊk×õ´ô £ÀBÓ¿Àh·÷Cå/f«ê§¨k»~ž`:ÀÀ¾aø¿Ûm¾³ÙfCIH5ÅúíG'8·=FKBx>ÏoGš{ï­€îÍD(­îœÂ× 1y}RÂÁi¦9‰œ&£Ã)80&9ºI%´„‡ ¼-/ET~á1Ù¤@¾LVÀ–>•¼sú|Qò)DùʶÉOž—üà›gú‚û àØ&Á;©áeóc4 U†»j( ðq Ì_ïc…œ3)…W9pÕ¨¶bõ¨¬ÁlHª¹Ë›–ð°\g™ø>;zø™õºÝÞDù½ü|?ÿ_– nó|?ìQe¶VÀæ#’=+ùÏç$ۃϪ8ç=G'8yn,¯ê~.Af=„Ù‰³wô|€ËÈç=“ÞåÀU  º 7gº &áð8¡ïG¦Só 7@xô²d_ igäTÆ xqöÃí•L9î·7KþûEÉ^ƒA™q'͵x÷1 ÖµY“ƒLó• — ?ßœ+"<±Ž˜œÓn:SÝ&T1ÇÑS–yXYn€Ðô¯sÝt •ߌø3pL_S$Ù1/ ÀÙí¥m´¡“¤ ·wI¾þ”êµg2(³Ö‚³ÄxÇò+[¬à*¼ÍtáMò*µð%ù‚]s+$)UÆt€¿Ç¢z dIß„úYî°r,—Iåih”5×"¹Šz‡Ï\ÿ—%²ö ÃópvGi†bºe$ Ú#ùú“ªÔؤ»nc.êŒñæ¥ –7úOP.ª%à1ʇ¤ËOHƒˆÁk&lØoÕNÇ€ÿ‡f"1¨’Òs;¦¾BPCP¿ ºš~m“O¯l=rs÷½²ù¼w÷ ÈzN R„½ä%s_=Ù,3ɧ·­Fðê…1ŽoïÜz}ò*ñ5*ò)${Ð.ÀPëѶ-®šT`SIׯÕ\Ù¢@À«,8Lûo?ð-åÕ(¿WНßãîb:å/f¡Ÿ{ äWŽÛQ'¸tIœÅõ…›;² OþນG5¡‰ðÐ<2C ¸¸Äk±ž¹@vœûgTÜ#w{i¨¼ùX…v2‘bM!ʧwi£à²ÅqæÖŠ¢jr¡×Ésw¦¸%¾¦…iZ+ÕÎíáÃ3@…ÿ\ ;¸nŽàÌùÂÈðCãÀþýL ÍGùƒ\€0V@¡MCLäØfÁ·Ö[´Ö„m>å¸+š-.]¶<*þJ-ó¬ì3þ‰YAÐ@:4³ÔDâ¿çéž:Oµ‹öæeø*¿v·—Æ|t»¸Ÿ  µÖ”´ig˜)Dù–ã®m³¸dQ<\/À*p ŠZÙJ„'à &ß ¼Twðôù‚õs…qûo³¶Þ¥¼yšùÒP©e+ Tn@F‚¦åSŽ›°à”¹1.쌖P.A ÉG„È`+d0 ÷œ™ÐŠê4|Šîà '¥«Ý¼Ú»/žyg_§òÉÐæÎyÝi¤ü¥"³ 9e 8§åSŽ[ƒsÚc¼l~,p üt0]‘|ù÷HJî=0s`>*ux­îày‚5m·ùg˜¶Þ&®€©Æ ðkRn+¦¦-¨üqj©m:·%!¸xaŒ5­Vi”±J]‚|†fYy‹ý’{f8€šH|p‚îàù‚ÕmÂ×ðlëm°«{±õF>¾¡_ok@FVÐ PЬú5˜NÇ_+¸dQŒåMV9ô¸bÖ@psYé;Ì£hB$ô'%wu@|šÀT ±v"ñ]Ý’„¥ÂYÙ]€²ºûàêê“éÒƒúÛJ_háèäãì$t~4;ÿ–x›ü›tIª”YÇ&‹‚¤«ÇÌiž\1ÙñpTƒŠá/¨ ·ÏˆB•±€‹PÈõ›¼·™N@8»ö¨gdvtgïAKxwš:®n°Ww ÷ëM¯øt€=À+Ò °ÔÈ·uIâ–* "£ÌŽ6\hÚx¹_%ÏUP”?KQýž‡ù9&Wm9 @ –5Y¼nIŒ¶„(ø\Ó 2÷>³áä*µz@а-ÃÀ’™Þ²ŽçyK°™; °ÈÍÒþuŸä5‹aY£˜¼Ð¶CÑý”ßi!8•’¬^}œRJaº»{ìèV€nçÏ:_™%&`m«ÅkÅ©‰P*…X!™œ|½R›õÔYºÞƒºÞ¦Q•™Û€ Óœ@»ó@JÂ_öJ.[K²AÀÝ´3k÷ö1ç1PjåÏÙÑ‹VäyŽrq/™cñªEq%b” ¨¨Kàiæk\‚I¥&׊È •v tV„é­°˜YòL»¤¤ª<Û;"³LlËù·«ŠÐ»Ÿ`îß"çºç™žÏMÑ:ÊÞ‚^W®î>+š->·¶†Ë—Nù³¾s¡'(ÿK•’‰©µe9ÒëÆÊ¬=¦Ÿ:ŽÏq‘uÜýºÙO¥A ×} )á{$]#ÊJáýЭÄ9mÉBœÃнZCHG}ùû V -/Ö)µú-<•^§üYÇ…ÀJo>n ™­ªÝøkpÔ=O‚€ ÜcspÌ¿cp1”_Î =åÕ¬Œ• YÂW©"û¸Ûbpý—5à>çl€‡€W£º gɸ ØmshÔÛÔ²Ð*£0VbÏåû: (˜á 0Ý]k „Èr|wÿœã"r\r?ð 'Iu,7î±éóé°ógíæE0í…yãÓ%?dƒÀLq ,KžÈw´Ê‹PMF_ätšIÁöØ÷PÎ@AƒR›ö^I%µQ¹y½µ§R _’Ï“Xœ´"Dù+ð6 g€ÔpnÜm3ô`ðóðÿƒvl݈3såú1it"— pK ÇÌN’-ÉDF-¿÷Á¤â'<†„Þ•…¯bš6õ=æñÜJ¹‘KP\^ [©Eh> rôrð^TžE– LÀ÷ÚŒ$³]­‚™ï‰áÏã<×À™àTðVêÜ(/€§üð>4 ^}㊵ƒãú…’s…qÕíT‹K0]y#’OøG"À_~|BwàÈ8üyÍxªP¥æäœ±‚ yî,—=(̲# X~|Zwàðüy¯Í¸,‘i_çÎV˜î._ö`@°|øGÝCcð×½öÔê0ä\Yvw‘ÿy#^`Ú¹~¡B¯ìÁÌäËÀ7uºGá–}6©|-*zn5Iääï„ÉŒÀ\>ü³î@ר\™’Á–€qjp…À ™ãèB…n— €pr5ðº{‡%wt©ºm?Å+š©?HÀ ‘Kç[û¤;³#'øð/¸·[Nñº‹EßÝ}_+B½OIA @ ˆ\‚ð–@Pö`ùÀÿÖÜ9$¹ï€ÌZ<¡ÍlQÀ*)–eP¥ÖÀlt ŠÁ Mö i§†r%¼ø­îàŽ!ÉC‡|f݉JQ ‚W%0[]‚*â"°8 p%ji޼0 yô¬8ë_5<À r ¦+/ K Š 0Þܤ;¸m@òD,žyŸïs«9 â*êDPxªÓpŽlí—à"`ƒz%ÛdøÅ•§¹?«#— ú¾sáäðJ`‹îàÆ^É\ÀÚ3 xIDATŽA©½kF!¹b)qµƒA*¬šï@x9\lÕÜÔ+Ù3œ›,TR5Lƒj²f›KP&^`,÷ØFÏGúœ—t§Ý»£$°á°„¹°°^ßQé}LH¥ö^æéÀ…òÎ ÍËï½e Ú&ÛïIqÏÃ)ÏSÈŠ#» °Ø}…7öJ, ê„ñÍv+º,öJ/¡Æˆ ‚‚jš\¼µßæöî‡Ç|O:„knf…É ÀùiXèFã'z$ëç¼Z¬ôùê€ÇBÒN¦´Óƒ ˜vÖ@¥'ï‘ÜÚ•d×PàI$ð\ó1"(\žGƒwóÝ °! m5EZ<®U›k0]‚¿sø—ÜÑbsŸ‘¯¿ø{àv÷ˆ,Žd&÷¸¤Ò–@ïxBG˜» Õ*…1æQ¨ÐKÆm¸û@Š~ÂDù÷NÕ)dW6¡&ß 4»A`cä乂¦D~kCkºˆy‹xªt l {mî;}Ä €Êüû'$7ìNò“&ØÌî? \‚ I?ö½"(ܼ˜ÐÀæ#’ÑTqŽ(›VÌàF#£)¸½+Å¿nàÉ#Æ߉À_òýlPZ¹5‘ø7îk=f«*µ­‚„†¥¡S›oȯÒYt…ùÈ3+T˜!øîèN2l¡ZØ)ôsÅ"-¹<ìL»Y›AJBï8Ì­U]\%Ù?ûX˜ã^¯¡HJ°¬Ñâ˜&«`¥˜Í.Ásý6¿Ù™dÓÇ*½$Q«/Gµª+ŠYå‘_¦¯õOÜk`4[ú$'´ b¢D+N–Ÿý/ËŽ<£{†3ø@|ŸBå›U"(Ÿü hD %Íñý¶öKV´ˆ,RFùÕ»Ð#— Wú&$wt¥L||€Ç«€;Kõy"(¯ü(ív}ß}`8 ÏõKŽovut—…+—œ&GÌ`MÁ}S RÀlàl OôÚ\»k‚íƒ2躢վ•TVrìŽ,€ÊÈ5@ j(i– %á…AÉÑM"Ð(´hÆZU <×osóþ½ÁI<ÀÏ/¡zM”M"¨œ|>}ý¯ÖÀŽ!ɲ1k/ÎtæöKn Gð}Ø\‰ë@eåP5α'Ô,£Eq­€iÓ¥ ¨gLr{wŠ-f%º¡Jtï®äõ ²"¦ïÃûs@ ©ÂE‹"¨f—`$÷›|»¯Q‚/€éB…ßî>80û†%õ"/e—3ªÍ%HIxìpŠ»¤|Óº3x|øšB±f·ØÀ»Ò÷ã-:HÚÓýe¾Š.gTÚ%À3}6·u…"ø¾¨¶ë@õHf"qj Q–ôO¨å7¿Öa dåö:BL®œ_YBeœm.ÁÞaÉ_÷'Ù=lôú?¡2øž¯ÖE@uÉjéïQÝ…r@@ ™S›Ÿ;PuÊ8\‚ÃcªßÓfߣ(‚ïžj_pTŸd&ÿÕq8Kú&@"i«Ñƒ@%ˆÂéÛŸ?†Sð@šàKš|_þïtq¸"¨NAM$¾8Gk hŽ ªzG®2HIxÔœàëE•çþ UDðE0½e8ÍÜ œ–c ŒKSýM@@V»2V/ -á ¾/ FÆM;‰ º¥¸Õbl}®; ‘â“ëwÖƒ@!ßq÷ˆä–}¡¾OÛ¦ó‹ úåªÓðÀš\w@‚º˜kñËÙ ù¼÷¡1É]IS‚ïÁwïLX\L9¼¸ X¥ ÔZP¹@ šyá”ä)4ËàÛ…ŠåO‚/€™%™‰Ä÷àšH *Yˆ“ý«¬V—`†‡§¸ï@2 Á÷4]ž#ˆ¤œ²ÕGà`™šâ@@ûÞ‚ïÖýIŽÌ‚/€™)»˜K¾Ð}p0 qTAY} P©Ï°cÐæ¯û“ì1&ø>šþ<£%€é)Ï35–¼Ã}p( ñ©¡î´áJ;°å´Iî0'øF|÷Í–…Àô•­¨áÀ\÷Á‘$ÔÅ!îR˜¢zA`8)¹û@ŠG§°ƒßèyTƒ–ë˜ùÕÕÌ y5–üv`Ž[ÇGRPgM)jIVvš\ — CðÝs ÉX0Á×|‡JðE0;dj6Ü-¸&ƒš@”pø%¨hÛò Áw‹Á7üø2*ÏbÖJ3C^ªht+Æ„ 1« €¨ lTŠo@ðÉ´™ÿÀöhÙD0“ä>à À@{Õ'mJ3y¨‚ ’à{EðÝ-•fªÜš€Z÷Á”,¨u~Õð! ¾çP±üYGðE0;åfà×êî¯,— ”€Iðþ‰YLðE0{åzTƒÑÿ¦ÒÓŸŠàäIð} UMI³R~‹ê/øSÀš® °}Ðæ¯û’t|Ÿ^Œn‘À/Ò÷ø?©\ϼ\‚ƒc’[ö'ÙÚoDð=ˆ"øˆny‘dËOPù߯ŠO` LHîìNñD¯Á·U¢û»è6G‰·ü _­VÏ|ÝIÆ‚7ý Á÷ý´ÏI‘È×PùŸ¯@E%6õ¦¸µ+ÅÀDà–?ü5B;"ø"ˆ$¤|!}Ï?S!×>K^°¹y_’ns‚ïj`Gt#ˆ$ùlÚøH]û,98ª¦ë©ï‰soÜ)$q=áp8®‡€Ãápp8Œï½÷ž`Dp8>üðC:ìnø Ÿ'ÂÀÿŸÔz!!yìÆGÏDàpEÑò]»á/ °q¼šÜ ÓÚ1)Šb­T/IŒ ãüÂÀÏ`PÕü];°(ŠJDʪªJ% ê.ÀË¥¿$˜†N?øàƒ_`p8ÞÿýïÅ€Éh¨W™f^‹1öÉî}u”㑼òß’üÖmHîí7$wì³ýš$nß¾ ym2™Äêÿ‘€»/ÃÉÉI¨ªjJò”ä•É}õ;ÖðpüV×"rªªç'''a>Ÿc \ ™Áà38áä>Hvùm—vÍ6Íï·ß»ü÷Íþ.OÞÖÞ>g!„"ýûOjw 8º>"²ÏþŠÝ ß @òa yÅþíàctÏcͶí÷»ùþí}ígh\w…9'€QÆ èÒ¶Ý2&àÕ€}Âá!´­á·ÞWUˆÈ6wàÒJräà1 ä~‡Œ ì5ž "c}câ‘×ã'µöôU«Ls8ú#Wû§û,u°›ˆ «º«ˆ}®xÐápUê `4þ3ɃP]qqq]pzz:„¸lý@‡ÚƒÖ@_ǘ@þND\8®œŽ{M=ÓK^ü@8¶úî¿íž[P?®1ø €ÃáA@‡+7â¬cŒ}€ƒäÓ†ûÞæëØJ‰ÛÆ$Ø€ÃáÒÝ€íÍÈãuæñuW]füC,rÄ;·‘FÑIW©WUÕNR¶(ŠícÙý–gîÁÈãumw•9ÿmcÖI`Ûšþ5\t8=”;8|oƒ¡Ü…ÆxÖõ]8®<pi&y•ÑU¯•°߃°‡¾œ|§˜§OŸâîÝ»`Ú®ÅeY¾š‘'¯æäétÚx¹ª’¶ –ïCpTÄàÐÉPÎÎÎðÉ'Ÿ`Þ}÷]tÀÀÏ0ü>$»ŽèöçèÐwÚt‡xðjùâÆAaÏà¾óñ¤>û¦ ¾ÇÀÏ0¼èýì{`/¦õ-Áß»·ûꫯðé§Ÿb…‡âexüø1=zÔAŠþ Ý1<áôëswYé¡¿ÄË(ïß¿]ðàÁƒ&Á ÿ ^}èðWƒõ!™ÏÏχ•èö c™á»¶Z t’¥p¨jK`røgð‰2þj°}ËåÁW-DÄ7>éØ?É}ÿm«N‡cäË€ßý‹Ǿð§'¸ÈÆõ¥~Ãm}I>Uup‹ßÏÆ8„ìo+©Ö{$ûôÑ+æÐŒÓô2<^øãßÿMì ÿ†Al!DZI¢Ò’:¼#¤‡ô僃Îõ[øÞ­ý õõ% ŒÌ3²¦ó¦*àÖkÖÌ4®Ú8¹q ­·S¢ B’ €jéÉ@ü|bç^Ê1¨a§ôÞ¿ðeÀùÙ7Ø\fög3ð¦Ê†WÒÔðøò˯@H½ÝKñÓ'ÿ±S»È|CHê›6Š=›Hn³Lú»àÉ“'88á¼>1€Ÿýâ¢w@šíÊ—«5ƒ4H¾÷÷ïãO~ôgXá£ÿå¦~Tk/…ró7"uB "‰€ŒÁýûßÅ;9ûϲýÈY‚C樰%à àwëö†ÿÆ«^šR}E²¬Áº©äH\ÜÉy9!Hí¾ÖŸ)€¹ö½—Ñúßsl°¨Ð;jölÒ?v Öfy¦Ö’©äËJqŸ%?¿MÞo'åb°»OBRÀ’I%ˆHÚàÙ!æ°/¹lŽ7¬Èí»ü #sþ÷ר~°ãL«$"í†*Q)AÊò"Ö+˜‘LÒ»i©7^»?øÃ?Â;wFNeD·>W¥„Hnêþ>PW(D¶ûÍ·Þ½»w·HUWü¼×wðç_ϱ7ÜÞMŽ/")”¥€ PÅ•´(b„‘e·ë lO»3»yUs¦Ï'̧M€‰¢6&Òs€"kã’ ¤Þ‡íÔ1ÆŸcܸqãð”€Àð>“*Ó¬Hж_€˜¨‘B™ì–ɰtc‡TÖd>Ó!D@âR0! " d0\ºÀ¤ʘ‹˜¨M$1ɵŠýà r”¯ÌòTàÃ\¢X€. ` J¥¥á&ÃVÜ$€¬½3Ôfc/!€˜0€éºŒvo®‰HœL‚¥(§î„r³4Yàè5/¡û‹A\ ©ªHÌ×\$ep‰*õ,Þ(›ò_Ò=k¢ ó9f³YÍ5àÆ.&ïÆ˜P £b¡ ¡`^*ÎËU༕Ba Æ=kyiÇt:Å7gOS9pS~Š8M¸p¥ú˜®V„`¬Å(`&‹YVÀ€(%>ûÏÏÒuË3Úºâ~øCÐÌ}£Î_ILƒ­ *ll!Œ”JB8IAʨ@TX[bÙv–ˆ@<;;Ã_}òˆò AðwVë<.gÛ‹ä¤/¢ R5 Û8ìÊÚ¬/‰ìó‡ *Å@¤‚¤©ƒ’` ’HPæn$Z×Q‰‚H‹GFPUÄzI (õTƒ[·naäØšq%à `Q%ÃZ¹VdU‚ÉФ‘ÊŸ¿à†iÍ{ €©ÝE¥`­ä7Ô”Á€XìAR0ð"TâtŠu\"2ç里Úgƒt%p<ð `™Œ}žˆ`©lÖ͵øÌî<›$°X,ðùÏ?7#WâõßþþÆ*ã’Ið?ŸŽŸ~ö_6ÓÁ÷çõ ˆ$ì¼T3¦E$ÎKETâfrK4¹QÑâ¿üå×ø§¿ÿ;LQˆâÝwÞA4ðøñcÛ18»ר] ¸  )é'Úìü<T ÔÚ*Àf~„$r@1E…ka$²I+âäæ-<Ÿ—F”¥úɉF ¢ˆ@Q¤ø™ªuy}‘H*Ò¡X½‚ îÞ»·S.ŃðÅ_4dôq¤“É1Ñ'3üy4©?/­`BÁ"m™Kq•&å×_p}à ±Ä|í¯üzB—ëùŠrÙΤÿ<*dc@“„hãA–ŸóÊ>Íø­ë¨"$ gà+ˆàüüÜð0á/1P1PV)` L”i Ûæ23õWˆbmzFÈm¢‚QQVX…PØØæ$@X5`4ÊU]BZš,•v„,»6r´ÃÎí«–â†ñdE0~ƒôB Ò‚€J,¢Z&`e³ð" ¢r]HeéTjÉ@YØ…-ÝÙ}ûŠÐR±PAÅY)€êbª! "ó¬o.qQ…´;‘“P‘ ¥‡d4ûò\…8påû+0_)€HÌ((­P(g=Úžkû³ " f´@J@+ ÔÜnUë/©ML¥ÂåĤ¿Åe PF˜J©"Sp’M `½Z±;Ü(NIbÇõ2 Ýæ´ï5ÉëŠ/8Öš ´#Ö@©ê.ƒš¦¢†u`™fq™¬¥=sI_ þDS#ø3…¯Þ†´úRd˽Œ¶‡1nMBߥģHšŒ8pbëì*X¨X0*nÐêðiò½©§2ÔßP6€}‰Rk.€L ÷• "DrR¬¨'Éâ2‹)ÍÐ#QVæ¦PLYäZ"$7A—‡€5"à–² ‚+‡ï`>v2²ù* ¨vDªµZ@žr©YJh"í´N•š_/‘<¶@LÏŒx&)ñGƒ Tk§"(Kš +`K€j¹†–„ ÓÓSì€1)íã¹ð `™‹‚*µ­Á5`€‰¨ù5]õ7¨ö­Fm(€LSH^ªMÐŽ<#¯K [_ú“ÁÖóì:B¾Çæ‘Æ% LåÂù¹ì°“h÷ˆ¦Qß½{w›´<&%0¾Ù¹ù·J8@D†î³ÆAÖÆ vd0&˲DAJ ³O&WF/vˆ™‚Wà]Ñ8$wV!„KŒåq€ËÁ!C”8ú )"­÷¯^ì`&€ÍÍáJà fæ‹‹‹î/$ÿ*€C@(™ÎÇ ‹;ì‚ÙlÖ—¯ìñ! À±ÿ  ¬_+.Ë“tž®íuôUäêÆ ÀwQÀ°Ç1³GÁubÁtm‡ÝOŸ-3_o¢íc†ooçðràá%€àºÁáàJ€0G¬HöŒ×2 ƒ-ºÔv8^%@âj!pŒöß÷ÝßxÀ‘K‚Ý(zK:æD W…êxŒ_¤Ã2 Ã•À5$€Ó1QFÂÔ‡)\ (|€N4B”Çœ¤"9¸°5h:âù¯ŸÙ~Íh¸{bÍ!þ]¾ (¦T‚ª¶ãÒß7ggø›¿þIsàüFàñE“èœPŽ1H‰Uäñ;ìß ¸uûöñº îþø*ÓÿO1qlPÛTÅ9äÀu¿T€g@þòŒ.ãØV_þj°Aƒ%e/ûÊ]á˜ÍfG±M¶ˆ³,wÀ*& I +8þ,à6ƒ97ÀáÕ€90x"À<\{%r¯‚ƒ@áhuéèàÛ6ÐéåÀ„á†ð°’…¤´ í}‘ѧ§§¾%ØIÀ\R‰ëЧ¿úvÁ“'OŽú]þ1F7 @sÒX3È-/½wo½õnÍ7§ôÑÖb ‡b4pøŽ@P0 ÀT9”´Ý+'#¯)ð¿É ' p… L’:¼ÊB r+¿œ={†k‡o NN§×·ïÜÁo¾i‚´/sLàz)¹ðxiÿµ`K,‡+w½·¯y×_ V–% TZ¤ÝdÒ$\ ¸p´¾ÇϤÃÀ¡‚=m,×òºƒíÞ€ƒ¸p88˜?iÇÒ_Ôsíó8îŒc3^‹‰_D®÷Š€oî €´clsG°2B%à àµ7þYÍmêÔ+Ø®é_/~O^Ÿ~!ßÑJfA%%Ë·¬¨•M,'vìÉ™Žð­zˆj=‘!P@€ÙˆÌÃÕ R ؾAÏËp%pUðìi”]Õuçûœ;¼±F©4Ïódlw#ŒãË#`Œ1$xvÛ鸻¿õʗΗ^«W'±ÛCpÛ±ÛœcŒ¡1v‚lƒ„Íh(Õ\¯ªÞ»÷ì.½“·îÒª……\zš¸{­¿n½zWë>Ué¿ç½Ï!²ßù6Å ¥>$ "DÀiÆ7™I ™»ÀdæûèÌkëýmbÕÙŽ`ÒLjRUhB0Nµ‰öÈïçnˆÁ …² ¢€‚;‡¿fÝǤ^»!"ð*åHq´MDW…&{ý«Nßõb¹Ð"iZˆ""jDDDÍþSdÌT@”ÃD3­€™(H‹,ʸ+Ⱦ¤Ûœ˜°ÊTØHE1ÎQMö$=ù2ôÚDfÖ1ê OšjnÉ4`œ€‘W_HâRw,È1ó× ‚èáŠÀ¥Š0FÈ¥ýJåćžüF1`0"ŠQ0Æ 1(š©ñD=Ô¿Ì@Ô/æ„æÊ}hy£žœ¯JoGGb[°B4ŒUĦ‚Ip¸ñÁ‹ª‰¯öZ »WA !AÌ V‚qJñ>•;Ÿ!°J%¶\´¬Â'ß2áTxl_ƒÛ¶¤LL¦Ú, 8%K–Fk "‚3~¯A¥a`§£>lq[aûdÊêS ½O骈±­LÂP¨×ëŠ1"’‘|¦ ffåEðÞ‚"3ˆÈ˜ïïI¦Ð K+†îHH P !‰„$…R(¼‚PG‘<î$‘„ö×ÙŸâcŒ™íç:y@VòËL¦_2‰þWk`p ±Á†&+ )€"‚ -þ“Õ¯iBfÔÂ1 Ðì} €ZÿÒ(b .–Ôþ×w°°3fÃ…]¼ÿ¬N:*!À›­òµI&¦”b`Á9@ÛÞ”äÄÆ¿ZT¨‹#p!Õ¡^2¤Æ"ìJùñ¯kDK ¨ ¢rx* ãˆd7 YNE@‘ìáj@DšQZ"­ >ô_Ó€tÒ!%‚b!aUÏÎÔ—)j§B`‘4¸öª²œ€ž:YXÙo|㼚|îsŸ£rã7¼êþEy}%ÍÛï´áþbÙÊŽ«ßõ}Ì-ów[t¤}E42Ø©­×ÑÔ´,´”¼š@@@ÌŒ¢³‡µ8QÄ&M”£“üãÐ8»wñ?Þ»ˆ‹ÏŸÃ–AåÅ­Ð;—roWwdÑDû, ‰SDAU¨'…†¤Š0׈÷'L ŽC¯CV„Ë œ6I@fô)(™ Ù%cÙ½xˆG¦,$Ó»„@EHGÁ„ä4öÂäe4 H.˜Kùâ)–ê>b"Ñ+ŽTAi)?E[•^@NÇiÇ#¿:x3¡‘5LºË¯ºdþÂÿù‰Õì>8ÅîþIî}ø†öÕpe‹)…D {±Å™ë>³3ÌÌ2Õá…ñh‰5­®T2W6p0ÑpìŸLyxH¸pȰõ¥·>:ÀÀœ9”WÍ¥P ÐÉÆq­ * âËxû†Ófü<Ôp\XcR"æ..`çC°´A°NH{„Q—’(à„‹ñˬ:ˆÑ™l#»]f¾×R´ˆW‡¤_ÑºâÆ…t¿ÐØ~ïP-Áx-à`ÒÁ<;@,uR,Š¡‘z…ç|ñtöÂrH£¡ñªEe ¡aY_¿ø“5\´¶ÊßÿÓvžŸÚ”ãÉgÊï\I±6MùÝ¢¿W§mvOš]m … <7Ö ­'t-é" 3Õ LANÀéÇ ¾d&¤Nh8åàA…¨Áݯ4ROþRlˆÄ6Žõ:¨€€ˆ9\‰z@ö¾dÉ$‹õü%ó(°‚Qa0‚í…tBhìVY$˜`æ(ñ¡²ØÐÝe¸°ÐÇŽ è) b¡«(<ôÀ=¨á0[ñä?ò÷gO~4MÙ¸qc6l`É’%¯šØ»w/àWµ…axú+€‰©4%¯Ýþ/»—ÜvÿÎK{æ¸jý.ê‚ßLÖ.Dœ]}í´r„{PÅ9mžh 8‡¨RV ’&h#Ûá…êì}ú£É# ™l Z„œò‰·4UFÆÑ±¾”&p´ˆ„Ÿ‘þ­ª3¿Ô좓`Bˆ– ï1 —S‰¢«ú„òxÃʈ†¡!ÇÊ¢¡@j B€õÞŠo:üãÉ)Ú0Óßßï=#AñÉÒ,”{B7ùL]Ãòª¥3ž;Øðä7Bl|MÿË=ù𥾮Ø'ý¼Õ÷ÄÁBà•F<Ú.9N¨"1'І%€Q°Nõpc¥3ºÑ.¬¼üÄ‹cüßÛžçœþaÞ·À±°6À)(œxÓ‹xœ ]G©(“N)YÚK_ ›LÑ?™b,DV(††¬‰9£'À9Pðî~Ë⇒) QFþ¶ìórO Ḭ̈ FUëVäær9”ñT¿ôâîÚŠÿýígøü5gqíŠ¾ìØ óC(Zp¯ß˜¾Ãïâ¾@”§Ôœr ‚aaÅðÎeQ³É'm½B9Â7ùd™þi[þ|%X;!¯ã” 1æ[ÅŽø«‡;ŸÛ:æþáû[)l9ȧ—ÁY‹an€yþ¢¦Re2…jlxÃüP”—“f¿V|óÏ[œÕõ‹;ªÞúOÃP [~´²þ˜¬¿¿ ’çrÀÈ‘ì[“*CÖšÛˇö <ö›•VD® …+—us¯ /öûÄ`%àu!êÉO}½eËÚžŽ@Ùt aûpеBh`NQ¸tIÀE}PZS}¦åö7¯™ÛŸ‘¿Íe¾yðšr!(Nu¿ùV¥3bÌÈynhÍ;·ð_>¶–÷-éä‡X6ïbE8}EÊD ݱá¬î°IôÇ÷L±Ìa­Pðñ<VE¬ë±4œ‚@Å·õú=~‘P <â Iþ&8.1Ž\¨pDÉr’°qzS©P£ð¥çvޝüË¿{–ÿö‰3ùèê^îØ´MX ‚¢§ñE Q¨%P -oZQ¶Â¯vNq`ÊaŒZÓTVú&Að?ƒ/óµjüÞòY{oÞ¼ÓŽ[®Ž ¤€…)cäÖb%’šê—÷ì›XrË?láê­â£g÷¡)lÙ-Tª…ô8¶4 àQÚÂãgJ¡³ üÑ¢ˆå·ûëìK  ,­.[³¦7h¾|I¯âã}ªqÖâúN?"ãÉàÒ—‘?#É .‰Èqy–ˆÌPm#mõñ›VÁ¦ÊX`仕jìjÖ|ùùFß÷ãmö½ WœÙÇœðâ>¡Q‡Î@O›F IŸðcN%à‚ù~jïéýu66Œ!2Bo8ÅÂÉÝŒn>Èã›Uåo[ï“}±¡êWzQ ¼»ß²üâc~£°–G^ÎÙ6‹>ŸûÜçh›ø€ç²y-žG®ŽR±:@U%Ä÷º÷[Ã÷*ÕÈŒYû¹_o^;™¾Ì'BÆåÝüØY6ïu„IJAŽ ?Û²¸ [Þ©L&Ð[ 8gNH_ÁðèÎIvŒ4¬P eI8Ãìg¾ ¶êüXMšV¿#6‡µ÷FÖ#Ì~M8r™… 4Ä΀½T„†¨žô‹‘Kå ­õUþìéÝ«¾2ü÷­ãCK{¸W OípÌ« ¢§\¦_R…‰„&‘߸ ¢·(ü|[­ÙáZCxò_qR%Ô ¼Õ÷µþ¬ÃÏ“ã‘=“ã"9r@~?ƒ(¤€Qm¢.Ž¿-•m8®Ñ—^éo,ûë;·ò™¯äú3çrWðÄ‹uº­P¶€ê©C~”©”i(Õ‚pÙ²"¡_îœà•±c…@ =2ɇÎíaU×yDžèåHxêWñÏ?ú>1~u÷g>ù'­R"2#Û/G¶„Üzë­œ}öÙôõõñ»dëÖ­ìß¿ŸgžyÆïð›¥dá\uÕUôôô̸g``à°ðàÊ+¯ôëÄg)·Ür çw‹/æwÉÝwßÍòåËÙ´i×]w]®Ú2‹T«€ƒ‰²M¿e+£†?ß±k|Á÷ïÛf7¤)8c>i#âé= ¦ê)½¨žä–NÁˆ·úS)Ì-Þ¼¸@(ʦ}u¶$X#ôÙIÖÚ~Ι;UQ"¿ÏŸJ$œ±b1›v’bÅš˜Í2çO?ýôâ|OØv‰'ÿ‘¿?{ò{¤iÊÆ›Ø°aK–,yÕüÀÞ½{h4§ä1bæò‚AÔ^_þá`O4qÇœªùZÜWÚñ›-#ÜóãíŒoÚËúRÎî³h`iÚ¾ÉÆcÙäÓļŠå‚y1Ý‘°qïÏöOaŒ¡XºmÊÚ Ÿ…fR§DÆgú[0É$¡¤‡@:kòç«´ ¿¿?{þlÎÌ«Â,Å 4T\xïÄ%ò©…¿ÜÿÐÀŠoo±óÃý ŠŸÙ´£¶dðÞ—øü•†¬ìňåÉ ±@aÂN=2F;æ9‘hsªï‚¾ˆ…å€_gÏxBÊ¡¡ç›=Ì‘QR§­åT£¬»/ Åâš0(&›XDœúï½VÉá-ûq—¬Dyº•g L2å Áóµ>.©n[½ò½åœ]×õå­»j|åû/òÙÁÖôaˆùÕK5zB(¢ 'QÌßpÞõ¯D†K–(…†‡¶×Ø[K1Ægîç• ï[]dßæ1Å¡”ƒV[¯¡|­ÕÝR :s°Ù[bDäuµ@CDŽÍóóN@Ž•¸;’îžêŒ*ŒÚùáPý«ÏÞ»î-üòWÜÏËÛÇùÞÛøHª¼Ý<ԕظ£Öt±»BÉxÏ÷4´b~¥+¶\ÒLø)÷L²}(!…À+ª–ËVĬíµìÇáPMèˆïô‹|¹¯zem‘8íÚ{sä€Ç;ŠO¸Ãsݸ‹MQb» ÿÈE]#|ýgxqó0÷ÿtïQå}«æâ’Ïí­34•Ðh·&kò™W ¸`^D9„'_©óÜ¡/Û± l¹ly7,ˆh8@=ù 4š  uFk²/4’Ñ=óÓ¡ª3¬XfÑÛØêšïå›ùyóÀìqqeWº2Lkil"IMoÙrÅEX_·†gŸdê'Û¸úÝÊWÎ%Ò{µÄQ0 :Û} G¿H[›|~ªïœy ª–‡·ÕØ>”Zã­z(lX]œ~?$U@!t ±4ˆiøÖÞl‡¡9­ € ärÌÈÛž >y#ÐìÑmk®†MëØÔAWÑrÍ»IR¸1U¶ìãÆûwðÅ÷À‡W÷yaŒÞB@~ßf ^Ô9RÌï3÷µT©ÆÂ›è.Zzy¼yRo`ý”^wÁð‘3Ьì¶ÔSÅá›z_Û'$ñã¼­î>_çb±xdò¿ºGp²[¶BÄ0 ›' ªy+ðÑ¢ WGS§Š¨ï|»öÍ]8àk)ÛöLpë¿ìàŠzÊ;ΘO ülË(”Jrœ¦ú&}ŸŽ‚áÒeEO쬱ÛÏóai5àí« ¬ì,P £à­?±$Coù£@¤µ¶[xaËf^Ï222BGGÇRººº8bŒ!MÓÓH(m“HgÄ—¹Tý>¼«.êĈðµŸõóòö~ôðnÞ“Âegͧ¾¢Ä“»j L%ô„´Uïò×Sè-ÛfLeÓþ:[DÖÚCä·\º,â¼y‰Ci*ŒŽÎ.θòTB¿Íçöï| #šÏÚPiƒuÊ:䎗\qž±ç5!ŽŽR­V9ÖòÀpùå—sðàA’$ÀZëÍQTHòƒAÚ)Ö€S!uÞè.Y>|AÆÀ7žÝ4ÄO~¾›÷ ¼óÌù$˜ß¾¢Œ4ª¦=Ý‚ ¤©RwÚœê;snÈœ‚á‰Ý“lLüØ.•Øò¶å1- Q§PòC=tDÅlƒ/V\–ðksÌÿ™Ï|æÈ Àß7ÛP`6]}ÇŠü3”èM7ÝÄ}÷Ý7û£Ãó•`´]Œ€ß(£"M‹{ÍŨ*ßpÂs/ŽrçC{¸Æï^9Cÿ·mŒX ð„:rq°u˜#ÞêðS}ÕØpN_ļ²å‘m“¼2ž(Z¡d…¯+°®×ÒHA >»ï•Ãá ¿iLŒ¶“üíÏ ä‚#Ö¼ 8û.]ŸðáÀ'ÞÔMê|bpë+“|ï¡Ý|Ì)ïX=@:xäùaª±P2`Pô˜lï…©бð¦Å Føå¶{Ç">s¿ bxïª"Ë: ª¢”OöV¿b›Íó—º:¸æê«éêêÄÈéšž¯[·Î'9}ù’‰‰ 6oÞ|ú:oš}§šÁá•xËù±‹»#|íჼ´sœ{ÝËå —­™‹Ñ*o¯5ˆºBÁ ð{– E¿Àª±åÂEçL±}$ŦIäå–õË#ÖÎ P@ŒßÞÛû8¿³Ðêðóß‚lžÿùEÚ:Ÿ>Ó:y7ÿDáU§ ׯ_߆®Åãïæ«jÞp¬eRçsŸLûÈùn|DØüÂ(>¾wo_3Mbž|EšhÐü~N‹õÔ[ÿž‚eÍœˆJ <³’—˜ÀÂÜ¢áÒå1/ŠI8ÅŸÏ_0tÄBÉoò¡Ô"¿…PA²F½NµÖ×%ªzRœŸxk÷´=1(*¸,'ÀtpK`yzó?þÅ^>¼}U/êb~¹#¡–*£Ø#ùùê¿àêÎ[ï5sBúÊ–Û5ÁÞñ„ÀB!ðË:7¬-6›€RO~bOì“~ÓWD·ïðËöög§öœz’»à¹0 #€ñJÀ©÷®½¸‹FªÜ’¤<¿{’ÛÙÇû§R.[3‡bP៟A"G E‘™ù Ðl°'u0™BGÑp^_L1ðuþÁ çÏç sŠ<£ÄòžUErh(EBŃRk‹OÖäƒä{ûsä!À1Pª¨úxúÚ7þÇìÀ#lÝ;Å?ýêïQxÚ^äŒ*n#!¥Þñ« #81€c*…¤©\,΋Qžéop`ÂÁaqGÀ¯(°¢' ² ±õî¾·ü~ô·¶ÚzÁ“Ÿœü¹'WŽ…PT§>Ã~ÅùX#|ýÑ!^Ø6ÆOŸìç2à¢Õs¨--±qO¡É‘`˜)ÆøLªÐ]2¬î àÅFsgl|æ~~%`ý²çÍH]vbO‹ô•È£zåüpxå!ä’£=x‰HçŒoúà¹Uþ6€§6ò³@Õð–Õ]¤˜{•ÑFBÅUp ©S’Té,Y–uTBxf_}µ”Ð E •‚ðÎÕΟ“ªB“ü­x_š  ìzÂágõ!¹eÎ=\ÃêBŠ’úÄ =%ËÇßÐIªps Ïíšäþà=(ëWuؘŸoM#GA_åE)„å]åÈòÛ½S OúU\‘?²‹ŸYf휰ù¼T¡gñ~+áWò®?ùód_Ž<Ðv%àÃO¼O\܉ˆpÓ£ƒlÙ;ÅOžìç]8þpe•¨ƒûž¢¡J)0€ÒpJ12¬î °âØr Áè”C#†y•€w­)°¢;À8UßàB%‚²?æœØBh TP@PT!mk)kæßUÕÓ÷h°ÜóÈ@Ö'à{œ*àëíW_؉1ðõGÙ²§ÆCO !b9wy'éê*ï¨1èå¢'2,.„à»ÇRú› ?°VXÜlò‰9»/BQüq]qVî«øþ~"ëÏž9ÚFPUÍ·Ÿ Àð–Vý¨î‡ÎíàK—öpö²J“ì?{j€g_âÜ.áâ…VÏ‹YÞ°¨l°À®‘„ã)Ö@` s*!o]Yà‹c¡à;ûÁ'þ<ù‰ƒÖL?XF<¤ [sÛñwó3üÛÿ¼<Ð~%à=§¤½%Ëçu jø¦Ûk<ô›AFÆSÎ^^á¬î˜ýà võ7Ø<0ÅxÝa|Ÿ>•Øò‘³*œÙ ¢þŒ¾‚¡yòÇâ(…Yƒ5 dw´$‚¶[²$IN¦až¬ËÏ<þ ð„¤Nß,tý›º£|Ca˾)~ùÒ[LÐ] h¤Ð?ž4¯A`1ÆïôÿȹU–v-­Ïð›Öö^J¡!%²Y¹Oc+ñÛ%ù$ßÌç8çZGíØ"Ü–Ð$Ïè±½¬pd›…®¹¨ u ²õà$Ç ×RD'ø|"¬ê‰y׺gÏ‹½'¡Jd½Û_iÆûþZ …€ì N‘,î?¦³³3·¢³W§dâ.oÒc­13KœzcÊ‘ [~9Èö¡S ÿ¼0,Ðeë,®ï`ìùâEï¦D⻫±¡ä­ÿ4¼Ûƒà÷&¿ß|sûí·ójò…/|£¶žž+€SÒTçÀµÂ㈼îüÍ0ÏïQ )±QÞTÜÁ’p) Qh¹ú~©‡ÿŸð3D\âIo²˜›oräǃç+ÁÚ’á°f¡ëßÔÉ…‹ üåq -Ókj¬Šé°“4ÔàTéŒ Q ›¤÷×ÖÝaBj2òËÉGçÈ“€¹' àûPôä?øG JŠpóç?ÅØ”kµêR«+ ÇÃ?ÌOï»#J Ž®û8Y™Ï“ßèÑ»ýÍ…”wÝu×—TÜsÏ=ÍvGäǃçǃ瘹Þ"̙ӃSAŒ8æU‚i@â”ZJ#U¬1œ³f¿Ü‹A Ä·G`%›ç÷  m 2›k³üqÕ¯-)˜ž䣡Gn6¢(ªiÖýÎ)F„jl=Ñ’ bI1¢”8ðóüY²oÆçùÿíÁn1†Ê"UâFÞ¢—>OÂT\xL®=T‰’l²;¡+¬¢R'‚ëûËá4FËü;Œÿ³+ãçäq ¯oî•@.¾'‹Ö`pLàé^u®ã]'›nû3äXöw2œ¬¹ºcÆ»¼«äß­ÏÈz–{ðú¸‹œŽ Ÿ{òÿýKѽÃræÑ鯄ÖSþìÁóñã둺¼ìOí{ñ„˜^,lšK2êÈøòä„¶6±‘¾ËÿÙ)Hä­¹E$P™JHìÁÈ$\ÐðÔw¤`°ö{?|»Z€í¶Žæ`âhͽCÇD)­¡¨=8öàqD„óÊÿV;m½ˆMÕ×€=¸QÎ<þ¬­€»»»s·ØŒT\”D$º†òöàØƒÓ(ß=¥¡T¿=8öàªÚè‘`”˜ñÒ0¾†ö˯؈«°—}›ÍæâaW Ø°Çœ“]óÓ/³ŽÖ€=x´ÌG¨&[~òÑ%žwšñ²‡BM@”»T£©P\<DÄ`»T…º¾µÆmá‘á">ˆ"Bm Ðða$^ýôØú£'[ÿ¡"x'PPþ{2½ˆòkŽÇFxü€ˆHûqSÌJÖ[|žHð¸,Û€læ×‡@ @%@Ü|A%€À÷d¶©@¸;R ´Z±Ý(•@ Ž«? ³vP|Þ†Šˆúü^k0U-âE ª±Xñ˜%| Î_¿gÍí»–¿>špÑ-Æ“cGϨ!%KÏk·ªëS?C&ù€Åb¡æÖ:žü½ B‰˜_‚Õø:Tµñ² nÞ1Z⿨êã~¿ÿîÖy6¾Úè"ý UmÝ5&¿¾|9_`=ͺýŒªúbó£Í¿|=R\àp8¨yäFoãa2|¶yió1\¸+JÈ›'ªÖŸXv©có`SoÓÿÁªÛþ€|Ö ºÝnŦùjµòdïL:UíDd1½/iíƒeB×fâqð‹N¼úß’ß«ƒq·Û)À¿ïïïÝ-W‡axµñ¼\.çÓnÀ‡ €Å›ˆÑ4ÕßWß÷®ðgàøoàœÊýõz-·¾S>==Ý$Ž{â7 hšméîd„  r‰ä|@à7ŒûO€ÞÜrIEND®B`‚16522qtrvsim-0.9.8/src/gui/resources/icons/document-import.png000066400000000000000000000026471467752164200236200ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î<$IDAThÕšÏoGÇ?3c\›"µQ@ü¨¢V‚CKJˆ*ª¨× rÊ$Gÿ Bþ'$àBàõB+Ô‚)=Ð TQÚô uë_õÌëaw͆Øñî:ð•FÖîξù¾™÷Þ¼yk%"¼ÍЫM [¤ÂJ)d€4kO9ÔªˆØà¦ LH)õÐkŒVJí‘V‡gk(¥fEä{kí=`NDjீ?ó=ƘÏDdŸµ`­9Ç6­õ6cÌ:kím¥Ô3±™dM"2èœ[M’ËÂ9‡ˆ ›ð87í|°ؼJÜâ`3×uðR¬_-F °sSå··M¾k-TÆFxˆ«ŒIðN;8ÀvìõÍqSËõj566öá©S§>ݾ}ûûZë®LÏ9'?^Èçów¯_¿þ31÷”R›€­õþa4=555644´1)éV¸ÿ~qttt¨-×Oksîp[Dž+ ˆnÙ^³£R©P­V‘Îd2d³YzñÒ˜eð¡ñ8‘ ‰ˆ ÈårÓ“““¿'öž;wng —‘0‘‡Ílrrrø;îÀþ» ι{.AWNL0ûÁ%ð_9ž¨8Ág)41V Å Á»±©„ 4ù†I«¨‰œs®Ù|l¸råÊ>üí=ZÈêØŸ¯,R ê ÖÚf ä ÷]¾|ù bše YQÐRȘ››k¶µZ¡¡¡¾K—.C‰„ 4' i<‘‘‘‘¯B÷ßüêõ:ƒƒƒ}£‡š$<$ŠBž>}úe»‡óóó€7£»wïî»xñâèáÇ;*±RQ(ÊN¬‹Åb$¡ÖZvíÚÕwáÂ…Ñ#GŽ,«DQhÉNÜщã,w¹\fff&…wô+­„Ìš\cGŒ(pÎqóæÍggΜ¹ TVBf;„M¨ã œ?¾mÎsìØ±­"­[·æOŸ>ýPäõø@“oª={ök@_½zõóàæøøø7€>zôè8@¡P( Å¬%;S¶–K’¹Xǹp–Ëåvà•ùb·\.·£‹l4¹W«UI§Ó ààÁƒ{Ž?¾'ÎèJ¥ Ôëõ8å”–N¬ü’E§—]¡Px¾wïÞ^`IZ…Bá9jB>Ç–û@TÔ&&&ÖjµOúûû{Œ1]¶¬µòàÁƒùk×®=$^Sð²°Õì7Æ [k;Í‚Þ µn‹ÂüjËŽoŒQþWš"òK’–ÿe`Ž•©j'©&.l…]õÏ9‹õZ¯ýj»Ï±»ªÄ@KœÖ:i…íÁçØ4Ý@ðÂZ[Éd2ºÛÐø:`ŒQ™LF[k+À üŒ7pâ2ð¤Ñh|¬”êÉf³t:RJ©T*…RJc”ÖcŒ2Æ(¥á{~Ÿfßà9x±^D‚_±ÖâÿŠsnÑóWîI£Ñ@D¤^¯7jµši4eà‰Ï¹¹(¼Ï—ýÀ ððÞœà(xGüàGàO‘ð_ 4ÐlÁ#Ÿ^žmQÇSâ`^D¼"é«·QJ¥ðLk­ÅT4DdÑ9ûE·‡HŸî%IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/finish.png000066400000000000000000000025241467752164200217440ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î<ÑIDAThíšÍOGÆŸwÆ;)*¨%¡iEQUE­µôÔpˆD•CP{à‚HÜñ'DÊÑwàÄA„8PqT* ¨À”¢ˆ” Ä—×õ»³o»^ÖÆØ^Cj[êO­½;;~Þ}?f<613ÊQlWÅç~CD€@%JÏ8À€83«äIJ†Ýð‘”ò+"ú’™?-ŽÎÌÑ[f^UJýà™€íûÉ×H)¿fæGJ)(µä¸+„¸+¥¬PJýBD̬’aPËÌ-¦iSdVLÓ3·¨…¥Ù‰ó ¸S$m^¸Kkpn€p³XŠ à&,ÍŽd·rÁÑ[j¥Ò3â’ץޏð¢\qPn9 5‰ËÉï!‰oôôô4Á.oòÁªí^t]g^¼xñíÂÂÂㆆ†jx É4MûIÓ´§š¦=P•£ÿûIâx<ŽÆÆÆÛóóóO‚Áभv³ £Ñ(’Í‹.á:^Ù¥t]Utuu}±²²ÒÑÚÚZ‡<¼a†ÓòÀÑ›R…r,äÎc4SKÇQ[[[=::úýÐÐÐw>Ÿ/«7ò5ÀÖè<÷ ¹žRÕîîîÙ:èº.쥸ƒRJ¶µµÝ_]]ýäåË—¿ŽýëËIz¿ŸBFr!¢ÑhAafü~ÿ­`0ø°³³ómww÷\8ަ÷)OUÈíæBZ4¥æææ{‹‹‹?<{öìs¸Jn9Ÿh7J©+7]×aš¦ÿùóçßLOO?®¯¯¯NÛ ÉÊk&.ÔÍ™ˆD"¨««»=55õäÕ«W[Çvfb/I|­3c{{›×××E{{»—[ Jâk5 ‹affæ ¯¯oýôôô¨···±qÜ!”Ó^ã3¦ibkk+Þßß¿¹¼¼ü'€0€@eô¿¡p8Ì“““¯%‰CQ @ÀãØB(/e½^UU¢‹Ã†µµµÈÀÀ@hssó @"½2z W2;::f²u˜˜˜xR–Ó‡‡‡j||üÍëׯ7˜ù@ WŸ‰­^’Xƒåò˸垈t]ÇÒÒÒñàààÆþþþ[ûþKs¡áéÅžœ›äDµ··w6::º377÷€qäØª¼®ü8‰ðìììÁÈÈȺ¦iïüƒ,OÝÍÉɉ—r´3ƒˆîxà—QÒ¨njjº …Þ8…µžïñ‡°ö;“Øc\Æ€Ÿ™y×Kç" …6`…‹× #=¿rÝŸ1‰I+ìN'V=3¿’Ø3n«”¶Uˆ2ÍB%†­ñÿ­’!%„„(}{lB(ådÑS¡AŒ'lNÉMpª”Šùý~!¥,9oH)Éï÷ ¥T Ö,}þ;1¬YpÇ0Œ&"ª Fee¥ˆÈçóˆHJIBH)IJID÷9»Ó7y”RÌÌÉ#+¥`Ù4Í”ëiçØ0 03Ÿ‰DB†°ckvÖBëçËÏ´¨‡µ>)%Na ÿÀ€}ff÷_ €u°ÄWG祜Á2â€cf¶6IÓÿnCD>X¡Uj5Õ`0sÊòü_%Ø©×!*\IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/forward.png000066400000000000000000000023741467752164200221330ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î<yIDAThíšÏoGÇ?oÇqlZ„„Ÿ=DœŠàµR­ªª½p*Uˆ3Bܸð/â\rBH„!$$Eæ¦U)2‘…PKSbAÇ?â}=ìzq'±×vmKýJ£]gg¾oÞ¯Ùg‹ª2ÈpzM ]Äê?ˆˆ@œþÎÖ€²ªÚZ§ÔLHD†}ƘOEäU=Úž!"©ê¯ÖÚ_€%U­@ `çGŒ1§TõŒµ ßœãˆã8GŒ1CÖÚYy£ª¶f&I`TUÇ=Ïë%Émáyª:Œâsí|Øì·VpŸë¼À»zÅ(vás  B¾ý*[†³Å}¿ÃÙt3¨¨`Ð|Xï㤠‡.:qòâÅ‹'ØpÎêºáÄLLLœJ¥Rg;¶—î˜fw¸\.süøñý?þîêÕ«ŸdÍnÀ©»vLk-Õj:þü‰t:ýÃéÓ§?êà!ßuQ¨Éƒœ†7´D]Ãuݰ•Ëe8°gjjêÌäää×±Xl¸æÇÐ,EU‘CÀWÀ7M̱7—Ëý´Ý€ÕÕU½ªcX^^.^¹r%}÷îÝ,`7?Ý~Rªú:Š£óóóßG\€x<®OŸ>]¸páB*ŸÏ"L ) Õ›H”V,åäÉ“Gggg¼téÒ8­‡Üö¢µ¶íV­VQÕáË—/öàÁƒoÇÆÆö!äFÊÄíj ¾ >¬¶ò|M€–ÞÈ‚ªE[ð¯÷îÝ{}ëÖ­L¥RùXZ™t“ µ¤\.·í.ŒŒˆÈæé\×ennnõæÍ›óÙlöþ®—š]· 5Ðl²çÎKm7`ffæËd2iêû–––ìôôô«™™™çªú(=‡\£8ñ»`ñ­4¶»"ªÕ*OžCÀñÿÂVß NÜUlåÄë: ðÇéd¶ì Žáq¤&@X¶Ö–‰„cŒé;mc$‘H8ÖÚuÂZ&./]×ýXDF’ɤÇc""±X cŒ8Žƒ1FŒ1""Ô÷c±µï¬µªªµ«Zk ®êyÞºï7ô©ëº¨ª®­­¹•JŸ®[^œÃÊœàÿ|yÆ€=ÿá7ƒe|â¿¿‹ªªõ5p€à>ùxoxn‰5|!^oUÕ/’n¬aŠH ß´ú-¦z€«ªëÎXÿ‚×…ë~ ÀIEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/gui.icns000066400000000000000000005211431467752164200214230ustar00rootroot00000000000000icns¢cic12 ‰PNG  IHDR@@ªiqÞziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆCIDATxí[ t•Õ•þî#¹ÉMÈ’! „—X¢¼(‚"}H‹Z@h­3ãPtÖLÕe]­Î¬1Ö:«N;R+k´ÕÊS|€(¢¶ ¨ bD Ã;IBòºyÞÇ|ûÿïïÿßÜgx¬åj÷ZçžsöÙ{Ÿsö9ÿÞûœÿ¿Àßáo[¦X§Ï´‘ÉäÙÉT+ï%Ò—“öKe'[/QŽÝl¨EW™C²«=yÙuLó¤p9!âX³jL.;œêíÔtºÂ¹øäA×í—sÑÊ**±Ö -´ü‰ô^žË¨<-0:k0dn ë›4œ=E6K«^ÕÜg’Åø¹®Ó6.Ð&*¡V‡‹©öá”öZL¯.ñÿ°»'/¥Ë° ¸Á_Þ¿+àë²RWjœó; ’ø-5/®rÑ•ZK”û(ù×_ŠŒ°  {)£'ð°_¼ÐÓéʺ¸ÆˆàöXÐÔ=® t¹R•Ôë¶#Þì@‚¥EIvë¤ÛΰwDyŽ÷VÀ\¡#|“c¬ÖÕ•bfî¶|¬5 ޶Ö} lUg(,»!¤ktzl¨ë‡ÚŽñ¨ë §;!”(^’xƒí‘•P ³©××PXÊP8ìŠsòyä9É$w1•p4@†¡v(#TdµÏ´OGUË|t»å¸=ô¸“pÖqƒ’-1:mr“>jWéeq/~2ó+¯€ÚÎ ¨¸¸çÀ ãâ,d§:‘“æD*ÐèºÖ$¦x¸ÜF;ÜéJÇçwãDë71.ýu L8TæåBFÜ´cÙÙMÞkª\wU}æTª®ÑÑæoãXëÜ>ã)ÌéÆm×¶1µâºÜÖ^’“ÿd-¦U±Ây~ö¹~‹í{jñî‘1¨nN÷Éií‚=õ 8} |H¼ÅS­¯¬Y+ ^Âu´û}Lý(„U'ŸJ™rð)ÕdÇ'ª3qºm(oü!j;ÇkMJ>&»ÿ>ï=ÌU“Iì'¡^ÍÔ_/Ž«Ù…éLO߆ÿ¼õ-¼uö”nÉ™ ñ ©(XvVkÏLÌØHy&ÙÚw«r”_Çè *u¸˜Ša@I›™fJt{¬Ø{a%-ü_SB\/žZ°K&í‡ÅÆ¢'ãÌ©W—ÃÇ+3•µ°¤ &µâ…™xâÍ,PUÙbzi'Æy^6𰲂i( ß}ÌåÙc³ÙÖè­¤A<§5hy$htºÜ„/šî2L~Hz/Ö®¬Æ„¼Ñ¤“8%Š·z°r^&ïÄ=«‡á¢Cµgµô,»ÎÇ]ùÛ |õMƒ‰8änC+bU’€‹ÊècVÀ¾Ê™ŠµVeEƒ»±ùÁÓÈjxPu>ZC¸Ük $º÷“øP3â€?/Œï¬{ _µ Tð{*ç °°ß(–Ë!zVÙ&¤Ž¢IQ–bRµ¾å‘äÂúû«‘•B£h¦a‹ꃸñ”逽¸w~°îŸþŠùÏÞ‚®^u'¼úÞ"\3ü$µ)ôC³Îw°0éz¯yî÷–_d¾Ç[.çêò–}YL xg÷x<ªÛ²˜=xéG»1ÜN '³bŸ|rû,)@ÂpÄ Æ¶e†àŸÛŠç–쎢’=½ñxÿÿæbѼ7•ºüpb‡™I·ùw™i ØÍ¶µ‚‘ð%Þ^tê\>VÑ€yáG×nÃôÏu¦oÞHÅ<ýg¦Œðà{ÓÈ›°Ü@ÔÜI÷²z=nÈ÷àÍ„(ÔÊwÓýï|9MA”}13K> ô›¬r¿!¬è^ÊéfVQzãk,¼ù0é)ÉæÆÃK €¿’jHøÝº¿à×;vˆûÂÁáÝ›­#M‹ûß„õ» ÞjÅm GRB0;¦ò<öýjlÊ w ›ÁÓš·—|úÓåϾÅ16è¤Æ\ «‘Æ>â¶:È⽚ô77bàquÞ(®å [ ±êT¯ã¡ë/}û6hŠôGO”cÃî/†§ mg_ERjáØ¨óÔ›P0È¥?À+nUxªÏçþëÓ¿>,0vc͇†f–Õ÷îΩÍFÊ.N¾óƒ5^–’?èÙôi *ÎðyQ—n­¥=щ1ðéåøcŠ;ÇîÔ1@ÂÆzDʾIE`ö]ƒ‹Ûiã@Z8úÔýl y@ör]Jö-üQ°² 6îÀ†G–áh wþgŒ´ƒîÒqµ’ÜJd&;ÑØî¶Œëò˜ªwmÀÐø¸žÙšÔ[&ÒýÈŠwÖPQç›>>¨ì‚Ò áêë—?:“sdz/X­½3µrsŸ*C pº,Ó\.‹‰h9aAïç;U Ñˤï[õö­ÖPþ¼Qwoˆá¤¨Ö_ˆ ³ýý[Ì®<.Pí}qÿ ì ð]݉›\n5‘.äHÚ¿àDh˜=¤ó¸}¤CÓ”rYåßêç¦ùš½ôÂÚ΋>œ4ÿeI¯3>Ýí6…wE>Îà…° ‹¹Õa|.sRý.’XZmÅØ‹|$.V­·†(ÎMÅwÆk5æbĆ&“qˆzˆ;¼ØšfÓI‰¹h”„Ýã1ÁÆŽZ8uÆççø¿c¢ÿŽÀ‡eAÎÎf=ÆP #Ó@”>R%¢R“[ 2êZ¢9wX”йi3ž_šŒ¡éq¸óú4,CC êÖÐÀž Ö¢àjuý›yìÎHmê IEC«ãçLJt@:’í&PÛB–âÅ~‚hKž^L+ˆÇÙgFù9â2Xnò×£(Õ6û …"³¹îD×O$<Ë[kJrëÂæVÕb¯•G.âÆÑuá-º HK6âío±^fÄE¨¨Ó‡Ëq3OD` ÛVt/ŸÐ¸3So †ˆ¤÷÷;ð‹‰? Jk/žrâ«ß´ê|ý™Ru±Gþ’m¯â-$˜ŠäðÁ!¿Qv{L»8ÆÓaD,aÿO„~ß@VBËÊ2s dƯH½òÂpœ¶üò3ý‰àaUw²~ T•ŸÄϘSëJ˜ïS˼à„ú´ÛýíÞ–pÙþs£ÑÐæZÛS_B€¸óLƒ™æ3½A%|?”¢ÝËÛ(ˆº ¯}VÀó;¢OrÇ'×\..“÷4¾øI½ ÐH. ‹¤ÇD,¿^1KOÓÂÊn=BÊœ¨X×YL¢9-‰äÙíw€pPhìdq®ÔÿáHü¸èId&=„´ù€Äò9ßÄÔ1ù *En“ìõò9ßÀ”Œ=@ÊT¤&%øXƒN7$cíóôM[9® A ñUï,ïb’ )¡ÏNˆ¨Úå½Àîý[mÞq»¢€¶n;~sxJïüвƒ€rëãFÉ5¹JR(‚\‚N•‹Édf 畦k‘ˆ'·OâͰ:\¾Gô¬\¼ÚS˜7f2ÑýÁè£UBØG€“çýµò^à÷3'òÓ±…G|}ýaW&ö A’«¬>‰«}aûáaØ\. ©ÂÔkÿj*Ì;ɰ?æÇhøÀ\”@Ü,&ýãð ž.¬HÈŠÿ¥È·gnó½ìèu™ðÃç‡ál#WN@ukõrû–y„O›r*êóqßÚé>yñ|ÿpëô´ú ~¥U‚å:%hÛÕ°Õ")À 3g`fNxׇkh³âîçòx>kNW8qåâ3zÔ4ÅaÙë¡£Çÿ¤.šû&—„í)°Ñ«„ÑÄßÄTªo÷KÖcÔ§ñVæøñlÔ8&+T5 ˜»ú'X{÷Ë(ÖßùÉ3*0^ ˈ_†‘îoÚwÜ®ì0Q²iɸ®øs­SN%ˆßþ8)¦ 2{øžn=ÒãÏødÉKÍùÿ»›ö¦Ñ<-÷üòòC¢?-É™^w<ö1œß?y!knÏÄK[–Ãé2âDÄTí‡øò0LÉzŽ3ø¢£'?ùãPÜüÄì®dÈkŠW“ÄÉ“Œ =°î³ð´W`ÛÞfÌxñwxts ÄÆhP›E¨8^|Y• N($|ï¶A‡ØÈ X#r0¼­¯vS N M*çû}.öŒÐšùÎ?›öçcÛçvÔ×Eª…o޲GÂÔ[Ï@‰áoúÍjÀD›áNšˆý5x±lÙ< ,‹¦N¾@ÑÁ˜´·1!crøI½“®Ðiþ¡:W?ÅG‹³ºß¼½¡CÇSѯælt3b8–hÍՕΑǸ”x@Ã¼Æîp¦k(Cnç{„œ'qé™ÃÑØtµmÉLé|å|&ÇÕó‰7 »ÌšSðö;Ÿ¯˜ÕÓkS ñuõ$þ‚å3~ÚÐi”•ˆ ”ê!·'§ÚnDUë- XÄ+ôl–VŒN}yÉ{‚}"³tkõªrJþ)G׃„éÿÍô3*"’;Ò±éîú Ø~Täæ‚”ÊÀå“ùp¢¾³˜or n7¨d«¹ òœçØq—âãÕ”NœàQ†¹³Yäóä{%.òÃLilûçX”pùÌ){ˆ3wbXÒ>%Éä» ÑáÌ@·÷39ù Êfn§QS?“K²6 Ãv‚×c¾³–*(̯W M$ÑïáøGù‰E í, ‚ Ú7B׫Ué÷v~Y‡¯äM§Jò3PaËziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ€IDATxí= xTÕÕ'Ûdßw ì²ïû"qi "Šš µýÔ¶¶U«þµÖ¿b+ú× Åº´"‹BÝe5ì–Uö²’I&™d2ÉÎ˼™7oî}ófæÍæ|ßwï9çÞ{î½çnçÞ÷ Zk µZk µZk µ~ˆ5ä«Bçèô$æõºŽ¾ÊÓOù\Á|£{íƒÝšý$ƒêlCTszÀˆF_Š.уdn–¨ñ(èDtg_½q,Ð…ö‘€Ó|”O esg ÓÅW @½â‡7E™}¥?´Æ¿iÊ«É"pÙ´¸Î(u4ârï2AÉ•&ùÖE%· †¾cÃÄÖ‰ÉsÑœ'O># ûŪQ®Ã0¥u+&É(”U;4Ÿ¡´RŸ | e4 GÎÍ–òìÆÑà†?Êæ¶ ð?A?ñ‡Ð·Hž]°k,e‰ÏÝþ(Wë"е@y¶*@5†?DiUÔzåÙªÔþ¥UüQë”g«PcøC”VðG­Pž­ @áQZÀµ@yºm Ä2¢ûÜR–P™nQªPP:D#8×òðý¯V§«Pô™<ñ[O™5ó&ÚÿE`2øéÉà ùÜÊ£‚¡ÞFs<>ã!(¨ "Bª§ 6`šUÏ­r»I+x 3ÿ‚'@õæ_"u_€E¾Þ Åu½¡ª¡½ÐØÔàFs6z61{p 2CxˆÞª¤Éáç!-â„U嫆©¢¨éäû±o£Í”œµ6‘£ G·üzÁ´£Ln صäFBJQðRèJ¤ß§Ä£–VÓ˜ŵ}°áû@E}6FÓ¦¤)§!#ò(ºc¨ zµ"ñøÖá­`MîBbãwÂLö¢KµdVƒÏ±¨-a·Zn  &¢¾¡-Ö„"lôSºš(.ó45‡@i]OÁ…Y¨»QG!+ê;ˆ õËQ½´ ³1 6>ácÐ=ŠîÖVCc œªœŽ?€ íS¸Ñ äNWMƒŽ1Û¡KüFhY?øT 13äÐYŽp'#@CS Vü¸\3 ¨gú(ÿóÕàŠa8t‰Ûc·AHÉŸ"išw@)€¹Y‡•=Îé'Ac­uLM‘p¢ò.¸X=º%¬…vÑûqõqó_t (©ëG*f «xw›=%¶2Z\f¼Ið§7~ &s”Ôw…bÓ(® …âòZ(ÖGA¥‘¦RנΜ‡¯?çõ``ʈ »æZÆ „=~ö®»±j\[ѧÅ5ÂÔ~Õèô0º›ÂÃûû‹ëqÛoˆê aY@–⦤æ T£aKÍXw$6†šzõÕQmÊ„üâßÀ€”¥ÂÎAÞ®Á!÷&; ž!”ÀmDCP©<ž¯ÃêK¬ ô?HîÆ`é¸ ž%°©9 WÌ‚ÃFT6*'£¦a£çö×Cÿì:vMgì0À½=*áÞ!5Р?ùÃú3Ã`Ýù P¢gÝä¶‹Íá°¿lôHX-¬¤m˜<¹/Ùǰ mÀÐT;Œš(ÊÝ]Wä'cÍþòypCØË;Ù%M/N? Sz¢eÏÂ_ë<4ó: }\]hLèxPpó“nÀ²Ã·Ãk«S¡¼ÚyÄŠ¾¡ ôK^qÓ-—ξž¬!ìõÉ G@  ªÚaÏùÐ|ê Òc*à÷£VÀý}6¡¥‡r ša!MðÓq0sX%,Þ”‹6&Cm½òÁ)Ù) ©0$õ=4"U:+ѧ`þÖ¸§ƒcj"iÍ£\*åÜ~ŽäÓç|¼´¤u£¡ä—<å´ñctuðü˜¥pà±y0§ß†–ÆW–GsjLD<3½¾{å,ä­€`åѤMÒ;q]@æh•ð:ò‘¬’_s6·Gw$1b?€=ߌs¿tM¯‚nƒŽ)¤Ÿ÷*±ª§…Æ«ç•qÒbsÁEpï`=<òv;¨0ðmuæD¡ŒmÊRQ¢¹79èezaDÃä ÷À8t#‡+ˆø ÍÄåVØg @N &g½cbïxwnÄEæ°äõ+nDWlzá<øöp²o§ Qn×…YÐü*Ü×(T sW;%âƒlýí)¬ˆ—¾ºÂ‚ߣrŒF%8É"JqžLÒtœøƒ„½3 ‘Jðøå°âñ+Øø8×(tHi€õÏ^€É}«%<_>¶ì§È#·îK=\¹rDfuÏdd{L «OF€ÃW' ‡98´÷ˆQ³©µÈÑ]ƒe|²âÕ Ö ¯›eËáûõÔrøñ*%º'ú]i,[T¦Ï@½OEz!Øa¢{1“PBþ!÷œ®ì ›NãÀú†pX±ö~øíÃo¢ý‚-Ç ^ –¯™=£ÓΊµ¥¦…aš,yÚk—á(xÝ¿qþßFgàUøvï %à™qŸ¿§Äžœþ}ØÓÐÅç°ýU¬)ÂÛ©Ÿ"$2Ñ~àÝÇqSÿj=œ.b/ JÚ¡“ý`@ÏC’˜ö^l°ýˆ!縠û7"ód„}gŠ çrÐkS@¥>¶7š+P¶õðöO <2år÷1!í+ž¸‰Ñ|E[»c*4š½ÚßÜ*µ×$Z—?™[àÄÈ:X>k1Äèñ¦Ç7¯åŽ‘Í 0Pe«éy? Ü>¸¯üèƒ<¼Ã Úªmù]¯J‚]‡†ÃØA;mÈðy¢»QþW-eÀqÖEe™pàØ Bæ{fÔ‡Ð!l žÈÉn+ëŽôm /Î6QÝ0¥lU©éËÀ¡<Èhƒ_±ŒR…Ë4*íÌêÝ>::‰É³q÷$ÀD„‰N Ÿ©Æó–§Ïn+Ú®·¢´ämÚ¹øèK~‚ÕÛsqÙåØ ˆ–P÷Ã#Z `õ÷øeª÷ƒ GÞ0œŒWæ5ýV)œg°—P?Áøõ¸f¦ø=Ò ?îç<žÇïG/‡ÏNŒÅ4ul†º(øvßx˜6F(ÿ¬Ã=L>F¸­<9Ï_í'Î÷à‘á…&Ðåü/—®–Є§|¾0ß D1¡<øaœýc3´‘¯—剦΄2].Ü¿d6Tƒ5þÜ•‘p÷]ÿ¡!îO 8Àc#öÂ[;ÆÈsÂ[÷iÕWI|¬¾œÉàc¤û%µ”öztssÀÒ¯giO²…úu¨ƒ»¡-»›‡îBq”ë[_Ì¡¯ê½¶‰=òˆ<Â3(Þø"jŒ-/Òª F8UxÝcÙ~56#Ø–ÂFsXпø öþ9b¾þ|j2`aNQ!p»‚- #yzé'%üU¿WƒÆ«¼¨øÆ‰í@B}gÀ3÷×A2×IÒ7´l›ËôFX´ÐXsùP \p\€„&XcÄGá©«àÅ-s­8™ç /’áüÔD$’Cª$lõÍ©…Qxm‹ Æ+%K¹d‚ÐF޽æó×¾:o>!ÓÃúLÿC!™7¾ Âó}‡[×Wˆ‹I‹:õ>€Øvè¹×Àßvß7Œ±vxK`,v–DÜÇã6È¿ Õ –‚4› wðÆ~™¼³ù\«`çW†;E;Øñ´ÄêBL0)‡,¼L ŽG g¿ƒf#j4uG®ä:9=³« aßÁå0Q³wõ¦&xí“mðæcwáx4ùl&Ø76ÚaÆrHR@$¡q-Í6œ³™dØp¶¬¹]öÀ¾Ÿ c¶ïFß kÈOÍå§¥«=Û¡C.z –9>< çÌxk ."_~êϧ%º Ø @äwÖïƒgfŒƒ6I¶tʪ °è›Ï‰Ì‡¨î˜7­å=‡ñt64:NU˜úTì48 =ÏÉý´œø½mþ Ìñ8Ó¦«ªct¼ÃzYÓ— C[$Iázu­4(øY|L!¨X ÒÔ³øY­TQ eIÆmÀø´~ÐQ:U5ü!2ð-]M€Ì­ñ£mIqìsoÏÅÏÙø8¾yXåÿØÁ ºj  ¤¬J’4¯ꢅ;¡!¾í$ÑÀ°¦£¤™Zdk`Í“gx$w*¬>´ ®–ñGÔÌ„0˜;¢€1…¸j(ûebLQ6IA©è ±ç?‹°&»} ߨÃÓ~IýhêÕ…†Àó÷MPLóÙÜtˆtœ’ãxBTª}5ôô$Oµq5Q›¡Um¶ÞåË›4Ú¥âˆÁ€Ì¤X˜76™AñÊú63#‹fÆõ1›×Pš(@\4¯K_äð5(ÏΑ:ŠMs<}P¢j‡ÛÅ(®ä×A\,¿îÜÎÐ…ˆ.Ô?Õø~!J|­Â>þ䌆îmí§¦ÎéØûÇàkVgCJ\sXøšÔçW€ŠR(u'ÉjB櫦 É+)€’ö»…zÖò¯„oiÒödýÏðcz+‚`ï%|ÿm4ï? ‡ÈŠeêÓÒˆ³˜a ¤£"j!,Ô;’AˆáÛú­…§7~:Χ<Ñ~£ÉÀÓ’–Âo‡$€ÍO6  Qš‡’Єěñ^ &é{’ˆ& ‚_ªšZGk mÀF÷EÃ'MÆ;ö @Æf ‘”–œìI¥Jã6á ¹„³P9¥ixÓ`k,ÂÝI…a)@AE˜o{ } ,6Óy —r½¯¥UaøÍC¦ Bµ!j7 ú!º Îö‡Û €¶kºU9ÄB³ðªøØª™…¥Žgô‘¥…Ð+˯÷¼S{*RÝv’y'PˆYXšµëñ]ÉxÅmKÔ!ó ÷}€õÛöA¯‘«äQda'ÖzËWøv€%Z‰,º,| }’—ý2±˜µ'q,–,KÅÞ}®?b¿‘å¶Wv%xÞ(j‹7Š ]‰$çÕj5¶8!¶òòÄÅðº3CÑ^Ž«]E';Á#[Ÿ¨ òøVšÄCoKù¬$•ñ­üž{ŒøvЖãÜ sØìA.x8ÛH þºs¶RîH©ÉJ ©X„_ŽO¦ì-èÎ…©]<Ùý´äBǽ«_Êc×—Š-^Ûäø–ø´µ¤]CTóN;eìâüP^ko”Ä Õë§’°K^­•À @[›­èƳJöò®§aÒÄÓøí_G²”®`%P¸R}(,ÊÉ•)&²féŸù*z¤áîI…ª:&¥¥h¢h üŠÙ­EÔßÁù«#~ô¸£äˆ9[ïN…9£o0é\$snX€Ÿ˜¯m ³HG OÃ<7ïµ¹H!·ÝTG.u­”@«]@W»è:·»Ø¥ÃÜ’¼ò%þ÷瀄é& |w!–îLäJ:q؈ŽT»õç&c%`ÀÙîà+\—qÛÙín…½žîU‰w«H쀾ƒsôto07…Øá)@çs·‡ÕO_‚ˆ0*ÃÍ…U 0ç½öX^Ý€g%ò/„iò*F‚(MÇß2Äòèûh?Çq -¸Hyâ) ×adÿ=r´5|èR$üòÃ6¶?ô 7€.¾ÐâjŽXùÜò¤ÎÀ»¯´8ú—¡Îs>ʃ2œÿy;z^þ0Éɯ#‚Ü`9Á•°Š‘€+whpEï#6C¸®žG†Ï÷ÇÃß7¤´Ð…oób5S%y8*Ðz!(¬ÅI†¸’¸O bž\û-jËM$3µßö_.] ‚‚œÄô·ðòðªÐ%‘™“•w<¯|™ŽpLxr þ]3áËS£¹òЕ¯Ù¹«ðÛH*57Á¢´ú¾Ýèæ£…x‡¡ñp‡‘ÁÓç@ü>î±Cép¸`"3)²ÁÌ{/ þù`LKc²$’ä^øM üe‡¢Á%´ËÐÀú©²°±iMç ªÎ¼®$÷ ì5P|=ÿñû6 :˜=üï‘ðܘYðüº{%‰FWµ…7r$8ž7ûO-÷xt7ðFS0üziøt×Ô+¤JŸ…UÚ ¹‘µæQ¼:ˆÒ’éw@òˆ +QÌç«;æÀϾzPè¥pæoY/КAÉ1srIÛ×é ²6>åpòBwÐ+¼7é¾ÚÅô‰¸¡Áõ04õ§ÿÀýÅÉ1pç¢;àÚ \ÄIlõôÞž'½O MÃCÿáË‘0q~g Œ(­H…Eÿ" •ÀIWSSLõé¯Ùž_™Ãÿ˜_ˆG…a²yI_÷Z¼ÿnôÏÁ[;Ç;mü°`¶•OT‚@œ|:ˆ­•~Æd,þ=Toâÿr™NØ%üc]¼4e#ŒêtQLÆö¤û4Bx ×pa¹JH¾÷ÿÙ‘>0ÓípµRݨ“ù=®s–âŸ`ß—kF8H"*A ž(Àn,å«–’>çPb'ˆ¨Ð •ñ78XþîèA¶…{þ•2Ï@n×=‚ë’\€;ð~€g Єœ8xÅëÎ ‡5§GÀ…m”’Psâ6áH¯AYš OÒJ¢B ªQ< âÝù“äâ¯Ó—šlñ\€N~úòxyÿNüdI;]5 ÎTMæEçâ;' w r‡ÆÀ ^Y¶QK×ô:šp-MÍÅKZÒJ›%|l‚†øÛ>ÅF"ÜS(5$rób‚ƒ¡_ÒG}ÀŽ,”Éx?œ)n‡iIeðØŒ÷¶þú»&ˆ8=ý®bÁ‹jûÃü+ù†¦(åÒ3R×ô5’ ü*WzÄyÈD—<Þq¾™ÅeP\t J°‘‹Ý ¸:è=ÎW<æM Ú)K Qw‰É›lŽ8x“ˆë¾¾²p:’ßA7—ÃvñKÐÑÐsÝTˆ³øôh¢Î¤Íщ&Æûœñ‰ôºÆD8…ÓÂUÃDùDD1kî3$Èb·BNÜf ®ãòIë>Ø}ašå,^I $Q€4êÏèæ+Ùï¥<õû|¨FàÈÐÐ?y9ŒËü+¤EâÜíG Ef‡˜Ýp{›—q¡·Zmã[%Ɔ¤S ÇнoEò=4콄îSTŸM; e°VÃR߆ŠúÎP`ˆ»…ÞøïãÜË–š–#6¬2" <ò{¤Ø ¤s[Š¿w!õŒ3ãÒ%R¯OÆWW§~iƒ ²¡×ö"Ü:V›2ù¬.Sš!)ü¢ÐèQÇ &´Ôåd„)@гL——%Å+ø¿FšW•  GÇŠi†ÝÁuÇ}·¡1EPú[z£9ÞêÌÍÊ£'Íá!UV—„†©ŒÈcBðXFWêÜë#+Âx¯fÜL9:´:ÇÉ/»á¶/•!ΪtClðplxZÐùhÛ—áBþ^U‚€Q€ü·§oNá•jÇ­Uî†uL†œ4öÍ¡üsepñºòÙ‚Xá³gãÆÂ6ó}´ÿ˜ñvGVBŒï–.²9< nÔÂÖ3%~D§T蜊§“ h #ó$š*mðüß ÇkÑýmU>¯)& `ÿ^€]zc(HÉHÜÔøë¿¿&<íb[Ͱ™€¥f<)j4ÛÕ³5¦3O#Æ¥øä”€¨bÍtÈ $¦“•ï’œí鼿Á_þõ4ÐßÊ»^QM Ò] $°Ë?¿án» @ÿZTÕ²ïæ)AR´ÿÔfA¼QÛ`IÚ`϶õw»ÎÇIŒ«îI.[ý€;ii®n+€³÷Ô–nÃñ"kÏÏÀžÔ=ÿºUÚdx³¦X{/” I^74@Ž,ñÞm ·äPqÇÙR8Oÿ‡0±{:þaƒ}z²è>Ò=I“I+7àõu×AS%ðÄôs”ý´Å©»"Ã(låOœ£tÌÆ§(=2â`X§è™Cq-p+À°¾û`Ö”OÜ-ЍÊÛ©{¢*’WÏ‹¯kË{¾46)Á­Òøb¹A FÄJù¡=I †ÜvàC7ËíñHЪnÖ¼–ÑfO[µÓ›çfš)A«¸YëZGC+!ù\ Z@ë–ô =(A«xÐ`Þˆêk%hUo´¢‡ij R+B«¨­)óy¨ÏàÑs?5"ß4 @æwѯ¦`·J@í:MMx¢»1ƒW-NM^Š<å5F¨6²i©ñwž+…'‹ÀdöÎ{öå5õ WÈÿb¹ºÓFÅBÚ«0Ho[cO²…À÷Umñnázh-ÚÍPÿÀÒ+{©K#ØIEND®B`‚ic139H‰PNG  IHDR\r¨fziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ7IDATxí}œEÚþ;³9çȲKÉ9IVL$=TŒßÞwêw§w÷×;³xzŠˆøIň .QIËX–ÍËæÙ8ÿ÷v`vvBwu÷LwOÕïW;ÛßzªëéŠopÃàp8ŽG€#Ààp8ŽG€#Ààp8ŽG€#Ààp8Ž€^0è¥ ¶å¸c\ÆL|~íp´©¶~üÍ!P†ïGûî²ìÜÕš“^å늰áSy^AKŸý!@p3A«þŠæ½“­b¹Þ†)óƯ¼^Oø”à÷^—BG覀_"³R´q:ª^”®´ S<öjºzq±è©Ð Ï¿Ø7@{áPä¡Ú[ë‰ú©b.•𺖠T=€žÊ"Sõê6?Ý–ÌÃãÆÃ€óì8jB€€šjƒËÂð0œ< 8ÏŽ# &T³ ¸âÕþݘ1Œà$9ÞzÍÉým³ãóhB ïè–uq ’Aô!‹PaÊ‚ævzO¼g"Š!.è$$Ÿ€¸à“j'„û—eç¾á=´œçŒ ?}ŸFû[´DdÌh× }‰ ŒÔbÔÔP &ŠÈÑÐ e¦~>KÖ/»×¶$#)%C~ÝDLÎ Qg!>èÄ[!‡Mrd£ë4:¾úßc!GÚ”>´7 ‚a†! œµó÷Ú#'¡§¯zQÃp8S?ªšz)˜“ÜI º9ÍbOÕN?C3¤„„îa{,„@C n"ð$ºÚ7~Û€‰øð’ÀÕHÔ+ðºá s´›ý Ô4ý((iô¬uÓf„B$1²Á~Õ¶íˆ (ÒzÑd“5}åàU†¾¹Â*„€L×·&@ní8[?Çóa2¥ª¾dLmQS3Íb£ ¡GØNè¾ËÒKPŸ´•ˆuŒÀ‡c8NÁRu°š–T8Y=»úÃpäLß14L8Ô¼ŽW_ ½#·B¯ðí¸iò:—4µó£Ë§n.}=èÉ{Œ`ŸoN‡Øð‹3¦ ŸhÍíápôüµØ+˜ßA¯ˆmj_EÐøK @$€•M½±áÏÂq~‘1õ¼¥=ÄÒ !B¯ˆíÐ;b ùÕê¿à.!'•Gcß#Uóà,võ¹qM äׇ~Q›,dÀW\cæ-_Nn7ƒ'÷&ã—mŽe®›àÜÛÚÆ|¸j®ˆŒÁ1« &(߯—ÿ«8¸¨êîÿ\yÐD7ìÐdáö’Çpµ`' ˆþçT¹+–½€ŽÉ ÀAåѤ֑ªëñË5Ú¯wýÍÔáÁdÛ Üûû°wâuÍ!hCñž{LŒl…Ìä&´Í™ÔY¿Ýb[€ “ÉÇÍgíÍœ a@Ä(Kã'È+Å1ùéJÈÉ= '+Ò §²œBÛÐBÛÖ=khwäÁÊE¸Ij [ ÆÏ Àsë„'€8h Ÿ–±ŽŸƒëùžU“…}b¿z‹×§âÂå9²kÀm ØSÜà RW^¬|*ï‰òî°½î°ýxüp< Î7xn×"-Ÿ~Wœ#â—AL`þE¹ø?žE€âÝÔ*{li/2¤ ®R SÔÁ„¾õÝêÙZÇÜ Hs}ãOCߥ°dj ´µàHal?›÷7¹éŠoljġʎâ߀˜¸dø-Je×»q‚JROã„‹úç 7k÷!ÕÒñ}Ì juÞ‹òLpRçΜiëÅI//l‡Ÿ··8 çÔ½¢)»üw`—_¾s÷Ž2ó3šaÚ :¸qìy˜=¸‚„½ìŽÒRÂä³ô°·pÿеpöl¬ýe ¬:4 NTtW"KKšÔÛ:R5×r$zHÜ œ tߦ£ã‹02YVó0F|…5²žâ©†Ôqhoñ$¸´wŸÖö•ÜÂ;¨» n欆øˆVOOR^Ý"Ëàá1kà¡1ká`q&¬>6ÖUõÊ ŠñàÔ¶â'`LÂRˆ8'IvY8j"áRKi€_Î_cóKNÊI4– u?L±=ŵjh¨0$ù$ éµþts,ÿ>^û*Jkäu[c`GÉoat›¤Š³2Z­6ÁrË_‹‚³öN@êr¬X§qsŠfZÖIøí”m0&½àBòJëi÷\¯" —3£îšR fÇÀË_ÄCae€¬0ÒvâìÒ`dü»rXÖ´yb]ð) -ªûp¼Oçôå6Ó3öÁ&­€Ë“s.$­ã½.4qÇäJ¸eB¬Ùÿø$Šªä#‚vsì)»†Ä}ˆJHvË]U<=¼B8á7e°_k»ÆF.ÙÿmÁõçÝe÷BeS†¬i§áXùï3Þ„ÙY»-3ë²&®òÄüÌ–ùëFÔÀ ›`éæ8Ü$Ïx‡zj*n±¬ÐdFnA$d4}ßÁ?ØÁ»WH¯¤O¯"¼­Çv¡‚ŽJFw)²Un€±î½· B|ö ¼O<5¿Ä²ÂñûS û„| Q~9а ô§²Õ]GB¤EÚÖÄÙ>øÊÿÞ"áKÝþÝ¥÷ÉÚø'¤ÿ ÏÏ|²â =V-dÔ/µ 6>–ëöDÁ“«“¡¼Vž×ëdÍL‹~R:¼ÈSCòÊ$[j¤ooÙ]PÕÜS–4ýŒíð—ŸÃ¯Çmà 6"0M•êð÷Þ6fZñX0º&÷¯‡ûÞIƒmGåé 9?u ÔYtÊR™A=$¼Ð“`i’´IÀ´³¬n~+Ph¥›0ÌÞº%ZÛÿ©òfÜÝ7€Ûˆ´ÿí» aTï^èL–W$ày†ÕÀK¸RðOœ$l—a âfËI¾pÂUÖ’ü:”{Þ†‰üm?´ösU’ÒïˆüGü%+È Lùp9Úç šEH‰Â ÌZÉ`¸Î§ùH‹­f&îÜûöϧ°ñ»ß¥&G~zIƒvÒ^ˆqX%}¹’&÷–ßE•éŠ@ÔÑø?ÂÄ—¡¥/‡ZÚGO”å)´»QFY·¬ª¥€X6ùLNÍT }öR ugŸÆÉ­•÷Ÿ†Ø0yèH•I‹ñiSÔ¶¿œ²v’*?Íé¬Ë¾J*’¤&å(þ=èxƒ#•¸ A9^SÝ3ýåüõ’1¢c·ïÜs˜U®é|’)ڽꡘ‹[¢¥êþöÝb§á„x8v9döÈñCI»4Sצ¥¶+­´—bk©Ð—¤vðßw¯Ä]~ÒfçÓã›aí#Ð+Ñf¢•¿Yú–‘tjW m³l8àÔ <2æ#ˆ©„G¿|WÈ…ÍlØrôìVÝ¥ïOK<Ûˆ4¡ b“Ä£±öË•›.†GsûAö/S%aB³Ôp¶ºSã—”"ì[.ÿ^˜õš»`.ý[Ûüá½o•<àï߆ ë]f¦Ï_P ²²ÍÀùÚ(ø`ÓM’À =´fÝ#Nc]}I¥VGä[‡| OLü@’0eUñ°ú«rÌ¢2IÂ(™–¢nǽ²uI5M´Ù‡&‚êC™a§‰©•œ†i¾½ŸŸ@">6þ#¸kØ&I)í?:~:z¹¤4°aQãƒv›¤„”‰|“Œ2î•3yMÏ:1¨ûÏjŒ8ôü/.õÍr±Á‡4ìªI·¶}aË×É66¿˜tn  îuñQéhà¹EUPÞV¦3g·aëµÐ?㱓96°\\f£ñä´4ÛÞC @iîaéx£Ð†\ŽaD» ec/˜Á4KMÍA°þiëýÿ¼éœE9§l.8‡séíuÏŠ H2KŒ¬ )[zo=”¼Ø»N²õèjê"áËfÂõS?‘$964šEÝÓa¥…¤1 %€M˜ÇK‚V8f‡_gOÿ³:°rû$éëѬùóx] áØï>qt'~¿o•Éw컫”úrÑ$—'÷{'3×Dï¤fxáæ"¾ÃAå"’Šô7ï:Ë\7íf#¬ùj>ŽÚh`Á;4G4ñ·æëyÐÞÎ&:©³z÷Þ3–«µÜÃý½ƒÀx_Â#W²OÆçí {ÓžwhnàÀ/CàÔ™ wårêÿ÷¹``l.û•NSVØÃ/·¨t—?“ÆãxKí‚U—y|ú1Øyl2ìÊgì“o¯†Ëû’4!È”±Æ"iЍ{÷Uö fˆ¯í·gü XîY3f‘„G í‹;Õï^hÈ’•BCz4½˜o_¹&¼³ªMa¢ó®o ƒÆÁô1[EÇõ¥lýh/!ôóñËðh"SîA ð÷éÿñ9ÅL`©$RJD<9y9³4ßî™ Í-{7ù˜è£vöUæŒ4Ñ[=Gý:ªéùऱÿæÓœy»uÿÃÄ®¾Yÿ:Ü}þ öÂwæðæ_TA“l†y¸Ÿ%D>-Û.±ijøøgÜ[zÎõxbL/3ÌÀÎFTˆËhó¼uȰòà ø©X¨­K¢Q/`çÁÑ0yÄöKŽþ{5¿bïè‹Ï^!¿ÞlTÓÜÅÍ6ÌÑSýàliª­“àÿ%åÂÃ>ÞSÀ©ˆÅË ß‰— ðd,®‰ßh†Ù¤“FA³-àž p²Ó|›Rquõ½Åf˜ŽDàmãgh‡çg½3—ÿ›i«ïÖÝWXN úû!ÓqÓM èëOëþ¬æ…Y¯ƒ¿‘¶Q«Ç90õûÆA¾$„¹o`ÿåä=VpÍ›öÿB~E¨³cöëØS \þbRšrnú¹˜(ÃVãæ =‡pg#7ðJÀ¡$.s zC~ÛδÅ*`Äx¡´\!³×½o¼ -m§¦J]ó_-Ã+»ÿd†?§Á„{gôú›%|;nm¾ù¥¥Pׄ,äÄÏ%k’á§×îG ÈÞ_SÿÓÂBøäx5T4ˆßüµe×0fðn0¢Vgn:# ‰À–ÝS;K-ð‰v–=~-n¥¦e.Ù²šÈ>ê¼ñ[‹—ƒ]ó{­O XÕlØyœrÞø­9.(¼’º‹ñ¬ñ½ñf¶ÜVl•MÌoEu,ÎŒÂìê°Åbâë9¬šzï ÐßÙƒs:#æX^R„(ú3tóø* ej3óŠ‹ôì—X<{‚c¸H_ÿÿýð×l|œ*‚Þ)q6.Þû÷ö¡_ÀK;o„ÊFº“AœYóõ‚Ü7ß]6K\,ý‡V àÄà÷7ÙN&.í…ÇÑAtã'•ÔΦƒTê3u6‡Üˆ—Wq¡pçT7zoÈ> ‡ò…ëL¸L¡CW°Ý7r<÷ý­,M'ešxç,Kd½ÆÁ~¡z V5|¦Ú^ˆ‡}ô¢àƒz-…5ÒêJì×_ZnÊÄ&½´§ƒÁл.Ms C¦j¢š€ †¡»èÅ0š³zäJ _ÿZ¼’ÚTàD$œk΋JÄÒ ØYw.­'Lù]oØW%êëoI€Ò*ÃõJ¥MnðŠžâ6—¨àzX2ìSx‡ æVü¨¼€½ ne(­€(j'€ÅÊÐ%ÈÕCk 3YB×µ1 n—tes õ“"G5Ï~Z ‹¯oƒKD^vF³úÿ»ž:T" ±¨E«´ é-ˆHŒûFn„7öÎ…¦V‡»ü\I:=q›üä*/ù©v€LMó^L]¶Å«tW‡yå-°b+;)m8pHøÜ£ªñ‹ ­†«²hBŸÉ0 )™rÒ@$Õb7m‚X I»ï$×› Å&©šðÏ~´ZZÅoh²|ý¿`øú«¦ä]¹ñ²-]…¹ÜŒÝ(a‰i=”š `6 ¸óGUã®?ìïêÐä•T2õôôõ·V딞 !LÜ\JG\:M6ÄšŽ¯ÿªyà –Ê¹q,ÓKá>+¿0<Ÿæ>œA¸¹ØúãÔ X¨й:sË×ÿ+œ°Üy!D8»0)¡‘vŽ " mí^0à;Xº÷z±.¥w‹mú¼Q%`- kf ØÚ!ÕÞŠ©÷êçñï+’ãðÑGÐý}Ç~n\­½€;gvìoOr=¤ÝðÃ!8TxÂMª.¼£&b¹G¸à=¯ma%€©(õ Þ“\=9«uÀôõ§µ_0Bçô°îïª>&åA¿Ë’Š«`Žü&uL2;òó)7Uö°ˆ¡E›iƒj/Ä©Áuü&êöÚ˜ÀT<ä>ÁÆA»ÿvé8)ŠØ]N’Q­³OX ÇΉV^€ã9 .T¶j ç!ÁÔÚM¤Jº_jÇÚ¿ 7®Ôîëlév[w½½ý­U9±oõ_±¿¢ß1±h!¼ê»féî g&ö­gV%-.'u„¶öœI£÷¯¿µÜc2kÎ}0Nšêe¢»ÙD›‰ýêEÇÑzg½_ùúSýE·ÁОL7fÁß¾–j  ¾HÎz¾òõ·¾'ûѲªhCÝEÇÒYÕêLB;;6ªBô @Jt ôJhÖYÕ+Ž}/À—¾þV„$?ÓÇÆš¯~UCæ8´_„›&‹vpºÉ§Æÿ¶øØ÷|íëOX\Öi@QûÒ_6j"‹Ö×ÒÊÑõ‘™$áäŸèÜÔÁÚ ðů?ÕFLXÄ…‹?#Q}žTµ º6ÒÙE.[]f²»ÿåëq+®È—O¤>—…GOk/ *,Xüyw‰[ôä¹ %¯?]ÉNǃE:þ]‘#úZqN"0VwIR/ <$Ð]0ñþžÒ`+¹Iôìæ`‹¢ ÿUÕ`éþS)³ðºo_7Ô ðe“Éö¤-ý爗ÂCëé4Õ&ÔK¹Í×0ô àlÿ»´½‚«ˆêZñ:ߣCÛ 6\äØ×jÙÊ˪ª±)äa$B¨­Ï€·&i –t;ÛZhjB'q&—ÿTpo…8¡E„N‹X`Ðî1j(Xz<[/åÓ,nEõJÀ™T&ˆ iw–œ÷Üñ4³Ÿ‹ÞL m\9'H¾‡fÄÃS+ ±™i»k—<ü‘ò›f†GÖºø9tHÆñ¸‚úLxFÃ,½YßSs°ÃbûŠ£ª€…¤¿<²WvÔìÛ wžlþô{ß¹¿Orútø5ª²ÿ÷†í6®ìÿÞ6 CÌ=Ñ“RÔÿ4“šïN „³½,ï\§Œ5þà­!€CØšØ8œ±â  RÇÿ™?B¥ß D_ÿ?Ì”§'¡6¨X߃¦&ñÃNµ•]Š<ª"–!@8Ñ»IމÀ^Ó©NÐX¾þñœtó@z ƒÄ“Ë;§а ª"–î+ók­¥öüýŒºýú[ë’åcÀòÎYóÓﺀ¡;æ+ µpÛ”LÈÐé×ßÚYÞNVôTðky[‰,p.[¥“.k/ÀòõŸ§MØ,ïË;'½&Õ“‚ªzAâOuÕ7©ªŠÖ,k/à¶iÃ!#‰¶\èÛ°¼ A¾}LU­'˜¡2êLª*‚â-Ll/Àòõ¿qªrr‘®ÅÆm«Bw3¸)Ë»ÀòιCSÞªÚÀÂÆ,•®©²ÖÚ º/ÀòõOŽÅZn—’L%+ÚíTsÇψ”¾j!F¶vn–ÿ1`éuŠ‘KíaÅ#¦`‰ØÀOA‰Ô™´Ð^€â_ÁÃÒý'ñy@E•ÈFªâ0ùѬÙPvªSº¸9ž™› ¿_u¦“»ýÃs’!Ão+ÆG/uËíeRꙵ'Èv†@©rx:]Íjõ>`ÂÆ_Û™è%yl<^rÊ¢:GæêAOM;‹qÑú€a%_ï¨êóÉRg*¤o‘Õbû +n5Ãê»Ì0¶Þ߉º@‚Š‘éï-6ÃÆ{̨/_‹%c“ù4ã{àësªêD„u\í%â(¯õ‡ó ~@z.š„ùñö·Æêo®€H`.ï/b†6< Cai¿¿/š“Ål{ú#Âèd¦ïU½.‰±4XorŠíTaðÙˆ*:Y»0â³Qu úÚûjã§ŠÉa úà„Ù­`¨º–åNU=€Ä¸R¦æ”Áˆ Vd Nù…ȼ‰'ˆ4àÓGÀT!^ˆ”S"žàY?8^(žbYªŠb"ÏC€+´´Š‹…ýCTî„£¯ÀóøCåMõÌQLï=yÓôrj,ï'ì5z¹Þ:eo4´C|Lœ+Kéäîî…ýÝ¥Éýµƒ­•T‹•#ë ±”¤ Œõ÷“üš<Àü“ùÖ.©¹ø<›XY,:ãÛjìpô¹Ç#…lõÿÕ3ïûpÕËŸù`6ö  úå-(Ù‹5Ó €øy€‚²@(¬ €´XÒî̯!°ãxk‘³FÔKP3|†ŠîË”Ân¶ua– ãq¼„ÀªÃÓXs^ÕÑPY㻌§5P- 4I³Ú%ÚNòŸ¹¬gò¥ü+>ízn!|ªîi)ÛØ~éLeT"Rs›?¼ºkkÒ?`c¤½%7jî ¨ž¼“8–¢qÛ8±5÷.޳¢ƒÕ¥ùµWR,Üw•g¯Î²Å.=1æRþùŸãÁ!úHÙ˜„^£mÔñ/­ûÓ™F³œ1ž,ÑÔJªØ ÿ‚Íÿ‚ÿ¥Ùâ—w±ìÉœè!›ýà_Ù‹Xs#u_°F–+‘¦¥ªá€ê{àoÄ_Ú>7°ãYðÏÒ=óáW3ûAß®”o¨?(XFÐ=/n΂3Õ¸™Íü Ÿ_çBª­'  @ÐÚqðºÒ9´Ž}ZñÖØß}Ô 6>–t‘†GŒQ°z 92!¿¯nÉ`JÊhh«}ì¶—vKêo»q OŸ1%(C$5‘€jÞTÔ x/bk[I nm{ÜðÌOÖÖ6DˆV’Ÿ}" Ö퉂£«;¥ÉÔmë~üÿR€–vYÌÌñ["º%}e÷a|~ÅÎÍ£j!Õ¢O“|·8«¿6˜3ù øè‹œqéþç5É0ã²:ˆ²½BÌe î©>ÞÛŽ†1‰B·MO¾ƒ)®'"©ØhÕè8ÈcäÀ!/a1e5þð× ÌcH–,y‰ÐO®¦ËÐÙÌ„aÙÜÀÙC±ˆ0+©ƒl_EÌXSà‡½€écØOr¾·->;À¬BÊC¯φ ®ÿCïucºðƒâ4ÔßÓ¿ª72À8G–ÄRPMpÜå» ["ûüÍCËSõ*i€y6ÞÚŸÿ$zºçbfWNø Xn›¾˜€‡ÿ‘Hq(îí,"{e'üæ °öäsí°pæ:x郅僚•KÞê›~—þø™áFu8“O¯eú YÊ’’P “F¸û¿Œïàvß‹+×Ù¹yôQâœÀpa½B(èZ´Á,SœžÝ `Ìà=°ëçQLIìÏ ¿®O‚¿Þ@ª±Gëø!}ðÖ’›öSH@úS]33vuÓ°Kµ) –¬˜Š³þìk¶ôð3¶¹CÁ^…4}E½n$S{²ÿ {¡\3å3Iò_tÓ ²S`p¬» S÷(•ÔFÀ5+ÿ »Î tXh3nLiÜÜÌB%ðz¸v•¾?8È‹¯Y©Ûq¿§*KW@ uÛ ßIƯ¦) æ}ô,l8:IrZ<€Æf#üæÝ4 ¯¿ÆÔ GOõ—#)ŸNCw@µ90f=t eÚÕéehn €»7>¿ûê78VÕÍh©S=ñpü\Ìx./l‰’5»¾X»·ƒË*ˆ†Ó%°[<4n$“¥j–˜³Þzh~€q|„“}ÓŸÍ€cEòo¶¢ÝƒœÄÕ‡}hÝ~ÖPŒŒÿ/d—>ç›{Ø—[ôóáâT¸â¯íðÒ­E0w¤Õb¤W?Hf}þͨضf§h¹½¡¡ÉhQåõÙÊ®¨XI€ÊI;C¹‡€n €`ð76Á˜Ä¥°½øQ¨oM‡ŒƒÐõøRßýv|s8žYPñ­B¡Ü#+§iÀÞŒF ûT2<¶!NâÞ ONì(ër` G ±Æ&¾Á~lªÄlÓ²þOkØ£ÿœ ¤a¨ µssºŠí7›ƒk—ÎñXã·bo%>'`EDØ¯î €`õ¯„‰I/Bx@©0T„¢3ÿ³2fÿ£,C¿AÚÌFxgÿÕ0ú­·€nïñ–á$ yŸ ‚%I`’@L`x”\Ä8Óq†›È ¨JÚ®6Ù¨Ò‹ôö}ŸÌXþ<þõ¯–Nå4á8ï!Òp˜®çì¡° ’^…}ewA©I¾5dj4X¹#>ÏÈô8T("ÆCQ“%õPiÆCf¦\§‚Py7I‚ûòŸrŽÕƒVqÇ®²ìéØW~7•”•(Ÿt OAáoh‚Q ÿŸ*oÂú®ÑéK—W¼Ÿ+wv‡ù¿ƒGÆ®†>qg„¥ÚÏzÝ),¬Ò¡ª¿ kg¨«¿éø8øwö¯àHi/;_y†V÷¤„^¸Z¶ws[G©ø´D84î}2ÖÀ©Ú©Žp‘äF …ÆÂk_³²öÀ¢Ë6ÃŒÞû Ð]o$$F.®‹…uG¦ÀŠƒ³ §2MbjΣqéömˆÆs†AÈÇäío*²æéK¿Þ"GûA—#ðó=>u3Æl€è Óp°b´šå_²¢®è—'G[lLp-Ìð=Ü0h+ O=Ž>ØV±ih †ÏQ=ÙwùC%ÙRÌhœ›¿ 'l+ºW€^D ÀöÐ%__pð  øt®¹“A5Í]Ü:Pè¶ GžÁnæPÓÜM¡\ªLðîþ9›SólƒÉ=À0$ƒ@?'û “ÆqÂå ѰãôeðÍ©‘ð)võëñzuO˜Œˆoa@ôFKÏÌY~ €³¬|ÊÝ+ 6„ÃýKaRÒ¿àpÕ\ȯ›¨¸x¹U©ðü‹,61I;³Š`∜n LžéÐRfö‰Q°#¿l/¸~)ë©xÙm3 .ÿи 9äg[g§ÿ[Iàhë8uNÜIM>1èVN¸ -–£ÄñÁ98AˆC‚ö`LjÉìjj ´t±©› ›‚ڡojd&¡Mn¾øÛ;ÜX)‘SÖ rrcpƒN EûQNI ä–a×'½`h9vxü»–=b²'¸nô{ðÕá;àHÎ1QqÐuáì@Á¹´1Ïò!¢§šml8 9ÒuÆdÊ ÛáçíòL²Ñ¶áƒ•7B¹©/“,JD2`MŇž‡ðÀ´h²ü“ áÈUt‘FnU®7¡®® êÛ¡»ðtцÜëóRÊG°™‘›¡Oä—.»ü®òÈì——Ú'¸ì­µK²rNgƸ ëĺXKPÅÖ»Nü}ÆYM0 QïÍŠ|ÎÖ¡§µ=È¿k<œmGªæ©ÍÉ"]#qÐéLRØæû ¤™û—eçÒ…˜Ô)Zƒö†ä.’¦CK±h+;l#’ƒgÆa ‚ËE5 µPwŒË {Ý>–šŽ}| «¾ òj'cÒhïÍŸ @ç0ŬƒTËÚ¾,íÊB”µD $èˆý‘ÅÃèF=ÒŠñW·†¿ÑnªÖßh—w=LNþ”ç&4÷¶EÀíÐ;r+LMù6þŸÐK–Æo›`¥;Û¢ý´“‡ðûÆO1iëáóh ‘`ž@«Ûv¢Û‚Q-Êi"ÏÂxâÏ*»JÙK~œdÞ qA9—Ííáp¶~8œ©%‹.BYÄ“1Ú0•r‡B{,ÄGÝ~µNÂk„€p¬…$½"¶YlmK29‰v4¶9šl”¤*ÁÑ×>gói ¯Ú ìEY/“Y^Ýô8ÈüfØ&G7õþúEo‚J"”áÎÂrS¨jê©úaB ±Þr,7>ø$½e×oýßA´¦/7P‘tAœ<ðvÒ¤¡eˆ€_QˆúÌrô¸²)ÃBDç›I…¸w÷dÑ~‡xÆ`ƒO:Eª?²,°ê† ÇLó$À €¥Ú%Æ!­D‰ÁG-–’ji…j<Š\ךu-‰[ã:ä%?C³E9j¸É…_Ô»GÿGZ¼úÆó¡¦èJJÓ$À @†7LjƆ Ým¸¤ Çòæšý-÷)Ðäbk{ö‚þð  }É/þâ½þ:^Ü!~UØàKð—fëåß‘'ãÓþ~¥fI€€Ò¯†„ôi}6ÓxrCqÕµÌC‚i’88y;~.<¿œ·¶mÄ3»³ %J¼&sÕ°íD©iØçë~Î÷{­Ûwî%ì½™3Ý›_§Êê:ÅOŠ †+úze#˜×Iå4Gœ¼ Ôø<ÍÖsÜ|´fôOMmífhlis ²N”§=,RLK[ײ4µv&)é'õ4NX±¨?Ψ‚[ÝëEe/œ}~Ù£&³ÙˆZ77.ÂPdÝšÔ„b7d7üp`¬Û°2Ð ¨†üqho‘±D'%µñ[3ä$`EB¿×NÙ' 2¡¬2Á“i‚œ= • ò’«ñ[‹b%Ûsã]‚›àŽë߇ÿVO b%¯L~)¬šzBäU$Œ«Æàƒ»EéäsfL8ަ4ìGÎV2'£{Å9ËÎ7¶Àñâš.þ#ÒcÁÏè\8š˜ä 5á’ÀrxgÃíÐÖFÇü=f¬$ ÊD>Oîÿ•S :4ÐíÛBa¾ÇY|G$W^ïvR0"ؤD9ͧ°ªÁ!ôKŽt9Ëï4AôÐû(Ü5÷=x{Ým8)èIP- x…pÂo¾öÃÅŽ’_㟠«¦A_~¡ŸȈ¿°lfO´œ66C—Êdâ¦vG"»ç/óûïúÛÍíí~žì©’ì¡§êo-fô‰eQ﬈¼b¿U"I}/nÞ¥Æ?1Ÿ=ùšY…á¿N X2ï=ƒŸŸÇ—]­$ š9o€ÓÊQƒÇ𱂺ýŽdµ’@VboüŽR‰›u8àë$À ÀÁ i”ˆ ‘À„Ìþåw€­šœ8 t‡«©~¸,Ű’€ÑˆÛ=kT1ø­ó,b<7Ž€ Ü<磣˜v³é»HÓë$À ÀEíp/ßA`ø€´D‡†|Š8øÎ;ÎKêT!öñ)ààæ¥àÞ¾…€¯‘'ßz¿yi àK$À @À Áƒø¾Bœ|ïÝæ%ˆ€/'/æ›è8øæ{ÍK-=“'/ê»è•8øî;ÍK./“Àj¼õXöãûœD¾<¸o#àE˜„È?-7úœäF”§§{¼HÄ^ÀP9æ 'š<-ŸAÀK$@ªeî”dNr¢ÉÓò)¼D7a/ H. 9È…¤M:­x´¼µør£¼@±ˆªlÃÙgõPåeµM™ÁTjü›ž³¨ñž…chfÊHÁH¥µ&è“ÄV~R…^Yߤ t²$©¼b—R‘ݳàG"ü*Ó)ÂõhÝ«œ²Ó€ÎõÇ;âØÃ[àHMîrq¾c1=ëz õïâ…šÃQç¾cmüÅ5&K´/œ-’ÀÉÒZô7Â(¼$TŒ¡Æÿ ÞXV§zxqñƒGí @LQ»„õ0 ˆ«˜.Ò^rð  øõ—D¸ðª ïâfF‰çÐ@?¨5u½1æç³ç-Ù %ûÆO‘鵓•¿º±ëÅGŠ.ÜŒ,”¬¿ÈÉMH”ÞI@¶ñ¥ÏÏÌaAŽyHàÇ÷·;jüÖ—ÝzkõYm¿3±üáNÊO$°¯úvgÜ5þd¼.}\†Gïås'²bþšØ-W¿ùr¥®t"‚,€|Ýõú&Ç=ê\(÷omo‡f'×_w‹±hV+Ôø¯” _.‚:å'È-«sYþ6,¿³ë¿©ñÏè— þ½ƒÃ»h+Ü(ÃÒåÉUBŸ'Ò 4bWžÅP㟆/¿«»ûXÒ•;Ž;`-¿R¿¥ÙL  DÅâ Šª ¬Å´eÓ`¬š;kp€¶:ö„®ƒ@9Z‡ž>Öö /ÁNµ¦pÖœHG@¹?ÍÌ;êŽÏ*ÛוzÎzb˯TãïãþeÙ¹oˆ•Éáqu€®Á“ku€æÉ2‘d#0Õ€Ôʹc\Æu˜ÆÇRÓ‘ƒänüRË$&¾$ pã§âh†HXIàilüÏPšrŸŸ´Ò:p61hÞþYËŸÊb8›´/¯ý³¿}–ª¦á Iû¤¨ÿãÿMîÂò9ˆZIàteƒ_çN4OØ7)Rõc~ç%¸àc%‚ q+³Tþ>‰‘² IÜÉ©%"ì Ð0w5Ú"e_‰áoÃ4Ø&£\dÆ À 8DS£œøêß™HÀ—˯D cÞ$@ÛxßB+dÓMvþ í*ŒÛu³zH5œ¤"ÈãsD € ™6–,@"è…¿·¢½mÚH´d ÐîB»ír ¯è¶J=€û+ˆ(7º@ \ë¥À†M_÷g:,Màÿ!è^ãɲé‰~Bàh}G¢ÜèõV>lø´½W¶-¾BñÑÍ*® ×a¡× -8§Y²Qò\ÍJ¯2ÁuC¸Þ¿´U’}"@Ë2w Ù˶NŸ0 /•®_ŒR,úp´_ ‡€‡Ô416ëø„FäÕ„˜º/ã®@*W&½0h»i¢&¸Î ùaã—}ÜY¦Ü#Ààp8Ž€~øÿæ—;åxìq IEND®B`‚ic089H‰PNG  IHDR\r¨fziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ7IDATxí}œEÚþ;³9çȲKÉ9IVL$=TŒßÞwêw§w÷×;³xzŠˆøIň .QIËX–ÍËæÙ8ÿ÷v`vvBwu÷LwOÕïW;ÛßzªëéŠopÃàp8ŽG€#Ààp8ŽG€#Ààp8ŽG€#Ààp8Ž€^0è¥ ¶å¸c\ÆL|~íp´©¶~üÍ!P†ïGûî²ìÜÕš“^å늰áSy^AKŸý!@p3A«þŠæ½“­b¹Þ†)óƯ¼^Oø”à÷^—BG覀_"³R´q:ª^”®´ S<öjºzq±è©Ð Ï¿Ø7@{áPä¡Ú[ë‰ú©b.•𺖠T=€žÊ"Sõê6?Ý–ÌÃãÆÃ€óì8jB€€šjƒËÂð0œ< 8ÏŽ# &T³ ¸âÕþݘ1Œà$9ÞzÍÉým³ãóhB ïè–uq ’Aô!‹PaÊ‚ævzO¼g"Š!.è$$Ÿ€¸à“j'„û—eç¾á=´œçŒ ?}ŸFû[´DdÌh× }‰ ŒÔbÔÔP &ŠÈÑÐ e¦~>KÖ/»×¶$#)%C~ÝDLÎ Qg!>èÄ[!‡Mrd£ë4:¾úßc!GÚ”>´7 ‚a†! œµó÷Ú#'¡§¯zQÃp8S?ªšz)˜“ÜI º9ÍbOÕN?C3¤„„îa{,„@C n"ð$ºÚ7~Û€‰øð’ÀÕHÔ+ðºá s´›ý Ô4ý((iô¬uÓf„B$1²Á~Õ¶íˆ (ÒzÑd“5}åàU†¾¹Â*„€L×·&@ní8[?Çóa2¥ª¾dLmQS3Íb£ ¡GØNè¾ËÒKPŸ´•ˆuŒÀ‡c8NÁRu°š–T8Y=»úÃpäLß14L8Ô¼ŽW_ ½#·B¯ðí¸iò:—4µó£Ë§n.}=èÉ{Œ`ŸoN‡Øð‹3¦ ŸhÍíápôüµØ+˜ßA¯ˆmj_EÐøK @$€•M½±áÏÂq~‘1õ¼¥=ÄÒ !B¯ˆíÐ;b ùÕê¿à.!'•Gcß#Uóà,võ¹qM äׇ~Q›,dÀW\cæ-_Nn7ƒ'÷&ã—mŽe®›àÜÛÚÆ|¸j®ˆŒÁ1« &(߯—ÿ«8¸¨êîÿ\yÐD7ìÐdáö’Çpµ`' ˆþçT¹+–½€ŽÉ ÀAåѤ֑ªëñË5Ú¯wýÍÔáÁdÛ Üûû°wâuÍ!hCñž{LŒl…Ìä&´Í™ÔY¿Ýb[€ “ÉÇÍgíÍœ a@Ä(Kã'È+Å1ùéJÈÉ= '+Ò §²œBÛÐBÛÖ=khwäÁÊE¸Ij [ ÆÏ Àsë„'€8h Ÿ–±ŽŸƒëùžU“…}b¿z‹×§âÂå9²kÀm ØSÜà RW^¬|*ï‰òî°½î°ýxüp< Î7xn×"-Ÿ~Wœ#â—AL`þE¹ø?žE€âÝÔ*{li/2¤ ®R SÔÁ„¾õÝêÙZÇÜ Hs}ãOCߥ°dj ´µàHal?›÷7¹éŠoljġʎâ߀˜¸dø-Je×»q‚JROã„‹úç 7k÷!ÕÒñ}Ì juÞ‹òLpRçΜiëÅI//l‡Ÿ··8 çÔ½¢)»üw`—_¾s÷Ž2ó3šaÚ :¸qìy˜=¸‚„½ìŽÒRÂä³ô°·pÿеpöl¬ýe ¬:4 NTtW"KKšÔÛ:R5×r$zHÜ œ tߦ£ã‹02YVó0F|…5²žâ©†Ôqhoñ$¸´wŸÖö•ÜÂ;¨» n欆øˆVOOR^Ý"Ëàá1kà¡1ká`q&¬>6ÖUõÊ ŠñàÔ¶â'`LÂRˆ8'IvY8j"áRKi€_Î_cóKNÊI4– u?L±=ŵjh¨0$ù$ éµþts,ÿ>^û*Jkäu[c`GÉoat›¤Š³2Z­6ÁrË_‹‚³öN@êr¬X§qsŠfZÖIøí”m0&½àBòJëi÷\¯" —3£îšR fÇÀË_ÄCae€¬0ÒvâìÒ`dü»rXÖ´yb]ð) -ªûp¼Oçôå6Ó3öÁ&­€Ë“s.$­ã½.4qÇäJ¸eB¬Ùÿø$Šªä#‚vsì)»†Ä}ˆJHvË]U<=¼B8á7e°_k»ÆF.ÙÿmÁõçÝe÷BeS†¬i§áXùï3Þ„ÙY»-3ë²&®òÄüÌ–ùëFÔÀ ›`éæ8Ü$Ïx‡zj*n±¬ÐdFnA$d4}ßÁ?ØÁ»WH¯¤O¯"¼­Çv¡‚ŽJFw)²Un€±î½· B|ö ¼O<5¿Ä²ÂñûS û„| Q~9а ô§²Õ]GB¤EÚÖÄÙ>øÊÿÞ"áKÝþÝ¥÷ÉÚø'¤ÿ ÏÏ|²â =V-dÔ/µ 6>–ëöDÁ“«“¡¼Vž×ëdÍL‹~R:¼ÈSCòÊ$[j¤ooÙ]PÕÜS–4ýŒíð—ŸÃ¯Çmà 6"0M•êð÷Þ6fZñX0º&÷¯‡ûÞIƒmGåé 9?u ÔYtÊR™A=$¼Ð“`i’´IÀ´³¬n~+Ph¥›0ÌÞº%ZÛÿ©òfÜÝ7€Ûˆ´ÿí» aTï^èL–W$ày†ÕÀK¸RðOœ$l—a âfËI¾pÂUÖ’ü:”{Þ†‰üm?´ösU’ÒïˆüGü%+È Lùp9Úç šEH‰Â ÌZÉ`¸Î§ùH‹­f&îÜûöϧ°ñ»ß¥&G~zIƒvÒ^ˆqX%}¹’&÷–ßE•éŠ@ÔÑø?ÂÄ—¡¥/‡ZÚGO”å)´»QFY·¬ª¥€X6ùLNÍT }öR ugŸÆÉ­•÷Ÿ†Ø0yèH•I‹ñiSÔ¶¿œ²v’*?Íé¬Ë¾J*’¤&å(þ=èxƒ#•¸ A9^SÝ3ýåüõ’1¢c·ïÜs˜U®é|’)ڽꡘ‹[¢¥êþöÝb§á„x8v9döÈñCI»4Sצ¥¶+­´—bk©Ð—¤vðßw¯Ä]~ÒfçÓã›aí#Ð+Ñf¢•¿Yú–‘tjW m³l8àÔ <2æ#ˆ©„G¿|WÈ…ÍlØrôìVÝ¥ïOK<Ûˆ4¡ b“Ä£±öË•›.†GsûAö/S%aB³Ôp¶ºSã—”"ì[.ÿ^˜õš»`.ý[Ûüá½o•<àï߆ ë]f¦Ï_P ²²ÍÀùÚ(ø`ÓM’À =´fÝ#Nc]}I¥VGä[‡| OLü@’0eUñ°ú«rÌ¢2IÂ(™–¢nǽ²uI5M´Ù‡&‚êC™a§‰©•œ†i¾½ŸŸ@">6þ#¸kØ&I)í?:~:z¹¤4°aQãƒv›¤„”‰|“Œ2î•3yMÏ:1¨ûÏjŒ8ôü/.õÍr±Á‡4ìªI·¶}aË×É66¿˜tn  îuñQéhà¹EUPÞV¦3g·aëµÐ?㱓96°\\f£ñä´4ÛÞC @iîaéx£Ð†\ŽaD» ec/˜Á4KMÍA°þiëýÿ¼éœE9§l.8‡séíuÏŠ H2KŒ¬ )[zo=”¼Ø»N²õèjê"áËfÂõS?‘$964šEÝÓa¥…¤1 %€M˜ÇK‚V8f‡_gOÿ³:°rû$éëѬùóx] áØï>qt'~¿o•Éw컫”úrÑ$—'÷{'3×Dï¤fxáæ"¾ÃAå"’Šô7ï:Ë\7íf#¬ùj>ŽÚh`Á;4G4ñ·æëyÐÞÎ&:©³z÷Þ3–«µÜÃý½ƒÀx_Â#W²OÆçí {ÓžwhnàÀ/CàÔ™ wårêÿ÷¹``l.û•NSVØÃ/·¨t—?“ÆãxKí‚U—y|ú1Øyl2ìÊgì“o¯†Ëû’4!È”±Æ"iЍ{÷Uö fˆ¯í·gü XîY3f‘„G í‹;Õï^hÈ’•BCz4½˜o_¹&¼³ªMa¢ó®o ƒÆÁô1[EÇõ¥lýh/!ôóñËðh"SîA ð÷éÿñ9ÅL`©$RJD<9y9³4ßî™ Í-{7ù˜è£vöUæŒ4Ñ[=Gý:ªéùऱÿæÓœy»uÿÃÄ®¾Yÿ:Ü}þ öÂwæðæ_TA“l†y¸Ÿ%D>-Û.±ijøøgÜ[zÎõxbL/3ÌÀÎFTˆËhó¼uȰòà ø©X¨­K¢Q/`çÁÑ0yÄöKŽþ{5¿bïè‹Ï^!¿ÞlTÓÜÅÍ6ÌÑSýàliª­“àÿ%åÂÃ>ÞSÀ©ˆÅË ß‰— ðd,®‰ßh†Ù¤“FA³-àž p²Ó|›Rquõ½Åf˜ŽDàmãgh‡çg½3—ÿ›i«ïÖÝWXN úû!ÓqÓM èëOëþ¬æ…Y¯ƒ¿‘¶Q«Ç90õûÆA¾$„¹o`ÿåä=VpÍ›öÿB~E¨³cöëØS \þbRšrnú¹˜(ÃVãæ =‡pg#7ðJÀ¡$.s zC~ÛδÅ*`Äx¡´\!³×½o¼ -m§¦J]ó_-Ã+»ÿd†?§Á„{gôú›%|;nm¾ù¥¥Pׄ,äÄÏ%k’á§×îG ÈÞ_SÿÓÂBøäx5T4ˆßüµe×0fðn0¢Vgn:# ‰À–ÝS;K-ð‰v–=~-n¥¦e.Ù²šÈ>ê¼ñ[‹—ƒ]ó{­O XÕlØyœrÞø­9.(¼’º‹ñ¬ñ½ñf¶ÜVl•MÌoEu,ÎŒÂìê°Åbâë9¬šzï ÐßÙƒs:#æX^R„(ú3tóø* ej3óŠ‹ôì—X<{‚c¸H_ÿÿýð×l|œ*‚Þ)q6.Þû÷ö¡_ÀK;o„ÊFº“AœYóõ‚Ü7ß]6K\,ý‡V àÄà÷7ÙN&.í…ÇÑAtã'•ÔΦƒTê3u6‡Üˆ—Wq¡pçT7zoÈ> ‡ò…ëL¸L¡CW°Ý7r<÷ý­,M'ešxç,Kd½ÆÁ~¡z V5|¦Ú^ˆ‡}ô¢àƒz-…5ÒêJì×_ZnÊÄ&½´§ƒÁл.Ms C¦j¢š€ †¡»èÅ0š³zäJ _ÿZ¼’ÚTàD$œk΋JÄÒ ØYw.­'Lù]oØW%êëoI€Ò*ÃõJ¥MnðŠžâ6—¨àzX2ìSx‡ æVü¨¼€½ ne(­€(j'€ÅÊÐ%ÈÕCk 3YB×µ1 n—tes õ“"G5Ï~Z ‹¯oƒKD^vF³úÿ»ž:T" ±¨E«´ é-ˆHŒûFn„7öÎ…¦V‡»ü\I:=q›üä*/ù©v€LMó^L]¶Å«tW‡yå-°b+;)m8pHøÜ£ªñ‹ ­†«²hBŸÉ0 )™rÒ@$Õb7m‚X I»ï$×› Å&©šðÏ~´ZZÅoh²|ý¿`øú«¦ä]¹ñ²-]…¹ÜŒÝ(a‰i=”š `6 ¸óGUã®?ìïêÐä•T2õôôõ·V딞 !LÜ\JG\:M6ÄšŽ¯ÿªyà –Ê¹q,ÓKá>+¿0<Ÿæ>œA¸¹ØúãÔ X¨й:sË×ÿ+œ°Üy!D8»0)¡‘vŽ " mí^0à;Xº÷z±.¥w‹mú¼Q%`- kf ØÚ!ÕÞŠ©÷êçñï+’ãðÑGÐý}Ç~n\­½€;gvìoOr=¤ÝðÃ!8TxÂMª.¼£&b¹G¸à=¯ma%€©(õ Þ“\=9«uÀôõ§µ_0Bçô°îïª>&åA¿Ë’Š«`Žü&uL2;òó)7Uö°ˆ¡E›iƒj/Ä©Áuü&êöÚ˜ÀT<ä>ÁÆA»ÿvé8)ŠØ]N’Q­³OX ÇΉV^€ã9 .T¶j ç!ÁÔÚM¤Jº_jÇÚ¿ 7®Ôîëlév[w½½ý­U9±oõ_±¿¢ß1±h!¼ê»féî g&ö­gV%-.'u„¶öœI£÷¯¿µÜc2kÎ}0Nšêe¢»ÙD›‰ýêEÇÑzg½_ùúSýE·ÁОL7fÁß¾–j  ¾HÎz¾òõ·¾'ûѲªhCÝEÇÒYÕêLB;;6ªBô @Jt ôJhÖYÕ+Ž}/À—¾þV„$?ÓÇÆš¯~UCæ8´_„›&‹vpºÉ§Æÿ¶øØ÷|íëOX\Öi@QûÒ_6j"‹Ö×ÒÊÑõ‘™$áäŸèÜÔÁÚ ðů?ÕFLXÄ…‹?#Q}žTµ º6ÒÙE.[]f²»ÿåëq+®È—O¤>—…GOk/ *,Xüyw‰[ôä¹ %¯?]ÉNǃE:þ]‘#úZqN"0VwIR/ <$Ð]0ñþžÒ`+¹Iôìæ`‹¢ ÿUÕ`éþS)³ðºo_7Ô ðe“Éö¤-ý爗ÂCëé4Õ&ÔK¹Í×0ô àlÿ»´½‚«ˆêZñ:ߣCÛ 6\äØ×jÙÊ˪ª±)äa$B¨­Ï€·&i –t;ÛZhjB'q&—ÿTpo…8¡E„N‹X`Ðî1j(Xz<[/åÓ,nEõJÀ™T&ˆ iw–œ÷Üñ4³Ÿ‹ÞL m\9'H¾‡fÄÃS+ ±™i»k—<ü‘ò›f†GÖºø9tHÆñ¸‚úLxFÃ,½YßSs°ÃbûŠ£ª€…¤¿<²WvÔìÛ wžlþô{ß¹¿Orútø5ª²ÿ÷†í6®ìÿÞ6 CÌ=Ñ“RÔÿ4“šïN „³½,ï\§Œ5þà­!€CØšØ8œ±â  RÇÿ™?B¥ß D_ÿ?Ì”§'¡6¨X߃¦&ñÃNµ•]Š<ª"–!@8Ñ»IމÀ^Ó©NÐX¾þñœtó@z ƒÄ“Ë;§а ª"–î+ók­¥öüýŒºýú[ë’åcÀòÎYóÓﺀ¡;æ+ µpÛ”LÈÐé×ßÚYÞNVôTðky[‰,p.[¥“.k/ÀòõŸ§MØ,ïË;'½&Õ“‚ªzAâOuÕ7©ªŠÖ,k/à¶iÃ!#‰¶\èÛ°¼ A¾}LU­'˜¡2êLª*‚â-Ll/Àòõ¿qªrr‘®ÅÆm«Bw3¸)Ë»ÀòιCSÞªÚÀÂÆ,•®©²ÖÚ º/ÀòõOŽÅZn—’L%+ÚíTsÇψ”¾j!F¶vn–ÿ1`éuŠ‘KíaÅ#¦`‰ØÀOA‰Ô™´Ð^€â_ÁÃÒý'ñy@E•ÈFªâ0ùѬÙPvªSº¸9ž™› ¿_u¦“»ýÃs’!Ão+ÆG/uËíeRꙵ'Èv†@©rx:]Íjõ>`ÂÆ_Û™è%yl<^rÊ¢:GæêAOM;‹qÑú€a%_ï¨êóÉRg*¤o‘Õbû +n5Ãê»Ì0¶Þ߉º@‚Š‘éï-6ÃÆ{̨/_‹%c“ù4ã{àësªêD„u\í%â(¯õ‡ó ~@z.š„ùñö·Æêo®€H`.ï/b†6< Cai¿¿/š“Ål{ú#Âèd¦ïU½.‰±4XorŠíTaðÙˆ*:Y»0â³Qu úÚûjã§ŠÉa úà„Ù­`¨º–åNU=€Ä¸R¦æ”Áˆ Vd Nù…ȼ‰'ˆ4àÓGÀT!^ˆ”S"žàY?8^(žbYªŠb"ÏC€+´´Š‹…ýCTî„£¯ÀóøCåMõÌQLï=yÓôrj,ï'ì5z¹Þ:eo4´C|Lœ+Kéäîî…ýÝ¥Éýµƒ­•T‹•#ë ±”¤ Œõ÷“üš<Àü“ùÖ.©¹ø<›XY,:ãÛjìpô¹Ç#…lõÿÕ3ïûpÕËŸù`6ö  úå-(Ù‹5Ó €øy€‚²@(¬ €´XÒî̯!°ãxk‘³FÔKP3|†ŠîË”Ân¶ua– ãq¼„ÀªÃÓXs^ÕÑPY㻌§5P- 4I³Ú%ÚNòŸ¹¬gò¥ü+>ízn!|ªîi)ÛØ~éLeT"Rs›?¼ºkkÒ?`c¤½%7jî ¨ž¼“8–¢qÛ8±5÷.޳¢ƒÕ¥ùµWR,Üw•g¯Î²Å.=1æRþùŸãÁ!úHÙ˜„^£mÔñ/­ûÓ™F³œ1ž,ÑÔJªØ ÿ‚Íÿ‚ÿ¥Ùâ—w±ìÉœè!›ýà_Ù‹Xs#u_°F–+‘¦¥ªá€ê{àoÄ_Ú>7°ãYðÏÒ=óáW3ûAß®”o¨?(XFÐ=/n΂3Õ¸™Íü Ÿ_çBª­'  @ÐÚqðºÒ9´Ž}ZñÖØß}Ô 6>–t‘†GŒQ°z 92!¿¯nÉ`JÊhh«}ì¶—vKêo»q OŸ1%(C$5‘€jÞTÔ x/bk[I nm{ÜðÌOÖÖ6DˆV’Ÿ}" Ö퉂£«;¥ÉÔmë~üÿR€–vYÌÌñ["º%}e÷a|~ÅÎÍ£j!Õ¢O“|·8«¿6˜3ù øè‹œqéþç5É0ã²:ˆ²½BÌe î©>ÞÛŽ†1‰B·MO¾ƒ)®'"©ØhÕè8ÈcäÀ!/a1e5þð× ÌcH–,y‰ÐO®¦ËÐÙÌ„aÙÜÀÙC±ˆ0+©ƒl_EÌXSà‡½€écØOr¾·->;À¬BÊC¯φ ®ÿCïucºðƒâ4ÔßÓ¿ª72À8G–ÄRPMpÜå» ["ûüÍCËSõ*i€y6ÞÚŸÿ$zºçbfWNø Xn›¾˜€‡ÿ‘Hq(îí,"{e'üæ °öäsí°pæ:x郅僚•KÞê›~—þø™áFu8“O¯eú YÊ’’P “F¸û¿Œïàvß‹+×Ù¹yôQâœÀpa½B(èZ´Á,SœžÝ `Ìà=°ëçQLIìÏ ¿®O‚¿Þ@ª±Gëø!}ðÖ’›öSH@úS]33vuÓ°Kµ) –¬˜Š³þìk¶ôð3¶¹CÁ^…4}E½n$S{²ÿ {¡\3å3Iò_tÓ ²S`p¬» S÷(•ÔFÀ5+ÿ »Î tXh3nLiÜÜÌB%ðz¸v•¾?8È‹¯Y©Ûq¿§*KW@ uÛ ßIƯ¦) æ}ô,l8:IrZ<€Æf#üæÝ4 ¯¿ÆÔ GOõ—#)ŸNCw@µ90f=t eÚÕéehn €»7>¿ûê78VÕÍh©S=ñpü\Ìx./l‰’5»¾X»·ƒË*ˆ†Ó%°[<4n$“¥j–˜³Þzh~€q|„“}ÓŸÍ€cEòo¶¢ÝƒœÄÕ‡}hÝ~ÖPŒŒÿ/d—>ç›{Ø—[ôóáâT¸â¯íðÒ­E0w¤Õb¤W?Hf}þͨضf§h¹½¡¡ÉhQåõÙÊ®¨XI€ÊI;C¹‡€n €`ð76Á˜Ä¥°½øQ¨oM‡ŒƒÐõøRßýv|s8žYPñ­B¡Ü#+§iÀÞŒF ûT2<¶!NâÞ ONì(ër` G ±Æ&¾Á~lªÄlÓ²þOkØ£ÿœ ¤a¨ µssºŠí7›ƒk—ÎñXã·bo%>'`EDØ¯î €`õ¯„‰I/Bx@©0T„¢3ÿ³2fÿ£,C¿AÚÌFxgÿÕ0ú­·€nïñ–á$ yŸ ‚%I`’@L`x”\Ä8Óq†›È ¨JÚ®6Ù¨Ò‹ôö}ŸÌXþ<þõ¯–Nå4á8ï!Òp˜®çì¡° ’^…}ewA©I¾5dj4X¹#>ÏÈô8T("ÆCQ“%õPiÆCf¦\§‚Py7I‚ûòŸrŽÕƒVqÇ®²ìéØW~7•”•(Ÿt OAáoh‚Q ÿŸ*oÂú®ÑéK—W¼Ÿ+wv‡ù¿ƒGÆ®†>qg„¥ÚÏzÝ),¬Ò¡ª¿ kg¨«¿éø8øwö¯àHi/;_y†V÷¤„^¸Z¶ws[G©ø´D84î}2ÖÀ©Ú©Žp‘äF …ÆÂk_³²öÀ¢Ë6ÃŒÞû Ð]o$$F.®‹…uG¦ÀŠƒ³ §2MbjΣqéömˆÆs†AÈÇäío*²æéK¿Þ"GûA—#ðó=>u3Æl€è Óp°b´šå_²¢®è—'G[lLp-Ìð=Ü0h+ O=Ž>ØV±ih †ÏQ=ÙwùC%ÙRÌhœ›¿ 'l+ºW€^D ÀöÐ%__pð  øt®¹“A5Í]Ü:Pè¶ GžÁnæPÓÜM¡\ªLðîþ9›SólƒÉ=À0$ƒ@?'û “ÆqÂå ѰãôeðÍ©‘ð)võëñzuO˜Œˆoa@ôFKÏÌY~ €³¬|ÊÝ+ 6„ÃýKaRÒ¿àpÕ\ȯ›¨¸x¹U©ðü‹,61I;³Š`∜n LžéÐRfö‰Q°#¿l/¸~)ë©xÙm3 .ÿи 9äg[g§ÿ[Iàhë8uNÜIM>1èVN¸ -–£ÄñÁ98AˆC‚ö`LjÉìjj ´t±©› ›‚ڡojd&¡Mn¾øÛ;ÜX)‘SÖ rrcpƒN EûQNI ä–a×'½`h9vxü»–=b²'¸nô{ðÕá;àHÎ1QqÐuáì@Á¹´1Ïò!¢§šml8 9ÒuÆdÊ ÛáçíòL²Ñ¶áƒ•7B¹©/“,JD2`MŇž‡ðÀ´h²ü“ áÈUt‘FnU®7¡®® êÛ¡»ðtцÜëóRÊG°™‘›¡Oä—.»ü®òÈì——Ú'¸ì­µK²rNgƸ ëĺXKPÅÖ»Nü}ÆYM0 QïÍŠ|ÎÖ¡§µ=È¿k<œmGªæ©ÍÉ"]#qÐéLRØæû ¤™û—eçÒ…˜Ô)Zƒö†ä.’¦CK±h+;l#’ƒgÆa ‚ËE5 µPwŒË {Ý>–šŽ}| «¾ òj'cÒhïÍŸ @ç0ŬƒTËÚ¾,íÊB”µD $èˆý‘ÅÃèF=ÒŠñW·†¿ÑnªÖßh—w=LNþ”ç&4÷¶EÀíÐ;r+LMù6þŸÐK–Æo›`¥;Û¢ý´“‡ðûÆO1iëáóh ‘`ž@«Ûv¢Û‚Q-Êi"ÏÂxâÏ*»JÙK~œdÞ qA9—Ííáp¶~8œ©%‹.BYÄ“1Ú0•r‡B{,ÄGÝ~µNÂk„€p¬…$½"¶YlmK29‰v4¶9šl”¤*ÁÑ×>gói ¯Ú ìEY/“Y^Ýô8ÈüfØ&G7õþúEo‚J"”áÎÂrS¨jê©úaB ±Þr,7>ø$½e×oýßA´¦/7P‘tAœ<ðvÒ¤¡eˆ€_QˆúÌrô¸²)ÃBDç›I…¸w÷dÑ~‡xÆ`ƒO:Eª?²,°ê† ÇLó$À €¥Ú%Æ!­D‰ÁG-–’ji…j<Š\ךu-‰[ã:ä%?C³E9j¸É…_Ô»GÿGZ¼úÆó¡¦èJJÓ$À @†7LjƆ Ým¸¤ Çòæšý-÷)Ðäbk{ö‚þð  }É/þâ½þ:^Ü!~UØàKð—fëåß‘'ãÓþ~¥fI€€Ò¯†„ôi}6ÓxrCqÕµÌC‚i’88y;~.<¿œ·¶mÄ3»³ %J¼&sÕ°íD©iØçë~Î÷{­Ûwî%ì½™3Ý›_§Êê:ÅOŠ †+úze#˜×Iå4Gœ¼ Ôø<ÍÖsÜ|´fôOMmífhlis ²N”§=,RLK[ײ4µv&)é'õ4NX±¨?Ψ‚[ÝëEe/œ}~Ù£&³ÙˆZ77.ÂPdÝšÔ„b7d7üp`¬Û°2Ð ¨†üqho‘±D'%µñ[3ä$`EB¿×NÙ' 2¡¬2Á“i‚œ= • ò’«ñ[‹b%Ûsã]‚›àŽë߇ÿVO b%¯L~)¬šzBäU$Œ«Æàƒ»EéäsfL8ަ4ìGÎV2'£{Å9ËÎ7¶Àñâš.þ#ÒcÁÏè\8š˜ä 5á’ÀrxgÃíÐÖFÇü=f¬$ ÊD>Oîÿ•S :4ÐíÛBa¾ÇY|G$W^ïvR0"ؤD9ͧ°ªÁ!ôKŽt9Ëï4AôÐû(Ü5÷=x{Ým8)èIP- x…pÂo¾öÃÅŽ’_㟠«¦A_~¡ŸȈ¿°lfO´œ66C—Êdâ¦vG"»ç/óûïúÛÍíí~žì©’ì¡§êo-fô‰eQ﬈¼b¿U"I}/nÞ¥Æ?1Ÿ=ùšY…á¿N X2ï=ƒŸŸÇ—]­$ š9o€ÓÊQƒÇ𱂺ýŽdµ’@VboüŽR‰›u8àë$À ÀÁ i”ˆ ‘À„Ìþåw€­šœ8 t‡«©~¸,Ű’€ÑˆÛ=kT1ø­ó,b<7Ž€ Ü<磣˜v³é»HÓë$À ÀEíp/ßA`ø€´D‡†|Š8øÎ;ÎKêT!öñ)ààæ¥àÞ¾…€¯‘'ßz¿yi àK$À @À Áƒø¾Bœ|ïÝæ%ˆ€/'/æ›è8øæ{ÍK-=“'/ê»è•8øî;ÍK./“Àj¼õXöãûœD¾<¸o#àE˜„È?-7úœäF”§§{¼HÄ^ÀP9æ 'š<-ŸAÀK$@ªeî”dNr¢ÉÓò)¼D7a/ H. 9È…¤M:­x´¼µør£¼@±ˆªlÃÙgõPåeµM™ÁTjü›ž³¨ñž…chfÊHÁH¥µ&è“ÄV~R…^Yߤ t²$©¼b—R‘ݳàG"ü*Ó)ÂõhÝ«œ²Ó€ÎõÇ;âØÃ[àHMîrq¾c1=ëz õïâ…šÃQç¾cmüÅ5&K´/œ-’ÀÉÒZô7Â(¼$TŒ¡Æÿ ÞXV§zxqñƒGí @LQ»„õ0 ˆ«˜.Ò^rð  øõ—D¸ðª ïâfF‰çÐ@?¨5u½1æç³ç-Ù %ûÆO‘鵓•¿º±ëÅGŠ.ÜŒ,”¬¿ÈÉMH”ÞI@¶ñ¥ÏÏÌaAŽyHàÇ÷·;jüÖ—ÝzkõYm¿3±üáNÊO$°¯úvgÜ5þd¼.}\†Gïås'²bþšØ-W¿ùr¥®t"‚,€|Ýõú&Ç=ê\(÷omo‡f'×_w‹±hV+Ôø¯” _.‚:å'È-«sYþ6,¿³ë¿©ñÏè— þ½ƒÃ»h+Ü(ÃÒåÉUBŸ'Ò 4bWžÅP㟆/¿«»ûXÒ•;Ž;`-¿R¿¥ÙL  DÅâ Šª ¬Å´eÓ`¬š;kp€¶:ö„®ƒ@9Z‡ž>Öö /ÁNµ¦pÖœHG@¹?ÍÌ;êŽÏ*ÛוzÎzb˯TãïãþeÙ¹oˆ•Éáqu€®Á“ku€æÉ2‘d#0Õ€Ôʹc\Æu˜ÆÇRÓ‘ƒänüRË$&¾$ pã§âh†HXIàilüÏPšrŸŸ´Ò:p61hÞþYËŸÊb8›´/¯ý³¿}–ª¦á Iû¤¨ÿãÿMîÂò9ˆZIàteƒ_çN4OØ7)Rõc~ç%¸àc%‚ q+³Tþ>‰‘² IÜÉ©%"ì Ð0w5Ú"e_‰áoÃ4Ø&£\dÆ À 8DS£œøêß™HÀ—˯D cÞ$@ÛxßB+dÓMvþ í*ŒÛu³zH5œ¤"ÈãsD € ™6–,@"è…¿·¢½mÚH´d ÐîB»ír ¯è¶J=€û+ˆ(7º@ \ë¥À†M_÷g:,Màÿ!è^ãɲé‰~Bàh}G¢ÜèõV>lø´½W¶-¾BñÑÍ*® ×a¡× -8§Y²Qò\ÍJ¯2ÁuC¸Þ¿´U’}"@Ë2w Ù˶NŸ0 /•®_ŒR,úp´_ ‡€‡Ô416ëø„FäÕ„˜º/ã®@*W&½0h»i¢&¸Î ùaã—}ÜY¦Ü#Ààp8Ž€~øÿæ—;åxìq IEND®B`‚ic04”ARGB€pƒ•qƒüñƒÿóÿ$ÿêƒÿëÿ ‚ $Ùÿéó÷ìÿØ{€ÿñùÿ òöÿNÆ<'ÿýƒÿýÿYÈA€ª…ÿË«€þ†ÿ«€$‡ÿ!«­…ÿÊ“Tÿýƒÿ ýÿ'ÿðúÿôúÿ#‚ !Øÿòûû÷ÿؼÀ €ÿïƒÿ ñÿùÏ 'ÿêƒÿêÿP !ÀàÜØÖàÜÀ(E€„baƒž£gƒag£ž££fƒaf£Ÿ‚ £bXC0/=Pa¤€££W4´ñùÉE>•NŒµ´€ ¤•[O2-\f¯´€ $™h\A,[H¥.´€ +˜|\O)/Bd>¤.´*œoH>"C4\O®´¶)8¨w[s[\]–N)ª¶¶')V¢k@]Yž–W,‚ '"4† ¢ŠE#¯µ³€))""A´µ³')""")ƒµµ€ '#!#+³µic14qˉPNG  IHDRôxÔúziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ@IDATxì¼Õù÷Ÿ½½÷\zo¢ˆtA±`oØKüÇ_c4=¦51‰%‰ÆBŒŠ-±€ JQ¥÷Þnáö~ïîûœ……[¶ÌîΜ93ó;÷3Ÿ½;sÊs¾ÏìÌoN"Î\w໺nšØ/–­›ÉÛ•¼ à­o9¼!€˜C Ž‹Ý~t›ÇŸ/?÷ùv±”' ¼‹ˆøÆ/üôÞîã­—L†‰ àTU\ñ¿ñö[-N…€z[ƒ€â~â›*›øo×)n*Ì8Nàsþw‹€½Çwá?P‹€Zþè` ßüãyÇǼÚá¾€XÀ~6r4‹€CV06:@Œóªl©ÿ‘­ÅÍßR.ƒ± pŒ@wþïå£cwŽíÄ?   U<ÑɾhLá]?ê´_A¬Eàt6÷ûÖ2Ö:…€ºžÆEC]ßÀ2‡ÀhâÊ" ‹tåðÅ¢G¿(Œ$ˆ   .¾lÚÙêšËœJ@MÏOb³Äœ{˜jj v" ¦7û©i¬ˆ~Ó‚C2ã@Ç6šœûD“iA”# º@@)J¹ã˜1‰ÇþÃ? v €ß´¼h³:@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€ÍÄÙ¬>¨€(G 5Ó5|Î졞v†mçÿÛÚ}7úß«¯»s×F‚ü­EÀ¿ø‡ú=Þ=ÙÏ!#w äÌLj6¬h¥Ûe^Œ¬òðC ŸŸ}FîJ62sämMþý6žw_åÿö‚€€€õ ` €õ}ˆ€€€@Ø ÂF†   `}Ö÷!j  a€€€€€õ @X߇¨€€„M ldH  Ö'`}¢   6¬62$Ë88«Ò`u+¯¸^C»ò îŒ×Ñ@@@À’#Ø;.Þpc·äi £A@ô&€A€zE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€@œl„‰  ÑXÄÉ—hÈ¢NCD± ' €öÙ{ýv®Æxˆ V pßuwnÐ"¬PبÇ>ù—3³™Z¸Í™=ôEŽw–¸ˆ  V$€1Vôl( @D ÉA@@ÀŠ ¬è5Ø   Q€ˆ ’ƒ€€€ @XÑk°@@¢$%@$+pÌ4@+:6Û“€‡\ÔæN VOµº}¶y(ÆÕFq®FŠ‹i:þÓÈ)Üö„Z˜FÀ4ô(ØÚ<ñT×Z@µ-…ü™GÍî¾¹óÝÃ7ööŸínôâX¸!ÆÕ‚€E‹â Xˆçc)qå”wˆÒâK(>¦>Üb@ÀA älT5R.jhËâ›ü‘}íѾølhÍæL]‘f¬9›…F³ØÜišÓ$ÄÔ²8"|¢@| ‘ Zäh¨õlãÒ.‘Wb—’Dù Ð@Ǿ<Ãÿ-<öMò?5‡Ý7s‘“$ëøâÄM¶¦¥ˆŽÝàÅ ¿µÐ{ãÍóV B,n[ÿ¦‹î„Ô¸².â =þZ :Òï‹»y5ÒoõËÑ™9åÏj{ogó–u”‚è+½.*ß;³áè>|h `ü£‹#¥#›&ö{Ž÷ÜØq/¾éMÀ퉥ªæ^TÚ4ˆÊñ²¹=NÖÄÊLØGyI›)/q3å&nõv7èÍÝ¡ù­{îóí#Z÷¨«Í7~¡ÀïáíÞzÈPÜüßçí',¶ˆƒÝí8ùj×þuÅPusïÍ^Üô7ö÷öÕ;¡îÚêèbATìݶÑ4ïÀìÄ]”Ïb@ˆ‚ìÄËc@@&¾ùãòD«l(•ÌqD7Ë9œæ×üù( VþD@ ì¶7ézoøeÞ§üÔƒô´‚©¢©¯wÛ\}h¥¢u@‚¬„]K  %bEH€oägpÒx ç^%„Àüàô7²ððÿ~„ÕOrìµ4ò`½C ÃŽÝô›ÚÒÕ2ÐÂֈÆÞªfrk@³·›@ˆ‚¤”‘°Ÿk‡k­…]¬”é|óνÁ[¤÷©ë9ívÞ~Ë‚‘‚õ“v€9Ä´ºƒõ£hOÝX*å¾|£òÍ©©Z¥Š‘%üÛz6M "왺‚ŠS¿¤¤Ø*µŒ…5–"À7qoz‹·Ì( ÿ çµ”[>Ž2[&‡°¥[í_)Ñ<-žFÅMÿ@ý‰dÅQúvóRMK7Z_ym¨¼»6±XIÝR¾ñ¶Ø­®¨áD_þ@Jù)çà&€(Ø¥.q“ÙSw íåM4÷#¨G@¬tXÚ8Ä»Ån¦î)_³ø‚r“¶xªg1,R‰?±‹Ùi÷êhÓtÎó$nøZÇ .Ú_?Ú»&¯¥Aòʃ;£ÈIAB€EÇ !PךÏ}Á3hOíXôïBغ™jÁ‹9ðN%B /I,뎆¬ëQX®*U=cS»Ä4¾ÍUgyŸôÄt1D ¬q0¯õ0Ø»üð@…Éb¹!@¼°Â%.1Ĉ€ð%nüNˆ(=9—Àa~ÁŠÒÛøM…{½]E¼¸ BÀ¹'j®ÝP"#*šúЦªsy¹Ø¡þch& ÞTøEÙÍÞ5D‹€˜B! "‚@]`‡šÝi´¾âBÚ]7^ì#PÓRD_•ß@;k§Ð 9¯RFðcê—¾˜g¾Gq1Q䆤 à<Îó¹a5®äezמEͽ +ƒ@{bm5§{—Šžýõà÷` `{Bø€ÌG4hq'ÓÆªóxŸSyhFökĆh:hä…¤V•ÝD»“&ÒÈì¹XUPG¶Èʾ ìë[ 5sñ[ùÆÐºÊ‹I¼°Ì&PÊÓü9 HÿˆfÎÇ«ˆÍvÊWš€ÒîQ×81ŸÿÛÃWPyÓu„eŽ$àöÄÒæê³hoý)4"û5*â•@º€èÊ{‚hõ$ò|þ³i[õ4nîÇú‚ Â!“ Ô·æÐÊÒ[Y¬a!ð:¥Ä6Ù"j€PËJ[#–gOý mÙJÛ©’q qJKtSZ’ØÚŽ~ú¾ógór¢´„zJŽo¢–¶xªmNön5â³)åÈw~gB­§˜jcŽm Í`Z|-^+]Ú8„e¾O2>æQ*n-ÉlOÀö.޾‚¢IuCå…ÞÑÖÑçf¯’âÝÔ¿°™5Ñþ >‹š©gn3¥óM_€ a× DmÕA£x&ñÌŠîwtˆ×ævQ]S ¨Œ£­ië¡„#Ÿ{ëhkIU4b\†X¿hJLMBàäÜ(1Vs_b|‚€M @ØÔ±zUK4£®*ûŽã§öç´¹¹ûnòG?»g·PŒIbc<”‘ÜæÝwk:îòòÿU-¡ò† ÚZ^L[‹­‡÷ÿ-ü}ge7juÇï ÿÊñ ÁŸzE@^Ò&ÕU® º2Áž£ĺý_—_Ë ú$;Љ¸¡ŸÔ§NRÇ[-é×@©ÜŒoµ›\M¹ÅëioíC‹;ŽÖ—ô¡OwžHKJ.¦e[3ÈIÝ bÆÊç%wðâAp·ÀèhràG€p”»µUV4ù¯¯¼ˆ¶×œ¦- bèÙHS¼7ü:?°ÎÛ|oƒjù­B|L+*ÚêÝîì5ˆš)›¾Þ™LK6¥Ò’©ôŶjn5©YïÅFìtñ;*ÎñÎbû<%¡KÀÈÈSqŠ;H¶yõ­yô%/¨"ÞÞgç úì<á×ÑÄAu”›Öfçê­›§0n@½w»gf)5¶Ä°`AÀb@l_±8ã ìÊÒbîÍãòÑ%`G£NA@ã´CêGÑêÃר¶É_Üè/_Egލ¡¢¬V§¹Ws}ÅÀFŸ8‰Ä̃¥kè%µ4oójæ™ v ¢K`w â…ƒÄ;Œ˜%œFýæÌ*úbÄèÃ…G?eb¬¸îÎ OË,e©O “øGšË»Nî´[ÆWqUíÏ[ÌŠyÍ}êªCŒ×Ñ"·'λšßŽš):æªFVb„þ¬ •tÙ¸Jê•Û¢†Q³BLa<{d 3›ªSéM“iîÚi´lÏ‹Õ$˜¹.^ßâ,*oìO'ç‰.ª`‘Ã>ëi|ïÄvÑ'ØÆY@DÏÑV9@tuç(Þõa×ÝòödäÅP]µœ&é:nò£üÅ‹|ì²SÛèâSª¼7þÑ<˜ÏeÏÖkSÜ•™TG×úлíª,¤×ÖM£WY ì¨ènŠ=z*V¶\t€g ä‰.zgü@@)J¹C®1¢ÉÿëÃ×ò”°$¹PZ|¬‡fœPã½éOQzþ½68-ËÞY‡èžI/Ó&½B«ö¦W×L£·6L¥ÊÆ4K£hv§q—À÷Žv Ìã.y­q–ã-GÀr.ÓÇ`ÑÜ¿¦â2ÎÌÚÇËé†)t?ñçð“?‚|â9¦ûFïöÀôÒüC·ÒK_O¦k¬¼Ñ‘.úÖ\:1çß¼ÖÎ-ùgJ4š€Ñ„•Ëßůî=×»ž¿r¦…a˜›ÿ#±>ô¡‰? pGMˆm¡óFl§ó&÷¢õû’èÑ÷òè¿_f’Ç¢Ñâm—Ím©4&ÿYŠsµ[lÉ`ŽÈdÀbâ2(+R†xyÏ7‡gYúæ?yp½u÷Nzÿ'ÛéÌ‘¸ù+rjù5cXFúçw÷Òòßm¡«'UR¯\hÅPÒ8”–º“D×؉ZìäÍ uqóZè«Êo ÑïoÅ0}Ø!º{Æ&Û÷èÝ­X ?6{ì?QÌÄxü†}tïy%4ûÃ<ú÷ÒlË-4TÑÜ›–ú!MÈ‚’ñVA?'2vY‘€½¦Íb)ß•¥·xW= 3©©ÑEßòùC>£N˜K# ·±å€©&¡ð(ôäi˜_}ÀÛuóÄüÎ¥~’CÕ Öx9Qc[¦·%`\þß)'ñ¨(5'Jˆ ` @ÄèÔOXךÏ«»-uóŸÞÿ ZvË­ôäyàæ¯þ)•…bùåŸ]XB«ÜBß;³œÄÛ ­D‹šx™ÐÁ;-„dò°QohЛ¨"ù‰…}Ä“¿U.õÈ(¥?Nÿ;3h9æ]+rÉ2C¼ÒX´\9±’î}©­Øš"«èˆËcj¾(ý.Êy™z¥-8‰ ûó*§«4–÷ùc?i¹²L³°?½¦—6ö^œZ=‰ÊW%.¦îû¦w1™”x»ŒìS»’ŠYÿ»w½º,‹~óz•תÝ- fÕˆwg4¹Ói`ÆGÌTùŒÑ¿@c¥Šþj /Vo!)qó÷®ÈÙ¦e 2–ody\œXå軼¡ÅXû8Ú§Ìî`²Â)þÈ<ãÓÃI"%î]çiòïž&)ÀQˆ_‰ñú/ôÌ-{(-I­Yeõ}éù·¯§6·ú+t¶ƒû ÿ?°Ýwüq}šE@nxÉäņÇ:ª’v×§õ¼ä¨JAôÁ¾tÇnúåŇ(Î"orS‰l1†ÀEcªé“_n£ÞùÍÆa®ë· ¥Wß¿œëâõŽ|ÓšÂ&Þ¦¸™V0/Ÿ|TUC!TõL;»*šúÒ7åbà­:!+¥Þ¼{Åk¶#€€jD—Àû?ÙA#zª5.`åÚ1´pÅTÕpù³G öCЇÀu,¨Ä,å€r.éhIüeùMJ-ñÛ-«…ÞýñSý@@U¼pÐ;<eÒà:¥L|wñ¹´sŸš3x¨ÆæDÑO1])hÖ7ƈ5¢¦5B#3àÿå×QC«:Óˆòüë÷ºƒ†to2²âÈt! Þ0÷û»¼Ëë’¡™¸=1ôü;×Q}£š3¾\7ZÌ÷ƒØô#0S¿¬ôË @?–ºç´ß0&Þð§J8¹oÍãfÕbÌïWÅ%°C18ð™[öÒ Í¨¬Î¢—æ]©äx€ÃU9XvRÃyf”â0ãK‰ŽyR0‡_HEsžòwaø J1}D-ýëÖ=]×`ßÍ…Ýjõ³„ÀÜlùúÑíÿ̵Aké ˆ*i-%žhÓþÓ$¸/£‡—\!¥ÌP…¬Û:Œ1…N;eq¨¨8†€0kt™6µr¿™:ýþ—¯¤ÇoØïqw ÞŒ%à±P—‹‡§ƒŠM± ÆÞÿxÒ ”ŸRF?þðv%ž¾ßY4“úôØI}ºïRŒÌqt(æe1EhÑÆ«¸ß?G ˾wf9=qÓ>ÿ7%,„ ›NšGÏ^ô %͆—ЀØnw ½øöµJèU´§Ì€ª:=Ë5*€PÌ+Ÿ~9™v–Tªû.9D¿»ü Ũ?mY ^0Â:.²”æ^ñ+J‰7¿ûêpu6ýgÞ,%Z$„GZ+Þ^tÈ:Þ´„¥óT´@!¯ì>ЋÞY¨ÆòÑ÷žWJß? 0Eg“{K/\òÅǘß°vëpâ_…ã/òPò†¥ŸlýwGÎð$†#ÖV@CS2/z­K…Þ0¥‚~|~‰6à ,Làô¾_ÑçýE‰ñ/ °XèCgüž_¬äKR ôqpT¹ˆ~ÿ—ß›E<ý&ª|ôH|ÞèjzøêäB³¿8‘‡\2l1=0]¼íÖÜ Þ ê“Í5„Kç–xõï¯L7Äú¬å*<¬j5 ðÌ’U“èÛÍæÏ÷+¦ýý潋uý8+`‚L·Žy›îš0Wf‘~Ëâa@‘÷ü•|ǯ¡Ø©…€èC½ŽÅ”Z/¥hg9@;fü[r8ŸÞ^x¾Ew(S¼K}Î÷öX4œHàS_¤kGÍ7½êk¶Œ •kÌå7߸ÚÆ%¼ýÍt(Ö3`3›<ž®VÙt½#Tþë .¡¶6s_Ú;¯™^»k‰eS@À©\üÜýç³þFg\a:1@…¥‚Š€ï3xÛb:õ ÓJžâm³Û¦º¹XÈD­ÞxmÞiîë¶óÒ[éu¾ù‹§D’úð¢/ʶpET%©‰w2? ¯˜D¢äþRјQ˜¸ >3k.]öb>-ßÝÏ ¼eÖ5¤Ò¼OÏ¡Ëg¼a𠾂ùF&š_ä7ڽğâäWó6ˆ·¼©ùB6LRlvó&ÄÑÞžb^¥üi‰`’›ššé¿›»ÔoZ’›æþ`õåW§FŠnŠ8)2]¿'j«VE|/E|«úvê`açñï»›éü?5ц},|L Ÿ=žÆ\I½ºí1É‚ŽÅm x‹÷ŠXˆ¡ÂâÃÝœß}:ç)nÒ'蜧Ȯ‘¹Xh™ÎŽ :òöíý¥3¨ªÖˆß޶*$Äy¸Ï7ÐËü…P´YŒX @VJ½öƒtÎCýhOy¼¼‚Û•$º_›)ýðúÇy1.w»#jü{´e JokXXqQr³½ºÛªwÝeç‡1²‰syûK»ñ¢§šPòñ"ÿxå:uˆZïI?nþó eµÒœ;v“Ëf…=‹éóÕãÍ*åÚœ€d{»ô$1­Ç¬páÉÕtã”ÃfrAÀò„x"Ú¬p°¬ˆ›ö]ö?÷Ÿû!ò%‘x/‚©¼à˜U–Í=ü‘XæA31!ï_³Šèì§n¢fÞãñͦhǾ>Ô·ÇNÍ6#"ø#àŠŽû>[=Á´—z\0d)}g¿È«Ú¼…LtDi¬âó­#j¿²W…,=!èþ3Zè'óo7ŪËΠ[.{Ö”²Q¨}  À@_¶´ÆÓ¢•S ,!pÖ¹ÉÕôÈÙãÅDqóL G@ rß=¦ö1çm¯ë· ¥½‡zDnŸ%Ç·›FÒÁ²B*Ê;¤¥ìm×ݹa€–ˆˆãNjÌn-Ô°]¥‡û¿\w2UTgé‘UXyÄò[ÃÄSIŒ Mÿa;¹¢žh5?#íä%*ˆÜÂèáºVó{Øvók"¾ÙGt HšN¡Nx•zejº kÊOk$1­ø£åÓ´FG<èBÀ1-¬~K»ÔÞÏŽ9³‡–øÙÖ.1ïI?Ì[Oy›†ìË^§G^Ïk»<ñ©‹–n#ZËï}7B_ÈãÁ^מBtÓxìîÛk¯Ïm|ŽŽH!«OÿÖ92ëèÜËe|ºìQžú Â÷Ñ´ð“Džâòñ•ƒu<"'hnJY­xú7×Ïá–nÂl©×­py ¾9°`øÜ¥þf±°\H=(©zf'®f›öH·K´Üuñ©¼ˆ“ŸnØœDî蚃›[Ýô‡¢_™—k–âs‰r¥öˆ_äކ—qZŸ¯)?µ’Jëô]r8ˆá§p÷e&¯ X$9Œ@? Ž>&Œ$QEѳ‘†öhŠ*S' ÊoJÑA ‹°È¾V€û¯÷3+}lP“µ|ვ´«Ì„›¿0.Ž™“µ˜‰8íÄÅ´ÑeÃÑS_\Ôn¯¡ÿŠÖÞSy{×ÐR¹¥ˆ“A;)U3 þÓîÕc5oüSÝóí›5Bú¢@R[/×GT! íf¦J…£´CÚHôû_:­uQúK™ä¾V½ zá£UÆ¿ñOo£‘Ÿ—ÀðÂ4¬»±o¨ì„ZÚõ«S¹øª(€ð#í4a`=dàÅ?á¹GíØz·àé_m‡²N, |áè’PÑô<>Š»1óôÌyY›€Fÿýáðè69aêÐNSÿÜÜÇÛ¸SÛfð{ïå°_)z·àéßúçÈ”Á²+1Uv(O]¨Ý7§i}ÌS‡tjlÜEtð_Ú2οŒH‡ÁeÚ C¬pFFxú–ÂQOìUM©‰nªk’ö,&Z1ßP L“H@ÚY'±NF%~8R‚Xö÷Ä>RÊB!r èÕ €§¹~3ª´øXM$õÕÑÒ®cF1C¾ú€ÐÎRÚg<÷ÿÇañíž±XÌhÇàéßbaî©üªo‰awgv—XŠR˜€çð¦G¬!ª.Q¦tnþ×%Wd¢ h[ðô¯Š'õ±£KwŸ>ÙËË£ã cÚœ-õ#ù‰@ÄÒ•@¤­xú×Õ Jd6¼¸‰²RÚdÚ"­5Sf¥PVø ´1+hI âB0œWD°7H[ðôo¿óB¬ù1In7€XÐ ä­jgqÖÃdÙ?™ßüã’UÊ1“@¸­xú7Ó[Æ–}ªÜ7~öãnMñŠ`‡@ €¶@Zÿ?šÿµ9ıÂmÀÓ¿¼î¿’€¸îó ;œN ÄÀJ9›£ä‡ˆ¦ÛaÑ€àZ[ðôoïsbPQåË]ùSÚC½=gíÚA„öŸ´Џˆ ‚shmÀÓ¿½Ï wûM–;@ÚuÍÞž³ví° ÿÍ™=ôÞ=FzïÓÃæ/;ÓO,ýw‰ €¸ 8‹€h¸ëâS)7=ÅoÅñôï‹ívŠî¿·¾o— ¤`V»´ø÷ÏY¼û.±¹=±3üGÑïŒþתr Õ €§ 8Q%Ïþ¢ƒÉÈÂâ B8°äpAˆúˆæý`Z,§@cðôo1GFaî€Âæ(R‡t0oB{cØØì• „?KKÿG’/!jŽÃ2 jÀÓ¿L/˜[V&¯"q `×VÞÅÍ\´(=€`Än·'†J+ä¼>[,Ò'_ê@šã:·àéß /˜[¦ä‡Œ0×ݦ—ŽA€A\p¸*›ÚÚbƒÄÐïP¯¼Jˆóè—¡UrjÚCäq˱¶­Ó+–唪¹_+Àý׋!(D–xúwóª•âUÕv1ñD Æ¿Cgw.Ûâ0¨ˆ…Xb@¾ÈÒ" ‚8ª¤\^ÿÿ€B‡Nÿ;ð,7µHzjƒú]ž¾éɉô‡W? rv*r¨i?Ñþ'1Æ@3ŠˆŠï6°€#YK„Ã=ªvAü#³ÿ`šÿƒ¸Â1‡|­½ ²iWI…cêŠ!€.œ 2 @¡-W8´ §­YiÉN­¾£ëG»_zå!‚ —9Pôý!€€ ZĆà<=y,P|¬‡ZÚ¤tWõ{èWÓŠ»hiGÚ}ÝJÛ}Ç¿6&Ĺ2[$7ý©5˜E Žgõ-h¦Íe˜×Ê£p;„þVØa¾Ø–€c/ï+Vôû—FOöS«k34F.ZFr奷F— RƒØ‚€x$¨²&‹ rðÀo‹'‚J8F0›$ÞzheÔÜœ 5jÔñð@¼ jŒÈlAàHw`º”º45KiiR>,€Y£ÄF§N ÀÞJ»-$¡­d«•νm•9%XæuNoNÈ/z65‹9!/­MNA(Ew§ö'bÓÜT¢KOÔ½úÈй¯h0ÀÊ €³dþ0Ò’$­„ ®Ø9XþýêõWpüÑJGko䎖˜Ræõ © '…D×*W”…0岓Ù4&ó/—¢Ž¥ÅçeLˆ.ÃÄo8ýÞèòèœ:>Ÿ®˜~ Ý?ÿSÚ¸_Í¥†ÅÓÿSˆ~üVgãuø.ü’;^‡ŒLÊ¢r!Q[I…û/Væõ@æuÎm±×LèËlHMD @7ßÇ//Ëä»X4!þ §ÖYÄeSlöTúÕµ™tÍÃ/Gcai }úËŒÞ/†Õ\CÆÕË•2¯2»:5xQ$@@à2•qZÆpƒev_qê 4¤X½·«úžþ-†’Ìë̸V=|"ó‡!³É/@u±;J±11ô««§G™‹þÉ }ú×ß\äÈd^d>èÀ¹ê€à™ƒcdþàT»u  Z+žþupª Y¤Hì”ù cJ‚@@2•1@'Xl·j­xú·Ø tÔÜ~ €¬qÖ蘄Å!ŽLe,sÐO€êb·NTiÀÓ¿N5)Y@æuÎ$”(6€pd*cY?öUÅn ˜Ý ›ç÷¯sµD² d¶tJć¢4€J¦2–9è'@u±[Gf·üèÜb¬ú§£?ÍÈJÖCÌ38¢Ìà ðij‘³D¦ì#ý Ø‹€Y­¹é)tÇônö‚éÀÚÈmm±$6g€àw[Î]96Fýuä Âî ÌjøÑ¥S)= ô ®±Ä¡X9—/ ·Gba– ï#!ø:1¡)À}w×6Æ’@_¨Šä&»Àûô^”ïKP„Óͨm”siމqS\V"uêù&ç,³ ]YÀÍ7ÿƸÁ‚§HH“e·xŸþ“åt]…¬<"DE ¶IÎ5!‰t\„'¨œeáÄrÎ2 ? YA–Ú—U”sœ€¬V<ýgn‡ÿd]d=èØÁ'v¬@¯ÊüaÈú±¨*vH@V+žþ t¢ Y˺&$&4šP;© ¼8€' €Áî° ˆV€ûÿómÜ[vZ- ,ýô_ù ¿Ž·>t5½¯>5t<›Ä%d¶tÚÄ5¶ª@w&%ÊSƲúûT» &àk¸æá— )ÉÒOÿÕ+‰Z‡æ’؃(Ó@ ƒƒe™:2êƒ2Â#€.€¼dþ0ê$ø PUì–@À¨±–~ú—ÀÝŠE4µÆ,#ȼÎɨÊ@^25’Ô~€ªb·¾V½‹²ôÓ¿Þ0l’Ÿ¬æ ]69i"¬@p‰ñÍŽè¿]ú3U1G½[ðô¯¢—£·I¦H8Û)z2ÈAo€¨Ìѱ2ðª‹Ý‘póX‘¦=šR‹^Ý?Ý0ŽÎà]MñCEúíU§PzL —ß)f[M§øj%2¯h°Ò™¡¿­˜ÊüaÈüÁ¨.vGJ i7ѾٚSÏ,"ºy‚‹ž]¦9‰ßˆg!ºmÄ".›7[y=ÙÕi+'Ù¤2èàH™? ™?øÕÅn‰¹ÄCC #/°0虫=x‰Tä•N)óz ó:§4t‡Àñ‰‰ÛUDÔawU½œ)?:˜Š,t ‘DôÙÝš>8üÌN*&Zy¯‡zf‡Ÿ)¬A ªAÞõ@fK§5è;ËJ€þ–ùÃØQšÀ ì¶+ì¢÷¾ç¡_žE$A¨Èu·ó4øOˆ›(VV?¾½DÞõ-V?[¢³cð“ùÃØr 1€Ømgq,¿wž‡î™NôÜr¢×¿vÑV^,ðÐÑ1|¹©DýóˆfŽðÐm“‰òÓìLuóØrPÞõ@æ`g_ýð©€¾ˆi£äÄjhJC¿Ý%ÕqTË¥'¹gšÜŸ¨×Ïo$†/,C@´üà4±Yý¥†{ŸZù ­¢•Áy¶Ji)uÎŒ#p E×òsJi÷^]°GüèOêÓ8gW#—#ârˆ²N³„Ãl'€ÊÎB €ÊÞ±ŸmèâÓø¸VÊɬC¿CM-.Ú{˜Gú#€8–€Ì®À‚\Ìpì‰v´â!Ω%Îÿ QmL ±%†öHzˆk¡ìôJÉ5Dqª@@ˆ€¶ KŸÃ¢ùoÚðZ}2C. –" –ëÈi)µ‡].Ïë~Ê»¤ý@±ë.' €*vâ*Ž<ÙOæL€ ûäöÕŸ jØ´_Þï¿¢:ûãëîÜp«5‡fpŒà“}1C£ôœÙC_äx׉¸2g,Û‚µ_µøq@ÀŽ>Û,õ÷¿ÉŽ Q§ð` @^²Ç¨Ä@À.Áa°%%¥¾íi£-!¢Ra€+#­†d¾péF~€€£쯈—ú†‹Gaþ+ àŸË±½b™ã–l‚8ÿ€€C,•ÿ»ßì´¨fAàøÉ€u|‚€sHÊ÷άv]Ô4Ç  @Ëþ¾=vѪõ£µD:ÎîòxÚõí³Ô;K±E:<ÍQ×-ª wí~0ª,¨Î€wŸ7îˆÎ®wŦ‡®WÓ^¢Cÿ/XŒÚú`GqÌ$bêß§¤¶ü}nRUQ¬b 48d`ï­béeɶÞÔ{ºè:õ´µŠ¥l£ÖYö´Dg—Ç­­Bž¶èÊ¥¸ ¨¿6ë+Ýe ²Wý$ˆ9v=Ô+·xÞ,nùxÕ®Œ¤^èÐ@MÌÈH•·>Æ’]£4X…( v ð©üþÿ…vàfĽî%!ÂLgëèÜ+Ø €Œi¨:¢€L`‰Ü™?¹:NËu‡hw>C´ƒìßA½äu”ÔeÓ–òâ`æà€€ ˆþÉànçR Ú¹cÚÁh÷ï\þ}»ï”—]Êï}¥{Ûï3òÑ 0(¯n5’1ò³ l>”J¥ÕR/ÃNìÿïìfŸ § zæuö‚ªßyÙàwÙ6± ¹Å#¨®à­÷±þ#ÀÍ£;˜``iÈ@À K7gË.àqˆæ€.?¿£ÍfÒ~< wœDõ-I­C4+˜÷M¾L³wòul‡Ì/Ë';0 ¼3Tš¨kN¦÷6OÏ:İ }Õù´Dn €´ë—eœÀ«p°­ŽÞ™º0¼èÑÅ~uí´è2@je ¼¾þ4ƒ%©×¯(ê%—ŠƒEÆ„q–róÙ>žG*ÖÐF²ˆ£.ÞylNEé•çaJÂØ0V5KìÆ Ô4Ê13FpÔy5¼~‡{bnGû[¹œ6VìXJào±Dq~VŒ­â4&ÚØbÇÓ|çÊøVçârÞä,¿zäìóµ8j` @ø—ÑŒ&E¸yåº7vÿˆî˜Q¾•VIÑíVy–¦ˆÉ«ô-/±7Q›;æYþQÕÒŽûd~ËšB”É[çú&ïYÑy/¾›@àÛƒýiSY/™%o02 Œ´,¶³‚´¦súxƒˆ¤†tèЩS!¤…W–eÉn&”V7N%ðêÚ3dW]êu+ÚÊ ÀyðU´y…™Þ×àˆaž}QøI"O±a_"­Û‹Ù‘DJP‹@‹;ŽÞXwšl£,%ˆãO€0óI)^Ó÷m˜É¢Šþ*· €؃À'ÛO¦ò§!7,’[œ>¥AèÃ1P.Èß/:S¥…×WfR+Þä&7 # ˜0øo1ßH-;"À¸³ 2¶s"KY*±Tè¢õaŒ¬¬¤0˜@ec½¿eœÁ¥tÉþÅ.{,¶"À‡ADÀ•OÆíœLê0otDà($ż³q25·ÅË´J̱}]fF• ?Yy×O /øIDAT€È™JmxouU7ˆª V%`Âèÿÿò³Úª¼:Û ЙHtß!"ç÷'mŠÌ#!@¬Gà/Ë®”mô!.pìBe” å8}²ql.B]‹%+¥„ øŸûé¦ñ«¥”gÙBRø)+‰WèCEˆUÿÞÝ4Q¶5/ñ²Uv¡²Ê"+FG :~rr±.@~tÙhOýøÂèÚA³)>ƶ¿kí0Ō˄ÄûM!ðز+Ì(×vÍÿ!Bt&Þwt„Ç«Cl>ùZxÇËvüeOU½.1ƒk…ìAÀ¾vVv£7øÍ’þ>}#¹LSŠ"€ ƲÁЇˆZ§$ÒU¶xšhóÀuü€¯  $¿.¿ŒÄ‹½$é×%ÉõëPD@š¿à.¢UÀˆâeë5àÀ¶Ã=HÌ'FP›À¾ê|zå[ñp*5¸¹´ÿH-Q ÂwƄϬC >é<<E¨í;0ø‹h¸hè~«¸Çà’ì“}¯‚,Õ·›®ê×-G×üŒÌ¬G^f×ú·”yÚBëâÅkâóºÄÐ-·Ë>ì8Nà‰•—xùä°€¯Kû%—©DqB`` vWH?3µ›f©˜/±µäMZ;ߺ’¾4ëX:kÞï®õLùíµ3HlN ¿¼ò [‡°ûD­•vùý’XHÔãN¿‡°Ó?Òº,zqõÙþ»×QÍÿQBt&ø;º³Ñ|„O¸½Yúë6ùìJ~þ—¦94ó@D¢§¾¸˜[d£¨åÿ+»PÕÊ"€mšÎ›è¢•Är­/q+Ä,™…FZ@¤äº¦{¦ë.c÷|u`}ºs”±… w° ˆ—þüë«™a§Ó!ÁË|ó«×!ËgÚ…¡i!^¸±Mkd½â=´äZ´èù€€Nžä¾ÿÚædrÓœü÷°æØˆÜÉÁùh>Ê'šX™Gê@@aÜÊ}CÉ„÷‹k悈 à4Û˲èo+.5£Ú¯ðuh««\&D@`ï```6‘y‘ýš·âHGšæ¾EwÒYSÇRVŠÐ 6 »yÍÅWmZ9TË.<<)ç'oOãWþšriåþ€Ù]ɘr–v5Ã{ø$kæ“L4Á=.³FåµñôÀ»ÃèO×Y¬Ü²ZmóFS¹ÜPšTï|•A 7÷”ZæÑÂÞâëÏ:3 ¶J™]=….€®L¢Ýó gÀ“«å†ç?͡ջ¤÷9Ê­$J… Ô6ÆÐ/_-2ËÂÌ*ØJå ÀöbvÀQ§¡@ç³—O°nx„³}H笃f'šïùw7úðg;(6‹……ƒ `‡ÿW@*yÁ$É¡ §dóÏ¿û0/p1”·€¡âº;7<𨃠%ำ!޳ðþ7göP±´ÙÉv‡õõ`ÙŸ6=üÜݵnwlZX £Œ,Zæ,ɦ§Ž2'$‡À†}‰ô÷ÍYòªsæb[Cõÿ‹JG pÀѢ݇˜X/^óq(Ê;D3&~L, &È#Î>hÂûß* óFWS^º%€ƒ —€h}»÷¥îÔæ–¿(×€žÛ¨oñN¹¶IiD`ÐÉ<å䥔˜ÐdPî³­ª¥ß¼Î˶"€H!ðêò,Z¾5EJY 9“4"' D§v였ÈÏ )S’êiòèσÆ1êà+Ëø‚´Åœ ’QuB¾  "JÜ¿6Ip÷ê¶›õÙ¢"KÙäd`à©zÚ˜O)>Μ¦ø{ÿÓZÚä7IˆYƒ€rà.·òszRE7#ÞªÏ)¡€¸DŸš„— @x¼ÂŠžZCF-+^‘Å ¤GßëúúV½òG> àtK7¥’˜~kF螀†÷_oFѶ-ÓdðÏ,.€Áħ[ÈÓòÚ .Åöz·€ÄE @@_¥ÕqtË?‹I 4#œ9Ÿþ]&nF…%•i¢3Ææ²º˜ €Á'VVz•icÄÅI\¤ÄÅ @@b´ÿmÏS‰I¿«âÂ}4jÈ·úT¹t!`¢8ù¿.¸À@¸¾¬Ï™ü!e¤Uû¾Jý)q±2cŠ’ÔŠ¢0Dà±÷óhñsZÖDŸÿå3Þ —xñ‚QL7U'ùBø£¢ó¾¤ÄFºhÚ;:çª=;q±-è|¾9•z§ ºL¢H=áÄÔ»ûî(r@R­L's7Àp­6FmÃÑÔ˜þ¤¡ßÐòoÆÑæ]5¦Ð7š¸hMXOÕé›1r‡(ãÑþßå.5·I]ï©Éu4sÊ{‘ÒîÏ«œ®Ò˜øy^6x¶Æ¸¶Ž&Dß§s%?âm´¤ÊžÈåHy±“cŸü1T-“ã§ádÑtwÙŒ7é¡gïáæøX#Šš§¸h‰‹×âû¶a•À ¤pºp{\tû³=èP•y—Ì N›G©Éõ]Ó¾Gë lö,íÓ –£—Ì;›¥T¯C!×ó·ì{$)È)¥iãÑ‚egH.ùHqââu_Äæþ`÷!†iBãN¢Ò×´%Êæ%ÓÄŠÊ Y¬!3Æk«¼Ü×Eh³ ±ºøëgçÒÂõR_íÑÁ†¾=vÒØ‘_t؇/òH9²j†1²H-çÌ QN†X}Òœ°ˆ/b½Ÿ~អ–Rm›»!üüí”BÜÔ㹟XËæ’ßd'Ô2ê²lÏúã‹eå· 1ÝO´bÚŸ_<ÒvJp@V¥ d‘>ZNB| ]ræ%—Ú±¸ß. eX*¸#|?Êë3é»oÿ„ûýÃm2ó“Y„»Ä{Ezì05’éI@’X¡§ÍÁò‚FÇ c#¬3u/1àæ¿÷¤Ýåòß]nRd ºhn‹§›ßþ)¬•Ö"Û¥bú°˜FŒ ƒE€ä±VVm!d‘îTŽh0ë=±>Àåõ1móN8ð”"Ðæ‰¡Ûþw-Ý%Öf1/ˆéÃb1‚Z OsÞÒ^ `Òy•›y˜fL3KÌ Û%Е³{Q]Nó¼€’U#àáWìülÁmôÎÆÉ¦š6¨÷Ó‡Ô$`€¨äš> ³¶¸òˤݩ¬ÓÇ.¢|ž`føzg2ÝðTOjn5¯ÓÌú£lèLàÏŸ]IÿújfçÝR¿‹÷‡xþñôau è,~Áù–Y[™´;•ÛJ—ùV§½ò¿Š™ÿïù¦-p"¿Æ(üxaõ9ôÐ’ký”¸WLÓ†Ô'ÐN¬ŒÂÚ_q>OF‘>¢¤aÓ/Ñà>›iü(iƒ>þæÊLúÕÜ"ÓÞnÐ0IÞÝ4‘îýðI¥.¦[þAÓ…¬Cਘ‡»‚b+§ù)§ÿ½µ…0ƒz§2/9ã¿$~ôf‡¿œKýï 0Û(_>Ïv¤[Þ1wºŸ¨µ˜&|ã…s¼Ÿò) ÄhðM¼‰·ïsbш/5äõÇÎiÒ×(NZ ЀzdzäGÿ"=òÂ]ÔÜ’ G–çñû· y©à6ºv²y‹El<‚@ÖêG×¾q5·™9oú+Ì=A-D|C ½ü÷èK}®æÿûð&–÷Íàmo¢Éw Çÿ›Ì?ãM­¾:…æ–Ðåg½A/½{•éFÝ=§»÷}gª1ÝFØU‘O—Ïý%Õ4iyMˆ‘–ã¥~O¡åÁÑX;»>ø/^èó }r3&tÃ5¢\O¾ŠÆÍ8’ˆŠí’È»PÐ?zÒ’©]ŽaØ…ÀþŠxºì?÷Ri]–éU*Ê;H—žù¦évÀg€PÌß—N‹²SÍÐÔâ¢Y÷¦ÿ}%Z­@À^6H¤sêK;š^1ôû›îÇ ˜ëÅÅàÌaÏS¬«ÙtËÄÚßá%ƒŸ_lÞR¨¦C€¶#°jG2Í|¸/í;¬ÆRØ—q¿Qúýmw¢Y B :I´œ3W Ë<¼É=/u£‡?ÂK’`± %œ#"&ðÑÚ4ºè‘>TQ§Æ[ÇrŸ¿Ø@À hu eöL]AeiOÝ8 ±òðûC¨ôàíôàŒ§¹uÂm|Ñ”PÁs¨«>&yi»ßF$^Œ`8×–gÑÏw§V·BVŒö«ý!€€Y Ì"¯¡\Ñ PÙÜ›jZŠ4Ä6>Ês_Ϥò†Lzúü?SBl‹ñFZB[-‘ج¹ —î{Mß‘€ç›ïo~WŸå‹ DL]£3>¡0&ï_üÄ­ÎÍV¼ 効¿SbÚ”ñ@ V' º°~óF¡R7ÁT,®Ââ_V÷/ìŽ@tü O€F*2ÀWYñŠÔóÿó•Ôeûvá”#ÐÒæâ&ÿô·ÕZÝR¼åoì _(Ç 9€|Þ‹ÇôI[¢”¥bõ´sæü™vVvSÊ.‚@Cs ]ÿdOze™ùsü;{dûÞ¾´qûàλñ¤€Ž<’=Ü ð:uOYIbÃÒìª,¢3Ÿ”æokXÈÂ%°õ`"ý`_Z°&=ܤRâ·ò’ÃϾy#mØ>DJy(€DF±ý.rÓèÜ(/i‹R–U4¦ÓÕ¯ÿšîûäfjqcL©RÎq 1¯¯È¤iô£u{“”®=D€ÒîqŒqruŒ«•Ææýƒ2ö*gõ“+/¡óÿýí©*PÎ6d¢Éÿ®»ÓmÏS}“5.kö?/U¯¡5~)ªS”h_\L#ÏŠRâÊ$–ª­¨/÷¡ÓŸ›M¬ë¥-b€¶p“ÿŒ?ö£/µÞ TˆNd1€ˆÑ™—01¶š&+¹‹W6Sïâ'^Y¾5…ž¹eõÊÕaƒ^·=Þ"Ý m,ÌÜ *Ÿ>–·M4ùÿôå"zé3ë=õûƒï7_ò< í·Ñ_ìÝ @èŽT^†b,Àؼ¿ÓòÒ;ÈíQcmóöµÿŠ_ºrúýýéo7î£sNŒ²µ"‘»zÞÓ>{uÿ/‡—"^ª®}·l¿Éïf~IÕÆýê ßhÐBDCi#!€.€H¨)”FÌ û<[ÄKž)ªêcéº'{ñÓZ7ªmÄ馠‹,c’›Oñ>ͦéÜäo·›¿Ï >€)‚>"ø4’®ÈFÒ•”·X@•·ªò3 shü}éíU$–gEp¬9Ø‹Îy°ýèßݽ‹ü„“Öjq!¬æ1ëÚ `]ßu°¼OÚRœù~‡}ª}9Xçmº½ü¯½iÛ¡Õ̃= ¨nJ¥Ÿ-¸ÎøÇ/hw)9%@8ÅÓæÖÀ\þº–.@ÿô…ºæiDf‹Ö§Ñ©¿@|»€[p ÁØêyzÈE¯¯;ÆýãôÏUçóçÍ(°úY¬¾ý¸úªï£0,ôÐðì·hhÖÿÂHcNT1Eð‘yù4é×ýiþ·j.Ùj”º©¬]ôŸ?Òmÿ»‡JëÔ[Ë_¦‡ dÒv^Y¶ó¹‡f̧sþÃÏPêw¶ï*K «ÿÖË;PpO9OõCp,ú–$úÝ¢›hê¿þFŸíéX+Й¾ëE@/’ŠåÓ+m’ÿOŠqé0_BÝÞ_Nî@ý °€à !šûçmž@þù4=¾ü2^×B½)­fã‚0Ûö,Àž~õÖª(ywÅÀøk,J#ÆÜÿf¡Wˆé^6>9¹jb6È'ÛFÒù/=D7¼ùKÚWo™ É|—ÒâIµ"@*nG`s7ç&n£I…Q/l• ºÄt¯“>žþ(×öÓ¾¬â½ìóùßãŸéèGW¼ücZ¾g¸^YžOŒ«NÎ{že~H ‡0œ8 0’V4’®"ygÄï§É…Ðò’;¨¶Õ"Ëé2»•ñô˹Eôè¼LºýÔ¯éæ ßPzR³ñTS%ö4¾+•ÐZETñQT·¹]ôö·ƒè/ŸœBåF•—‰c]Í4–»Õò“Ž,Õ+DµŸ—|Ÿj[ ¥™äk À²ÁÒÛ¶ Ûº¶cÅRâÓä¢GYÜF•ͽ;Tü[y]2ýþƒ‰ôøÂQt˘wx{›r’£\Z8Xcx¾9@GBmÜ‚T1¿ã>ßšÛâhîÚiôWîßßQÑ]c*µ¢%ÄÔÒø‚§)+aWà :àÀ‹@€Å¹â"6±pö±'˜hò2#­XæÏŸ]E'>ù<Ý÷ÉÍt¨6Ç 3P¦F­ ô Ïá?åïÏÐ]ïÿÀ²7ÿd!ž író÷að‰Œ ðÁ§U@XÅS:Ùçj¢qùOS”U:å(?1]ìÉ•—ÐIOý‹îýð{´¶¤¯|#Pb@Y˜=¶ì öÏsôS^ÅÏJƒû:WJtŸZøîë/é|¨Ãw‹ˆ€½l´–û{œ@]Nðr§:ŠL£ó^ ¤ÊJÚV}F§£ÖùÚÜOÏ}=Ó» /ØA³F|B—[D…i‡­S ›X*DÙ{<•ïUnê_¼ó$[¬Ü——´™NÉ{†´Î¢ñ‰EÇl»îÎ lrº¡:p’à‘]<á8t˜ÆQ^ÍÚ1Ä"AóþK¹‰Ûéëòk©ÅmíuÖ×q+€èøÍÂïÐi}¾¦Y#?¦s.£äø&k;JaëÅò¼Ÿí>oúgÐÿ6M¤ºfkŸCÇQ{ø½ðHÿø‚á>¾[Ê‹ 5@'pŒ`õ[ªÅ±sf ÞÖ§% Å)Jþ–¦=H«Ê¾C賸)}²c´wKKh  †,å–iBϵ¼(’ú+#ú«“jû6—÷ôê{×ê·ró¾?®‰±5trî ”—´ÉßaMû 4aB$8F(ÀZYÄ I<ÈiCå…´­æteí ×°Z~"ýÏ·gz·âŒRº|ø'tw ÌÝnVŽ_^ŸIon˜B¯®9ƒVhK¢É_ÜüuX3"À–§ˆí*`;—FV!1.`xö›”›´Õ])ìåUæ]6Ë»õÎ:D§öþÆ»Mîõ-Æ t†ÅßEsþ²½ÃiÉ®QÞmÍÁ~Üi¤¥ÍOfÊïMþï{÷ ·É?XÕ ‚ÑÁ1@¨à…l]§q—À—e7q—@…,ÓÏ”]•…´«rýû›ÞLåî9&&õ^CÙúe™œšxÊÞû†»áu`#ÖäOû'ç>ÏMþ[ ñ•O,/û>U7a± C #Óˆ @DŒÎ¾ żg±|ð†ª x–€iï ú´ÅöìWçñ3®‡Fô(§S‡¹hÊ^üe`=¥%…7Ì ´ZÚ\´zW2-Y~-Ù1ˆVìFbV…“B>÷óö6ù¸¨"`Z¿Ù´ŒW €N~‡è¤Ó×ê–ôíáYtØ­Pà«E$ÇVÒˆìש[Ê·l±9kA$$Sùä‹çø,+H}â•Û/­©K—ýB ˆŸðiÛy=»–ÀÉœøÑˆ3Ð!á·KZ•íuË2¦Í¢Ÿ|OÝ8Z_q! H 35¢ƒ€bJ_ÿŒO¼+ú‰w`˜Ö=÷ùöímÈ-ž×¿ÂÛöû%ü ²Š@ €‚^ºib¿çج4­ƒIb`àÆÊ hgíDÞS©|1•€èã?!g.¥Ç0ÕŽv…w☠"€mÓ?ð&„ˆxWxoüþg}%âs wTð'‚Íભ C­"|èÄz¢[ ª¹Ø· Ÿ ` Ñ¿?<ëM*No»4§¹?@Åý ×D  …TÄ[°ábºË—¼-àí#Þ>gAÐÌŸ' {°²ÅqÁ|²vÒ”¢?ÑÈì×4¿9Í_>Ø‘Sûú¦JÓºÝÏ7q¯Rêæ´Z|37a1øxcЈúŒå,…jvó¥ŠûÄXÞ~ÁÛBÞ¶°hù¿£-üÁª ¬ê9Åìý­G.À¿ç ðŠYsìL ;a—娉" ’S£'ú'oYÜÀ[(IH#€ÈN*B,­::÷EšXð8÷¿tRÕQWÉâcêiTÎ+4¹èÊLØ#¹tý‹³˜úñö!Yi{0©ì˜×X\c{Ù¤‚¼aGZ¡1®Vo“m¯´e´¯n m®žAµ-Ê®wd¤¶¶1ûøÅ¿\*úû„à›é4®·‹EŠ[¸¯þ$cépS?̃ ¤Æ•yŸô{ò Ïþ!:ÑñCêã ޳ÀŠSÁúðÊob«kÍg!p wŒ¥úV¬Bªšëâc¨GÊW|ã_A9‰;Ù<û¬Ö§kˆ¼`} ¬ïCGÖ@ œùoï{[ö°Ø_?šZÜÉŽä¡B¥E?¾Ì)šøÅ'Fòë•£"àz.e¥±%éš;Ö Ðgt™ADÇ©M'àá'ÌmÞmdö":|Bt‚È?Rñrù“;í–ñ5ž éÏ[ÌŠyÍ}ꪣkÚÕÓ`3oþ¾z@øHàÓŠbb]â=Õ¾uûÇéY‡äÄ&ºàôy4÷ÃËôÌVż tö @W £xׇ]wËÛ“‘CuÕjôcªpó÷‘‡ð‘À't$0î„/èãåÓ¨¼*§ãû}ƒÐѧ&ø% ÒÍßg O`L€>A€(6¦Î›úžSPøDÆDéq€(Ú5¹Š7kˆ |‚Àq' ]MSN^z|‡½ÿƒÐÁ¿:@´[*ßü}¬!|$ð Ç \8í4°÷Öã;ìýD@”þ…ˆ Ý’[áæïcà#O8B@tÜxá‹”›)o­“ÙCDá ŒžÝ’FsóOIˆå~Èèôd=/ÀÓæoöƒOè9E0‰W LO“2" M¼fAs›[Sâ´Ä8rE±ÈŽ‹Ì] GS%I*Ôäzº}Ö?höË·SUgÃê˜"x ‰¶ ´q²}¬hnþýóÓèÔ|#‹SIM#‰¥i[4Þ<}¥é-Nì™Mb‹4¬ØQNëˆÕYC‡™#»SJ~†¡I!F8ò²ËèΫž‚šãF÷Èæ@`v¬² 7Áµ =‰f +¢øØðOK!¾Úí˜fO;ž†¨“Î|" 3]›Õ¹x3²óµ`v€Fúá_i5fŒhÖ  ÊÍßG+RÐ-3™ÆõÉóeƒO&àé)5¡_ø`baø XvŒúÍÞʈª¥W³¿¿ÂÃâæ?}HÅÅFÙáÏì‹"à×>—–RÓbñªh5"@#)Çt>ò¿1“ \¦iˆãè(FÞü}`}" Ô˜Üü}Äð  p×µOÄc```FN<âÀνž·ÈGv9ñìðSg7_±¡Dnþ>RøÐ|Ý¡Y9%ºœâiê)óæï3×': ÄÍßGŸ  €O`` vfvŽ `gïêX·œÔ]¦úEbRg€›$‘Ž€À™à#à#Ï Äâ8ÑÎóZ@ˆƒ>Ð+'þB°ÂaE" !g‡p†ŸmQK!ÎRˆÑþ¶ð&*a6ˆ³=`~ùæû€€€) LÁ®L¡ʸ†€€€|ò™«R"€*ž€  `ˆ“À›\,€É@ñ   ŸHJh¨QÁ 6ˆûß‹¹Åóûî gŠ+"à–ËŸ}™mÝg{u°ÑÑ"@‡3Y€€€]ô+ÞYÁu97ˆ»85@= €Ánp*ò½3·rÝOã "ÀÆ'€‹ª€@¤ "%gtÖñ,© ¤â–^€tä(@¬C"À:¾ ×R€p‰!>€8ŒD€=`O¿¢V   +ˆ]q*‘€n€   >ˆõ}Ž…áÐB\p8ˆûœöñ%j R@HÁlx!†#F  `?Ö÷)€õ}ˆ€€€) LÁ®[¡º¡DF  à<Öõ9€u}ËA@@ J¸!l# ÂF†   @t&¢þwõ} A@À ,á¦cFBC@@¢%-Ayé!ä±FI  àW[ÉÁVòl‹p¨x>·xÞ$‹¸ˆ ¬â)Ø  #à@Ï.zƒE@±\`/ÁF°(Š€BvÕ[,’Uw€ê‚}  `qcØe¨î6Õ=û@@À(¾Ç­=Tv€ÊÞm  `#‰ìºŸ«ì>•½Û@@Àf&¾Ë­½Tu!€ªž]  `SbVÀ÷Tu#€ªž]  `cg©êFU=»@@Àæ"Nän€|]  ¢W`€8„€CDÀ*º@E¯À&¿*ë›é³m¥äöxüÇNkp€˜ª¢gâT4 6©G ¥ÍmªQâæÿþºÔØÒFM-n:mpŸ\¦Úä¤Â[ÙÿBv™E¼¥ÕÜóÏ&¾Þ«±UãéMˆn*?3]Ä›ÒóçÙ¾pƒ’]áºÑ¡ñKk›håÎrÛ'W:ö7Qø®Ãu´hS D€DOT6´ÐçÜú2±¾tPÓØBŸn)•X[[µíº;7 P½f6*²wRÀ`v€X£9Ôv•ŠŽRÁ¦uû«¼"@¦-oþ¾²}"Ý>"Æn>Tã2;`ÄÍÿýµ¨®¹Õø ¢%Ø´; ] ¸ŒpL «_Msf-éÄ_Û"@-nþ>s|"Ý>"Æ  ‚Œ–Üü÷§ª%ذ%@Ià¤UÏuËÙ%£% ÔÍßÍ'Ðà#bü§Œ–Üü÷£ê%ج%àˆrV :€b‘m΢Ⱥ¦ŒZoþ>V>á)ŒÌÿFŠ€hnþIñ±Ô+75|H¡$‰€ *†PÑ+mÓ;‡FöÈŠ¨D#D@¸7ŸáB¬ØQîûŠONøÿíOˆE‡[wóŸè®‚!QXHŒ š DEDЛ".žrÏ^ DÄžQ‚‚è!„z aŒÆÝÄ$JvC¢›lÔõ÷6³›&™éž®zÕóuáyÝ8|ìL¡‰UÙžBð·GO½Ð‚­‡³åƒ~ïÄ}79Uhb`G/pPŠÁ¿ÑÍö}}ts.S¥ M Õ!%Þ^ ô»lºK @÷3«U1Da å„ux H!ø›«o»iͼ$ìöEÓ=$üyò¥÷ìòüÍ~/=zžÐbA&¦ü "v]ÍÃÄ@‚¿ëS$ºq–Ȉ’ãѹlÀ²i¿[rÍ ÈEÃŽ¥b&ÿ¥žˆó=f@ðãóÔ´:J~»SàG‚—œØ# ø;q¾Ìˆ‘üýø?K–$“‘ìµàÿ°ìèèí³‘l\TË€E|é„Àœ€Ÿÿ¨þåV+²Gï\Ç 8&Ð1—ç\—Ÿ´‡eª-ˮϹc]6Ä Õ‚®Yë–hbàêÖ'’{vo!øŸ¨³”*€Røú³²% ‰@èï^oÑ „L(ðJ@IÀ¤’€‡dßÛ’gØùt<-½ÉcÂ-€g* @ ,c{þþ9É+’ÙŠ´ÿ­v_’<˜Zð7$F@µ#  <'Ù£ŽJÞ’\êa'¿T[›Ôþ^É¿=l7XS$ÁP£€bP€žì’n[eÕÖæÿ« gTo¯d«Ú{\òkÁv\Tc€ 7` TM °_ÐüKî—<Ö{ôyµxxJÛÇr@ŸûÕÆE}Ö¢\­ÃµèXâp»vtâ\1±ؽbŠ â6'àPCv+!°eñWJÖJn¬–Lê8»â¯m!ðéÚ_|š…U€@AüM¢šýœôØ…—Éé:=è`€/´Úp´u[ „ $켺šNàÓ³64UÕc+>{ŒU¨7/êÝ=z—"‡^ÓkCmÉš†I€@÷lÙÁî«QÕ ¨–o™ÖßPåÿÊ4@]@À=Jêí3®¸rÇcôã°~í¾²…o€@‚l=úw´“û€ €o'¿&óÜ¿SÚ7B¬ƒ@4?JóWÿÑø£¸ 6ûÙ‘À‘‰©¹»7$VIvD4Õ€@w>ÕáO*øOwW£!Ž€-~@I€ÀØö‘§dæ«’m ˜‹‰èWÇÔñ×%o*ø3‡§_Ï‚DúMˆ£ÌL%æ¯û$ÏHF%#’›%@ óRkëvØsþŸI>WàOòÅ0²@€ @€ @€ @€ @€ ÿMÔNüÐTÑ–IEND®B`‚ic09qˉPNG  IHDRôxÔúziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ@IDATxì¼Õù÷Ÿ½½÷\zo¢ˆtA±`oØKüÇ_c4=¦51‰%‰ÆBŒŠ-±€ JQ¥÷Þnáö~ïîûœ……[¶ÌîΜ93ó;÷3Ÿ½;sÊs¾ÏìÌoN"Î\w໺nšØ/–­›ÉÛ•¼ à­o9¼!€˜C Ž‹Ý~t›ÇŸ/?÷ùv±”' ¼‹ˆøÆ/üôÞîã­—L†‰ àTU\ñ¿ñö[-N…€z[ƒ€â~â›*›øo×)n*Ì8Nàsþw‹€½Çwá?P‹€Zþè` ßüãyÇǼÚá¾€XÀ~6r4‹€CV06:@Œóªl©ÿ‘­ÅÍßR.ƒ± pŒ@wþïå£cwŽíÄ?   U<ÑɾhLá]?ê´_A¬Eàt6÷ûÖ2Ö:…€ºžÆEC]ßÀ2‡ÀhâÊ" ‹tåðÅ¢G¿(Œ$ˆ   .¾lÚÙêšËœJ@MÏOb³Äœ{˜jj v" ¦7û©i¬ˆ~Ó‚C2ã@Ç6šœûD“iA”# º@@)J¹ã˜1‰ÇþÃ? v €ß´¼h³:@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€Í@ØÌ¡¨€€h! … €€ÍÄÙ¬>¨€(G 5Ó5|Î졞v†mçÿÛÚ}7úß«¯»s×F‚ü­EÀ¿ø‡ú=Þ=ÙÏ!#w äÌLj6¬h¥Ûe^Œ¬òðC ŸŸ}FîJ62sämMþý6žw_åÿö‚€€€õ ` €õ}ˆ€€€@Ø ÂF†   `}Ö÷!j  a€€€€€õ @X߇¨€€„M ldH  Ö'`}¢   6¬62$Ë88«Ò`u+¯¸^C»ò îŒ×Ñ@@@À’#Ø;.Þpc·äi £A@ô&€A€zE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€€œA@@@ozE~   `pL½ @èMù€€€@XÀI0@@ô& 7Qä   `'ÁDЛ€ÞD‘€€X€@œl„‰  ÑXÄÉ—hÈ¢NCD± ' €öÙ{ýv®Æxˆ V pßuwnÐ"¬PبÇ>ù—3³™Z¸Í™=ôEŽw–¸ˆ  V$€1Vôl( @D ÉA@@ÀŠ ¬è5Ø   Q€ˆ ’ƒ€€€ @XÑk°@@¢$%@$+pÌ4@+:6Û“€‡\ÔæN VOµº}¶y(ÆÕFq®FŠ‹i:þÓÈ)Üö„Z˜FÀ4ô(ØÚ<ñT×Z@µ-…ü™GÍî¾¹óÝÃ7ööŸínôâX¸!ÆÕ‚€E‹â Xˆçc)qå”wˆÒâK(>¦>Üb@ÀA älT5R.jhËâ›ü‘}íѾølhÍæL]‘f¬9›…F³ØÜišÓ$ÄÔ²8"|¢@| ‘ Zäh¨õlãÒ.‘Wb—’Dù Ð@Ǿ<Ãÿ-<öMò?5‡Ý7s‘“$ëøâÄM¶¦¥ˆŽÝàÅ ¿µÐ{ãÍóV B,n[ÿ¦‹î„Ô¸².â =þZ :Òï‹»y5ÒoõËÑ™9åÏj{ogó–u”‚è+½.*ß;³áè>|h `ü£‹#¥#›&ö{Ž÷ÜØq/¾éMÀ퉥ªæ^TÚ4ˆÊñ²¹=NÖÄÊLØGyI›)/q3å&nõv7èÍÝ¡ù­{îóí#Z÷¨«Í7~¡ÀïáíÞzÈPÜüßçí',¶ˆƒÝí8ùj×þuÅPusïÍ^Üô7ö÷öÕ;¡îÚêèbATìݶÑ4ïÀìÄ]”Ïb@ˆ‚ìÄËc@@&¾ùãòD«l(•ÌqD7Ë9œæ×üù( VþD@ ì¶7ézoøeÞ§üÔƒô´‚©¢©¯wÛ\}h¥¢u@‚¬„]K  %bEH€oägpÒx ç^%„Àüàô7²ððÿ~„ÕOrìµ4ò`½C ÃŽÝô›ÚÒÕ2ÐÂֈÆÞªfrk@³·›@ˆ‚¤”‘°Ÿk‡k­…]¬”é|óνÁ[¤÷©ë9ívÞ~Ë‚‘‚õ“v€9Ä´ºƒõ£hOÝX*å¾|£òÍ©©Z¥Š‘%üÛz6M "왺‚ŠS¿¤¤Ø*µŒ…5–"À7qoz‹·Ì( ÿ çµ”[>Ž2[&‡°¥[í_)Ñ<-žFÅMÿ@ý‰dÅQúvóRMK7Z_ym¨¼»6±XIÝR¾ñ¶Ø­®¨áD_þ@Jù)çà&€(Ø¥.q“ÙSw íåM4÷#¨G@¬tXÚ8Ä»Ån¦î)_³ø‚r“¶xªg1,R‰?±‹Ùi÷êhÓtÎó$nøZÇ .Ú_?Ú»&¯¥Aòʃ;£ÈIAB€EÇ !PךÏ}Á3hOíXôïBغ™jÁ‹9ðN%B /I,뎆¬ëQX®*U=cS»Ä4¾ÍUgyŸôÄt1D ¬q0¯õ0Ø»üð@…Éb¹!@¼°Â%.1Ĉ€ð%nüNˆ(=9—Àa~ÁŠÒÛøM…{½]E¼¸ BÀ¹'j®ÝP"#*šúЦªsy¹Ø¡þch& ÞTøEÙÍÞ5D‹€˜B! "‚@]`‡šÝi´¾âBÚ]7^ì#PÓRD_•ß@;k§Ð 9¯RFðcê—¾˜g¾Gq1Q䆤 à<Îó¹a5®äezמEͽ +ƒ@{bm5§{—Šžýõà÷` `{Bø€ÌG4hq'ÓÆªóxŸSyhFökĆh:hä…¤V•ÝD»“&ÒÈì¹XUPG¶Èʾ ìë[ 5sñ[ùÆÐºÊ‹I¼°Ì&PÊÓü9 HÿˆfÎÇ«ˆÍvÊWš€ÒîQ×81ŸÿÛÃWPyÓu„eŽ$àöÄÒæê³hoý)4"û5*â•@º€èÊ{‚hõ$ò|þ³i[õ4nîÇú‚ Â!“ Ô·æÐÊÒ[Y¬a!ð:¥Ä6Ù"j€PËJ[#–gOý mÙJÛ©’q qJKtSZ’ØÚŽ~ú¾ógór¢´„zJŽo¢–¶xªmNön5â³)åÈw~gB­§˜jcŽm Í`Z|-^+]Ú8„e¾O2>æQ*n-ÉlOÀö.޾‚¢IuCå…ÞÑÖÑçf¯’âÝÔ¿°™5Ñþ >‹š©gn3¥óM_€ a× DmÕA£x&ñÌŠîwtˆ×ævQ]S ¨Œ£­ië¡„#Ÿ{ëhkIU4b\†X¿hJLMBàäÜ(1Vs_b|‚€M @ØÔ±zUK4£®*ûŽã§öç´¹¹ûnòG?»g·PŒIbc<”‘ÜæÝwk:îòòÿU-¡ò† ÚZ^L[‹­‡÷ÿ-ü}ge7juÇï ÿÊñ ÁŸzE@^Ò&ÕU® º2Áž£ĺý_—_Ë ú$;Љ¸¡ŸÔ§NRÇ[-é×@©ÜŒoµ›\M¹ÅëioíC‹;ŽÖ—ô¡OwžHKJ.¦e[3ÈIÝ bÆÊç%wðâAp·ÀèhràG€p”»µUV4ù¯¯¼ˆ¶×œ¦- bèÙHS¼7ü:?°ÎÛ|oƒjù­B|L+*ÚêÝîì5ˆš)›¾Þ™LK6¥Ò’©ôŶjn5©YïÅFìtñ;*ÎñÎbû<%¡KÀÈÈSqŠ;H¶yõ­yô%/¨"ÞÞgç úì<á×ÑÄAu”›Öfçê­›§0n@½w»gf)5¶Ä°`AÀb@l_±8ã ìÊÒbîÍãòÑ%`G£NA@ã´CêGÑêÃר¶É_Üè/_Egލ¡¢¬V§¹Ws}ÅÀFŸ8‰Ä̃¥kè%µ4oójæ™ v ¢K`w â…ƒÄ;Œ˜%œFýæÌ*úbÄèÃ…G?eb¬¸îÎ OË,e©O “øGšË»Nî´[ÆWqUíÏ[ÌŠyÍ}êªCŒ×Ñ"·'λšßŽš):æªFVb„þ¬ •tÙ¸Jê•Û¢†Q³BLa<{d 3›ªSéM“iîÚi´lÏ‹Õ$˜¹.^ßâ,*oìO'ç‰.ª`‘Ã>ëi|ïÄvÑ'ØÆY@DÏÑV9@tuç(Þõa×ÝòödäÅP]µœ&é:nò£üÅ‹|ì²SÛèâSª¼7þÑ<˜ÏeÏÖkSÜ•™TG×úлíª,¤×ÖM£WY ì¨ènŠ=z*V¶\t€g ä‰.zgü@@)J¹C®1¢ÉÿëÃ×ò”°$¹PZ|¬‡fœPã½éOQzþ½68-ËÞY‡èžI/Ó&½B«ö¦W×L£·6L¥ÊÆ4K£hv§q—À÷Žv Ìã.y­q–ã-GÀr.ÓÇ`ÑÜ¿¦â2ÎÌÚÇËé†)t?ñçð“?‚|â9¦ûFïöÀôÒüC·ÒK_O¦k¬¼Ñ‘.úÖ\:1çß¼ÖÎ-ùgJ4š€Ñ„•Ëßůî=×»ž¿r¦…a˜›ÿ#±>ô¡‰? pGMˆm¡óFl§ó&÷¢õû’èÑ÷òè¿_f’Ç¢Ñâm—Ím©4&ÿYŠsµ[lÉ`ŽÈdÀbâ2(+R†xyÏ7‡gYúæ?yp½u÷Nzÿ'ÛéÌ‘¸ù+rjù5cXFúçw÷Òòßm¡«'UR¯\hÅPÒ8”–º“D×؉ZìäÍ uqóZè«Êo ÑïoÅ0}Ø!º{Æ&Û÷èÝ­X ?6{ì?QÌÄxü†}tïy%4ûÃ<ú÷ÒlË-4TÑÜ›–ú!MÈ‚’ñVA?'2vY‘€½¦Íb)ß•¥·xW= 3©©ÑEßòùC>£N˜K# ·±å€©&¡ð(ôäi˜_}ÀÛuóÄüÎ¥~’CÕ Öx9Qc[¦·%`\þß)'ñ¨(5'Jˆ ` @ÄèÔOXךÏ«»-uóŸÞÿ ZvË­ôäyàæ¯þ)•…bùåŸ]XB«ÜBß;³œÄÛ ­D‹šx™ÐÁ;-„dò°QohЛ¨"ù‰…}Ä“¿U.õÈ(¥?Nÿ;3h9æ]+rÉ2C¼ÒX´\9±’î}©­Øš"«èˆËcj¾(ý.Êy™z¥-8‰ ûó*§«4–÷ùc?i¹²L³°?½¦—6ö^œZ=‰ÊW%.¦îû¦w1™”x»ŒìS»’ŠYÿ»w½º,‹~óz•תÝ- fÕˆwg4¹Ói`ÆGÌTùŒÑ¿@c¥Šþj /Vo!)qó÷®ÈÙ¦e 2–ody\œXå軼¡ÅXû8Ú§Ìî`²Â)þÈ<ãÓÃI"%î]çiòïž&)ÀQˆ_‰ñú/ôÌ-{(-I­Yeõ}éù·¯§6·ú+t¶ƒû ÿ?°Ýwüq}šE@nxÉäņÇ:ª’v×§õ¼ä¨JAôÁ¾tÇnúåŇ(Î"orS‰l1†ÀEcªé“_n£ÞùÍÆa®ë· ¥Wß¿œëâõŽ|ÓšÂ&Þ¦¸™V0/Ÿ|TUC!TõL;»*šúÒ7åbà­:!+¥Þ¼{Åk¶#€€jD—Àû?ÙA#zª5.`åÚ1´pÅTÕpù³G öCЇÀu,¨Ä,å€r.éhIüeùMJ-ñÛ-«…ÞýñSý@@U¼pÐ;<eÒà:¥L|wñ¹´sŸš3x¨ÆæDÑO1])hÖ7ƈ5¢¦5B#3àÿå×QC«:Óˆòüë÷ºƒ†to2²âÈt! Þ0÷û»¼Ëë’¡™¸=1ôü;×Q}£š3¾\7ZÌ÷ƒØô#0S¿¬ôË @?–ºç´ß0&Þð§J8¹oÍãfÕbÌïWÅ%°C18ð™[öÒ Í¨¬Î¢—æ]©äx€ÃU9XvRÃyf”â0ãK‰ŽyR0‡_HEsžòwaø J1}D-ýëÖ=]×`ßÍ…Ýjõ³„ÀÜlùúÑíÿ̵Aké ˆ*i-%žhÓþÓ$¸/£‡—\!¥ÌP…¬Û:Œ1…N;eq¨¨8†€0kt™6µr¿™:ýþ—¯¤ÇoØïqw ÞŒ%à±P—‹‡§ƒŠM± ÆÞÿxÒ ”ŸRF?þðv%ž¾ßY4“úôØI}ºïRŒÌqt(æe1EhÑÆ«¸ß?G ˾wf9=qÓ>ÿ7%,„ ›NšGÏ^ô %͆—ЀØnw ½øöµJèU´§Ì€ª:=Ë5*€PÌ+Ÿ~9™v–Tªû.9D¿»ü Ũ?mY ^0Â:.²”æ^ñ+J‰7¿ûêpu6ýgÞ,%Z$„GZ+Þ^tÈ:Þ´„¥óT´@!¯ì>ЋÞY¨ÆòÑ÷žWJß? 0Eg“{K/\òÅǘß°vëpâ_…ã/òPò†¥ŸlýwGÎð$†#ÖV@CS2/z­K…Þ0¥‚~|~‰6à ,Làô¾_ÑçýE‰ñ/ °XèCgüž_¬äKR ôqpT¹ˆ~ÿ—ß›E<ý&ª|ôH|ÞèjzøêäB³¿8‘‡\2l1=0]¼íÖÜ Þ ê“Í5„Kç–xõï¯L7Äú¬å*<¬j5 ðÌ’U“èÛÍæÏ÷+¦ýý潋uý8+`‚L·Žy›îš0Wf‘~Ëâa@‘÷ü•|ǯ¡Ø©…€èC½ŽÅ”Z/¥hg9@;fü[r8ŸÞ^x¾Ew(S¼K}Î÷öX4œHàS_¤kGÍ7½êk¶Œ •kÌå7߸ÚÆ%¼ýÍt(Ö3`3›<ž®VÙt½#Tþë .¡¶6s_Ú;¯™^»k‰eS@À©\üÜýç³þFg\a:1@…¥‚Š€ï3xÛb:õ ÓJžâm³Û¦º¹XÈD­ÞxmÞiîë¶óÒ[éu¾ù‹§D’úð¢/ʶpET%©‰w2? ¯˜D¢äþRјQ˜¸ >3k.]öb>-ßÝÏ ¼eÖ5¤Ò¼OÏ¡Ëg¼a𠾂ùF&š_ä7ڽğâäWó6ˆ·¼©ùB6LRlvó&ÄÑÞžb^¥üi‰`’›ššé¿›»ÔoZ’›æþ`õåW§FŠnŠ8)2]¿'j«VE|/E|«úvê`açñï»›éü?5ц},|L Ÿ=žÆ\I½ºí1É‚ŽÅm x‹÷ŠXˆ¡ÂâÃÝœß}:ç)nÒ'蜧Ȯ‘¹Xh™ÎŽ :òöíý¥3¨ªÖˆß޶*$Äy¸Ï7ÐËü…P´YŒX @VJ½öƒtÎCýhOy¼¼‚Û•$º_›)ýðúÇy1.w»#jü{´e JokXXqQr³½ºÛªwÝeç‡1²‰syûK»ñ¢§šPòñ"ÿxå:uˆZïI?nþó eµÒœ;v“Ëf…=‹éóÕãÍ*åÚœ€d{»ô$1­Ç¬páÉÕtã”ÃfrAÀò„x"Ú¬p°¬ˆ›ö]ö?÷Ÿû!ò%‘x/‚©¼à˜U–Í=ü‘XæA31!ï_³Šèì§n¢fÞãñͦhǾ>Ô·ÇNÍ6#"ø#àŠŽû>[=Á´—z\0d)}g¿È«Ú¼…LtDi¬âó­#j¿²W…,=!èþ3Zè'óo7ŪËΠ[.{Ö”²Q¨}  À@_¶´ÆÓ¢•S ,!pÖ¹ÉÕôÈÙãÅDqóL G@ rß=¦ö1çm¯ë· ¥½‡zDnŸ%Ç·›FÒÁ²B*Ê;¤¥ìm×ݹa€–ˆˆãNjÌn-Ô°]¥‡û¿\w2UTgé‘UXyÄò[ÃÄSIŒ Mÿa;¹¢žh5?#íä%*ˆÜÂèáºVó{Øvók"¾ÙGt HšN¡Nx•zejº kÊOk$1­ø£åÓ´FG<èBÀ1-¬~K»ÔÞÏŽ9³‡–øÙÖ.1ïI?Ì[Oy›†ìË^§G^Ïk»<ñ©‹–n#ZËï}7B_ÈãÁ^מBtÓxìîÛk¯Ïm|ŽŽH!«OÿÖ92ëèÜËe|ºìQžú Â÷Ñ´ð“Džâòñ•ƒu<"'hnJY­xú7×Ïá–nÂl©×­py ¾9°`øÜ¥þf±°\H=(©zf'®f›öH·K´Üuñ©¼ˆ“ŸnØœDî蚃›[Ýô‡¢_™—k–âs‰r¥öˆ_äކ—qZŸ¯)?µ’Jëô]r8ˆá§p÷e&¯ X$9Œ@? Ž>&Œ$QEѳ‘†öhŠ*S' ÊoJÑA ‹°È¾V€û¯÷3+}lP“µ|ვ´«Ì„›¿0.Ž™“µ˜‰8íÄÅ´ÑeÃÑS_\Ôn¯¡ÿŠÖÞSy{×ÐR¹¥ˆ“A;)U3 þÓîÕc5oüSÝóí›5Bú¢@R[/×GT! íf¦J…£´CÚHôû_:­uQúK™ä¾V½ zá£UÆ¿ñOo£‘Ÿ—ÀðÂ4¬»±o¨ì„ZÚõ«S¹øª(€ð#í4a`=dàÅ?á¹GíØz·àé_m‡²N, |áè’PÑô<>Š»1óôÌyY›€Fÿýáðè69aêÐNSÿÜÜÇÛ¸SÛfð{ïå°_)z·àéßúçÈ”Á²+1Uv(O]¨Ý7§i}ÌS‡tjlÜEtð_Ú2οŒH‡ÁeÚ C¬pFFxú–ÂQOìUM©‰nªk’ö,&Z1ßP L“H@ÚY'±NF%~8R‚Xö÷Ä>RÊB!r èÕ €§¹~3ª´øXM$õÕÑÒ®cF1C¾ú€ÐÎRÚg<÷ÿÇañíž±XÌhÇàéßbaî©üªo‰awgv—XŠR˜€çð¦G¬!ª.Q¦tnþ×%Wd¢ h[ðô¯Š'õ±£KwŸ>ÙËË£ã cÚœ-õ#ù‰@ÄÒ•@¤­xú×Õ Jd6¼¸‰²RÚdÚ"­5Sf¥PVø ´1+hI âB0œWD°7H[ðôo¿óB¬ù1In7€XÐ ä­jgqÖÃdÙ?™ßüã’UÊ1“@¸­xú7Ó[Æ–}ªÜ7~öãnMñŠ`‡@ €¶@Zÿ?šÿµ9ıÂmÀÓ¿¼î¿’€¸îó ;œN ÄÀJ9›£ä‡ˆ¦ÛaÑ€àZ[ðôoïsbPQåË]ùSÚC½=gíÚA„öŸ´Џˆ ‚shmÀÓ¿½Ï wûM–;@ÚuÍÞž³ví° ÿÍ™=ôÞ=FzïÓÃæ/;ÓO,ýw‰ €¸ 8‹€h¸ëâS)7=ÅoÅñôï‹ívŠî¿·¾o— ¤`V»´ø÷ÏY¼û.±¹=±3üGÑïŒþתr Õ €§ 8Q%Ïþ¢ƒÉÈÂâ B8°äpAˆúˆæý`Z,§@cðôo1GFaî€Âæ(R‡t0oB{cØØì• „?KKÿG’/!jŽÃ2 jÀÓ¿L/˜[V&¯"q `×VÞÅÍ\´(=€`Än·'†J+ä¼>[,Ò'_ê@šã:·àéß /˜[¦ä‡Œ0×ݦ—ŽA€A\p¸*›ÚÚbƒÄÐïP¯¼Jˆóè—¡UrjÚCäq˱¶­Ó+–唪¹_+Àý׋!(D–xúwóª•âUÕv1ñD Æ¿Cgw.Ûâ0¨ˆ…Xb@¾ÈÒ" ‚8ª¤\^ÿÿ€B‡Nÿ;ð,7µHzjƒú]ž¾éɉô‡W? rv*r¨i?Ñþ'1Æ@3ŠˆŠï6°€#YK„Ã=ªvAü#³ÿ`šÿƒ¸Â1‡|­½ ²iWI…cêŠ!€.œ 2 @¡-W8´ §­YiÉN­¾£ëG»_zå!‚ —9Pôý!€€ ZĆà<=y,P|¬‡ZÚ¤tWõ{èWÓŠ»hiGÚ}ÝJÛ}Ç¿6&Ĺ2[$7ý©5˜E Žgõ-h¦Íe˜×Ê£p;„þVØa¾Ø–€c/ï+Vôû—FOöS«k34F.ZFr奷F— RƒØ‚€x$¨²&‹ rðÀo‹'‚J8F0›$ÞzheÔÜœ 5jÔñð@¼ jŒÈlAàHw`º”º45KiiR>,€Y£ÄF§N ÀÞJ»-$¡­d«•νm•9%XæuNoNÈ/z65‹9!/­MNA(Ew§ö'bÓÜT¢KOÔ½úÈй¯h0ÀÊ €³dþ0Ò’$­„ ®Ø9XþýêõWpüÑJGko䎖˜Ræõ © '…D×*W”…0岓Ù4&ó/—¢Ž¥ÅçeLˆ.ÃÄo8ýÞèòèœ:>Ÿ®˜~ Ý?ÿSÚ¸_Í¥†ÅÓÿSˆ~üVgãuø.ü’;^‡ŒLÊ¢r!Q[I…û/Væõ@æuÎm±×LèËlHMD @7ßÇ//Ëä»X4!þ §ÖYÄeSlöTúÕµ™tÍÃ/Gcai }úËŒÞ/†Õ\CÆÕË•2¯2»:5xQ$@@à2•qZÆpƒev_qê 4¤X½·«úžþ-†’Ìë̸V=|"ó‡!³É/@u±;J±11ô««§G™‹þÉ }ú×ß\äÈd^d>èÀ¹ê€à™ƒcdþàT»u  Z+žþupª Y¤Hì”ù cJ‚@@2•1@'Xl·j­xú·Ø tÔÜ~ €¬qÖ蘄Å!ŽLe,sÐO€êb·NTiÀÓ¿N5)Y@æuÎ$”(6€pd*cY?öUÅn ˜Ý ›ç÷¯sµD² d¶tJć¢4€J¦2–9è'@u±[Gf·üèÜb¬ú§£?ÍÈJÖCÌ38¢Ìà ðij‘³D¦ì#ý Ø‹€Y­¹é)tÇônö‚éÀÚÈmm±$6g€àw[Î]96Fýuä Âî ÌjøÑ¥S)= ô ®±Ä¡X9—/ ·Gba– ï#!ø:1¡)À}w×6Æ’@_¨Šä&»Àûô^”ïKP„Óͨm”siމqS\V"uêù&ç,³ ]YÀÍ7ÿƸÁ‚§HH“e·xŸþ“åt]…¬<"DE ¶IÎ5!‰t\„'¨œeáÄrÎ2 ? YA–Ú—U”sœ€¬V<ýgn‡ÿd]d=èØÁ'v¬@¯ÊüaÈú±¨*vH@V+žþ t¢ Y˺&$&4šP;© ¼8€' €Áî° ˆV€ûÿómÜ[vZ- ,ýô_ù ¿Ž·>t5½¯>5t<›Ä%d¶tÚÄ5¶ª@w&%ÊSƲúûT» &àk¸æá— )ÉÒOÿÕ+‰Z‡æ’؃(Ó@ ƒƒe™:2êƒ2Â#€.€¼dþ0ê$ø PUì–@À¨±–~ú—ÀÝŠE4µÆ,#ȼÎɨÊ@^25’Ô~€ªb·¾V½‹²ôÓ¿Þ0l’Ÿ¬æ ]69i"¬@p‰ñÍŽè¿]ú3U1G½[ðô¯¢—£·I¦H8Û)z2ÈAo€¨Ìѱ2ðª‹Ý‘póX‘¦=šR‹^Ý?Ý0ŽÎà]MñCEúíU§PzL —ß)f[M§øj%2¯h°Ò™¡¿­˜ÊüaÈüÁ¨.vGJ i7ѾٚSÏ,"ºy‚‹ž]¦9‰ßˆg!ºmÄ".›7[y=ÙÕi+'Ù¤2èàH™? ™?øÕÅn‰¹ÄCC #/°0虫=x‰Tä•N)óz ó:§4t‡Àñ‰‰ÛUDÔawU½œ)?:˜Š,t ‘DôÙÝš>8üÌN*&Zy¯‡zf‡Ÿ)¬A ªAÞõ@fK§5è;ËJ€þ–ùÃØQšÀ ì¶+ì¢÷¾ç¡_žE$A¨Èu·ó4øOˆ›(VV?¾½DÞõ-V?[¢³cð“ùÃØr 1€Ømgq,¿wž‡î™NôÜr¢×¿vÑV^,ðÐÑ1|¹©DýóˆfŽðÐm“‰òÓìLuóØrPÞõ@æ`g_ýð©€¾ˆi£äÄjhJC¿Ý%ÕqTË¥'¹gšÜŸ¨×Ïo$†/,C@´üà4±Yý¥†{ŸZù ­¢•Áy¶Ji)uÎŒ#p E×òsJi÷^]°GüèOêÓ8gW#—#ârˆ²N³„Ãl'€ÊÎB €ÊÞ±ŸmèâÓø¸VÊɬC¿CM-.Ú{˜Gú#€8–€Ì®À‚\Ìpì‰v´â!Ω%Îÿ QmL ±%†öHzˆk¡ìôJÉ5Dqª@@ˆ€¶ KŸÃ¢ùoÚðZ}2C. –" –ëÈi)µ‡].Ïë~Ê»¤ý@±ë.' €*vâ*Ž<ÙOæL€ ûäöÕŸ jØ´_Þï¿¢:ûãëîÜp«5‡fpŒà“}1C£ôœÙC_äx׉¸2g,Û‚µ_µøq@ÀŽ>Û,õ÷¿ÉŽ Q§ð` @^²Ç¨Ä@À.Áa°%%¥¾íi£-!¢Ra€+#­†d¾péF~€€£쯈—ú†‹Gaþ+ àŸË±½b™ã–l‚8ÿ€€C,•ÿ»ßì´¨fAàøÉ€u|‚€sHÊ÷άv]Ô4Ç  @Ëþ¾=vѪõ£µD:ÎîòxÚõí³Ô;K±E:<ÍQ×-ª wí~0ª,¨Î€wŸ7îˆÎ®wŦ‡®WÓ^¢Cÿ/XŒÚú`GqÌ$bêß§¤¶ü}nRUQ¬b 48d`ï­béeɶÞÔ{ºè:õ´µŠ¥l£ÖYö´Dg—Ç­­Bž¶èÊ¥¸ ¨¿6ë+Ýe ²Wý$ˆ9v=Ô+·xÞ,nùxÕ®Œ¤^èÐ@MÌÈH•·>Æ’]£4X…( v ð©üþÿ…vàfĽî%!ÂLgëèÜ+Ø €Œi¨:¢€L`‰Ü™?¹:NËu‡hw>C´ƒìßA½äu”ÔeÓ–òâ`æà€€ ˆþÉànçR Ú¹cÚÁh÷ï\þ}»ï”—]Êï}¥{Ûï3òÑ 0(¯n5’1ò³ l>”J¥ÕR/ÃNìÿïìfŸ § zæuö‚ªßyÙàwÙ6± ¹Å#¨®à­÷±þ#ÀÍ£;˜``iÈ@À K7gË.àqˆæ€.?¿£ÍfÒ~< wœDõ-I­C4+˜÷M¾L³wòul‡Ì/Ë';0 ¼3Tš¨kN¦÷6OÏ:İ }Õù´Dn €´ë—eœÀ«p°­ŽÞ™º0¼èÑÅ~uí´è2@je ¼¾þ4ƒ%©×¯(ê%—ŠƒEÆ„q–róÙ>žG*ÖÐF²ˆ£.ÞylNEé•çaJÂØ0V5KìÆ Ô4Ê13FpÔy5¼~‡{bnGû[¹œ6VìXJào±Dq~VŒ­â4&ÚØbÇÓ|çÊøVçârÞä,¿zäìóµ8j` @ø—ÑŒ&E¸yåº7vÿˆî˜Q¾•VIÑíVy–¦ˆÉ«ô-/±7Q›;æYþQÕÒŽûd~ËšB”É[çú&ïYÑy/¾›@àÛƒýiSY/™%o02 Œ´,¶³‚´¦súxƒˆ¤†tèЩS!¤…W–eÉn&”V7N%ðêÚ3dW]êu+ÚÊ ÀyðU´y…™Þ×àˆaž}QøI"O±a_"­Û‹Ù‘DJP‹@‹;ŽÞXwšl£,%ˆãO€0óI)^Ó÷m˜É¢Šþ*· €؃À'ÛO¦ò§!7,’[œ>¥AèÃ1P.Èß/:S¥…×WfR+Þä&7 # ˜0øo1ßH-;"À¸³ 2¶s"KY*±Tè¢õaŒ¬¬¤0˜@ec½¿eœÁ¥tÉþÅ.{,¶"À‡ADÀ•OÆíœLê0otDà($ż³q25·ÅË´J̱}]fF• ?Yy×O /øIDAT€È™JmxouU7ˆª V%`Âèÿÿò³Úª¼:Û ЙHtß!"ç÷'mŠÌ#!@¬Gà/Ë®”mô!.pìBe” å8}²ql.B]‹%+¥„ øŸûé¦ñ«¥”gÙBRø)+‰WèCEˆUÿÞÝ4Q¶5/ñ²Uv¡²Ê"+FG :~rr±.@~tÙhOýøÂèÚA³)>ƶ¿kí0Ō˄ÄûM!ðز+Ì(×vÍÿ!Bt&Þwt„Ç«Cl>ùZxÇËvüeOU½.1ƒk…ìAÀ¾vVv£7øÍ’þ>}#¹LSŠ"€ ƲÁЇˆZ§$ÒU¶xšhóÀuü€¯  $¿.¿ŒÄ‹½$é×%ÉõëPD@š¿à.¢UÀˆâeë5àÀ¶Ã=HÌ'FP›À¾ê|zå[ñp*5¸¹´ÿH-Q ÂwƄϬC >é<<E¨í;0ø‹h¸hè~«¸Çà’ì“}¯‚,Õ·›®ê×-G×üŒÌ¬G^f×ú·”yÚBëâÅkâóºÄÐ-·Ë>ì8Nà‰•—xùä°€¯Kû%—©DqB`` vWH?3µ›f©˜/±µäMZ;ߺ’¾4ëX:kÞï®õLùíµ3HlN ¿¼ò [‡°ûD­•vùý’XHÔãN¿‡°Ó?Òº,zqõÙþ»×QÍÿQBt&ø;º³Ñ|„O¸½Yúë6ùìJ~þ—¦94ó@D¢§¾¸˜[d£¨åÿ+»PÕÊ"€mšÎ›è¢•Är­/q+Ä,™…FZ@¤äº¦{¦ë.c÷|u`}ºs”±… w° ˆ—þüë«™a§Ó!ÁË|ó«×!ËgÚ…¡i!^¸±Mkd½â=´äZ´èù€€Nžä¾ÿÚædrÓœü÷°æØˆÜÉÁùh>Ê'šX™Gê@@aÜÊ}CÉ„÷‹k悈 à4Û˲èo+.5£Ú¯ðuh««\&D@`ï```6‘y‘ýš·âHGšæ¾EwÒYSÇRVŠÐ 6 »yÍÅWmZ9TË.<<)ç'oOãWþšriåþ€Ù]ɘr–v5Ã{ø$kæ“L4Á=.³FåµñôÀ»ÃèO×Y¬Ü²ZmóFS¹ÜPšTï|•A 7÷”ZæÑÂÞâëÏ:3 ¶J™]=….€®L¢Ýó gÀ“«å†ç?͡ջ¤÷9Ê­$J… Ô6ÆÐ/_-2ËÂÌ*ØJå ÀöbvÀQ§¡@ç³—O°nx„³}H笃f'šïùw7úðg;(6‹……ƒ `‡ÿW@*yÁ$É¡ §dóÏ¿û0/p1”·€¡âº;7<𨃠%ำ!޳ðþ7göP±´ÙÉv‡õõ`ÙŸ6=üÜݵnwlZX £Œ,Zæ,ɦ§Ž2'$‡À†}‰ô÷ÍYòªsæb[Cõÿ‹JG pÀѢ݇˜X/^óq(Ê;D3&~L, &È#Î>hÂûß* óFWS^º%€ƒ —€h}»÷¥îÔæ–¿(×€žÛ¨oñN¹¶IiD`ÐÉ<å䥔˜ÐdPî³­ª¥ß¼Î˶"€H!ðêò,Z¾5EJY 9“4"' D§v였ÈÏ )S’êiòèσÆ1êà+Ëø‚´Åœ ’QuB¾  "JÜ¿6Ip÷ê¶›õÙ¢"KÙäd`à©zÚ˜O)>Μ¦ø{ÿÓZÚä7IˆYƒ€rà.·òszRE7#ÞªÏ)¡€¸DŸš„— @x¼ÂŠžZCF-+^‘Å ¤GßëúúV½òG> àtK7¥’˜~kF螀†÷_oFѶ-ÓdðÏ,.€Áħ[ÈÓòÚ .Åöz·€ÄE @@_¥ÕqtË?‹I 4#œ9Ÿþ]&nF…%•i¢3Ææ²º˜ €Á'VVz•icÄÅI\¤ÄÅ @@b´ÿmÏS‰I¿«âÂ}4jÈ·úT¹t!`¢8ù¿.¸À@¸¾¬Ï™ü!e¤Uû¾Jý)q±2cŠ’ÔŠ¢0Dà±÷óhñsZÖDŸÿå3Þ —xñ‚QL7U'ùBø£¢ó¾¤ÄFºhÚ;:çª=;q±-è|¾9•z§ ºL¢H=áÄÔ»ûî(r@R­L's7Àp­6FmÃÑÔ˜þ¤¡ßÐòoÆÑæ]5¦Ð7š¸hMXOÕé›1r‡(ãÑþßå.5·I]ï©Éu4sÊ{‘ÒîÏ«œ®Ò˜øy^6x¶Æ¸¶Ž&Dß§s%?âm´¤ÊžÈåHy±“cŸü1T-“ã§ádÑtwÙŒ7é¡gïáæøX#Šš§¸h‰‹×âû¶a•À ¤pºp{\tû³=èP•y—Ì N›G©Éõ]Ó¾Gë lö,íÓ –£—Ì;›¥T¯C!×ó·ì{$)È)¥iãÑ‚egH.ùHqââu_Äæþ`÷!†iBãN¢Ò×´%Êæ%ÓÄŠÊ Y¬!3Æk«¼Ü×Eh³ ±ºøëgçÒÂõR_íÑÁ†¾=vÒØ‘_t؇/òH9²j†1²H-çÌ QN†X}Òœ°ˆ/b½Ÿ~អ–Rm›»!üüí”BÜÔ㹟XËæ’ßd'Ô2ê²lÏúã‹eå· 1ÝO´bÚŸ_<ÒvJp@V¥ d‘>ZNB| ]ræ%—Ú±¸ß. eX*¸#|?Êë3é»oÿ„ûýÃm2ó“Y„»Ä{Ezì05’éI@’X¡§ÍÁò‚FÇ c#¬3u/1àæ¿÷¤Ýåòß]nRd ºhn‹§›ßþ)¬•Ö"Û¥bú°˜FŒ ƒE€ä±VVm!d‘îTŽh0ë=±>Àåõ1móN8ð”"Ðæ‰¡Ûþw-Ý%Öf1/ˆéÃb1‚Z OsÞÒ^ `Òy•›y˜fL3KÌ Û%Е³{Q]Nó¼€’U#àáWìülÁmôÎÆÉ¦š6¨÷Ó‡Ô$`€¨äš> ³¶¸òˤݩ¬ÓÇ.¢|ž`føzg2ÝðTOjn5¯ÓÌú£lèLàÏŸ]IÿújfçÝR¿‹÷‡xþñôau è,~Áù–Y[™´;•ÛJ—ùV§½ò¿Š™ÿïù¦-p"¿Æ(üxaõ9ôÐ’ký”¸WLÓ†Ô'ÐN¬ŒÂÚ_q>OF‘>¢¤aÓ/Ñà>›iü(iƒ>þæÊLúÕÜ"ÓÞnÐ0IÞÝ4‘îýðI¥.¦[þAÓ…¬Cਘ‡»‚b+§ù)§ÿ½µ…0ƒz§2/9ã¿$~ôf‡¿œKýï 0Û(_>Ïv¤[Þ1wºŸ¨µ˜&|ã…s¼Ÿò) ÄhðM¼‰·ïsbш/5äõÇÎiÒ×(NZ ЀzdzäGÿ"=òÂ]ÔÜ’ G–çñû· y©à6ºv²y‹El<‚@ÖêG×¾q5·™9oú+Ì=A-D|C ½ü÷èK}®æÿûð&–÷Íàmo¢Éw Çÿ›Ì?ãM­¾:…æ–Ðåg½A/½{•éFÝ=§»÷}gª1ÝFØU‘O—Ïý%Õ4iyMˆ‘–ã¥~O¡åÁÑX;»>ø/^èó }r3&tÃ5¢\O¾ŠÆÍ8’ˆŠí’È»PÐ?zÒ’©]ŽaØ…ÀþŠxºì?÷Ri]–éU*Ê;H—žù¦évÀg€PÌß—N‹²SÍÐÔâ¢Y÷¦ÿ}%Z­@À^6H¤sêK;š^1ôû›îÇ ˜ëÅÅàÌaÏS¬«ÙtËÄÚßá%ƒŸ_lÞR¨¦C€¶#°jG2Í|¸/í;¬ÆRØ—q¿Qúýmw¢Y B :I´œ3W Ë<¼É=/u£‡?ÂK’`± %œ#"&ðÑÚ4ºè‘>TQ§Æ[ÇrŸ¿Ø@À hu eöL]AeiOÝ8 ±òðûC¨ôàíôàŒ§¹uÂm|Ñ”PÁs¨«>&yi»ßF$^Œ`8×–gÑÏw§V·BVŒö«ý!€€Y Ì"¯¡\Ñ PÙÜ›jZŠ4Ä6>Ês_Ϥò†Lzúü?SBl‹ñFZB[-‘ج¹ —î{Mß‘€ç›ïo~WŸå‹ DL]£3>¡0&ï_üÄ­ÎÍV¼ 効¿SbÚ”ñ@ V' º°~óF¡R7ÁT,®Ââ_V÷/ìŽ@tü O€F*2ÀWYñŠÔóÿó•Ôeûvá”#ÐÒæâ&ÿô·ÕZÝR¼åoì _(Ç 9€|Þ‹ÇôI[¢”¥bõ´sæü™vVvSÊ.‚@Cs ]ÿdOze™ùsü;{dûÞ¾´qûàλñ¤€Ž<’=Ü ð:uOYIbÃÒìª,¢3Ÿ”æokXÈÂ%°õ`"ý`_Z°&=ܤRâ·ò’ÃϾy#mØ>DJy(€DF±ý.rÓèÜ(/i‹R–U4¦ÓÕ¯ÿšîûäfjqcL©RÎq 1¯¯È¤iô£u{“”®=D€ÒîqŒqruŒ«•Ææýƒ2ö*gõ“+/¡óÿýí©*PÎ6d¢Éÿ®»ÓmÏS}“5.kö?/U¯¡5~)ªS”h_\L#ÏŠRâÊ$–ª­¨/÷¡ÓŸ›M¬ë¥-b€¶p“ÿŒ?ö£/µÞ TˆNd1€ˆÑ™—01¶š&+¹‹W6Sïâ'^Y¾5…ž¹eõÊÕaƒ^·=Þ"Ý m,ÌÜ *Ÿ>–·M4ùÿôå"zé3ë=õûƒï7_ò< í·Ñ_ìÝ @èŽT^†b,Àؼ¿ÓòÒ;ÈíQcmóöµÿŠ_ºrúýýéo7î£sNŒ²µ"‘»zÞÓ>{uÿ/‡—"^ª®}·l¿Éïf~IÕÆýê ßhÐBDCi#!€.€H¨)”FÌ û<[ÄKž)ªêcéº'{ñÓZ7ªmÄ馠‹,c’›Oñ>ͦéÜäo·›¿Ï >€)‚>"ø4’®ÈFÒ•”·X@•·ªò3 shü}éíU$–gEp¬9Ø‹Îy°ýèßݽ‹ü„“Öjq!¬æ1ëÚ `]ßu°¼OÚRœù~‡}ª}9Xçmº½ü¯½iÛ¡Õ̃= ¨nJ¥Ÿ-¸ÎøÇ/hw)9%@8ÅÓæÖÀ\þº–.@ÿô…ºæiDf‹Ö§Ñ©¿@|»€[p ÁØêyzÈE¯¯;ÆýãôÏUçóçÍ(°úY¬¾ý¸úªï£0,ôÐðì·hhÖÿÂHcNT1Eð‘yù4é×ýiþ·j.Ùj”º©¬]ôŸ?Òmÿ»‡JëÔ[Ë_¦‡ dÒv^Y¶ó¹‡f̧sþÃÏPêw¶ï*K «ÿÖË;PpO9OõCp,ú–$úÝ¢›hê¿þFŸíéX+Й¾ëE@/’ŠåÓ+m’ÿOŠqé0_BÝÞ_Nî@ý °€à !šûçmž@þù4=¾ü2^×B½)­fã‚0Ûö,Àž~õÖª(ywÅÀøk,J#ÆÜÿf¡Wˆé^6>9¹jb6È'ÛFÒù/=D7¼ùKÚWo™ É|—ÒâIµ"@*nG`s7ç&n£I…Q/l• ºÄt¯“>žþ(×öÓ¾¬â½ìóùßãŸéèGW¼ücZ¾g¸^YžOŒ«NÎ{že~H ‡0œ8 0’V4’®"ygÄï§É…Ðò’;¨¶Õ"Ëé2»•ñô˹Eôè¼LºýÔ¯éæ ßPzR³ñTS%ö4¾+•ÐZETñQT·¹]ôö·ƒè/ŸœBåF•—‰c]Í4–»Õò“Ž,Õ+DµŸ—|Ÿj[ ¥™äk À²ÁÒÛ¶ Ûº¶cÅRâÓä¢GYÜF•ͽ;Tü[y]2ýþƒ‰ôøÂQt˘wx{›r’£\Z8Xcx¾9@GBmÜ‚T1¿ã>ßšÛâhîÚiôWîßßQÑ]c*µ¢%ÄÔÒø‚§)+aWà :àÀ‹@€Å¹â"6±pö±'˜hò2#­XæÏŸ]E'>ù<Ý÷ÉÍt¨6Ç 3P¦F­ ô Ïá?åïÏÐ]ïÿÀ²7ÿd!ž író÷að‰Œ ðÁ§U@XÅS:Ùçj¢qùOS”U:å(?1]ìÉ•—ÐIOý‹îýð{´¶¤¯|#Pb@Y˜=¶ì öÏsôS^ÅÏJƒû:WJtŸZøîë/é|¨Ãw‹ˆ€½l´–û{œ@]Nðr§:ŠL£ó^ ¤ÊJÚV}F§£ÖùÚÜOÏ}=Ó» /ØA³F|B—[D…i‡­S ›X*DÙ{<•ïUnê_¼ó$[¬Ü——´™NÉ{†´Î¢ñ‰EÇl»îÎ lrº¡:p’à‘]<á8t˜ÆQ^ÍÚ1Ä"AóþK¹‰Ûéëòk©ÅmíuÖ×q+€èøÍÂïÐi}¾¦Y#?¦s.£äø&k;JaëÅò¼Ÿí>oúgÐÿ6M¤ºfkŸCÇQ{ø½ðHÿø‚á>¾[Ê‹ 5@'pŒ`õ[ªÅ±sf ÞÖ§% Å)Jþ–¦=H«Ê¾C賸)}²c´wKKh  †,å–iBϵ¼(’ú+#ú«“jû6—÷ôê{×ê·ró¾?®‰±5trî ”—´ÉßaMû 4aB$8F(ÀZYÄ I<ÈiCå…´­æteí ×°Z~"ýÏ·gz·âŒRº|ø'tw ÌÝnVŽ_^ŸIon˜B¯®9ƒVhK¢É_ÜüuX3"À–§ˆí*`;—FV!1.`xö›”›´Õ])ìåUæ]6Ë»õÎ:D§öþÆ»Mîõ-Æ t†ÅßEsþ²½ÃiÉ®QÞmÍÁ~Üi¤¥ÍOfÊïMþï{÷ ·É?XÕ ‚ÑÁ1@¨à…l]§q—À—e7q—@…,ÓÏ”]•…´«rýû›ÞLåî9&&õ^CÙúe™œšxÊÞû†»áu`#ÖäOû'ç>ÏMþ[ ñ•O,/û>U7a± C #Óˆ @DŒÎ¾ żg±|ð†ª x–€iï ú´ÅöìWçñ3®‡Fô(§S‡¹hÊ^üe`=¥%…7Ì ´ZÚ\´zW2-Y~-Ù1ˆVìFbV…“B>÷óö6ù¸¨"`Z¿Ù´ŒW €N~‡è¤Ó×ê–ôíáYtØ­Pà«E$ÇVÒˆìש[Ê·l±9kA$$Sùä‹çø,+H}â•Û/­©K—ýB ˆŸðiÛy=»–ÀÉœøÑˆ3Ð!á·KZ•íuË2¦Í¢Ÿ|OÝ8Z_q! H 35¢ƒ€bJ_ÿŒO¼+ú‰w`˜Ö=÷ùöímÈ-ž×¿ÂÛöû%ü ²Š@ €‚^ºib¿çج4­ƒIb`àÆÊ hgíDÞS©|1•€èã?!g.¥Ç0ÕŽv…w☠"€mÓ?ð&„ˆxWxoüþg}%âs wTð'‚Íભ C­"|èÄz¢[ ª¹Ø· Ÿ ` Ñ¿?<ëM*No»4§¹?@Åý ×D  …TÄ[°ábºË—¼-àí#Þ>gAÐÌŸ' {°²ÅqÁ|²vÒ”¢?ÑÈì×4¿9Í_>Ø‘Sûú¦JÓºÝÏ7q¯Rêæ´Z|37a1øxcЈúŒå,…jvó¥ŠûÄXÞ~ÁÛBÞ¶°hù¿£-üÁª ¬ê9Åìý­G.À¿ç ðŠYsìL ;a—娉" ’S£'ú'oYÜÀ[(IH#€ÈN*B,­::÷EšXð8÷¿tRÕQWÉâcêiTÎ+4¹èÊLØ#¹tý‹³˜úñö!Yi{0©ì˜×X\c{Ù¤‚¼aGZ¡1®Vo“m¯´e´¯n m®žAµ-Ê®wd¤¶¶1ûøÅ¿\*úû„à›é4®·‹EŠ[¸¯þ$cépS?̃ ¤Æ•yŸô{ò Ïþ!:ÑñCêã ޳ÀŠSÁúðÊob«kÍg!p wŒ¥úV¬Bªšëâc¨GÊW|ã_A9‰;Ù<û¬Ö§kˆ¼`} ¬ïCGÖ@ œùoï{[ö°Ø_?šZÜÉŽä¡B¥E?¾Ì)šøÅ'Fòë•£"àz.e¥±%éš;Ö Ðgt™ADÇ©M'àá'ÌmÞmdö":|Bt‚È?Rñrù“;í–ñ5ž éÏ[ÌŠyÍ}ꪣkÚÕÓ`3oþ¾z@øHàÓŠbb]â=Õ¾uûÇéY‡äÄ&ºàôy4÷ÃËôÌVż tö @W £xׇ]wËÛ“‘CuÕjôcªpó÷‘‡ð‘À't$0î„/èãåÓ¨¼*§ãû}ƒÐѧ&ø% ÒÍßg O`L€>A€(6¦Î›úžSPøDÆDéq€(Ú5¹Š7kˆ |‚Àq' ]MSN^z|‡½ÿƒÐÁ¿:@´[*ßü}¬!|$ð Ç \8í4°÷Öã;ìýD@”þ…ˆ Ý’[áæïcà#O8B@tÜxá‹”›)o­“ÙCDá ŒžÝ’FsóOIˆå~Èèôd=/ÀÓæoöƒOè9E0‰W LO“2" M¼fAs›[Sâ´Ä8rE±ÈŽ‹Ì] GS%I*Ôäzº}Ö?höË·SUgÃê˜"x ‰¶ ´q²}¬hnþýóÓèÔ|#‹SIM#‰¥i[4Þ<}¥é-Nì™Mb‹4¬ØQNëˆÕYC‡™#»SJ~†¡I!F8ò²ËèΫž‚šãF÷Èæ@`v¬² 7Áµ =‰f +¢øØðOK!¾Úí˜fO;ž†¨“Î|" 3]›Õ¹x3²óµ`v€Fúá_i5fŒhÖ  ÊÍßG+RÐ-3™ÆõÉóeƒO&àé)5¡_ø`baø XvŒúÍÞʈª¥W³¿¿ÂÃâæ?}HÅÅFÙáÏì‹"à×>—–RÓbñªh5"@#)Çt>ò¿1“ \¦iˆãè(FÞü}`}" Ô˜Üü}Äð  p×µOÄc```FN<âÀνž·ÈGv9ñìðSg7_±¡Dnþ>RøÐ|Ý¡Y9%ºœâiê)óæï3×': ÄÍßGŸ  €O`` vfvŽ `gïêX·œÔ]¦úEbRg€›$‘Ž€À™à#à#Ï Äâ8ÑÎóZ@ˆƒ>Ð+'þB°ÂaE" !g‡p†ŸmQK!ÎRˆÑþ¶ð&*a6ˆ³=`~ùæû€€€) LÁ®L¡ʸ†€€€|ò™«R"€*ž€  `ˆ“À›\,€É@ñ   ŸHJh¨QÁ 6ˆûß‹¹Åóûî gŠ+"à–ËŸ}™mÝg{u°ÑÑ"@‡3Y€€€]ô+ÞYÁu97ˆ»85@= €Ánp*ò½3·rÝOã "ÀÆ'€‹ª€@¤ "%gtÖñ,© ¤â–^€tä(@¬C"À:¾ ×R€p‰!>€8ŒD€=`O¿¢V   +ˆ]q*‘€n€   >ˆõ}Ž…áÐB\p8ˆûœöñ%j R@HÁlx!†#F  `?Ö÷)€õ}ˆ€€€) LÁ®[¡º¡DF  à<Öõ9€u}ËA@@ J¸!l# ÂF†   @t&¢þwõ} A@À ,á¦cFBC@@¢%-Ayé!ä±FI  àW[ÉÁVòl‹p¨x>·xÞ$‹¸ˆ ¬â)Ø  #à@Ï.zƒE@±\`/ÁF°(Š€BvÕ[,’Uw€ê‚}  `qcØe¨î6Õ=û@@À(¾Ç­=Tv€ÊÞm  `#‰ìºŸ«ì>•½Û@@Àf&¾Ë­½Tu!€ªž]  `SbVÀ÷Tu#€ªž]  `cg©êFU=»@@Àæ"Nän€|]  ¢W`€8„€CDÀ*º@E¯À&¿*ë›é³m¥äöxüÇNkp€˜ª¢gâT4 6©G ¥ÍmªQâæÿþºÔØÒFM-n:mpŸ\¦Úä¤Â[ÙÿBv™E¼¥ÕÜóÏ&¾Þ«±UãéMˆn*?3]Ä›ÒóçÙ¾pƒ’]áºÑ¡ñKk›håÎrÛ'W:ö7Qø®Ãu´hS D€DOT6´ÐçÜú2±¾tPÓØBŸn)•X[[µíº;7 P½f6*²wRÀ`v€X£9Ôv•ŠŽRÁ¦uû«¼"@¦-oþ¾²}"Ý>"Æn>Tã2;`ÄÍÿýµ¨®¹Õø ¢%Ø´; ] ¸ŒpL «_Msf-éÄ_Û"@-nþ>s|"Ý>"Æ  ‚Œ–Üü÷§ª%ذ%@Ià¤UÏuËÙ%£% ÔÍßÍ'Ðà#bü§Œ–Üü÷£ê%ج%àˆrV :€b‘m΢Ⱥ¦ŒZoþ>V>á)ŒÌÿFŠ€hnþIñ±Ô+75|H¡$‰€ *†PÑ+mÓ;‡FöÈŠ¨D#D@¸7ŸáB¬ØQîûŠONøÿíOˆE‡[wóŸè®‚!QXHŒ š DEDЛ".žrÏ^ DÄžQ‚‚è!„z aŒÆÝÄ$JvC¢›lÔõ÷6³›&™éž®zÕóuáyÝ8|ìL¡‰UÙžBð·GO½Ð‚­‡³åƒ~ïÄ}79Uhb`G/pPŠÁ¿ÑÍö}}ts.S¥ M Õ!%Þ^ ô»lºK @÷3«U1Da å„ux H!ø›«o»iͼ$ìöEÓ=$üyò¥÷ìòüÍ~/=zžÐbA&¦ü "v]ÍÃÄ@‚¿ëS$ºq–Ȉ’ãѹlÀ²i¿[rÍ ÈEÃŽ¥b&ÿ¥žˆó=f@ðãóÔ´:J~»SàG‚—œØ# ø;q¾Ìˆ‘üýø?K–$“‘ìµàÿ°ìèèí³‘l\TË€E|é„Àœ€Ÿÿ¨þåV+²Gï\Ç 8&Ð1—ç\—Ÿ´‡eª-ˮϹc]6Ä Õ‚®Yë–hbàêÖ'’{vo!øŸ¨³”*€Røú³²% ‰@èï^oÑ „L(ðJ@IÀ¤’€‡dßÛ’gØùt<-½ÉcÂ-€g* @ ,c{þþ9É+’ÙŠ´ÿ­v_’<˜Zð7$F@µ#  <'Ù£ŽJÞ’\êa'¿T[›Ôþ^É¿=l7XS$ÁP£€bP€žì’n[eÕÖæÿ« gTo¯d«Ú{\òkÁv\Tc€ 7` TM °_ÐüKî—<Ö{ôyµxxJÛÇr@ŸûÕÆE}Ö¢\­ÃµèXâp»vtâ\1±ؽbŠ â6'àPCv+!°eñWJÖJn¬–Lê8»â¯m!ðéÚ_|š…U€@AüM¢šýœôØ…—Éé:=è`€/´Úp´u[ „ $켺šNàÓ³64UÕc+>{ŒU¨7/êÝ=z—"‡^ÓkCmÉš†I€@÷lÙÁî«QÕ ¨–o™ÖßPåÿÊ4@]@À=Jêí3®¸rÇcôã°~í¾²…o€@‚l=úw´“û€ €o'¿&óÜ¿SÚ7B¬ƒ@4?JóWÿÑø£¸ 6ûÙ‘À‘‰©¹»7$VIvD4Õ€@w>ÕáO*øOwW£!Ž€-~@I€ÀØö‘§dæ«’m ˜‹‰èWÇÔñ×%o*ø3‡§_Ï‚DúMˆ£ÌL%æ¯û$ÏHF%#’›%@ óRkëvØsþŸI>WàOòÅ0²@€ @€ @€ @€ @€ ÿMÔNüÐTÑ–IEND®B`‚ic05 {ARGB£‰‹ÿŒ‹qÃÿÚ‡U‘ÿO‡U‘ÿO‡9‘ÿ/ˆ:VÇ‹ÿÃC+HL‡ª€ÿþ‡ÿ®¨®„‰Öÿÿ÷‡ÿýÿÿî£ ¨®„_€ÿýˆÿýÿ†¥àâ¥I‚_ÿÿþŠÿþ€ÿб俱P‚<‘ÿ2¨®…7õŽÿw¨®… ÿ“¨®… Žÿþ娮„U‘ÿR¨®„U‘ÿR¨®„:‘ÿ0¨®…Tÿ¦–î1„ïŒÿþÿ_ ½í1‚‰çÿü¦ ½í_ÿþ€ÿY€ ˆ_ÿÿü‰ÿùÿY‡<ÿÿüÿþ‡ÿþÿ2ˆ6LÀÿþ€ÿþƒÿÂÍô¢"‰ª‹ÿ® ÷ÿì'…‰ÖÿîÝÿÿì'„_‘ÿÐÿÿç'ƒ_ÿÿü‹ÿþÿÿ^¶ÿÿç"‚<ÿÿü‹ÿþÿÿ2³ÿÿƒ6LËÿÀ9'ŸçH…S‹¯Vƒ€£a‹¢£w‹av££ª‡¢££w‹av££¡‡¢££w‹av££¡‡¡££w‹av€£ˆ££j€aZI:0'3BR`aag¤ ‡ba`?%€%Vaa„¿¤£wU(9ŸÐùþåµp@u££¢„¤££lø„ÿÅ/D££X‚¤£¢2µ‡ÿô<‡£S‚‚¢£in€ÿûÍÿÿüÌ€ÿÓ+Ÿ£…¢,ñ€ÿ»ÊÿŒö€ÿ‰1…vÿµLôó€ÿà…X¥ÿµ[ó€ÿþ%ª„¢WÕÿµ,,óÿM›„¢VÕÿµ±'žóÿM›„£s¦ÿµóþµó€ÿþ!2¥…jwÿµóÿµó€ÿá"…-ò€ÿÌSöÿÌSö€ÿŠ‚¿¤`p‰ÿ Ô)¢¤£¢/¸‡ÿõ9†££€¤££j‚ù„ÿÇ.ˆ££‡¢££vT.;¢Òúÿç¸s=+ˆ£ˆ ¥¤ia`<&€%Uaa‰b€aYI9*#2BQ`€a€…¿¤£wa'[6 `!aA@av£:€„¤££waa[aa!`a aA@av£Ÿ$€ƒ¤££va a !`a aA@au££˜€‚¢££va`H\a!`a`7Aau€£$ƒ¥¤iaA ,_aKaaB ,_af¡£$…b‡£:‹“’X‹:W“’€‡€“X‹:W““”‡€“X‹:W““”‡”““X‹:W““’ˆ‘”F€:71+*%(.4€:C””‡;::.&€#6:;„€““X5&3qާž‘~T-W““‹„”““Q ^§€« ®Ÿ«ª.9““V‚‚”““/†„Ÿ ¯ŸŸ™3|“Q‚•“cN€Ÿ€®Ÿ€Ÿ†0”…",­²««~‡œ^¥««²^6… [²«£ªy3£¢ªª²…Tu«zA£««®Ÿ$+€„“T’€«›y¢ªªŸ D Œ„“T’€«Ÿwa­§¶Ÿ D Œ„‘k|¶««Ÿ¢©y­Ÿ¶ŸŸ&6•…dSŸŸ®Ÿq‘«n­Ÿ¶Ÿ(…+™€ ‹;™«ˆ4°Ÿ¶Ÿ^‚€“\Y¶¶«ª¶Ÿ«ªŸ¶Ÿ¶‡.‹”“’-€««ª¶¶«ªŸ¶Ÿ¯/{“’€”““O_ªŸŸ˜«ªŸ¶€-}“’‡•““V5)2l’œ«œsQ,*$}”ˆ ’”E:9,'€#5:?$‰;€:71+%"(.4€:;€…€““X:7 ::'&:W“<€„”““X::6:::::'&:W“*€ƒ”““V:: :::'&:U““Š‚•““V:9+7:::9!':U““”$ƒ’”E:'9:-::'9:A”$…Œ:;‡£Œ"#‹))$‹"$)*+‡*))$‹"$))*‡*))$‹"$))*‡())$‹"$))+ˆ(*#€"/NlŽ˜z\>$€"**µµ‡#"$i³µµ´«€µ”7""µ¶„@))$9µ§o_.>x‘µ±a%)).µ¶„())4¯´Œ^€[ k/\[•¯µm))pµ¶‚()*‘µ—ƒ-/k--3›²D)v¶µµ¶¶‚+)bµ€/.&k..%€/H³-)µ¶…*±°Œz\\DH4Z]]zrµ–µ¶…·µz]<[AW W[[z@µ´µ¶…sµ~[][]B1Y]]k0¯¡+µ¶„*sµl[][A W[[-/£±/µ¶„*tµl[][-bA„MŠ-/¢±2µ¶„(Xµš‰][-bW[A„-Š-0¯—+µ¶…aµ{--j- \„-Š-@µ¤´µ¶„ÿ´ª6€/V--\I…-Š-oµ´³µµ¶‚@)iµ¤‰‰[[Š/\[-Š-ŠF³Ÿ0.³µµ¹()*µx[][Љ\[-Š-Œœ³F)(€³¶¶())5®´‹m-.\[-ŠM¯µ°C)(‡+))$:•µždy2\dB~´±f«C)ˆ +(""%i³µµ±¬€µ•8")ª³µ´‰#€"0Pn‹˜{]?$€"³µµ¶·…@))$"  " ""$)޵µ¶·„())$" " "" "" ""$)-£€µ·ƒ())$" " "" ""#))4µ´‚+))$"" " """"#€)¶µƒ+("" !""" !"#('¶€µ…Œ"!ƒÿ€ic10¥‰PNG  IHDR+ƒziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ@IDATxìÝ|ÅùðñçÔ%ɽwl°ÛÓLï-Á4“ÐBIHBHIþ É›ÞHN-Àôš1Í6Í6¸à.7ÉVïít÷>s¶@¶eéNÚ»›Ýýíç³Üiovæ™ï–öÙÝY@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ :@tÅ(…]¸böèƒtÿ³t¦ë =ë`}í©+  €~hÒêZ°gݤ¯/èºè_oolÔW@8ˆ*U"`ô ¬¾\¥ëÙºŽ×•@Ú¨ÔM"࿺>®É€PûÅù@ ±hQ(ôÀߜٿMWsðŸÅ.A@ý–é¦ïèú¢&ÂûÌ@XHÄ*Fy  þúÑtý†®Ù(Æf@ˆM`¡ÿ²&VŶ¥@ö °¯?#Ð =øï§»=¦ëÑØ]@@ }jýøM<Ý~1>EhO€@{:|†@zð?E‹=©ëˆ(ŠS@:'`nø?]Î-d/@€û“ù Ð=øŸ©»/ÒÕ\À‚ €ñ0'®Nеߴa½ž_¶µ,~-Q3 àQö‹n!w=ø¢<¡kNÜ£@h¸Aß\ßò¯ €Ñ p @ôV”DàS=ø7“ü™3ÿ‡º‘7 € (fmèd½àÕD5H; €€¸À £H’!p‡6ÊÁ2äi@ÝÙ}DòæÑ», €Q ˆŠb´èSõýU-?óŠ €Iè­­šÇï² €D)@ J(Š!ÐJàç­Þó@’'pµ&æÇ%¯yZFÜ%@À]ãE´IÐ?2ŽÓNMr4 €»Ì­~  €@t$¢s¢-ßlyÃ+ €X!p¡&èGZ A €– °|€Ïý㢻Fs¢=  €ì8 @ŽHtlD ZNÒ7™-?ðŠ €ÖœmM$‚X,@ÀâÁ!4ëøãº!! @"Çé•z¹X €´/@ }>E µÀœÖ?ð@¬HÓHfZ €– °t`Ë.=«Ј†ØÑ € €@+Á­Þó@  m ° 6zê¶ì6¶³ @ìdGDØ+@ÀÞ±!2»ø£Â®ñ @öàwõ¾"üŒì#@`~Dà}°Í € `‡@?; @À^öŽ ‘Ù%`æ`A@{ø]mïØX"@À’ @@@â)@ žºÔ € € €€%$,Â@@@@ ž$â©KÝ € € €X"@À’ @@@â)@ žºÔ € € €€%$,Â@@@@ ž$â©KÝ € € €X"@À’ @@@â)@ žºÔ € € €€%$,Â@@@@ ž$â©KÝ € € €X"@À’ @@@â)@ žºÔ € € €€%$,Â@@@@ ž$â©KÝ € € €X"@À’ @@@â)ÏÊ©@@D ž2ヒÇÏÛÓV¾®Ðµ)m[ÐÆ}óo\ý_ â °\€€åDx € €1 Ò=Ìê—å¿t”~"€@×HtÍÏ7{ßwÇø~ÚÙ™¾éðÿ?Ò5sÇúæ‘kÞ ú¬ût@@¼$@ÀK£ß¾LÕ꟎oöÖž“°78"C@@¢`À((‚ € € €€ÛH¸}‰@@@(HDD@@@Ü.@Àí#Hü € € €D!@ $Š € € € àvnAâG@@@ Q Q@@@· pû? € € €Qˆ‰" € € €¸]€€ÛGø@@@ˆB€@HA@@@Àí$Ü>‚Ä € € €@$¢@¢ € € €n àö$~@@@¢ E@@@p» · ñ#€ € € … €((‚ € € €€ÛÒÜÞâG@@Àç—ÞwÇø|‡ Êç߸úY‡ë¤:H² €$Í#€ € ÐE ºÿý]¬cßÝ?Ò $öUág\.À-.@ÂG@@@ ®ˆFÉeeô°?kÈ—;vŽÃõQ € € €@H$;Meh[°'œ¦@@@Û¸Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@ à"U € € € `» ÛGˆø@@@p@€€ˆT € € €€í$l!âC@@@À R € € €¶ °}„ˆ@@@H8€H € € €Ø.@Àö">@@@Hs ª@@@ä ܦMÿ,yÍÓ2¸E€€[FŠ8@@h[ 8ÿÆÕÁ¶?b+ ð™ €Ï,¼ôîíÌwè$­ï‡ë¤:@@@ Ht"›Ñ ð«ÚžY[î»cüZ­Œ€c¢T„ € €$V€IëMk € € €$E€@RØi@@@Ä H¬7­!€ € € Ia§Q@@@+@ ±Þ´† € € €@RH$…F@@@H¬ €ÄzÓ € € €I vE@@@ ±$ëMk € € €$E€@RØi@@@Ä H¬7­!€ € € Ia§Q@@@+@ ±Þ´† € € €@RH$…F@@@H¬@Zb›£5@â%¦P–®Ý"¯!I“P8UWóºg•ŽkÙ°$Eš%Jª®@³îi^ƒ’¢ïSÌ«þymãçÔ@“¤§ÔH†®¦<  € `ƒ F@ö0àÁP¶4êÁ|c³®æ5Ô½ÕÏ­ßïùLË…õ°Ü¶%-¥AÕ‘d@ä5µvÏϺíÓ÷š,HÝ0Ø4h²­ă € àA¤  €€ÛÌz}0Wj›ûHm°õÚ;òs}s®•óq†25™‘)µÒ'êÝÓRê%'µTrÒJtmyÕ÷©æç1Ÿ³ € €± ˆUŒò € ˜3ø Í=õ`~÷ýÞú½¥N·Ûx¶¾ÃŽ%¨@Poe¨ –ʦÁm¶˜žR»wr`Ob %ahls?6"àeª²ðbíߟ¼ÜÇvú¶¬ÏøøT€À§¼AèŒ@CsȪ9X­ly_Õ4Pï»OïLuì…@S(G*Í:¬ÍÒY©Ò3}»ôÌØñék÷´ÌGЦ½"P[Οãêû½ÒúÄC€@‹?õv‚’†ƒ"kKÍÁ^F¾ôÉÜ(½uí¥«I° €´/ þ“´ÄMº^ªkFû¥#ŸæéOÚ³š eZÇ_õõNMl7XpR€€“šÔ…¸@ 9œ!e #öì‘ÒÆQ:K}['%\ÐBŒ‹@(œ¦ßýnèÚ²˜ÛL2 eí–V¬që@‹¯ ào=hŸ¥ÿOWs0ß•¥—î|«®ßÔ:Ò×h"`SW*d_Z h­Á{@ÀƒærþÖg÷+‡r)¿Ç9Þ]2;š5¿zv¤©ÌÔªÝÉ€ŒÝIÜŒ­L2ïA ~°N@ÒS5¨ïêúC]Stuj1Çi—éz¶¶q­&L2€. è2! €v 4†ºIQý!²«n|ä²îÚ`ôÏŸ·«'Dc³€™ü± vJd5q¦š¤WÆé›õ‰ È^%¹ú>À6!±!€@ôÀÜ<Šå~]ébUíín&¢þ¶u²¾ÞÈüíQñY4$¢Q¢  `±@X³Ê‡ëÿ„Ȭïåzy¿ÙÆ‚@"ÌS"Jô–³~RqºÎP-ý³×Hÿ¬•‘Wó3  à= 7O‡zM×DMšs…¶5CÛ=V“%^q¤‰ xsZDº,Ðê®üz–¿~bäÕüÌ‚€Mæ;¹­æðÈjæ 0Wô×+úg­’¼LsuO½²i¼ˆ¢ЃðZú]uðßÜD}󌶂&˜™µE…טHÄÄEa@ 9f¦þò=˯Ïuß©gúÍá,rƒV;!²Æ‘õ“ŠÓôê€é—µ&r«@¿¬Õbæ`AÜ  ß}5Îu”¤xÍdƒkçi€çµ&iÜÜ, 7±#€€§‚¡L)¬›¤ü‡Fîé7÷ö³ àó]Þ^;=²šþä邿ê€AÙËtîóÔ+ž.à…q¦xM@ºÍ±ÓSºœä¾©íÿQ×’Í»P€€ @À»æ}…zÀ¿£ö0=ðŸ(æql,x] ¼q˜^Õ2LÖVœ"ÝÒŠdH·dpÎÒ3½@»N2ÀëãOÿp‘À—4Ö#-‰÷zMHÜ«W,¶$Âp‰Yºd ¼+Ь“§íÒƒýíµÓ"gûM€¿ ÔûE&Ð#½0’¢É€îé;ýJB¿@À=Ø6÷ûÿØ‚PZ‡ðëHM0©JkÞ·+@ ]>Dâ#`Îì›ûùwèAaí$ †3ãÓµ"àbª¦‘' ˜§ ôLß!ƒõÊ“ 0W ° € ¸MÛKô¤uq†¸T×û:*Èç´h‘àˆ³@(œ¹—ß\Þ_P7Y‚¡¬8·HõxG ²i°T––5ågê<[5ðaäꀜ4ž†åQ¦'Ø) gÙͬÿ_¶3:ù¹Æ÷ ^Ðli|„e™ Ë„p@ÀkÈsÑ·ÖÌ”‚ÚÉÒÊñZé ¨Ðù̺ªül}¼`¾^ð¾ ëö®>] :á±Ð øBàóÚËTK{:Dã:Z×…–ÆGX– °l@¼!ÐÐÜC¶ÖÌ-Õ³¥:Øß¢X(ÐòxÁÕåçèS–ˈîoKŸ¬µúL&´p¸ · \`yà&¾…–ÇHx–°d Ü/ÖCŽâúƒ%¿ú¨ÈãûÌ%ÿ, óÿÛv½½Æ¬9iÅšxG¯ X,Y©•‰ €V@À“zyýPíØ,Ë;w¾Æù5&´|”, €%A à^úæ<=Ó?S¶ÔÌ–Ú mó¹×•Èè¬@m°¯¬.?Kç 8Cd¹* öjMÑ1QvgMÙ œí‚¾Ö×u© b%Ä$ HòÐ<¸S ,)úȾ zà”¾NÔ‹îìQ#àaóÿi¡N¸iÖìÔr®W ïöŽd§•y¸×t 8ØáúâU‰“@¼t=T/  &]Aø ˜3üæL¿9ãoÎü³ €€;êôÿ×O*NÓõT韵:rU€¹: %ÀÄÙîA¢D if’=7,n‰Ó –žŽ‘€§‡—Î!€€3æÞþƒdCÕ ‘³þÂÙ~gX©¤dWý„Èš™Z%£º/’‘=Þä I EÀn9°vKœ®t/IÀË£Kß@ KfR±‚º©²¾ò„È#ǺT;#€€uæik*Îu•'G& Óó5é–Vd]œ„Ip˵[âLê`Ò¸ ¾ €À>ÁP–äëeþ«Ž“º`¯}>åGðš@s8]6W­ë”³BÆôxEzgnòZ7étN ·s»%|/îKL8¹;$àÎq#jˆƒ€¹Gx“ôoÖ‰ýL€ü&‚Ú)‘µ—&ÒDÀÀœxz€ß¾ôð° .]Cè*‡êýýse{ÍtÍ?%º(…ž(k%ï6\­·˘ž¯ê-K$5Ðèé>Ó9@ï ðþÓChSÀLvˆlÐûû‹êÝò„Ÿ6;ÂFˆ£@M°¯¬(½PÖ”Ÿ¡“¾™4ÐLÈ‚ €€H¸qÔˆ:-`Îðo¯9,2éWUÓ N×ÃŽ à/ÆP7Y«\_y¢^ °TÆöüŸä¤•ø Þ"€¸^€€ë‡ €@4a½‹· vª>üt©jÍ.”Aö…Ó$¿z¶l©ž%#º¿#cs_”ìÔ²ýʱ@HØ8*Ä„ ¤°îÐÈ£¾*yBŽƒ°T…€¯ÌÕDfÂÐ-5&ðf䊀¬ÔJ_›Ðy@ûHØ?FDˆ0÷ø×ûvO—òƪ@ŽBáT}zȱzEÀl#`‘&^–Œ”êŽvãs@’"@ )ì4Šñ(®«güÏ’RÅ›H„@s8=2©è檣et…úä€W4P›ˆ¦i@¨HDMEA°] ´a´øŸ)&À‚$C 9œ™dtSõ12¦Ç«º¾&i)õÉ…6@ØO€À~$l@· ˜KüÍ#ºÌ%ÿ, €€ ÁPVdÒÑMUÇéÕ/Ë(½= -Ð`ChÄ€ àc>|ºŽ€Ûª›Ȫòst’¿Inï ñ#€€GC9²ºül½=`®ŒË}AFê„)fö–n!€Ø.@Àö">ØO Iÿ þ¤â4xë13q³ €¶ 4†ºËÇeŸÓ'-‡öZ ý³VÙ2ñ!€xP€€•.!àUs°Ÿ¯Ý2—û7†ºyµ›ô <,`®\Z¼ëz½R&æ-îé»<Ü[º† `› ÛF„x@ Mâúƒå£² ¤ªiP›Ÿ³p“Àꉲ«n¼>1àu½5àyIO©sSøÄŠ àR.8ÂFÀ/5Á¾²²ì<½Ï²_ºL?@À'檦 UÇËÖš#ä¼gdD÷w$ !Ÿôžn"€$C€@2Ôi:03h¯­¨l"oïúª ÊY®óÖ ë €ñ UêDN ”6Œ‰Üç_Ñ8¬Sû³ à‚Ú)²³îPÓãUÛóEIKiðB·è €€$,B@Àïæ9Ù+ËÎ×û`gú‚þ#€sëӺʓôßÅ2¹÷e`ö d@è² €.Rt^ Ûk§EžÍåþWdOð®@}s®,-ºFç,“I½‘ÌÔJïv–ž!€Ä]€@܉iÚ¨kΓJçéìþ‡¶õ1Û@Z ì¨*Eú8Ô‰y dx÷%úI¸Õ§¼E@ :Ñ9Q 0“üåWÏ‘UåçH0”éP­Tƒx_ )”-ËJ/•mµGÈ”ÞI·´"ïwš"€8*@ÀQN*CöªšÊòÒ‹¥´at{Åø @ âúqòZÁwäÜgeLÏ×4­j§4!€ ð™ €Ï,x‡q0“Y­×ɬÖVž*æ=  €@×Bát½’ê\Gåp™ÚûÉÍØÖµ Ù@À$|1Ìtä ”5ŒÔKV/‘ª¦AÉ ‚–@ T4•E…ßÒ+^•ƒsŸ“Ô@“G{J·@œ à„"u €À~Áp¦¬)?K6V£Ÿöûœ $S 5%,é)AÉLkÔ×&}mÚós“d¤6IJ ,MÍiÒYÓõµe5ÛÌ{~}&süh{o°¤èUV'JN8¥÷¤oÖÚ½ ð €{ø †¯8.PÒp|P2_ꂽ¯› HÑ|R¯îAéÝ­YútoÖ÷æ5(½Úø¹·~–“’Œ´pdÍL×ÿÔ°˜€lÿ£HöNšÉ,›šS?M˜¤@C0]*ӑҴ㤴:M×T)ѵ¬&m÷käç4ýy÷öÚ†”NµÍNH &ØWÞÞu£Œìþ–Lìµ@¯h¹}[Fj0²îIîN‘>5{m:Ð M)Õä@ayšä§ËÖ’ŒÝ¯ÅúZ’.[ôµ1˜äŽ(x¶[-°¹ú()n+ÓûÜ£slµ:V‚CH¬ €ÄzÓž¨ ö“÷‹¿ å#<ÛG:挀9 ?nPƒŒ4ö{ð[òͶž±÷Ãbå5EÖi#ëöërH/R(ªÔäÀÎFÙºöÉ/ [+H¾®ëK†ÊŽª¾ûíÃZª›úË;oÖ'<£ó¼¢×¬èŠ@À÷$|ÿ® dKõ,ù¨ìsÒÎèjeìï1s`?ahƒLR¯¯õ2qHƒŒê߸û|õÕéäe@·*™‘¶p¿êËë»Ë𢲲h”¬Ü5JVí)«‹GHMcö~eÙàOsUÖªòsdWý™Öç^ÉN-÷'½FøT€À§¼AXC9²¼ôâÈÄS±îKyo ôÈ ÉD=Àäëëx=Яýf;K|ò²ªeÖ°•‘µ¥…P8¹JÀ$ViB@Wó~cé`=ÿËí-N~{-®+ ¾™ ppÎ2¿uŸþ"€´ Ð ƒ· ½@qý¸ÈDõÍyÑïDIOô8Ҝџ1¦Vf­•ÃG×é½úb¶³$WÀ<½`D^ad=}Ü;ŸS×”)Ëw$K·—%Û&èë)«ïñéç¼ñ¾@“&lß+¾J†w[,‡özTÒR¼ßizˆ °Ÿ €ýHØ€í ˜KJ×Tœ¥œš«Å8âkÏÊ+Ÿ™{ò§ª“YÕÊ ]ÍÏìf¯tÏýÈNoYCõj]Íb®XŸöMY²uœ,]Ÿ#Ktݸ‹[xüðeØR3KÌ“Zëûo镱Ù]¦ €­H´Âà-´/PÝ4@Þ/ù¢T4m¿ ŸºZÀÜwÞr°?SøÍ¥ýæÑy,Þ0W ŒP-ãF”Éü9e‘Ž™ —nØ 0¯Ëó³ôQ‡$ù¼3êŸõÄ<.ðÍ›äàÜçdlîKšÊåVÏtx‡x[€€·Ç—Þ!à@@Ìc¥V–¯ý¥;T'ÕØ"‘–9×È ‡VË «eÌ€.ç·epG¿žA9cZed5ÍÖ5¦È[ŸäÈË÷е»l.â GÜ› KŠ^Íu¦N8^¨¦•ƽM@H¾ €ä `µ@0œ)ËJ.‘µ‡Y'ÁÅ&`fâ?ÑðZ%G«õÍ£÷bSòwisëlj“ª#«‘ؤ·˜DÀ+šxã“nÒÐÄÕ^ø†”6Œ‘……·Êa}þ-²wß"â…~Ñ@¶H´íÂVPê`y·è©jˆ‡Ë²ÒC2çZ=诊œå7 b0ß™kæ–FÖú¦y{mŽ&4!°²»¬/ÌŒ¥*ÊZ&ÐÊ–%E×ê-Ï˸Üô–nù±lˆpL€€c”T„€· ë&Gfù†²¼Õ1õf`^PÎ:¬RNž\%³ÇÖHf:ÔûhøãÚU“Pš«·‹˜õ§ÚR¾Þ`Ͻ’7Ö Ò[…RâÚ>•ÇC ŸTœ.å#ôj€{%=¥6P' €@’H$yhÛ"÷…–Ÿ!ë*O¶-4â‰BÀÜÇ}öôJ9ïðŠÈŒý)\¥…Eº*0¢_£\y\©\yØÛR²å5yfíly|õ1òVþ$=—Ì—°«¾‰ÜgÝDYTø-9¢ß?¤gúöD6Ýå¶ O™wßÅãç ¢ªl÷ÒæWæß¸úÊæ‰/”|Ao )ò—”@³í! €@$¢@¢ˆÌQƒoúÙ!%U²½Üÿ­53eyéE óO‚Íãlî»6—÷Ÿ?£BŽÑƒ~óø>Ü"0¨G‰\wÄ“‘ukEyú“9òðÇseå®Qné‚/ãÜXu¬&†Êá}ï–¬ÔJ_Ði@ÀKüµï¥Ñ¤/Ä(`ø?.»@6W›‹­“†×ËåG—Ézàß3›³p¶ŽqE/0,w—Ü0c\?ãqYV0Vî]~Š,Xu¬Ô4z:×=e%Í£Þ¢I€HïÌM–EG8 €±ˆE‹²xH ®9OÞ+¾JÊFz¨WÞéJ÷¬Pä€ßøOQçŽÑZ ˜ÇÍM´6²þxî?"Þ·ìTù `\«R¼µA ¾¹§¼µóërh¯ÇdT74$®@²a\ˆˆU€@¬b”GÀe £ô~ÿk¤¡Ùs"¹kÀ]'óõ ÿ\Å¿[fÈ]Á-]èž¡ßý)/FÖõ¶“xdåñRÙЭ µ²«“æ)1•}^o ®þ‡yœÄ¥.@ A$M3Ø"°£vjdb'î÷·eDDruB¿ gUDü' ©·'0"A I‡öß$¿<ùÏòÃãï–§ÖÍ•ûV])‹×3Áy’†c¿fͼ1uͽå½% =¥v¿ÏÙ€ `¯ {džÈpX ë+çʪòs®—ê:+0qh½\R‰ží¯3Á ì-Þ ó&½.óÎ<^ÖdÊ?ö–ÞÌ“ú&ó€–d ו7wÞ$3ûýYrÒJ“ m#€Ä @ ,Š"àVÈe›¥Ÿg²?KpîÄjùòÉÅ‘™üK‚" ,7¨A~yqÜrö.ù—&þþjo)®âϘd[UÓ@ycç75 ðWÉËÈOf(´ ¥¿9£„¢n†2åý’+dgÝD·vÁq§§†ås3+"gü¹ÌßCJ'’$л[³Ü|F‘|E“hÿ]’'wý¯¬+ÌLR44kæ’ykç×dzß{d`ö @@, `ù]¨×™þ—]+ú g–ä˜ûû¿xL™\3·Dæ“­"àAÌô°ÌŸS&—U&¯|ÜCîÔDÀ[Ÿ0a`2†º9œ.K‹®Ö',Ñ=&#ÚDˆR€@”PCÀm•MCdÉ®ët¢¦<·…î‰x‡÷i’ëôþ~spÂlþžR:a©@ŠÞFsÒ¤ªÈº,?[þ¤‰€§Þï)Í!î¯Iìäã² ¤6ØW&j" Ìk’XZC¢ ¥p•À®úñò^ñUb.ÿgI¬€™Øï¦Ó‹äÌê$-…çd'VŸÖü.0uDüýšmòƒóÓå//÷‘½Þ[ƒ$ù½ØXu¬&zGn H 4&²iÚBˆB€@HAÀMùÕ³eEé<1ÿ±$N`\ÿ¹õ¤7åÌC×ê³±õÀ¿7ñµÝÿ lŸ¦@ zsEÀï.ß!K~¼^æY®WéD¿/%;/P§·¼¹óRÚ0ºó•°' €€£$å¤2/ §éýþWʶš‰o܇-îQ,¿=õNYü¥/É%“_Òûü›}¨@—p§ÀÈ~ò§+¶Ë[?Z/çQ!qȦP¶¼³ëËR\pÜÛ¢@ŽHtlD ¬hg裗®‘‚Ú)ÖÆè•Àúu+—ŸøWy÷Úkä SŸ—ŒTé畱¥þ;°!2Yàë?Ø gLãõxÌïªÅE×ÉκCãÝõ#€t Àñ1¶ ˜þ—èT% Ù¢'âê–Q'ߘý°|iúS’Þà‰>Ñ Ø-0aH½üûú­²bK–|ÿ‘òÖ'Ý ‰“€¹ZÍ$¬§÷ý· Îù N­P- €@G$:âs,h åÈâ]7HYã £óFH}Ž‚¹Äÿ{ÇÞ+ý»•y£SôÚ˜<¼^žøÆfyöÞrÛ£$¿8£Írl욀™¯æýâ/JsŸtÖmI×*co@N è;!<†æòNÑ—¥²qHò‚ðxË3‡®Š\î?eàz÷”î!€@‹€™àÌÃ*å¤IUòç—ûÈíÏõ“Úî”lñqêÕ<±ÆLZk®bÕc‘SÕRÏn“ï»cüßâ€qÓüW×Ä¡^ªD$H:M"ÐYúæùOrêØ%Þê½AëÌ$çL¯”c©‘>:@x«—u1º- õ•'JZ ^Æå¾è¶Ð‰°Z€+¬‚ó“@Cs½çÿF© öñS·ãÒ×+{VÞ¾ú:þã¢K¥ p ^Ýšå_Ø! ¾±YFôkÝ›åß×o‘ûßì%ß}x Ô5rþ%ÖKм_r…ÌHù›ôÏZëî”GØ#@€¯IØý‡ÌeWý„$´îþ&ÓRÂòswÉWNJjÊ|÷wˆ €€çÌ“æ]&GŽ­•kÿ9D–çg{¾ÏNw0N•¥EWË‘ýï’>™ë®žúâ$Ðgè³™Zµ9Ûa2õ-«™ôÈ-ÏyÌÒXݰŒUë;ܨÆhî‹*Ôuûžu›¾n(ÙvFH_Yâ,@ ÎÀTÀ¾aý}÷aÉe\ʸ/L”?îß(»f›LÁåþQ’Q ,8h`ƒ<Ë&ùåSýå/ö•pØ¢à\J(œ®óæ\'³Ü!yù.ˆØŸ!êhŽöüT]/ÐõL]¹©8-–](뀀Œ]¯Õ<ª+à8àI Ô‹ô{w|‡%)Ю €vyø® ˜ƒþ%E×I]s^×*òÑÞó‚òÔ·6˕ǕŠ9+Æ‚øI`P^“<õÍM‘ýÔï®öÕ$ÖîšÑÕjØ?J=û¶½KW~SGiF1GÌ„’/è÷ÏWìŒüíêm‘°Í½ÿ, €Ÿ Lnž„²AN˜XýÙFÞP ¾!KþöÈÕRYÓã€eø sz°e.÷ÿ‡®\ÚØ9BörVÀÌp‹³Uú£6þgz™@‚Ú©²²ü¼¶èÞ¦ÌY­¿³IΟQáÞN9 g^ÝšåÁ·ÈM§Ź%oT_ZÙKþþè•ÒØd®fqPàt­‹?p¥ª. üHSú\‹Ï* à³§»ñ(k©÷ý_ßFGØ_àØñ5òœN8¤7“÷–—Ï•kÝ{#?uFà¦ÎìÄ>$@ WÛ¸"íx¦®û˜ã@IDAT žJ:’LË.sù?ËRtê _\\ ?¾°PÌ¥¬, €?¤Aþ§·QMÖIYÚxàÙ‹egIÿö ñéVm8$S?¼è€øä pÿm c@ ,Š"ЖÀÖš™ÌøßL«mf¦ÿûnØ"W_Új+o@º"0 7(Ok“œ<¹ª+Õx~߆ÆL¹ûñ/ˆye‰]àÙE§™K(˜Q1v:öHœÀ½ +q͹»%î?¢O²@EãPY^:/ÉQØÝ|ÿžAyæ[›å”)üj÷H¸Q [¦I°n•«H°¶;|;KȃÏÍ“°˜'Ù±Ä"PQ;=–ò”E f®iIhוM’på°´ ¡nzßÿ5Lú×Î`2¸!2Óÿ”uí”â#@®˜Ûª~qÑî[¬ßrù'“åµ%Çðs>h[@¯œ8¬íOØŠ€U3¬ŠÆâ`HX<8„f¯@XRäƒâ/Hm°·½A&9²£©‘g¿½I†õa’ª$Í#€€Ì¿™dõ_×n•Œ4æY9Ð?ýú².ÿ }Ìö6š›S'·±™MØ&ÀQŽ €(¡(†@kOÊO—]õã[oâ}+Sõrÿ‡nÌ—ÜœæV[y‹ o3«”‡¿š/9zkËþáp@îyr¾”Wæíÿ![ÚÐt÷ÿ·)ÃF˘ ÊI‹²Å@`@aÝdY[y 8ïˆ ¹ëÊ풞Ũ‚¿Š+P›p¡@#DòŽwaà‡Ü¬·mý•ÅÚÚÑÝD»ä ™÷à7¥²!Û¾“QM]7¹û‰Ëå«—Þ%i©Á$GCó €@bH$Ö›Ö\.Pì/”Ìwy/âþ¥G•Éíó ¢Ì_S™&x2@üF„š.Ð\“ð&½ß &›Š½ßM‡{xÄ€byò’[äsýDJêz:\»û«ÛR0\¼|®\xÊ£îï =@bà€°(êo`8SÞ-ºF‚!®0jë›ð¥¹%ò»ËwDðßV%lCpL`Ò€ òÔ¥·È€î$ZÛB}{Ù,Y¼‚yÃÚ²axW€€wÇ–ž9(`´¼ä©jè`­Þ©ê¦Ó‹ä§ó %…Ù§½3¨ô €(¡(æOçÞ8U¶íâÏÎ ×æàÿÏWn“Ëæè þ, €®è]%_ü]9|ðWň`ÿûÂ礬2/M¹ª‹Nû¯¹·z½«‚&X¿ ¼Z²íŒ(ž?í7–¶ûK m¶" ëò’W—‡Ä>¿›¿C>7³bŸ­üˆ à™µòÐ…·É¡6º%ä„ÄY×- €@k[¹_.˜°°õ&ß¾_½ñù`ÕTßöÿ@׃²&]ïÐÏÇêz—®¤‹í±˜¹&nÕu‚~¿וËScÑk§, €vpøÈÛ¯,9^ Šy»“QôÎÌòÿk¶ÉÔÌúE@_ 4M~Ç¿3/‹È‚—Ï•šºnP´! hź~Y?š¤ë¯te’À6œØÔ¡À{Zâ;ºŽÓïÓ/uå’ÿÉb+[qJ#à %ýåÅ·OòFgºØ‹Ÿ]T fÖÿ¤,¹zûE¨>)MÓ(R¹X¤™y„ý&déu²£URYò24„{¯|KN»kˆ¬/ò÷}ðæàÿñWΖËÎüOòÆÒô€m•†vKŸ¡Ïš³·“u½@×éºÙ³öÕWÌ•"…ºîÐu»®¯ëº@¿?ùúÊGqÄ¥j;Ìlÿë¥ÿæ¿/×X"W_š<“`A Yµú7* gõMÀ¬,žè¥Çý½XNþE)©ò÷Ÿï­œ.Ó'|(ãG¯ñÜ8;Ù!=3—l/ß³~Zµ&2õ‡~ººeB“Ðèþiì}ó¶†v‘½áíYP*ÒïˆyeI°€¿ÿO06ÍÙ!ðö²Y²qÛ(;‚Ib§O­’}ÎLàË‚ €@Ç#ú5ʃ_Ù"gÿf”44¹åØ­ã~u¦„™ð–«~#™\«Ÿô´m±î—¬òš°pËœ j»5YN´ëæpÏX©U¹òÔÂ3¨ÉÝULY'½z›¤¦0ŸŠ»G’è@Ä LU'¹j›ü}üy$ yŒ0  à6n1âí´€ytÏ#ÿ;_Í•gþ]†ëLÿæ Ž™ùŸ@XÎ:¬R¯ 3·îú{16fAÜ$@ÀM£E¬]X¾f²|¼~b—êpûÎæ ÿ~=øïד[®Ü>–Ä$SàzCæâÙþ~ì»9±ðÐ 2§P2¿ˆ´1 ˆ™ŒÜ(P[Ÿ#¾tžCw4æ?\¾C& aÖ}GQ© ð¡€¹à×—ÈäáþþRP4PÌc…Y@·pËHg—ž|íL©®uî]êf»;_{B‰œ?£¢Ý2|ˆ €@´Yé!¹çú-Ò«[s´»x²œy¬°y¼0  àn%bì’À¦m#eÉŠ]ªÃí;Ï[+?dÆ·#ñ#€Ö ˜yeþv¿'4~ô¥óÅÜÀ‚Ø.@Àö"¾. „ÃYðʹ]ªÃí;È ÊÝ×n•ôTfüwûX? `£Àñªå»çì²1´„Å´.ÿ ùx¿çJ6 !€@—Ht‰mx÷ãÃekáPÛÃŒ[|æ ÿ_×m•þLú7c*FùÚiErÚÔ*_S<ùêYlNóµGûHØ?FDØIó¸¿g^?½“{{c·Ÿ\X(3ÆÔz£3ô@ÀZ½úýOWl—1­1Þ—÷‘×ß;:ÞÍP? Ð%]âcg›^z穬éasˆqíÂYåråq¥qmƒÊ@hè™Ý,÷Þ°Er2C-›|÷ú¿·Oôõß¾p:Œ€ H¸pйcÍ¿öî±ôh‰‰Cëå·—ˆyL  €‰8xPƒÜñÅí‰jκvÌÕ‡Ï.:ͺ¸h Ð"Á«§Ìcÿ̬¼~\rsô Ìõ[%;ÿg`ü8îô°Eàœé•rÃI%¶„“ð8–®8B¶í’ðviˆF€@4J”q•Àº-ÉŠµ“\³“Áþþò2¢ŸïÁtÒ’º@:'ðýówÊ´‘uÛÙå{™Ç.xù\ èòq$|¼*@À«#ëÓ~…Â)òøËçø´÷"—Í)“³«ômÿé8 €€æ)4½z›oçظm”,[=ÅŽÁ @ • €V¼u¿Àâå3eGÑ ÷w¤=Õ¿Q~:¯°{²  €Î ŒÖßK?¿È¿¿—žZx¦4Ó‡¥F@  $º€Ç®v Ô5dëÄ;§ÚT‚¢IK ËßôLK7ϼœ jšAˆAà’Ùþ½2­¬2O^]z\ ZEâ/@ þÆ´ ß:Ijêº%¨5»š¹åì"ßÞki×H  €@kó4šÛçïAyM­7ûæý+‹çJyU®oúKG@À~öF!°«´Ÿ,zN%½WäȱµòÕS‹½×1z„ à ^Ýšå®+·ûòÑ´MéòôÂ3<1Žt¼!ænÐ ¿ ˜_®¡ÿòY=³ƒòçË—Ij°Þï_úïe€>Ò3½¯—{˜œ¾ËDs’Ó6­úNàèÑ"_>!Eî|y¸ïúþþªÃä¸#Þa·ú®ïtì `ߘQŒ[ ‡ÉGëq/oÿíÉ¿•¡5‹Dj¼Ñz@›é½E†ÝÚæGlì‚À®‡º°3»"»Àw§¥ËëýV>Ú9&ö]¾Çsoœ"×~þ.ïá#€€üwÊÔ £Fö0¿Tý¸Ì;ô9o¼ü³ € àŒÔ&ùëÙ¿–¬´FDëlˆ«7"›·p¶RjC:!@ hìb€ùej~©úm‘·S~qÒ_üÖmú‹ àrq}¶ÊONø»Ë{ѹðŸ{ßO*êœ{!€@¼HÄK–z"à×_¦wžq»ôȬMˆ1 € à¤À¦=/sG}àd•®¨kmþXY¿Õ·?¸bp ðÑ`{­«æ—¨ùeê·å‹Óž“#‡}ì·nÓ_@$,¿9õNÉNoðH¢ïÆs‹NÕÞë³Y@$ H<ÍvMÀüò4¿Dý¶ ì^*?8î¿u›þ"€xL`xîNùÞ1ÿöX¯:îÎÆm£dífÿ¼èX† (ž(iÚqTà“McÅüõÛòëSþ$=3™òßoãN@/ \søÓòتãäÂq^ìÞûô¬žÀ7ržÊ°L>x» ûh׿}ÀvpŸ ÷™ï#Žœý÷áD:gò¦œ6v±ïÇ@o¤BòûÓþ('Üó †R½Ñ©(z±¥`¸¬Ú0^&ŽYE阊üoþ«ýùh¤˜˜(Œ€¿¸ÀßãïÊÞ›_šæ—§Ÿ–ܬfý÷Ó€ÓW@À'ûo’¯ÎzÔ'½ý¬›Ïë#Œ™ à3Þ!€@⸠qÖ‰jé m(ÃáÆ~¢õãpªÎü²4¿4ý¶ü¿¹ÿþÝÊüÖmú‹ à›g?$O­9JÖ—õAowwqÛÎ!òÑÚCeò¸|Óg:Šv°c‹B/ýZëXe{*ºïŽñfÊy+æ—¥ù¥é§åèËå’É/ù©ËôÕ-šsúp«Hm“HCp÷Ô;AGö™õE‹ÓX­TèŒðæÙó\ŽQpí.’ªg‡ÞuñÖÿôì2Yš¿°õ¦¤¾7‰ˆo¿8FžøÎÙIƒÆÝ#pìœúþyaÝL÷Ý…Hßøà(™;s¡¤§1iJÙÚ Ð%O J‘…>šüoÞ‘å2ml77+ ÎWÖÈÿ»Ô™Ê¬å±e"/®9e¼ƒ•z¹ª€Þ•1(æUÔÈÿ=ðvÌûÅ{‡§–n”WW×ÊÜ)câÝõ{A ’ÿ7÷òʆéÒòþŸ­æ€w?ž.³§.öÂèѰP€[,BY¾v’”VôöENfH¾ÞN_ô•N&VàO¼)5vÎ)ñÃ>Š0±êö´öÛ¯KuÏ_üáÿ³ŠH¬Ýk‡|鈧¬Ó©_{÷X½m‹ù2œò¤Ø[€ÀÞüd€™ ÷µ¥ÇYIbBøÚ©Å20/˜˜ÆhÅ7a½éÿ‘7WXÛß%›w_`m€.Ìœý¿óiûÎþ·°¾¹r³”úço-ýæµó7Ï~HúäTt¾íi¸rÃEL¨ à&n-ŸÄºqë(ÙR0̽íÛ#(ןX⋾ÒÉÄ ¬ÞºKÖn/Nl£1¶ö£ç활0ÆÐ­/nÎþ×6Ø}ñהּޑíè™Y#_?ò¿öçH^[zlœ[ zð« ¿Ž¼ÅýöÓ/½¯V,æœXð¶>sÏò…«â3@¶Ÿýoéõã.øŽ¶ÄÊ«WL{Nv/µ#˜8G±aëh=2<έP=øQ€€GÝâ>—Wæùæ²7sÙÿÇ–Y<„æfçÞ]ãŠð¹ ÀùarÃÙÓë×Vlšz;ç(p~T¨Ñ ¬´F¹iöÃNTåŠ:üô(dW A"àH¯tcñG3|3ñÍ7N/’¬tÎþ{å»k[?6ºã,W8ûÍqËÙÓëæPH¶—T: @mž˜?åEÚ³Èóý4\òÑáu¬žb&0—D³^föcAÚðþóTÚë=ŸY% §Èâ3¬Š)^Á íÝ$—Íáì¼|ý^oS°Yvé$pnYÌU§Œ×é?™ôºËCæ–³ÿ-Ý^R!ã†ômù‘W:ÈHm’›úÜôüW;,ëþì{Ÿšìïîzè/îï =@[HØ2vÇñz"Â{ã½£Æè-%¢­d·qó™E’‘Nv´ïQ²*½’Æ=߯–«NeÒë.}#Ýtö¿¥£;¸ …‚×.šôŠüþ %¿|` {¹¶è59 ×#`Ÿ ûÆÄºˆæß¸ú% ʬq]ú ýÍ‚¸6`Iå#û5ÊEG–[ axQ`G©û.«æ*€®Ývößô˜[º>î~¬!=%(·Ìy@nxæf?tÿ°>CŸ=¬dÛø¡³ôâ/Àñ7¦…(ô—›IãŸEQ×ùöYE’žêž³³®÷aꃮëuËU® Ü’€ÝxößÐÕ5Úý¨BK†—0Ú¸`âBÛg[Ÿxr“¹ €pD€€#ŒTâ€ÀµÏ_‘2v`ƒ\0£Â.ª@À{< ócêÆ³ÿï-{" ’É·õ*Ÿ,—ꉒn>é+ÝD8 ˆ30Õw, ¿ÔÌ÷ðêŽKº¿„9ûŸšÂÙ÷$=ˆ‡WtNÕ­gÿ;×[öBà3syC&ôÛüÙï¾ë¡]»Ð»Ý£g H‰Ô¦­ §Œ9Ї^Ù>aH½œs8gÿ½2žô#>\»+gÿc7co¤ÂrëÑ÷{£3÷‚Û:6¢D!@ $ŠÄ]À¿Ôn:½XRxÌYÜ¿L4àn®ˆmü8û›¥½'pÚ¸Årpß-ÞëØþ=:R¯˜œ¸ÿf¶ €± ˆÍ‹Ò è/3óèó®Öºê†ön’³¦»ofvë È\ý0sö?z+JzS a¹aÆãÞìÜþ½òÅ “ý»ÍpR€€“šÔÕùºSFgvtÓ>מX"iÜûï¦!#Ö$ p@tøœýΉRÞøüÄ×þ?{÷fUu.þÿ=Ó;à C*Š-j¬1‰-1õ¦èÿ&¹IÌÍÍÏon’“xõÆK[ì ;b ]iÒ†>LŸó_{”pÊ)»­w}÷óeÎÙ{­÷ý¬ sλ×Y[jJ¸½îEæÂI‘þ%CR€@º´Ý¥€ù%æMˆW_Í®(n•‹&nêÒ‚@`wfìîÑÑO\ýïH…ç\(Èm–o{Ô…Ô«L’g¹(9"€@p‚³¥åîŽ0»Œê~7»÷øêÑ›¤¬¨Íî$ˆ˜Ð58Wÿ»öáU÷.ó„ç7º¸ú '. "9"¥€(õéû«Ú ¼iÿßž¼Q{šä‡@ Ì蜕«ÿÛðŠ›=‹¶É…£Ÿq!ùcÍ ÊÁ.$JŽ Œ@^0ÍÒ*] ˜_^ùfõ‹ÿ=a‹ô«lîCÛ«õˆ4.×–•]ùl×QtÚ9 àäƒ,â÷ÎýÍÓ xýÖ&¹öÑWí#´Æ–îZ.j;2׊*µ"»ïŒXn~ë4iKzß0T½k²»Ju†$‡ PŒ–†»8μ^ÝÍ>Ö¿ü½k­Ï!íêš7ô/¦}ø(Ð~à o€½Y'±&›†å"Þ#ÀíªG²£)ÀÂlÚ+n4¶ø $Ì[EK C*×Êiû¾*.˜_O"û’i†€?–´‚€s|À¹!MÂÞ//ÕÛ¤ý¶ËTçHr-Ð> `žc³hº@]¿]äÚ—ºØ—p\àûtA`¼™I9Ü…DÉü à¿)-v#`~iy·ýS¿Ší÷]¼úßÍØó2™\ñxƒ$“ÉLUwÌUÓ]ýW7:$Cú/”ÃÎC(AÇà} € H[€@ÚdàƒÀ ¦JÚ‰mû hI£Ì¥:6ÈZà¥-òô[‹²nÇö¸úoûXß›ðPX]EÙú™”QâÒ7š(hÝøæ¦þ—Öwޝ•„5_ZŽï‰Bdì¸âÎ真ÀÕÿgÿG k“ö~C†V®éz'û_cfTîmd€a P[ÜñþÌ/«"Cp¦f†ŠâV9k|û*lšÓ$7Bxcá §gpõ?ÔÓÎ,ÈM´ÉW~Êò,R _ý•”Ø Ò ;û p’i£Ü‡vbÛÄÝ"Åm±À°UÀåY\ý·õ¬%î¨Î;ð9ÉËiªû°úýbXÑè  g,mÉD}µú+Gm²e,ˆ«\ÀÕ«NS‚‰@Méf9Ù|@ùv ™Y9Jyޤ‡> Pð”æ:0¿¤JÌ«§w¾‡ý¯<¤^Ä­ÿìI2ˆ«€‹³¸ú׳‘¸â.pÑA| îcD| ¾€ðÍ]îñs&ùRÍ\ý×<ºä×fpõ?g1Ø*0iØÛ2°b½­á§÷Í–NU‹ý@@(p„) zúIa›œ=aK˜žô…€“.Íàê¿“§8Iû$à-xÁAOûÔZl›ñ¾p@l£#0ˆ€Ø ‰Î€LuºÌdvšÎì>Éêìñ[¤¬ˆÅÿ41¹ÅCÀ•Y\ýÇùFv \0úYÉI$íN¢ûèU_`é>}ö@t(¤£Å¾Ùœj.Φ¸{‹ÿÅ}ˆˆO‘€ ³¸ú¯è„%•Èú—oÉÃgGÖHó5€ é 4Œ¢9¨¾ú¿ß€;´ÞŽ‘ JhŸÀÕ'))ÄFà+«_ poƒí=Ø@n(tKÄÙ ˜éÿÞyvR¶íÄùxïê‚%xâGh¬´ÌàêV§#ЭÀé#_évËw `ù>aä…Ñ }8- ú—Ñ™ã˜þÊÙÈÉëJW*:Ék1ilS‘JªIx³N»¹G·ãðΩ¶©vø~WM¯—M ÷«rJDò½™ËlñÐóVqPu2®ÿ™½zd|¹³‹l„™y9¢vå©d× G#€€f=ÿªk%KsûôöjW¥õþ;zT¥£cYØ}Eü«eAGîæ%¦ó" ü®wÎ8ù}Sï¼ÏWSß7à=×o©“k_ümÀ½Ä°ùEÃÀI«À™ækŠ Þ°yï»®Õ:~ä…Ù ¨š= -ø pi£íIJ‰ÓÆneú,G† \°y-€«|Qv46»:tä@hgð5€Ð¬éâ)@ žã¢%*ÕÓÿÏ·UË8‘*vΰ-™ö«ÿ½f[ØÄ‹€•ýÊkå°s­Œ=Å 530ù^MŠX솀‹\õðrV[¨.k•£F2ý?¼S‰žHMÀÆY\ýOmlÙ ¿Îõ²_MűbÔ1q Œ˜@ â1ê¢0ÕçJ“Ôáêû4!oú^«ÿk_ò²WÀ¶Y\ý·÷\#r{¼»¤³^¨…™ª]ɱ db'@ vC¢& oU'³t»ÎÕÿuŽ+Yé°iWÿuœsda—@ïÒMrÄ^ëì :½hÕÎÀL½@ # ©ðœj«Ï5-rÄ>ñ¹u˜ƒEh°eWÿ5uäb›ÀYcVØr:ñîkfbMçöEw(¸3Öagzt؆Õßic¶J.ÓÿÃâ¦2°aWÿ3ZBÀÏþHû×Ô¾óå  àðà•º©:÷6mïTûQ·{âèíQ‡@ÿ Ð@Ügpõ¿›äe¨.k”±Cëî%ÒæŒ´w:GØ PˆíÐXØVGßEðyI™¸/«ÿwAÄKÄF γ¸ú›Ó„@˜|À6ÍÙSÐ<ºä†@yYË¡t& ö—ΑûÔIqA[gyò|ýb‘ÆU]ï“î«y"ecÓ=ŠýpZ`ç,€“Ù7V\ýÕpŒÃǰ]®|Ì›´¨rÛßÌÈìY»òÔM*³#)ÈX€@ÆtØ…€ÚÀqæÍB·ÛŽù"[^év·´v(B -0vFàoÀIc÷1ßõMĆ„«ÿ± q\à ! RUÚ*ëÔÞ´È»óŽ3é#€À|`~ÌNÀT›‹L ‡d×J|ö®°!€€=;gÄ%b®þÇe$ˆs¯b³ ï±û«þ½®ö‚ ç/d.@ s;ŽìX`œyº ã—ì~vpu³ŒèÓhwD€ƒqZ €«ÿž€¤kå…} ±>ûh(D㮹׉Z“ó ŠÑ,b­Ìä…€ïq™ÀÕ߇–ÈZà83@ñïöCÍÌL•e²x@Àa ~@©«­6Ofú@§ Í"¼@fpõ?øq¦Ò¨.o‘ƒ«½ ÷µÌ1éš°?è  {|CÍÎT™½óIå-½Ûÿ5’Ûÿ…zBÑ> D= €«ÿ>&M!à³_ð”æ@ Öb=<ÖçÝk«Êº¨Sø°;¤´°›Ûÿ¥Ð» €@tQÎàêtãNÏt'0ù@ìΈ×@@=c‡LÔNÿ?þÀmqð%ÈB ªY\ýÏbÐ8Æ­—žæv€J·#Í ÍøÜU)2i!`“›F+þ±ª-x‹±!€€ýQÌàê¿ýç èðn8i?µ¿çû˜Ñ®{ÉÒ Žûv' ²à-´o?nÿ×Ýàó:6„= €«ÿ6œĈ€ÈÄ}U¯ó£òýç-d&@ 37ŽÚCÀL/ëmžÚ{§Uüè}ÿ_ñ-‚TŒI Ž@˜³¸úŸÎȰ/Ñ j~×+ÞÔÞ¢Yñ˜‘ PŒÖ¹†ÇjÍXù›­ÃF^t*Ö,®þw:¼€@ìö13ýz”¨]@í{´ØH„€,$KB<Ð’8ÓsÂ^ª¯ ¤íÁhcWÿ5œ)äàŠ@ŽY&oü^õZÓÝßÌÔÌÕšy!€@zÒóbïÎFwþ’½¯æ'eôà{ rèP èY\ýï'ˆµÀ¡z þE~D¬ñ B µúŽTƘ[ä%Õ "à¢@³¸úïâEζ (ÿÊŸÊ÷i¶ŸsÄ@¢PWÖ§™VV`R¥,­öt_ Ð8\ä„@ZAÍàêZÃÀÎÄFÀ+úç™[*Ý((XÒB ] 銱Gûš'ó;zÁöç”_ °}xˆ¬‚˜ÀÕÿ¬‡…ˆD ¸ MFQûµ?µk5Er²Ð) P°xðbºÚ_*ãõ~0F§¡ €ß³¸úÝXÒ3~x·þUº1@éÀ’é PHWŒý;PùKe_sK ž¥jo ÔÑ8òN ø9 €«ÿNžB$­H@ñ†™¯l–+*RA (dÇa» ¨,LÐ{`·Áã\ðkWÿ]?“È_ƒ€ò¯þ aŒÈ²ÈËîpŽvE`Ê5£ŠM®½;Ê÷‡W¶I&õÕ’”¿ èh(yg¼Y'ÝG s3ð 7®þgÇaÄH ¦¢E†Ö4ɲõÞúÆê6ï‚Íëê²"!HK@ß§¶´Ògç4&š}—íùØÑP²Ì|øï›F;Öì:~¸ÚïZ3Š@XÙÎàêX#E?/ øk*glFк(èÏгY½¾_è}†ÑaIa› ëÝFWô1Èf-®þÇd ¤öN|8?hÛ(Ø>‚Ç¿zÎÀ~%'ó™À Ý#€@&™Îàê&Úƒ@|ö¨¶p Yw7ñ=õˆ P(„¬·­3F PûË_ïÉHfø É,®þûOÄHÀ» tëaò¤47ÒB(¤Ån h ¸úßñ@ò,´ ¤; €«ÿœ8èðìUÞ¢/±O2âkZG–¼HQ€@ŠPìöY¤$dí•ëÿ €ÏŽ7Ï àŠ@:³¸úïÊYAž® ì?Pí,nèÚÉL¾ì!@`~L] nG©45«¼MŽŒÒ;ý/õfOHuWÿ=AHÛ Å†:1€$‰ P蔆ºظ¥ª»]¬|}@U³T–´Z;A#€€?©Ìàê¿?Ö´‚@öÓ»à°8z„'@ ýˆ@òmÆU Ô*ý €âïý©>3JnÛ,‘¶úŒõAÛkcž-Áíœpò!ûî2WÿwãÈå"[^Ê® ŽŽ@~o‘’‘ñ‰'‹H ó“2¢o£,ZS˜E+±<Ô[¼©Ÿy¬Šet… PœXoZ×Pü½?½'c¦™mž.Ò¼!Ó£ã{ÜV/´D|ã³(2oÀIc÷‘D⟞\ý÷qëŠÔš›²1j Þ€x¼Ô†šO‚ ˜äà û•²ÆyIÙ«O“_D´ƒ– 윰3 ®þï”àÿèØOï†é=2DÎ(t&Ãó] $“ Ù¤pÀ}%?7Ùen ìºWÿÝ{²u[`dÿ­Cµ&F^ н€îØ£­uåÒÒªï$Cjš;È–§@Àe³¸úïòY@î. (~OÀ OhrFàS}ŸàÚP´~ÿp5ÓÿC9è˼YG0Lv4R$´l茿' ñYÁØ/@Àþ1Œ$µ€^¼¹ä„¢Sb.à͘½xeÌ£$<ðS ¬¨MªJ[ec]®ŸÍÆ¡­¡q‚@ ¾»õ½Ön®²>‡ŽP\íï(]žC4ZÛÚÒØ›]@@ƒÀ ^*g®8•‹€NPr@ þòg€Æ!"Ìà,@@íCÌÌÀw–kK3÷¬ÉL>fܨ5Ý$ÖpÑ¥óu³/#€€e,°¸„«ñ€ží`•þ¸œ6Ä €€Uƒ”® 4 ÷ê§Rˆ÷Ì>£SØ]@À"¾`Ñ`Å)Ô oØÓ|ϯÜ|ß @ð¼7­395Ž9!à·3üA{S®õ&ŒÓ|å°í%%![¶õØù£šÿsõ_ÍP’ €¾h}o°Yáû8_œFp@€€ÎAnÒúÇv¿Slj*–V}§ÎàjU~¿ÇŸö@pE@ë{ƒºúRW†<@`¾°?v/ õ—†Ö*÷#Ê € БÀ`¥_¨«/é(]žC(80È~§¨õ—†Ö*¿ßãO{ €¸"P”ß&5-êÒÕz1GÝ@‘PU{“Zi áÚO]òC@ m j}/—öàr PppгMYë €U¬í¹Áñ¤+0¬:Ý#Ø¿;ὺۃ×@ ·Ôú^.qe_\ àêÈg‘·ÖªqMEk*Š™|㈤ô.ÏäHŽéLàç'%;{‰ç@ ê2}ï´¾—Ë`x9ç(87äÙ'¬õ—Fe©¾_ðÙ6- ¬@I¾ÈOç«_ʧ(2v _­ÑxU EÒÚ–Ë#€€ƒôlSÖ8m¬GI«äåð!$ÛsƒãÈDà;…Y™ÀupÌåŸãß±Xx ¬ªÊô-èìàNYŒ€­l¹ãÖ8 'Wÿ#<£èÚu’føq´_ýäGK´» T)} ñýÜ®ãÆŸ@ c¼ŽŸæY:Ðø Cã÷û:A^ T Ç|šMÚE·çx_gÙÑín±Ø!ÇXåÈwŽIÊ•ÏÕɺm\ÁÎt\¬¼úïý]1ãÏ@›ù7"©óʶߚ¿àiœÑé÷ØÓ(hÕ€sªÛQpá7ßSá÷ûÂW¤Çv“Dz-ÆÖ%¦ÿ¢!ÕÞ«N2QJÌþ?ýÒËòã›OõHöÛEÀÚ«ÿ•G›ñøïË.ŽNýqí­¦N8ß©”3MVëW4^ÐÉtŒ9—ø €K£íS®u Þ[u][µÒï÷é%²Ñ.ðS“Þ•eÚÓ $?+¯þ"A£ø/À ÿMi¢ ½µ=kœ õû}Öždî¤@Ia¾üô “œÌ=›¤­½úŸMÒ‹@ˆZß#0 Ä“ˆ®ˆ‘€ † ¡45çKs‹¹o—²Mku_Ù0‘ŽÌH¹úŸ¾G Ž@qA›æë[Ÿ„@:gû" G€€ž± %“õú¾ÿïÁiý~_(' ࣳÒÃäêz^ì@&‰„yŸPªoÁD3:3_ŽAÀ5 ®x–ù64E¼ºy–ñwv83:“áyÂ`@êæ\ýOÝŠ=ÈF@ãû­ïé²gŽEÀ .Œ²9¶´æúØZ|šÒúý¾ø © 0 5+®þ§æÄ^ø! ± õ=ãMh  ytÈ­Ui€Ûp²Ð$Y0  {<®þwoÄø% ñBAK+w÷ëü l `ÓhÅ V­¿,JÍ?l ft=\ýïÚ‡Wð[ ¤Pßû­uü{ÚC@›m#p>ZYäçé[Ý7àSæ\€Ysõ¿s^A ï´^Ô büiM4f¹hýeQH „³‡.HO€Y{qõ¿cžE Hï´^Ô ò< m4PÐ0Š!æ uÁ•ýO ºB 0f|––«ÿŸ5á‚ÈÏÕ7SPëE ÏÚGÀv ¶`ÈñkýeQ˜§ï»}!Ÿt‡@ ÌØ•«ÿ»{ða æë{Ÿ õ¢NXçý `«[G.¢¸[•®Ë €ˆN(ºE fü‰«ÿÿ´àO„)À €0µé ‚ ¤®Â¶5V‹ór’’“P8X¤„€f|2\ýWrB“†•…ùú¾ÀVžŠ@Ö²&t«3¸úïÖ9L¶v 0 @„«ÿvž»D­C@å €–<ƒC –€´¸ØYãÜ€Ø ¸> €«ÿ±?E P¹€Ê»´QP~Ú’ Pè…';Ðø 6Ï#/—gpõ?^ç"Ѹ' ñ½BKK®{IÆ 8 Ò`@Z\ìŒ> ¸: àô {ËØA>BÒ¤- ±Ð–ÌïÁ†n ð·Þ­ñÎ:[ Æhü¥žõ@Ó1pqÀå_>*¦£AX¸# õ½‚Æ÷udŠ@f2ssö(¿( rõ­ìëì Jâê\›pú¡ûÉØ½úªWD îZ gvÆý\">¢ õXÖk›¾ï‹åšÛ²!€€=Þ,€>•eöœE¤—_p|Gs(ø%“Ðù^!™ä>È~#´ƒ€-l©˜Ä™—Û“Hü £©•_~þiÒÁ ´Ï8wRðEÜÃ'WÿDÝ#€€' õ½BnN+ŒŽ PplÀ³MWc ¹…@¶çÇ#¶À¿|Nÿ,®þ‡}VÑ h}¯—§ïÂNç£È+ à PàbÒd% yWÿ³:58ß4ÎðÞÓ%DçÚ¾Ÿ4ˆ€" Š3ŒTtÎà+aœ;ô€ßZgpõßï3…öÈ^ Qá×5¾§Ë~¤iýô±¯jœФ𗺯ƒNcÄX@ã,®þÇø„#4g´Îpv@I‡(8<ø™¤ž§p ¯d\&§Ç ¹€¶Y\ýü”":Ð8@ã{º'@`7 »qðCwZW‹miãkÝ=¯#WM³¸ú׳Œ¸\`€ëgù# G€€ž± %­÷‹åk¡œ>t‚@ Zfpõ?ÓƒFðE@ã ÖðåÔ ¬ȳ.bŽT@ë ¯PZ)-#€@Þ,€+ï{A>Þ¼=‹V¢=”«ÿ!û·Õ‹$}¾µm¼­Ê) 9º C ¹UßLAë:…q.ж P°}CŽ_ë ¿ØC>5èHvÎø·¿>i™vÎÕÿLå²8îã)"õdÑ@‡–O©ùB/ð”íg æšÛ²!€€{|À½1Ï*c­3›õUö³hFÀB›×àê¿…'!;% ±—çó §Î’EÀ^ öŽ]$‘çåè¬küÅÉ B§D(°s@„!dÔ5Wÿ3bã Bи€Ö÷t¡žt†€…,´(CÖZ-Þ²#7JVúFŸlœÀÕŸŸfP@ãû­³:< hT cxIhý¾ØÆíÂ;‹è àl›ÀÕÿàÎZFÀOÛõ-›¥u]'?ǶÐ(@@㨘S~^s€­G×ôÆ:}¿Ø£Ó¤g¢°iWÿ£=WèT4^(ÈÏ×ùž.Õ1e?\ àêÈg˜wiñŽ Œ÷aµÌˆ÷iØ2 €«ÿi *»"±€Æ@i‘Î÷tŸ*t@ì(Ä~ˆâ`qa½$ÉxåC4›(ø HÄGÀ†Y\ýÏùB$t%ÐÒ–-õú¾*XZ\×UÚ¼†J((Ø Òò>ü—ÕÕ|díÖ*ün_d˜tŒ@ â> €«ÿ18I¶ÔåJRßµ)Q:«3Åae7œ àìÐgž¸ÆŠñ&óË t x³ö껤r ùå…'Ä..BŽ6*}PV €ŽGœgÐ-ÀÊgºÇ7ì>)ÔÒvT²@Tòôë¼@ÃR‘­ÁÔ¢K îµ”3ÿðF¬˜pÊp9¸×2“ÚñøgéLKgxƒ§uŠŸ3'&‰"ÐÀ9‹üí¢¤˜EøCݾ3Qäg…ßo¨IÒŠ4®བྷKEIŧ-©!Щ€Nix¡3kx¹®ÝÌš˜9Ï# EàÂñ"}+)5eÁg”g~Ãþê´¤\k¾÷vÑ!øìèwÖlÎW—¬Ö÷rꊄ@€@¨Ú›ÔxoÌ>ªÕ÷ ^û¹H~d"pú"ïý<)gŒÎäèÔŽÙ¿ŸÈ?IŠ÷½ÿ¨¾vZ¤ì…Ý ¬Pøþ@ë{¹îÆ’×@À¼/t´V—o(H—‚ý@ÀRÞå"~3)·\˜”Á=ýK¢Ü¬ðÿ³Df™ÿcú×.-!€@4mf–ü …ï(Ds>Ñ+q`ÎsFÁ²´þÒ`€e'"á"¥€7-ÿâCE.Ÿ”ÇÞ¹öÅ„L_œY£ûöùþ1IùªiÏ+°!€€õ[óÄ[(XÛ¦õ½œ¶q"‚ „ªò6KŠv¨Ì*‡•¤èVÀû®þYy¤Ì]#2m‘Èìå ™½Bdá:éð¡*EÆ öI9r¸ÈÑ#˜êß-4; `¡€Ö÷ZgsZxŠ2¡ PÜþsrÚÄûÅQW_b2»d°bƒOkT!Râó;s¸¤¸ËPñGð¾»ï=ÌÇþö>¶6ˆ|¼m÷î*ŠDú˜¯°!€€~ßÞÄŒª¬d{Ì""K€@XÒÊú©ê±Q]`ÕÆ|iiKH^N–·ÅÉï%â=Ø@Àzïþ÷`C7VÔê\È{džn ° ›ãžuÖqxþ×l¢&–õÉA €(Ð: ªÇ&%#D ®€tÅØ¿] Ziåø#¥•~N[@H_@ã<­ïãÒaŽ@À= î¹/k­/÷k_”i@¢X^ëÓú@Q&±Gß%EõRTh8aC'(89ìÙ'­ñ+ž 3²?7h@ ­æ««´¾‡ÓpΑaPCYaÕ•:a€Â“•”@È@`Íæ¼öÅ384Ö‡Pˆõð PœXg=+´t®ö«ó,$+@‚Pûý¥q‚;h]tghÙä7Kyé7Ç­÷à:ú`-€àti@{>üXç{´ç$R‚ „ª#mj\pö<ñl € à¶ÀÜ•E*ø €Êa%)Rà“NÊT츧€WA^¾zðžO[ÿó¼U…rôÈëó ¬È1WØrùUäëXå¶™æ}m’ÆpQÀ{? q£ qTÉ Ôxוº{î! õˆWñ?zdÝÙò#"Pu²È‰4íl£­«MêW;›>‰#à‡@2)2Oí €M~ÑX*ÀW,¸8„­µ õ~Îb@@À5›óeóŽ\BM+Ʋ’íRß”Ö1쌺(èÏP³Ñz+@­ßù õä 3@,˜·Rçô­ïÝ,>ÕÐ(„N®§C­3¬.Tyß_=g™ € ¬ÀÜU,¬0­#€@T¢’WÐoÏŠÍ’ó%9e[SKB–®ÓyëeCE: €" õë€Ü0Ó…F°J€€Uï`ór[Dã­=å¹J§þÅë "@â)0Oé €šžâ NT š€Ð¨uvÔ¯fÊÄ´VþUI!€ ࣀ7pñ3û÷Öù¾ÍÇá§)Ô PP?ÄÁ&¨õ‰Öïþ{6Ð: €ö ,Z«s- D")}ª×Ú?@d€Y äeu4;/Ð_é €ùJïýëü  €Ýh}`¾º¹¼ ¿ùìnÒßõå†]àÏ  C€€ŽqŒ,‹þ½WGÖw¯¨Í—­õ¹RQÜd7´ €1˜»Jç-›[òg]téü·bÆM8 ²€ÁCêîEÓO³Ï}`Ú¾g›½zÖJ~^‹4·è;•æ,/’£GÖí™2?#€ €€b·–kÍî]­‰‘¤. ïS[깫ÝÓTwo7Éyß¶)׌ò ÏìÙ`N¢MúöZ+­¸çKÖÿüÆ%¬E@@ uæÖ„PHÝ‹=@À>´oÌb±Öuf𠀏#ðÞŠ"ihVûö˜îœÊdŠ@§jÿ…ë4c^ð]@ë:³–”Hk[Âw/D@x ÌÐ[üßnÄ—ÇS¨@ L aj+íKë €í 92_éB@JOEÒB@ +™ªý÷^íÊSÛ²Âá`P!@@Å0F›D¿½÷”õÖ`C@ýɤˆâßûLÿ× “!) PH‰‰º(+Ù.¥ÛºÚÅÚ×ÞÐ{%ÀÚ1!p@‚X¾¡@ÖoU»>6€ NÚDÀB ZCîß{MÃÊ:&Ìš@°B@ñÕÏÿ=+ @ p »ÑAÿšÕ*]¹1_VoÊW™I!€ €À?”Ïú£ðÏ¡æO8-@Àéá÷/ù~JgxBʯøwÐ € (žõ·Â,¸Ùâ¡!tðQ€€˜.7¥õNÞ˜*^ØåS–Ü@ø‡Àæ¹²`uá?~Vö¾ÿ¯l@IlÔ®t’ Ǧ/Я×Z),h”Æ&}¿kÂ3 í¿\‰d†GÇû°iK‘¤0¥6Þ£Dt €¤/ðü\µWÿ= ¦ÿ§JØ|DgÛD)¸1ÎgI c:ìH`Ø@ëx¹NûðŽRæ9@°T ¥-!Ó™`éèvºÀqý% ®Ÿ>ç?\qà9Öðùl¡9@¢xki±lÞ‘mÁõþ¡ùþÿÚàš§å˜ PˆùE€¨ä•ö;|À2¥™‰Ìøh©k*V›‰!€ àšÀóLÿwmÈ]Ë—"€k#žB¾R@b—Ô*+6‹÷и5·åÉËËGkLœ@pRà9 NŽ»cISplÀ»K—@wB¼¾SÀ»ì–TCú-oÞy¶ÿó5m#J> €® lØ–'s–«žÙÇ\=¹?›7E€Ïš8ûLž³™“xZ]:º9 2•ƒªt‰ÙïšTöµmŸifïv€ ó_6@°W@ùíÿ¼é˜óí"@`gàD³6ÄÌÚ§IK˜`É@Y¦ÚŠóG[z˵,ÂE@=”ßþï5ó!¯mÏœùÙyE€ ÎK8 @ÀáÁ0õ÷LÛÛl?Ò¦ù@¤ütŽ €@Ö­Üþ/kC°V€"€µCçOàüq¤•]LÅÙ[/àõ]žRõÇ©‹ŽP•É € àšÀKkdcÚÛÿyév6¦kçj@ùRÖ†f)Ø0JvÆ8Íΰ»úö“5Ûª»ß‘=@@ –¿=(–qùTig†OmÑŒ^ŠzǶËÌ(tÉËY<™Å±±>Ô[ðÑ…c#Á!€ €@Ç-m¹òè;ª ϛ٘gϳì&@`77~ àÆ8G‘¥·Àª(:£Ï‡çF7ô €> ¼¶â@Ù°½ÈçVc՜ڋ0±RÖ E=c™R&Rbb§tLåÙ»OÞSégËþ³V”•[kl —8@@àS‡¥Ý‚€öö??Šþ›Æ¶E ±©-x£ó¨þ7*NB’@@`§@s[ž<¾ðÈ?jüÿsf™ÆÄ"Ì©)¾Ãìš"@˜ÚöE B|º~ÎäØª5χ櫿‚ uèÈ @ÀQ——–õåš³W}ñ%¢û²é·!¢¾Ãî–"@Øâô—AŸt鈀©@o®8õ5“®ÊOÊo¯ÙG–7Ÿ$Cª692¢¦™WL祣M‰j{0mGÙjÉ6Óû‚(#H½ï¢!"å}ºÞ¿Í¼ïª{·ë}4¿šÈ)“z†¥;̾sSߟ=pHÀ5|˜þïóùlÞÏN3ïgO3Í>nªø”ngàD“ûLŸ9i.b0ÊCð~©,xãöÈÒ/Éÿ·ïåC¨8½ª“u&·v‰ÉË’@ÙA"5ÝÜU£¹Öí@N±1úBêçê¶Õf_ ©ƒ±§+M­y2uÑšÓõª/iN0ªÜ(D%O¿Að€ TisW§výAÛŸšíIÙ@@ î/.#[Jãf6ñM7TÍ”)¶ ¼"€i×› àŠñΙ‚ð¤Íè(DgïJÏsL¢kµ&ûÞŠ"Y²®@kzä… €€‡ôß—éÿŸ­¦ùP(„Âìn'æJÕ·ôFöaf¸{‚“9 €€-òäâìˆ5‹ UϺÌÂÅ×C)øÊIcPˆÝÁ.UÿBºwFIze6@ˆ¥ÀSLm%±ŒÍ§ ›¦úÔÍt#@  ^޵€Xšàž5™´©ÉfD>X[(o| úMÅó# €v L™£tÑ×ÓÿÿiÊŸ(„ÂL'P•&w0ÿ@n4ÏÌØýY]?ÝþrO] ‘  €J–oî#/˜•o"`Š ÓeÖ²&¤TÿbzäͲyGnŠì† €a ÜùîIauU?Þªô/FÕ¹ëýRpý °/ ö™­?hkà©ÄÝØœûßà–€©X± €a ´´åÊ]ïžVwQõó„ùZUçô+B€³À& 6–űšç™ðß·8…nCŸb¾Àb€Ý2± €¡ <÷á8Y»½*´þ"êèïõK·»P؃?ÆZ€@¬‡G]p÷ªËh—„æ®,’·—ïò D@(nGýâ;ŒïÔ(éûŸþiÁŸâ+@ ¾c£12õjo €D/°z[/yîÃñÑl›uÁvAëéPHG‹}£ …º£}š™ÔçhNÿY=d{­41¹!€Ø!à}÷¿-™°#ØÌ£Tq%sšèޤ==w/À'•îØÃ_Õ¿¨v4æÈC¦À† €Ñ xüï|÷Äè§çí¦ÕwY ‡1˜^(ãJ«Ù PÈÞÒP½€Gq;_HïŒ`o@|xaÙùhKoŸ[]sš™¬þ»aùg@þiÁŸâ#@ >cáD$æÂ%&ÑÙš“õ|ß,Ȇ €ÑL™£~ñ?Võ¬ÊhÎÿ{¥à¿)-f'@ ;?ŽÎL@ý/¬›žWË¡ÌFž£@X`åÖybÑá÷yó[MOG¤$@ %&v I€@HÐt³›À}»ý¤ð‡{gTʺ­y 3#%@â-pãì3¤5©þ-îÃæCec¼G‚èv °«ŽR@ý¿ŽQâÒwÇæÀåæ•¿ªãÙ¦–„Ü-þå©<¹xÈå’›h‹OPDbŸ@¾¹•Õ Û7#€! <²à(Y³­:Ä#ëJý,ÊÈdCì˜"@ˆØtµ›ó“wãà‡î¹¿Ð»[¾¹¯<¹è°Ðû¥C@\HJBþoæÙ.¤¼Î$ù¼ ‰º£W0yz3\È×ä¸s&ÀGòešb9,Îu—É´^{¶ÿ7óí)’ €‘ ¼¼ì yÿãá‘ÆRç3[Bê‹nB 2]ì&@`7~SÀüƒ·Ùô§þ–€³V”™«F…IK_ €8%àÈÕoLovj`I–"€#“4)Äd ã¯.äþo0 À…q&G@ðæ¯"Ó–~Çá÷ø¢ù ¸(üné1 Ša(Ó‡'@€ó jWMó£"èþŸ0ë,ÙÔ?ènh@çþâÆwÿ½qu⢉s'ð. S؃?&@ 0ZNEÀüC—4ûݔʾ6ïÓ¾8ÑN,Ndó0; €€eÞªÿ÷ÏdYÔ…»Éõ@FGrU¬.+ƒ¥`å°© úv“‘úûÙÞõî òÑs;76@ðEà¯}IšÛœ¸«õóÁЕ•â}97ln„"€Í£ÿØ)ÄŒÔGhþ‘Û`’|H{¢Þ”«^;O{šä‡ €@(^QýŽwN ¥¯tÂôÿ B˜!PSÛ­¾(¸5ÞqÎÖ‰_lw¿{¼,e-€8Ÿ‡Ä† `‰€WTwäêÿ óað}K†…0} à#&MýCÀ‰9SÿÈ–?ÄY`º n‰y sÙÆÖšÌ‘ß¿zžüå´«²mŠãèT oÏrùêd;VÄÞo_‹ét 3|¡ª¼$µñ¯_(Òº=Ã^:9,¿F¤pp'/~ö郆õûì“<ƒ@ ^1Ý+ª;²9q‘Ä‘±L;M¯P=pêiæÀÇÍ£(íì; ‡ ù“ó‰&÷™ö…ÿˆ)ÄŒœˆÐüo3ѽÅ£=áûÞ?V~pø½²OõGÚS%¿ˆF¬‘[ôňz§Û¨×T¦6þ«ÿ"Ò°Íßp+öéu–¿mÒ\ùÊùâÕؼ¿¤w ORìB€"@8¼”¶€ÿr¦­ÂQ üÍtÜUçaõëÝàÊ—/«;úA@@•À¢ÚA®¬üïÛ]æÃ_ª$™Œ¼"€9Л àÊb;gLÈŒƒ: Ð) /„-`þa[cú|,ì~£èïáGÉÜuâèš>@°ZÀ+¢{ÅtG6¦ÿ;2Щ¤I %öéN€@wB¼¶€3¿è~÷ ³Â>¹è@Àn¯xîÑÙÞ6øÞt$WÒLQ€"@ŠPìÖ©€Nix!"§M¿+"ê;ÔnŸXt¸¼³vD¨}Ò €6 8V+ðì{å2}^Ùg_ÐûŒ÷ý±ûõ¦GfQPˆB=þ}Rˆÿ¡ÈácW Þ]Q$w¿ÖÓ•tÉ@ÝšZò‹{ûîöœ?üÙ|Xc :ì)„-ÿþ(ÄŒœÐüÃÕh®q â¿ê-ÛøëéÒ˜“+ €À'7M¯’%ë \âØj’½É¥„É5\Šázǽ7î÷"¾×›?üÜ<œø‚üú­yòÇ©5òŸç83ñaç8ó@‡6lË“?<^ã”À¤ñ/yÜc+EFe›÷´‹.V¶p¼N¯À-uŽmºYq‰1]1öDÀü£Uk:¾%’Î#êôºg«eîJná0Ý"€ÄNà?ÌÂ[ëscWPåæ´Ê¤ñ/yÓ¼{fûpâ"IPcáB»Ìpa”»Ï‘Ý9¿Ç”kFl&G ±jÝUùWýí­mÉ\'Þ´˜•p{yêgK%7‡U£>ÿè@ XçÞ+“fzwórg;ì 7¤²|‹; “iä̈|"€@äC`EM”?Ž:Ò½×ÈQ‡¼&/Î>*êPBëÿíeÅrãóUòÝã½ l €èØnÖ½ù·;ûëL®“¬òr[äÄý۵³!®E€p½ãÖ_ˆÛˆO—“{^òóÜZ$÷7÷–åœZ ©Ës€@ô üúá>²jc¾¾ÄºÈèÈ1¯K®þw!ÄKA ðu€ uãÝ6€xÑí!PQºÍÌxuguÿXß”#?¾£Ÿ$ù€î&;@ÀQYKJÄ[ùߥͻ˜á]Ô`C JŠQêG×7€èìé9CɇN—Âï΀îlÓç•É}oTº“0™"€8!ÐÔbÖ»¹­¿sEnïb†wQƒ ¨(D=á÷O |szÌR ´¸NŽ>äå,[±ïpoedïöHl €h¸ú©^²pM¡–tRÊûˆá]Ì`C .â2áÄA gzñYàØ /JQaƒÏ­Æ»¹Mu¹âØ@Ð à}ðÿãÔ ©¤•Ã1ã^ïbq §Ñ6 ÁúÒz@%Eõâ\Û¼Û#y·IbC@Àf6³®ÍÍ­n›[6§‘vìÞÅ‹IãÝ{ÿ’6D"@ öÐ;¥:9ú%pŒù@IÑ¿š³¦ï6IÞí’Ø@°Uào/VÉÌKl ?㸽‹ÞE 6â*àp`ߏމßqñ)ÂoQÚ MÀ«¢»ø:ï6IW<Ð'4g:B@ÀOïÖ¶ÿõ {¿Ç¼‹ÞÅ 6â.àhà‘êS{Ä}lüˆ€Š´™€·ŠnYÉöÈúªã[Í•“gÞ-ª{úE@ #–¶„|ï–NÎdó.Z¸¶~QF' ÅBÀÁ"€7àNSÈÅ€qi:x‚ü&9ÞÑûè^jn›´n+wþ,£@¿þüd/yã÷¦þ{+¼‹lØ$à`àT3>ÿiÓe+€LÔ8&VGŽy]z”mULaSkn xé­œ»wr¶ô à¿À¬%%òûÇÜ[õß“<áðiâ]´`CÀ6‹—™Yƒm§t⥎ûÆR ?¯YN:ò™XÆtPÓæ–ÉMÓ«‚î†ö@ÈJ`›Y¼ö;7 Vó×¶ž›åˆƒg¸–6ù*p¬P`†î犆ï3©Pø OØ(pØA3e@ïÕ6†žuÌÿy_™¿ª0ëvh@ þýî~â-þçâvú±‰w±‚ ›+|ÃÌfóxu;€®txÍœD›œ5ùkâõ3Ц–„üËM¥±Ù½«*~:Ò €@0Íê!÷¼^Lã1ouøÀ¥rðÈwc%á!š€CEo‘­OMž½(Ø7fD܉ÀˆÁÊè}ÞëäUÝOÏ[Uää-•t*Ù!€ö ¬4·®ýñýìO$ƒ ’”³X¼ÿ³! EÀ¡"ÀYf€ÊÏÊ*“ÒòŒ<Ò8ãØÇ%/·%ýqôjñÖ`C@ Þ÷ý½[þmÙ¡þ®Zr:z– 쳪Ã×x›)ô2c4Úæqê,v Éð¼•Õ•µ2iüKVÆîGЗ˜»xw`C@ jkŸ©–וFF$ý4Ê©G?IßtŠ@ŽNÃ2ì>ø¤¶8ý.àÝjgæ{ãek]yà}Å­ƒõ[Í­oë/w|…ä°$@܆‡x@gÞZZ,¿}¸·3ùî™è‰G<'å¥Ûö|:èŸOœrͨèä‡]:¿.€viÒr¯`¦ÉŸfÒxÜ<Š,O§£ð½Àï;zÁæç(Ø_õ?Þ|o_6ðKà±¹ûËÿ>åîß«¸íŸ_gíØ& °àÝÂÄ[Û Þ¶±è*^ ]éðšõŸ?fª¼»èinqs*â»+Šä§wõ“«¿²Ja- ؼÖ|Sp®¿çNáÛ£5»"¥ûÛ3Ñ"à˜À¢ÚArÉç8–õîéyðëÒ¯ÆüdCÀa…EïC„ª·tø/¨ ©WVl–ɇMw!ÕNs¼ëÕJ¹ý垾Π €d#°½©X¾úà/¤®ÉëÝŠ ëåsG=íhö¤Àî^À<ãÝ a÷W¬ûi½Ée«uQw0€n€xÙ~ã&L—ªíO$‹ ~vw?™½¤8‹8@Ï $%!—Ný¡,®øÙz攣Ÿ’ÒbÊwhÈIµ%E€ݤiåˬ6‚NG  ¿Y¾xÒé¢nßæÖ„|íúA²~+ßúQ7¸$„D(píŒsä±…GFAô]í¿\Žózô1PP ³sŠpHY`ä°…âÝÐåmÍæ|ù¦¹3€«÷evyìÉBà¥e˯^¼8ˆ¦­i37§U¾ü¹û$'âb»Öè("–ækCfhUrêPàÌÉ:?=ïÕ…¥òËûûtèÓ €¤*°|sùÖ#—I[2¬fS,ÜýŽ?üyéÛ‹…ÿÂU§7Û,.ù^ÉËmIC]p[À²"ÀÍZG‹€Ö‘%¯’”sÍ‚€ùM¾îÊ“mI‘oÜ8PÞ]QäJÊä‰ ¥€·âÿžüWyuÅY¶dÿáǼ&Ã.³?2@ dKŠÛ ‹ÚÄ)„|ÒÓ]ôU›ä´cžˆ>ˆ#¨oÊ‘ó®"+7æG Ý#€Ø ðûWΗ{ß?ΆP±²| ï#¦qí~mbÜ¡u(hYòêR`âØ×Ä»mëÛÇ[òÚ‹[ës]§ @.îyo²\i lÒ>“°¨° ÈB ÆE€·LZWe‘Zì¥û!"À ¼Ûõx·íñnßãú6U¡|íúAÒÜêöJήŸät&àÝîÏ›úÏ&2fÔÙ¯yP €€1,x‹z|ÝÄ¥zq >œ¼4a§€wÛïö=l"/Î/•ßÑO’fm6@v ,Ü0X.~èçÒÒÆL±’¢z9{ò#;iø?ø ³"ÀoM<ïøV¬› ëá!¸ ¼Û÷x·ña¹óÕžòç'k @@ ]`]]Os»¿+dkc)"FàÌã•òRom06ðS &E€MN¿ô3¯¸¶E ®#C\¡x·ïñnããÝ€Mä×÷–fö€@ÀqÍErþ}ÿ)méí¸Ä'éï3t±Œ?p6 À§E€SLó›ꢫf½ÿß51´uµ“–×(hIòÈXÀ»ÏÑã^Éøxm^rë™6·L[Zäƒ ¢@Sk¾\üàÈœµ{§x„îÝ åK'ßÇÅÝÃLv10À§›0&˜ÇÜùÁôå̇Ï•@ˆg]ÅWà´c¦J¿š5ñ 0Äȼſò—ÁòÚ"¦|†ÈNW €@,šÛòä›\&Ï/‹xâĹ'>(Õ=6Æ!b@@½€)|`’<Ü<8ÙZÓþæáԇϔ€§Àæ¼@~^‹|åówŠ÷•6‘Ææ„¹=à`™½¤@GZ“9rÉã?”'yï½Ù<±û½-‡ìïÝŒ Â0Eo±sÌã›æ±"€~ï1mŽ2ýÜeÎ}˜@gMÚ)Яf­œ~ìãv@Ôu9ò¥ÿ"ïT@ë4‰ '¤™àþã§.‘æMŠSX‘ÆÒ³b³xWÿY'(Òa sGÌó6ó¸Ù¤ï}é{æ±*K ïÞß™ÇɦÝóÌc}–íY{8k‡ŽÀƒ8êWeÔðA4me›[väÊ9"‹ÖZ?A#€t/à}øÿÅsß’)ïœÔýÎŽì‘H$å"33°¸°Þ‘ŒIx ˜êMæq‰n„y|Éë軤 g»e‘î²õíEom6@x $ÍzÙ¿y¸·üêÁ>ñ 0⨎;ìÙ{0‹‰G< t! P šnì(/Ù*ãzÝÊÔÀ†qÕÆüö"ÀüU…¼ÊS €Q xþqo_ùã5Q†Û¾½þ§õdlã#0@Ào ~‹ÒžZ^E‹dTå£jóË&1ïÖ€§ÿa˜¼³¼8›f8@ÀGÖ¶„ühJ¹aZµ­êiªÒ|ïÿ«gÜ!99mz’"@  Ýñ2» Œ¨˜&ýJæìúþTÀ»5à™W •Ëb‚ ±@skB¾wË™òJψ#‰g÷¹¹­òµ3o“²¾ÞÏ"*J€%¼ƒ’¥]¥ISu‡loî+Û̃mwm 9rîÍçÊçÌ•c†R(Ù]'‹ŸZ7‹||{ ph‡U§Šäse´Cž´Z ©%!ß¼q<1§Üê<‚ þœã’!ýWÙm#€± Ëa!¨8 äå4Êø^7ÉKÿDZÚøÞûžcUßœ/çÝw…Üræoää½ßØóe~ÎD ­I¤îýLŽä˜®*5¯R芈×ìØÑ˜#_?HžŸ[f_ð!E|èè™røÁü~ ‰›n@ f| fB8v”ålfL±#Ø¢ljÍ“¯<øÿä–·ÌV6@PÖ™õX>ÿ‡¡|øïB{Pß•ò…dQß.Œx t PÐ=¾d @¿’wdïŠgìÁî¦Û’ ùé3ߓ˟ÿ†xfCN`ÁêB9é·ÃYŒµ âÒâòµ³n“ü¼–.öâ%@@·ÝãKv Œ¬|\jŠÜ‹ÝÍÿeæÙòõ‡.õÍ|]Âî‘$zˆ«ÀË Jå”ß “jóãbäq%IùÊéwHUŦÈc!@ J QêÓ·õ i“CzýMŠóxCÑÕ`>¾ð9óîßʆ•]íÆk €i Üóz¥œûç!²µ>7Í#ÝÚýÔ£Ÿ”}‡.r+i²E: Ð O!Ž@AÎööEsL)ìÊíÍÕûÊI·ÿQ×r›À®œx HE ™ùÝ£½å’[˜iùšUWf£÷y_&6½«]x pF€€3CM¢A T¬Ñ=ÿd*Ú^¾¹|nÊUòúG¨È‡$@(¼Ûü}ß|ðÿýã5QtoUŸ¹9­ò¹‰O³èŸU£F° ¤€ uiÛ)Áe3dhÙËNåœI²›Êäœ{~-÷ÏõnÁƆ ŽÀæ¹rîÕCäÞ|¥*·Ö¶\ùëý_—[ªRÙ}@õÔ1 †)p`ÕýÒ»h^˜]ZÙ—w›Àï<öc¹êµ/KÒ\—aCè^`ù†ùÜÿ “W–v¿3{üC`ãÖžrí]ߥðþ€. PpyôÉÝwoQÀq½n‘Š‚U¾·­±Áß¾t‘|û‘ŸJ]S±ÆôÈ ðMàÅù¥r¯‡ËâµÜQ%TŠ™¨q h  qTÉ)R¼œF9¬æz)ÊÝi¶tþÐü£Íâ€WÉ’Mým ™8@мÅþ®~ª—Yé¨l¬c¥ÿlà)d£Ç±  E€€–‘$X xþ½"@^¢1VqÅ5˜†Èä¿]-O->4®! ºÀ¶†¹øúAò«ûH›)°e/@ {CZ@»(Ø=~Dcïkãjn1ßpo‹q”ñ m[c‰\øÀåâ}- 5É?Mñ"A(­)”~3\¦¾]E÷ªû¤ zxIºà]v7@¼Œ@6Þ‚€£«îͦ çŽõ<ïÞ+dSC¹s¹“0 à <úfEû‡ÿø¾`'E€Àhib.@ æDxö ){UFTOgß-´/ x¢YàòûúÊ®ÄqF €@@3W’I·\#W> 32ŽK³â2Ä™ PÈTŽãP`dåT^þB€=¸Ó´·(à_ž­–£®ØK^œ_êNâdŠ lo*–Ëžù®œ:å÷²¨vPàýÑA<(Äcˆ2 ™G!°@Rèù  ){-à~ÜiÞ»÷ö9*—þm€lªËu'q2E@žýp¼ñ×ëåæ·N3÷pa½‘@cÜ(E€¡!€@—ºäáE¢HÊèª{dhÙËQ¡®ï»_«”Ã/!Íê!In¨n|I Ö×UÊ·¹Lλz[¯ »£ý Pˆñàt*@ S^@ z„¹®4ºê>Q1-ú`E°a[ž|ë¯åÌ?•÷W)ÊŒT@ (¦Ö<ù¿7Ζ 7þUštPÝЮe,0ÂE¡ÀI€@ì’²_å#²o'b©m¾º°TŽ3+vÿèŽþRkŠl €ÀžÞôþ§?8T޼é:ùÏéßm%{îÂÏŽ Ppü }, `Ù€®«ISxRö¯|ÈU€Àòö ¼ý¥ž2þ#Ú ôn!Ȇx 6 ‘sïù•\pÿå²tSPèT€"@§4¼€1 ³!ºØ«âùöuÄ|5€Í_­õ¹í· <êŠòÌ»å¬à//­!`•ÀÆúòöÕý¹ùZyaÙ«b'Øè(DgOÏ º€Ô­ØX -{UÆVßa&¥Rb@>ü¸@οv°|ñê!²pMa]Ð&ÄT ¹-Onœ}ºL¸á¦öÕý[“¼MŠéPÅ6,бCOøÍÆ©€€…Kgʸ^·HN¢ÕÂèíyú¼29úнäßïéÇmí2¢D +ç—ŽïŠÿÏŸûÙÜP–U[ì¶E·ÇŸìˆ»€¸ñ!Љ@¿’92¡×¦ÐÜÉ<­@k[Bþú|•Œÿ½åÏOö’ºFþÉÌ֔㈛À[kö‘sÿþ+ù¢y,ª·ðTÅSž¿ÆäãÆì5ŠªN]’A@•ïfU 'ɸ&лxžVsä&š\K=Ô|7ïÈ•ÿ~¨ŒýùÞí 64óOg¨@g ðþÚí‹ûxÛŸdº¹úϬ@ßâw嘾WÊÁUw™Ž(«Më €@缋í܆W°B WÑb9¢÷5’ŸSoE¼6éÝ*ðòûúÊ!¦pÓô*áŽ6&±»*°`u¡|íúA2麟¶ßÞÏU‡0óX:ûÓ¯­µÈà²Âħ/@` {€ð#6 ô,\&Gö¹ZŠr7Û¾u1¼%O~vw?sëÀ½Ûo!ØÜÊ­­DvNÀ[àóÛ7 ïN½Uá\þQ%<¬ü%S=e·5k(D5ô‹ˆPà,@@‰@Eþ*9ªïUâýŸ-UóåGwô—Ãþß¹ûµJi1k°!€@¼–¯/Kn ‡_¾·<8³·ø mx’r@ÏåÀž÷›»Ö´}¦WŠŸ!á @ ¼Pz¡E ØÌ˜ØçÏ2{Ã×d]Ã~¡ôI'"Ë7È¥ ~T䲉wÉ£^6ë2|ö ¯µVù5"ƒ~lmø¢ÀÖ×E¶Î±ÃλZµµ—\õÚ—å®wO0ŹÜÎwäßrÍâ´c«o“~%ïtÙ¶Wð¶9Ï7ÿÕ_@ݹ0à%ç_'U=6¶çÎ@°˜¶8ý!°@^NƒÚûZöjÀ=Ñüžn ß~ô'rè 7È-o"õÍfo±+ =³åg:ˆö|ÝPùÞã?’C®¿YnŸs2þ;¦€ž/ÌÝ&G˜¯¤u÷ág÷ÌØ)Áÿ@p(„ãL/„*àM·]õwÙ¯ò‘Pû¥³O–mî'?}æ{rÐ_n“ÿyùBY_W (4WŸ7+ùážÿ–I·\+÷¾üôî¬é²üå¨>WIÏ‚åíÒáó:dáI@  °Ò(qHʈŠçÌÊË·šÅ—Zâs1l¬/—?¼zž)üM~øÔ¥²¸v s$Œ@M­yrÏ{“嘛¯•/þýWò²1AvGÛ]xw¤9ªÏ¥$¯¶‹½:‰"@ç6¼‚ø)À~jÒ1è_ò–¹;À&™¹þ_¤©­4†ê©©5_¦˜©ÈÞãÄ3å’ Êáƒß7×,ݸ¶þ&ð¶4”Êms>'7Î>CÖn¯ »{úÛC``é¬ö[ûe[lfM€=`ù@€@¨4‰@ܪ —¶ß!`ƺïJ]‹YÐ-2g>˜ Þãྋåû‡>(Ÿß÷UÉËi,:FÀ&[ú´èŸòΉR×TlSèjcÝ·Ç“â=>Yë$û4)doH  €@WºÒá5 ”æ­o/Ì\ÿmÙØ8\Qfv¦2gíÞò­G.“ë傃ž– F?+ýË7Ø™ Q# @k2G¦/9Dnç$yzñ¡âýÌJ\<&?ºIDAT½€·ÖÌÁÕwÉ Ò7|†"@V¤¯eutÇS¥îØ…g°R€€•ÃFÐd&PS'Gô¾VÞ®½@Ví8$³F8ÊW•[käwf¡Àß¿rL>[¾rðSrÂ^³˜à«2Ù(àýݸëÝåNs¿UæÏlñÈÏ©—ñ½n–^E  Š"@F´Ï\téü“2:’ƒ@À Î 5‰"ð‰@Žwæ^·Iù–µ²`Ë)æIý÷^¶aìÛ’ yöÃñí>eåüŸ• ÍÌ€!•Û>1"à‹@s[žùŠÌøöõ2¦™«þÞêþlñðVúßë&)Ï_x`'¦pP€€¾A?Õ¤äÝ|ÜÏí¿McgøÙ mE+à->·O§¤²`…¼YûUin+‰6 zßMàc³¨ÙŸ^ÿRû㘡sä"3+à”½_—‚\îæ°?¨ðn9eÎIr÷{Ç˺ºžjòÒ–H¿’wdLÕ3C©1´Ô(„FMG àˆem¦~-ò;¥)׌zß´IÀoØ´×»xžÓ÷÷2kÃ7dK·¨‹Á|&„—,Þ£ºx«|éÀç̬€gdŸê>³O `›@CK<¹ø0¹ÝÜãååÙ¾SñzEãQ•µßZÖ¯ÅþÒ¤Žû"€] PèÚ‡WP/P’·A&öù“¼³ñK²²n‚ú|mM°¶¾Bþ2óìöÇþ½—Ê™£^–3G¾,Ãz®¶5%âvPÀ»%æóKÆÊCó–§>8”•ü-8¼µcÆõº5Ðïû§Â@ %öAº Ð½{  ^ 7Ñ$c«ïžËåýMç˜k=¬²çAŸ»n˜x_¿øÝ÷C9käKrº)°^@œGÍÝØšZóä¥eċþ£ä‰Å‡Ë¶F¾rdËÙà}MÌû¾qÞ¦X„L Ã@ `¹ËððO )ÃÊ_’+e¶ùJ@Ck…MÓR`ï®ÝK¼Ç/|MÆö[df¼$gŒ|E˜Û ²!•€·˜ß+ËGËÃæCÿÔEGÈæ†²¨B¡ß —½.£{Þ'Þ±qÚ(Äi4ˆl `ã¨3 T.1ëüξ.µ{ØMû-ðÖš}Ä{\þü7e€ùr†ùšÀff@_sW6‚hiË•×?: }zÿã ”õåAwIûä$ZåÀž÷ʲ n'ïOÀüq¤pS€€›ãNÖt)P˜»Uï}ÌÛ|¦,Ù6©Ë}y1ž3WïñÏ}[ìó¡Lþ¦?|¶Œ°À¬àÝÏ ‰Ê:ïŽÏ/+Ó>'/˜iþ\é·nw ¸8w³Œ«¹©ýë`»½Ã(ÄpP ¬ `Å0$á xWèù€¹Uàr³@àùÒšÌ?zôEà½÷ïñç׿(…u2iØÛíㆽ)ýÊk}éƒFÜð®òÏ^5Rž[2®ýñþÇÃÝHÜ,{-–Cªo•ÂÜmÖdKÀš¡"Pˆ‘€ ¡ G¥³¥¢`ùJÀ×d{sŸ8†HLilm,•GLlx‡ywØ9;`üÀù’ŸÓ’Fkìê‚ÀšmÕ2mÉ!æ1®ý–”Þ9ĦI ){W<'#+—„´Y—E놌€@ b Ý#`ƒ@Eþ*³.À•2wÓ™²lûQ6„LŒ) ì¼£ÀÿÎø‚”ÔË1CçÈÄ!ïÈaçɨše|] EGM»y·œœµr”ÌX¹¿L7Óû½s„M§@‘™ò?¶úvs‹¿ÅV'HÀêá#xY€@Èàt‡€­Þ­GWÝ+½‹çÉœÚ ¤©U½mËÎâÞÞTlVl?¼ýáíSj ãú/”C/“ cËdÜðRVdßÂÎòåy1·üLȇÈ+÷“™æC¿÷ÿ6„Æþ%sÌ¿éwKAÎÙzE€Šêyyñ—ÛÏkIu‘ÄÆ­=åÚ»¾+—œTõ`¡×.¨x ö °?"€@×}‹ß—cûýVÞ®½PÖ5Œêzg^µZ Î^\vpûC^s;0‘ý6È¡#vÈ¡{í æÿ«âu‹0«ÁC¾©%!s–ËÌJä¹ÿ"3—ïŠ?›;;‹¹ƒJgš¤“ªß·Ï 0"Wîyò\ŠªF–d@ÀO ~jÒŽxw 8´÷u²tÛ1íw hKæ:’¹Ûi¶™Ï ïTÔþ¸yzU;ÆS˜`Š jý4ȨÒ¿g³$L±€-Z†æY¸ºPæ®,”ù«Šä­eÅò¶yxE€O6Öôˆv„Âï½§YÔul¯Û¤4o}ø‡Ôã¡£½Â†PÉ›n@À> ö# „¹¾2¼ü…ö¹á«²­¹_,â"ˆpVmÌ—‡6ö‡fõøGÇ=JZe?SØßÌð£>- ”òõ ùø‡¤)Ì|dÆaÞÊ"óa¿È|Ø÷>ôɇŠW´aCÀû÷zïOË>O™™<úoêjàÛçÞT,2ŸèR€@—<¼ˆÝ x Ý÷÷2ó²ÄÌ`C`ËŽ\y}qIûcW¡5Mí¯80Ò†öj–A½š¤§)0c`W©ŽÿÜÜšÕæƒþòÚüö÷Þ•}ïC¿wu[CNÇñ¬óÅyÍíýn—ªÂ²p²p÷wÆUüÉÐÚ•§.sj°IÒ ;#€@G¹‰f9 çýÒ»hž¼½ñBil-ïh7žs\`ÙúñSßÞÂ[Xpˆ) ªnÞíÿƒM`°y¾Ü‘o˜´&sÄ»åÞG[úÈòÍ}dÅ–¾æaþ¼¥¿|´}„¬Þ”ÏýÝO~êFÀ»ë=ï5·÷¬ïfO/»Vؾ£Ü̪ND@ç9MVø!@ÀEÚ@vï“úþVþÿöîHÒ³¾ïøÓsß×Îìîì}H–vWHèB·,±ÂH– ârÀ8…œà"qU’"`Wˆ9,;"1ˆ )(°Œ)2BB«õÊ !t Õ½ìjwµÇì9÷Ýù?ïÌ»3³;=}¼×s|»êu÷t¿ïs|þm±Ï¯ß~û™ÿL¹J”O¯õ)ëz[ìÖÙ|¾ZÛújmÛQµ¬é´ZÖxZu6Èã~ÕÕ8³éÇ ýª­aX®koÎyïãS5ê¤\dO_hïäH«:>Ü®NŽê{ý÷Ìó‡»dÁ¿RìïQ“Óž¤‹šçb¨©Uw~KéÀ÷›o!€Ô{½l„¾¿ñ™?K,ÃK P¾@}õ€ºªçnµoðõ©ߔÍ⋺ò[æ_NÉ"zh³zîðæ¢5USª£a&Ð!šjGU]õ¤l ï;7«ºú6UW“¶Z¹¯—­¶:¯ª«òJŸr¯/˜7·UÍ{œ ^[ðzNîÿ uâô-ê„,îõ¦Z‘i ô4¼¤.‘Ÿ÷k’Sÿ¹ÍðN@ææ,x„± äÕú–]jEã ê¹ïU‡G.Ž­eB`)ý ú±áŽ`[j¿ä^›»br}Ð2ç ÔU «m§Ö6?)/šs̹#ÍæB€lÜéÌàªAæÕ„!àŒ@Cõiõ¶ž¯¨+»ïQú§¹!€Ä/°ºégêæÞOËâ_ÿž¿‹ÿc‡¦€u…6 Öõtõý¡GHá×6Èœ¹!€gðF@Äz›ž•Ÿ |Eí>õOä«×&Þ €>4VŸTw}+8Ûʇù›ãÔ„¾ãC/î_z¿ü¹\$O?âÙrKïëÄ«aÀ…('“@ º@tCZø±“\jŽÃùµòúï.µ¯-- ¯B­¿—ººé)õì‰ßQC“=KÀ« €òjcëãjKûª¦j¬À><]H@®ÿ×è—  !ñ<8+àCòélñ˜Xz¸vÓ ÒÛŽôzt»§©|­zåômêµþír²*ßDr»ÚÌâh­=,aê7TWý/ãlÖ•¶¾õÕ]{ÞWêd$ø=Ù×—@³ì“3´7<à ‹ÏÔÈJ :7¡¶t< V5=üdàéq}‚7@BU¹)u~Û÷d{TUå& íÆóep&€R‚Ô ÙVÙÞ*Û¥²/[³lú'LšæÝ×Ëã>ÙôW,ÎÞ~.–Gäyn `gXP$†˜½g$W}Àžþ›ÕK§oWúÌn € :ë÷ª·Ê§þ­µ‡¾À_g ”u@x°‡g“¹ÿH¶ódÛ&[ÿãûœ´ó}Ù•íq †äž(@``Q’yÉ×dh²[ýâä?UGFô¿E¸!€ÔÊOû]ØþÚкS®V7 HqŠݬ‡!@qÍÊ÷—CwÉv¯l_“0`°ò¦8âàË·q‹ÒT$Ð\sL]Õóeuõò/©–ZÎ$¬‘ƒ@À ½ØßغCm_õÉàžÅòeÕ_^>(›¿¿£³þZÁM²}A¶®ü™lú׸!€€! €ÀœÀò†Ýꦕwª‹:ïUú—¸!€> ô4¼¤nêý¬zKçߪº*΢N³ö„‰h·K«•m„÷Êv½lœœ5"Pš@iNì…) è‹]mjýqðé׆–ÇåÔW>I‘Ÿ®@ æš>õ¶žÿ¥®YþE¾ëŸØ%!@(û½^sü–lËö€„ëbï@ $€’˜Ø ²¨«Tw}[> »Sõ4¼œÅèHT ¦jTmë¸OÝÜûµ²ñÒg¢à%4NPR´]~Cß-!À‡eãÉ¢Yr4e ”MÆ ¶€¾òõ5ËÿR>»[éOɸ!€ö äÕú–]j{ï'Õæ¶ÈOûMÙ?%‡f@x1›¥‡»dû‰„—'Þ €À€3<@³òòéØóò)ٟʧe÷+ý©7@ÀFeõ¯©_]ùßÔ%]ßTõÕ6NÁ‹1¤RæË¤—ŸJð)ÙX—¤BN'¾ ðÿh¾¿˜?– Tå&åӲǂOÍô§gœ.kY. 4ÕœPWvÿ•ºnÅ_¨öºKØ3uB€Tj¥×#“í›4¦Ò# à±€ÇÅgêØ, ?5ÓŸžÝ,×èmzÖæ©0vp\@ÿ÷ê-òË&oïý´ü÷ê™-ßó·©ä„©Uë½ÒÓcô¤Ö#!à¡€‡Egʸ$ ¯pe÷=r:íU+‚ h¹4;æ‚6 è ™ê¯,ݲ꿨òË&U¹ ›§ãõØ R+ÿ5ÒÓ?JpAj=Òž xVp¦‹€«útÚ«ä'´nXñßå^rušÌ ,¨­Q[: þú+KÕ¹q FÍ‹ ŠíõMÒÒ\[‹4„gÎPð\è¬ßübÀu+þ§ÒÚ↤%PS5¦.hÿ®,ü?¡Îo{D.V:–V×ô“’!@JÐJuJOKp}j=ÒžxRh¦‰€ozñ¯/´uÍò/( pC’ПðŸßöh°ð¿ ýï•>€›»„©Õ¶Ezú.!@jÞtä‰@'ódš à¥@^¾ð²l¯¨##[ÕK§oW§Ç×z)Á¤@ ~ýþ-«óÚ¾ÏÏùÅÏkt‹:…©ã=²åŒ¬Ýƒ C€ÛÄ|§ÝSaô˜!@`F$*— ¾ Ûnuhøâ ˜èM´GGwªrSj}Ë?§ù7TŸvw¢ÌlIB€%yâ|‘ NMÚò^€Àû·ø$~2peÓsêèÈ6õZÿvu|ì<Ÿ˜+DЧöohÙ\ÑŸ…H‡%H­˜„©QÓ‘ë®W˜ù!€À99ù ný“z;5¾N½Þÿvõæð¥ò,—E9‹'@@5ÖœP›[¨Ö5?Á…ýx?œ#@pIRO$%K»^ ð¯]¯ÊÍd@àlŽº7ÔåÝ£¶¯úµIþÏÏu-Äßø+ ÿûpE÷Wåâ~ú¿?bñïï[¡èÌu ;}P¶|ÑÙ!Š@ðëQ9ÖkÎðºüLB&ù„ï¢ÎïÈOx=¬ö ^§ö üªj_æ<X)gmn{L~Jôu™5ë9Jiªœ ‰¯œƒÃ€ –£Æ¾Ì ðV@æ ÔV ˽•Oû~ _._Ø®ú'VÍÛƒ‡ à¢@UnR­mþIpªKí§ÈœR Hy¦ B€Ô¨éÈ5×*Ê|@ }•ïµÍ?•íIÕ7zApÁÀ¾Ñ ci›F@Àºª!¹¨ß¹¸ßãü”Ÿ9e±z$„©• 5j:rI€À¥j2H@ ¯z^ ¶þ‰ÕjïÀuêÀð•jrº!¾hÒè¨Û'?å·K­i~Šk¤…îQ?„©› 5j:rE€À•J2H\ ­ö º¸ëÛj[çýÁ¯èkœÛ˜x¿t€ñèŸñ[#gõ¬oÞ¥ÚêÆÓ(­ P@€ LüOÄoJ‹ 8\\¦†Éè_ ÐßÖÛÀD¯\4ðu`è*5>Ý”L‡´Š‘ºäb~úÓþUMÏði$I.W€ \±Š÷'¨˜Ž} ð­âÌbh­=üzÀÖŽÕ¡‘‹ƒ_86z~¬}Д/ ¿Û¯Cºu-O¨ÖÚÃå7ÀÄ$@dñfбЀ7 ƒ@UnB­núY° MögìºZMµÆÐ:M €@©Ý /Ÿö÷6>§ô•ý¹!`‚!@jU HšŽl °µrŒŒh®éS[;P¶?¤ŽŒ\$aÀµêèèoÎØ130l¨¯îWëšÿ1ø´¿¹æ˜ÍSaì ¤V\B€Ô¨éÈF«Æ˜@À ýS‚½MÏÛèT›:4|©:8|™\8p“ãg˜, Oñï•ïô¯nzZ-kxMâµi“‡ËØR{#¤FMG¶ ØV1Æ‹V 4È'”[l#SÁ¯¼9t™:9¾ÁÊù0h²ÐWñסÚ*Yôw׿"§øOe1 úD ’!@$¾r&(G‹}½ ð¦ÔLLh¬>¥6·þ0؆'»f€áËÕ©ñµ¦ ‘q `Œ@MÕ¨Òßç׋þž†—XôSE`6X.mÜ¥Ž-*@P”ˆ| ð­âÌŒhª9¡Îk{,؆&»% ¸,øš@ÿøj£ÆÉ`HS@ÿÔæÊÆçÕêæ§Õò†eÑ?‘f÷ô…@ZÓêÈó~<0ý… =ø ÈL@_¼ìü¶G‚mpbù™0``¢7³1Ñ1i èEÿŠÆ‚ïô/—ûjýiÑÓOv—f×µw=xWr&\H€  Ï#€ ´ÔU¿Òþp°é¯ ÝªŽŽlU}£¨©|]†#£kâh­=,ŸðïVË_TËê_ç“þøhiÉ·Ú1LgFIàL)™H€(z‹¤  ¿&°¡eg°Mçk‚_82pv@  ‹Øjrcª»áå`Á¯þú½Í –­yHÿ.,g¤_|B€ôÍéÑ0à Âp@¥ªr“²€z%ضuܯF&;åì€-Á}£ªÉéú¥ç5Rh­=$ þÝj…,ø»‚Où¹rêE CÖÉ :L˜c"ð ÈL±°@a^AŒh¬9©Ö·ì ¶é|upv@È×ú'¸ ñtp€5UcÁÕúÃSû«O:8K¦„@d>ýL©B€H|l³€ÍÕcì €À<ý›èÝ ¯ÛÖŽÔèT»›Õñ±MA0Ð?¾Få•>ë”ñ ÔU Ê'û{ÎluoðS}ññÒ’»«Üš53#°¦T 4N€85i 0H ¡útðÛéú÷Óõm2_¯Nm8œßÈW ª—-CѨœYð¿Ü·ÔôÉÐó¶ Ÿq"`Š@“)ñ|„ž¿|œ>€UgÎ à¥@x6}6}Ë«*Õ?¾*8;à„>K`|SpM/q˜ô¢ú¬’Žº}g>Ýïªÿ¥ÒŸøsCÈ‘[ ¸â’¤+¬(ƒDâÈ©iÕ^w Ø6¶î:™ê8œ_'×XÅYñÓÛbsÍ1ÕVwPuÖí ýuûùi>c«ÅÀ,à ³ H`V=M‚ âÒ4 `›@cõ)µZ¾2 ·™[N Ë/ è 곂{ †&–s=ÛŠ;o¼µU#ª­öÍ`±Ü×Tújýú~Ü@ ÎH…¹¬NÊâbg[l­ãFRȿծ¯}eãógzœÊת‰•ó‚ ÆW«ñiýï'n¦è³f}ÁǦšã³Û Õ\s4Xô·Ö–Sø'cîæ@ ~’%Ä„š H–fÍ 0£Œp@ ¯ê«ûUÞ^:k>99; Y I(0ó©™ÇÓyþ'é,´3ÖW¨¦êgù²Øo–­QÎÌÐϳÈ?CÅl8hË@='!€§…÷aÚükˇ*3G@ s|põøººA¹ÀܾsF“Wúì¶3g ŒNu ƧdÓ÷òõ‚ñ©&5!õþ¶ßªsãb2¤êªeÓ÷ruýù碯÷å†N ìwj6nN†Àͺz?+ïß €Ù ädI¯Oc×›þ©¹¥nzñ?1ÝãS á@Ìü=1Ý ôyU-_={ÙôßÓòwp_àïÅ‚ýSxUjR>e—{9>'[µü“¿«Ã¿õ½šÿ÷„,è‡ÏZÔÏ,òkgüúkÜ@À[;JO`Gee`±+ €@ö:,˜Y\Ëið}±(/Ký 8ÈçfüSÒ~>Ö>h {Þ„öÔŠ‘– PUÂ>ì‚ €€úªùút{ýsx3ß«gñïEá™$é ¤o¥Ç0¸>J#‹€ &T1 € €x#püÀíƒ2ÙãÞL؉¸QGïgAàý[@@ vfÐ']F ˆæÇÑP†€ € àÀ÷½›±&p£ŽÞ΂‹z[z&Ž@º¯õ ¨Ã§GÓí4ÁÞVw4©ÝÍ ö`NÓ#SêgûN˜3 GFrÉšÕÚP›Ùlž;xJõÄûK½íjsþ·±Ÿ·Ãý£êµ£±N¾º*§®ÙÔk›4fŒ€1¥({ ap›|ƒ39Êæã€,²Ô§o<xép¿zbÏ1§fûªü#:¿Ü‹ÅÎøä´Òóå¯À¯¬hÍ48prX‘kœ7½Xõ9ÐJÜÿ¿RSMç{Ô°¶^–ñmaãb8¥ ”æÄ^† ðà ÂppMÀÅÅX£¯U¯÷éë8qC@ <ùäXÿÌg”ÇfÚÞap½ic< ($Ãó YÀåňCJp PÀ#Ã!f ˜UFSD€ /#€@e>,þCB€P‚{@2ýO–y »›'@`^MQ€0<• ø´ø•B î@J¯ ɾw—º?û-@`ty\(@Jp±ø¸øáB î@ÊøKÙwªŒýÙÕ\BskÃÈføÞ  ›€Ï‹ÿQ‡úæó•ÐC î@4V¬«úí¯ÿΖß.ЧÁ?eòQõÕûïÈ?ûò%†ÎÓ– „!?hYá|.€/•fž$,Àâ˜`΂G €€!­†ŒcÑaÜü¶Š`Q[Ÿ$°µrŒ›Àƒ"Gâ×?¿åVic{Ôv,:¾]Æz…lʦ¿&3}âðôég~8!¹-&Àâÿ\B€sMx@`q «ö© «÷©½×/¾ÏÚ(@`cÕ<3€EŽaŠú·M?C;Ö6QU­­|Âgñ_˜ ° ¯ €,ø­[îSwýï§òùÜÂøËfB›«çèØ¹ £…eZ¤!À⿸²^ï,¾#{ €x-°våuãå;½6ptòa ?Pã†@æ™—€ `§‹ÿÒëFPº{"€> üú «Ž¶S>¸:wBW+ká¼,,CF kÿåW€ |3Ž@|¨¯SïyÇw|›¶/ó%ð¥Ò†Ï“Àð1<L`ñ_yE*·ãH@ÀmçíV—\ðœ/Óõmž„¾UÜÀùX†„€©,þ£W† º!- €® ¼ç×¾£–uw}š¾ÎÀ×Ê2oC Á00]€Å|"ˆÏ’–@ZšÕï¿çÕÔ0ââô˜“R„¼ 2 ÈŒžŽ°G€Åüµ"ˆß”@—–wõ©ßûÍ¿QÕUS.M‹¹Ì ÌYð(E€±é Xü'W5B€älipAà¼u¯«÷Ýö·.L…9,.@°¸ Ï&(@ .M#`»‹ÿä+H¼1= €6 \yÑSêÖë±y Œ}iB€¥}x5f€˜AiWXü§WIB€ô¬é °Qà×?ªnºr‡CgÌ¥ ”æÄ^1ÔÄÐM €€cY-þÛkUs]öÿY›T£©VU‡ú¶¹GÿÀ¬[MUN­joÌlP“Óyut`4öþ{ZêUmuv9x]†}ÇŽIƒ ¨@NåÕ»ßþ`ÐÇž¼1Ѿh<30¸íøÛwf6 :v^ ûi;O̰K «Å¯,0o¹p¥ª©Îe6>5­Ù}Hõ Œ¥:SC€æúõÎm½©ZÌïL‡1÷>½þS±<¾zS·ê–€ `ƒ!€ UŠŠŒ×@ uÿ3äú“Ù_ÛÚ«zZÓ_òu€ÔßötˆX#†|Àš’U2Ð0¸¾’ƒ9bÅ„xOXü/,tÖ!Àžcƒ Ä_ €ˆ!€oB/ÊœÍ$ ²q§WŒ`ñ¿x9² k«UWsúg,®À³ €¦ ˜V‘DÆC+ð@ÀsÿK¿ÒôâÿÖ‹V©¹ "7@ ’qêyB§ÊiÆd̨£@ ÿ¥±§°ø/­ì… 0#@àÅ;À‹2§7I€ô¬é ãž;x*õ1™tµÿr&ŸtÀ⿜j°/ €@(@J8}OàtyÓ@ºÞô†€×¶.þâ%°ø…¹G¨D€ 5ëŽ!°®df¸ÆÌa1ªJ¾þù-ɱq_=ìòJÇÃq„¶/þÃy„!À#»©¾±ðéŠïYüWLÇ €óÂ@?õ£'oœ÷ C€Ûޏ}§Cób*) ¤ˆRW÷I?ç¥ÔÝ P’€+‹ÿp²q…,þCQî@â ˆCÑø6Œ/‘Ùä+fׇÑ!`½€k‹ÿ° aÐÓZÙ 7,þCIî@âC€›®Üg³´e–@\oÖ° 6T‰1"`©€«‹ÿ°•†,þCAî@’ HBÕ¸6 Œ+‰"°£NŒë\_ü‡)7`ñÊq ¤!@’ºÆ´M`L)ì€=µb¤X#àËâ?,H©!‹ÿPŒ{@4ÒPμB€ÌK`×쪣EÀxm ê– Wªšêœñcs€ÅBÿqjÓ €@©„¥JY½!€ÕåKwðézÓÎ ¬ílònñµPÀâ?â@ B€,ÔSï“ ur;;$°³nŒ 8;`ñoh¡ à™!€'ð¢ÌÑ&IÍ£@stðέ½j]W³ºõ¢Uª£±öœ}x@´ÒϤ?B€LØíé”ÀžZ1R°H VB€í®`ñoQÍ* àƒ!€UV„^”¹²ITæÆQ € €X)@`eÙÊ4!@¹bžìOàI¡™& € €¡!@(áô=!€Óå­lr•¹q € €V X]¾ROPª”'ûxRh¦‰ € €ÀÙ„g‹8ù7!€“e­lR•¹q € €N8QÆb“ (&äÉëžši"€ € PH€ ŒSÏ8UÎÊ&CP™G!€ € à”!€Så,4B€B2žF+†G`E™$ € € ($ãÌóú:_æ«ÑëIÝ@@@ cB€Œ |÷o—.ÞŸ|7n÷@àv}™ € €Þ8_ê»ä,ýÜ* ¨ŽÃ@@@À<BójãˆôâÿÏblÏ»¦¼+9F@@ÀmB§ëûÏå,€MNÏ0ÁÉ$ˆKÓ € € !@6î)ôš“>þM ý8Ù€“eeR € € @àì{àƒr@›³³Kpb âÒ4 € €d+@­B½·J»ÿ"¡¶n–Àéò29@@ pò=ðoå,Ö³e–°2ÁØ@@ì °¯fEF¼Y^¿­È>¼|–ÀY ü‰ € €n 8W×w97£„'D00Í#€ € €€9„æÔ"†‘¼#†6¼j‚À«r3Y@@ pæ=°Q®°É™Ù¤0€é@@Ì 0«FÃYeà”Å® € € àŽ!€µ¼Å‰Y¤4 €” é@@Ì 0¯&eŽh;?Xº@éV쉔,0Ï«§ß8©F'¦J>†@@ B€lÜcêµSÚYS[Î7Cà|‰™ ¤- ÿ¿Ú§ž=pR=üÂ!B€´ @ €T @Pš9‡¬5g(f„Àìú0:°L \üï96Œüäð8!€e5d¸ €þ X[{€KWSâ~솔$plpLåeÏ\I{»µÓÙ‹ÿpvapë¶^ÕP[>Í=Î œWSÓyU]åã”êu®¦LÈ:'±wßeÓ!€|§ü#³–NÀ”&ã (Ñ” D(vCÒöR»^ïS×nîñ*(´øÕB î]8:0ª~øòuó+¼ žÚwB½rdÀåò27ó¹ãC/¾ÓüaÚ1BB;ê4o”ó0–zÈW–Òá5¨H@ÿ#X‡úLnÅÿ¡ApaÀP„{öŸB}&€/7½øþà)_¦Ë<ðF€¯XUê5V6ÃÁr@†ø u}»´[sÛŸ–öÞs›4ç¸@øI˜ëg”ºøË†| áÞE0ðáLÿ.¾ƒ™sœ 0gaø#ýKÜJ (ɦ]äÔ¯Wâï×?¿åÒ&@ܰ´çzPîâ?,9!@(Á½Ë>„,þ]~37ææ, ~4lðØŒ_0ª ÷\ý:@¥‹ÿ°ÂaÀ×Bî]C¿ÀâßÅw,sB °_(lcÈ+%‚ D(vCÊ\ ¢.þCIB€P‚{—\ Xü»üŽen (lcÀ+#ŒÁŠ!XQ&‰€ý®„q-þʄܻ,àRÀâßåw*sC ¸!@q£Œöà €á J„b7ˆ.`{÷â?%%¸wYÀ…€Å¿ËïPæ†@é„¥[¥¸'g”ˆMP"»!à¢À†®æÔ§ekÔâ?,!@(Á}Zë—¥ÿÿÿ6‡Y-þ7tµ¤õ– (C€  ¬tvH§û{!°¿†ÌŠÞ¶q™ÚÒÛVññ•h[ôâ?t$%¸OC`[o»ºb}W]-èÃÆ «Åÿæžuýy= üøÌ 0§2’ŒÁƒ!0¸8 4®ÞØM°tZ‹ÿp„¡÷i¼eu!@è,ÿ7œ·\årEÈË ©!@¦üó;ÿùü?x\X€ ° ¯ à!Àâ¥N{ñŽB‡{Ž †r@¢„…yYü¶á˜ ˜³ÈèQ¿ô»7£¾­ë–Àº’1`’ XèšÕâ_âbùTv«œžÍ ´Εfñ® Ï €@aB€Â6)¼ò¬øO§Ð]8QF&@<„3ŽY/þ/Ïà{Ùñ¼ƒhÅfB€¹ê±øŸ³à”.@PºUÌ{rú 5eìË® à€ôíÅCúlªônú€#ãSª­±6½N ô¤OÁóTú¿&£?ùgñ_ (<Š€ôM/€Ó¼é ~o÷!ÕÝRŸf·‹ö546©öZôµ$ŸÔüã;ÿI Ó6éè`Ùš‡>2ÛÛ‡ÓéÕû^žñ^  €2°Ø_² ô"@ôEyáI dõu€¤æcr»,þM®ŽŸcËêë>j³ø÷±êÌÙ¾Z• Ö‡SëÍŽ("S@ )B€¤dçÚeñ?gÁ#³’¯‹ÿäé,RÑÿF*½8Ô €CÅd*$!@„êL›,þ“³¥åxâq\¬ÿ‹©ðî $ZÓqiý¾D{p°q‹Ê”ˆ[€ nÑ™Ÿúã‚ñ»Òbü„ñ›²øß”0Y€ ±ê<$¶§kÝц -,ÓB nB€øDùä?>KZJG€ >gÿñYÒ6 $R-Nÿ¯€•_¨CðU@‡ú–öOºäÍâߥjú5è[Ú?è’2‹ÿd«yìÐôƒÒÃ$Û‹Ñ­ûù3F—dáàtÀO.4‰ð×+rìýŽ÷öPoKÏĨL€ 27}‹ÿÊí8Ò B€ÊëÀâ¿r»RœšPÃw|èÅý¥îÏ~d!@›úËÉØZó¨!Šaª?Žp¬‡ä×ÊD~׉ÉÄ0 B€òYü—oÆf ”_ÿå›q. D®îÏ¥…{#·âiž¾œiKšþ¨ì¯7oo¸vÓ 2y€yïB€yE²ø/ÄËÖ ”^2ÿ¥[±'> Dªö¿éH-x|0€ÇÅgêD (.È⿸Q±=šëkÔ{/_Wl·²_o¨­.û˜ ˜³(ôˆÅ!žG-@PÑû@Ÿ™üHEGrP @À" æcñ_ئœWªr9¥Cnæ ® ‹ÿÂ6¼‚s„s%<š’}þH›•°/»àg Àð4”. C€-½m¥àÁž,þ=(2S tpÅú.4æ °øŸ‡ÁC(*0» ýˆìø¹¢;û½Ã'Äê§~DŸ=@tCZ@ ˜{°øŸ³à‘„sufñ?gÁ#(]€ ¨Õc²Çg‹îÅEб”*@ÀOý•ú^a?÷”bñïÞûš!¦!@Aí£òÊûÅG€[D€ˆ€Ž |øäá{¿üð9`ñïßû#„!À¢ªwˆËáE_áɲÊ&ã(&àcÀâ¿Ø»‚×}ð1`ñïË»›y"Ž!ÀçO‹Wý_@í€h~| Xüxð´·>…,þ½}›3q xÿ‡üß' íaã)#–€!‹ÿ´ÞMôc›€!‹ÛÞ•Œ»<ôâÿßÏØU8ÃGK`x¶ ¸°ø·ýÝÉø“p9`ñŸô»‡ö@@ Ì þ“G",þ,vM‚mÓ4 è ¦ªJ:=âŒÈšÎ&uéÚNgæÃDHJ@‡U¹œÚsl0©.Ro·»¥>øéS™7@ qÙàÎekÚ#}M¶úÄ;Í®ÿ Û$ Ló 0#pÅú.(@ÀSm«Ú•Þ¸!€T. AÀ·$Ø/-ü_Ùº+oÉÈ#'dTÿA¶ÏqÚ²õá+ÉúÒ: € € ‹€,ŽwICWËör, šÑÈ/e×ÉÜîbñŸ|A’7¦@@@ Y$¿. éàîX̶‘oK÷—ÊœžÌvþôNàO­™) € €8 æS²ý¾LåÙv[8¥Q³ÿûd§-¿µC&°¶t @@|ÅóN™ÿ¥²}L¶1 ,¦dŒ_‘í|ûݲå-³SC$pªœL@@|Eô¸lŸ‘9¿E¶{e›6tþútÿ­2Ö%ÛCÇèü°øçKÌ@@@ÀuYT¿*s|üRÀz¹ÿÙþ¥l²e}{XðÇ2¾§³ý+ż @@@Gd¡½O¶?’鬕MYübÀ Òï˶YÆr‹‘0䯆‚a € € €q È¢{PÚú¢œðe¹×× x‡l·Èv½lõ²Å}Û+ ~SoÒ÷óq7N{ñÄãH+ € € €€q²××øÙìöY šäñu²é@à*Ùô™kd«•­ÔÛ²ã3²ý|ÞýÒõ+U0£ý2‚§[ëôK¹!€ €€¹üoµ¹µad È"}X†óèìŒLBýÕðå²é @½²Ë6"›Þ_oú±ÞöHÇåž›…!g"p4“^é@J8RêŽì‡ fÏ8,Ïêí©…¯ò—K\Ð¥j2—$%Ù8m#€ €@d7#·@ €€ãŽ˜éÅ#ðÕ]{†¤¥þxZ£@H@€°>TšD·ܪ'³IV`²ÍÓ: €D8áXE¼ ð¢ÌL2&Çbj‡f@@ ^}¦ÞOâm’Ö@÷Ü«)3JNà䚦e@ˆ ð=ùºÞh„ã9ðB€À‹23ɘvH;§cj‹f@@ >Búø,i  p¸¸L-^ùdaBZüñ¶Jk € Q@ÿïóßGlƒÃ@/¼(3“ŒQàO¥­éÛ£)@ˆ&ð% éû¢5ÁÑ €€~Ô™YÆ$ ÿÀØ-M}-¦æh@¢ Ê៉ÖG#€þøSkfŸÀ'¤©±øš£%@¨PàÏ%œ?Z᱆x'@à]É™pTù‡Æ~iãSQÛáx@ˆ$ðŠ}W¤8ðL€À³‚3ÝØî”–î­5B@rô¯ò¼KBùrb_@ÀwœïÌJ>pí¦f9öd»¤Ò68@ÊÐãýuYü¯ì#9ð\€3<0ýÊäCrô»eÛWy+‰ €eäeß±ø/CŒ]@yó0xˆ@¹ò½ø¿R¶åËþ € P–€¾âÿ»å{¿XÖQìŒ pF úÌ# €@EÏì?9|éÚÎoÈÁ+d»¼¢F8@–Ø#/n—ÅÿÎ¥vâ5@¥–öáUJ`JB€‡dçݲ]&[WI² €,%0!/~A¶÷Ëâÿ¥vä5@â\°¸{ P–€\°Nø l—MŸÀ @ÊÐßõÿ?²}\þ{Ë;”½@ ’áy" ÌþJÀ»¤½Ý&[{Ä&9@—ô¢ÿ'²=(ÛßÉÂÿe—'ËÜ@,²P§Oï$ ¨•Iß(Û[eë· 7@ïÆeƇe;4»í•ûGeѯŸã† € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €” ðÿv)jòaÌQIEND®B`‚ic11 %‰PNG  IHDR szzôziCCPICC Profile(‘}M+DQÇ‘! Š…ÅÍÛjˆQ253 e¡AyÛܹîÌ(3n÷^! e«(±ñ¶à°±PÖJ)R²ñ ˆt=gf4^ÊSç<¿óœóü{Î|ݲæJ: qíXDŸ˜ÔÊž(ÅOÝøuñÂÃÃCH|åŸñvK‘Ê7mJëïý¿áŸ1ŠÊ…{ Ëv…„›]K±Ò«µe(áUÅÉo)Žçø$ûf4>ÖŒ”>#ü 0Rv|J¿9þíMò§çŒü<ê'•fflDr£¬bôAc>¢âI'!Ù»i#H»œpÍ%W5Gç­e{6™rµ°8ajƒ£= ;:C |ýíW¡6¿=¯P¼Q¨Å·álêï µæ=¨^ƒÓKK·õl©X–/‘€çc¨š€šk¨˜r]ÁÜ*#Púèy/-P¶ ž÷~ày‡Ò,]dråµ8ºƒÑº‚]híêéO*bg4dµÆ^IDATX ÅW{P”×ÿí·yìÑ…-C•@“ÖPB2 3†hM‰¶M#µíÔ6c›Î$flòOÇÔI;mÓÄiþ0ÓN-ZÓÔŒHcmÐÚ—‚/‚ÃSEYvØewÙݯ¿{?>ÜoÓÉL¦gæÜsï9çÞs¾{Ϲ÷|ÀÿLsÙÿNeá/)Û2—üø¿y£íÒ3Ÿ #Å3hx¥è)JêζNV]ë‹ÿ/kÌЙ¿PÁ]UÖ‹4Ÿ«²32CiŠ¡$ h|Ç/«ùŸ²ç=M|èfó ÜLñ³’%;0ðê¹Ùš³Å@%'äoŒ<51®Vè“ñ x#·Â)@P-ÄÄä<¤›ûà°õÁIÌ´]† ZÌØRÑRõHÊVνÊó?'ÖÈÉoZIbñ <|PŒu˜á€.`ìc ¯Àyo­W©o5«ÈH™ÀHpž®Žì”±,§i–ë‚·ŸYP7-d‡ì!±ÑßàƒÐB¥ˆ«™E—ºçãŒÿ{¡ëÁ\ûb×(¾ÿÀ,[8‚¢<¬§pẻvO%Þ;Ÿ‡†·C1EãÅη•/ÞÙ‚Ò*‹—ë4Ÿà.ær@L„Ç9¹;Ñz}K<µÚTÓ‰ç:K솮ó~¸M-p»P[ÒuUlzÝ3#kaéKG)gQy}Ó±•ý9ù/Þʾ8N…Žì"ÝÉx‡ÉTžfÛ¥z5µ)ÜÔ‡Ú¼?!)JjÃà;†JÇi´þЦ¬üÝj{ÿ Ó—‡:‘ïÄdÔ*l¤A/ú)D ÉYÐ-¸ÇÛ+Ðë¹ÝôøÝÿ¦ñWÉj ¢qNö†Ç›‹«øOûߦåi¶(v<ú–Ia¨ì<ø¢1 ©iÜï]C¥â Ñ'¾Í¾ƒ<«–XL©8ðþš`žsÛ6¤1z¦ÏwIlî]€/<ÿꢟ1?¶µáÞmݘ°S^*±¤änl®~W‡sñÛ]›žåš'uc³QƒBaó‹¿ E,ójË<È´Žá~nÏEEdR‹Ÿýù )øõsˆ“‹‘¯2¾¾L³Ùw¥ _2nÒÌpàÁŠ#[…~™»—ƉìŒ!UMZÒ4¼Œ¼~×üS!eBNŒúQàô!ÝQ³ž:f–M[döÖà€ö˜6Õr¦›|Gå.^qÁ-øSs;Š?g×Tô¯ÔŒ~ª(]4n 8Ü¡ˆm•a¤Á!0+ˆh·ß&E/|£‹ó2ñô ƈ€4ÆHl”1P¦e«jm|†‰-¼ƒ ]rÜq­” gšâè|y\¹4¬ƒˆ“)PUÎöeÀ½à2Rí¡K:6jpÛ6¶‹'½ÀÐN`¼0óëøþ®Qï!7w* ¯y—Ðöûœ ÚàÍÜÍ5¹€q¦Õ¼ˆ–M%18 8{­{ˬ¨¾¿~X†±HªX£­’ºÜËQWY³½@Nv¹ïAÝ=™0›Ç¶÷T™Üÿ¸ó]©¨5¢B:E<œè„a¦þùGõ·›WåÖßïÅËõƒÚôÀi Ú9ñ6wS‚ïªçn5Hz®ã0jv<‰çpló†íûRl‘Ü…€X„†Åë%ª¤r¼ú“w@¾5Ëææg]DÃYx÷Ÿ^͈¼ 9M€ë›Mjƒa÷|¯&P¿z·™Æ£ÊWt5 ²¿šø{¢Ü¥d¤®H£û wŬJë_«Â¶ƒåˆ¨NÍ}¿z‰Í‰ÞEøÒO?¹àÉcxÄ (Ú¥•¨#ú â³DíæD…ºÚùWð|ƒ5c²C‰ @}ïÃ;LM§2`µ°:È(çÛ?Â8˜«£©h=Á«Gr±åàBPŠœ&ÅjEKG –v!3mìçûß¾’h'±oˆ!`,'YÐv ü“PUªjÆGc¢Ë£ ±™£È°Oªž@êôüì””g7 Ýz °¦|pxðù´`(u 3ý/\o+¿xÖtœ^€JÐ+"ŠeÂYD,`Y¶¢DsØúe9&Ê2‡mpº$ãœýú^YOê!ŠëRÐûèD© èY@ Y‰ÿ‚¶îa„øEbqÔ,uáâÐ>º>†L»ÕK\8zaÕ‹]èñ˜*n»%SÿÞ{7z»z–NYœÕ‰ä Ô+¢"ÝMa\®¡1›YA±ÛGªf\x/2qÈÚ¸ö¬̑Ž)yi3S‘Çr’˜–ð]‘a<õÂf™SuzŽÞaJ·,Œ•g¾½ý%òeùEšKNè»’˜Ürz·l±b¹+þ Lò’A—#Q¾‚†•ªi©Á³ì|•¨—ã‰K!ÃgñÆj!ï^âê1oü¸P*Ês ™ç<à ¬U帓<Ý”è y EA¶V¦û‡Õcœ*þ/–rÍ“ ¾0ûk‰o¯%èëèãiÊ,x”ÉŸvó¿`ßl¹ý&:49ÿùȺR`f«{IEND®B`‚info bplist00ÔX$versionX$objectsY$archiverT$top† ¥U$nullÓ WNS.keysZNS.objectsV$class¡ €¡€€TnameTiconÒZ$classnameX$classes\NSDictionary¢XNSObject_NSKeyedArchiverÑTroot€#-27=CJR]dfhjlnsx}ˆ‘ž¡ª¼¿ÄÆqtrvsim-0.9.8/src/gui/resources/icons/gui.png000066400000000000000000000056361467752164200212570ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsèèµ{RktEXtSoftwarewww.inkscape.org›î< IDAThÝšyxÔÅÇ?óÛ3çf  AlK9‚5!)B©"*ˆ÷ÕÇ ÚÖ'VŸ§­Zô©-‡­<•#¯x„D*ˆGŠ$Pä>6›d“=~Ó?v6a7Ù öû<ûdgæ}gÞïμóÎ;ø‰C„#tÏ$K?)tw©í÷9¸‚t éZ÷òþ3—ÚGXIô÷Kx&,¶}€Dzðì¥öÒ¦‚Õi™BªSŽ|ìÊ®=«þüRé ‰C5ŸY'ê¨Rݱøxi_ôƒÎ@Áê´LEU—HȈ2 8ûÝ †ˆ(&€œ dlX‘J_H(Á*…*süÆÿ0IQ䨾è%ðSÂÿ'Uʽ >ù¡P$$;ú¢Ô‰ïX|¼tÊTŸ´·ÈL`J¨NlN uWÒá1Óá‰Å­Ñkì5-DëjIˆ8‚A±×mÅù’ý •}ío‹µlë§Ås›Í+-gf!ã€o'(¸{rÊÒîœj'[r¨rŒ—m®¸C„@b6œ&9zƒ£"çÛšªÔC·=T¶&˜žÏýÀ3:<„ˆ}ެ**Z²(·O§ÓcôÚçƒ9ÊC‚ÉEŒ8Mmg 56…—‰ ±s(C9iÏ&=n ý'zK€Qúþ†’ I pÕÈ<©ŠL€#Ÿ¸&ÕVª8ÕH5ÜCcÄy¹‰ÃÛ™{µé£ì 2»¼•ù²Yþ‡•”|t7Ë®ç\“ާ…ýµ1ÒTÌpÓ.K7ÎOµzQtû¢cE½2ë€×xžD0 Ê$h;ϺEj›+^HxŠ%YkÉú¹W©É÷ €’±CŒ•xta:kvÆóBÉì Çm³iu'œöZ†„ L+Xi¥/$‚Rdûp¹ ¬¿ñ×·±ò.FÝ-À-a dÔIϨ'ol ·®¾œoªôT¶]Íþ-¤ŒÚæ³î>˜ùËxËsë€(¿§HXoÙº°K!ç5Væmï‘@wlûò6lÎËx0·ž?åBe/»]Êò®åŠ|o5Prs s6>˱ºd–O#õx cSàöè´€!D¯J·¶^ |u"ŠštrÒ[Y2·”\0ç†VòŠŒØø;'9O»i°kÙT:ë°ãõL»f×Ö®Öô·l]*a‰€eõgf- 6Tð%„R,¤:Á#•Ì­»gí`MîÝhN·]$oà–q0zy×úµùÞú˜®:IÀó9S¸kË´µG³ëß?cæÔíEnÁwwâÛý°`eÛ÷N¿»¦aÀ­¿ŸÕLlê’ nÝÏo7½ÍÞr(}¡~é¾kyaËj4Y<}ÇŒ‹ôò†Â„OËøììHJLëȸòØ_ÿóG¿3?‰~–å÷ .ÒÃ×l1Ý–HG€`ó—ðeE£ê/òyi«7DtÖ»`ÎE˜sydâ›ÜºéI<ªb|~ýÃøàÐ÷B€quJmíL)%¹£ZÑ·|ÐuÝ®ë/÷ÅH O½¾“¢'–óÜ¿Šiwîñ¶›¦BJ^Ða²R>'Ò ªíŠ‚Êà¾y]˜ºv¾”ÒmµCSxg¬ÍûްýÐ ^*9–¼^ã"óÊ6À`èÌ K)!3²/Ž6=â/_>À\Û¿”: ¸<’ž*ÀátùÊ€mTì¾Xß7‹É¾þ…– +Rs¾—ŒÌåÖŽñ—ãÜ¡{HYñ³¸qêUDt8œ.„,ï“1MõÊ~ë%ÐÑiÔ::ãÂ5>$p¾”2”TW$šcx`æDn˜œÎ¨AÝC,Cé; !Ñ æh^„$Ýrþ{u³¶çÀå‡mK'ïæ…¹’U³¾º¸=êf ‘Fc{Ó}1‚ú€*å^£±ó00àÛz×\ÓTb¬y4x*¯³æ_\ß:Üzö–E©fg`F¦âÍ|$òÆ„„íƒé‡Œ¿Éÿl[¼E»XPzêZœC¢×v[ž~gôÅLS€Ý&~6½ÍÀG§ÇÐáÒ(--±ëÛônñ¢K+ç‚ÈpëÜ÷¿|[výgT…E@J±E¹ÀæPX·y/Œc&ŒxÇæ]ÇkrF$ñX.L5,Dÿð·}7ù‹v£ÒÚeû¬®žY—˜X2Í¥•; éñ|ØDH+­ó¤ç±Üeÿx¼ÙÖfŠûë{˜?ûZb#<]+òÉLK&3-ÙW¾Ð”™–Lf„„”Ô c¼{(–ƒç’˜<ú@å¼›òn_Ôõ0W]=³.!a{Ž[çÞ ¤K烘Á›¯³Ÿ½¡Bø@ÁJë<ü£¢qßwãôÍq ­î[cÁ£ÒsTg·¾µ%ð諉DGµ2'û=«@.-Xi×]¶¦fz­Ö¥Òuèoó·dÈIøÒ¼ŒáG–àõ«G£YöV"²±‡@ÆV ·-£©UHæNÛ‚Aß `L§¦fz­SU³$<âÚ}XÙôÑ…îZL‹k0/–ÆSu&Ÿ)DèU¯@/ L Êkô,X5D–×ë@¤¾áCÊÃ1û¹ÙõÀßëºZÔi;¹zÀ¢´ul)»–ܧ‡RúuLG„@8œ /ì»™¬§†ÉòƒNqÐîŒfõ뿦µ-:,Ý¡ Vù«Yý[ÄåxSXškUÚêÛIŠú ›3‰vwêíZÞúÔÄLJëé¨ÛÍÀˆ*bͯ˜s¡ij\.‡ŽVòò‡~5ƒ÷¿™ˆË#„@b{—1ý6ÒLµÍ—q´ÜJêв÷ ‘Žo—ÔÕ…K äÚ†U#')>?øb—{vc•š J…S­Y|cËÅ©FuÑ1E¨$Fž!6nµõ-T· ÓÕu’Mú3¤Çm"Þxƒ)þÝ­ßä_ÕÞ9D£qŸSUÍËÞ©ÿ6/¬Ä&¬W£»'§,•Ð%Ÿt©‘œ´gs®m$Ò.p}à „Ïè G‹ÿ°C{î96Q(IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/icons.qrc000066400000000000000000000011561467752164200216000ustar00rootroot00000000000000 gui.png application-exit.png reload.png document-import.png finish.png forward.png next.png pause.png refresh.png play.png stop.png new.png open.png save.png closetab.png compfile-256.png build-256.png qtrvsim-0.9.8/src/gui/resources/icons/new.png000066400000000000000000000163761467752164200212670ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs  šœ IDATxœíO‹$Éùß?ODþ©žéÝÑj5ì®°@2?ô£ƒÁ`¾È>ëà»/>Ú¯Àºø%ø$Ø×aŒÁ°Æù¦«‹ÆHƻޕvf§»ª23"""3»ºª+«*«ºG;ϓՑ™Uù<ñ<ßçOD ïè⤊0ª˜q›â&‚žû»È¹oðŽ@«JÁ—RS`0*â& |Ðô/ˆmp|„Á‰àçþnïàL”Fv¥¡¢ ÀRb°"4µA0 Ñ (AëÆ£xO‡Ãɇ´@3—vx'3“*¨yE¥5†RÚºP£%B¨ ‚Á(w@U% x ˆŠSÅKN«ÆèÄÑð½^NÒ ï`&JvýŠ×ÔÔj¨éª ¡Äh‰h‰+-¢`E4jI|PP@‚ªÀ£â¤pN*Ž -UÓáY‹§Õ÷Y‹°>V#¼€(jyÅBKXtUÑ ¡Â¢¢b  À«E"{×à•d°âÀ{‡J‡J‡u-JK–²mð¬¥c­ßcm Í¡ßýœ@ªˆ~Á3ž± àŠ®^`ÃB µ:[‹ÑJÅVx*‰P*jÁFýôÓxïÿ‹1æ%@]×ÔuÝ3zŸ LaüøØCLËm§öÙÕd!ˆ›sÐ9áÍ›†¶•êýï—ÿö¶ùû¿ûòL –` Öƒ«ÑªA¾UÞJlÓ¤Dµàæ¦å³ÿö[ÚVÍçÿóûÿêïúÕÄ`ˆ˜ ,Y¨Õ¯ ªÜì†' €ªþSÁÃOúÓ‹3ÿb¤K`ºBdºF¹]™¿Ží¬A“Ѐv@‹ˆ:PGÔÊž¨v €ª)€´D¨¸¾.ùÑ?ø?ÿù+¼“Ÿ`ä9*cD A`ÑhºÙrÛÏ:YD¤‚îÆïõë×ã>;ÏÏçŒUïžûm=žÏ=67KH{‘Û$ ó£`¬iÓ9Q´ésBÔ%Pbl t5WWÅÂÓ¶”ˆ¹Ô âЀb‚Š Öy,^¿Å…€ß'8‹¸^¯ùë_ÿ lgHSñxÆ !œs;¸±S¸€¬Y"oÌm–ˆ,1²FdÈ a…HƒÐ¦c‘ñ"I à“&ð}Û4€êHP£ËW³q”EÇ¢V ªr-bÒõBÍ€ôP¢Á£»{DPƒŠEÕ!Ñ5 €zʲ£®=bÄ' –Ü éÜ´EYÇÏ`EY:ª2¹Á\£>(.ˆv¨8Ó"Ú)´x­Åh­BC[—Z4uÒk8“ Ø|˜›Ç±÷—`üÖ~Ú!fÚ’„ Ýí™ß™¿@䊨®ˆ L&¡iÉ®¡Kñƒ¤ˆ•cRÄ~ ÖÞPUD0\M_NM‡j‡HHCðb+•ÓÒÆWJý s ÀÔ‡:'Žô¸ÏÌŽ ÙL ™ší|ú,u?òEžd°Ã}ïØ~¡º0ŠÐ;÷¨€¦6ªë`´DM‰†‘2@)‚EM¡x Ö"¡PÑÁJÍÿÉ ‰u86óç`üö~!2[1Ñ/’7q‹í1¡é÷Á1%w„@ëÑÈϘàŒW `lûãÈ|¬ëµN¼®˜"Ö—-ƒ11a@(0Q¢ bI(Óx% Œ4µÅ4Fc‡Óé`mŠÇs ³Ê˜- 7i‚QŸ>z§ )ܼÏÂPõî`dþÕHŒ ~Ä‘/É#P¦E(“GÓÄÆ‚/bÜ‹‹J"ȳÄÍ 5šþVÁ˜ÙAÇà€]ÇÓ%4F#£Q¤/ÚЄÌlj›¤F‚61Ç$äž„@Šø²Ú®“<¹"%TQ3?Ì&“V`¸¶Hô÷¼ÅHrÔ`r^ÙñÞhšˆ"ý„”X•üh p×ñ9MÁ”öí}†R­ñ&¢#$¾¥-Wz÷ÅÄ´B/ubþ5Q ("U²ùrøXÇ…!öîµ1é¸3( Ý$ºFÀK¬<¶A4Î=Ò”´GSûs|_ÛÃ}F#\u4ꇾ,Ò÷Wèƒ9ù¿ÄDL:iÌ<‹ô&á½t?iQ]qŸÑ0·á®›¢*:þ;þšþï³b8>f,`ÜW$˜sÒ†^ŒÎ ><·K(2LØãôªùüíαôý•AkhÜ«©Ü¡ È£k †5ª-whþœ/¾¹õ ÷:¨HœkœÿÞrò,nà®Q=…;u¼½Ï6U·¨ìÍ–6“áæÄÎ8ÅÛ3{ðÅ _d˜ê ûBÒñµb èn=¡#F‡ˆÁÜ y%N?VSÎÒäÓ("„‹¤ƒa:£çLUM´ÙŒ·dÏÉm™žmµªÐ—{ k< 11—@**é#|êQ‚ÈBÐÐW§€éúbºX{QƼE„\!¨k Õa3@|htžƒùçs nj̱÷Žåš=Éž :D{†e¦Çê è¥ ½Ÿß§y! L-Éƪ©¨Dc²oˆ::Ð!« ÁÁk–FMë d”„€¹N‚OÇ%LL7ƒ ôŒî 5MŒ¿¤‘ON×JÅÀüÌô¤AC¯Ù|ºèêÝ g-‘ËÌ×`šØ?m’0Ò™à»`BŒõ\Põ‚:4UYñQ7u\‚æÉÔL9÷˜ãûÚ¶·[TsP'OÊ„ŠÔcöÃß–Xs™"³ÚÒGcÅlDø’¯¯¹0{Ÿ´k4¬@’& IÇGZ…Ð‘Ž Æwñ¦ÚèTñy†±¢âUq48˜Ñ ØÿPAâç<ØÞ3ÕŒ4AR LB½e’œ!ìFÌ7‰ù&j~ ÑÈIlò&HZ!«÷vÄüHÆ-T[ºÎ@ Á„6¡ËB‡ªSQ‡j¬a ®ƒà(¼ÇGÀóÑLà½ÇsTQècá€}‚1ŒþQR§Ä•ýߊM*¾H#9…|uÉPÄ‘Á" •€hÂY£hþ>¹&ÐE@òˆo¢`˜q|ƒsF‰óÑ$DR´‹¾¤6(§qä;T: ҩ҉̨âC{ pžX@.Ú%tRj7úéqÄK/ iÔŠóþ¤Fz¤Ÿ :È#ߣ¹hDs‚nÍîbÖ"´‘ù’ç6¨®èœ¡mñk4MR@‚6bóUc•Õ/-y¡Õ°âØÙ½€§€ŽŠô oF#¼DLE´ÁUDäÒË»r)W OâˆSÅ ÏôÙ=GNìè0Ž#乄9”µÁ ï-mkðÑ™[cüe„Ô)¹†–à[ÑЪ -^:]Zi ˜Leê6à”Hà9\BÕ¨ê#Ãã–‹DÉóüîMóŠŒVÍAš5"˱âCs!Hr+d¤ X%]giZ¡mLXXaÂÕµˆ6¨4hhD´Q+zi1´”m+M`Î kƒÍ‡ûTLÁ”ö!Y“–Fùûa¤ú³$­FZH,h‡È-qDS»æ.ÿï„’“7 %"yVÑçnhCÓ*hX"a…êZůPÖ]Ç¥cÂZ½DûQ¶ m¶%]$8~¨»þ>䨡}÷µín/ˆe[1è’«…ãç̤œ2†œ V„œŽB0v}Òùú²a’¨ wŸ¡ZMÐÕŠ®+X7†®C‘p‹†¥ˆ.Q]XbÂ* Áë×8³Ö¼¸¿°ä£„ì£K0¯KÈ‚Xø™Õ}Dû=ª'ýþ4ò‘ÄP¢}Ï‹< e:¿Jv~œé‹w‹Z¡JÆ @¤FuRѹ’¦1¸MÌ¿E¹Eu‰Ñ!¬0a…õ+ñf¥e³–¦_Áâ]djXÖy1ˆ) oæÏc ,"W)È“œh_ÂÙ•m#ßÕ~—@cºŽŽ4ȽBb~!† T‹XþŸJÌ;W±Z ]w˜/º$„[1a¥Á,!¬´hWt¬ô{¬Í–ebf« Þ¥¾úê+>ÿüsŠ¢à‡?ü!?þñï-ávŠ[x —PµB¸J#>Ä{Ñ‹56Q„>äK¶ýI²ç .Ö<°@DL,¥¤D  ZW(%m[°^[œŠúÔ¬w‹†[LXi[Œ[‰7K…5KÖæÅöUDÏž øãÿÈ|Àõõ5Þ{Däߊg°ß\õ`Op“éÓ~åw?‹Eµ@¤CÓüÂG$ÙœêèZÃõ¢ )cºXj4•‘w®¤i %pƒq«—¹Åú%Î,µhV¬XÊÇÛׂ3…‚ão‰O¨ª*>øà^¾|IÛ¶Eµ–õzýäCÆwûâü~zæÇÎ8ê‰A~Âgç¼@ÄqÅÍÑŸ«‰²¤ebR$R±QÈ3 ¤mk–K‹ó€ 7„°’<ò­_âeIÙ,¥aɸ•–Ž=;üä“O€¸Ôb±àûßÿ>_}õÕÖ¾Où[³„<©ýŒø‡„ÏP œQöå³_Ÿ\ÇŒç äÑ?Ž0–<¡Dµˆ& I@ô&ª}³Â¸%ÎdæßòÁþ%cÏž øä“OPUž?Îûï¿Ïíí-]×½ÅA¢åù€ôÇû”,ŠK7ˆäÜAÎŒGIèèÍ€Mf ¦šU¯’¨é\Íjeéœ*!Ü`ý Š´T¬4,ó݃?” ÅŒ1¬V+V«è…l‚¾©¡àsjƒ)í ×ô…!k¢Úo“Û™ŸWSòÔ±”0ê]À Ð!ƒ˜W CÊhÿÓúM[³Z´-ŠñoÄ›^ÖZ4+Ö¬øÛMÿ_ríó¶ô¹f_ŒûY”ëdïbWK?Ù³Ï÷çøŽŒ‰Ô<ùBï= # X0Ì',躚ÕÚÒu€3o´lÖknXÉÇ,²ù›4ÜFǸ\OÉìï#$´göÄ=õα٠Ô$ãª^†½H²ÙÈéhƒr…ê3‚¶«X.- ŠmÞH“^ñþá/Œ¸X(¦1{ß9‡;æø!ßm :1>Weæ·£àO›²„)tg•ÐÁÄO˜Ô´Bˆö ¤í ×¼Öfâû6él ð˜ðïcjƒ©í»û%Š;‹DÓ‘'zÆàÏ]Ð8À¦ ëäÙÄ%m»`¹´¬Td·?…žL2hÎ|Áe\Â]T¤$Nƒ@Ùþ“køS(yÔd²ä|ȪW %mwEÓx¿äOø¶'Ò¶µ÷7é\@ð陂1ÅÊâ8ó7×ðo€À;8 ¿!Qõ ýÌ`)¢v‘BÎ'}·Î §Ò6·p[Ÿ)×™ãøÔûMïŸ]Ä<`Æ¥_p7‘éyNBÊ2ös]çtºøÄ)ÌÞw]×rÞ¾{žîL97ƒŒ…âð{Í!õ¦Ð\ x:¦`?¯=å9Îù¼g€CÞ1£øØ>Çß×vÊ÷›*§ÒÙ#§Ð)j~J¿¹¨39ÇsÓÉB@äþŠŸsŒþ}ôq‚©}9ÿ 0—xr Óæâcß×v*MÁ‡â„©tšÿÆ4pèh¿´6Øwü’8`êýþæ5À˜Cìk;¤Ï6šÛÕgÎg}¶’°L‡FçÀ O%_0õûžÝ¶ö'ç>Í)û®w.S°ñŸÓ=©tðcÅ v›Ò6']:g^&(‡ö9Å%<¤_¦©‰°KhÖG—ˆœ+_0õþSÎ݇‡6ÛʺC³‚ÀCŠ˜“æ‹Ç?…ö Ã>Ð|*ElË BOML½Ç®¾Sø)·=)7ÿB›?tn)¿„68õÚ‡º~çÒ <„ËSxèxn;õw=Ïãì PUùòË/iÛ–?þ˜ªªî´3ZO¡S‘ýÜßï!Änûˆþþ÷¿çõë×\]]ñúõk~þóŸß›>•.¡ 96å;f:ÖõÛ&s áÙ5À«W¯xùò%/^¼À9‡skí$!x mp.p8ž›á›tvøâÅ ®¯¯ùè£X­V\__ÓuÝVxlÏáA¢]t¨ê?—œþä'?¡( –Ë%ï¿ÿ>×××8ëÙOq­Îe‹§›óÞ»®÷7ß{ï=^¼xÁóçϾùæBØ?‹é’Ú`êýOu ú½U påBàÍ›7g ´Ì¥ŽºÞ¦à˜¨ß¹…àd—/9åÜK‰.}ÍcèÑà\AKiƒ95Õþ?i/à8÷9hNÓqŠ6˜rþ!®ß¥èd Ý)?à&ÎÕwÊù©í©Â3Uõ_ÊÌj.19d®¾ûÎ#_0õ^‡ÞsNšäý¥ÁÌ>:ÇÃ}L¬2=ÊÔ°¹lÞ¥€ä\ù‚©qþs¦Ê7éd ཿøìà¹éÐ{¹{̈ß.šÅ\ŠæzXsNÅ)áBq€Kü sEíâŸû;BoE$ð©Ò” Ñc'{öÑ,ÙÀ§àžã‡ªæS´Ð[8>•‘p*E|,šÍ<%zlÍ‘ÛOM_‚fóžš<&mb€§Lï@àwœž4|[is–ÔS¦Gç §ð]žÚ3ÙE“ ðtÌÔ­KM÷:„]:÷±ÐcÞÿR÷žÕ xñÀ!ßußÞõÛ·*Úà"éàS§‹¿mô6 €· k.æåÇ^û’÷˜JßÉ8ÀÜßuêïŠÏéQàÀï1Fý!àÔ{ÍE§€EáÑŠJž*JŸ ˆŸ‚68†yñHp\…Ì”ûØtê(?tdïû.»®·ïž$D>T9˜ñŠÑ–ßhXxïíC DL¡C<ˆ‡<Šs{»®È}§š‚èŠ;¯$ë?O¢)`R¿ü>ô;›ˆlÕOö Ï¡ï:–)÷9&B8õ¼‚pçµdýˈò«J÷Ò>0 ¯¼Ê0„2„`¦h€CGÉ9úC‡ÁfŸ©×?öÜD5ãó›§Iûô¾ÚÝô#F§}5ú»$ Àæ.Š‚²,w>¤Bÿ­^‡v쌙C /æ.ß>Vøò3›"\œy" Œ¿s*{4ÁC¥ªØ²ï… ©¡{‹>¼÷Þ{;/<6§¾sp=EÓ§Šlü¦rÜÄðRÂñË w®ÈñÐÓOïDO/³¶±º1ι×MÓpss3éˆƘ³0ÿmÍIL%UåøÞû¿0â÷y•ÿÞIS@ lùœUŽ|óÍ7Ÿ=þü_¨*¿þõ¯ùÕ¯~ÅóçχÎ4nÈzŒI$sÒ¶ßå½ç³Ï>ã‹/¾`¹\þ×Ô´É6Žï¤‡:ŒÁ_õÀßÕ/ùËÿpuuõ/÷ÝìÍGιÏûÛßþ››››oPGÿÊò;Ÿwº…vWC¢±*‘Ͻ´ýéOú/_¾¤,Ë¿3Æ”».öŽf!wssóŸ÷»ßýûo¿ýö5‘¹™ÉncËoªÞIûTÄÄÏnw°ìb±¸úä“O~$"`TU‹Å_×ëõ‡ÇýÖï4)€ˆ €Šˆÿúë¯ÿüêÕ«7Dw ÌküwË&Øî2{,›^Á¦/šÁÇ7ÀËI?ùÉ3øð›¨~3ò7ÞÆ°7"8:û0öƦ` ÜN¸Ï;ºK›yàÙ/{@™¦æüÆ6;Þq ¹Þ À14åþ ÜÆÇ•¿IÇú8ãÿ󅨮¼Ïw™\Ú+÷`› ô˜ËÉ«þlû³8bÂâFÛ`SN¦KE9Þª•HžÍÂàwôޤÿIô‰|Umf8IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/next.png000066400000000000000000000070671467752164200214510ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î< ´IDAThÕZKˆ^Õ–þÖÞûìóúÿªJR’îÄ6=I‚´HC&Ì$ >0‡NDÈ,Nî$píIÀ£†4NuêD”€ihÐAÐ ‚ö¤éŽxc¬JU¥ê?¯ýX=¨½Ž§*ïmzpí ‡ªú³þsÖã[¯ï„˜ÿŸúk+ð=fúi‹ßŸqÀ cæ ŽQ~öìÙ¿½víÚŸyæ™×´Ö‡˜Æô}ÏZkRJ±sZkh­B@H)…#bŒðÞ#„€£ÜD¥v}"r µ!„"‚ÖÞ{(¥e¼÷È󜻮[ÿþûï?½råÊ¿Ñ}fY<ÿÔ_|ñ¯Ï>ûì?=zô(ÃÀ¸m[”e‰Åb™™Ê²D×uˆ1"Ïsh­Ñ¶-œs£RÎ9Cä0óÔ`dYc œspΡ( (¥ÐuʲDr×u¾ïiyyGŽQß~ûíG¯¿þú?ø…™ƒ0pò‡~ø÷aªa ”â¾ï¡”â¦i`­EåÌWI*Ë’š¦a"B–e4 ÃÀÆXk‘ @‚{QœˆÀÌèº`­E×uèû~ôòl6cçŒ1RØZ‹#ñ¾Î;5@É—“Ê9Góù\yïQ–¥JÉGÖZjÛ–slŒ!f¦¶my†1i§ B½Î̈1¢i03²,Ã0 \×5÷}) DÄ1FŠ1²sŽÈOu#v¥&êº&fÆ|>WD„¢(ȃ#¬µB ¾ï9Aƒ$’É8Ó!1¬ïû1"Þ{ÔuM}ߣª*8ç`­…÷žR"­5†a ©cö@Þ{"¢±ž33”R4›Í”RŠªªRZkʲŒ²,“h1꺎ŵ#˜yô8°ÛĆae4ÕzžÍfhÛyž£ë:dY6Št„XðüÚ‰i÷™ I)’J‘úʲ¤€cŒ\–%ïìì0±RJ ÃÀ©†Sê°$ѯk­¡”BÆäyÎÞ{Ìçsjšóù]×q*×l­¥¾ï€bföÞ „Ob qŒ‘eTPJFäyNeYªº®U]פµ¦²,)ÆHX5„06&éÈâmf†s©r±RJ"€º®Ñ¶-cÈ{?&-3“Ö ÿ{Ît˜S¢pŒQ:4BÐZ#Æ­5²,£¤¨b渹¹É©´Žõ| ›ÔÆ(x†µ–SNa”e¹Gù#åyަi¤B±Dvêxƒ}gŠUiù Óøê«¯°ººŠÓ§OÓl6#°±±­µèûždøöíÛšˆ°ººÊâùñ¡©Ü–e‰ÞyçüÞ½{ Ž;ß{ï½NpŸe@–e*3F@a·ŒÂ{Twc›“R —/_ÖÞ{\¸pß}÷]Ìf³±*¬­­Eçœ$>øàB çž{οúê«^œç9¬µœç9Ò´Ëkkkj>ŸË}TÊAˆ¦™ !Îó\‰¾ûs€ˆˆìÁ¾Džçøì³ÏèüùóêÆ˜ÍfêСCúðáÃ:Ïó±ò¤ª…Û·o›÷ß?ÿî»ïXk¹ª*k­9Æ8N¦ÆdY&—²ÖR§U]×TU•Êó|ì¼D#Q\æxʲÄöö6._¾¬Þ~ûmRJÑÑ£GÕêêª*Š‚öË}úé§ö“O>1iä`‰¬8KvŒô,*Ë’æó9ÕuMeY’äßo€ã˜p¢¸$¤`W.k-f³nÞ¼IçÏŸWŸþ9;vÌ=zTk­i¿ìòò2îÞ½k®^½Z|ýõ×:Ý—ªªÚ#kŒÁÊÊŠZZZ¢,Ëh6›©••šÍfª®k’!ð Ta´L”NÆ‘xuzUUfÆÕ«WÕ¥K—T]׿øñãæI²ÖZúøãók×®Zkµ¼¼¬§²J):tHÍçs%ÑZ“4PkížQâ±*4Qzüs:ÖZܹs.\Po½õý9Ùµµ5uåÊ•ü7ÞˆSÙd¨q(O·»éÙÓ‰¥ÚHöS.²M=éHÙýðé,Ë¿Hö£>RSÙô š–sö$7ÇN<}íóüôv¿•’íÏÔ#Fgüod§y—®q‚ž¢bjÉxö 23¥iqœ÷ëRJÁ{sçÎEïý_${áÂÞ/;uš8u:`NÏB$ÃØ$TỊ̀ן!‰9¯½öZˆ1†7nä¿%ûôÓOãøŸ>}š¯_¿NS‰Ây?ýKéµmËB@š@Yf˜ýJÉàvþüùpòäÉðàÁƒXUÕecŒxóÍ7ùâÅ‹c/˜ÊÊÜ@ŒŸ8öÀqš‹†aWº4Œ±÷]×±4¹á0 8~üx|ñÅãææføùçŸaŒ¡¢(”=qâ_ºt‰O:¥Ô¸Ne%é{tP.<)j±X Æç/ ™B€0rƘq4~饗üñãÇã½{÷ÆQº®kžzUd_yåòäɰ¹¹IwïÞUO=õ”~i¦p4Òç÷Gñ0 <ƒú¾—1Æ ÀS§NÅsçÎÅõõõpÿþý1ìóù|¬""{âĉøÂ /ç\X__Gb3bŒ«««j?ܦQ0îÅ¢ãtÌyÌ€¾ï™ˆ0 œsŒÝ5“_I/^ôyž#˲xÿþ}3„€º®¡”â˜/¿ür¥T|ðàA¬ëD„®ëxcc#éqøða:sæ óÍ7gΜÙ3~Oá3͉ƒ  ¾ï%ÑXšÄiRbÂööö¸ÏÊ š¸Lž,DhÛÖË5ŸÏQ’AhšJ)&"!àòåËqiiIœs< ƒ(Êi¹â}õà$ž|Ø­FLD4 33u]‡ô‘9N<Ð¸Ì Iåœ#YÅ15"âÅbAÌ™Y…¸m[È`7Ù ©” t„ ÇAI,ÞŸH”öZYèǶÞ÷½Oãd<†¦c¸URTåþ‘ˆT!.//«²,Q …˜vgŸ“sŽSu!™¾ƒ‰­DÒÒÔã'ቤkzï…1à1¤Ü‘J6>$\l­¥äINä/;çØ{O’àÌŒªª˜™Q×5¼÷T ‰<¡U‹ â) —TaŒ‰H¸{–QXX8yeBàiòMv""NÄä>‹Å‚f³vvvX"B º®yªªŠ¥òMÏž¥¾,KÈë$ñºT˜ä!È{ÏB£'ì³÷ž%J‰„’5Pz DµÖ$ýDÞÞÞ†Ö>dç‹?|ø1FÞÜÜä¶m§Óèãt]Çu]ΰB7Zk…üe­5…„EC–e¥$jÀØúÃ$œsŽÓ°Æ‰û$­5?zôEQ`ccƒSä_~ù…•RØØØà®ëøIÄÅb±HÄ*‹ÅÈÓÇ9±Ñ#~Åã’¬Î9Js“42Á7÷}ÏmÛ¢ë:É#J¯«8½k#ç·mKZklmmˆ°½½ÍmÛ~úé'β wîÜi°ûÎx=€­[·nýWâé¹,KìììH½§¾ï9íªÂ ”¨ï{îû^˜é‘¨’*ÏsE"BÛ¶Ü4 ËK¼½½ÍY–IXe×uhÛ–·¶¶eÖÖÖøæÍ›ßØJ:IÜøÓ—_~ù¥s®>{öìßi­«Ã‡Ë >Îó\IiµÖªÔy9½&iVÂHOû‡ü.F`§ÖZi­yggÖZµ´´ÄÛÛÛ¨ª yžc±X`ee?þøcsëÖ­»×¯_ÿ7J:/º ÀQÿàü=€eü¾Îvÿÿ àgI")‡ü v•·=ŸxìqÀ3ÿZ¦‡ˆ v¡õ{üÏž™÷4‚ÿ{Ï[µÞIEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/open.png000066400000000000000000000124751467752164200214330ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs  šœßIDATxœí{p\WyÀçìû¡•vW²ü2‰mœØ‰­Ä&4h$@I€&3¥ ý£Ófh˜BÉÃü&SZÊÐét:%<š6@ ah'%%¡$ÐÄxŠc'¶Ëò3²VÚ§öyNÿØ]í•tW{µZÉK|¯îÞ—öûÎ÷}ç;ç;lllll.RÄ…~›ùÑ»¯7à-æ÷ ôMñ*JÞ3tÿèa«çÛ Ð€K#¡¼O_.5—£E¿D…ÒÝ •'ZçµÐÌ#ÔY'4œJ½îÌËýGwÆ õl½ûzž|á))¹¾¶W™pz.=÷™si+×°`«¿Ô³T– 7)-Þ¥…¸AÂê¦/¦ÐZrÅóBð\ÑS|âä§±VG.õ¸(+>¿mo» ŸÏǹÓçØ¿ÿ@ùr¶0§O×&µW~MÃuFÍw\{|ø£Þº­»RHDõ§"|!ÊÛn ÏrÝ+” šøH‚ÑÓcä&òå“·H¥n^µ'ü°–rÇð=£§§_õàj¯ÎÇ0)|Ÿ—mÛË—TÜQ\ л¯7à-µâSB2Ù¬½n:Wñ]󺾨 _È)—†ý²²ßå,é릷¯‡ÄhŠ7NŽOƒDHÄ£J·¯Ùþëã—Œ}™;(AYøÂ›|L ß àõy¹ºÒòk g+€)«w‡¯ùÂw¬©~GÞ›®•AÜù ÊÑ÷¤ÉŸ¶-̶ V"ÜÝI¤'L<–`øÈ)&2Y@úì]},ò>ñu§34~¶˜I~¸ÊÂß¶}¿Ï?MÉl˜ŠF¬Þù$‚}ˆòßépIºVuˆz[r‹)¦ƒ`ê~iØ/§Y !áh‘h˜s§F>vŠb±ˆ€ë””Š™Èo€ßðz½\½}¿ß?M±¤mŒôîë øvç¾äÃÕ}n/áÕ¡¦}ütª-YZ·4DN±3]„3•bùÊe,éíæÈ˯;?†”t2)|W½m€€ß_;oRÉš?È–|mĪ=a_±ðŸHùa(Gö‘þѵ­~ÁΦÒ‚[ðx–+S”f¦b5Ç›FÖîë]R,æ~&‘ë\>'K6„q¸f °)’MäÉ¥ &г¥™}ó B\>.¿OЯӃÃë0íÔÙžáË JíŽò;×wÏØ?Å ”©Þ °lp™¿XœøaUøî€‹%뻦´ÞÂD‘ôù,™X–b®dùÚZkò™"ùLù|—ÏEGŸÎž .ô»7½8UYf„“-ÚÄ-̶]U¦fsz¿ý ðï8<Dzß¹*Âßžô÷ÙDžÄ™4ÙxÞôt> â°ÐzHè€ ­èAÐb’5Õs b'⌠'èèн"Œ7è©ë׫!Ûd+®ç"¦µîzÊ$ÍŽ¿X`õ±Ènà6(ûüžu]H‡ 0QdìDr†àêZþÀ!Ô nõs«£sý»–ô"‹×+­ß¯µ¸UJ:µÖ$FR$FRtõ†X¶¦‡Ç=£u7rÖóõM¥ôï‰Ü¤áné”ô¬ëÂá”ÄO¥IœNOóëúi´ü»žèø_¼‹Â\ïõúýoœí{¨Ï's¿ÐŸ®?— y>Ųµ½t/ÎÚÝ›¾ßÌELɺ{ÆÀsеi2 ü­U€å»;¢Z©o Ë~>º6„tHΊ‘OÕä«Ï Á_ß1öÀñÜûä§ONßDó­þ½]ï/Á—%r]©¤8yä ɱ4ýVât9꺅êq aÒ´]„Õø¡ÉnàomÀ%\_GÊåÁ%>¤SröàhMøŠ1ºshGìúã;b/,ÈCôë÷?ÌŽoBë{•"?ŸàðKGÉOä§ú~“î^ÍÌKö!~°’Gh¶ù3O  5â™Ï3·1ÓyðÎÖì ¿Íí.¯_—‡7^C—ª&_¿TÔâ'ï?Å} ÿ\/ï$cöïézª¤yT ¹>›Éqè¥#¼uË:Aÿ4!Ï®º{F+1`64uÖà rÀµrRâ/¤$ÐÔ›B½žSòŸq%¹ ¼ªƒñ“©ÉÙ8ž dðòΑÔâ=Wµ{ÃE%þM Þàr;Ù4°Ð_3× "{³ý3c‰©®àÄð ž}áÙòw0‡ùM¹€çÊ»Aܽ¸Âý¿ùïW…ï ¹IœÍÔ¦biýµ¡·Än»PÂxíÞ±xO4ö{h(ä‹Üÿ …|©5Ý=ƒë˜žPj†9»€'v­¼N—Äà tñ–í·7uã¹’ËŒqôùïò_Ž‚ ʺb®D©2ÝJkýðÐ}cG0ûļEàÅ»(Ü0»sÈvƒøP.›ãÐÃl¹z3BZëîÕUŠ:® Y0'xj×Òž|Iü«”8@pÍþ ÑMMݸ„ÃIüùʺjFO)òÞµƒð«ü÷NŠË½wz¼¹µÀ•‰ñ$Ç ó–uý–º{u{uòMÊߺ Dµûa)Y°ùæ/ªð6\û ®ò†§ï×®â‡Ïì<“YÔ‡±À:ÎäQêXõ÷SçQ%5ïîÞôýÕÿ›Á²(ûýò¬”@¤‡èš•d?oê¦óáK·ü)Ÿ}ì+¤@'Bõiùçß¾;v¬ñ™‹ËÆAÜCîð#HñA§ËÉ–Í8®yu÷¦n•¢9,)€Ñï;\n6Þt+ª4‚²>¦Ò2"á ÷o»…£¿x@jÅçopý“·ÝóJrñŸÆœ¾‡ú|™\æ{np¹]l¹ê B¡ùw÷¦Œ'Ô\D³©À†vã©]K{´P™L¹îÚwãïŒ4u³V±âòº×\ €¬ùÌ?hÝt#h){‚Î|úGUá{ñ:#™ "Ýa.»b#BÈò¨¤ˆÊ¬R„FPY¹cÚ~Myq „@£Ë“+h4Zk¤…@h*ç‚Ðõ…¯”jêo©ç&Ó*¢}ÿ…Â-j_vìüÏ>½ø)ñÙ”,¯<Òд»ÿ¿ܸ²›A?§Rm7þ„Fýêø¥ãÿcõxs0 «j•o6Íü¦%à„GnÙÆ· q:]ôû¿‘ ›Ê£ú…ïT÷kÍ!WN~µº®€,Y[þ3éñÂ_ni~±ùpà™cœKŒB}÷³çþh>×2ïh­«Ý ¡s-ÓÓóÉ»îzq²vÎT”к6ËÌZ/àµßä8ytñ»D6ÖRz€-{cä5àËÕýSÁ:•ÉÖoœ*‹Þ@˜576ûœ6 V¼òÜch­QZÿ.@h9%ÜÈ( ÉXÙ/-ë5\²ýÏZòÜ6­¡Tãð³ß@HqÖø™… ß0HƒRå©Y‘¾õX26‹ÆDb¸ö‹f¿ñ3s 0%PlxƒÄX­@¸”=B>Ñø›Åãì«&·º±±Ò–±š“ðøÓ” Ç­?Í‚3:\~€Rh<þÆÏÌÀ˜°@@yÆ+]À`W ²dŸmÚ…R±D&^™·¨f€0O ÍrÙJ ÒF+´Øé±”ñe’3ü?Ô†¶2ÀÚþ¿ý˜¶Þ$Æj`G8`÷ÿÛŒÄh-ç#œ®9(€E[7¬³Œø±-@{‘-Ëjˆ}àž×†¹wæ1ÇfQ…D¥ èùpº$v }ÐJ“/€õ’¨Ó¨æêQÈC&]>&µ[»‘ŽgP¥²L´¦æꦂeÃTpÜèÿ#vÿ¿ÝHŒ×J˜™®ÒtŸ’ôµtª²ÍüI@HÇÀÂppb¬¶Ýñc[€ö"+û¥Hç7 ©w\Ó znÜ^‰´UR0«¨ÒpJ˜Ö‚é­»T„T¢:ì›ñ¹Í…%“ÈQ,TVQ§~MZ€Ä¸œì†"¾–+ÚÌŸÄhºöË,=¨W¢Ñr– n˜Øñb[€ö¢jþ´¦cUš³†1€Î¨×î´ÉÑÊ0¥ ùRèàlÇÖ‰´ží ÕÐåqà 8±-@{‘ˆ•@#Þ±óåYëûçœ VZ¯d#^ì追ÈfŠä³•º 9»ÿ+åáÓHÅË•À¡¨íÿÛdlJ±ð¬þšˆ¦€nl Ð^$F Pg€‘9O KÆBÏÌl.(‰X¹D_)t¾4q Áás·ã£Õ* ‰¿ÃiçÚŒähY¹ÃÂûÍG•ÖÂ$ um  #ìFZY:ÄfÑ(äér(Lj̘“ȤÅbµ`ûÿv#a5ý?ÔëHY 0ì7€¡¨Ûÿ·‰˜á…²þ#s² 〈۴‰X-çcVd†¹(ôäë¤ ¼j„»ì `»‘¬)ÀðLª€Ì˜“¨ÎêèrRö¶´ ¥¢&˜\ýÍRë‡z½9³<<›ä+.&qÙU@mFj,?™¶×Úšÿ‡9,3¥ Èöÿm‡Ñÿ[ÉV©§3š·qp(ì´«€ÚŒÄè¤ùGé’¥X© ¨È9Q©B{`»U@1zÛçNŸäsÖγV@‡‡ì°}Ð RãÕ!`µ¿^uÖ F_MXÈÁDµ (âÀ~{‘Š'‡èg«2ÃR8ÅÿGØæ¿½HÄj sji¾@=,M1*@gDÚsÛŒD¬Rr¶Ö k T@Û´ñX¹@)ÒûKÇëV™aa­àšðnØ Ð^$*+µK©ì|`n湡(• ]©ê K éöðÅÄÄ„¦T¬¦g¯0£Nq¨˜ŒR CPÈÁDÜnýíD"QkðJÈ9ù°`R†•F}þ™u‚6–LÊ`ñë,7 × ®Ö€ Ú¿—{®·°YHRGÿ(Xª2£±HT× ⮚ûÚ,Z1vî—åmÉoîx`ö* 3æª`dih;l'r™8¹l58· `•† šbtËSÄ>ÞÌ=lˆdÂP¾!Z©&ƒ Á°Àö"cX`.sŒX ìZº·«™[Ø,©#g€’å* 3,­ìñù -˜­bÜfÑÑŒ=€”úÕ;h\d†% YÚ Âj'Jù$™de°ÉêÆSˆð{ãdÎü¢Ù{Ø,éd­Äj–,€Ï“¦J7>ÐfÑHŒj¨oh ëÔÃÒ|ÀfGÚ\(’Æ1‡µ* 3¦‚¥Cгñ½é0;Ôæ‘úõÓ@ `øC;N6{Óv- {Ã=A[øm†.‰×ÖlºõCÝuuBT|€tJFNœ˜Ï=lZÌD:S{Ð<ü?ÔQ€’Pÿâ,‰‘Â1r2ÎÈÉy)™Í¢„øÙ|Î7ueŸ¢? zΣK6‹ˆVÿx뎡gæs‰Ys{OíZÚSPδœ÷ &mZ~ýÖ†ç<þoccccccccccccccccccs1òÿ®Ú{³÷é^IEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/pause.png000066400000000000000000000064111467752164200216000ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î< †IDAThÕZI‹$×vþÎb̬ªV#¹½°d40HÞi¯…Æ4h£"0Fk­ í?á¥ÑÖ`@!ô´0¹M= µ©®ª®!#âŽÇ‹º'™Õ¼xò…"3#oFœá;Ów‹˜ÿŸ—úS ð]fùˆ4€@…ߟr€01s’‹³DTß¿ÿÏ>|ø÷¯¾úêßj­ï03Œ1pα֚”RB€ÖZk¤”RRJ!猜3bŒH)!ç,÷A©›È>ÐZƒˆRAk#”R°Ö"ƈº®yš¦ÓãããùôÓOÿ‘ˆž0³bf±üË_~ùå?½óÎ;wyy™½÷ €ÇqDÛ¶Øl6™™©m[LÓ„œ3꺆Öã8"„0 B QD3/†µÆ„B@Ó4PJaš&´m‹bîûÎ9:<<ÄÝ»wÕwß}÷Ï<ø'ÌœD€·~úé§óÞwÞ{(¥Ø9¥ÀªªRby3Ïž©ª !8çæ¿#…fÄ ZkcÀ̳‚u]#ƈ#š¦AÎÆBÜu¼÷Ô4MîºîúÝwßýÿÁÌׂs à®1f­”Ru]SŒQ5MCÞ{Õ¶-…(¥DMÓÐ0 ˆ1R]×*çLÃ0 „@UU‘µ–Œ1JkMÌL^¤”"c MÓDÓ43“1††a ÕuMã8’1J)圃\«ª ã8*cÌ!€»Eæ9P5€ÚZ«Šu¨ï{òÞÓÁÁyïQUÕìâ¦i(ƈq ”RBQ DÄDc ´Ö€”ÆqÄ8ŽH)ÁZ Øl6s|\__£ï{N)‘RŠ1$𚦠u]Ã9Gê"ó¬€XŠµÖªë:J)áðð¦iÂÁÁ !€ˆ¨ª* ÃÀUUAka˜™Q×µàÎ9LÓÄÃ0`G8ç pRJÁƒiš0Mªª8bµZaš&jšFŠ[kQ<Ñ,ïR@ŒQ,C«ÕŠB8::"ï=Öëµ*PÛ¶4 ¬µä½gï=cPU Hp/‚˜Ó4ªªÂ4MpÎÍV^­VB€1F²WU…œ3ñNå]* ˆˆäÇE B õz­bŒhÛV•࣪ªhG!°1†˜™Æqdïý´ËN)ÍVgfäœ1 ˜ÖZxï¹ï{vÎA’qΙrÎB òªö)0cWr2¡ï{bf¬×kEDhš†Œ1È9£ª*J)‘sŽ 4HÊe)¼XgŸeß|óMBÀ“'Oò믿®oÛwpp0hÙÂ,Ó¹@[®aQ‰w³Ð^¡—q!Ö‘÷2".—Ö?þøc<>>Îï¿ÿ¾~å•Wômû–†YnñÇËïÇ®Ïk ‘Rba–Zt4¾ýöÛÄÌøúë¯ã|­µÙ·o×Ó;±7¿îQbK@ÒŒ-\Å‚sÂ99!fÆ÷ßoS`Ÿñˆ±ž³~yS鄯qdTà”JÊ1ÆY2&òFË%Ç‘˜™ezÛ·o‰÷%tJÌß- »·¦Ífïý<Ò•fŒcŒ˜¦‰å¦Ó4Íö6Å)ÆHι¹üßx`ÇÚ´/nó€Úl6È9#„À›ÍF:@¤”fâÊ{Ï‚]éï÷ 6Ž£Ìc¼5._@»™iùn«———ì½g©ÀÀÍRÚ\H¡Ë9“Œ‰·¥Ç`f”Nsï¾ÝÝżÌÅK%—kKç¼÷!ðÒz1FJ)1Ñ0 s¯ÿÆoäããã­Áè­·ÞÊιù!zûí·óãÇ·ö½÷Þ{|yyÉ«Õjž?ö­Àgû 眲¼¼aJ‰ 'C2¸ûá‡Æµ–¥F<{öŒøá± ¼÷øè£ÂÇ,T 5M"¢“““y¨,å2\ñNºÝÄÞû­MÂÅxï™™iš&dàˆ1âòò’sYŠaš&ÄUŒqŽ•§OŸòùù9Ë­5u]‡££#UêŒêºŽdˆ*µ†PR¹@GØpì b±þ‚@¢2×J@ÎeÝ9'M×ü€œ3Jê¥eÓ·LbeabŒ™ˆTJ)ª¶mÑ4 ¥”fF{YÌ^ÄÄÌ,Ä‹4OÞûù&b=)n…ÿ$c ¤”R$4ºX2ç,,/û™OOO33«c>::"™Ì<•(ó"!„@J)*,|(€í"#×êºñ4M³ëC³DYï½$yD-¢««+^¯×tvvƇ‡‡ëõZ˜º¹?“¸ÜUbËJ)i'HzqyèÒ•D4ŸoPΙKfšEi‰ˆSJpÎÁZ‹âe.Ž6› 7MC\ ‰õzM!îû~e…·ºÍª´´´¸ÀIÆ?)H1Fa ¸x %v$“Í)—Ñ‘™™eL !pŒ‘„ºaft]ÇÌŒ¾ïc¤¦iXHä­òœ PK‰»$óȤDDÂݳÌÂÂÉ‘Q©³!Œ1°ÖÂZKDÄ…¸‚Üg³ÙÐjµÂõõ5‹GSJÔ÷={ï©ë:–Ì·\[ÜhÛ¶ã$±ºd˜b!aß(ÆÈB£ìsŒ‘ÅK…„"k-UU%µƒ¢Zk’z"_]]Ak³³3!`³ÙðÙÙrÎüìÙ3ÇqÙ>¯À4MÜ÷ýL¬ [²WUEò^kM)%aÑ`­…%^æÒ/¦Â»rK³Æ…û$­5_^^¢iœŸŸsÉ€|rrÂJ)œŸŸsi*÷*7›Í¦«Øl63O_x*eÉT1F–` !Pé›äDFðÍÎ9ÇqîbË‘-¦iârÖF!Ç‘´Ö¸¸¸áêêŠÇqüúë¯l­ÅãÇÜœo)à\ùä“»råÊ‹‡‡‡iš&À}ߣª*´m›˜™ªªÂ0 H)¡( h­Ñ÷=¼÷³QÞ{Gä0óÒaXkaŒ÷Þ{”e ¥†a@UUÈá¦i0Ž#m6\¼xQݽ{÷ßoܸñ/~dæ(¬<õí·ßþç4Mõ4MPJñ8ŽPJq×upÎ!ÆÈrfž3㜃÷ã8ίyïg$ ZkcÀ̳ƒEQ „€ʲDJ Ʈ뚼÷\×5¦i¢²,S]×ÇW¯^ý'ÿÃÌÇ‚s à¢1f­”REQPA•eIÓ4©ªªÈ{O1F*Ë’º®CŠ¢P)%êºÞ{rΑµ–Œ1JkMÌL^¤”"c  Ã@Ã03“1†º®#ï=EA}ß“1J)5Ž#ä3çú¾WƘ €‹Ùæ¹P5€ÂZ«rt¨iš¦‰vvvhš&8çæ—eI!ô}/P #²c "&"c µÄÑ÷=ú¾GŒÖZ@Û¶s}£iŽ1’RŠ1$ð†EQ`GPd›g$R¬µVu]SŒ›Í††aÀÎÎŽòÞƒˆÈ9‡®ëØ9­5º®cfFQ‚[Œãˆa¸ë:ô}q!pRJÁƒa0 œsG¬V+ Ã@eYJsbk-r&à½g"ší]:!HdhµZ‘÷çΣiš°^¯U6€ªª¢®ë˜ˆ`­¥išxš&6ÆÀ9‡ Ü‹áDfÆ0 ç†aÀ8Žs”W«{ïaŒvbçRJLDÄ[wé€""’œPÞ{Z¯×*„€ªªT.>rÎQß÷ì½gc 13õ}ÏÓ4ÍE»,àãufFJ ]×™a­Å4MÜ4 ã!"┥”Ø{Oä]åÀŒ]ád"BÓ4ÄÌX¯×ŠˆP–%cR‚sŽbŒ4Ž#ghd2;'pš!$Žã8g$„€¦ihGÔu ï=œs!PîC¤µÆ4M´ ̶B "šùœ™¡”¢Õj¥”RT×µÒZ“µ–¬µ’-@Ã0°@ –R3ÏNšØ4M ¢™F3×ójµBß÷(ŠÃ0ÀZ;E¾>bŒ,ø~éÄtrO…l Sä>ªª(ÃCà”WUÅÇÇÇLD¬”RÓ4qæpÊ–$›u­5”Rˆ1ƒ¢(8„€õzM]×a½^cÎtÍÎ9Ç‘(fæ‚@èá"–§”XF¥ÔìDQTU•jšF5MCZkªªŠRJôÞ{ï™·ß~ÛÉ!I:²D›™á½Gf.VJIÐ4 ú¾gc …æ¢efÒZ#ãÿÔYsJ N)I‡FŒZk¤” µ†µ–2£(fNûûûìœÃG}d˜™¾üòK}óæMåÊ•(Æ/Ù(„­5œsœk Ó4¡ªªSƧ”¨( t]' Å’Ùeà ¶Î«Òò3¦¥&`Œ¡Õj%N`oo/E”½ûî»î©§žŠ/½ô’—F¶d?¡Ûªªc„sŽóøBÌÌÞû÷ÖZk­ÊãÌ){Õâ]-#.NHQ‹‹ “V«•ÚÙÙQçÏŸW2çXkÑ4 ¾ûî;ýæ›owïÞÕ1FxïgÜ;ç¸( 03´Öc¤là 5ÈÑü=ÄY)%5 ¶3@DÄf'–QF’Ï«ÕJi­IFìe”SJôá‡Ú/¾øBݸqÃ7Mç×u "bfJ‰sÄQ–%Yk‘RRƧUv˜Š¢˜»ð),ɇB[†Ï? wËÏÒ+ÄåËZ‹èwÞy§øüóÏÕz½†RŠeìÈlG)%Z­Vªª*@UUÑz½¦¦i¨ª*’úÛvàT d–†‹±KÎ:¡³N† }üñÇîë¯¿Ž¯½öÚ´ÙlÕu ¥i­Q9瀄«ª¢Œ}ðÐ=¶Yˆ–ÑØùÔçg}gBÛGkÍfƒƒƒ}ûöíòùçŸ/¿ür*Š‚Œ1”’aOÝr““¿á×Xhaôüë¶r±„’\üÏ90ß0gãƒ>°_}õß¾};=þøãóu–‹©x¹Ý-ÏrœVÛØ_¾–ŸŸõ®”z¨õ²ÖâÂ… ØÝÝ¥[·niÁy†Ð¼øH¤›/l™;ñ6 a;Ú•eäå{ò¹Ü@¢ø—­5._¾üP@¶^¼,<ªˆ·‹5¯„ˆ1²¨ ËGQ*Ô_!à„,ú¾Çõë×ùÕW_å³2¼ Ò6‘,Ïr˜#ÆPbi"Dyà¼>ò4M!ðññ1k­ÍŸs@æ ‹/âÖ­[üôÓOsŒñLs°Š~~Ÿ©ô„ú¾gÒ8ƈy¨/£žWR~ýõ×ÓÕ«W¹—ØyQÐYµð¨ ¨¶m‘R‚÷žÛ¶• 2Ëäe„eÌÈË: Ãp&ŠñÜsÏÅgžy&¦{÷î©išðØc)Ñ—ä, íÙkù7<ªò4M,8YBò˜ it)%’5QÆã%„2´°^¯ùúõë±iš¸¿¿ÏÌŒýý}ÖZ§”.]º¤êº~ˆ–Y½xéäòœr`G&"LÓï=ãdÍä¬WRŒ‘‰ˆº®›Ù®$Þ{ô}gŸ}6=ùä“ñÁƒÌÌhšD„axoo/Û’páÂZ­VóþqVÑ |–5q–4Ž£ˆ²¼¼`Œ‘²&C]×Ím^VЪªfYäÒ¥KéæÍ›é‡~ˆ< HY–'8U ]×A)ÅDÄBÇMÓd~a(ç劷êÙE£êº&Y¢r¯!d*èˆ޳ŠX¢¿(ïµ²ÐÏë8Ž2tqž‰‚1÷ïßÇ4M´œ“–$ Qu!„ˆHÅÓf³Q9›$»=FüZ3³/2<ûì²Íswþøé§Ÿ~ê½o®]»öwZëúÂ… ò€‹¢PB­Î9%ŠZ~ MÒ¬D‘ÞÞ£ÌN`g^EùøøÎ9µ³³ÃGGG¨ëEQ m[œ;wßÿ}wçÎÞÿýü1Ûð}µCXôe@P§Ó逮ér¼/?Š5 ìÝ»·qçΛ6mÚTUSS³¦ººº"•J©±X,‰DS—/_‹D"‰xOŽ+ᜃ"ø½ .7lذ¡òÆ_755Õñºàs”R$“ÉìÅ‹çÏŸÿz‰`‚ @Ó´ïüƒsû„ãÇoß·o߯œN§ÃjuK)Å‹/"{öìùÛôôtòShá% 'NœøÝþýû­ªj®QÓ4¤R)$  3n·Û¾nÝ:‡(Šp8ï:‚ùùùtKKË·oß¾µäR†€¿ø;ç«§OŸî÷ù|ßc‰"Ò°À_¡[ ’ÖH îCN:õ[ÇSÉc SSSìСC@ 0 `@&Oƒ^Ëÿ˜J¥B'Ožìïé鉘}EAGGÇvÇSYät÷D^zO€Uöl›7o®QUŒ1¨ªŠ3gμH¡xd‘Ìž={vpll,mŠEQܱcÇ/`-W`kÖ¬©hll¬RUªª" fïܹ3 kû5™LNwuuM˜c¨ªŠ†††ŸÃ(Ò¬¢œR‚´µµÕSJ©9{ÏŸ?ŸFi1=;881­ÈC}}ýÏ,òÈ=c5 ‰~¿¿µ¶¶Öv»}­±k477WÜ¿ÿ ( ?pàÀ¿B¡Ð,Š[C ƒñx<®VUUÙ ¾¾¾Òà”-Ò¯ ‚âÊéÝ»w³’$Õy½Þºêêê*sÖcðz½_x½Þ:¯×[700`…BV-¡$“IÅÇn·Û`mR(§‹-âô½{÷†>|8›O|á ³—.]‚B—\ ’$9%IÍþ¯^½Jš–¼ˆ5sçΊF£J!òÙl.\K$SÐÃç’$Z[[×+ŠBÌ1ÆÇÇç-öÍ¡”™‹ÅÞø|¾ EQ èíí>yòä%ô0j´­­­1Œ‘‘‘9XËÆwdVò@º··wøñãdz ]çÚµkCæa-Œ’ƒ6mݺÕkŽ‘N§ùàà`´È`uO¬˜»råÊP,ScÈd2¸zõjI®ÓÖÖÖ¸k×®¦L&“K„·oßMNNN— `‘¬®%‹½ñûý²,£¯¯/Úßß?†¥]‡Øív‡ÏçûæØ±c_˲ì0Øèèhª»»{À9”œ"Ý××7¼qãÆ/zzzþ"QgÛ¶mž#GŽl—$©Êív¯M&“Žx<þn tšwvv~/Ëò ʨFË ˜ëêêú'ôYûë’$­—$©‘1†éééÜ Î9b±˜ÒÝÝ=1::ú_èÅ_Éø˜=±½ê,·3™ —eù½6Y–ñìÙ³øõë×ÿ333óÖ]ÇDŽ«-¯¡œMý’&×4 ™LŠ¢ ‘H(¡P(ýôéÓèƒFÄQÞÌçøæ[`YŽX&''S/'&&âápxz“4®’}Þ@ÁELŒÝNùlƒ‡ÃáH8ŽBw9f\eÝ ºÐr€CŸéåÀâLLYõ¼Ç‚™øs;ýÿ;&æYÍj†Áñ£O%Vh‚ (+@¦$s±Þ0ÇK‹¢(PJW5(¥DE1–`&Ä\Hx­ªêBˆ»¢¢Bu86B±Ùl „J)”RB)%„ä·Ïäž5ïcŒsÎÍO΃ñÉ5M{ïþ‚6®ª*8ç\–e5›ÍRUUS^œsg£úÏ—Û4hPõ?œ`+˜ƒNü€D9ç<ÿ_ n^èä…ÇY1ÈÐEDÄ9çú!éÂ$!æÙÌj‹©•sþÞÞã'̵ÚJR4PIEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/reload.png000066400000000000000000000036561467752164200217410ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î<+IDAThÝZ[lÙþÎ_&†4ëÆ™B ¡/ Ú4lÕ*R•UµZµÍ Hð„P^xBHHˆGBq HVd‘"@bADÚT­¸”’‡´»¹RáHÆ—\LâõmfΜ}˜c㌠iB?idçÌœ3ßwþÿüÿŽC8çøœ!¬4…-ÿB p`õ‰ÓÈ2œsf6Ó…!NÕ”ÒßB¾äœ×­ Ï „„8çÆØ€Îy0,`̼›RÚÂ9ÿc VÛâX/ÂzJ©1ö”2Å9g¦›T¨áœ7kš¶’$‹BÓ4pΛÔ@çœós;€ÚâV j¡sµïP®•bT\Ð9çãú\ã»ÚBeÉ>ð}µCXôe@P§Ó逮ér¼/?Š5 ìÝ»·qçΛ6mÚTUSS³¦ººº"•J©±X,‰DS—/_‹D"‰xOŽ+ᜃ"ø½ .7lذ¡òÆ_755Õñºàs”R$“ÉìÅ‹çÏŸÿz‰`‚ @Ó´ïüƒsû„ãÇoß·o߯œN§ÃjuK)Å‹/"{öìùÛôôtòShá% 'NœøÝþýû­ªj®QÓ4¤R)$  3n·Û¾nÝ:‡(Šp8ï:‚ùùùtKKË·oß¾µäR†€¿ø;ç«§OŸî÷ù|ßc‰"Ò°À_¡[ ’ÖH îCN:õ[ÇSÉc SSSìСC@ 0 `@&Oƒ^Ëÿ˜J¥B'Ožìïé鉘}EAGGÇvÇSYät÷D^zO€Uöl›7o®QUŒ1¨ªŠ3gμH¡xd‘Ìž={vpll,mŠEQܱcÇ/`-W`kÖ¬©hll¬RUªª" fïܹ3 kû5™LNwuuM˜c¨ªŠ†††ŸÃ(Ò¬¢œR‚´µµÕSJ©9{ÏŸ?ŸFi1=;881­ÈC}}ýÏ,òÈ=c5 ‰~¿¿µ¶¶Öv»}­±k477WÜ¿ÿ ( ?pàÀ¿B¡Ð,Š[C ƒñx<®VUUÙ ¾¾¾Òà”-Ò¯ ‚âÊéÝ»w³’$Õy½Þºêêê*sÖcðz½_x½Þ:¯×[700`…BV-¡$“IÅÇn·Û`mR(§‹-âô½{÷†>|8›O|á ³—.]‚B—\ ’$9%IÍþ¯^½Jš–¼ˆ5sçΊF£J!òÙl.\K$SÐÃç’$Z[[×+ŠBÌ1ÆÇÇç-öÍ¡”™‹ÅÞø|¾ EQ èíí>yòä%ô0j´­­­1Œ‘‘‘9XËÆwdVò@º··wøñãdz ]çÚµkCæa-Œ’ƒ6mݺÕkŽ‘N§ùàà`´È`uO¬˜»råÊP,ScÈd2¸zõjI®ÓÖÖÖ¸k×®¦L&“K„·oßMNNN— `‘¬®%‹½ñûý²,£¯¯/Úßß?†¥]‡Øív‡ÏçûæØ±c_˲ì0Øèèhª»»{À9”œ"Ý××7¼qãÆ/zzzþ"QgÛ¶mž#GŽl—$©Êív¯M&“Žx<þn tšwvv~/Ëò ʨFË ˜ëêêú'ôYûë’$­—$©‘1†éééÜ Î9b±˜ÒÝÝ=1::ú_èÅ_Éø˜=±½ê,·3™ —eù½6Y–ñìÙ³øõë×ÿ333óÖ]ÇDŽ«-¯¡œMý’&×4 ™LŠ¢ ‘H(¡P(ýôéÓèƒFÄQÞÌçøæ[`YŽX&''S/'&&âápxz“4®’}Þ@ÁELŒÝNùlƒ‡ÃáH8ŽBw9f\eÝ ºÐr€CŸéåÀâLLYõ¼Ç‚™øs;ýÿ;&æYÍj†Áñ£O%Vh‚ (+@¦$s±Þ0ÇK‹¢(PJW5(¥DE1–`&Ä\Hx­ªêBˆ»¢¢Bu86B±Ùl „J)”RB)%„ä·Ïäž5ïcŒsÎÍO΃ñÉ5M{ïþ‚6®ª*8ç\–e5›ÍRUUS^œsg£úÏ—Û4hPõ?œ`+˜ƒNü€D9ç<ÿ_ n^èä…ÇY1ÈÐEDÄ9çú!éÂ$!æÙÌj‹©•sþÞÞã'̵ÚJR4PIEND®B`‚qtrvsim-0.9.8/src/gui/resources/icons/save.png000066400000000000000000000052131467752164200214200ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs  šœ -IDATxœí]L×Çÿ÷î‡KH×à4õ‚15`bLT»±µRq U,‘ö¥Š£ÆU¥>ØýL”Ëjó’>4o•ŸÚ>T²ãZÇXN@"8‰íJ)ÂnÝÄØ8ª›c(° ÎÂro`ØÝ™Ùï¹?iÅ03;÷ì½ÿ9çÜ{ç@ ÝÿþýuŒ±%j £œoŽsþ´Úï¹ Jé]ÿÍ´s¾ÄëœÖª`a¤™9x@}²ç6ŒËr@ëîÞºc"³ÈLcmÙNÌ–|…Éåh4*»¯QÝ=¤®3‘h$’\^ò=fX¹† `ÑDäñ凋¼wéfgg3îgvwÏ "³³Ì–Ö!î-Ìò í04Ü©M¾†ññq}åìÛ·EEEÉíkbÝòòЬÛÒ–å¶¥îgóss¸rå fff·ë_64ä:ôðk»1Úp57Najj ===Foyníø ¦6¶Z¦á#Ÿoû!"¥µØróÏ(™ü'gF›`)8¡˜.kÄXÝ𿊆—oÊPðTE3¦*šAX<ùÌ·Â<~pâ1­|S»ÜãÅ’Ç6ӎIJAcp9B.'{¶ÀÃú!<€Ëp9–ž èð.GÀ帑¸á\Ž€Ëp9"p9ºMÆFî¡`îK½ï*Ub¾(ý=CZ ‹ ¢_`wßAXî7R VaÔ‹ü_jc©.Š <š¯!”ÅQòð†.æÕýz¬C‡áÛÏ=§w1Ždèƒpþüy@ì1}n+×];››ÑÜܬw1Ž$& ¢èrôéŠn£>èP¯Â¸!—cH0ûî[G ÓŹÂ¸ݻٞ»sóæMܾ}[o3,IMM êêê$·á9M½1ïòÐNžW_.W7¢(ÐcfÅH`N¤Õ›xN @k„\Ž\ˆX~óçÉÍÿˆéà<È£Þ8ÈRýôÓß¾õÖ[ÿryy™½÷@¦iB×u8YDØuæyFÎMÓÀZ‹išBX !PÑ#"[‡QUœs! „€¶maŒÁ<Ïèº% 2 –eáññ1=zd¾øâ‹ß½÷Þ{ÿàTD’:°ð믿þú÷ÞûÞ{cŒ,ËcŒŒãˆº®‘R½ˆ¬™©ë!,˲þÄBXÐ,Xkᜃˆ¬6Mƒ#bŒhÛ9g8ç¤ï{†¤ï{xïÙ¶mîûþúí·ßþ'ÿ-"׊ó À#çÜÞcš¦aŒÑ´mKï½éºŽ!¦”ض-ÇqDŒ‘MÓ˜œ3ÇqDu]³ª*:猵–"Â/cèœ#IÎóÌyž)"tÎqG†Ø4 §i¢sƳ, ô³º®1M“qÎxTl^ Õhªª2%:†Þ{Ñ{º®×·mË#¦iR(0¥„âH I8ç`­¤”0M¦iBJ UU‡ÃZ××׆ARJ4ƈsŽ ¯yžÑ4 –e!€¦Ø¼: ‘k­éûž)%sžg™H²®kŒã(u]ÃZ‹qEDÐ4â˲`žgÇÓ4aY(œŒ1pÎažgÌ󌺮ŽØív˜ç™mÛjs’ªªP2‚\íÝ:ˆ1jd¸ÛíBÀÉÉ ½÷Øï÷¦À®ë8Ž£DUUôÞ‹÷^œs¨ëTÜ«á$!"˜çP×5æyƲ,k”w»„àœSv’º®‘s’”;wë€!IýÇÅ Bà~¿71Ft]gJñ±®kNÓ$!qÎQD8M“xï×¢ÝpJiºˆ çŒq!"¨ª Þ{†A–e’IÉ93ç,!ÐWsŸ+v•“IbŠöû½!‰¶méœCÎu]3¥ÄeY¤@ƒšÉâœÂi…:¶,Ëš‘#†aà²,èû!Ôu#K¢µÞ{nsׯIrås1†»ÝÎcØ÷½±Ö²ª*VU¥ÙœçY4 µœ3Dd8pÓļ÷ ¹ÒházÙív˜¦ MÓ`žgTUµE¹>RJ¢ø~èļ¹§A1ŠÊ¥O ë:x’s–®ëäúúZHŠ1Æxï¥p8K‡¥fS£n­…1)%8çÐ4ıßï9Ž#öû=æy–B×R×5—eFD$ƨz¹ˆ5Å9gÑQÁ³:Ñ4 »®3Ã0˜ah­e×uÌ9€h¡¦”ÖÆ¤Y£-"! 0—c4†Ó4‰sŽ1ƵhE„ÖZüß:ÛaΨÁ9gíÐH)ÁZ‹œ3¬µ¨ªŠÅP#"ùüü\ µ®|¾…Mé kbŒ°Ö¢®k)5ï=º®»e|ΙMÓ`Ge(ÑÌnïpçl±ª-¿`ZkÎ9îv;4|ðAõÍ7ß¼™ÿÏyüøqþ裖º®¥Œ/ !¬¸¯ªŠPU•)ã̽0¸¡QÄQx9çµ9)<6ï¹ÛíxzzʼŠý¸¸¸0ÖZI)1¥$Æ)—)%Qˆ–™ )%i𯍽[€$À ›mÏPFÒÏ:Z¿ÊQh朥DmÛ²ª*äœsNÇiÓ4 D„MÓ¬]ø%€èO‘Õ­‹-¬^×”êºfλݎºt]Ƕm•HX(ú'@Îy¬â] ×Ï^j$ʼnW9Æô}Oc ­µhš†u]•»®cÁ>Õéí¹ËBÔ­i ¹õùÝ÷¯ãÀññ±uα,4ÔaOëq»Ééwø)Ú½þzW¹ØBéu!ôøñckŒYTÊÝL Ûín{nube5ò>Éek¼nX¯ãÀÑÑÑ í³¥s…¶~†M'¾ËB÷½­ ޾ߤõÏ>,½¶¾Þù‘íwj’¾¹uç»ÅZVB¤”DU†m‡Ö®ú:¸›é;µ·¾ÞãÄ-€:ŒmR%Šsª‡"¬âp8¬:}ÑmXn*ÊT1FÑb !°ÌMúDFñ-˲È4Më[Ùbžg)ÏÚBišh­ÅÅÅHâêêJ¦i|÷ÝwRU¾üòË7ÏŒo9°¸xúôé^º®Ãõõµò=—eçsΪ+”¸,‹,Ë¢Êôúµ`MÓ Œ˜¦IÆq}H@®®®¤ª*Í€h£œçÓ4ÉÅŪªÂóçÏåóÏ?ÿÅæµˆGÏ>ûì³ÏBÓ'OþÞZÛ?|øPðIÓ4F©µ®k£ŠZy MmVªHßÝ£¬N…§µÖXkåúúu]›££#¹ººBß÷hš‡Ã'''øöÛoǧOŸþï'Ÿ|òž›×Ýð ÿàü À1~^ç7†ÿÀø?-"Ià€Ç¸1¾þëØù£ÇãÆ‰?x!"?°Ãöt¸ÖÏñ?{D¹ÕþR] ü ’YIEND®B`‚qtrvsim-0.9.8/src/gui/resources/samples/000077500000000000000000000000001467752164200203045ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/resources/samples/samples.qrc000066400000000000000000000002531467752164200224570ustar00rootroot00000000000000 simple-lw-sw-ia.S template.S template-os.S qtrvsim-0.9.8/src/gui/resources/samples/simple-lw-sw-ia.S000066400000000000000000000016351467752164200233640ustar00rootroot00000000000000// Template file with simple memory example // QtRVSim simulator https://github.com/cvut/qtrvsim/ // // template-os.S - example file // // (C) 2021 by Pavel Pisa // e-mail: pisa@cmp.felk.cvut.cz // homepage: http://cmp.felk.cvut.cz/~pisa // work: http://www.pikron.com/ // license: public domain // Directives to make interesting windows visible #pragma qtrvsim show registers #pragma qtrvsim show memory .globl _start .option norelax .text _start: loop: // load the word from absolute address lw x2, 0x400(x0) // store the word to absolute address sw x2, 0x404(x0) // stop execution wait for debugger/user // ebreak // ensure that continuation does not // interpret random data beq x0, x0, loop nop nop ebreak .data .org 0x400 src_val: .word 0x12345678 dst_val: .word 0 // Specify location to show in memory window #pragma qtrvsim focus memory src_val qtrvsim-0.9.8/src/gui/resources/samples/template-os.S000066400000000000000000000050371467752164200226670ustar00rootroot00000000000000// Template file with defines of system calls // QtRVSim simulator https://github.com/cvut/qtrvsim/ // // template-os.S - example file // // (C) 2021 by Pavel Pisa // e-mail: pisa@cmp.felk.cvut.cz // homepage: http://cmp.felk.cvut.cz/~pisa // work: http://www.pikron.com/ // license: public domain // Directives to make interesting windows visible #pragma qtrvsim show terminal #pragma qtrvsim show registers #pragma qtrvsim show csrdock #pragma qtrvsim show memory .globl _start .globl __start .option norelax // Linux kernel compatible system calls subset .equ __NR_exit, 93 // void exit(int status) .equ __NR_read, 63 // ssize_t read(int fd, void *buf, size_t count) .equ __NR_write, 64 // ssize_t write(int fd, const void *buf, size_t count) .equ __NR_close, 57 // int close(int fd) .equ __NR_openat, 56 // int openat(int fd, const char *pathname, int flags, mode_t mode) // use fd = -100 for normal open behaviour. Full openat not supported. .equ __NR_brk, 214 // void * brk(void *addr) .equ __NR_ftruncate64, 46 // int ftruncate64(int fd, off_t length) .equ __NR_readv, 65 // ssize_t readv(int fd, const struct iovec *iov, int iovcnt) .equ __NR_writev, 66 // ssize_t writev(int fd, const struct iovec *iov, int iovcnt) .text __start: _start: addi a7, zero, __NR_write // load syscall number addi a0, zero, 1 // load file descriptor la a1, text_1 // load text start address la a2, text_1_e // load text end address sub a2, a2, a1 // compute text length ecall // print the text addi a7, zero, __NR_exit // load syscall numver addi a0, zero, 0 // load status argument ecall // exit final: ebreak // request developer interaction jal zero, final .data .org 0x400 data_1: .word 1, 2, 3, 4 text_1: .ascii "Hello world.\n" // store ASCII text, no termination text_1_e: // The sample can be compiled by full-featured riscv64-unknown-elf GNU tool-chain // for RV32IMA use // riscv64-unknown-elf-gcc -c -march=rv64ima -mabi=lp64 template-os.S // riscv64-unknown-elf-gcc -march=rv64ima -mabi=lp64 -nostartfiles -nostdlib template-os.o // for RV64IMA use // riscv64-unknown-elf-gcc -c -march=rv32ima -mabi=ilp32 template-os.S // riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -nostartfiles -nostdlib template-os.o // add "-o template-os" to change default "a.out" output file name qtrvsim-0.9.8/src/gui/resources/samples/template.S000066400000000000000000000114541467752164200222500ustar00rootroot00000000000000// Template file with defines of peripheral registers // QtRVSim simulator https://github.com/cvut/qtrvsim/ // // template.S - example file // // (C) 2021-2024 by Pavel Pisa // e-mail: pisa@cmp.felk.cvut.cz // homepage: http://cmp.felk.cvut.cz/~pisa // work: http://www.pikron.com/ // license: public domain // Directives to make interesting windows visible #pragma qtrvsim show terminal #pragma qtrvsim show registers #pragma qtrvsim show memory .globl _start .globl __start .option norelax // Serial port/terminal registers // There is mirror of this region at address 0xffff0000 // to match QtSpim and Mars emulators .equ SERIAL_PORT_BASE, 0xffffc000 // base address of serial port region .equ SERP_RX_ST_REG, 0xffffc000 // Receiver status register .equ SERP_RX_ST_REG_o, 0x0000 // Offset of RX_ST_REG .equ SERP_RX_ST_REG_READY_m, 0x1 // Data byte is ready to be read .equ SERP_RX_ST_REG_IE_m, 0x2 // Enable Rx ready interrupt .equ SERP_RX_DATA_REG, 0xffffc004 // Received data byte in 8 LSB bits .equ SERP_RX_DATA_REG_o, 0x0004 // Offset of RX_DATA_REG .equ SERP_TX_ST_REG, 0xffffc008 // Transmitter status register .equ SERP_TX_ST_REG_o, 0x0008 // Offset of TX_ST_REG .equ SERP_TX_ST_REG_READY_m, 0x1 // Transmitter can accept next byte .equ SERP_TX_ST_REG_IE_m, 0x2 // Enable Tx ready interrupt .equ SERP_TX_DATA_REG, 0xffffc00c // Write word to send 8 LSB bits to terminal .equ SERP_TX_DATA_REG_o, 0x000c // Offset of TX_DATA_REG // Memory mapped peripheral for dial knobs input, // LED and RGB LEDs output designed to match // MZ_APO education Zynq based board developed // by Petr Porazil and Pavel Pisa at PiKRON.com company .equ SPILED_REG_BASE, 0xffffc100 // base of SPILED port region .equ SPILED_REG_LED_LINE, 0xffffc104 // 32 bit word mapped as output .equ SPILED_REG_LED_LINE_o, 0x0004 // Offset of the LED_LINE .equ SPILED_REG_LED_RGB1, 0xffffc110 // RGB LED 1 color components .equ SPILED_REG_LED_RGB1_o, 0x0010 // Offset of LED_RGB1 .equ SPILED_REG_LED_RGB2, 0xffffc114 // RGB LED 2 color components .equ SPILED_REG_LED_RGB2_o, 0x0014 // Offset of LED_RGB2 .equ SPILED_REG_KNOBS_8BIT, 0xffffc124 // Three 8 bit knob values .equ SPILED_REG_KNOBS_8BIT_o, 0x0024 // Offset of KNOBS_8BIT // The simple 16-bit per pixel (RGB565) frame-buffer // display size is 480 x 320 pixel // Pixel format RGB565 expect // bits 11 .. 15 red component // bits 5 .. 10 green component // bits 0 .. 4 blue component .equ LCD_FB_START, 0xffe00000 .equ LCD_FB_END, 0xffe4afff // RISC-V ACLINT MSWI and MTIMER memory mapped peripherals .equ ACLINT_MSWI, 0xfffd0000 // core 0 SW interrupt request .equ ACLINT_MTIMECMP, 0xfffd4000 // core 0 compare value .equ ACLINT_MTIME, 0xfffdbff8 // timer base 10 MHz // Mapping of interrupts // mcause mie / mip // irq number bit Source // 3 3 ACLINT MSWI // 7 7 MTIME reached value of MTIMECMP // 16 16 There is received character ready to be read // 17 17 Serial port ready to accept character to Tx // Start address after reset .org 0x00000200 .text __start: _start: loop: li a0, SERIAL_PORT_BASE // load base address of serial port la a1, text_1 // load address of text next_char: lb t1, 0(a1) // load one byte after another beq t1, zero, end_char // is this the terminal zero byte addi a1, a1, 1 // move pointer to next text byte tx_busy: lw t0, SERP_TX_ST_REG_o(a0) // read status of transmitter andi t0, t0, SERP_TX_ST_REG_READY_m // mask ready bit beq t0, zero, tx_busy // if not ready wait for ready condition sw t1, SERP_TX_DATA_REG_o(a0) // write byte to Tx data register jal zero, next_char // unconditional branch to process next byte end_char: ebreak // stop continuous execution, request developer interaction jal zero, end_char .org 0x400 .data data_1: .word 1, 2, 3, 4 // example how to fill data words text_1: .asciz "Hello world.\n" // store zero terminated ASCII text // if whole source compile is OK the switch to core tab #pragma qtrvsim tab core // The sample can be compiled by full-featured riscv64-unknown-elf GNU tool-chain // for RV32IMA use // riscv64-unknown-elf-gcc -c -march=rv64ima -mabi=lp64 template.S // riscv64-unknown-elf-gcc -march=rv64ima -mabi=lp64 -nostartfiles -nostdlib template.o // for RV64IMA use // riscv64-unknown-elf-gcc -c -march=rv32ima -mabi=ilp32 template.S // riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -nostartfiles -nostdlib template.o // add "-o template" to change default "a.out" output file name qtrvsim-0.9.8/src/gui/statictable.cpp000066400000000000000000000235431467752164200176400ustar00rootroot00000000000000#include "statictable.h" #include "machine/simulator_exception.h" #include StaticTableLayout::StaticTableLayout( QWidget *parent, int margin, int horizontal_big_spacing, int horizontal_small_spacing, int vertical_spacing) : QLayout(parent) { setContentsMargins(margin, margin, margin, margin); bhspace = horizontal_big_spacing; shspace = horizontal_small_spacing; vspace = vertical_spacing; setSizeConstraint(QLayout::SetMinAndMaxSize); cch_do_layout.size = QSize(0, 0); cch_do_layout.count = 0; cch_heightForWidth.w = 0; cch_heightForWidth.count = 0; cch_heightForWidth.width = 0; cch_minSize.count = 0; cch_minSize.size = QSize(0, 0); } StaticTableLayout::~StaticTableLayout() { for (auto &row : items) { for (auto &col : row) delete col; } } Qt::Orientations StaticTableLayout::expandingDirections() const { return Qt::Horizontal; } bool StaticTableLayout::hasHeightForWidth() const { return true; } int StaticTableLayout::heightForWidth(int w) const { if (cch_heightForWidth.w != w || cch_heightForWidth.count != items.count()) cch_heightForWidth.width = layout_height(w); cch_heightForWidth.w = w; cch_heightForWidth.count = items.count(); return cch_heightForWidth.width; } QSize StaticTableLayout::minimumSize() const { if (cch_minSize.count == items.size()) return cch_minSize.size; cch_minSize.count = items.size(); cch_minSize.size = QSize(); for (const auto &item : items) { QSize ss; for (auto layout_item : item) { ss = cch_minSize.size.expandedTo(layout_item->minimumSize() + QSize(shspace, 0)); } cch_minSize.size = cch_minSize.size.expandedTo(ss - QSize(shspace, 0)); } int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); cch_minSize.size += QSize(left + right, top + bottom); return cch_minSize.size; } void StaticTableLayout::setGeometry(const QRect &rect) { QLayout::setGeometry(rect); do_layout(rect); } QSize StaticTableLayout::sizeHint() const { return minimumSize(); } void StaticTableLayout::addItem(QLayoutItem *item __attribute__((unused))) { // Just implement it but it does nothing } QLayoutItem *StaticTableLayout::itemAt(int index __attribute__((unused))) const { return nullptr; // This is just dummy implementation to satisfy // reimplementation } QLayoutItem *StaticTableLayout::takeAt(int index __attribute__((unused))) { return nullptr; // This is just dummy implementation to satisfy // reimplementation } int StaticTableLayout::count() const { return items.size(); } void StaticTableLayout::addRow(const QList &w) { items.append(list2vec(w)); } void StaticTableLayout::insertRow(const QList &w, int i) { items.insert(i, list2vec(w)); } void StaticTableLayout::removeRow(int i) { for (auto &item : items[i]) { delete item->widget(); delete item; } items.remove(i); } void StaticTableLayout::clearRows() { for (auto &item : items) { for (auto &layout_item : item) { delete layout_item->widget(); delete layout_item; } } items.clear(); } void StaticTableLayout::itemRect(QRect &rect, QVector &separators, int i) { separators.clear(); int row = i / columns(); int col = i % columns(); int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); int x = left; for (int s = 0; s < col; s++) { for (int row_width : row_widths[s]) { x += row_width + shspace; } x += bhspace - shspace; } if (col > 0) { // otherwise we are on the left edge and there was no previous // column so no big space x -= bhspace / 2; } int y = top + (row * (row_height + vspace)); int width = 0; for (int row_width : row_widths[col]) { width += row_width + shspace; separators.append(width - shspace / 2); } if (col <= 0) { width -= bhspace / 2; } rect = QRect(x, y - vspace / 2, width - shspace + bhspace, row_height + vspace); separators.removeLast(); // drop the last separator as that one we don't want to // see } int StaticTableLayout::columns() { return row_widths.size(); } int StaticTableLayout::real_row_height() const { return row_height + vspace; } int StaticTableLayout::layout_count_approx(const QRect &rect) const { if (items.empty() || rect.width() < rect.height()) return 1; // Note: for some reason (probably optimisation) when qlabel is not // visible, it reports zero size. So we have to find at least one that is // visible !items[vis][0]->widget()->isVisible() int vis = 0; while (items[vis].empty() || items[vis][0]->widget()->sizeHint().width() == 0) { vis++; if (vis >= items.size()) return 1; // If none is visible, then just say that it has to be a single column } int w = 0; for (auto item : items[vis]) w += item->sizeHint().width() + shspace; w -= shspace; // subtract the latest spacing int width = rect.right() / w; // Note: this always rounds down so this // always founds maximal possible count return width <= 0 ? 1 : width; // We have to fit at least one column } int StaticTableLayout::layout_size(int &row_h, QList> &row_w, int count) const { row_h = 0; row_w.clear(); int col = 0; for (const auto &item : items) { if (row_w.size() <= col) row_w.append(QList()); for (int y = 0; y < item.size(); y++) { QSize s = item[y]->sizeHint(); row_h = qMax(row_h, s.height()); if (row_w[col].size() <= y) row_w[col].append(0); row_w[col][y] = qMax(row_w[col][y], s.width()); } if (++col >= count) col = 0; } SANITY_ASSERT(row_w.size() <= count, "We should end up with maximum of count columns"); int w = 0; for (auto &i : row_w) { for (int y : i) { w += y + shspace; } w += bhspace - shspace; // subtract latest small spacing and add big // spacing } w -= bhspace; // subtract latest big spacing return w; } void StaticTableLayout::layout_parms(QRect &rect, int &row_h, QList> &row_w, int &count) const { int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); rect = rect.adjusted(left, top, -right, -bottom); // Firt let's do orientation count only on the first line count = layout_count_approx(rect); while (layout_size(row_h, row_w, count) > rect.right() && count > 1) { // Not using orientation count go down if we can't fit (if we can then // just be happy with what we have) count--; } } void StaticTableLayout::do_layout(const QRect &rect) { if (cch_do_layout.size == rect.size() && cch_do_layout.count == items.size()) // No effective change so don't do layout return; cch_do_layout.size = rect.size(); cch_do_layout.count = items.size(); int row_h; QList> row_w; int count; QRect reff(rect); layout_parms(reff, row_h, row_w, count); int col = 0; int x = reff.x(), y = reff.y(); for (auto &item : items) { for (int ii = 0; ii < item.size(); ii++) { item[ii]->setGeometry(QRect(x, y, row_w[col][ii], row_h)); x += row_w[col][ii] + shspace; } x += bhspace - shspace; if (++col >= count) { col = 0; x = reff.x(); y += row_h + vspace; } } row_height = row_h; row_widths = row_w; } int StaticTableLayout::layout_height(int width) const { QRect reff(0, 0, width, 0); int row_h; QList> row_w; int count; layout_parms(reff, row_h, row_w, count); return (row_h + vspace) * ((items.size() + count - 1) / count); } QVector StaticTableLayout::list2vec(const QList &w) { QVector v; for (auto &i : w) { addChildWidget(i); v.append(new QWidgetItem(i)); } return v; } StaticTable::StaticTable(QWidget *parent) : QWidget(parent), layout(this) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); } int StaticTable::count() { return layout.count(); } void StaticTable::addRow(const QList &w) { layout.addRow(w); } void StaticTable::insertRow(const QList &w, int i) { layout.insertRow(w, i); } void StaticTable::removeRow(int i) { layout.removeRow(i); } void StaticTable::clearRows() { layout.clearRows(); } int StaticTable::columns() { return qMax(layout.columns(), 1); } int StaticTable::row_size() { return layout.real_row_height(); } void StaticTable::paintEvent(QPaintEvent *) { if (layout.columns() <= 0) // Don't paint unless we have at least one column return; QPainter p(this); p.setPen(QPen(QColor(200, 200, 200))); QRect rect; QVector separators; for (int i = 0; i < layout.count(); i++) { int row = i / layout.columns(); int col = i % layout.columns(); if ((col % 2) == (row % 2)) p.setBrush(QBrush(QColor(255, 255, 255))); else p.setBrush(QBrush(QColor(235, 235, 235))); layout.itemRect(rect, separators, i); int x = rect.left(); // just to store x if (col <= 0) // this is left most row rect.setLeft(-2); if (col >= (layout.columns() - 1)) rect.setRight(width()); if (row <= 0) rect.setTop(-2); p.drawRect(rect); for (int separator : separators) { int sep_x = x + separator; p.drawLine(sep_x, rect.top(), sep_x, rect.bottom()); } } } qtrvsim-0.9.8/src/gui/statictable.h000066400000000000000000000063311467752164200173010ustar00rootroot00000000000000#ifndef STATICTABLE_H #define STATICTABLE_H #include #include #include #include /* * This implements new layout and widget in the same time. * The Basic idea is that we need some table view that can also fill in horizontal space. This * widget paints simple table underneath the widgets and lays them out in to them. It shows more * than one column when there is enough horizontal space. */ class StaticTableLayout : public QLayout { public: explicit StaticTableLayout( QWidget *parent, int margin = 4, int horizontal_big_spacing = 4, int horizontal_small_spacing = 8, int vertical_spacing = 4); ~StaticTableLayout() override; Qt::Orientations expandingDirections() const override; bool hasHeightForWidth() const override; int heightForWidth(int) const override; QSize minimumSize() const override; void setGeometry(const QRect &rect) override; QSize sizeHint() const override; void addItem(QLayoutItem *item) override; QLayoutItem *itemAt(int index) const override; QLayoutItem *takeAt(int index) override; int count() const override; // This returns number of item blocks void addRow(const QList &); // This adds a row of widgets void insertRow(const QList &, int i); // Insert row to given position while shifting // all others up void removeRow(int i); // Remove row void clearRows(); // Clear all rows from table void itemRect(QRect &rect, QVector &separators, int i); // This returns a single item // rectangle (if expand_margin, and // it's on edge also count in // margin) int columns(); int real_row_height() const; protected: int shspace, bhspace, vspace; QVector> items; int row_height {}; QList> row_widths; int layout_count_approx(const QRect &rect) const; int layout_size(int &row_h, QList> &row_w, int count) const; void layout_parms(QRect &rect, int &row_h, QList> &row_w, int &count) const; void do_layout(const QRect &rect); int layout_height(int width) const; QVector list2vec(const QList &); struct { QSize size; int count {}; } cch_do_layout; mutable struct { int w, count; int width; } cch_heightForWidth {}; mutable struct { int count {}; QSize size; } cch_minSize; }; class StaticTable : public QWidget { public: explicit StaticTable(QWidget *parent = nullptr); int count(); void addRow(const QList &); void insertRow(const QList &, int i); void removeRow(int i); void clearRows(); int columns(); int row_size(); // return real row size (height) including spacing protected: void paintEvent(QPaintEvent *) override; StaticTableLayout layout; }; #endif // STATICTABLE_H qtrvsim-0.9.8/src/gui/textsignalaction.cpp000066400000000000000000000027241467752164200207170ustar00rootroot00000000000000#include "textsignalaction.h" #include #include TextSignalAction::TextSignalAction(QObject *parent) : Super(parent) { connect( this, &TextSignalAction::triggered, this, &TextSignalAction::process_triggered); } TextSignalAction::TextSignalAction(const QString &text, QObject *parent) : Super(text, parent) , signal_text(text) { connect( this, &TextSignalAction::triggered, this, &TextSignalAction::process_triggered); } TextSignalAction::TextSignalAction( const QString &text, QString signal_text, QObject *parent) : Super(text, parent) , signal_text(std::move(signal_text)) { connect( this, &TextSignalAction::triggered, this, &TextSignalAction::process_triggered); } TextSignalAction::TextSignalAction( const QIcon &icon, const QString &text, QObject *parent) : Super(icon, text, parent) , signal_text(text) { connect( this, &TextSignalAction::triggered, this, &TextSignalAction::process_triggered); } TextSignalAction::TextSignalAction( const QIcon &icon, const QString &text, QString signal_text, QObject *parent) : Super(icon, text, parent) , signal_text(std::move(signal_text)) { connect( this, &TextSignalAction::triggered, this, &TextSignalAction::process_triggered); } void TextSignalAction::process_triggered(bool checked) { (void)checked; emit activated(signal_text); } qtrvsim-0.9.8/src/gui/textsignalaction.h000066400000000000000000000015541467752164200203640ustar00rootroot00000000000000#ifndef TEXTSIGNALACTION_H #define TEXTSIGNALACTION_H #include #include class TextSignalAction : public QAction { Q_OBJECT using Super = QAction; public: explicit TextSignalAction(QObject *parent = nullptr); explicit TextSignalAction(const QString &text, QObject *parent = nullptr); TextSignalAction( const QString &text, QString signal_text, QObject *parent = nullptr); TextSignalAction( const QIcon &icon, const QString &text, QObject *parent = nullptr); TextSignalAction( const QIcon &icon, const QString &text, QString signal_text, QObject *parent = nullptr); signals: void activated(QString signal_text); protected slots: void process_triggered(bool checked); protected: QString signal_text; }; #endif // TEXTSIGNALACTION_H qtrvsim-0.9.8/src/gui/ui/000077500000000000000000000000001467752164200152435ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/ui/hexlineedit.cpp000066400000000000000000000025231467752164200202530ustar00rootroot00000000000000#include "hexlineedit.h" HexLineEdit::HexLineEdit( QWidget *parent, int digits, int base, const QString &prefix) : Super(parent) { this->base = base; this->digits = digits; this->prefix = prefix; last_set = 0; QChar dmask; QString t = ""; QString mask = ""; for (int i = 0; i < prefix.count(); i++) { mask += "\\" + QString(prefix.at(i)); } switch (base) { case 10: mask += "D"; dmask = 'd'; break; case 2: mask += "B"; dmask = 'b'; break; case 16: case 0: default: mask += "H"; dmask = 'h'; break; } if (digits > 1) { t.fill(dmask, digits - 1); } mask += t; setInputMask(mask); connect( this, &QLineEdit::editingFinished, this, &HexLineEdit::on_edit_finished); set_value(0); } void HexLineEdit::set_value(uint32_t value) { QString s, t = ""; last_set = value; s = QString::number(value, base); if (s.count() < digits) { t.fill('0', digits - s.count()); } setText(prefix + t + s); } void HexLineEdit::on_edit_finished() { bool ok; uint32_t val; val = text().toULong(&ok, 16); if (!ok) { set_value(last_set); return; } last_set = val; emit value_edit_finished(val); } qtrvsim-0.9.8/src/gui/ui/hexlineedit.h000066400000000000000000000011121467752164200177110ustar00rootroot00000000000000#ifndef HEXLINEEDIT_H #define HEXLINEEDIT_H #include #include class HexLineEdit : public QLineEdit { Q_OBJECT using Super = QLineEdit; public: explicit HexLineEdit( QWidget *parent = nullptr, int digits = 8, int base = 0, const QString &prefix = "0x"); public slots: void set_value(uint32_t value); signals: void value_edit_finished(uint32_t value); private slots: void on_edit_finished(); private: int base; int digits; QString prefix; uint32_t last_set; }; #endif // HEXLINEEDIT_H qtrvsim-0.9.8/src/gui/widgets/000077500000000000000000000000001467752164200162745ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/widgets/hidingtabwidget.cpp000066400000000000000000000011361467752164200221360ustar00rootroot00000000000000#include "hidingtabwidget.h" void HidingTabWidget::tabInserted(int index) { QTabWidget::tabInserted(index); if (count() == 1) { show(); requestAddRemoveTab(this, true); } tabCountChanged(); } void HidingTabWidget::tabRemoved(int index) { QTabWidget::tabRemoved(index); if (count() == 0) { hide(); requestAddRemoveTab(this, false); } tabCountChanged(); } void HidingTabWidget::addRemoveTabRequested(QWidget *tab, bool exists) { if (!exists) { removeTab(indexOf(tab)); } else { addTab(tab, tab->windowTitle()); } } qtrvsim-0.9.8/src/gui/widgets/hidingtabwidget.h000066400000000000000000000011671467752164200216070ustar00rootroot00000000000000#ifndef HIDINGTABWIDGET_H #define HIDINGTABWIDGET_H #include #include /** A widget that hides itself when it has no tabs. */ class HidingTabWidget : public QTabWidget { Q_OBJECT using Super = QTabWidget; public: explicit HidingTabWidget(QWidget *parent = nullptr) : Super(parent) {}; void tabInserted(int index) override; void tabRemoved(int index) override; signals: void requestAddRemoveTab(QWidget *tab, bool visible); public slots: void addRemoveTabRequested(QWidget *tab, bool exists); protected: virtual void tabCountChanged() {}; }; #endif // HIDINGTABWIDGET_H qtrvsim-0.9.8/src/gui/windows/000077500000000000000000000000001467752164200163205ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/cache/000077500000000000000000000000001467752164200173635ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/cache/cachedock.cpp000066400000000000000000000064311467752164200217770ustar00rootroot00000000000000#include "cachedock.h" CacheDock::CacheDock(QWidget *parent, const QString &type) : QDockWidget(parent) { top_widget = new QWidget(this); setWidget(top_widget); layout_box = new QVBoxLayout(top_widget); top_form = new QWidget(top_widget); top_form->setVisible(false); layout_box->addWidget(top_form); layout_top_form = new QFormLayout(top_form); l_hit = new QLabel("0", top_form); layout_top_form->addRow("Hit:", l_hit); l_miss = new QLabel("0", top_form); layout_top_form->addRow("Miss:", l_miss); l_m_reads = new QLabel("0", top_form); layout_top_form->addRow("Memory reads:", l_m_reads); l_m_writes = new QLabel("0", top_form); layout_top_form->addRow("Memory writes:", l_m_writes); l_stalled = new QLabel("0", top_form); layout_top_form->addRow("Memory stall cycles:", l_stalled); l_hit_rate = new QLabel("0.000%", top_form); layout_top_form->addRow("Hit rate:", l_hit_rate); l_speed = new QLabel("100%", top_form); layout_top_form->addRow("Improved speed:", l_speed); graphicsview = new GraphicsView(top_widget); graphicsview->setVisible(false); layout_box->addWidget(graphicsview); cachescene = nullptr; no_cache = new QLabel("No " + type + " Cache configured", top_widget); layout_box->addWidget(no_cache); setObjectName(type + "Cache"); setWindowTitle(type + " Cache"); } void CacheDock::setup(const machine::Cache *cache, bool cache_after_cache) { l_hit->setText("0"); l_miss->setText("0"); l_stalled->setText("0"); l_m_reads->setText("0"); l_m_writes->setText("0"); l_hit_rate->setText("0.000%"); l_speed->setText("100%"); l_speed->setHidden(cache_after_cache); if (cache != nullptr) { connect( cache, &machine::Cache::hit_update, this, &CacheDock::hit_update); connect( cache, &machine::Cache::miss_update, this, &CacheDock::miss_update); connect( cache, &machine::Cache::memory_reads_update, this, &CacheDock::memory_reads_update); connect( cache, &machine::Cache::memory_writes_update, this, &CacheDock::memory_writes_update); connect( cache, &machine::Cache::statistics_update, this, &CacheDock::statistics_update); } top_form->setVisible(cache != nullptr); no_cache->setVisible(cache == nullptr || !cache->get_config().enabled()); delete cachescene; cachescene = new CacheViewScene(cache); graphicsview->setScene(cachescene); graphicsview->setVisible(cache != nullptr && cache->get_config().enabled()); } void CacheDock::hit_update(unsigned val) { l_hit->setText(QString::number(val)); } void CacheDock::miss_update(unsigned val) { l_miss->setText(QString::number(val)); } void CacheDock::memory_reads_update(unsigned val) { l_m_reads->setText(QString::number(val)); } void CacheDock::memory_writes_update(unsigned val) { l_m_writes->setText(QString::number(val)); } void CacheDock::statistics_update( unsigned stalled_cycles, double speed_improv, double hit_rate) { l_stalled->setText(QString::number(stalled_cycles)); l_hit_rate->setText(QString::number(hit_rate, 'f', 3) + QString("%")); l_speed->setText(QString::number(speed_improv, 'f', 0) + QString("%")); } qtrvsim-0.9.8/src/gui/windows/cache/cachedock.h000066400000000000000000000017241467752164200214440ustar00rootroot00000000000000#ifndef CACHEDOCK_H #define CACHEDOCK_H #include "cacheview.h" #include "graphicsview.h" #include "machine/machine.h" #include #include #include class CacheDock : public QDockWidget { Q_OBJECT public: CacheDock(QWidget *parent, const QString &type); void setup(const machine::Cache *cache, bool cache_after_cache = false); private slots: void hit_update(unsigned); void miss_update(unsigned); void memory_reads_update(unsigned val); void memory_writes_update(unsigned val); void statistics_update( unsigned stalled_cycles, double speed_improv, double hit_rate); private: QVBoxLayout *layout_box; QWidget *top_widget, *top_form; QFormLayout *layout_top_form; QLabel *l_hit, *l_miss, *l_stalled, *l_speed, *l_hit_rate; QLabel *no_cache; QLabel *l_m_reads, *l_m_writes; GraphicsView *graphicsview; CacheViewScene *cachescene; }; #endif // CACHEDOCK_H qtrvsim-0.9.8/src/gui/windows/cache/cacheview.cpp000066400000000000000000000332121467752164200220260ustar00rootroot00000000000000#include "cacheview.h" #include "fontsize.h" #include #include ////////////////////// #define ROW_HEIGHT 14 #define VD_WIDTH 10 #define DATA_WIDTH 72 #define PENW 1 #define LETTERW 7 ////////////////////// #include "common/endian.h" #include "machine/memory/cache/cache.h" #include using namespace std; static inline unsigned int bitsToRepresent(quint32 range_max_val) { return 32 - qCountLeadingZeroBits(range_max_val); } CacheAddressBlock::CacheAddressBlock(const machine::Cache *cache, unsigned width) { rows = cache->get_config().set_count(); columns = cache->get_config().block_size(); s_row = cache->get_config().set_count() > 1 ? bitsToRepresent(cache->get_config().set_count() - 1) : 0; this->width = width; s_col = cache->get_config().block_size() > 1 ? bitsToRepresent(cache->get_config().block_size() - 1) : 0; s_tag = 30 - s_row - s_col; // 32 bits - 2 unused and then every bit used // for different index this->width = width; tag = 0; row = 0; col = 0; connect(cache, &machine::Cache::cache_update, this, &CacheAddressBlock::cache_update); } QRectF CacheAddressBlock::boundingRect() const { return { 0, 0, static_cast(width), 40 }; } void CacheAddressBlock::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { (void)option; (void)widget; QFont fnt; fnt.setPointSize(7); painter->setFont(fnt); unsigned wpos = 5; // Part used for tag (we expect that tag is always used) unsigned wid = s_tag == 0 ? 0 : (((s_tag - 1) / 4) + 1); unsigned tag_center = wpos + wid * LETTERW / 2 + 1; QRectF rect(wpos, 16, wid * LETTERW + 2, ROW_HEIGHT); painter->drawRect(rect); painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(tag, wid, 16, QChar('0'))); wpos += wid * LETTERW + 2; // Part used for the set unsigned row_center = wpos; if (s_row > 0) { wid = s_row == 0 ? 0 : (((s_row - 1) / 4) + 1); row_center += wid * LETTERW / 2 + 1; rect = QRectF(wpos, 16, wid * LETTERW + 2, ROW_HEIGHT); painter->drawRect(rect); painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(row, wid, 16, QChar('0'))); wpos += wid * LETTERW + 2; } // Part used for block unsigned col_center = wpos; if (s_col > 0) { wid = s_col == 0 ? 0 : (((s_col - 1) / 4) + 1); col_center += wid * LETTERW / 2 + 1; rect = QRectF(wpos, 16, wid * LETTERW + 2, ROW_HEIGHT); painter->drawRect(rect); painter->drawText(rect, Qt::AlignCenter, QString("%1").arg(col, wid, 16, QChar('0'))); wpos += wid * LETTERW + 2; } // Part used for two lowers bits painter->setBrush(QBrush(QColor(Qt::gray))); painter->drawRect(wpos, 16, LETTERW + 2, ROW_HEIGHT); painter->setBrush(QBrush(QColor(Qt::black))); wpos += LETTERW + 2; // Pain address label painter->drawText(QRectF(5, 0, wpos - 5, 14), Qt::AlignCenter, "Address"); uint32_t addr = (((tag * rows) + row) * columns + col) * 4; painter->drawText( QRectF(50, 0, wpos + 40, 14), Qt::AlignCenter, "0x" + QString("%1").arg(addr, 8, 16, QChar('0'))); QPen p; p.setWidth(2); painter->setPen(p); // Tag line painter->drawLine(-8, 40, -8, 33); painter->drawLine(-8, 33, tag_center, 33); painter->drawLine(tag_center, 33, tag_center, 30); // set line if (s_row > 0) { painter->drawLine(-4, 40, row_center, 40); painter->drawLine(row_center, 40, row_center, 30); } // block line if (s_col > 0) { painter->drawLine(width - 16, 40, col_center, 40); painter->drawLine(col_center, 40, col_center, 30); } } void CacheAddressBlock::cache_update( unsigned associat, unsigned set, unsigned col, bool valid, bool dirty, uint32_t tag, const uint32_t *data, bool write) { (void)associat; (void)valid; (void)dirty; (void)data; (void)write; this->tag = tag; this->row = set; this->col = col; update(); } CacheViewBlock::CacheViewBlock(const machine::Cache *cache, unsigned block, bool last) : QGraphicsObject(nullptr) , simulated_machine_endian(cache->simulated_machine_endian) { islast = last; this->block = block; rows = cache->get_config().set_count(); columns = cache->get_config().block_size(); curr_row = 0; last_set = 0; last_col = 0; last_highlighted = false; QFont font; font.setPixelSize(FontSize::SIZE7); validity = new QGraphicsSimpleTextItem *[rows]; if (cache->get_config().write_policy() == machine::CacheConfig::WP_BACK) { dirty = new QGraphicsSimpleTextItem *[rows]; } else { dirty = nullptr; } tag = new QGraphicsSimpleTextItem *[rows]; data = new QGraphicsSimpleTextItem **[rows]; int row_y = 1; for (unsigned i = 0; i < rows; i++) { int row_x = 2; validity[i] = new QGraphicsSimpleTextItem("0", this); validity[i]->setPos(row_x, row_y); validity[i]->setFont(font); row_x += VD_WIDTH; if (dirty) { dirty[i] = new QGraphicsSimpleTextItem(this); dirty[i]->setPos(row_x, row_y); dirty[i]->setFont(font); row_x += VD_WIDTH; } tag[i] = new QGraphicsSimpleTextItem(this); tag[i]->setPos(row_x, row_y); tag[i]->setFont(font); row_x += DATA_WIDTH; data[i] = new QGraphicsSimpleTextItem *[columns]; for (unsigned y = 0; y < columns; y++) { data[i][y] = new QGraphicsSimpleTextItem(this); data[i][y]->setPos(row_x, row_y); data[i][y]->setFont(font); row_x += DATA_WIDTH; } row_y += ROW_HEIGHT; } unsigned wd = 1; auto *l_validity = new QGraphicsSimpleTextItem("V", this); l_validity->setFont(font); QRectF box = l_validity->boundingRect(); l_validity->setPos(wd + (VD_WIDTH - box.width()) / 2, -1 - box.height()); wd += VD_WIDTH; if (cache->get_config().write_policy() == machine::CacheConfig::WP_BACK) { auto *l_dirty = new QGraphicsSimpleTextItem("D", this); l_dirty->setFont(font); box = l_dirty->boundingRect(); l_dirty->setPos(wd + (VD_WIDTH - box.width()) / 2, -1 - box.height()); wd += VD_WIDTH; } auto *l_tag = new QGraphicsSimpleTextItem("Tag", this); l_tag->setFont(font); box = l_tag->boundingRect(); l_tag->setPos(wd + (DATA_WIDTH - box.width()) / 2, -1 - box.height()); wd += DATA_WIDTH; auto *l_data = new QGraphicsSimpleTextItem("Data", this); l_data->setFont(font); box = l_data->boundingRect(); l_data->setPos(wd + (columns * DATA_WIDTH - box.width()) / 2, -1 - box.height()); connect(cache, &machine::Cache::cache_update, this, &CacheViewBlock::cache_update); } CacheViewBlock::~CacheViewBlock() { delete[] validity; delete[] dirty; delete[] tag; for (unsigned y = 0; y < rows; y++) { delete[] data[y]; } delete[] data; } QRectF CacheViewBlock::boundingRect() const { return QRectF( -PENW / 2 - 11, -PENW / 2 - 16, VD_WIDTH + (dirty ? VD_WIDTH : 0) + DATA_WIDTH * (columns + 1) + PENW + 12 + (columns > 1 ? 7 : 0), ROW_HEIGHT * rows + PENW + 50); } void CacheViewBlock::paint( QPainter *painter, const QStyleOptionGraphicsItem *option __attribute__((unused)), QWidget *widget __attribute__((unused))) { // Draw horizontal lines for (unsigned i = 0; i <= rows; i++) { painter->drawLine( 0, i * ROW_HEIGHT, VD_WIDTH + (dirty ? VD_WIDTH : 0) + DATA_WIDTH * (columns + 1), i * ROW_HEIGHT); } // Draw vertical lines painter->drawLine(0, 0, 0, rows * ROW_HEIGHT); int c_width = VD_WIDTH; painter->drawLine(c_width, 0, c_width, rows * ROW_HEIGHT); if (dirty) { c_width += VD_WIDTH; painter->drawLine(c_width, 0, c_width, rows * ROW_HEIGHT); } c_width += DATA_WIDTH; painter->drawLine(c_width, 0, c_width, rows * ROW_HEIGHT); for (unsigned i = 0; i < columns; i++) { c_width += DATA_WIDTH; painter->drawLine(c_width, 0, c_width, rows * ROW_HEIGHT); } QPen p_wide, p; p.setWidth(1); p_wide.setWidth(2); painter->setPen(p); // Tag compare unsigned allright = (dirty ? 2 : 1) * VD_WIDTH + DATA_WIDTH * (columns + 1); unsigned bottom = ROW_HEIGHT * rows; unsigned tag_center = (dirty ? 2 : 1) * VD_WIDTH + DATA_WIDTH / 2; painter->drawEllipse(QPointF(tag_center, bottom + 15), 5, 5); painter->drawText(QRectF(tag_center - 5, bottom + 9.5, 10, 10), Qt::AlignCenter, "="); painter->setPen(p_wide); painter->drawLine(tag_center, bottom, tag_center, bottom + 10); painter->setPen(p); // And painter->drawLine(tag_center + 10, bottom + 25, tag_center + 10, bottom + 35); painter->drawLine(tag_center + 10, bottom + 25, tag_center + 15, bottom + 25); painter->drawLine(tag_center + 10, bottom + 35, tag_center + 15, bottom + 35); painter->drawArc(tag_center + 10, bottom + 25, 10, 10, 270 * 16, 180 * 16); // Connection from and to right painter->drawLine(tag_center + 20, bottom + 30, allright, bottom + 30); // Connection from valid to and painter->drawLine(VD_WIDTH / 2, bottom, VD_WIDTH / 2, bottom + 32); painter->drawLine(VD_WIDTH / 2, bottom + 32, tag_center + 10, bottom + 32); // Connection from tag comparison to and painter->drawLine(tag_center, bottom + 20, tag_center, bottom + 28); painter->drawLine(tag_center, bottom + 28, tag_center + 10, bottom + 28); unsigned data_start = (dirty ? 2 : 1) * VD_WIDTH + DATA_WIDTH; if (columns > 1) { // Output mutex const QPointF poly[] = { QPointF(data_start, bottom + 10), QPointF(data_start + columns * DATA_WIDTH, bottom + 10), QPointF(data_start + columns * DATA_WIDTH - 10, bottom + 20), QPointF(data_start + 10, bottom + 20) }; painter->drawPolygon(poly, sizeof(poly) / sizeof(QPointF)); unsigned data_center = data_start + DATA_WIDTH * columns / 2; painter->setPen(p_wide); painter->drawLine(data_center, bottom + 20, data_center, bottom + 25); painter->drawLine(data_center, bottom + 25, allright, bottom + 25); for (unsigned i = 0; i < columns; i++) { unsigned xpos = data_start + i * DATA_WIDTH + DATA_WIDTH / 2; painter->drawLine(xpos, bottom, xpos, bottom + 10); } // Mutex source painter->drawLine(allright + 5, -16, allright + 5, bottom + 15); painter->drawLine( allright + 5, bottom + 15, data_start + columns * DATA_WIDTH - 4, bottom + 15); if (!islast) painter->drawLine(allright + 5, bottom + 15, allright + 5, bottom + 40); } else { // Wire with data to right painter->setPen(p_wide); painter->drawLine( data_start + DATA_WIDTH / 2, bottom, data_start + DATA_WIDTH / 2, bottom + 25); painter->drawLine(data_start + DATA_WIDTH / 2, bottom + 25, allright, bottom + 25); } // Connection with tag painter->setPen(p_wide); painter->drawLine(-9, -16, -9, bottom + 15); painter->drawLine(-9, bottom + 15, tag_center - 5, bottom + 15); if (!islast) { painter->drawLine(-9, bottom + 15, -9, bottom + 40); } // Connection with row if (rows > 1) { unsigned selected = ROW_HEIGHT * curr_row + ROW_HEIGHT / 2; painter->drawLine(-5, -16, -5, islast ? selected : bottom + 40); painter->drawLine(-5, selected, 0, selected); } } void CacheViewBlock::cache_update( unsigned associat, unsigned set, unsigned col, bool valid, bool dirty, uint32_t tag, const uint32_t *data, bool write) { (void)col; if (associat != block) { if (last_highlighted) { this->data[last_set][last_col]->setBrush(QBrush(QColor(0, 0, 0))); } last_highlighted = false; return; // Ignore blocks that are not used } validity[set]->setText(valid ? "1" : "0"); if (this->dirty) { this->dirty[set]->setText(valid ? (dirty ? "1" : "0") : ""); } // TODO calculate correct size of tag this->tag[set]->setText(valid ? QString("0x") + QString("%1").arg(tag, 8, 16, QChar('0')) : ""); for (unsigned i = 0; i < columns; i++) { this->data[set][i]->setText( valid ? QString("0x") + QString("%1").arg( byteswap_if(data[i], simulated_machine_endian != NATIVE_ENDIAN), 8, 16, QChar('0')) : ""); // TODO Use cache API } if (last_highlighted) { this->data[last_set][last_col]->setBrush(QBrush(QColor(0, 0, 0))); } if (write) { this->data[set][col]->setBrush(QBrush(QColor(240, 0, 0))); } else { this->data[set][col]->setBrush(QBrush(QColor(0, 0, 240))); } last_highlighted = true; curr_row = set; last_set = set; last_col = col; update(); } CacheViewScene::CacheViewScene(const machine::Cache *cache) { associativity = cache->get_config().associativity(); block = new CacheViewBlock *[associativity]; int offset = 0; for (unsigned i = 0; i < associativity; i++) { block[i] = new CacheViewBlock(cache, i, i >= (associativity - 1)); addItem(block[i]); block[i]->setPos(1, offset); offset += block[i]->boundingRect().height(); } ablock = new CacheAddressBlock(cache, block[0]->boundingRect().width()); addItem(ablock); ablock->setPos(0, -ablock->boundingRect().height() - 16); } CacheViewScene::~CacheViewScene() { delete[] block; } qtrvsim-0.9.8/src/gui/windows/cache/cacheview.h000066400000000000000000000037561467752164200215050ustar00rootroot00000000000000#ifndef CACHEVIEW_H #define CACHEVIEW_H #include "common/endian.h" #include "graphicsview.h" #include "machine/machine.h" #include #include #include class CacheAddressBlock : public QGraphicsObject { Q_OBJECT public: CacheAddressBlock(const machine::Cache *cache, unsigned width); [[nodiscard]] QRectF boundingRect() const override; void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; private slots: void cache_update( unsigned associat, unsigned set, unsigned col, bool valid, bool dirty, uint32_t tag, const uint32_t *data, bool write); private: unsigned rows, columns; unsigned tag, row, col; unsigned s_tag, s_row, s_col; unsigned width; }; class CacheViewBlock : public QGraphicsObject { Q_OBJECT public: CacheViewBlock(const machine::Cache *cache, unsigned block, bool last); ~CacheViewBlock() override; [[nodiscard]] QRectF boundingRect() const override; void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; private slots: virtual void cache_update( unsigned associat, unsigned set, unsigned col, bool valid, bool dirty, uint32_t tag, const uint32_t *data, bool write); private: const Endian simulated_machine_endian; bool islast; unsigned block; unsigned rows, columns; QGraphicsSimpleTextItem **validity, **dirty, **tag, ***data; unsigned curr_row; bool last_highlighted; unsigned last_set; unsigned last_col; }; class CacheViewScene : public QGraphicsScene { Q_OBJECT public: explicit CacheViewScene(const machine::Cache *cache); ~CacheViewScene() override; private: unsigned associativity; CacheViewBlock **block; CacheAddressBlock *ablock; }; #endif // CACHEVIEW_H qtrvsim-0.9.8/src/gui/windows/coreview/000077500000000000000000000000001467752164200201435ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/coreview/components/000077500000000000000000000000001467752164200223305ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/coreview/components/cache.cpp000066400000000000000000000010521467752164200240750ustar00rootroot00000000000000#include "cache.h" Cache::Cache( const machine::Cache *cache, svgscene::SimpleTextItem *hit_text, svgscene::SimpleTextItem *mis_text) : QObject() , hit_text(hit_text) , mis_text(mis_text) { connect(cache, &machine::Cache::hit_update, this, &Cache::hit_update); connect(cache, &machine::Cache::miss_update, this, &Cache::miss_update); } void Cache::hit_update(unsigned value) { hit_text->setText(QString::number(value)); } void Cache::miss_update(unsigned int value) { mis_text->setText(QString::number(value)); } qtrvsim-0.9.8/src/gui/windows/coreview/components/cache.h000066400000000000000000000011331467752164200235420ustar00rootroot00000000000000#ifndef QTRVSIM_CACHE_H #define QTRVSIM_CACHE_H #include #include #include #include class Cache : public QObject { public: Cache( const machine::Cache *cache, svgscene::SimpleTextItem *hit_text, svgscene::SimpleTextItem *mis_text); protected slots: void hit_update(unsigned value); void miss_update(unsigned value); protected: BORROWED svgscene::SimpleTextItem *hit_text; BORROWED svgscene::SimpleTextItem *mis_text; }; #endif // QTRVSIM_CACHE_H qtrvsim-0.9.8/src/gui/windows/coreview/components/value_handlers.cpp000066400000000000000000000051331467752164200260320ustar00rootroot00000000000000#include "value_handlers.h" #include using svgscene::SimpleTextItem; const QString BoolValue::COMPONENT_NAME = QStringLiteral("bool-value"); const QString PCValue::COMPONENT_NAME = QStringLiteral("pc-value"); const QString RegValue::COMPONENT_NAME = QStringLiteral("reg-value"); const QString RegIdValue::COMPONENT_NAME = QStringLiteral("reg-id-value"); const QString DebugValue::COMPONENT_NAME = QStringLiteral("debug-value"); const QString MultiTextValue::COMPONENT_NAME = QStringLiteral("multi-text-value"); const QString InstructionValue::COMPONENT_NAME = QStringLiteral("instruction-value"); BoolValue::BoolValue(SimpleTextItem *const element, const bool &data) : element(element) , data(data) {} void BoolValue::update() { element->setText(data ? QStringLiteral("1") : QStringLiteral("0")); } PCValue::PCValue(SimpleTextItem *element, const machine::Address &data) : element(element) , data(data) {} PCValue::PCValue(const PCValue &other) : QObject(other.parent()) , element(other.element) , data(other.data) {} void PCValue::clicked() { emit jump_to_pc(data); } void PCValue::update() { element->setText(QString("0x%1").arg(data.get_raw(), 8, 16, QChar('0'))); } RegValue::RegValue(SimpleTextItem *element, const machine::RegisterValue &data) : element(element) , data(data) {} void RegValue::update() { element->setText(QString("%1").arg(data.as_u32(), 8, 16, QChar('0'))); } RegIdValue::RegIdValue(svgscene::SimpleTextItem *element, const machine::RegisterId &data) : element(element) , data(data) {} void RegIdValue::update() { element->setText(QString("%1").arg(data, 2, 10, QChar('0'))); } DebugValue::DebugValue(SimpleTextItem *element, const unsigned int &data) : element(element) , data(data) {} void DebugValue::update() { element->setText(QString("%1").arg(data, 0, 10, QChar(' '))); } MultiTextValue::MultiTextValue(SimpleTextItem *const element, Data data) : element(element) , current_text_index(data.first) , text_table(data.second) , originalBrush(element->brush()) {} void MultiTextValue::update() { if (current_text_index != 0) { // Highlight non-default value. element->setBrush(Qt::red); } else { element->setBrush(originalBrush); } element->setText(text_table.at(current_text_index)); } InstructionValue::InstructionValue(SimpleTextItem *const element, Data data) : element(element) , instruction_data(data.first) , address_data(data.second) {} void InstructionValue::update() { element->setText(instruction_data.to_str(address_data)); } qtrvsim-0.9.8/src/gui/windows/coreview/components/value_handlers.h000066400000000000000000000074421467752164200255040ustar00rootroot00000000000000/** * Components defined in here update the GUI placeholders with up to date * values that is read from provided source. * * Components accept different types and produce different formatting. * * @file */ #ifndef QTRVSIM_VALUE_HANDLERS_H #define QTRVSIM_VALUE_HANDLERS_H #include #include #include #include #include #include #include #include #include #include class BoolValue { public: BoolValue(svgscene::SimpleTextItem *element, const bool &data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const bool &data; }; class PCValue : public QObject { Q_OBJECT public slots: void clicked(); signals: void jump_to_pc(machine::Address pc_value); public: PCValue(svgscene::SimpleTextItem *element, const machine::Address &data); PCValue(const PCValue &); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const machine::Address &data; }; class RegValue { public: RegValue(svgscene::SimpleTextItem *element, const machine::RegisterValue &data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const machine::RegisterValue &data; }; class RegIdValue { public: RegIdValue(svgscene::SimpleTextItem *element, const machine::RegisterId &data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const machine::RegisterId &data; }; class DebugValue { public: DebugValue(svgscene::SimpleTextItem *element, const unsigned int &data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const unsigned &data; }; class MultiTextValue { using Source = const std::unordered_map &; using Data = std::pair; public: MultiTextValue(svgscene::SimpleTextItem *element, Data data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const unsigned ¤t_text_index; Source &text_table; QBrush originalBrush; }; class InstructionValue { using Data = std::pair; public: InstructionValue(svgscene::SimpleTextItem *element, Data data); void update(); static const QString COMPONENT_NAME; private: BORROWED svgscene::SimpleTextItem *const element; const machine::Instruction &instruction_data; const machine::Address &address_data; }; template class Multiplexer { public: Multiplexer( std::vector connections, const SOURCE &active_connection) : connections(std::move(connections)) , active_connection(active_connection) , current_active_connection(0) { // Hide all but first for (size_t i = 1; i < this->connections.size(); ++i) { this->connections.at(i)->hide(); } } void update() { if (current_active_connection != active_connection) { connections.at(static_cast(current_active_connection))->hide(); connections.at(static_cast(active_connection))->show(); current_active_connection = active_connection; } } private: const std::vector connections; const SOURCE &active_connection; SOURCE current_active_connection; }; #endif // QTRVSIM_VALUE_HANDLERS_H qtrvsim-0.9.8/src/gui/windows/coreview/data.h000066400000000000000000000254551467752164200212400ustar00rootroot00000000000000/** * This file contains maps with data for core visualization. * - Tables of strings. * - Maps of string hook used in SVG files onto lenses into the core state * struct. (see `common/type_utils/lens`) * * @file */ #ifndef QTRVSIM_DATA_H #define QTRVSIM_DATA_H #include "common/type_utils/lens.h" #include using std::pair; using std::unordered_map; using std::vector; class CoreViewScene; using machine::Address; using machine::CoreState; using machine::Instruction; using machine::RegisterId; using machine::RegisterValue; static const std::unordered_map EXCEPTION_NAME_TABLE = { { machine::EXCAUSE_NONE, QStringLiteral("NONE") }, { machine::EXCAUSE_INSN_FAULT, QStringLiteral("I_FAULT") }, { machine::EXCAUSE_INSN_ILLEGAL, QStringLiteral("I_ILLEGAL") }, { machine::EXCAUSE_BREAK, QStringLiteral("BREAK") }, { machine::EXCAUSE_LOAD_MISALIGNED, QStringLiteral("L_MALIGN") }, { machine::EXCAUSE_LOAD_FAULT, QStringLiteral("L_FAULT") }, { machine::EXCAUSE_STORE_MISALIGNED, QStringLiteral("S_MALIGN") }, { machine::EXCAUSE_STORE_FAULT, QStringLiteral("S_FAULT") }, { machine::EXCAUSE_ECALL_U, QStringLiteral("ECALL_U") }, { machine::EXCAUSE_ECALL_S, QStringLiteral("ECALL_S") }, { machine::EXCAUSE_RESERVED_10, QStringLiteral("RES_10") }, { machine::EXCAUSE_ECALL_M, QStringLiteral("ECALL_M") }, { machine::EXCAUSE_INSN_PAGE_FAULT, QStringLiteral("I_PGFAULT") }, { machine::EXCAUSE_LOAD_PAGE_FAULT, QStringLiteral("L_PGFAULT") }, { machine::EXCAUSE_RESERVED_14, QStringLiteral("RES_14") }, { machine::EXCAUSE_STORE_PAGE_FAULT, QStringLiteral("S_PGFAULT") }, // Simulator specific exception cause codes, alliases { machine::EXCAUSE_HWBREAK, QStringLiteral("HWBREAK") }, { machine::EXCAUSE_ECALL_ANY, QStringLiteral("ECALL") }, { machine::EXCAUSE_INT, QStringLiteral("INT") }, }; static const std::unordered_map STALL_TEXT_TABLE = { { 0, QStringLiteral("NORMAL") }, { 1, QStringLiteral("STALL") }, { 2, QStringLiteral("FORWARD") }, }; /** * Link targets available for use in the SVG. * * EXAMPLE: * ```svg * * Registers * * ``` */ static const unordered_map HYPERLINK_TARGETS { { "#focus_pc", &CoreViewScene::request_jump_to_program_counter_wrapper }, { "#registers", &CoreViewScene::request_registers }, { "#cache_data", &CoreViewScene::request_cache_data }, { "#cache_program", &CoreViewScene::request_cache_program }, { "#data_memory", &CoreViewScene::request_data_memory }, { "#peripherals", &CoreViewScene::request_peripherals }, { "#program_memory", &CoreViewScene::request_program_memory }, { "#terminal", &CoreViewScene::request_terminal }, }; using MultiTextData = pair &>; /** * Maps SVG usable value names to lenses (lazy references) to fields, where thy * can be * retrieved. */ const struct { const unordered_map> BOOL { { QStringLiteral("decode-RegWrite"), LENS(CoreState, pipeline.decode.result.regwrite) }, { QStringLiteral("decode-MemToReg"), LENS(CoreState, pipeline.decode.result.memread) }, { QStringLiteral("decode-MemWrite"), LENS(CoreState, pipeline.decode.result.memwrite) }, { QStringLiteral("decode-MemRead"), LENS(CoreState, pipeline.decode.result.memread) }, { QStringLiteral("decode-BranchBxx"), LENS(CoreState, pipeline.decode.result.branch_bxx) }, { QStringLiteral("decode-BranchJal"), LENS(CoreState, pipeline.decode.result.branch_jal) }, { QStringLiteral("decode-BranchJalr"), LENS(CoreState, pipeline.decode.result.branch_jalr) }, { QStringLiteral("decode-BranchVal"), LENS(CoreState, pipeline.decode.result.branch_val) }, { QStringLiteral("decode-AluMul"), LENS(CoreState, pipeline.decode.internal.alu_mul) }, { QStringLiteral("decode-AluSrc"), LENS(CoreState, pipeline.decode.result.alusrc) }, { QStringLiteral("decode-AuiPC"), LENS(CoreState, pipeline.decode.result.alu_pc) }, { QStringLiteral("exec-RegWrite"), LENS(CoreState, pipeline.execute.result.regwrite) }, { QStringLiteral("exec-MemToReg"), LENS(CoreState, pipeline.execute.result.memread) }, { QStringLiteral("exec-MemWrite"), LENS(CoreState, pipeline.execute.result.memwrite) }, { QStringLiteral("exec-MemRead"), LENS(CoreState, pipeline.execute.result.memread) }, { QStringLiteral("exec-BranchBxx"), LENS(CoreState, pipeline.execute.internal.branch_bxx) }, { QStringLiteral("exec-BranchJal"), LENS(CoreState, pipeline.execute.result.branch_jal) }, { QStringLiteral("exec-BranchJalr"), LENS(CoreState, pipeline.execute.result.branch_jalr) }, { QStringLiteral("exec-BranchVal"), LENS(CoreState, pipeline.execute.result.branch_val) }, { QStringLiteral("exec-AluMul"), LENS(CoreState, pipeline.execute.internal.alu_mul) }, { QStringLiteral("exec-AluSrc"), LENS(CoreState, pipeline.execute.internal.alu_src) }, { QStringLiteral("exec-AuiPC"), LENS(CoreState, pipeline.execute.internal.alu_pc) }, { QStringLiteral("exec-AluZero"), LENS(CoreState, pipeline.execute.result.alu_zero) }, { QStringLiteral("mem-RegWrite"), LENS(CoreState, pipeline.memory.result.regwrite) }, { QStringLiteral("mem-MemToReg"), LENS(CoreState, pipeline.memory.result.memtoreg) }, { QStringLiteral("mem-MemWrite"), LENS(CoreState, pipeline.memory.internal.memwrite) }, { QStringLiteral("mem-MemRead"), LENS(CoreState, pipeline.memory.internal.memread) }, { QStringLiteral("mem-BranchOutcome"), LENS(CoreState, pipeline.memory.internal.branch_outcome) }, { QStringLiteral("mem-BranchJalx"), LENS(CoreState, pipeline.memory.internal.branch_jalx) }, { QStringLiteral("mem-BranchJalr"), LENS(CoreState, pipeline.memory.internal.branch_jalr) }, { QStringLiteral("wb-RegWrite"), LENS(CoreState, pipeline.writeback.internal.regwrite) }, { QStringLiteral("wb-MemToReg"), LENS(CoreState, pipeline.writeback.internal.memtoreg) }, }; const unordered_map> REG { { QStringLiteral("alu-res"), LENS(CoreState, pipeline.execute.result.alu_val) }, { QStringLiteral("alu-src1"), LENS(CoreState, pipeline.execute.internal.alu_src1) }, { QStringLiteral("alu-src2"), LENS(CoreState, pipeline.execute.internal.alu_src2) }, { QStringLiteral("decode-imm"), LENS(CoreState, pipeline.decode.result.immediate_val) }, { QStringLiteral("exec-imm"), LENS(CoreState, pipeline.execute.result.immediate_val) }, { QStringLiteral("decode-inst-bus"), LENS(CoreState, pipeline.decode.internal.inst_bus) }, { QStringLiteral("mem-write-val"), LENS(CoreState, pipeline.memory.internal.mem_write_val) }, { QStringLiteral("mem-write-addr"), LENS(CoreState, pipeline.memory.internal.mem_addr) }, { QStringLiteral("mem-read-val"), LENS(CoreState, pipeline.memory.internal.mem_read_val) }, { QStringLiteral("decode-rs1"), LENS(CoreState, pipeline.decode.result.val_rs) }, { QStringLiteral("decode-rs2"), LENS(CoreState, pipeline.decode.result.val_rt) }, { QStringLiteral("exec-rs1"), LENS(CoreState, pipeline.execute.internal.rs) }, { QStringLiteral("exec-rs2"), LENS(CoreState, pipeline.execute.internal.rt) }, { QStringLiteral("wb"), LENS(CoreState, pipeline.writeback.internal.value) }, }; const unordered_map> REG_ID { { QStringLiteral("decode-rd"), LENS(CoreState, pipeline.decode.result.num_rd) }, { QStringLiteral("exec-rd"), LENS(CoreState, pipeline.execute.result.num_rd) }, { QStringLiteral("mem-rd"), LENS(CoreState, pipeline.memory.result.num_rd) }, { QStringLiteral("wb-rd"), LENS(CoreState, pipeline.writeback.internal.num_rd) }, { QStringLiteral("rs1"), LENS(CoreState, pipeline.decode.result.num_rs) }, { QStringLiteral("rs2"), LENS(CoreState, pipeline.decode.result.num_rt) }, }; const unordered_map> DEBUG_VAL { { QStringLiteral("CycleCount"), LENS(CoreState, cycle_count) }, { QStringLiteral("StallCount"), LENS(CoreState, stall_count) }, { QStringLiteral("decode-AluControl"), LENS(CoreState, pipeline.decode.internal.alu_op_num) }, { QStringLiteral("exec-AluControl"), LENS(CoreState, pipeline.execute.internal.alu_op_num) }, { QStringLiteral("exec-ForwardA"), LENS(CoreState, pipeline.execute.internal.forward_from_rs1_num) }, { QStringLiteral("exec-ForwardB"), LENS(CoreState, pipeline.execute.internal.forward_from_rs2_num) }, }; const unordered_map> PC { { QStringLiteral("fetch-pc"), LENS(CoreState, pipeline.fetch.result.inst_addr) }, }; #define MULTITEXT_LENS(INDEX, TABLE) \ [](const CoreState &base) -> MultiTextData { return { base.INDEX, TABLE }; } const unordered_map< QStringView, LensPair>> MULTI_TEXT { { QStringLiteral("fetch-exception"), MULTITEXT_LENS(pipeline.fetch.internal.excause_num, EXCEPTION_NAME_TABLE) }, { QStringLiteral("decode-exception"), MULTITEXT_LENS(pipeline.decode.internal.excause_num, EXCEPTION_NAME_TABLE) }, { QStringLiteral("execute-exception"), MULTITEXT_LENS(pipeline.execute.internal.excause_num, EXCEPTION_NAME_TABLE) }, { QStringLiteral("memory-exception"), MULTITEXT_LENS(pipeline.memory.internal.excause_num, EXCEPTION_NAME_TABLE) }, { QStringLiteral("hazard"), MULTITEXT_LENS(pipeline.execute.internal.stall_status, STALL_TEXT_TABLE) }, }; const unordered_map> INSTRUCTION { { QStringLiteral("fetch"), LENS_PAIR(CoreState, pipeline.fetch.result.inst, pipeline.fetch.result.inst_addr) }, { QStringLiteral("decode"), LENS_PAIR(CoreState, pipeline.decode.result.inst, pipeline.decode.result.inst_addr) }, { QStringLiteral("exec"), LENS_PAIR(CoreState, pipeline.execute.result.inst, pipeline.execute.result.inst_addr) }, { QStringLiteral("mem"), LENS_PAIR(CoreState, pipeline.memory.result.inst, pipeline.memory.result.inst_addr) }, { QStringLiteral("wb"), { LENS_PAIR( CoreState, pipeline.writeback.internal.inst, pipeline.writeback.internal.inst_addr) } }, }; } VALUE_SOURCE_NAME_MAPS; #endif // QTRVSIM_DATA_H qtrvsim-0.9.8/src/gui/windows/coreview/scene.cpp000066400000000000000000000247371467752164200217610ustar00rootroot00000000000000#include "scene.h" #include "common/logging.h" #include "data.h" #include "machine/core.h" #include #include #include #include #include using std::unordered_map; using std::vector; using svgscene::HyperlinkItem; using svgscene::SimpleTextItem; using svgscene::SvgDocument; using svgscene::SvgDomTree; LOG_CATEGORY("gui.coreview"); CoreViewScene::CoreViewScene(machine::Machine *machine, const QString &core_svg_scheme_name) : SvgGraphicsScene() , program_counter_value((VALUE_SOURCE_NAME_MAPS.PC.at(QStringLiteral("fetch-pc")))( machine->core()->get_state())) { SvgDocument document = svgscene::parseFromFileName(this, QString(":/core/%1.svg").arg(core_svg_scheme_name)); for (auto hyperlink_tree : document.getRoot().findAll()) { this->install_hyperlink(hyperlink_tree.getElement()); } /* * TODO: * Components not implemented: * - colored frames on special values */ const machine::CoreState &core_state = machine->core()->get_state(); // Find all components in the DOM tree and install controllers for them. for (auto component : document.getRoot().findAll("data-component")) { QStringView component_name = component.getAttrValueOr("data-component"); if (component_name.isEmpty()) { continue; } // This switch is performance optimization. // Single char lookup will usually give only one match, outperforming // a hashtable, which has to check the key in the end as well hut // hashing is more complex than single char lookup. switch (component_name.at(0).toLatin1()) { case 'b': { if (component_name == BoolValue::COMPONENT_NAME) { install_value( values.bool_values, VALUE_SOURCE_NAME_MAPS.BOOL, component, core_state); } break; } case 'd': { if (component_name == DebugValue::COMPONENT_NAME) { install_value( values.debug_values, VALUE_SOURCE_NAME_MAPS.DEBUG_VAL, component, core_state); } else if (component_name == QStringLiteral("data-cache")) { if (machine->config().cache_data().enabled()) { auto texts = component.findAll(); // Diagrams.net dow not allow me, to put there some marks. // :( auto miss = texts.takeLast().getElement(); auto hit = texts.takeLast().getElement(); data_cache.reset(new Cache(machine->cache_data(), hit, miss)); } else { component.getElement()->hide(); } } break; } case 'i': { if (component_name == InstructionValue::COMPONENT_NAME) { install_value( values.instruction_values, VALUE_SOURCE_NAME_MAPS.INSTRUCTION, component, core_state); } break; } case 'm': { if (component_name == MultiTextValue::COMPONENT_NAME) { install_value( values.multi_text_values, VALUE_SOURCE_NAME_MAPS.MULTI_TEXT, component, core_state); } else if (component_name == QStringLiteral("mux2")) { const QString &source_name = component.getAttrValueOr("data-source"); // Draw.io does not allow tagging the paths, to I use this style identification hack. auto conn_trees = component.findAll("stroke-linecap", "round"); if (conn_trees.size() != 2) { WARN( "Mux2 does not have 2 connections found %zi (source: \"%s\").", conn_trees.size(), qPrintable(source_name)); break; } std::vector connections; connections.reserve(conn_trees.size()); std::transform( conn_trees.begin(), conn_trees.end(), std::back_inserter(connections), [](SvgDomTree &e) { return e.getElement(); }); try { const bool &source = VALUE_SOURCE_NAME_MAPS.BOOL.at(source_name)(core_state); values.mux2_values.emplace_back(std::move(connections), source); } catch (std::out_of_range &e) { WARN( "Source for mux2 value not found (source: \"%s\").", qPrintable(source_name)); } } else if (component_name == QStringLiteral("mux3")) { const QString &source_name = component.getAttrValueOr("data-source"); // Draw.io does not allow tagging the paths, to I use this style identification hack. auto conn_trees = component.findAll("stroke-linecap", "round"); if (conn_trees.size() != 3) { WARN( "Mux3 does not have 3 connections found %lld (source: \"%s\").", conn_trees.size(), qPrintable(source_name)); break; } std::vector connections; connections.reserve(conn_trees.size()); std::transform( conn_trees.begin(), conn_trees.end(), std::back_inserter(connections), [](SvgDomTree &e) { return e.getElement(); }); try { const unsigned &source = VALUE_SOURCE_NAME_MAPS.DEBUG_VAL.at(source_name)(core_state); values.mux3_values.emplace_back(std::move(connections), source); } catch (std::out_of_range &e) { WARN( "Source for mux3 value not found (source: \"%s\").", qPrintable(source_name)); } } break; } case 'p': { if (component_name == PCValue::COMPONENT_NAME) { install_value(values.pc_values, VALUE_SOURCE_NAME_MAPS.PC, component, core_state); } else if (component_name == QStringLiteral("program-cache")) { if (machine->config().cache_program().enabled()) { auto texts = component.findAll(); // Diagrams.net does not allow me, to put there some // marks. :( auto miss = texts.takeLast().getElement(); auto hit = texts.takeLast().getElement(); program_cache.reset(new Cache(machine->cache_program(), hit, miss)); } else { component.getElement()->hide(); } } break; } case 'r': { if (component_name == RegValue::COMPONENT_NAME) { install_value(values.reg_values, VALUE_SOURCE_NAME_MAPS.REG, component, core_state); } else if (component_name == RegIdValue::COMPONENT_NAME) { install_value( values.reg_id_values, VALUE_SOURCE_NAME_MAPS.REG_ID, component, core_state); } break; } } } if (machine->config().hazard_unit() == machine::MachineConfig::HU_NONE) { // Hazard unit conditional hide for (auto elem_tree : document.getRoot().findAll("data-tags", "hazardunit")) { elem_tree.getElement()->hide(); } } update_values(); // Set to initial value - most often zero. // Update coreview with each core step. connect(machine->core(), &machine::Core::step_done, this, &CoreViewScene::update_values); } CoreViewScene::~CoreViewScene() = default; void CoreViewScene::install_hyperlink(svgscene::HyperlinkItem *element) const { if (element->getTargetName() == "#") { DEBUG("Skipping NOP hyperlink."); return; } try { connect( element, &svgscene::HyperlinkItem::triggered, this, HYPERLINK_TARGETS.at(element->getTargetName())); DEBUG("Registered hyperlink to target %s", qPrintable(element->getTargetName())); } catch (std::out_of_range &) { WARN( "Registering hyperlink without valid target (href: \"%s\").", qPrintable(element->getTargetName())); } } template void CoreViewScene::install_value( vector &handler_list, const unordered_map &value_source_name_map, SvgDomTree component, const CoreState &core_state) { SimpleTextItem *text_element = component.template find().getElement(); const QString &source_name = component.getAttrValueOr("data-source"); try { handler_list.emplace_back(text_element, value_source_name_map.at(source_name)(core_state)); DEBUG( "Installing value %s with source %s.", qPrintable(T_handler::COMPONENT_NAME), qPrintable(source_name)); } catch (std::out_of_range &) { WARN( "Source for %s value not found (source: \"%s\").", typeid(T).name(), qPrintable(source_name)); } } template void CoreViewScene::update_value_list(std::vector &value_list) { DEBUG("Calling full update of %s...", typeid(T).name()); for (auto &value_handler : value_list) { value_handler.update(); } } void CoreViewScene::update_values() { update_value_list(values.bool_values); update_value_list(values.debug_values); update_value_list(values.reg_values); update_value_list(values.reg_id_values); update_value_list(values.pc_values); update_value_list(values.multi_text_values); update_value_list(values.instruction_values); update_value_list(values.mux2_values); update_value_list(values.mux3_values); } void CoreViewScene::request_jump_to_program_counter_wrapper() { emit request_jump_to_program_counter(program_counter_value); } CoreViewSceneSimple::CoreViewSceneSimple(machine::Machine *machine) : CoreViewScene(machine, "simple") {} CoreViewScenePipelined::CoreViewScenePipelined(machine::Machine *machine) : CoreViewScene( machine, (machine->config().hazard_unit() == machine::MachineConfig::HU_STALL_FORWARD) ? "forwarding" : "pipeline") {} qtrvsim-0.9.8/src/gui/windows/coreview/scene.h000066400000000000000000000074401467752164200214160ustar00rootroot00000000000000#ifndef QTRVSIM_SCENE_H #define QTRVSIM_SCENE_H #include "./components/cache.h" #include "./components/value_handlers.h" #include "common/polyfills/qstring_hash.h" #include "graphicsview.h" #include #include #include #include #include #include #include #include class CoreViewScene : public svgscene::SvgGraphicsScene { Q_OBJECT public: CoreViewScene(machine::Machine *machine, const QString &core_svg_scheme_name); ~CoreViewScene() override; /** Hyperlink handler which automatically uses current PC value via this object */ void request_jump_to_program_counter_wrapper(); signals: /* Hyperlink handlers propagated to the main window. */ void request_registers(); void request_data_memory(); void request_program_memory(); void request_jump_to_program_counter(machine::Address addr); void request_cache_program(); void request_cache_data(); void request_peripherals(); void request_terminal(); public slots: /** * Update all installed dynamic values. * * @see install_value */ void update_values(); protected: /** * Lookup link target and connect element one of `request_` slots. * @param element the clickable element */ void install_hyperlink(svgscene::HyperlinkItem *element) const; /** * Create update handler for dynamic value in core view. * * @tparam T_handler one of classes in * `coreview/components/numeric_value.h` * @tparam T type of value to update from * @param handler_list list, where the created handler will be * stored * @param value_source_name_map maps of load_sections_indexes names used in svg to * references in the state struct * @param component text element that will be updated * @param source_name name of data source, see * value_source_name_map */ template void install_value( std::vector &handler_list, const std::unordered_map &value_source_name_map, svgscene::SvgDomTree component, const machine::CoreState &core_state); /** * Update all value components of given type. * * @tparam T type of component * @param value_list list of components * @see install_value */ template void update_value_list(std::vector &value_list); protected: /** * Lists of dynamic values from svg that should updated each cycle. */ struct { std::vector bool_values; std::vector reg_values; std::vector reg_id_values; std::vector debug_values; std::vector pc_values; std::vector multi_text_values; std::vector instruction_values; std::vector> mux2_values; std::vector> mux3_values; } values; Box program_cache; Box data_cache; /** Reference to current PC value to be used to focus PC in program memory on lick */ const machine::Address& program_counter_value; }; class CoreViewSceneSimple : public CoreViewScene { public: explicit CoreViewSceneSimple(machine::Machine *machine); }; class CoreViewScenePipelined : public CoreViewScene { public: explicit CoreViewScenePipelined(machine::Machine *machine); }; #endif qtrvsim-0.9.8/src/gui/windows/coreview/schemas/000077500000000000000000000000001467752164200215665ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/coreview/schemas/forwarding.svg000066400000000000000000004311301467752164200244530ustar00rootroot00000000000000 NONE NONE NONE NONE Immediate decode 00 00 rs1 00000000 00000000 ALU zero Peripherals MemToReg MemWrite BranchBxx AluControl Data Memory Cache Hit: Miss: 0 0 4 RegWrite BranchJalr RegWrite rd 00000000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Hazard Unit: NORMAL ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 00 Registers 00000000 00 00000000 Terminal Cycles: Stalls: 0 0 00000000 AuiPC 0 0 BranchVal 0 0 0 0 0 IF/ID rs2 00000000 00000000 0 AluSrc BranchJal ID/EX 00000000 00000000 00000000 Control Unit 0  PC+4   PC  00 rd 00 MEM/WB 00000000  WriteData  xor Branch Jalx EX/MEM 00000000 BranchOutcome 0 Program Memory Cache Hit: Miss: 0 0  PC+4  rd rd  BranchTarget  Instruction  RegWriteData   PC+4   PC  AluMul 0 0 0  AluOut 0 MemRead 0 0 MemWrite MemRead 0 0 Branch Jalr 0x00000000 PC 00000000 qtrvsim-0.9.8/src/gui/windows/coreview/schemas/pipeline.svg000066400000000000000000004053311467752164200241220ustar00rootroot00000000000000 NONE NONE NONE NONE Immediate decode 00 00 rs1 00000000 00000000 ALU zero Peripherals MemToReg MemWrite BranchBxx AluControl Data Memory Cache Hit: Miss: 0 0 4 RegWrite BranchJalr RegWrite rd 00000000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Hazard Unit: NORMAL ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 ADD $0, $1, $3 00 Registers 00000000 00 00000000 Terminal Cycles: Stalls: 0 0 00000000 AuiPC 0 BranchVal 0 0 0 0 0 IF/ID rs2 00000000 00000000 0 AluSrc BranchJal ID/EX 00000000 00000000 00000000 Control Unit 0  PC+4   PC  00 rd 00 MEM/WB 00000000  WriteData  xor Branch Jalx EX/MEM 00000000 BranchOutcome 0 Program Memory Cache Hit: Miss: 0 0  PC+4  rd rd  BranchTarget  Instruction  RegWriteData   PC+4   PC  AluMul 0 0 0  AluOut 0 MemRead 0 0 MemWrite MemRead 0 0 Branch Jalr 0x00000000 PC 00000000 qtrvsim-0.9.8/src/gui/windows/coreview/schemas/schemas.qrc000066400000000000000000000002431467752164200237170ustar00rootroot00000000000000 simple.svg pipeline.svg forwarding.svg qtrvsim-0.9.8/src/gui/windows/coreview/schemas/simple.svg000066400000000000000000003177241467752164200236160ustar00rootroot00000000000000 NONE Immediate decode 00 00 rs1 00000000 00000000 ALU zero Peripherals MemToReg MemWrite BranchBxx AluControl Data Memory Cache Hit: Miss: 0 0 4 BranchJalr RegWrite rd 00000000 0 0 0 0 0 0 0 0 0 0 Hazard Unit: NORMAL ADD $0, $1, $3 Registers 00000000 00 00000000 Terminal Cycles: Stalls: 0 0 00000000 AuiPC BranchVal 0 0 0 0 rs2 00000000 00000000 0 AluSrc BranchJal 00000000 Control Unit  PC+4   PC  00 rd  WriteData  xor Branch Jalx 00000000 BranchOutcome 0 Program Memory Cache Hit: Miss: 0 0  PC+4   BranchTarget  Instruction  RegWriteData   PC+4   PC  AluMul 0 0 0  AluOut 0 MemRead 0 MemWrite MemRead 0 0 Branch Jalr 0x00000000 PC qtrvsim-0.9.8/src/gui/windows/csr/000077500000000000000000000000001467752164200171075ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/csr/csrdock.cpp000066400000000000000000000102171467752164200212440ustar00rootroot00000000000000#include "csrdock.h" #include "csr/controlstate.h" CsrDock::CsrDock(QWidget *parent) : QDockWidget(parent) { scrollarea = new QScrollArea(this); scrollarea->setWidgetResizable(true); widg = new StaticTable(scrollarea); xlen = machine::Xlen::_32; for (size_t i = 0; i < machine::CSR::REGISTERS.size(); i++) { auto &desc = machine::CSR::REGISTERS.at(i); csr_view[i] = new QLabel(sizeHintText(), widg); csr_view[i]->setFixedSize(csr_view[i]->sizeHint()); csr_view[i]->setText(""); csr_view[i]->setTextInteractionFlags(Qt::TextSelectableByMouse); auto desc_label = new QLabel(QString(desc.name), widg); desc_label->setToolTip( (QString("%0 (0x%1)").arg(desc.description).arg(desc.address.data, 0, 16))); widg->addRow({ desc_label, csr_view[i] }); csr_highlighted[i] = false; } scrollarea->setWidget(widg); setWidget(scrollarea); setObjectName("Control and Status Registers"); setWindowTitle("Control and Status Registers"); pal_normal = QPalette(csr_view[1]->palette()); pal_updated = QPalette(csr_view[1]->palette()); pal_read = QPalette(csr_view[1]->palette()); pal_normal.setColor(QPalette::WindowText, QColor(0, 0, 0)); pal_updated.setColor(QPalette::WindowText, QColor(240, 0, 0)); pal_read.setColor(QPalette::WindowText, QColor(0, 0, 240)); csr_highlighted_any = false; } const char *CsrDock::sizeHintText() { if (xlen == machine::Xlen::_64) return "0x0000000000000000"; else return "0x00000000"; } void CsrDock::setup(machine::Machine *machine) { if (machine == nullptr) { // Reset data for (auto &i : csr_view) { i->setText(""); } return; } const machine::CSR::ControlState *controlst = machine->control_state(); if (controlst == nullptr) return; // if xlen changes adjust space to show full value if (xlen != machine->config().get_simulated_xlen()) { xlen = machine->config().get_simulated_xlen(); auto *dumy_data_label = new QLabel(sizeHintText(), widg); for (size_t i = 0; i < machine::CSR::REGISTERS.size(); i++) { csr_view[i]->setFixedSize(dumy_data_label->sizeHint()); } delete dumy_data_label; } for (size_t i = 0; i < machine::CSR::REGISTERS.size(); i++) { labelVal(csr_view[i], controlst->read_internal(i).as_xlen(xlen)); } connect(controlst, &machine::CSR::ControlState::write_signal, this, &CsrDock::csr_changed); connect(controlst, &machine::CSR::ControlState::read_signal, this, &CsrDock::csr_read); connect(machine, &machine::Machine::tick, this, &CsrDock::clear_highlights); } void CsrDock::csr_changed(size_t internal_reg_id, machine::RegisterValue val) { // FIXME assert takes literal SANITY_ASSERT( (uint)internal_reg_id < machine::CSR::REGISTERS.size(), QString("CsrDock received signal with invalid CSR register: ") + QString::number((uint)internal_reg_id)); labelVal(csr_view[(uint)internal_reg_id], val.as_xlen(xlen)); csr_view[internal_reg_id]->setPalette(pal_updated); csr_highlighted[internal_reg_id] = true; csr_highlighted_any = true; } void CsrDock::csr_read(size_t internal_reg_id, machine::RegisterValue val) { (void)val; // FIXME assert takes literal SANITY_ASSERT( (uint)internal_reg_id < machine::CSR::REGISTERS.size(), QString("CsrDock received signal with invalid CSR register: ") + QString::number((uint)internal_reg_id)); if (!csr_highlighted[internal_reg_id]) { csr_view[internal_reg_id]->setPalette(pal_read); } csr_highlighted[internal_reg_id] = true; csr_highlighted_any = true; } void CsrDock::clear_highlights() { if (!csr_highlighted_any) { return; } for (size_t i = 0; i < machine::CSR::REGISTERS.size(); i++) { if (csr_highlighted[i]) { csr_view[i]->setPalette(pal_normal); csr_highlighted[i] = false; } } csr_highlighted_any = false; } void CsrDock::labelVal(QLabel *label, uint64_t value) { QString t = QString("0x") + QString::number(value, 16); label->setText(t); } qtrvsim-0.9.8/src/gui/windows/csr/csrdock.h000066400000000000000000000020611467752164200207070ustar00rootroot00000000000000#ifndef CSRDOCK_H #define CSRDOCK_H #include "machine/csr/controlstate.h" #include "machine/machine.h" #include "statictable.h" #include #include #include #include #include #include class CsrDock : public QDockWidget { Q_OBJECT public: explicit CsrDock(QWidget *parent); void setup(machine::Machine *machine); private slots: void csr_changed(std::size_t internal_reg_id, machine::RegisterValue val); void csr_read(std::size_t internal_reg_id, machine::RegisterValue val); void clear_highlights(); private: machine::Xlen xlen; const char *sizeHintText(); QT_OWNED StaticTable *widg; QT_OWNED QScrollArea *scrollarea; std::array csr_view {}; bool csr_highlighted[machine::CSR::REGISTERS.size()] {}; bool csr_highlighted_any; QPalette pal_normal; QPalette pal_updated; QPalette pal_read; static void labelVal(QLabel *label, uint64_t val); }; #endif // CSRDOCK_H qtrvsim-0.9.8/src/gui/windows/editor/000077500000000000000000000000001467752164200176065ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/editor/editordock.cpp000066400000000000000000000247241467752164200224520ustar00rootroot00000000000000#include "editordock.h" #include "common/logging.h" #include "dialogs/savechanged/savechangeddialog.h" #include "editortab.h" #include "helper/async_modal.h" #include #include #include #include #include #include LOG_CATEGORY("gui.editordock"); #ifdef __EMSCRIPTEN__ #include "qhtml5file.h" #endif int compare_filenames(const QString &filename1, const QString &filename2) { QFileInfo fi1(filename1); QFileInfo fi2(filename2); QString canon1 = fi1.canonicalFilePath(); QString canon2 = fi2.canonicalFilePath(); if (!canon1.isEmpty() && (canon1 == canon2)) { return 2; } if (filename1 == filename2) { return 1; } return 0; } EditorDock::EditorDock(QSharedPointer settings, QTabWidget *parent_tabs, QWidget *parent) : Super(parent) , settings(std::move(settings)) { { auto bar = tabBar(); bar->setMovable(true); QFont font = bar->font(); font.setPointSize(10); font.setBold(false); bar->setFont(font); } setObjectName("EditorDock"); setTabsClosable(true); connect(this, &EditorDock::tabCloseRequested, this, [this](int index) { close_tab(index); }); connect( this, &EditorDock::currentChanged, parent_tabs, [this, parent_tabs](int index) { // Update parent title if (count() == 0 || index < 0) return; auto *editor = get_tab(index)->get_editor(); QString title = QString("&Editor (%1)").arg(editor->title()); parent_tabs->setTabText(parent_tabs->indexOf(this), title); // IMPORTANT: This repeated call solved a very annoying QT resize bug. Do not remove it! parent_tabs->setTabText(parent_tabs->indexOf(this), title); parent_tabs->setCurrentIndex(parent_tabs->indexOf(this)); }, Qt::QueuedConnection); } EditorTab *EditorDock::get_tab(int index) const { return dynamic_cast(widget(index)); } EditorTab *EditorDock::open_file(const QString &filename, bool save_as_required) { auto tab = new EditorTab(line_numbers_visible, this); if (tab->get_editor()->loadFile(filename)) { addTab(tab, tab->title()); setCurrentWidget(tab); if (save_as_required) tab->get_editor()->setSaveAsRequired(save_as_required); return tab; } else { delete tab; return nullptr; } } EditorTab *EditorDock::open_file_if_not_open(const QString &filename, bool save_as_required) { auto tab = find_tab_by_filename(filename); if (tab == nullptr) { return open_file(filename, save_as_required); } else { setCurrentWidget(tab); return tab; } } EditorTab *EditorDock::create_empty_tab() { auto tab = new EditorTab(line_numbers_visible, this); while (true) { auto filename = QString("Unknown %1").arg(unknown_editor_counter++); if (!find_tab_id_by_filename(filename).has_value()) { tab->get_editor()->setFileName(filename); tab->get_editor()->setSaveAsRequired(true); break; } } addTab(tab, tab->title()); setCurrentWidget(tab); return tab; } std::optional EditorDock::find_tab_id_by_filename(const QString &filename) const { int best_match = 0; int best_match_index = -1; for (int i = 0; i < this->count(); i++) { auto *editor = get_tab(i)->get_editor(); int match = compare_filenames(filename, editor->filename()); if (match == 2) { return i; } if (match > best_match) { best_match = match; best_match_index = i; } } if (best_match_index >= 0) { return best_match_index; } return std::nullopt; } EditorTab *EditorDock::find_tab_by_filename(const QString &filename) const { auto index = find_tab_id_by_filename(filename); if (index.has_value()) { return get_tab(index.value()); } else { return nullptr; } } SrcEditor *EditorDock::get_current_editor() const { if (count() == 0) return nullptr; return get_tab(currentIndex())->get_editor(); } QStringList EditorDock::get_open_file_list() const { QStringList open_src_files; for (int i = 0; i < this->count(); i++) { auto *editor = get_tab(i)->get_editor(); if (editor->filename().isEmpty()) { continue; } open_src_files.append(editor->filename()); } return open_src_files; } bool EditorDock::get_modified_tab_filenames(QStringList &output, bool report_unnamed) const { output.clear(); for (int i = 0; i < this->count(); i++) { auto editor = get_tab(i)->get_editor(); if (editor->filename().isEmpty() && !report_unnamed) { continue; } if (!editor->isModified()) { continue; } output.append(editor->filename()); } return !output.empty(); } void EditorDock::set_show_line_numbers(bool visible) { line_numbers_visible = visible; settings->setValue("editorShowLineNumbers", visible); for (int i = 0; i < this->count(); i++) { get_tab(i)->set_show_line_number(visible); } } void EditorDock::tabCountChanged() { Super::tabCountChanged(); emit editor_available_changed(count() > 0); } void EditorDock::open_file_dialog() { #ifndef __EMSCRIPTEN__ QString file_name = QFileDialog::getOpenFileName( this, tr("Open File"), "", "Source Files (*.asm *.S *.s *.c Makefile)"); if (file_name.isEmpty()) { return; } auto tab_id = find_tab_id_by_filename(file_name); if (tab_id.has_value()) { setCurrentIndex(tab_id.value()); return; } if (!open_file(file_name)) { showAsyncCriticalBox( this, "Simulator Error", tr("Cannot open file '%1' for reading.").arg(file_name)); } #else QHtml5File::load("*", [&](const QByteArray &content, const QString &filename) { auto tab = create_empty_tab(); tab->get_editor()->loadByteArray(content, filename); setTabText(indexOf(tab), tab->get_editor()->title()); }); #endif } void EditorDock::save_tab(int index) { auto editor = get_tab(index)->get_editor(); if (editor->saveAsRequired()) { return save_tab_as(index); } #ifndef __EMSCRIPTEN__ if (!editor->saveFile()) { showAsyncCriticalBox( this, "Simulator Error", tr("Cannot save file '%1'.").arg(editor->filename())); } #else QHtml5File::save(editor->document()->toPlainText().toUtf8(), editor->filename()); editor->setModified(false); #endif } void EditorDock::save_current_tab() { if (count() == 0) return; save_tab(currentIndex()); } void EditorDock::save_tab_as(int index) { #ifndef __EMSCRIPTEN__ QFileDialog fileDialog(this, tr("Save as...")); fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setDefaultSuffix("s"); if (fileDialog.exec() != QDialog::Accepted) { return; } const QString fn = fileDialog.selectedFiles().first(); auto tab = get_tab(index); if (!tab->get_editor()->saveFile(fn)) { showAsyncCriticalBox(this, "Simulator Error", tr("Cannot save file '%1'.").arg(fn)); return; } setTabText(index, tab->get_editor()->title()); emit currentChanged(index); #else QString filename = get_tab(index)->get_editor()->filename(); if (filename.isEmpty()) filename = "unknown.s"; auto *dialog = new QInputDialog(this); dialog->setWindowTitle("Select file name"); dialog->setLabelText("File name:"); dialog->setTextValue(filename); dialog->setMinimumSize(QSize(200, 100)); dialog->setAttribute(Qt::WA_DeleteOnClose); connect( dialog, &QInputDialog::textValueSelected, this, [this, index](const QString &filename) { save_tab_to(index, filename); }, Qt::QueuedConnection); dialog->open(); #endif } void EditorDock::save_current_tab_as() { if (count() == 0) return; save_tab_as(currentIndex()); } void EditorDock::save_tab_to(int index, const QString &filename) { if (filename.isEmpty()) { WARN("Cannot save file '%s'.", filename.toStdString().c_str()); return; } auto editor = get_tab(index)->get_editor(); if (filename.isEmpty() || (editor == nullptr)) { return; } editor->setFileName(filename); if (!editor->filename().isEmpty()) { save_current_tab(); } } void EditorDock::save_current_tab_to(const QString &filename) { if (count() == 0) return; save_tab_to(currentIndex(), filename); } void EditorDock::close_tab(int index) { auto editor = get_tab(index)->get_editor(); if (!editor->isModified()) { close_tab_unchecked(index); } else { confirm_close_tab_dialog(index); } } void EditorDock::close_current_tab() { if (count() == 0) return; close_tab(currentIndex()); } void EditorDock::close_tab_by_name(QString &filename, bool ask) { auto *tab = find_tab_by_filename(filename); if (tab == nullptr) { WARN("Cannot find tab for file '%s'. Unable to close it.", filename.toStdString().c_str()); return; } if (!ask) { close_tab(indexOf(tab)); } else { confirm_close_tab_dialog(indexOf(tab)); } } void EditorDock::close_tab_unchecked(int index) { auto *tab = get_tab(index); removeTab(index); delete tab; } void EditorDock::confirm_close_tab_dialog(int index) { auto *msgbox = new QMessageBox(this); msgbox->setWindowTitle("Close unsaved source"); msgbox->setText("Close unsaved source."); msgbox->setInformativeText("Do you want to save your changes?"); msgbox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgbox->setDefaultButton(QMessageBox::Save); msgbox->setMinimumSize(QSize(200, 150)); msgbox->setAttribute(Qt::WA_DeleteOnClose); connect( msgbox, &QDialog::finished, this, [this, index](int result) { if (result == QMessageBox::Save) { save_tab(index); close_tab_unchecked(index); } else if (result == QMessageBox::Discard) { close_tab_unchecked(index); } }, Qt::QueuedConnection); msgbox->open(); } bool EditorDock::set_cursor_to(const QString &filename, int line, int column) { auto tab = (filename == "Unknown") ? get_tab(currentIndex()) : find_tab_by_filename(filename); if (tab == nullptr) { WARN( "Cannot find tab for file '%s'. Unable to set cursor.", filename.toStdString().c_str()); return false; } setCurrentWidget(tab); tab->get_editor()->setCursorTo(line, column); return true; } qtrvsim-0.9.8/src/gui/windows/editor/editordock.h000066400000000000000000000041041467752164200221050ustar00rootroot00000000000000#ifndef EDITORDOCK_H #define EDITORDOCK_H #include "common/memory_ownership.h" #include "editortab.h" #include "widgets/hidingtabwidget.h" #include #include class EditorDock : public HidingTabWidget { Q_OBJECT using Super = HidingTabWidget; public: /** * @param parent_tabs used to update parent tab based on current state */ explicit EditorDock( QSharedPointer settings, QTabWidget *parent_tabs, QWidget *parent = nullptr); BORROWED [[nodiscard]] EditorTab *get_tab(int index) const; BORROWED EditorTab *create_empty_tab(); BORROWED EditorTab *open_file(const QString &filename, bool save_as_required = false); BORROWED EditorTab * open_file_if_not_open(const QString &filename, bool save_as_required = false); BORROWED [[nodiscard]] std::optional find_tab_id_by_filename(const QString &filename) const; BORROWED [[nodiscard]] EditorTab *find_tab_by_filename(const QString &filename) const; BORROWED [[nodiscard]] SrcEditor *get_current_editor() const; [[nodiscard]] QStringList get_open_file_list() const; bool get_modified_tab_filenames(QStringList &output, bool report_unnamed = false) const; bool set_cursor_to(const QString &filename, int line, int column); protected: void tabCountChanged() override; signals: void editor_available_changed(bool available); public slots: void set_show_line_numbers(bool visible); void open_file_dialog(); void save_tab(int index); void save_current_tab(); void save_tab_as(int index); void save_current_tab_as(); void save_tab_to(int index, const QString &filename); void save_current_tab_to(const QString &filename); void close_tab(int index); void close_current_tab(); void close_tab_by_name(QString &filename, bool ask = false); private: void close_tab_unchecked(int index); void confirm_close_tab_dialog(int index); private: QSharedPointer settings; bool line_numbers_visible = true; size_t unknown_editor_counter = 1; }; #endif // EDITORDOCK_H qtrvsim-0.9.8/src/gui/windows/editor/editortab.cpp000066400000000000000000000037271467752164200223000ustar00rootroot00000000000000#include "editortab.h" #include "srceditor.h" #include #include EditorTab::EditorTab(bool show_line_numbers, QWidget *parent) : Super(parent) , layout(new QVBoxLayout(this)) , editor(new SrcEditor(this)) , status_bar_layout(new QHBoxLayout()) , status_bar_path(new QLabel("Unknown", this)) , status_bar_location(new QLabel("0:0", this)) { layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(reinterpret_cast(editor)); status_bar_layout->setSpacing(0); status_bar_layout->setContentsMargins(5, 0, 5, 0); status_bar_layout->addWidget(status_bar_path); status_bar_layout->addWidget(status_bar_location); layout->addLayout(status_bar_layout); status_bar_path->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); status_bar_location->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); connect(editor, &SrcEditor::cursorPositionChanged, this, [this]() { auto cursor = editor->textCursor(); status_bar_location->setText( QString("%1:%2").arg(cursor.blockNumber() + 1).arg(cursor.columnNumber() + 1)); }); connect(editor, &SrcEditor::file_name_change, this, [this]() { elide_file_name(); }); set_show_line_number(show_line_numbers); } QString EditorTab::title() { return editor->title(); } void EditorTab::set_show_line_number(bool visible) { editor->setShowLineNumbers(visible); } void EditorTab::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); elide_file_name(); } void EditorTab::elide_file_name() { auto filename = editor->filename().isEmpty() ? "Unknown" : editor->filename(); QFontMetrics metrics(status_bar_path->font()); int width = status_bar_layout->geometry().width() - status_bar_location->geometry().width() - 10; QString clippedText = metrics.elidedText(filename, Qt::ElideMiddle, width); status_bar_path->setText(clippedText); } qtrvsim-0.9.8/src/gui/windows/editor/editortab.h000066400000000000000000000014631467752164200217400ustar00rootroot00000000000000#ifndef EDITORTAB_H #define EDITORTAB_H #include "common/memory_ownership.h" #include "srceditor.h" #include #include #include class EditorTab : public QWidget { Q_OBJECT using Super = QWidget; public: explicit EditorTab(bool show_line_numbers, QWidget *parent = nullptr); [[nodiscard]] SrcEditor *get_editor() const { return editor; } QString title(); public slots: void set_show_line_number(bool visible); protected: void resizeEvent(QResizeEvent *event) override; void elide_file_name(); private: QT_OWNED QVBoxLayout *layout; QT_OWNED SrcEditor *editor; QT_OWNED QHBoxLayout *status_bar_layout; QT_OWNED QLabel *status_bar_path; QT_OWNED QLabel *status_bar_location; }; #endif // EDITORTAB_Hqtrvsim-0.9.8/src/gui/windows/editor/highlighterasm.cpp000066400000000000000000000103011467752164200233040ustar00rootroot00000000000000/* Based on Qt example released under BSD license */ #include "highlighterasm.h" #include "QStringList" #include "machine/csr/controlstate.h" #include "machine/instruction.h" HighlighterAsm::HighlighterAsm(QTextDocument *parent) : QSyntaxHighlighter(parent) { HighlightingRule rule; QTextCharFormat keywordFormat, registerFormat, singleLineCommentFormat, multiLineCommentFormat, quotationFormat; keywordFormat.setForeground(Qt::darkBlue); keywordFormat.setFontWeight(QFont::Bold); registerFormat.setFontWeight(QFont::Bold); registerFormat.setForeground(Qt::darkMagenta); singleLineCommentFormat.setForeground(Qt::darkGray); multiLineCommentFormat.setForeground(Qt::darkGray); quotationFormat.setForeground(Qt::darkGreen); { const QStringList keywordPatterns = { QStringLiteral("\\.org"), QStringLiteral("\\.word"), QStringLiteral("\\.text"), QStringLiteral("\\.data"), QStringLiteral("\\.bss"), QStringLiteral("\\.option"), QStringLiteral("\\.globl"), QStringLiteral("\\.set"), QStringLiteral("\\.equ"), QStringLiteral("\\.end"), QStringLiteral("\\.ent"), QStringLiteral("\\.ascii"), QStringLiteral("\\.asciz"), QStringLiteral("\\.byte"), QStringLiteral("\\.skip"), QStringLiteral("\\.space") }; rule.pattern = QRegularExpression("(" + keywordPatterns.join('|') + ")\\b"); rule.format = keywordFormat; highlightingRules.append(rule); } { QStringList inst_list; machine::Instruction::append_recognized_instructions(inst_list); inst_list.append("nop"); rule.pattern = QRegularExpression( QString("\\b(" + inst_list.join('|') + ")\\b"), QRegularExpression::CaseInsensitiveOption); rule.format = keywordFormat; highlightingRules.append(rule); } { QStringList reg_list; machine::Instruction::append_recognized_registers(reg_list); rule.pattern = QRegularExpression("\\b(" + reg_list.join('|') + "|x[0-9]+)\\b"); rule.format = registerFormat; highlightingRules.append(rule); } { QTextCharFormat namedValueFormat; namedValueFormat.setFontWeight(QFont::Bold); namedValueFormat.setForeground(Qt::darkMagenta); QString pattern = "\\b("; for (const auto ® : machine::CSR::REGISTERS) { pattern.append(reg.name).append('|'); } pattern = pattern.left(pattern.size() - 1); pattern.append(")\\b"); rule.pattern = QRegularExpression(pattern); rule.format = namedValueFormat; highlightingRules.append(rule); } rule.pattern = QRegularExpression(QStringLiteral("(;[^\n]*)|(#[^\n]*)|(//[^\n]*)")); rule.format = singleLineCommentFormat; highlightingRules.append(rule); rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); rule.format = quotationFormat; highlightingRules.append(rule); for (auto &rule : highlightingRules) { rule.pattern.optimize(); } } void HighlighterAsm::highlightBlock(const QString &text) { for (const HighlightingRule &rule : qAsConst(highlightingRules)) { auto matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); setFormat(match.capturedStart(), match.capturedLength(), rule.format); } } setCurrentBlockState(0); #if 0 int startIndex = 0; if (previousBlockState() != 1) startIndex = text.indexOf(commentStartExpression); while (startIndex >= 0) { QRegularExpressionMatch match = commentEndExpression.match(text, startIndex); int endIndex = match.capturedStart(); int commentLength = 0; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; } else { commentLength = endIndex - startIndex + match.capturedLength(); } setFormat(startIndex, commentLength, multiLineCommentFormat); startIndex = text.indexOf(commentStartExpression, startIndex + commentLength); } #endif } qtrvsim-0.9.8/src/gui/windows/editor/highlighterasm.h000066400000000000000000000012101467752164200227500ustar00rootroot00000000000000/* Based on Qt example released under BSD license */ #ifndef HIGHLIGHTERASM_H #define HIGHLIGHTERASM_H #include #include #include QT_BEGIN_NAMESPACE class QTextDocument; QT_END_NAMESPACE class HighlighterAsm : public QSyntaxHighlighter { Q_OBJECT public: explicit HighlighterAsm(QTextDocument *parent = nullptr); protected: void highlightBlock(const QString &text) override; private: struct HighlightingRule { QRegularExpression pattern; QTextCharFormat format; }; QVector highlightingRules; }; #endif // HIGHLIGHTERASM_H qtrvsim-0.9.8/src/gui/windows/editor/highlighterc.cpp000066400000000000000000000151011467752164200227510ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "highlighterc.h" //! [0] HighlighterC::HighlighterC(QTextDocument *parent) : QSyntaxHighlighter(parent) { HighlightingRule rule; keywordFormat.setForeground(Qt::darkBlue); keywordFormat.setFontWeight(QFont::Bold); const QString keywordPatterns[] = { QStringLiteral("\\bchar\\b"), QStringLiteral("\\bclass\\b"), QStringLiteral("\\bconst\\b"), QStringLiteral("\\bdouble\\b"), QStringLiteral("\\benum\\b"), QStringLiteral("\\bexplicit\\b"), QStringLiteral("\\bfriend\\b"), QStringLiteral("\\binline\\b"), QStringLiteral("\\bint\\b"), QStringLiteral("\\blong\\b"), QStringLiteral("\\bnamespace\\b"), QStringLiteral("\\boperator\\b"), QStringLiteral("\\bprivate\\b"), QStringLiteral("\\bprotected\\b"), QStringLiteral("\\bpublic\\b"), QStringLiteral("\\bshort\\b"), QStringLiteral("\\bsignals\\b"), QStringLiteral("\\bsigned\\b"), QStringLiteral("\\bslots\\b"), QStringLiteral("\\bstatic\\b"), QStringLiteral("\\bstruct\\b"), QStringLiteral("\\btemplate\\b"), QStringLiteral("\\btypedef\\b"), QStringLiteral("\\btypename\\b"), QStringLiteral("\\bunion\\b"), QStringLiteral("\\bunsigned\\b"), QStringLiteral("\\bvirtual\\b"), QStringLiteral("\\bvoid\\b"), QStringLiteral("\\bvolatile\\b"), QStringLiteral("\\bbool\\b") }; for (const QString &pattern : keywordPatterns) { rule.pattern = QRegularExpression(pattern); rule.format = keywordFormat; highlightingRules.append(rule); //! [0] //! [1] } //! [1] //! [2] classFormat.setFontWeight(QFont::Bold); classFormat.setForeground(Qt::darkMagenta); rule.pattern = QRegularExpression(QStringLiteral("\\bQ[A-Za-z]+\\b")); rule.format = classFormat; highlightingRules.append(rule); //! [2] //! [3] singleLineCommentFormat.setForeground(Qt::red); rule.pattern = QRegularExpression(QStringLiteral("//[^\n]*")); rule.format = singleLineCommentFormat; highlightingRules.append(rule); multiLineCommentFormat.setForeground(Qt::red); //! [3] //! [4] quotationFormat.setForeground(Qt::darkGreen); rule.pattern = QRegularExpression(QStringLiteral("\".*\"")); rule.format = quotationFormat; highlightingRules.append(rule); //! [4] //! [5] functionFormat.setFontItalic(true); functionFormat.setForeground(Qt::blue); rule.pattern = QRegularExpression(QStringLiteral("\\b[A-Za-z0-9_]+(?=\\()")); rule.format = functionFormat; highlightingRules.append(rule); //! [5] //! [6] commentStartExpression = QRegularExpression(QStringLiteral("/\\*")); commentEndExpression = QRegularExpression(QStringLiteral("\\*/")); } //! [6] //! [7] void HighlighterC::highlightBlock(const QString &text) { #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) foreach (const HighlightingRule &rule, highlightingRules) #else for (const HighlightingRule &rule : qAsConst(highlightingRules)) #endif { QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text); while (matchIterator.hasNext()) { QRegularExpressionMatch match = matchIterator.next(); setFormat( match.capturedStart(), match.capturedLength(), rule.format); } } //! [7] //! [8] setCurrentBlockState(0); //! [8] //! [9] int startIndex = 0; if (previousBlockState() != 1) { startIndex = text.indexOf(commentStartExpression); } //! [9] //! [10] while (startIndex >= 0) { //! [10] //! [11] QRegularExpressionMatch match = commentEndExpression.match(text, startIndex); int endIndex = match.capturedStart(); int commentLength = 0; if (endIndex == -1) { setCurrentBlockState(1); commentLength = text.length() - startIndex; } else { commentLength = endIndex - startIndex + match.capturedLength(); } setFormat(startIndex, commentLength, multiLineCommentFormat); startIndex = text.indexOf(commentStartExpression, startIndex + commentLength); } } //! [11] qtrvsim-0.9.8/src/gui/windows/editor/highlighterc.h000066400000000000000000000064631467752164200224310ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HIGHLIGHTERC_H #define HIGHLIGHTERC_H #include #include #include QT_BEGIN_NAMESPACE class QTextDocument; QT_END_NAMESPACE //! [0] class HighlighterC : public QSyntaxHighlighter { Q_OBJECT public: explicit HighlighterC(QTextDocument *parent = nullptr); protected: void highlightBlock(const QString &text) override; private: struct HighlightingRule { QRegularExpression pattern; QTextCharFormat format; }; QVector highlightingRules; QRegularExpression commentStartExpression; QRegularExpression commentEndExpression; QTextCharFormat keywordFormat; QTextCharFormat classFormat; QTextCharFormat singleLineCommentFormat; QTextCharFormat multiLineCommentFormat; QTextCharFormat quotationFormat; QTextCharFormat functionFormat; }; //! [0] #endif // HIGHLIGHTERC_H qtrvsim-0.9.8/src/gui/windows/editor/linenumberarea.cpp000066400000000000000000000035701467752164200233100ustar00rootroot00000000000000#include "linenumberarea.h" #include "srceditor.h" #include #include #include constexpr int RIGHT_MARGIN = 5; constexpr int RIGHT_PADDING = 5; constexpr int LEFT_PADDING = 5; LineNumberArea::LineNumberArea(SrcEditor *editor_) : QWidget(editor_), editor(editor_) {} QSize LineNumberArea::sizeHint() const { if (!line_numbers_visible) { return { 0, 0 }; } int digits = std::log10(std::max(1, editor->blockCount())) + 2; int space = editor->fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits + LEFT_PADDING + RIGHT_PADDING + RIGHT_MARGIN; return { space, 0 }; } void LineNumberArea::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.fillRect(event->rect(), palette().base()); painter.drawLine( event->rect().right() - RIGHT_MARGIN, 0, event->rect().right() - RIGHT_MARGIN, event->rect().bottom()); QTextBlock block = editor->firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(editor->blockBoundingGeometry(block).translated(editor->contentOffset()).top()); int bottom = top + qRound(editor->blockBoundingRect(block).height()); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(palette().windowText().color()); painter.drawText( 0, top, this->sizeHint().width() - RIGHT_PADDING - RIGHT_MARGIN, editor->fontMetrics().height(), Qt::AlignRight, number); } block = block.next(); top = bottom; bottom = top + qRound(editor->blockBoundingRect(block).height()); ++blockNumber; } } void LineNumberArea::set(bool visible) { QWidget::setVisible(visible); line_numbers_visible = visible; } qtrvsim-0.9.8/src/gui/windows/editor/linenumberarea.h000066400000000000000000000007461467752164200227570ustar00rootroot00000000000000#ifndef LINENUMBERAREA_H #define LINENUMBERAREA_H #include "common/memory_ownership.h" #include class SrcEditor; class LineNumberArea : public QWidget { public: explicit LineNumberArea(BORROWED SrcEditor *editor_); void set(bool visible); [[nodiscard]] QSize sizeHint() const override; protected: void paintEvent(QPaintEvent *event) override; private: BORROWED SrcEditor *editor; bool line_numbers_visible = false; }; #endif // LINENUMBERAREA_Hqtrvsim-0.9.8/src/gui/windows/editor/srceditor.cpp000066400000000000000000000206541467752164200223170ustar00rootroot00000000000000#include "srceditor.h" #include "common/logging.h" #include "editordock.h" #include "editortab.h" #include "linenumberarea.h" #include "windows/editor/highlighterasm.h" #include "windows/editor/highlighterc.h" #include #include #include #include #include #include #include #include #include #include LOG_CATEGORY("gui.src_editor"); SrcEditor::SrcEditor(QWidget *parent) : Super(parent), line_number_area(new LineNumberArea(this)) { QFont font1; saveAsRequiredFl = true; font1.setFamily("Courier"); font1.setFixedPitch(true); font1.setPointSize(10); setFont(font1); tname = "Unknown"; highlighter.reset(new HighlighterAsm(document())); QPalette p = palette(); p.setColor(QPalette::Base, Qt::white); p.setColor(QPalette::Text, Qt::black); p.setColor(QPalette::WindowText, Qt::darkGray); setPalette(p); // Set tab width to 4 spaces setTabStopDistance(fontMetrics().horizontalAdvance(' ') * TAB_WIDTH); connect(this, &SrcEditor::blockCountChanged, this, &SrcEditor::updateMargins); connect(this, &SrcEditor::updateRequest, this, &SrcEditor::updateLineNumberArea); // Clear error highlight on typing connect(this, &SrcEditor::textChanged, [this]() { setExtraSelections({}); }); updateMargins(0); } QString SrcEditor::filename() const { return fname; } QString SrcEditor::title() { return tname; } void SrcEditor::setFileName(const QString &filename) { QFileInfo fi(filename); saveAsRequiredFl = filename.isEmpty() || filename.startsWith(":/"); fname = filename; tname = fi.fileName(); if ((fi.suffix() == "c") || (fi.suffix() == "C") || (fi.suffix() == "cpp") || ((fi.suffix() == "c++"))) { highlighter.reset(new HighlighterC(document())); } else { highlighter.reset(new HighlighterAsm(document())); } emit file_name_change(); } bool SrcEditor::loadFile(const QString &filename) { QFile file(filename); if (file.open(QFile::ReadOnly | QFile::Text)) { setPlainText(file.readAll()); setFileName(filename); return true; } else { return false; } } bool SrcEditor::loadByteArray(const QByteArray &content, const QString &filename) { setPlainText(QString::fromUtf8(content.data(), content.size())); if (!filename.isEmpty()) { setFileName(filename); } return true; } bool SrcEditor::saveFile(QString filename) { if (filename.isEmpty()) { filename = this->filename(); } if (filename.isEmpty()) { return false; } QTextDocumentWriter writer(filename); writer.setFormat("plaintext"); bool success = writer.write(document()); setFileName(filename); if (success) { document()->setModified(false); } return success; } void SrcEditor::setCursorToLine(int ln) { QTextCursor cursor(document()->findBlockByNumber(ln - 1)); setTextCursor(cursor); } void SrcEditor::setCursorTo(int ln, int col) { QTextCursor cursor(document()->findBlockByNumber(ln - 1)); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, col - 1); setTextCursor(cursor); setFocus(); } bool SrcEditor::isModified() const { return document()->isModified(); } void SrcEditor::setModified(bool val) { document()->setModified(val); } void SrcEditor::setSaveAsRequired(bool val) { saveAsRequiredFl = val; } bool SrcEditor::saveAsRequired() const { return saveAsRequiredFl; } void SrcEditor::keyPressEvent(QKeyEvent *event) { QTextCursor cursor = textCursor(); if (cursor.hasSelection()) { switch (event->key()) { case Qt::Key_Tab: { indent_selection(cursor); return; } case Qt::Key_Backtab: { unindent_selection(cursor); return; } case Qt::Key_Slash: if (event->modifiers() & Qt::ControlModifier) { toggle_selection_comment(cursor, is_selection_comment()); return; } break; default: break; } } switch (event->key()) { case Qt::Key_Return: { // Keep indentation QString txt = cursor.block().text(); QString indent; for (auto ch : txt) { if (ch.isSpace()) { indent.append(ch); } else { break; } } cursor.insertText("\n"); cursor.insertText(indent); setTextCursor(cursor); return; } case Qt::Key_Slash: { if (event->modifiers() & Qt::ControlModifier) { // Toggle comment if (cursor.block().text().startsWith("//")) { cursor.movePosition(QTextCursor::StartOfLine); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); cursor.removeSelectedText(); } else { cursor.movePosition(QTextCursor::StartOfLine); cursor.insertText("//"); } return; } break; } } QPlainTextEdit::keyPressEvent(event); } void SrcEditor::indent_selection(QTextCursor &cursor) { auto end = cursor.selectionEnd(); cursor.beginEditBlock(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::StartOfLine); while (cursor.position() < end) { cursor.insertText("\t"); if (!cursor.movePosition(QTextCursor::Down)) break; } cursor.endEditBlock(); } void SrcEditor::unindent_selection(QTextCursor &cursor) { cursor.beginEditBlock(); auto end_line = document()->findBlock(cursor.selectionEnd()).blockNumber(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::StartOfLine); while (cursor.blockNumber() <= end_line) { auto txt = cursor.block().text(); if (txt.isEmpty()) { // Empty line, skip } else if (txt.startsWith("\t")) { cursor.deleteChar(); } else if (txt.startsWith(" ")) { // Delete at most TAB_WIDTH spaces unsigned to_delete = std::min(txt.size(), TAB_WIDTH); while (to_delete > 0 && cursor.block().text().startsWith(" ")) { cursor.deleteChar(); to_delete--; } } if (!cursor.movePosition(QTextCursor::Down)) break; } cursor.endEditBlock(); } bool SrcEditor::is_selection_comment() { QTextCursor cursor = textCursor(); bool all_commented = true; auto end_line = document()->findBlock(cursor.selectionEnd()).blockNumber(); while (cursor.blockNumber() <= end_line) { auto txt = cursor.block().text(); if (!txt.startsWith("//")) { all_commented = false; break; } if (!cursor.movePosition(QTextCursor::Down)) break; } return all_commented; } void SrcEditor::toggle_selection_comment(QTextCursor &cursor, bool is_comment) { auto end_line = document()->findBlock(cursor.selectionEnd()).blockNumber(); cursor.beginEditBlock(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::StartOfLine); while (cursor.blockNumber() <= end_line) { if (is_comment) { cursor.deleteChar(); cursor.deleteChar(); } else { cursor.insertText("//"); } if (!cursor.movePosition(QTextCursor::Down)) break; } cursor.endEditBlock(); } void SrcEditor::updateMargins(int /* newBlockCount */) { setViewportMargins(line_number_area->sizeHint().width(), 0, 0, 0); } void SrcEditor::updateLineNumberArea(const QRect &rect, int dy) { if (dy) { line_number_area->scroll(0, dy); } else { line_number_area->update(0, rect.y(), line_number_area->width(), rect.height()); } if (rect.contains(viewport()->rect())) updateMargins(0); } void SrcEditor::resizeEvent(QResizeEvent *event) { QPlainTextEdit::resizeEvent(event); QRect cr = contentsRect(); line_number_area->setGeometry( QRect(cr.left(), cr.top(), line_number_area->sizeHint().width(), cr.height())); } void SrcEditor::setShowLineNumbers(bool show) { line_number_area->set(show); updateMargins(0); } void SrcEditor::insertFromMimeData(const QMimeData *source) { if (source->hasText()) { insertPlainText(source->text()); } } bool SrcEditor::canInsertFromMimeData(const QMimeData *source) const { return source->hasText(); } qtrvsim-0.9.8/src/gui/windows/editor/srceditor.h000066400000000000000000000044361467752164200217640ustar00rootroot00000000000000#ifndef SRCEDITOR_H #define SRCEDITOR_H #include "common/memory_ownership.h" #include "linenumberarea.h" #include "machine/machine.h" #include #include #include #include #include #include class SrcEditor : public QPlainTextEdit { Q_OBJECT using Super = QPlainTextEdit; public: explicit SrcEditor(QWidget *parent); [[nodiscard]] QString filename() const; QString title(); bool loadFile(const QString &filename); bool saveFile(QString filename = ""); bool loadByteArray(const QByteArray &content, const QString &filename = ""); void setCursorToLine(int ln); void setCursorTo(int ln, int col); void setFileName(const QString &filename); [[nodiscard]] bool isModified() const; void setModified(bool val); void setSaveAsRequired(bool val); [[nodiscard]] bool saveAsRequired() const; protected: void keyPressEvent(QKeyEvent *event) override; void resizeEvent(QResizeEvent *event) override; void insertFromMimeData(const QMimeData *source) override; bool canInsertFromMimeData(const QMimeData *source) const override; signals: void file_name_change(); public slots: void setShowLineNumbers(bool visible); private slots: void updateMargins(int newBlockCount); void updateLineNumberArea(const QRect &rect, int dy); private: ::Box highlighter {}; LineNumberArea *line_number_area; bool line_numbers_visible = true; QString fname; QString tname; bool saveAsRequiredFl {}; /** Width of a tab character in spaces. */ static constexpr unsigned TAB_WIDTH = 4; /** Indents selected lines by one tab. */ void indent_selection(QTextCursor &cursor); /** Unindents selected lines by one tab or 4 spaces from the beginning of each line. * If only some lines contain less prefix whitespace, remove as much as possible to mimic * VS Code behavior. */ void unindent_selection(QTextCursor &cursor); /** Returns true if all lines in the selection are commented out. */ bool is_selection_comment(); /** Comments out all lines in the selection. */ void toggle_selection_comment(QTextCursor &cursor, bool is_comment); friend class LineNumberArea; }; #endif // SRCEDITOR_H qtrvsim-0.9.8/src/gui/windows/lcd/000077500000000000000000000000001467752164200170625ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/lcd/lcddisplaydock.cpp000066400000000000000000000044111467752164200225570ustar00rootroot00000000000000#include "lcddisplaydock.h" #include "lcddisplayview.h" #include #include LcdDisplayDock::LcdDisplayDock(QWidget *parent, QSettings *settings) : Super(parent) { (void)settings; lcd_display_widget.reset(new LcdDisplayView(this)); auto *fill_widget = new QWidget(this); layout = new QBoxLayout(QBoxLayout::LeftToRight, fill_widget); // add spacer, then your widget, then spacer layout->addItem(new QSpacerItem(0, 0)); layout->addWidget(lcd_display_widget.data()); layout->addItem(new QSpacerItem(0, 0)); fill_widget->setLayout(layout); setWidget(fill_widget); setObjectName("LCD Display"); setWindowTitle("LCD Display"); } void LcdDisplayDock::setup(machine::LcdDisplay *lcd_display) { lcd_display_widget->setup(lcd_display); update_layout(width(), height()); } void LcdDisplayDock::update_layout(int w, int h) { // Keeping the aspect ratio based on // https://stackoverflow.com/questions/30005540/keeping-the-aspect-ratio-of-a-sub-classed-qwidget-during-resize float thisAspectRatio = (float)w / h; int widgetStretch, outerStretch; float arWidth = lcd_display_widget->fb_width(); // aspect ratio width float arHeight = lcd_display_widget->fb_height(); // aspect ratio height if ((arWidth == 0) || (arHeight == 0)) { outerStretch = 0; widgetStretch = 1; } else if (thisAspectRatio > (arWidth / arHeight)) { // too wide layout->setDirection(QBoxLayout::LeftToRight); widgetStretch = height() * (arWidth / arHeight); // i.e., my width outerStretch = (width() - widgetStretch) / 2 + 0.5; } else { // too tall layout->setDirection(QBoxLayout::TopToBottom); widgetStretch = width() * (arHeight / arWidth); // i.e., my height outerStretch = (height() - widgetStretch) / 2 + 0.5; } layout->setStretch(0, outerStretch); layout->setStretch(1, widgetStretch); layout->setStretch(2, outerStretch); } void LcdDisplayDock::resizeEvent(QResizeEvent *event) { // Keeping the aspect ratio based on // https://stackoverflow.com/questions/30005540/keeping-the-aspect-ratio-of-a-sub-classed-qwidget-during-resize update_layout(event->size().width(), event->size().height()); Super::resizeEvent(event); } qtrvsim-0.9.8/src/gui/windows/lcd/lcddisplaydock.h000066400000000000000000000011211467752164200222170ustar00rootroot00000000000000#ifndef LCDDISPLAYDOCK_H #define LCDDISPLAYDOCK_H #include "lcddisplayview.h" #include "machine/machine.h" #include #include class LcdDisplayDock : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: LcdDisplayDock(QWidget *parent, QSettings *settings); void resizeEvent(QResizeEvent *event) override; void setup(machine::LcdDisplay *lcd_display); // public slots: private: void update_layout(int w, int h); QT_OWNED QBoxLayout *layout; Box lcd_display_widget; }; #endif // LCDDISPLAYDOCK_H qtrvsim-0.9.8/src/gui/windows/lcd/lcddisplayview.cpp000066400000000000000000000044631467752164200226200ustar00rootroot00000000000000#include "lcddisplayview.h" #include #include #include LcdDisplayView::LcdDisplayView(QWidget *parent) : Super(parent) { setMinimumSize(100, 100); scale_x = 1.0; scale_y = 1.0; } void LcdDisplayView::setup(machine::LcdDisplay *lcd_display) { if (lcd_display == nullptr) { return; } connect(lcd_display, &machine::LcdDisplay::pixel_update, this, &LcdDisplayView::pixel_update); fb_pixels.reset( new QImage(lcd_display->get_width(), lcd_display->get_height(), QImage::Format_RGB32)); fb_pixels->fill(qRgb(0, 0, 0)); update_scale(); update(); } void LcdDisplayView::pixel_update(size_t x, size_t y, uint r, uint g, uint b) { int x1, y1, x2, y2; if (fb_pixels != nullptr) { fb_pixels->setPixel(x, y, qRgb(r, g, b)); x1 = x * scale_x - 2; if (x1 < 0) { x1 = 0; } x2 = x * scale_x + 2; if (x2 > width()) { x2 = width(); } y1 = y * scale_y - 2; if (y1 < 0) { y1 = 0; } y2 = y * scale_y + 2; if (y2 > height()) { y2 = height(); } update(x1, y1, x2 - x1, y2 - y1); } } void LcdDisplayView::update_scale() { if (fb_pixels != nullptr) { if ((fb_pixels->width() != 0) && (fb_pixels->height() != 0)) { scale_x = (float)width() / fb_pixels->width(); scale_y = (float)height() / fb_pixels->height(); return; } } scale_x = 1.0; scale_y = 1.0; } void LcdDisplayView::paintEvent(QPaintEvent *event) { if (fb_pixels == nullptr) { return Super::paintEvent(event); } if (fb_pixels->width() == 0) { return Super::paintEvent(event); } QPainter painter(this); painter.drawImage(rect(), *fb_pixels); #if 0 painter.setPen(QPen(QColor(255, 255, 0))); painter.drawLine(event->rect().topLeft(),event->rect().topRight()); painter.drawLine(event->rect().topLeft(),event->rect().bottomLeft()); painter.drawLine(event->rect().topLeft(),event->rect().bottomRight()); #endif } void LcdDisplayView::resizeEvent(QResizeEvent *event) { Super::resizeEvent(event); update_scale(); } uint LcdDisplayView::fb_width() { if (fb_pixels == nullptr) { return 0; } return fb_pixels->width(); } uint LcdDisplayView::fb_height() { if (fb_pixels == nullptr) { return 0; } return fb_pixels->height(); } qtrvsim-0.9.8/src/gui/windows/lcd/lcddisplayview.h000066400000000000000000000013571467752164200222640ustar00rootroot00000000000000#ifndef LCDDISPLAYVIEW_H #define LCDDISPLAYVIEW_H #include "common/memory_ownership.h" #include "machine/memory/backend/lcddisplay.h" #include #include class LcdDisplayView : public QWidget { Q_OBJECT using Super = QWidget; public: explicit LcdDisplayView(QWidget *parent = nullptr); void setup(machine::LcdDisplay *lcd_display); uint fb_width(); uint fb_height(); public slots: void pixel_update(std::size_t x, std::size_t y, uint r, uint g, uint b); protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: void update_scale(); float scale_x; float scale_y; Box fb_pixels; }; #endif // LCDDISPLAYVIEW_H qtrvsim-0.9.8/src/gui/windows/memory/000077500000000000000000000000001467752164200176305ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/memory/memorydock.cpp000066400000000000000000000047741467752164200225210ustar00rootroot00000000000000#include "memorydock.h" #include "memorymodel.h" #include "memorytableview.h" #include "ui/hexlineedit.h" #include #include #include #include MemoryDock::MemoryDock(QWidget *parent, QSettings *settings) : Super(parent) { setObjectName("Memory"); setWindowTitle("Memory"); auto *content = new QWidget(); auto *cell_size = new QComboBox(); cell_size->addItem("Byte", MemoryModel::CELLSIZE_BYTE); cell_size->addItem("Half-word", MemoryModel::CELLSIZE_HWORD); cell_size->addItem("Word", MemoryModel::CELLSIZE_WORD); cell_size->setCurrentIndex(MemoryModel::CELLSIZE_WORD); auto *cached_access = new QComboBox(); cached_access->addItem("Direct", 0); cached_access->addItem("Cached", 1); auto *memory_content = new MemoryTableView(nullptr, settings); // memory_content->setSizePolicy(); auto *memory_model = new MemoryModel(this); memory_content->setModel(memory_model); memory_content->verticalHeader()->hide(); // memory_content->setHorizontalHeader(memory_model->); auto *go_edit = new HexLineEdit(nullptr, 8, 16, "0x"); auto *layout_top = new QHBoxLayout; layout_top->addWidget(cell_size); layout_top->addWidget(cached_access); auto *layout = new QVBoxLayout; layout->addLayout(layout_top); layout->addWidget(memory_content); layout->addWidget(go_edit); content->setLayout(layout); setWidget(content); connect( this, &MemoryDock::machine_setup, memory_model, &MemoryModel::setup); connect( cell_size, QOverload::of(&QComboBox::currentIndexChanged), memory_content, &MemoryTableView::set_cell_size); connect( cached_access, QOverload::of(&QComboBox::currentIndexChanged), memory_model, &MemoryModel::cached_access); connect( go_edit, &HexLineEdit::value_edit_finished, memory_content, [memory_content](uint32_t value) { memory_content->go_to_address(machine::Address(value)); }); connect( memory_content, &MemoryTableView::address_changed, go_edit, [go_edit](machine::Address addr) { go_edit->set_value(addr.get_raw()); }); connect( this, &MemoryDock::focus_addr, memory_content, &MemoryTableView::focus_address); connect( memory_model, &MemoryModel::setup_done, memory_content, &MemoryTableView::recompute_columns); } void MemoryDock::setup(machine::Machine *machine) { emit machine_setup(machine); } qtrvsim-0.9.8/src/gui/windows/memory/memorydock.h000066400000000000000000000007651467752164200221620ustar00rootroot00000000000000#ifndef MEMORYDOCK_H #define MEMORYDOCK_H #include "machine/machine.h" #include "machine/memory/address.h" #include #include #include class MemoryDock : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: MemoryDock(QWidget *parent, QSettings *settings); void setup(machine::Machine *machine); signals: void machine_setup(machine::Machine *machine); void focus_addr(machine::Address); private: }; #endif // MEMORYDOCK_H qtrvsim-0.9.8/src/gui/windows/memory/memorymodel.cpp000066400000000000000000000201311467752164200226620ustar00rootroot00000000000000#include "memorymodel.h" #include using ae = machine::AccessEffects; // For enum values, the type is obvious from context. MemoryModel::MemoryModel(QObject *parent) : Super(parent), data_font("Monospace") { cell_size = CELLSIZE_WORD; cells_per_row = 1; index0_offset = machine::Address::null(); data_font.setStyleHint(QFont::TypeWriter); machine = nullptr; memory_change_counter = 0; cache_data_change_counter = 0; access_through_cache = 0; } const machine::FrontendMemory *MemoryModel::mem_access() const { if (machine == nullptr) { return nullptr; } if (machine->memory_data_bus() != nullptr) { return machine->memory_data_bus(); } // Direct access to memory is not allowed, data bus must be used. At least a // trivial one. If this occurred, there is a misconfigured machine. throw std::logic_error("No memory available on machine. This is a bug, please report it."); } machine::FrontendMemory *MemoryModel::mem_access_rw() const { if (machine == nullptr) { return nullptr; } if (machine->memory_data_bus_rw() != nullptr) { return machine->memory_data_bus_rw(); } // Direct access to memory is not allowed, data bus must be used. At least a // trivial one. If this occurred, there is a misconfigured machine. throw std::logic_error("No memory available on machine. This is u bug, please report it."); } int MemoryModel::rowCount(const QModelIndex & /*parent*/) const { return 750; } int MemoryModel::columnCount(const QModelIndex & /*parent*/) const { return cells_per_row + 1; } QVariant MemoryModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { if (section == 0) { return tr("Address"); } else { uint32_t addr = (section - 1) * cellSizeBytes(); QString ret = "+" + QString::number(addr, 10); return ret; } } } return Super::headerData(section, orientation, role); } QVariant MemoryModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole || role == Qt::EditRole) { QString s, t; machine::Address address; uint32_t data; const machine::FrontendMemory *mem; if (!get_row_address(address, index.row())) { return QString(""); } if (index.column() == 0) { t = QString::number(address.get_raw(), 16); s.fill('0', 8 - t.count()); return "0x" + s + t; } if (machine == nullptr) { return QString(""); } mem = mem_access(); if (mem == nullptr) { return QString(""); } if ((access_through_cache > 0) && (machine->cache_data() != nullptr)) { mem = machine->cache_data(); } address += cellSizeBytes() * (index.column() - 1); if (address < index0_offset) { return QString(""); } switch (cell_size) { case CELLSIZE_BYTE: data = mem->read_u8(address, ae::INTERNAL); break; case CELLSIZE_HWORD: data = mem->read_u16(address, ae::INTERNAL); break; default: case CELLSIZE_WORD: data = mem->read_u32(address, ae::INTERNAL); break; } t = QString::number(data, 16); s.fill('0', cellSizeBytes() * 2 - t.count()); t = s + t; #if 0 machine::LocationStatus loc_stat = machine::LOCSTAT_NONE; if (machine->cache_data() != nullptr) { loc_stat = machine->cache_data()->location_status(address); if (loc_stat & machine::LOCSTAT_DIRTY) t += " D"; else if (loc_stat & machine::LOCSTAT_CACHED) t += " C"; } #endif return t; } if (role == Qt::BackgroundRole) { machine::Address address; if (!get_row_address(address, index.row()) || machine == nullptr || index.column() == 0) { return {}; } address += cellSizeBytes() * (index.column() - 1); if (machine->cache_data() != nullptr) { machine::LocationStatus loc_stat; loc_stat = machine->cache_data()->location_status(address); if (loc_stat & machine::LOCSTAT_DIRTY) { QBrush bgd(Qt::yellow); return bgd; } else if (loc_stat & machine::LOCSTAT_CACHED) { QBrush bgd(Qt::lightGray); return bgd; } } return {}; } if (role == Qt::FontRole) { return data_font; } return {}; } void MemoryModel::setup(machine::Machine *machine) { this->machine = machine; if (machine != nullptr) { connect(machine, &machine::Machine::post_tick, this, &MemoryModel::check_for_updates); } if (mem_access() != nullptr) { connect( mem_access(), &machine::FrontendMemory::external_change_notify, this, &MemoryModel::check_for_updates); } emit update_all(); emit setup_done(); } void MemoryModel::setCellsPerRow(unsigned int cells) { beginResetModel(); cells_per_row = cells; endResetModel(); } void MemoryModel::set_cell_size(int index) { beginResetModel(); cell_size = (enum MemoryCellSize)index; index0_offset -= index0_offset.get_raw() % cellSizeBytes(); endResetModel(); emit cell_size_changed(); } void MemoryModel::update_all() { const machine::FrontendMemory *mem; mem = mem_access(); if (mem != nullptr) { memory_change_counter = mem->get_change_counter(); if (machine->cache_data() != nullptr) { cache_data_change_counter = machine->cache_data()->get_change_counter(); } } emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } void MemoryModel::check_for_updates() { bool need_update = false; const machine::FrontendMemory *mem; mem = mem_access(); if (mem == nullptr) { return; } if (memory_change_counter != mem->get_change_counter()) { need_update = true; } if (machine->cache_data() != nullptr) { if (cache_data_change_counter != machine->cache_data()->get_change_counter()) { need_update = true; } } if (!need_update) { return; } update_all(); } bool MemoryModel::adjustRowAndOffset(int &row, machine::Address address) { row = rowCount() / 2; address -= address.get_raw() % cellSizeBytes(); uint32_t row_bytes = cells_per_row * cellSizeBytes(); uint32_t diff = row * row_bytes; if (machine::Address(diff) > address) { row = address.get_raw() / row_bytes; if (row == 0) { index0_offset = machine::Address::null(); } else { index0_offset = address - row * row_bytes; } } else { index0_offset = address - diff; } return get_row_for_address(row, address); } void MemoryModel::cached_access(int cached) { access_through_cache = cached; update_all(); } Qt::ItemFlags MemoryModel::flags(const QModelIndex &index) const { if (index.column() == 0) { return QAbstractTableModel::flags(index); } else { return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; } } bool MemoryModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::EditRole) { bool ok; machine::Address address; machine::FrontendMemory *mem; uint32_t data = value.toString().toULong(&ok, 16); if (!ok) { return false; } if (!get_row_address(address, index.row())) { return false; } if (index.column() == 0 || machine == nullptr) { return false; } mem = mem_access_rw(); if (mem == nullptr) { return false; } if ((access_through_cache > 0) && (machine->cache_data_rw() != nullptr)) { mem = machine->cache_data_rw(); } address += cellSizeBytes() * (index.column() - 1); switch (cell_size) { case CELLSIZE_BYTE: mem->write_u8(address, data, ae::INTERNAL); break; case CELLSIZE_HWORD: mem->write_u16(address, data, ae::INTERNAL); break; default: case CELLSIZE_WORD: mem->write_u32(address, data, ae::INTERNAL); break; } } return true; } qtrvsim-0.9.8/src/gui/windows/memory/memorymodel.h000066400000000000000000000055211467752164200223350ustar00rootroot00000000000000#ifndef MEMORYMODEL_H #define MEMORYMODEL_H #include "machine/machine.h" #include #include class MemoryModel : public QAbstractTableModel { Q_OBJECT using Super = QAbstractTableModel; public: enum MemoryCellSize { CELLSIZE_BYTE, CELLSIZE_HWORD, CELLSIZE_WORD, }; explicit MemoryModel(QObject *parent); [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int columnCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; [[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; bool adjustRowAndOffset(int &row, machine::Address address); void update_all(); void setCellsPerRow(unsigned int cells); [[nodiscard]] inline unsigned int cellsPerRow() const { return cells_per_row; } [[nodiscard]] inline const QFont *getFont() const { return &data_font; } [[nodiscard]] inline machine::Address getIndex0Offset() const { return index0_offset; } [[nodiscard]] inline unsigned int cellSizeBytes() const { switch (cell_size) { case CELLSIZE_BYTE: return 1; case CELLSIZE_HWORD: return 2; case CELLSIZE_WORD: return 4; } return 0; } inline bool get_row_address(machine::Address &address, int row) const { address = index0_offset + (row * cells_per_row * cellSizeBytes()); return address >= index0_offset; } inline bool get_row_for_address(int &row, machine::Address address) const { if (address < index0_offset) { row = -1; return false; } row = (address - index0_offset) / (cells_per_row * cellSizeBytes()); if ((address - index0_offset > 0x80000000) || row > rowCount()) { row = rowCount(); return false; } return true; } public slots: void setup(machine::Machine *machine); void set_cell_size(int index); void check_for_updates(); void cached_access(int cached); signals: void cell_size_changed(); void setup_done(); private: [[nodiscard]] const machine::FrontendMemory *mem_access() const; [[nodiscard]] machine::FrontendMemory *mem_access_rw() const; enum MemoryCellSize cell_size; unsigned int cells_per_row; machine::Address index0_offset; QFont data_font; machine::Machine *machine; uint32_t memory_change_counter; uint32_t cache_data_change_counter; int access_through_cache; }; #endif // MEMORYMODEL_H qtrvsim-0.9.8/src/gui/windows/memory/memorytableview.cpp000066400000000000000000000156211467752164200235540ustar00rootroot00000000000000#include "memorytableview.h" #include "common/polyfills/qt5/qfontmetrics.h" #include "hinttabledelegate.h" #include "memorymodel.h" #include #include #include #include #include #include #include MemoryTableView::MemoryTableView(QWidget *parent, QSettings *settings) : Super(parent) { setItemDelegate(new HintTableDelegate(this)); connect( verticalScrollBar(), &QAbstractSlider::valueChanged, this, &MemoryTableView::adjust_scroll_pos_check); connect( this, &MemoryTableView::adjust_scroll_pos_queue, this, &MemoryTableView::adjust_scroll_pos_process, Qt::QueuedConnection); this->settings = settings; initial_address = machine::Address(settings->value("DataViewAddr0", 0).toULongLong()); adjust_scroll_pos_in_progress = false; setTextElideMode(Qt::ElideNone); } void MemoryTableView::addr0_save_change(machine::Address val) { settings->setValue("DataViewAddr0", qint64(val.get_raw())); } void MemoryTableView::adjustColumnCount() { auto *m = dynamic_cast(model()); if (m == nullptr) { return; } auto *delegate = dynamic_cast(itemDelegate()); if (delegate == nullptr) { return; } if (horizontalHeader()->count() >= 2) { QModelIndex idx; QFontMetrics fm(*m->getFont()); idx = m->index(0, 0); QStyleOptionViewItem viewOpts; initViewItemOption(&viewOpts); // int width0_dh = itemDelegate(idx)->sizeHint(viewOptions(), // idx).get_width() + 2; int width0_dh = delegate->sizeHintForText(viewOpts, idx, "0x00000000").width() + 2; horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); horizontalHeader()->resizeSection(0, width0_dh); idx = m->index(0, 1); QString t = ""; t.fill(QChar('0'), m->cellSizeBytes() * 2); int width1_dh = delegate->sizeHintForText(viewOpts, idx, t).width() + 2; if (width1_dh < QFontMetrics_horizontalAdvance(fm, "+99")) { width1_dh = QFontMetrics_horizontalAdvance(fm, "+99"); } horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed); horizontalHeader()->resizeSection(1, width1_dh); int w = verticalHeader()->width() + 4; unsigned int cells; int width0 = columnWidth(0); int width1 = columnWidth(1); w = width() - w - width0; if (w < width1 + 4) { cells = 1; } else { cells = w / (width1 + 4); } if (cells != m->cellsPerRow()) { m->setCellsPerRow(cells); } for (unsigned int i = 1; i < m->cellsPerRow() + 1; i++) { horizontalHeader()->setSectionResizeMode(i, QHeaderView::Fixed); horizontalHeader()->resizeSection(i, width1); } if (!initial_address.is_null()) { go_to_address(initial_address); initial_address = machine::Address::null(); } } } void MemoryTableView::recompute_columns() { adjustColumnCount(); } void MemoryTableView::set_cell_size(int index) { machine::Address address; int row; bool keep_row0 = false; auto *m = dynamic_cast(model()); if (m != nullptr) { keep_row0 = m->get_row_address(address, rowAt(0)); m->set_cell_size(index); } adjustColumnCount(); if (keep_row0) { m->adjustRowAndOffset(row, address); scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop); } } void MemoryTableView::adjust_scroll_pos_check() { if (!adjust_scroll_pos_in_progress) { adjust_scroll_pos_in_progress = true; emit adjust_scroll_pos_queue(); } } void MemoryTableView::adjust_scroll_pos_process() { adjust_scroll_pos_in_progress = false; machine::Address address; auto *m = dynamic_cast(model()); if (m == nullptr) { return; } QModelIndex prev_index = currentIndex(); auto row_bytes = machine::Address(m->cellSizeBytes() * m->cellsPerRow()); machine::Address index0_offset = m->getIndex0Offset(); do { int row = rowAt(0); int prev_row = row; if (row < m->rowCount() / 8) { if ((row == 0) && (index0_offset < row_bytes) && (!index0_offset.is_null())) { m->adjustRowAndOffset(row, machine::Address::null()); } else if (index0_offset > row_bytes) { m->get_row_address(address, row); m->adjustRowAndOffset(row, address); } else { break; } } else if (row > m->rowCount() - m->rowCount() / 8) { m->get_row_address(address, row); m->adjustRowAndOffset(row, address); } else { break; } scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop); setCurrentIndex(m->index(prev_index.row() + row - prev_row, prev_index.column())); emit m->update_all(); } while (false); m->get_row_address(address, rowAt(0)); addr0_save_change(address); emit address_changed(address); } void MemoryTableView::resizeEvent(QResizeEvent *event) { auto *m = dynamic_cast(model()); machine::Address address; bool keep_row0 = false; if (m != nullptr) { if (initial_address.is_null()) { keep_row0 = m->get_row_address(address, rowAt(0)); } else { address = initial_address; } } Super::resizeEvent(event); adjustColumnCount(); if (keep_row0) { initial_address = machine::Address::null(); go_to_address(address); } } void MemoryTableView::go_to_address(machine::Address address) { auto *m = dynamic_cast(model()); int row; if (m == nullptr) { return; } m->adjustRowAndOffset(row, address); scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop); setCurrentIndex(m->index(row, 1)); addr0_save_change(address); emit m->update_all(); } void MemoryTableView::focus_address(machine::Address address) { int row; auto *m = dynamic_cast(model()); if (m == nullptr) { return; } if (!m->get_row_for_address(row, address)) { go_to_address(address); } if (!m->get_row_for_address(row, address)) { return; } setCurrentIndex(m->index(row, 1)); } void MemoryTableView::keyPressEvent(QKeyEvent *event) { if (event->matches(QKeySequence::Copy)) { QString text; QItemSelectionRange range = selectionModel()->selection().first(); for (auto i = range.top(); i <= range.bottom(); ++i) { QStringList rowContents; for (auto j = range.left(); j <= range.right(); ++j) { rowContents << model()->index(i, j).data().toString(); } text += rowContents.join("\t"); text += "\n"; } QApplication::clipboard()->setText(text); } else { Super::keyPressEvent(event); } } qtrvsim-0.9.8/src/gui/windows/memory/memorytableview.h000066400000000000000000000020631467752164200232150ustar00rootroot00000000000000#ifndef MEMORYTABLEVIEW_H #define MEMORYTABLEVIEW_H #include "common/polyfills/qt5/qtableview.h" #include "machine/memory/address.h" #include #include #include class MemoryTableView : public Poly_QTableView { Q_OBJECT using Super = Poly_QTableView; public: MemoryTableView(QWidget *parent, QSettings *settings); void resizeEvent(QResizeEvent *event) override; signals: void address_changed(machine::Address address); void adjust_scroll_pos_queue(); public slots: void set_cell_size(int index); void go_to_address(machine::Address address); void focus_address(machine::Address address); void recompute_columns(); protected: void keyPressEvent(QKeyEvent *event) override; private slots: void adjust_scroll_pos_check(); void adjust_scroll_pos_process(); private: void addr0_save_change(machine::Address val); void adjustColumnCount(); QSettings *settings; machine::Address initial_address; bool adjust_scroll_pos_in_progress; }; #endif // MEMORYTABLEVIEW_H qtrvsim-0.9.8/src/gui/windows/messages/000077500000000000000000000000001467752164200201275ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/messages/messagesdock.cpp000066400000000000000000000030711467752164200233040ustar00rootroot00000000000000#include "messagesdock.h" #include "assembler/messagetype.h" #include "messagesmodel.h" #include "messagesview.h" #include "ui/hexlineedit.h" #include #include #include #include #include MessagesDock::MessagesDock(QWidget *parent, QSettings *settings) : Super(parent) { setObjectName("Messages"); setWindowTitle("Messages"); this->settings = settings; QWidget *content = new QWidget(); QListView *messages_content = new MessagesView(nullptr, settings); MessagesModel *messages_model = new MessagesModel(this); messages_content->setModel(messages_model); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(messages_content); content->setLayout(layout); setWidget(content); connect( this, &MessagesDock::report_message, messages_model, &MessagesModel::insert_line); connect( this, &MessagesDock::pass_clear_messages, messages_model, &MessagesModel::clear_messages); connect( messages_content, &QAbstractItemView::activated, messages_model, &MessagesModel::activated); connect( messages_model, &MessagesModel::message_selected, this, &MessagesDock::message_selected); } void MessagesDock::insert_line( messagetype::Type type, QString file, int line, int column, QString text, QString hint) { report_message( type, std::move(file), line, column, std::move(text), std::move(hint)); } void MessagesDock::clear_messages() { emit pass_clear_messages(); } qtrvsim-0.9.8/src/gui/windows/messages/messagesdock.h000066400000000000000000000016601467752164200227530ustar00rootroot00000000000000#ifndef MESSAGESDOCK_H #define MESSAGESDOCK_H #include "messagesmodel.h" #include #include #include #include class MessagesDock : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: MessagesDock(QWidget *parent, QSettings *settings); public slots: void insert_line( messagetype::Type type, QString file, int line, int column, QString text, QString hint); void clear_messages(); signals: void report_message( messagetype::Type type, QString file, int line, int column, QString text, QString hint); void pass_clear_messages(); void message_selected( messagetype::Type type, QString file, int line, int column, QString text, QString hint); private: QSettings *settings; }; #endif // MESSAGESDOCK_H qtrvsim-0.9.8/src/gui/windows/messages/messagesmodel.cpp000066400000000000000000000062271467752164200234720ustar00rootroot00000000000000#include "messagesmodel.h" #include #include class MessagesEntry { public: inline MessagesEntry( messagetype::Type type, QString file, int line, int column, QString text, QString hint) { this->type = type; this->file = std::move(file); this->line = line; this->column = column; this->text = std::move(text); this->hint = std::move(hint); } messagetype::Type type; QString file; int line; int column; QString text; QString hint; }; MessagesModel::MessagesModel(QObject *parent) : Super(parent) { } MessagesModel::~MessagesModel() { clear_messages(); } int MessagesModel::rowCount(const QModelIndex & /*parent*/) const { return messages.count(); } int MessagesModel::columnCount(const QModelIndex & /*parent*/) const { return 1; } QVariant MessagesModel::headerData( int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { switch (section) { case 0: return tr("Type"); case 1: return tr("Source"); case 2: return tr("Line"); case 3: return tr("Column"); case 4: return tr("Text"); default: return tr(""); } } } return Super::headerData(section, orientation, role); } QVariant MessagesModel::data(const QModelIndex &index, int role) const { if (index.row() >= rowCount()) { return {}; } if (role == Qt::DisplayRole || role == Qt::EditRole) { MessagesEntry *ent = messages.at(index.row()); QString ret = ""; if (!ent->file.isEmpty()) { ret += ent->file + ":"; } if (ent->line) { ret += QString::number(ent->line) + ":"; } if (ent->column) { ret += QString::number(ent->column) + ":"; } ret += ent->text; return ret; } if (role == Qt::BackgroundRole) { MessagesEntry *ent = messages.at(index.row()); switch (ent->type) { case messagetype::MSG_ERROR: return QBrush(QColor(255, 230, 230)); case messagetype::MSG_WARNING: return QBrush(QColor(255, 255, 220)); default: return {}; } } return {}; } void MessagesModel::insert_line( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); messages.append(new MessagesEntry(type, file, line, column, text, hint)); endInsertRows(); } void MessagesModel::clear_messages() { auto row_count = rowCount(); if (row_count == 0) return; beginRemoveRows(QModelIndex(), 0, row_count - 1); while (!messages.isEmpty()) { delete messages.takeFirst(); } endRemoveRows(); } void MessagesModel::activated(QModelIndex index) { if (index.row() >= rowCount()) { return; } MessagesEntry *ent = messages.at(index.row()); emit message_selected( ent->type, ent->file, ent->line, ent->column, ent->text, ent->hint); } qtrvsim-0.9.8/src/gui/windows/messages/messagesmodel.h000066400000000000000000000023761467752164200231400ustar00rootroot00000000000000#ifndef MESSAGESMODEL_H #define MESSAGESMODEL_H #include "assembler/messagetype.h" #include #include #include class MessagesEntry; class MessagesModel : public QAbstractListModel { Q_OBJECT using Super = QAbstractListModel; public: explicit MessagesModel(QObject *parent); ~MessagesModel() override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int columnCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; public slots: void insert_line( messagetype::Type type, const QString &file, int line, int column, const QString &text, const QString &hint); void clear_messages(); void activated(QModelIndex index); signals: void message_selected( messagetype::Type type, QString file, int line, int column, QString text, QString hint); private: QVector messages; }; #endif // MESSAGESMODEL_H qtrvsim-0.9.8/src/gui/windows/messages/messagesview.cpp000066400000000000000000000020151467752164200233330ustar00rootroot00000000000000#include "messagesview.h" #include "messagesmodel.h" #include #include #include #include #include #include MessagesView::MessagesView(QWidget *parent, QSettings *settings) : Super(parent) { this->settings = settings; } void MessagesView::resizeEvent(QResizeEvent *event) { Super::resizeEvent(event); } void MessagesView::keyPressEvent(QKeyEvent *event) { if (event->matches(QKeySequence::Copy)) { QString text; QItemSelectionRange range = selectionModel()->selection().first(); for (auto i = range.top(); i <= range.bottom(); ++i) { QStringList rowContents; for (auto j = range.left(); j <= range.right(); ++j) { rowContents << model()->index(i, j).data().toString(); } text += rowContents.join("\t"); text += "\n"; } QApplication::clipboard()->setText(text); } else { Super::keyPressEvent(event); } } qtrvsim-0.9.8/src/gui/windows/messages/messagesview.h000066400000000000000000000007051467752164200230040ustar00rootroot00000000000000#ifndef MESSAGESVIEW_H #define MESSAGESVIEW_H #include #include #include #include class MessagesView : public QListView { Q_OBJECT using Super = QListView; public: MessagesView(QWidget *parent, QSettings *settings); void resizeEvent(QResizeEvent *event) override; protected: void keyPressEvent(QKeyEvent *event) override; QSettings *settings; }; #endif // MESSAGESVIEW_H qtrvsim-0.9.8/src/gui/windows/peripherals/000077500000000000000000000000001467752164200206365ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/peripherals/peripheralsdock.cpp000066400000000000000000000010251467752164200245170ustar00rootroot00000000000000#include "peripheralsdock.h" PeripheralsDock::PeripheralsDock(QWidget *parent, QSettings *settings) : QDockWidget(parent) { (void)settings; top_widget = new QWidget(this); setWidget(top_widget); layout_box = new QVBoxLayout(top_widget); periph_view = new PeripheralsView(nullptr); layout_box->addWidget(periph_view); setObjectName("Peripherals"); setWindowTitle("Peripherals"); } void PeripheralsDock::setup(const machine::PeripSpiLed *perip_spi_led) { periph_view->setup(perip_spi_led); } qtrvsim-0.9.8/src/gui/windows/peripherals/peripheralsdock.h000066400000000000000000000011761467752164200241730ustar00rootroot00000000000000#ifndef PERIPHERALSDOCK_H #define PERIPHERALSDOCK_H #include "machine/machine.h" #include "machine/memory/backend/peripheral.h" #include "machine/memory/backend/peripspiled.h" #include "peripheralsview.h" #include #include #include class PeripheralsDock : public QDockWidget { Q_OBJECT public: PeripheralsDock(QWidget *parent, QSettings *settings); void setup(const machine::PeripSpiLed *perip_spi_led); private: QVBoxLayout *layout_box; QWidget *top_widget, *top_form {}; QFormLayout *layout_top_form {}; PeripheralsView *periph_view; }; #endif // PERIPHERALSDOCK_H qtrvsim-0.9.8/src/gui/windows/peripherals/peripheralsview.cpp000066400000000000000000000100521467752164200245510ustar00rootroot00000000000000#include "peripheralsview.h" #include "ui_peripheralsview.h" PeripheralsView::PeripheralsView(QWidget *parent) : QWidget(parent) , ui(new Ui::PeripheralsView) { ui->setupUi(this); ui->dialRed->setStyleSheet("QDial { background-color: red }"); ui->dialGreen->setStyleSheet("QDial { background-color: green }"); ui->dialBlue->setStyleSheet("QDial { background-color: blue }"); connect( ui->dialRed, &QAbstractSlider::valueChanged, ui->spinRed, &QSpinBox::setValue); connect( ui->dialGreen, &QAbstractSlider::valueChanged, ui->spinGreen, &QSpinBox::setValue); connect( ui->dialBlue, &QAbstractSlider::valueChanged, ui->spinBlue, &QSpinBox::setValue); connect( ui->spinRed, QOverload::of(&QSpinBox::valueChanged), ui->dialRed, &QAbstractSlider::setValue); connect( ui->spinGreen, QOverload::of(&QSpinBox::valueChanged), ui->dialGreen, &QAbstractSlider::setValue); connect( ui->spinBlue, QOverload::of(&QSpinBox::valueChanged), ui->dialBlue, &QAbstractSlider::setValue); } void PeripheralsView::setup(const machine::PeripSpiLed *perip_spi_led) { int val; connect( ui->spinRed, QOverload::of(&QSpinBox::valueChanged), perip_spi_led, &machine::PeripSpiLed::red_knob_update); connect( ui->spinGreen, QOverload::of(&QSpinBox::valueChanged), perip_spi_led, &machine::PeripSpiLed::green_knob_update); connect( ui->spinBlue, QOverload::of(&QSpinBox::valueChanged), perip_spi_led, &machine::PeripSpiLed::blue_knob_update); val = ui->spinRed->value(); ui->spinRed->setValue(val - 1); ui->spinRed->setValue(val); val = ui->spinGreen->value(); ui->spinGreen->setValue(val - 1); ui->spinGreen->setValue(val); val = ui->spinBlue->value(); ui->spinBlue->setValue(val - 1); ui->spinBlue->setValue(val); connect( ui->checkRed, &QAbstractButton::clicked, perip_spi_led, &machine::PeripSpiLed::red_knob_push); connect( ui->checkGreen, &QAbstractButton::clicked, perip_spi_led, &machine::PeripSpiLed::green_knob_push); connect( ui->checkBlue, &QAbstractButton::clicked, perip_spi_led, &machine::PeripSpiLed::blue_knob_push); ui->checkRed->setChecked(false); ui->checkGreen->setChecked(false); ui->checkBlue->setChecked(false); ui->labelRgb1->setAutoFillBackground(true); ui->labelRgb2->setAutoFillBackground(true); connect( perip_spi_led, &machine::PeripSpiLed::led_line_changed, this, &PeripheralsView::led_line_changed); connect( perip_spi_led, &machine::PeripSpiLed::led_rgb1_changed, this, &PeripheralsView::led_rgb1_changed); connect( perip_spi_led, &machine::PeripSpiLed::led_rgb2_changed, this, &PeripheralsView::led_rgb2_changed); led_line_changed(0); led_rgb1_changed(0); led_rgb2_changed(0); } void PeripheralsView::led_line_changed(uint val) { QString s, t; s = QString::number(val, 16); t.fill('0', 8 - s.count()); ui->lineEditHex->setText(t + s); s = QString::number(val, 10); ui->lineEditDec->setText(s); s = QString::number(val, 2); t.fill('0', 32 - s.count()); ui->lineEditBin->setText(t + s); } static void set_widget_background_color(QWidget *w, uint val) { int r = (val >> 16) & 0xff; int g = (val >> 8) & 0xff; int b = (val >> 0) & 0xff; QPalette::ColorRole brole = w->backgroundRole(); QPalette pal = w->palette(); pal.setColor(brole, QColor(r, g, b)); w->setPalette(pal); } void PeripheralsView::led_rgb1_changed(uint val) { QString s, t; s = QString::number(val, 16); t.fill('0', 8 - s.count()); ui->lineEditRgb1->setText(t + s); set_widget_background_color(ui->labelRgb1, val); } void PeripheralsView::led_rgb2_changed(uint val) { QString s, t; s = QString::number(val, 16); t.fill('0', 8 - s.count()); ui->lineEditRgb2->setText(t + s); set_widget_background_color(ui->labelRgb2, val); } qtrvsim-0.9.8/src/gui/windows/peripherals/peripheralsview.h000066400000000000000000000010771467752164200242250ustar00rootroot00000000000000#ifndef PERIPHERALSVIEW_H #define PERIPHERALSVIEW_H #include "common/memory_ownership.h" #include "machine/memory/backend/peripspiled.h" #include "ui_peripheralsview.h" #include class PeripheralsView : public QWidget { Q_OBJECT public: explicit PeripheralsView(QWidget *parent = nullptr); void setup(const machine::PeripSpiLed *perip_spi_led); public slots: void led_line_changed(uint val); void led_rgb1_changed(uint val); void led_rgb2_changed(uint val); private: Box ui {}; }; #endif // PERIPHERALSVIEW_H qtrvsim-0.9.8/src/gui/windows/peripherals/peripheralsview.ui000066400000000000000000000243651467752164200244200ustar00rootroot00000000000000 PeripheralsView 0 0 573 484 Form QLayout::SetMaximumSize LED RGB 1 Qt::AlignCenter Qt::AlignBottom|Qt::AlignHCenter true Qt::Horizontal 40 20 LED RGB 2 Qt::AlignCenter Qt::AlignBottom|Qt::AlignHCenter true QLayout::SetNoConstraint 255 true Red Knob Qt::AlignCenter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 Qt::Horizontal 40 20 255 true Green Knob Qt::AlignCenter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 Qt::Horizontal 40 20 255 true Blue Knob Qt::AlignCenter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 Word hexadecimal Qt::AlignBottom|Qt::AlignHCenter Qt::AlignCenter true Qt::Horizontal 40 20 Word decimal Qt::AlignBottom|Qt::AlignHCenter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Word binary Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft Qt::AlignCenter true qtrvsim-0.9.8/src/gui/windows/predictor/000077500000000000000000000000001467752164200203135ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/predictor/predictor_bht_dock.cpp000066400000000000000000000200451467752164200246500ustar00rootroot00000000000000#include "predictor_bht_dock.h" LOG_CATEGORY("gui.DockPredictorBHT"); DockPredictorBHT::DockPredictorBHT(QWidget *parent) : Super(parent) { setObjectName("PredictorBHT"); setWindowTitle("Predictor Branch History"); ///////////////////////// // Assign layout // Name layout_type->addWidget(label_type); layout_type->addWidget(label_type_value); // Stats layout_stats->addWidget(label_stats_correct_text, 0, 0); layout_stats->addWidget(label_stats_correct_value, 0, 1); layout_stats->addWidget(label_stats_wrong_text, 1, 0); layout_stats->addWidget(label_stats_wrong_value, 1, 1); layout_stats->addWidget(label_stats_accuracy_text, 2, 0); layout_stats->addWidget(label_stats_accuracy_value, 2, 1); // Main layout layout_main->addLayout(layout_type); layout_main->addLayout(layout_stats); layout_main->addLayout(layout_event); layout_main->addWidget(bht); content->setLayout(layout_main); setWidget(content); ///////////////////////// // Init widget properties // Name label_type->setText("Predictor type:"); label_type->setStyleSheet("font-weight: bold;"); clear_name(); // Stats label_stats_correct_text->setText("Correct predictions:"); label_stats_wrong_text->setText("Wrong predictions:"); label_stats_accuracy_text->setText("Accuracy:"); clear_stats(); // BHT bht->setRowCount(0); bht->setColumnCount(5); bht->setHorizontalHeaderLabels({ "Index", "State", "Correct", "Incorrect", "Accuracy" }); bht->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); bht->verticalHeader()->hide(); bht->resizeRowsToContents(); } // Get BHT cell item, or create new one if needed QTableWidgetItem* DockPredictorBHT::get_bht_cell_item(uint8_t row_index, uint8_t col_index) { QTableWidgetItem *item { bht->item(row_index, col_index) }; if (item == nullptr) { item = new QTableWidgetItem(); bht->setItem(row_index, col_index, item); item->setTextAlignment(Qt::AlignCenter); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); } return item; } void DockPredictorBHT::set_table_color(QColor color) { for (uint16_t row_index = 0; row_index < bht->rowCount(); row_index++) { for (uint16_t column_index = 0; column_index < bht->columnCount(); column_index++) { get_bht_cell_item(row_index, column_index)->setBackground( QBrush(color)); } } } void DockPredictorBHT::set_row_color(uint16_t row_index, QColor color) { for (uint16_t column_index = 0; column_index < bht->columnCount(); column_index++) { get_bht_cell_item(row_index, column_index)->setBackground( QBrush(color)); } } void DockPredictorBHT::setup( const machine::BranchPredictor *branch_predictor, const machine::Core *core) { clear(); number_of_bhr_bits = branch_predictor->get_number_of_bhr_bits(); number_of_bht_bits = branch_predictor->get_number_of_bht_bits(); initial_state = branch_predictor->get_initial_state(); const machine::PredictorType predictor_type { branch_predictor->get_predictor_type() }; const bool is_predictor_dynamic { machine::is_predictor_type_dynamic(predictor_type) }; const bool is_predictor_enabled { branch_predictor->get_enabled() }; if (is_predictor_enabled) { content->setDisabled(false); label_type_value->setText(branch_predictor->get_predictor_name().toString()); connect( branch_predictor, &machine::BranchPredictor::predictor_stats_updated, this, &DockPredictorBHT::update_predictor_stats); connect( branch_predictor, &machine::BranchPredictor::prediction_done, this, &DockPredictorBHT::show_new_prediction); connect( core, &machine::Core::step_started, this, &DockPredictorBHT::reset_colors); if (is_predictor_dynamic) { bht->setDisabled(false); bht->setRowCount(qPow(2, number_of_bht_bits)); clear_bht(initial_state); connect( branch_predictor, &machine::BranchPredictor::update_done, this, &DockPredictorBHT::show_new_update); connect( branch_predictor, &machine::BranchPredictor::predictor_bht_row_updated, this, &DockPredictorBHT::update_bht_row); } else { bht->setDisabled(true); bht->setRowCount(0); } } else { content->setDisabled(true); label_type_value->setText("None"); } } void DockPredictorBHT::show_new_prediction( uint16_t btb_index, uint16_t bht_index, machine::PredictionInput input, machine::BranchResult result, machine::BranchType branch_type) { UNUSED(btb_index); UNUSED(input); UNUSED(result); if (branch_type == machine::BranchType::BRANCH) { set_row_color(bht_index, Q_COLOR_PREDICT); } } void DockPredictorBHT::show_new_update( uint16_t btb_index, uint16_t bht_index, machine::PredictionFeedback feedback) { UNUSED(btb_index); if (feedback.branch_type == machine::BranchType::BRANCH) { set_row_color(bht_index, Q_COLOR_UPDATE); } } void DockPredictorBHT::update_predictor_stats(machine::PredictionStatistics stats) { label_stats_correct_value->setText(QString::number(stats.correct)); label_stats_wrong_value->setText(QString::number(stats.wrong)); label_stats_accuracy_value->setText(QString::number(stats.accuracy) + " %"); if (stats.total > 0) { label_stats_accuracy_value->setText(QString::number(stats.accuracy) + " %"); } else { label_stats_accuracy_value->setText("N/A"); } } void DockPredictorBHT::update_bht_row(uint16_t row_index, machine::BranchHistoryTableEntry bht_entry) { if (row_index >= bht->rowCount()) { WARN("BHT dock update received invalid row index: %u", row_index); return; } for (uint16_t column_index = 0; column_index < bht->columnCount(); column_index++) { get_bht_cell_item(row_index, DOCK_BHT_COL_STATE)->setData( Qt::DisplayRole, machine::predictor_state_to_string(bht_entry.state, true).toString()); get_bht_cell_item(row_index, DOCK_BHT_COL_CORRECT)->setData( Qt::DisplayRole, QString::number(bht_entry.stats.correct)); get_bht_cell_item(row_index, DOCK_BHT_COL_INCORRECT)->setData( Qt::DisplayRole, QString::number(bht_entry.stats.wrong)); if (bht_entry.stats.total > 0) { get_bht_cell_item(row_index, DOCK_BHT_COL_ACCURACY)->setData( Qt::DisplayRole, QString::number(bht_entry.stats.accuracy) + " %"); } else { get_bht_cell_item(row_index, DOCK_BHT_COL_ACCURACY)->setData( Qt::DisplayRole, "N/A"); } } } void DockPredictorBHT::reset_colors() { set_table_color(Q_COLOR_DEFAULT); } void DockPredictorBHT::clear_stats() { label_stats_correct_value->setText("0"); label_stats_wrong_value->setText("0"); label_stats_accuracy_value->setText("N/A"); } void DockPredictorBHT::clear_name() { label_type_value->setText(""); } void DockPredictorBHT::clear_bht(machine::PredictorState initial_state) { for (uint16_t row_index = 0; row_index < bht->rowCount(); row_index++) { get_bht_cell_item(row_index, DOCK_BHT_COL_INDEX)->setData( Qt::DisplayRole, QString::number(row_index)); get_bht_cell_item(row_index, DOCK_BHT_COL_STATE)->setData( Qt::DisplayRole, machine::predictor_state_to_string(initial_state, true).toString()); get_bht_cell_item(row_index, DOCK_BHT_COL_CORRECT)->setData( Qt::DisplayRole, QString::number(0)); get_bht_cell_item(row_index, DOCK_BHT_COL_INCORRECT)->setData( Qt::DisplayRole, QString::number(0)); get_bht_cell_item(row_index, DOCK_BHT_COL_ACCURACY)->setData( Qt::DisplayRole, QString("N/A")); } bht->resizeRowsToContents(); set_table_color(Q_COLOR_DEFAULT); } void DockPredictorBHT::clear() { clear_name(); clear_stats(); clear_bht(); } qtrvsim-0.9.8/src/gui/windows/predictor/predictor_bht_dock.h000066400000000000000000000065031467752164200243200ustar00rootroot00000000000000#ifndef PREDICTOR_BHT_DOCK_H #define PREDICTOR_BHT_DOCK_H #include "common/polyfills/qt5/qtableview.h" #include "machine/machine.h" #include "machine/memory/address.h" #include "machine/predictor.h" #include "machine/predictor_types.h" #include "ui/hexlineedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOCK_BHT_COL_INDEX 0 #define DOCK_BHT_COL_STATE 1 #define DOCK_BHT_COL_CORRECT 2 #define DOCK_BHT_COL_INCORRECT 3 #define DOCK_BHT_COL_ACCURACY 4 #define STYLESHEET_COLOR_DEFAULT "background: rgb(255,255,255);" #define STYLESHEET_COLOR_PREDICT "background: rgb(255,173,173);" #define STYLESHEET_COLOR_UPDATE "background: rgb(173,255,229);" #define Q_COLOR_DEFAULT QColor(255, 255, 255) #define Q_COLOR_PREDICT QColor(255, 173, 173) #define Q_COLOR_UPDATE QColor(173, 255, 229) class DockPredictorBHT : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: // Constructors & Destructor DockPredictorBHT(QWidget *parent); private: // Internal functions QTableWidgetItem* get_bht_cell_item(uint8_t row_index, uint8_t col_index); void set_table_color(QColor color); void set_row_color(uint16_t row_index, QColor color); public: // General functions void setup(const machine::BranchPredictor *branch_predictor, const machine::Core *core); public slots: void show_new_prediction( uint16_t btb_index, uint16_t bht_index, machine::PredictionInput input, machine::BranchResult result, machine::BranchType branch_type); void show_new_update( uint16_t btb_index, uint16_t bht_index, machine::PredictionFeedback feedback); void update_predictor_stats(machine::PredictionStatistics stats); void update_bht_row(uint16_t row_index, machine::BranchHistoryTableEntry bht_entry); void reset_colors(); void clear_name(); void clear_stats(); void clear_bht(machine::PredictorState initial_state = machine::PredictorState::UNDEFINED); void clear(); private: // Internal variables uint8_t number_of_bhr_bits{ 0 }; uint8_t number_of_bht_bits{ 0 }; machine::PredictorState initial_state{ machine::PredictorState::UNDEFINED }; QT_OWNED QGroupBox *content{ new QGroupBox() }; QT_OWNED QVBoxLayout *layout_main{ new QVBoxLayout() }; // Name QT_OWNED QHBoxLayout *layout_type{ new QHBoxLayout() }; QT_OWNED QLabel *label_type{ new QLabel() }; QT_OWNED QLabel *label_type_value{ new QLabel() }; // Stats QT_OWNED QGridLayout *layout_stats{ new QGridLayout() }; QT_OWNED QLabel *label_stats_correct_text{ new QLabel() }; QT_OWNED QLabel *label_stats_wrong_text{ new QLabel() }; QT_OWNED QLabel *label_stats_accuracy_text{ new QLabel() }; QT_OWNED QLabel *label_stats_correct_value{ new QLabel() }; QT_OWNED QLabel *label_stats_wrong_value{ new QLabel() }; QT_OWNED QLabel *label_stats_accuracy_value{ new QLabel() }; // Prediction & Update QT_OWNED QHBoxLayout *layout_event{ new QHBoxLayout() }; // BHT QT_OWNED QTableWidget *bht{ new QTableWidget() }; }; #endif // PREDICTOR_BHT_DOCK_Hqtrvsim-0.9.8/src/gui/windows/predictor/predictor_btb_dock.cpp000066400000000000000000000122551467752164200246460ustar00rootroot00000000000000#include "predictor_btb_dock.h" LOG_CATEGORY("gui.DockPredictorBTB"); DockPredictorBTB::DockPredictorBTB(QWidget *parent) : Super(parent) { setObjectName("PredictorBTB"); setWindowTitle("Predictor Branch Target Buffer"); ///////////////////////// // Assign layout layout->addWidget(btb); content->setLayout(layout); setWidget(content); ///////////////////////// // Init widget properties // BTB btb->setRowCount(0); btb->setColumnCount(4); btb->setHorizontalHeaderLabels({ "Index", "Instr. Address", "Target Address", "Type" }); btb->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); btb->verticalHeader()->hide(); btb->resizeRowsToContents(); } uint8_t DockPredictorBTB::init_number_of_bits(const uint8_t b) const { if (b > BP_MAX_BTB_BITS) { WARN("Number of BTB bits (%u) was larger than %u during init", b, BP_MAX_BTB_BITS); return BP_MAX_BTB_BITS; } return b; } // Get BTB cell item, or create new one if needed QTableWidgetItem* DockPredictorBTB::get_btb_cell_item(uint8_t row_index, uint8_t col_index) { QTableWidgetItem *item { btb->item(row_index, col_index) }; if (item == nullptr) { item = new QTableWidgetItem(); btb->setItem(row_index, col_index, item); item->setTextAlignment(Qt::AlignCenter); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); } return item; } void DockPredictorBTB::set_table_color(QColor color) { for (uint16_t row_index = 0; row_index < btb->rowCount(); row_index++) { for (uint16_t column_index = 0; column_index < btb->columnCount(); column_index++) { get_btb_cell_item(row_index, column_index)->setBackground( QBrush(color)); } } } void DockPredictorBTB::set_row_color(uint16_t row_index, QColor color) { for (uint16_t column_index = 0; column_index < btb->columnCount(); column_index++) { get_btb_cell_item(row_index, column_index)->setBackground( QBrush(color)); } } void DockPredictorBTB::setup( const machine::BranchPredictor *branch_predictor, const machine::Core *core) { clear(); number_of_bits = init_number_of_bits(branch_predictor->get_number_of_btb_bits()); const bool is_predictor_enabled { branch_predictor->get_enabled() }; if (is_predictor_enabled) { btb->setRowCount(qPow(2, number_of_bits)); btb->setDisabled(false); clear_btb(); connect( branch_predictor, &machine::BranchPredictor::btb_row_updated, this, &DockPredictorBTB::update_btb_row); connect( branch_predictor, &machine::BranchPredictor::prediction_done, this, &DockPredictorBTB::highligh_row_after_prediction); connect( branch_predictor, &machine::BranchPredictor::update_done, this, &DockPredictorBTB::highligh_row_after_update); connect( core, &machine::Core::step_started, this, &DockPredictorBTB::reset_colors); } else { btb->setRowCount(0); btb->setDisabled(true); } } void DockPredictorBTB::update_btb_row( uint16_t row_index, machine::BranchTargetBufferEntry btb_entry ) { if (row_index >= btb->rowCount()) { WARN("BTB dock update received invalid row index: %u", row_index); return; } if (btb_entry.entry_valid) { get_btb_cell_item(row_index, DOCK_BTB_COL_INSTR_ADDR)->setData( Qt::DisplayRole, machine::addr_to_hex_str(btb_entry.instruction_address)); get_btb_cell_item(row_index, DOCK_BTB_COL_TARGET_ADDR)->setData( Qt::DisplayRole, machine::addr_to_hex_str(btb_entry.target_address)); get_btb_cell_item(row_index, DOCK_BTB_COL_TYPE)->setData( Qt::DisplayRole, machine::branch_type_to_string(btb_entry.branch_type).toString()); } else { get_btb_cell_item(row_index, DOCK_BTB_COL_INSTR_ADDR)->setData( Qt::DisplayRole, ""); get_btb_cell_item(row_index, DOCK_BTB_COL_TARGET_ADDR)->setData( Qt::DisplayRole, ""); get_btb_cell_item(row_index, DOCK_BTB_COL_TYPE)->setData( Qt::DisplayRole, ""); } } void DockPredictorBTB::highligh_row_after_prediction(uint16_t row_index) { set_row_color(row_index, Q_COLOR_PREDICT); } void DockPredictorBTB::highligh_row_after_update(uint16_t row_index) { set_row_color(row_index, Q_COLOR_UPDATE); } void DockPredictorBTB::reset_colors() { set_table_color(Q_COLOR_DEFAULT); } void DockPredictorBTB::clear_btb() { for (uint16_t row_index = 0; row_index < btb->rowCount(); row_index++) { get_btb_cell_item(row_index, DOCK_BTB_COL_INDEX)->setData( Qt::DisplayRole, QString::number(row_index)); get_btb_cell_item(row_index, DOCK_BTB_COL_INSTR_ADDR)->setData( Qt::DisplayRole, QString("")); get_btb_cell_item(row_index, DOCK_BTB_COL_TARGET_ADDR)->setData( Qt::DisplayRole, QString("")); get_btb_cell_item(row_index, DOCK_BTB_COL_TYPE)->setData( Qt::DisplayRole, QString("")); } btb->resizeRowsToContents(); set_table_color(Q_COLOR_DEFAULT); } void DockPredictorBTB::clear() { clear_btb(); }qtrvsim-0.9.8/src/gui/windows/predictor/predictor_btb_dock.h000066400000000000000000000036171467752164200243150ustar00rootroot00000000000000#ifndef PREDICTOR_BTB_DOCK_H #define PREDICTOR_BTB_DOCK_H #include "common/polyfills/qt5/qtableview.h" #include "machine/machine.h" #include "machine/memory/address.h" #include "machine/predictor.h" #include "machine/predictor_types.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DOCK_BTB_COL_INDEX 0 #define DOCK_BTB_COL_INSTR_ADDR 1 #define DOCK_BTB_COL_TARGET_ADDR 2 #define DOCK_BTB_COL_TYPE 3 #define Q_COLOR_DEFAULT QColor(255, 255, 255) #define Q_COLOR_PREDICT QColor(255, 173, 173) #define Q_COLOR_UPDATE QColor(173, 255, 229) // Branch Target Buffer Dock class DockPredictorBTB : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: // Constructors & Destructor DockPredictorBTB(QWidget *parent); private: // Internal functions uint8_t init_number_of_bits(const uint8_t b) const; QTableWidgetItem* get_btb_cell_item(uint8_t row_index, uint8_t col_index); void set_table_color(QColor color); void set_row_color(uint16_t row_index, QColor color); public: // General functions void setup(const machine::BranchPredictor *branch_predictor, const machine::Core *core); public slots: void update_btb_row(uint16_t row_index, machine::BranchTargetBufferEntry btb_entry); void highligh_row_after_prediction(uint16_t btb_index); void highligh_row_after_update(uint16_t btb_index); void reset_colors(); void clear_btb(); void clear(); private: // Internal variables uint8_t number_of_bits{ 0 }; QT_OWNED QGroupBox *content{ new QGroupBox() }; QT_OWNED QVBoxLayout *layout{ new QVBoxLayout() }; QT_OWNED QTableWidget *btb{ new QTableWidget() }; }; #endif // PREDICTOR_BTB_DOCK_Hqtrvsim-0.9.8/src/gui/windows/predictor/predictor_info_dock.cpp000066400000000000000000000316631467752164200250360ustar00rootroot00000000000000#include "predictor_info_dock.h" #include #include #include #include #include #include #include LOG_CATEGORY("gui.DockPredictorInfo"); DockPredictorInfo::DockPredictorInfo(QWidget *parent) : Super(parent) { setObjectName("PredictorInfo"); setWindowTitle("Predictor Info"); ///////////////////////// // Assign layout // Stats layout_stats->addWidget(label_stats_total_text, 0, 0); layout_stats->addWidget(label_stats_total_value, 0, 1); layout_stats->addWidget(label_stats_miss_text, 1, 0); layout_stats->addWidget(label_stats_miss_value, 1, 1); layout_stats->addWidget(label_stats_accuracy_text, 2, 0); layout_stats->addWidget(label_stats_accuracy_value, 2, 1); // BHR layout_bhr->addWidget(label_bhr); layout_bhr->addWidget(value_bhr); // Prediction - BTB index layout_event_predict_index_btb->addWidget(label_event_predict_index_btb); layout_event_predict_index_btb->addWidget(value_event_predict_index_btb); // Prediction - BHT index layout_event_predict_index_bht->addWidget(label_event_predict_index_bht); layout_event_predict_index_bht->addWidget(value_event_predict_index_bht); // Prediction - Indexes layout_event_predict_index->addLayout(layout_event_predict_index_btb); layout_event_predict_index->addLayout(layout_event_predict_index_bht); // Prediction layout_event->addWidget(group_event_predict); group_event_predict->setLayout(layout_event_predict); layout_event_predict->addWidget(label_event_predict_header); layout_event_predict->addWidget(label_event_predict_instruction); layout_event_predict->addWidget(value_event_predict_instruction); layout_event_predict->addWidget(label_event_predict_address); layout_event_predict->addWidget(value_event_predict_address); layout_event_predict->addLayout(layout_event_predict_index); layout_event_predict->addWidget(label_event_predict_result); layout_event_predict->addWidget(value_event_predict_result); // Update - BTB index layout_event_update_index_btb->addWidget(label_event_update_index_btb); layout_event_update_index_btb->addWidget(value_event_update_index_btb); // Update - BHT index layout_event_update_index_bht->addWidget(label_event_update_index_bht); layout_event_update_index_bht->addWidget(value_event_update_index_bht); // Update - Indexes layout_event_update_index->addLayout(layout_event_update_index_btb); layout_event_update_index->addLayout(layout_event_update_index_bht); // Update layout_event->addWidget(group_event_update); group_event_update->setLayout(layout_event_update); layout_event_update->addWidget(label_event_update_header); layout_event_update->addWidget(label_event_update_instruction); layout_event_update->addWidget(value_event_update_instruction); layout_event_update->addWidget(label_event_update_address); layout_event_update->addWidget(value_event_update_address); layout_event_update->addLayout(layout_event_update_index); layout_event_update->addWidget(label_event_update_result); layout_event_update->addWidget(value_event_update_result); // Main layout layout_main->addLayout(layout_stats); layout_main->addLayout(layout_bhr); layout_main->addLayout(layout_event); layout_main->addSpacerItem(vertical_spacer); content->setLayout(layout_main); setWidget(content); ///////////////////////// // Init widget properties // Stats label_stats_total_text->setText("Jump/Branch count:"); label_stats_miss_text->setText("Misprediction count:"); label_stats_accuracy_text->setText("Total accuracy:"); clear_stats(); // BHR label_bhr->setText("Branch History Register:"); value_bhr->setReadOnly(true); value_bhr->setAlignment(Qt::AlignCenter); value_bhr->setFixedWidth(120); clear_bhr(); // Prediction label_event_predict_header->setText("Last prediction"); label_event_predict_header->setStyleSheet("font-weight: bold;"); label_event_predict_instruction->setText("Instruction:"); label_event_predict_address->setText("Instruction Address:"); label_event_predict_index_btb->setText("BTB index:"); label_event_predict_index_bht->setText("BHT index:"); label_event_predict_result->setText("Prediction result:"); value_event_predict_instruction->setReadOnly(true); value_event_predict_address->setReadOnly(true); value_event_predict_index_btb->setReadOnly(true); value_event_predict_index_bht->setReadOnly(true); value_event_predict_result->setReadOnly(true); value_event_predict_instruction->setAlignment(Qt::AlignCenter); value_event_predict_address->setAlignment(Qt::AlignCenter); value_event_predict_index_btb->setAlignment(Qt::AlignCenter); value_event_predict_index_bht->setAlignment(Qt::AlignCenter); value_event_predict_result->setAlignment(Qt::AlignCenter); set_predict_widget_color(STYLESHEET_COLOR_DEFAULT); clear_predict_widget(); // Update label_event_update_header->setText("Last update"); label_event_update_header->setStyleSheet("font-weight: bold;"); label_event_update_instruction->setText("Instruction:"); label_event_update_address->setText("Instruction Address:"); label_event_update_index_btb->setText("BTB index:"); label_event_update_index_bht->setText("BHT index:"); label_event_update_result->setText("Branch result:"); value_event_update_instruction->setReadOnly(true); value_event_update_address->setReadOnly(true); value_event_update_index_btb->setReadOnly(true); value_event_update_index_bht->setReadOnly(true); value_event_update_result->setReadOnly(true); value_event_update_instruction->setAlignment(Qt::AlignCenter); value_event_update_address->setAlignment(Qt::AlignCenter); value_event_update_index_btb->setAlignment(Qt::AlignCenter); value_event_update_index_bht->setAlignment(Qt::AlignCenter); value_event_update_result->setAlignment(Qt::AlignCenter); set_update_widget_color(STYLESHEET_COLOR_DEFAULT); clear_update_widget(); } void DockPredictorInfo::set_predict_widget_color(QString color_stylesheet) { value_event_predict_instruction->setStyleSheet(color_stylesheet); value_event_predict_address->setStyleSheet(color_stylesheet); value_event_predict_index_btb->setStyleSheet(color_stylesheet); if (is_predictor_dynamic) { value_event_predict_index_bht->setStyleSheet(color_stylesheet); } value_event_predict_result->setStyleSheet(color_stylesheet); } void DockPredictorInfo::set_update_widget_color(QString color_stylesheet) { value_event_update_instruction->setStyleSheet(color_stylesheet); value_event_update_address->setStyleSheet(color_stylesheet); value_event_update_index_btb->setStyleSheet(color_stylesheet); if (is_predictor_dynamic) { value_event_update_index_bht->setStyleSheet(color_stylesheet); } value_event_update_result->setStyleSheet(color_stylesheet); } void DockPredictorInfo::setup( const machine::BranchPredictor *branch_predictor, const machine::Core *core) { clear(); number_of_bhr_bits = branch_predictor->get_number_of_bhr_bits(); initial_state = branch_predictor->get_initial_state(); const machine::PredictorType predictor_type { branch_predictor->get_predictor_type() }; is_predictor_dynamic = machine::is_predictor_type_dynamic(predictor_type); is_predictor_enabled = branch_predictor->get_enabled(); if (is_predictor_enabled) { connect( branch_predictor, &machine::BranchPredictor::total_stats_updated, this, &DockPredictorInfo::update_stats); connect( branch_predictor, &machine::BranchPredictor::prediction_done, this, &DockPredictorInfo::show_new_prediction); connect( core, &machine::Core::step_started, this, &DockPredictorInfo::reset_colors); connect( branch_predictor, &machine::BranchPredictor::update_done, this, &DockPredictorInfo::show_new_update); if (is_predictor_dynamic) { connect( branch_predictor, &machine::BranchPredictor::bhr_updated, this, &DockPredictorInfo::update_bhr); } } // Toggle BHT index display if (is_predictor_dynamic) { label_event_predict_index_bht->setEnabled(true); value_event_predict_index_bht->setEnabled(true); label_event_update_index_bht->setEnabled(true); value_event_update_index_bht->setEnabled(true); } else { label_event_predict_index_bht->setEnabled(false); value_event_predict_index_bht->setEnabled(false); label_event_update_index_bht->setEnabled(false); value_event_update_index_bht->setEnabled(false); } // Toggle BHR display if (is_predictor_dynamic && number_of_bhr_bits > 0) { label_bhr->setEnabled(true); value_bhr->setEnabled(true); } else { label_bhr->setEnabled(false); value_bhr->setEnabled(false); } // Toggle whole widget if (is_predictor_enabled) { content->setDisabled(false); } else { content->setDisabled(true); } clear_bhr(); } void DockPredictorInfo::update_bhr(uint8_t number_of_bhr_bits, uint16_t register_value) { if (number_of_bhr_bits > 0) { QString binary_value, zero_padding; binary_value = QString::number(register_value, 2); zero_padding.fill('0', number_of_bhr_bits - binary_value.count()); value_bhr->setText("0b" + zero_padding + binary_value); } else { value_bhr->setText(""); } } void DockPredictorInfo::show_new_prediction( uint16_t btb_index, uint16_t bht_index, machine::PredictionInput input, machine::BranchResult result, machine::BranchType branch_type) { value_event_predict_instruction->setText(input.instruction.to_str()); value_event_predict_address->setText(addr_to_hex_str(input.instruction_address)); value_event_predict_index_btb->setText(QString::number(btb_index)); if (!is_predictor_dynamic) { value_event_predict_index_bht->setText(""); } else if (branch_type == machine::BranchType::BRANCH) { value_event_predict_index_bht->setText(QString::number(bht_index)); } else { value_event_predict_index_bht->setText("N/A"); } value_event_predict_result->setText(machine::branch_result_to_string(result).toString()); set_predict_widget_color(STYLESHEET_COLOR_PREDICT); } void DockPredictorInfo::show_new_update( uint16_t btb_index, uint16_t bht_index, machine::PredictionFeedback feedback) { value_event_update_instruction->setText(feedback.instruction.to_str()); value_event_update_address->setText(addr_to_hex_str(feedback.instruction_address)); value_event_update_index_btb->setText(QString::number(btb_index)); if (!is_predictor_dynamic) { value_event_update_index_bht->setText(""); } else if (feedback.branch_type == machine::BranchType::BRANCH ) { value_event_update_index_bht->setText(QString::number(bht_index)); } else { value_event_update_index_bht->setText("N/A"); } value_event_update_result->setText( machine::branch_result_to_string(feedback.result).toString()); set_update_widget_color(STYLESHEET_COLOR_UPDATE); } void DockPredictorInfo::update_stats(machine::PredictionStatistics stats) { label_stats_total_value->setText(QString::number(stats.correct)); label_stats_miss_value->setText(QString::number(stats.wrong)); label_stats_accuracy_value->setText(QString::number(stats.accuracy) + " %"); } void DockPredictorInfo::reset_colors() { set_predict_widget_color(STYLESHEET_COLOR_DEFAULT); set_update_widget_color(STYLESHEET_COLOR_DEFAULT); } void DockPredictorInfo::clear_stats() { label_stats_total_value->setText("0"); label_stats_miss_value->setText("0"); label_stats_accuracy_value->setText("N/A"); } void DockPredictorInfo::clear_bhr() { if (number_of_bhr_bits > 0) { QString zero_padding; zero_padding.fill('0', number_of_bhr_bits); value_bhr->setText("0b" + zero_padding); } else { value_bhr->setText(""); } } void DockPredictorInfo::clear_predict_widget() { value_event_predict_instruction->setText(""); value_event_predict_address->setText(""); value_event_predict_index_btb->setText(""); value_event_predict_index_bht->setText(""); value_event_predict_result->setText(""); set_predict_widget_color(STYLESHEET_COLOR_DEFAULT); } void DockPredictorInfo::clear_update_widget() { value_event_update_instruction->setText(""); value_event_update_address->setText(""); value_event_update_index_btb->setText(""); value_event_update_index_bht->setText(""); value_event_update_result->setText(""); set_update_widget_color(STYLESHEET_COLOR_DEFAULT); } void DockPredictorInfo::clear() { clear_stats(); clear_bhr(); clear_predict_widget(); clear_update_widget(); } qtrvsim-0.9.8/src/gui/windows/predictor/predictor_info_dock.h000066400000000000000000000126221467752164200244750ustar00rootroot00000000000000#ifndef PREDICTOR_INFO_DOCK_H #define PREDICTOR_INFO_DOCK_H #include "common/polyfills/qt5/qtableview.h" #include "machine/machine.h" #include "machine/memory/address.h" #include "machine/predictor.h" #include "machine/predictor_types.h" #include "ui/hexlineedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define STYLESHEET_COLOR_DEFAULT "background: rgb(255,255,255);" #define STYLESHEET_COLOR_PREDICT "background: rgb(255,173,173);" #define STYLESHEET_COLOR_UPDATE "background: rgb(173,255,229);" #define Q_COLOR_DEFAULT QColor(255, 255, 255) #define Q_COLOR_PREDICT QColor(255, 173, 173) #define Q_COLOR_UPDATE QColor(173, 255, 229) class DockPredictorInfo : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: // Constructors & Destructor DockPredictorInfo(QWidget *parent); private: // Internal functions void set_predict_widget_color(QString color_stylesheet); void set_update_widget_color(QString color_stylesheet); public: // General functions void setup(const machine::BranchPredictor *branch_predictor, const machine::Core *core); public slots: void update_bhr(uint8_t number_of_bhr_bits, uint16_t register_value); void show_new_prediction( uint16_t btb_index, uint16_t bht_index, machine::PredictionInput input, machine::BranchResult result, machine::BranchType branch_type); void show_new_update( uint16_t btb_index, uint16_t bht_index, machine::PredictionFeedback feedback); void update_stats(machine::PredictionStatistics stats); void reset_colors(); void clear_stats(); void clear_bhr(); void clear_predict_widget(); void clear_update_widget(); void clear(); private: // Internal variables bool is_predictor_enabled{ false }; bool is_predictor_dynamic{ false }; uint8_t number_of_bhr_bits{ 0 }; machine::PredictorState initial_state{ machine::PredictorState::UNDEFINED }; QT_OWNED QGroupBox *content{ new QGroupBox() }; QT_OWNED QVBoxLayout *layout_main{ new QVBoxLayout() }; QT_OWNED QSpacerItem *vertical_spacer{ new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding) }; // Stats QT_OWNED QGridLayout *layout_stats{ new QGridLayout() }; QT_OWNED QLabel *label_stats_total_text{ new QLabel() }; QT_OWNED QLabel *label_stats_miss_text{ new QLabel() }; QT_OWNED QLabel *label_stats_accuracy_text{ new QLabel() }; QT_OWNED QLabel *label_stats_total_value{ new QLabel() }; QT_OWNED QLabel *label_stats_miss_value{ new QLabel() }; QT_OWNED QLabel *label_stats_accuracy_value{ new QLabel() }; // Prediction & Update QT_OWNED QHBoxLayout *layout_event{ new QHBoxLayout() }; // Prediction QT_OWNED QGroupBox *group_event_predict{ new QGroupBox() }; QT_OWNED QVBoxLayout *layout_event_predict{ new QVBoxLayout() }; QT_OWNED QHBoxLayout *layout_event_predict_index{ new QHBoxLayout() }; QT_OWNED QVBoxLayout *layout_event_predict_index_btb{ new QVBoxLayout() }; QT_OWNED QVBoxLayout *layout_event_predict_index_bht{ new QVBoxLayout() }; QT_OWNED QLabel *label_event_predict_header{ new QLabel() }; QT_OWNED QLabel *label_event_predict_instruction{ new QLabel() }; QT_OWNED QLabel *label_event_predict_address{ new QLabel() }; QT_OWNED QLabel *label_event_predict_index_btb{ new QLabel() }; QT_OWNED QLabel *label_event_predict_index_bht{ new QLabel() }; QT_OWNED QLabel *label_event_predict_result{ new QLabel() }; QT_OWNED QLineEdit *value_event_predict_instruction{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_predict_address{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_predict_index_btb{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_predict_index_bht{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_predict_result{ new QLineEdit() }; // Update QT_OWNED QGroupBox *group_event_update{ new QGroupBox() }; QT_OWNED QVBoxLayout *layout_event_update{ new QVBoxLayout() }; QT_OWNED QHBoxLayout *layout_event_update_index{ new QHBoxLayout() }; QT_OWNED QVBoxLayout *layout_event_update_index_btb{ new QVBoxLayout() }; QT_OWNED QVBoxLayout *layout_event_update_index_bht{ new QVBoxLayout() }; QT_OWNED QLabel *label_event_update_header{ new QLabel() }; QT_OWNED QLabel *label_event_update_instruction{ new QLabel() }; QT_OWNED QLabel *label_event_update_address{ new QLabel() }; QT_OWNED QLabel *label_event_update_index_btb{ new QLabel() }; QT_OWNED QLabel *label_event_update_index_bht{ new QLabel() }; QT_OWNED QLabel *label_event_update_result{ new QLabel() }; QT_OWNED QLineEdit *value_event_update_instruction{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_update_address{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_update_index_btb{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_update_index_bht{ new QLineEdit() }; QT_OWNED QLineEdit *value_event_update_result{ new QLineEdit() }; // BHR QT_OWNED QHBoxLayout *layout_bhr{ new QHBoxLayout() }; QT_OWNED QLabel *label_bhr{ new QLabel() }; QT_OWNED QLineEdit *value_bhr{ new QLineEdit() }; }; #endif // PREDICTOR_INFO_DOCK_Hqtrvsim-0.9.8/src/gui/windows/program/000077500000000000000000000000001467752164200177675ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/program/programdock.cpp000066400000000000000000000125321467752164200230060ustar00rootroot00000000000000#include "programdock.h" #include "helper/async_modal.h" #include "programmodel.h" #include "programtableview.h" #include "ui/hexlineedit.h" #include #include #include #include #include ProgramDock::ProgramDock(QWidget *parent, QSettings *settings) : Super(parent) { setObjectName("Program"); setWindowTitle("Program"); this->settings = settings; follow_source = (enum FollowSource)settings->value("ProgramViewFollowSource", FOLLOWSRC_FETCH).toInt(); for (auto &i : follow_addr) { i = machine::Address::null(); } auto *content = new QWidget(); auto *follow_inst = new QComboBox(); follow_inst->addItem("Follow none"); follow_inst->addItem("Follow fetch"); follow_inst->addItem("Follow decode"); follow_inst->addItem("Follow execute"); follow_inst->addItem("Follow memory"); follow_inst->addItem("Follow writeback"); follow_inst->setCurrentIndex((int)follow_source); auto *program_content = new ProgramTableView(nullptr, settings); // program_content->setSizePolicy(); auto *program_model = new ProgramModel(this); program_content->setModel(program_model); program_content->verticalHeader()->hide(); // program_content->setHorizontalHeader(program_model->); auto *go_edit = new HexLineEdit(nullptr, 8, 16, "0x"); auto *layout = new QVBoxLayout; layout->addWidget(follow_inst); layout->addWidget(program_content); layout->addWidget(go_edit); content->setLayout(layout); setWidget(content); connect(this, &ProgramDock::machine_setup, program_model, &ProgramModel::setup); connect( go_edit, &HexLineEdit::value_edit_finished, program_content, [program_content](uint32_t value) { program_content->go_to_address(machine::Address(value)); }); connect(program_content, &ProgramTableView::address_changed, go_edit, &HexLineEdit::set_value); connect(this, &ProgramDock::jump_to_pc, program_content, &ProgramTableView::go_to_address); connect( follow_inst, QOverload::of(&QComboBox::currentIndexChanged), this, &ProgramDock::set_follow_inst); connect(this, &ProgramDock::focus_addr, program_content, &ProgramTableView::focus_address); connect( this, &ProgramDock::focus_addr_with_save, program_content, &ProgramTableView::focus_address_with_save); connect( program_content, &QAbstractItemView::doubleClicked, program_model, &ProgramModel::toggle_hw_break); connect( this, &ProgramDock::stage_addr_changed, program_model, &ProgramModel::update_stage_addr); connect(program_model, &ProgramModel::report_error, this, &ProgramDock::report_error); connect(this, &ProgramDock::request_update_all, program_model, &ProgramModel::update_all); } void ProgramDock::setup(machine::Machine *machine) { machine::Address pc; emit machine_setup(machine); if (machine == nullptr) { return; } pc = machine->registers()->read_pc(); for (machine::Address &address : follow_addr) { address = pc; } update_follow_position(); } void ProgramDock::set_follow_inst(int follow) { follow_source = (enum FollowSource)follow; settings->setValue("ProgramViewFollowSource", (int)follow_source); update_follow_position(); } void ProgramDock::update_pipeline_addrs(const machine::CoreState &s) { const machine::Pipeline &p = s.pipeline; fetch_inst_addr(p.fetch.result.inst_addr); decode_inst_addr(p.decode.result.inst_addr); execute_inst_addr(p.execute.result.inst_addr); memory_inst_addr(p.memory.result.inst_addr); writeback_inst_addr(p.writeback.internal.inst_addr); } void ProgramDock::fetch_inst_addr(machine::Address addr) { if (addr != machine::STAGEADDR_NONE) { follow_addr[FOLLOWSRC_FETCH] = addr; } emit stage_addr_changed(ProgramModel::STAGEADDR_FETCH, addr); if (follow_source == FOLLOWSRC_FETCH) { update_follow_position(); } } void ProgramDock::decode_inst_addr(machine::Address addr) { if (addr != machine::STAGEADDR_NONE) { follow_addr[FOLLOWSRC_DECODE] = addr; } emit stage_addr_changed(ProgramModel::STAGEADDR_DECODE, addr); if (follow_source == FOLLOWSRC_DECODE) { update_follow_position(); } } void ProgramDock::execute_inst_addr(machine::Address addr) { if (addr != machine::STAGEADDR_NONE) { follow_addr[FOLLOWSRC_EXECUTE] = addr; } emit stage_addr_changed(ProgramModel::STAGEADDR_EXECUTE, addr); if (follow_source == FOLLOWSRC_EXECUTE) { update_follow_position(); } } void ProgramDock::memory_inst_addr(machine::Address addr) { if (addr != machine::STAGEADDR_NONE) { follow_addr[FOLLOWSRC_MEMORY] = addr; } emit stage_addr_changed(ProgramModel::STAGEADDR_MEMORY, addr); if (follow_source == FOLLOWSRC_MEMORY) { update_follow_position(); } } void ProgramDock::writeback_inst_addr(machine::Address addr) { if (addr != machine::STAGEADDR_NONE) { follow_addr[FOLLOWSRC_WRITEBACK] = addr; } emit stage_addr_changed(ProgramModel::STAGEADDR_WRITEBACK, addr); if (follow_source == FOLLOWSRC_WRITEBACK) { update_follow_position(); } } void ProgramDock::update_follow_position() { if (follow_source != FOLLOWSRC_NONE) { emit focus_addr(follow_addr[follow_source]); } } void ProgramDock::report_error(const QString &error) { showAsyncMessageBox(this, QMessageBox::Critical, "Simulator Error", error); } qtrvsim-0.9.8/src/gui/windows/program/programdock.h000066400000000000000000000027001467752164200224470ustar00rootroot00000000000000#ifndef PROGRAMDOCK_H #define PROGRAMDOCK_H #include "machine/machine.h" #include "windows/peripherals/peripheralsview.h" #include #include #include class ProgramDock : public QDockWidget { Q_OBJECT using Super = QDockWidget; public: ProgramDock(QWidget *parent, QSettings *settings); void setup(machine::Machine *machine); signals: void machine_setup(machine::Machine *machine); void jump_to_pc(machine::Address); void focus_addr(machine::Address); void focus_addr_with_save(machine::Address); void stage_addr_changed(uint stage, machine::Address addr); void request_update_all(); public slots: void set_follow_inst(int); void fetch_inst_addr(machine::Address addr); void decode_inst_addr(machine::Address addr); void execute_inst_addr(machine::Address addr); void memory_inst_addr(machine::Address addr); void writeback_inst_addr(machine::Address addr); void report_error(const QString &error); void update_pipeline_addrs(const machine::CoreState &p); private: enum FollowSource { FOLLOWSRC_NONE, FOLLOWSRC_FETCH, FOLLOWSRC_DECODE, FOLLOWSRC_EXECUTE, FOLLOWSRC_MEMORY, FOLLOWSRC_WRITEBACK, FOLLOWSRC_COUNT, }; void update_follow_position(); enum FollowSource follow_source; machine::Address follow_addr[FOLLOWSRC_COUNT] {}; QSettings *settings; }; #endif // PROGRAMDOCK_H qtrvsim-0.9.8/src/gui/windows/program/programmodel.cpp000066400000000000000000000206241467752164200231670ustar00rootroot00000000000000#include "programmodel.h" #include using ae = machine::AccessEffects; // For enum values, the type is obvious from context. ProgramModel::ProgramModel(QObject *parent) : Super(parent), data_font("Monospace") { index0_offset = machine::Address::null(); data_font.setStyleHint(QFont::TypeWriter); machine = nullptr; memory_change_counter = 0; cache_program_change_counter = 0; for (auto &i : stage_addr) { i = machine::STAGEADDR_NONE; } stages_need_update = false; } const machine::FrontendMemory *ProgramModel::mem_access() const { if (machine == nullptr) { return nullptr; } if (machine->memory_data_bus() != nullptr) { return machine->memory_data_bus(); } throw std::logic_error("Use of backend memory in frontend."); // TODO // return machine->memory(); } machine::FrontendMemory *ProgramModel::mem_access_rw() const { if (machine == nullptr) { return nullptr; } if (machine->memory_data_bus_rw() != nullptr) { return machine->memory_data_bus_rw(); } throw std::logic_error("Use of backend memory in frontend."); // TODO // return machine->memory_rw(); } int ProgramModel::rowCount(const QModelIndex & /*parent*/) const { return 750; } int ProgramModel::columnCount(const QModelIndex & /*parent*/) const { return 4; } QVariant ProgramModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { switch (section) { case 0: return tr("BP"); case 1: return tr("Address"); case 2: return tr("Code"); case 3: return tr("Instruction"); default: return tr(""); } } } return Super::headerData(section, orientation, role); } QVariant ProgramModel::data(const QModelIndex &index, int role) const { const machine::FrontendMemory *mem; if (role == Qt::DisplayRole || role == Qt::EditRole) { QString s, t; machine::Address address; if (!get_row_address(address, index.row())) { return QString(""); } if (index.column() == 1) { t = QString::number(address.get_raw(), 16); s.fill('0', 8 - t.count()); return "0x" + s + t; } mem = mem_access(); if (mem == nullptr) { return QString(" "); } machine::Instruction inst(mem->read_u32(address)); switch (index.column()) { case 0: if (machine->is_hwbreak(address)) { return QString("B"); } else { return QString(" "); } case 2: t = QString::number(inst.data(), 16); s.fill('0', 8 - t.count()); return s + t; case 3: return inst.to_str(address); default: return tr(""); } } if (role == Qt::BackgroundRole) { machine::Address address; if (!get_row_address(address, index.row()) || machine == nullptr) { return {}; } if (index.column() == 2 && machine->cache_program() != nullptr) { machine::LocationStatus loc_stat; loc_stat = machine->cache_program()->location_status(address); if (loc_stat & machine::LOCSTAT_CACHED) { QBrush bgd(Qt::lightGray); return bgd; } } else if (index.column() == 0 && machine->is_hwbreak(address)) { QBrush bgd(Qt::red); return bgd; } else if (index.column() == 3) { if (address == stage_addr[STAGEADDR_WRITEBACK]) { QBrush bgd(QColor(255, 173, 230)); return bgd; } else if (address == stage_addr[STAGEADDR_MEMORY]) { QBrush bgd(QColor(173, 255, 229)); return bgd; } else if (address == stage_addr[STAGEADDR_EXECUTE]) { QBrush bgd(QColor(193, 255, 173)); return bgd; } else if (address == stage_addr[STAGEADDR_DECODE]) { QBrush bgd(QColor(255, 212, 173)); return bgd; } else if (address == stage_addr[STAGEADDR_FETCH]) { QBrush bgd(QColor(255, 173, 173)); return bgd; } } return {}; } if (role == Qt::FontRole) { return data_font; } if (role == Qt::TextAlignmentRole) { if (index.column() == 0) { return Qt::AlignCenter; } return Qt::AlignLeft; } return {}; } void ProgramModel::setup(machine::Machine *machine) { this->machine = machine; for (auto &i : stage_addr) { i = machine::STAGEADDR_NONE; } if (machine != nullptr) { connect(machine, &machine::Machine::post_tick, this, &ProgramModel::check_for_updates); } if (mem_access() != nullptr) { connect( mem_access(), &machine::FrontendMemory::external_change_notify, this, &ProgramModel::check_for_updates); } emit update_all(); } void ProgramModel::update_all() { const machine::FrontendMemory *mem; mem = mem_access(); if (mem != nullptr) { memory_change_counter = mem->get_change_counter(); if (machine->cache_program() != nullptr) { cache_program_change_counter = machine->cache_program()->get_change_counter(); } } stages_need_update = false; emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } void ProgramModel::check_for_updates() { bool need_update = stages_need_update; const machine::FrontendMemory *mem; mem = mem_access(); if (mem == nullptr) { return; } if (memory_change_counter != mem->get_change_counter()) { need_update = true; } if (machine->cache_data() != nullptr) { if (cache_program_change_counter != machine->cache_program()->get_change_counter()) { need_update = true; } } if (!need_update) { return; } update_all(); } bool ProgramModel::adjustRowAndOffset(int &row, machine::Address address) { row = rowCount() / 2; address -= address.get_raw() % cellSizeBytes(); uint32_t row_bytes = cellSizeBytes(); uint32_t diff = row * row_bytes; if (diff > address.get_raw()) { row = address.get_raw() / row_bytes; if (row == 0) { index0_offset = machine::Address::null(); } else { index0_offset = address - row * row_bytes; } } else { index0_offset = address - diff; } return get_row_for_address(row, address); } void ProgramModel::toggle_hw_break(const QModelIndex &index) { machine::Address address; if (index.column() != 0 || machine == nullptr) { return; } if (!get_row_address(address, index.row())) { return; } if (machine->is_hwbreak(address)) { machine->remove_hwbreak(address); } else { machine->insert_hwbreak(address); } update_all(); } Qt::ItemFlags ProgramModel::flags(const QModelIndex &index) const { if (index.column() != 2 && index.column() != 3) { return QAbstractTableModel::flags(index); } else { return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; } } bool ProgramModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == Qt::EditRole) { bool ok; QString error; machine::Address address; uint32_t data; machine::FrontendMemory *mem; if (!get_row_address(address, index.row())) { return false; } if (index.column() == 0 || machine == nullptr) { return false; } mem = mem_access_rw(); if (mem == nullptr) { return false; } switch (index.column()) { case 2: data = value.toString().toULong(&ok, 16); if (!ok) { return false; } mem->write_u32(address, data, ae::INTERNAL); break; case 3: try { machine::Instruction::code_from_string(&data, 4, value.toString(), address); } catch (machine::Instruction::ParseError &e) { emit report_error(tr("instruction 1 parse error - %2.").arg(e.message)); return false; } mem->write_u32(address, data, ae::INTERNAL); break; default: return false; } } return true; } void ProgramModel::update_stage_addr(uint stage, machine::Address addr) { if (stage < STAGEADDR_COUNT) { if (stage_addr[stage] != addr) { stage_addr[stage] = addr; stages_need_update = true; } } } qtrvsim-0.9.8/src/gui/windows/program/programmodel.h000066400000000000000000000051621467752164200226340ustar00rootroot00000000000000#ifndef PROGRAMMODEL_H #define PROGRAMMODEL_H #include "machine/machine.h" #include #include class ProgramModel : public QAbstractTableModel { Q_OBJECT using Super = QAbstractTableModel; public: explicit ProgramModel(QObject *parent); [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int columnCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; [[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; bool adjustRowAndOffset(int &row, machine::Address address); [[nodiscard]] inline const QFont *getFont() const { return &data_font; } [[nodiscard]] inline machine::Address getIndex0Offset() const { return index0_offset; } [[nodiscard]] static inline unsigned int cellSizeBytes() { return 4; } inline bool get_row_address(machine::Address &address, int row) const { address = index0_offset + row * cellSizeBytes(); return address >= index0_offset; } inline bool get_row_for_address(int &row, machine::Address address) const { if (address < index0_offset) { row = -1; return false; } row = (address - index0_offset) / cellSizeBytes(); if (((address - index0_offset) > 0x80000000) || row > rowCount()) { row = rowCount(); return false; } return true; } enum StageAddress { STAGEADDR_FETCH, STAGEADDR_DECODE, STAGEADDR_EXECUTE, STAGEADDR_MEMORY, STAGEADDR_WRITEBACK, STAGEADDR_COUNT, }; signals: void report_error(QString error); public slots: void setup(machine::Machine *machine); void check_for_updates(); void toggle_hw_break(const QModelIndex &index); void update_stage_addr(uint stage, machine::Address addr); void update_all(); private: [[nodiscard]] const machine::FrontendMemory *mem_access() const; [[nodiscard]] machine::FrontendMemory *mem_access_rw() const; machine::Address index0_offset; QFont data_font; machine::Machine *machine; uint32_t memory_change_counter; uint32_t cache_program_change_counter; machine::Address stage_addr[STAGEADDR_COUNT] {}; bool stages_need_update; }; #endif // PROGRAMMODEL_H qtrvsim-0.9.8/src/gui/windows/program/programtableview.cpp000066400000000000000000000146501467752164200240530ustar00rootroot00000000000000#include "programtableview.h" #include "hinttabledelegate.h" #include "programmodel.h" #include #include #include #include #include #include ProgramTableView::ProgramTableView(QWidget *parent, QSettings *settings) : Super(parent) { setItemDelegate(new HintTableDelegate(this)); connect( verticalScrollBar(), &QAbstractSlider::valueChanged, this, &ProgramTableView::adjust_scroll_pos_check); connect( this, &ProgramTableView::adjust_scroll_pos_queue, this, &ProgramTableView::adjust_scroll_pos_process, Qt::QueuedConnection); this->settings = settings; initial_address = machine::Address(settings->value("ProgramViewAddr0", 0).toULongLong()); adjust_scroll_pos_in_progress = false; need_addr0_save = false; setTextElideMode(Qt::ElideNone); } void ProgramTableView::addr0_save_change(machine::Address val) { need_addr0_save = false; settings->setValue("ProgramViewAddr0", qint64(val.get_raw())); } void ProgramTableView::adjustColumnCount() { QModelIndex idx; auto *m = dynamic_cast(model()); if (m == nullptr) { return; } auto *delegate = dynamic_cast(itemDelegate()); if (delegate == nullptr) { return; } QStyleOptionViewItem viewOpts; initViewItemOption(&viewOpts); int totwidth = 0; idx = m->index(0, 0); auto cwidth_dh0 = delegate->sizeHintForText(viewOpts, idx, "BP").width() + 2; horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); horizontalHeader()->resizeSection(0, cwidth_dh0); totwidth += cwidth_dh0; idx = m->index(0, 1); auto cwidth_dh1 = delegate->sizeHintForText(viewOpts, idx, "0x00000000").width() + 2; horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed); horizontalHeader()->resizeSection(1, cwidth_dh1); totwidth += cwidth_dh1; idx = m->index(0, 2); auto cwidth_dh2 = delegate->sizeHintForText(viewOpts, idx, "00000000").width() + 2; horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); horizontalHeader()->resizeSection(2, cwidth_dh2); totwidth += cwidth_dh2; horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); idx = m->index(0, 3); totwidth += delegate->sizeHintForText(viewOpts, idx, "BEQ $18, $17, 0x00000258").width() + 2; totwidth += verticalHeader()->width(); setColumnHidden(2, totwidth > width()); setColumnHidden(1, totwidth - cwidth_dh2 > width()); setColumnHidden(0, totwidth - cwidth_dh2 - cwidth_dh1 > width()); if (!initial_address.is_null()) { go_to_address(initial_address); initial_address = machine::Address::null(); } } void ProgramTableView::adjust_scroll_pos_check() { if (!adjust_scroll_pos_in_progress) { adjust_scroll_pos_in_progress = true; emit adjust_scroll_pos_queue(); } } void ProgramTableView::adjust_scroll_pos_process() { adjust_scroll_pos_in_progress = false; machine::Address address; auto *m = dynamic_cast(model()); if (m == nullptr) { return; } QModelIndex prev_index = currentIndex(); auto row_bytes = machine::Address(ProgramModel::cellSizeBytes()); machine::Address index0_offset = m->getIndex0Offset(); do { int row = rowAt(0); int prev_row = row; if (row < m->rowCount() / 8) { if ((row == 0) && (index0_offset < row_bytes) && (!index0_offset.is_null())) { m->adjustRowAndOffset(row, machine::Address::null()); } else if (index0_offset >= row_bytes) { m->get_row_address(address, row); m->adjustRowAndOffset(row, address); } else { break; } } else if (row > m->rowCount() - m->rowCount() / 8) { m->get_row_address(address, row); m->adjustRowAndOffset(row, address); } else { break; } scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop); setCurrentIndex(m->index(prev_index.row() + row - prev_row, prev_index.column())); emit m->update_all(); } while (false); m->get_row_address(address, rowAt(0)); if (need_addr0_save) { addr0_save_change(address); } emit address_changed(address.get_raw()); } void ProgramTableView::resizeEvent(QResizeEvent *event) { auto *m = dynamic_cast(model()); machine::Address address; bool keep_row0 = false; if (m != nullptr) { if (initial_address.is_null()) { keep_row0 = m->get_row_address(address, rowAt(0)); } else { address = initial_address; } } Super::resizeEvent(event); adjustColumnCount(); if (keep_row0) { initial_address = machine::Address::null(); go_to_address(address); } } void ProgramTableView::go_to_address_priv(machine::Address address) { auto *m = dynamic_cast(model()); int row; if (m == nullptr) { return; } m->adjustRowAndOffset(row, address); scrollTo(m->index(row, 0), QAbstractItemView::PositionAtTop); setCurrentIndex(m->index(row, 1)); if (need_addr0_save) { addr0_save_change(address); } emit m->update_all(); } void ProgramTableView::go_to_address(machine::Address address) { need_addr0_save = true; go_to_address_priv(address); } void ProgramTableView::focus_address(machine::Address address) { int row; auto *m = dynamic_cast(model()); if (m == nullptr) { return; } if (!m->get_row_for_address(row, address)) { go_to_address_priv(address); } if (!m->get_row_for_address(row, address)) { return; } setCurrentIndex(m->index(row, 3)); } void ProgramTableView::focus_address_with_save(machine::Address address) { need_addr0_save = true; focus_address(address); } void ProgramTableView::keyPressEvent(QKeyEvent *event) { if (event->matches(QKeySequence::Copy)) { QString text; QItemSelectionRange range = selectionModel()->selection().first(); for (auto i = range.top(); i <= range.bottom(); ++i) { QStringList rowContents; for (auto j = range.left(); j <= range.right(); ++j) { rowContents << model()->index(i, j).data().toString(); } text += rowContents.join("\t"); text += "\n"; } QApplication::clipboard()->setText(text); } else { Super::keyPressEvent(event); } } qtrvsim-0.9.8/src/gui/windows/program/programtableview.h000066400000000000000000000021741467752164200235160ustar00rootroot00000000000000#ifndef PROGRAMTABLEVIEW_H #define PROGRAMTABLEVIEW_H #include "common/polyfills/qt5/qtableview.h" #include "machine/memory/address.h" #include #include #include class ProgramTableView : public Poly_QTableView { Q_OBJECT using Super = Poly_QTableView; public: ProgramTableView(QWidget *parent, QSettings *settings); void resizeEvent(QResizeEvent *event) override; signals: void address_changed(uint32_t address); void adjust_scroll_pos_queue(); public slots: void go_to_address(machine::Address address); void focus_address(machine::Address address); void focus_address_with_save(machine::Address address); protected: void keyPressEvent(QKeyEvent *event) override; private slots: void adjust_scroll_pos_check(); void adjust_scroll_pos_process(); private: void go_to_address_priv(machine::Address address); void addr0_save_change(machine::Address val); void adjustColumnCount(); QSettings *settings; machine::Address initial_address; bool adjust_scroll_pos_in_progress; bool need_addr0_save; }; #endif // PROGRAMTABLEVIEW_H qtrvsim-0.9.8/src/gui/windows/registers/000077500000000000000000000000001467752164200203275ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/registers/registersdock.cpp000066400000000000000000000075131467752164200237110ustar00rootroot00000000000000#include "registersdock.h" #include "machine/instruction.h" RegistersDock::RegistersDock(QWidget *parent, machine::Xlen xlen) : QDockWidget(parent) , xlen(xlen) , scroll_area(new QScrollArea(this)) , table_widget(new StaticTable(scroll_area.data())) , pal_normal(createPalette(QColor(0, 0, 0))) , pal_updated(createPalette(QColor(240, 0, 0))) , pal_read(createPalette(QColor(0, 0, 240))) { scroll_area->setWidgetResizable(true); gp_highlighted.reset(); for (size_t i = 0; i < gp.size(); i++) { gp[i] = addRegisterLabel(QString("x%1/%2").arg(i).arg(machine::Rv_regnames[i])); } pc = addRegisterLabel("pc"); scroll_area->setWidget(table_widget.data()); setWidget(scroll_area.data()); setObjectName("Registers"); setWindowTitle("Registers"); } const char *RegistersDock::sizeHintText() { if (xlen == machine::Xlen::_64) return "0x0000000000000000"; else return "0x00000000"; } QLabel *RegistersDock::addRegisterLabel(const QString &title) { auto *data_label = new QLabel(sizeHintText(), table_widget.data()); data_label->setFixedSize(data_label->sizeHint()); data_label->setText(""); data_label->setPalette(pal_normal); data_label->setTextInteractionFlags(Qt::TextSelectableByMouse); auto *title_label = new QLabel(title, table_widget.data()); title_label->setPalette(pal_normal); // Add row take ownership of the labels. table_widget->addRow({ OWNED title_label, OWNED data_label }); return BORROWED data_label; } void RegistersDock::connectToMachine(machine::Machine *machine) { if (machine == nullptr) { // Reset data pc->setText(""); for (auto &i : gp) { i->setText(""); } return; } const machine::Registers *regs = machine->registers(); // if xlen changes adjust space to show full value if (xlen != machine->config().get_simulated_xlen()) { xlen = machine->config().get_simulated_xlen(); auto *dumy_data_label = new QLabel(sizeHintText(), table_widget.data()); for (auto & i : gp) { i->setFixedSize(dumy_data_label->sizeHint()); } pc->setFixedSize(dumy_data_label->sizeHint()); delete dumy_data_label; } // Load values setRegisterValueToLabel(pc, regs->read_pc().get_raw()); for (size_t i = 0; i < gp.size(); i++) { setRegisterValueToLabel(gp[i], regs->read_gp(i)); } connect(regs, &machine::Registers::pc_update, this, &RegistersDock::pc_changed); connect(regs, &machine::Registers::gp_update, this, &RegistersDock::gp_changed); connect(regs, &machine::Registers::gp_read, this, &RegistersDock::gp_read); connect(machine, &machine::Machine::tick, this, &RegistersDock::clear_highlights); } void RegistersDock::pc_changed(machine::Address val) { setRegisterValueToLabel(pc, val.get_raw()); } void RegistersDock::gp_changed(machine::RegisterId i, machine::RegisterValue val) { setRegisterValueToLabel(gp[i], val); gp[i]->setPalette(pal_updated); gp_highlighted[i] = true; } void RegistersDock::gp_read(machine::RegisterId i, machine::RegisterValue val) { Q_UNUSED(val) if (!(gp_highlighted[i])) { gp[i]->setPalette(pal_read); gp_highlighted[i] = true; } } void RegistersDock::clear_highlights() { if (gp_highlighted.any()) { for (size_t i = 0; i < gp.size(); i++) { if (gp_highlighted[i]) { gp[i]->setPalette(pal_normal); } } } gp_highlighted.reset(); } void RegistersDock::setRegisterValueToLabel(QLabel *label, machine::RegisterValue value) { label->setText(QString("0x%1").arg(value.as_xlen(xlen), 0, 16)); } QPalette RegistersDock::createPalette(const QColor &color) const { QPalette palette = this->palette(); palette.setColor(QPalette::WindowText, color); return palette; } qtrvsim-0.9.8/src/gui/windows/registers/registersdock.h000066400000000000000000000024321467752164200233510ustar00rootroot00000000000000#ifndef REGISTERSDOCK_H #define REGISTERSDOCK_H #include "machine/machine.h" #include "statictable.h" #include #include #include #include #include using std::array; using std::bitset; /** * NOTE: RV64 ready */ class RegistersDock final : public QDockWidget { Q_OBJECT public: explicit RegistersDock(QWidget *parent, machine::Xlen xlen); void connectToMachine(machine::Machine *machine); private slots: void pc_changed(machine::Address val); void gp_changed(machine::RegisterId i, machine::RegisterValue val); void gp_read(machine::RegisterId i, machine::RegisterValue val); void clear_highlights(); private: machine::Xlen xlen; const char *sizeHintText(); Box scroll_area; Box table_widget; BORROWED QLabel *pc {}; array gp {}; bitset gp_highlighted { false }; QPalette pal_normal; QPalette pal_updated; QPalette pal_read; private: void setRegisterValueToLabel(QLabel *label, machine::RegisterValue value); BORROWED QLabel *addRegisterLabel(const QString &title); [[nodiscard]] QPalette createPalette(const QColor &color) const; }; #endif // REGISTERSDOCK_H qtrvsim-0.9.8/src/gui/windows/terminal/000077500000000000000000000000001467752164200201335ustar00rootroot00000000000000qtrvsim-0.9.8/src/gui/windows/terminal/terminaldock.cpp000066400000000000000000000043531467752164200233200ustar00rootroot00000000000000#include "terminaldock.h" #include "machine/memory/backend/serialport.h" #include #include #include TerminalDock::TerminalDock(QWidget *parent, QSettings *settings) : QDockWidget(parent) { (void)settings; top_widget = new QWidget(this); setWidget(top_widget); layout_box = new QVBoxLayout(top_widget); terminal_text = new QTextEdit(top_widget); terminal_text->setMinimumSize(30, 30); layout_box->addWidget(terminal_text); append_cursor.reset(new QTextCursor(terminal_text->document())); layout_bottom_box = new QHBoxLayout(); layout_bottom_box->addWidget(new QLabel("Input:")); input_edit = new QLineEdit(); layout_bottom_box->addWidget(input_edit); layout_box->addLayout(layout_bottom_box); // insert newline on enter (it will be displayed as space) connect(input_edit, &QLineEdit::returnPressed, [this]() { input_edit->setText(input_edit->text() + '\n'); }); setObjectName("Terminal"); setWindowTitle("Terminal"); } void TerminalDock::setup(machine::SerialPort *ser_port) { if (ser_port == nullptr) { return; } connect( ser_port, &machine::SerialPort::tx_byte, this, QOverload::of(&TerminalDock::tx_byte)); connect(ser_port, &machine::SerialPort::rx_byte_pool, this, &TerminalDock::rx_byte_pool); connect(input_edit, &QLineEdit::textChanged, ser_port, &machine::SerialPort::rx_queue_check); } void TerminalDock::tx_byte(unsigned int data) { bool at_end = terminal_text->textCursor().atEnd(); if (data == '\n') { append_cursor->insertBlock(); } else { append_cursor->insertText(QString(QChar(data))); } if (at_end) { QTextCursor cursor = QTextCursor(terminal_text->document()); cursor.movePosition(QTextCursor::End); terminal_text->setTextCursor(cursor); } } void TerminalDock::tx_byte(int fd, unsigned int data) { (void)fd; tx_byte(data); } void TerminalDock::rx_byte_pool(int fd, unsigned int &data, bool &available) { (void)fd; QString str = input_edit->text(); available = false; if (str.count() > 0) { data = str[0].toLatin1(); input_edit->setText(str.remove(0, 1)); available = true; } } qtrvsim-0.9.8/src/gui/windows/terminal/terminaldock.h000066400000000000000000000014541467752164200227640ustar00rootroot00000000000000#ifndef TERMINALDOCK_H #define TERMINALDOCK_H #include "machine/machine.h" #include #include #include #include #include #include class TerminalDock : public QDockWidget { Q_OBJECT public: TerminalDock(QWidget *parent, QSettings *settings); void setup(machine::SerialPort *ser_port); public slots: void tx_byte(unsigned int data); void tx_byte(int fd, unsigned int data); void rx_byte_pool(int fd, unsigned int &data, bool &available); private: QVBoxLayout *layout_box; QHBoxLayout *layout_bottom_box; QWidget *top_widget, *top_form {}; QFormLayout *layout_top_form {}; QTextEdit *terminal_text; Box append_cursor; QLineEdit *input_edit; }; #endif // TERMINALDOCK_H qtrvsim-0.9.8/src/machine/000077500000000000000000000000001467752164200154465ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/CMakeLists.txt000066400000000000000000000126071467752164200202140ustar00rootroot00000000000000project(machine DESCRIPTION "The actual simulator as a library. Link with an UI of your choice.") set(CMAKE_AUTOMOC ON) set(machine_SOURCES execute/alu.cpp csr/controlstate.cpp core.cpp instruction.cpp machine.cpp machineconfig.cpp memory/backend/lcddisplay.cpp memory/backend/memory.cpp memory/backend/peripheral.cpp memory/backend/peripspiled.cpp memory/backend/serialport.cpp memory/backend/aclintmtimer.cpp memory/backend/aclintmswi.cpp memory/backend/aclintsswi.cpp memory/cache/cache.cpp memory/cache/cache_policy.cpp memory/frontend_memory.cpp memory/memory_bus.cpp programloader.cpp predictor.cpp registers.cpp simulator_exception.cpp symboltable.cpp ) set(machine_HEADERS execute/alu.h csr/controlstate.h core.h core/core_state.h csr/address.h instruction.h machine.h machineconfig.h config_isa.h machinedefs.h memory/address.h memory/address_range.h memory/backend/backend_memory.h memory/backend/lcddisplay.h memory/backend/memory.h memory/backend/peripheral.h memory/backend/peripspiled.h memory/backend/serialport.h memory/backend/aclintmtimer.h memory/backend/aclintmswi.h memory/backend/aclintsswi.h memory/cache/cache.h memory/cache/cache_policy.h memory/cache/cache_types.h memory/frontend_memory.h memory/memory_bus.h memory/memory_utils.h programloader.h predictor_types.h predictor.h pipeline.h registers.h register_value.h simulator_exception.h symboltable.h utils.h execute/alu_op.h execute/mul_op.h ) # Object library is preferred, because the library archive is never really # needed. This option skips the archive creation and links directly .o files. add_library(machine STATIC ${machine_SOURCES} ${machine_HEADERS}) target_link_libraries(machine PRIVATE ${QtLib}::Core PUBLIC libelf) if(NOT ${WASM}) # Machine tests (not available on WASM) add_executable(alu_test execute/alu.test.cpp execute/alu.test.h execute/alu.cpp execute/alu.h ) target_link_libraries(alu_test PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME alu COMMAND alu_test) add_executable(registers_test register_value.h registers.cpp registers.h registers.test.cpp registers.test.h simulator_exception.cpp simulator_exception.h ) target_link_libraries(registers_test PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME registers COMMAND registers_test) add_executable(memory_test memory/backend/backend_memory.h memory/backend/memory.cpp memory/backend/memory.h memory/backend/memory.test.cpp memory/backend/memory.test.h memory/frontend_memory.cpp memory/frontend_memory.h memory/memory_bus.cpp memory/memory_bus.h simulator_exception.cpp simulator_exception.h tests/utils/integer_decomposition.h ) target_link_libraries(memory_test PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME memory COMMAND memory_test) add_executable(cache_test machineconfig.cpp machineconfig.h config_isa.h memory/backend/backend_memory.h memory/backend/memory.cpp memory/backend/memory.h memory/cache/cache.cpp memory/cache/cache.h memory/cache/cache.test.cpp memory/cache/cache.test.h memory/cache/cache_policy.cpp memory/cache/cache_policy.h memory/frontend_memory.cpp memory/frontend_memory.h memory/memory_bus.cpp memory/memory_bus.h simulator_exception.cpp simulator_exception.h tests/data/cache_test_performance_data.h tests/utils/integer_decomposition.h ) target_link_libraries(cache_test PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME cache COMMAND cache_test) add_executable(instruction_test csr/controlstate.cpp csr/controlstate.h instruction.cpp instruction.h instruction.test.cpp instruction.test.h simulator_exception.cpp simulator_exception.h ) target_link_libraries(instruction_test PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME instruction COMMAND instruction_test) add_executable(program_loader_test csr/controlstate.cpp csr/controlstate.h instruction.cpp instruction.h memory/backend/backend_memory.h memory/backend/memory.cpp memory/backend/memory.h programloader.cpp programloader.h programloader.test.cpp programloader.test.h simulator_exception.cpp simulator_exception.h symboltable.cpp symboltable.h ) target_link_libraries(program_loader_test PRIVATE ${QtLib}::Core ${QtLib}::Test libelf) add_test(NAME program_loader COMMAND program_loader_test) add_executable(core_test csr/controlstate.cpp csr/controlstate.h core.cpp core.h core.test.cpp core.test.h execute/alu.cpp execute/alu.h instruction.cpp instruction.h memory/backend/backend_memory.h memory/backend/memory.cpp memory/backend/memory.h memory/cache/cache.cpp memory/cache/cache.h memory/cache/cache_policy.cpp memory/cache/cache_policy.h memory/frontend_memory.cpp memory/frontend_memory.h memory/memory_bus.cpp memory/memory_bus.h registers.cpp registers.h predictor.cpp predictor.h predictor_types.h simulator_exception.cpp simulator_exception.h machineconfig.cpp ) target_link_libraries(core_test PRIVATE ${QtLib}::Core ${QtLib}::Test libelf) add_test(NAME core COMMAND core_test) add_custom_target(machine_unit_tests DEPENDS alu_test registers_test memory_test cache_test instruction_test program_loader_test core_test) endif() qtrvsim-0.9.8/src/machine/bitfield.h000066400000000000000000000031751467752164200174070ustar00rootroot00000000000000/** * Utility to parse and encode binary encoded fields. * * Use BitField if the field is guaranteed to be continuous. * Use SplitBitField if the field is not guaranteed to be continuous. * * @file */ #ifndef QTRVSIM_BITFIELD_H #define QTRVSIM_BITFIELD_H #include "common/containers/cvector.h" #include struct BitField { uint8_t count; uint8_t offset; template [[nodiscard]] T decode(T val) const { return (val >> offset) & (((uint64_t)1 << count) - 1); } template [[nodiscard]] T encode(T val) const { return ((val & (((uint64_t)1 << count) - 1)) << offset); } [[nodiscard]] uint64_t mask() const { return (((uint64_t)1 << count) - 1) << offset; } }; template struct SplitBitField { cvector fields; size_t shift = 0; [[nodiscard]] typename decltype(fields)::const_iterator begin() const { return fields.cbegin(); } [[nodiscard]] typename decltype(fields)::const_iterator end() const { return fields.cend(); } [[nodiscard]] uint32_t decode(uint32_t ins) const { uint32_t ret = 0; size_t offset = 0; for (BitField field : *this) { ret |= field.decode(ins) << offset; offset += field.count; } return ret << shift; } [[nodiscard]] uint32_t encode(uint32_t imm) const { uint32_t ret = 0; imm >>= shift; for (BitField field : *this) { ret |= field.encode(imm); imm >>= field.count; } return ret; } }; #endif // QTRVSIM_BITFIELD_H qtrvsim-0.9.8/src/machine/config_isa.h000066400000000000000000000045451467752164200177300ustar00rootroot00000000000000#ifndef MACHINE_CONFIG_ISA_H #define MACHINE_CONFIG_ISA_H #include #include namespace machine { struct ConfigIsaWord { constexpr ConfigIsaWord() : bits(0) {}; constexpr ConfigIsaWord(const quint64 &abits) : bits(abits) {}; constexpr ConfigIsaWord(const ConfigIsaWord &isaWord) = default; //> Copy constructor constexpr ConfigIsaWord &operator=(const ConfigIsaWord &isaWord) = default; //> Assign constructor constexpr static ConfigIsaWord empty() {return ConfigIsaWord(); }; constexpr ConfigIsaWord &operator&=(const ConfigIsaWord &isaWord) { bits &= isaWord.bits; return *this; } constexpr ConfigIsaWord &operator|=(const ConfigIsaWord &isaWord) { bits |= isaWord.bits; return *this; } constexpr ConfigIsaWord operator~() const { ConfigIsaWord ans(~bits); return ans; } friend constexpr ConfigIsaWord operator|(ConfigIsaWord lhs, const ConfigIsaWord& rhs) { lhs |= rhs; // reuse compound assignment return lhs; // return the result by value (uses move constructor) } friend constexpr ConfigIsaWord operator&(ConfigIsaWord lhs, const ConfigIsaWord& rhs) { lhs &= rhs; // reuse compound assignment return lhs; // return the result by value (uses move constructor) } constexpr friend bool operator==(const ConfigIsaWord& lhs, const ConfigIsaWord& rhs) { return lhs.bits == rhs.bits; } static constexpr ConfigIsaWord byChar(char ch) { if (ch >= 'A' && ch <= 'Z') ch -= 'A'; else if (ch >= 'a' && ch <= 'z') ch -= 'a'; else ch = 0; auto abits = static_cast(1) << ch; return ConfigIsaWord(abits); }; constexpr bool isEmpty() const { return bits == 0; }; constexpr bool contains(char ch) const { return !(*this & byChar(ch)).isEmpty(); }; constexpr bool contains(ConfigIsaWord &isaWord) const { return (*this & isaWord) == isaWord; }; ConfigIsaWord &modify(ConfigIsaWord &mask, ConfigIsaWord &val) { (*this) &= ~mask | val; (*this) |= mask & val; return *this; } constexpr auto toUnsigned() const { return bits; }; quint64 bits; }; } Q_DECLARE_METATYPE(machine::ConfigIsaWord) #endif // MACHINE_CONFIG_ISA_H qtrvsim-0.9.8/src/machine/core.cpp000066400000000000000000000713601467752164200171110ustar00rootroot00000000000000#include "core.h" #include "common/logging.h" #include "execute/alu.h" #include "utils.h" #include LOG_CATEGORY("machine.core"); using namespace machine; static InstructionFlags unsupported_inst_flags_to_check(Xlen xlen, ConfigIsaWord isa_word) { unsigned flags_to_check = IMF_SUPPORTED; if (xlen == Xlen::_32) flags_to_check |= IMF_RV64; if (!isa_word.contains('A')) flags_to_check |= IMF_AMO; if (!isa_word.contains('M')) flags_to_check |= IMF_MUL; return InstructionFlags(flags_to_check); } Core::Core( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word) : pc_if(state.pipeline.pc.final) , if_id(state.pipeline.fetch.final) , id_ex(state.pipeline.decode.final) , ex_mem(state.pipeline.execute.final) , mem_wb(state.pipeline.memory.final) , xlen(xlen) , check_inst_flags_val(IMF_SUPPORTED) , check_inst_flags_mask(unsupported_inst_flags_to_check(xlen, isa_word)) , regs(regs) , control_state(control_state) , predictor(predictor) , mem_data(mem_data) , mem_program(mem_program) , ex_handlers() , ex_default_handler(new StopExceptionHandler()) { stop_on_exception.fill(true); step_over_exception.fill(true); step_over_exception[EXCAUSE_INT] = false; } void Core::step(bool skip_break) { emit step_started(); state.cycle_count++; do_step(skip_break); emit step_done(state); } void Core::reset() { state.cycle_count = 0; state.stall_count = 0; do_reset(); } unsigned Core::get_cycle_count() const { return state.cycle_count; } unsigned Core::get_stall_count() const { return state.stall_count; } Registers *Core::get_regs() const { return regs; } CSR::ControlState *Core::get_control_state() const { return control_state; } FrontendMemory *Core::get_mem_data() const { return mem_data; } FrontendMemory *Core::get_mem_program() const { return mem_program; } BranchPredictor *Core::get_predictor() const { return predictor; } const CoreState &Core::get_state() const { return state; } void Core::insert_hwbreak(Address address) { hw_breaks.insert(address, new hwBreak(address)); } void Core::remove_hwbreak(Address address) { hwBreak *hwbrk = hw_breaks.take(address); delete hwbrk; } bool Core::is_hwbreak(Address address) const { hwBreak *hwbrk = hw_breaks.value(address); return hwbrk != nullptr; } void Core::set_stop_on_exception(enum ExceptionCause excause, bool value) { stop_on_exception[excause] = value; } bool Core::get_stop_on_exception(enum ExceptionCause excause) const { return stop_on_exception[excause]; } void Core::set_step_over_exception(enum ExceptionCause excause, bool value) { step_over_exception[excause] = value; } bool Core::get_step_over_exception(enum ExceptionCause excause) const { return step_over_exception[excause]; } Xlen Core::get_xlen() const { return xlen; } void Core::register_exception_handler(ExceptionCause excause, ExceptionHandler *exhandler) { if (excause == EXCAUSE_NONE) { ex_default_handler.reset(exhandler); } else { ExceptionHandler *old = ex_handlers.take(excause); delete old; ex_handlers.insert(excause, exhandler); } } bool Core::handle_exception( ExceptionCause excause, const Instruction& inst, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr) { if (excause == EXCAUSE_INSN_ILLEGAL) { throw SIMULATOR_EXCEPTION( UnsupportedInstruction, "Instruction with following encoding is not supported", QString::number(inst.data(), 16)); } if (excause == EXCAUSE_HWBREAK) { regs->write_pc(inst_addr); } if (control_state != nullptr) { control_state->write_internal(CSR::Id::MEPC, inst_addr.get_raw()); control_state->update_exception_cause(excause); if (control_state->read_internal(CSR::Id::MTVEC) != 0 && !get_step_over_exception(excause)) { control_state->exception_initiate(CSR::PrivilegeLevel::MACHINE, CSR::PrivilegeLevel::MACHINE); regs->write_pc(control_state->exception_pc_address()); } } bool ret = false; ExceptionHandler *exhandler = ex_handlers.value(excause, ex_default_handler.data()); if (exhandler != nullptr) { ret = exhandler->handle_exception( this, regs, excause, inst_addr, next_addr, jump_branch_pc, mem_ref_addr); } if (get_stop_on_exception(excause)) { emit stop_on_exception_reached(); } return ret; } static int32_t amo32_operations(enum AccessControl memctl, int32_t a, int32_t b) { switch(memctl) { case AC_AMOSWAP32: return b; case AC_AMOADD32: return a + b; case AC_AMOXOR32: return a ^ b; case AC_AMOAND32: return a & b; case AC_AMOOR32: return a | b; case AC_AMOMIN32: return a < b? a: b; case AC_AMOMAX32: return a < b? b: a; case AC_AMOMINU32: return (uint32_t)a < (uint32_t)b? a: b; case AC_AMOMAXU32: return (uint32_t)a < (uint32_t)b? b: a; default: break; } return 0; } static int64_t amo64_operations(enum AccessControl memctl, int64_t a, int64_t b) { switch(memctl) { case AC_AMOSWAP64: return b; case AC_AMOADD64: return a + b; case AC_AMOXOR64: return a ^ b; case AC_AMOAND64: return a & b; case AC_AMOOR64: return a | b; case AC_AMOMIN64: return a < b? a: b; case AC_AMOMAX64: return a < b? b: a; case AC_AMOMINU64: return (uint64_t)a < (uint64_t)b? a: b; case AC_AMOMAXU64: return (uint64_t)a < (uint64_t)b? b: a; default: break; } return 0; } enum ExceptionCause Core::memory_special( enum AccessControl memctl, int mode, bool memread, bool memwrite, RegisterValue &towrite_val, RegisterValue rt_value, Address mem_addr) { Q_UNUSED(mode) switch (memctl) { case AC_CACHE_OP: mem_data->sync(); mem_program->sync(); predictor->flush(); break; case AC_LR32: if (!memread) { break; } state.LoadReservedRange = AddressRange(mem_addr, mem_addr + 3); towrite_val = (int32_t)(mem_data->read_u32(mem_addr)); break; case AC_SC32: if (!memwrite) { break; } if (state.LoadReservedRange.contains(AddressRange(mem_addr, mem_addr + 3))) { mem_data->write_u32(mem_addr, rt_value.as_u32()); towrite_val = 0; } else { towrite_val = 1; } state.LoadReservedRange.reset(); break; case AC_LR64: if (!memread) { break; } state.LoadReservedRange = AddressRange(mem_addr, mem_addr + 7); towrite_val = mem_data->read_u64(mem_addr); break; case AC_SC64: if (!memwrite) { break; } if (state.LoadReservedRange.contains(AddressRange(mem_addr, mem_addr + 7))) { mem_data->write_u64(mem_addr, rt_value.as_u64()); towrite_val = 0; } else { towrite_val = 1; } break; case AC_FISRT_AMO_MODIFY32 ... AC_LAST_AMO_MODIFY32: { if (!memread || !memwrite) { break; } int32_t fetched_value; fetched_value = (int32_t)(mem_data->read_u32(mem_addr)); towrite_val = amo32_operations(memctl, fetched_value, rt_value.as_u32()); mem_data->write_u32(mem_addr, towrite_val.as_u32()); towrite_val = fetched_value; break; } case AC_FISRT_AMO_MODIFY64 ... AC_LAST_AMO_MODIFY64: { if (!memread || !memwrite) { break; } int64_t fetched_value; fetched_value = (int64_t)(mem_data->read_u64(mem_addr)); towrite_val = (uint64_t)amo64_operations(memctl, fetched_value, rt_value.as_u64()); mem_data->write_u64(mem_addr, towrite_val.as_u64()); towrite_val = fetched_value; break; } default: break; } return EXCAUSE_NONE; } FetchState Core::fetch(PCInterstage pc, bool skip_break) { if (pc.stop_if) { return {}; } const Address inst_addr = Address(regs->read_pc()); const Instruction inst(mem_program->read_u32(inst_addr)); ExceptionCause excause = EXCAUSE_NONE; if (!skip_break && hw_breaks.contains(inst_addr)) { excause = EXCAUSE_HWBREAK; } if (control_state != nullptr) { control_state->increment_internal(CSR::Id::MCYCLE, 1); } if (control_state != nullptr && excause == EXCAUSE_NONE) { if (control_state->core_interrupt_request()) { excause = EXCAUSE_INT; } } return { FetchInternalState { .fetched_value = inst.data() }, FetchInterstage { .inst = inst, .inst_addr = inst_addr, .next_inst_addr = inst_addr + inst.size(), .predicted_next_inst_addr = predictor->predict_next_pc_address(inst, inst_addr), .excause = excause, .is_valid = true, } }; } DecodeState Core::decode(const FetchInterstage &dt) { InstructionFlags flags; bool w_operation = this->xlen != Xlen::_64; AluCombinedOp alu_op {}; AccessControl mem_ctl; ExceptionCause excause = dt.excause; dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl); if ((flags ^ check_inst_flags_val) & check_inst_flags_mask) { excause = EXCAUSE_INSN_ILLEGAL; } RegisterId num_rs = (flags & (IMF_ALU_REQ_RS | IMF_ALU_RS_ID)) ? dt.inst.rs() : 0; RegisterId num_rt = (flags & IMF_ALU_REQ_RT) ? dt.inst.rt() : 0; RegisterId num_rd = (flags & IMF_REGWRITE) ? dt.inst.rd() : 0; // When instruction does not specify register, it is set to x0 as operations on x0 have no // side effects (not even visualization). RegisterValue val_rs = (flags & IMF_ALU_RS_ID) ? uint64_t(size_t(num_rs)) : regs->read_gp(num_rs); RegisterValue val_rt = regs->read_gp(num_rt); RegisterValue immediate_val = dt.inst.immediate(); const bool regwrite = flags & IMF_REGWRITE; CSR::Address csr_address = (flags & IMF_CSR) ? dt.inst.csr_address() : CSR::Address(0); RegisterValue csr_read_val = ((control_state != nullptr && (flags & IMF_CSR))) ? control_state->read(csr_address) : 0; bool csr_write = (flags & IMF_CSR) && (!(flags & IMF_CSR_TO_ALU) || (num_rs != 0)); if ((flags & IMF_EXCEPTION) && (excause == EXCAUSE_NONE)) { if (flags & IMF_EBREAK) { excause = EXCAUSE_BREAK; } else if (flags & IMF_ECALL) { excause = EXCAUSE_ECALL_M; // TODO: EXCAUSE_ECALL_S, EXCAUSE_ECALL_U } } if (flags & IMF_FORCE_W_OP) w_operation = true; return { DecodeInternalState { .alu_op_num = static_cast(alu_op.alu_op), .excause_num = static_cast(excause), .inst_bus = dt.inst.data(), .alu_mul = bool(flags & IMF_MUL), }, DecodeInterstage { .inst = dt.inst, .inst_addr = dt.inst_addr, .next_inst_addr = dt.next_inst_addr, .predicted_next_inst_addr = dt.predicted_next_inst_addr, .val_rs = val_rs, .val_rs_orig = val_rs, .val_rt = val_rt, .val_rt_orig = val_rt, .immediate_val = immediate_val, .csr_read_val = csr_read_val, .csr_address = csr_address, .excause = excause, .ff_rs = FORWARD_NONE, .ff_rt = FORWARD_NONE, .alu_component = (flags & IMF_AMO) ? AluComponent::PASS : (flags & IMF_MUL) ? AluComponent::MUL : AluComponent::ALU, .aluop = alu_op, .memctl = mem_ctl, .num_rs = num_rs, .num_rt = num_rt, .num_rd = num_rd, .memread = bool(flags & IMF_MEMREAD), .memwrite = bool(flags & IMF_MEMWRITE), .alusrc = bool(flags & IMF_ALUSRC), .regwrite = regwrite, .alu_req_rs = bool(flags & IMF_ALU_REQ_RS), .alu_req_rt = bool(flags & IMF_ALU_REQ_RT), .branch_bxx = bool(flags & IMF_BRANCH), .branch_jal = bool(flags & IMF_JUMP), .branch_val = bool(flags & IMF_BJ_NOT), .branch_jalr = bool(flags & IMF_BRANCH_JALR), .stall = false, .is_valid = dt.is_valid, .w_operation = w_operation, .alu_mod = bool(flags & IMF_ALU_MOD), .alu_pc = bool(flags & IMF_PC_TO_ALU), .csr = bool(flags & IMF_CSR), .csr_to_alu = bool(flags & IMF_CSR_TO_ALU), .csr_write = csr_write, .xret = bool(flags & IMF_XRET), .insert_stall_before = bool(flags & IMF_CSR) } }; } ExecuteState Core::execute(const DecodeInterstage &dt) { enum ExceptionCause excause = dt.excause; // TODO refactor to produce multiplexor index and multiplex function const RegisterValue alu_fst = [=] { if (dt.alu_pc) return RegisterValue(dt.inst_addr.get_raw()); return dt.val_rs; }(); const RegisterValue alu_sec = [=] { if (dt.csr_to_alu) return dt.csr_read_val; if (dt.alusrc) return dt.immediate_val; return dt.val_rt; }(); const RegisterValue alu_val = [=] { if (excause != EXCAUSE_NONE) return RegisterValue(0); return alu_combined_operate(dt.aluop, dt.alu_component, dt.w_operation, dt.alu_mod, alu_fst, alu_sec); }(); const Address branch_jal_target = dt.inst_addr + dt.immediate_val.as_i64(); const unsigned stall_status = [=] { if (dt.stall) return 1; if (dt.ff_rs != FORWARD_NONE || dt.ff_rt != FORWARD_NONE) return 2; return 0; }(); return { ExecuteInternalState { .alu_src1 = dt.val_rs, .alu_src2 = alu_sec, .immediate = dt.immediate_val, .rs = dt.val_rs_orig, .rt = dt.val_rt_orig, .stall_status = stall_status, .alu_op_num = static_cast(dt.aluop.alu_op), .forward_from_rs1_num = static_cast(dt.ff_rs), .forward_from_rs2_num = static_cast(dt.ff_rt), .excause_num = static_cast(dt.excause), .alu_src = dt.alusrc, .alu_mul = dt.alu_component == AluComponent::MUL, .branch_bxx = dt.branch_bxx, .alu_pc = dt.alu_pc, }, ExecuteInterstage { .inst = dt.inst, .inst_addr = dt.inst_addr, .next_inst_addr = dt.next_inst_addr, .predicted_next_inst_addr = dt.predicted_next_inst_addr, .branch_jal_target = branch_jal_target, .val_rt = dt.val_rt, .alu_val = alu_val, .immediate_val = dt.immediate_val, .csr_read_val = dt.csr_read_val, .csr_address = dt.csr_address, .excause = excause, .memctl = dt.memctl, .num_rd = dt.num_rd, .memread = dt.memread, .memwrite = dt.memwrite, .regwrite = dt.regwrite, .is_valid = dt.is_valid, .branch_bxx = dt.branch_bxx, .branch_jal = dt.branch_jal, .branch_val = dt.branch_val, .branch_jalr = dt.branch_jalr, .alu_zero = alu_val == 0, .csr = dt.csr, .csr_write = dt.csr_write, .xret = dt.xret, } }; } MemoryState Core::memory(const ExecuteInterstage &dt) { RegisterValue towrite_val = dt.alu_val; auto mem_addr = Address(get_xlen_from_reg(dt.alu_val)); bool memread = dt.memread; bool memwrite = dt.memwrite; bool regwrite = dt.regwrite; Address computed_next_inst_addr; enum ExceptionCause excause = dt.excause; if (excause == EXCAUSE_NONE) { if (is_special_access(dt.memctl)) { excause = memory_special( dt.memctl, dt.inst.rt(), memread, memwrite, towrite_val, dt.val_rt, mem_addr); } else if (is_regular_access(dt.memctl)) { if (memwrite) { mem_data->write_ctl(dt.memctl, mem_addr, dt.val_rt); } if (memread) { towrite_val = mem_data->read_ctl(dt.memctl, mem_addr); } } else { Q_ASSERT(dt.memctl == AC_NONE); // AC_NONE is memory NOP } } if (dt.excause != EXCAUSE_NONE) { memread = false; memwrite = false; regwrite = false; } // Conditional branch (BXX = BEQ | BNE...) is executed and should be taken. const bool branch_bxx_taken = dt.branch_bxx && (!dt.branch_val ^ !dt.alu_zero); // Unconditional jump should be taken (JALX = JAL | JALR). const bool branch_jalx = dt.branch_jalr || dt.branch_jal; computed_next_inst_addr = compute_next_inst_addr(dt, branch_bxx_taken); // Predictor update if (dt.branch_jal) { // JAL Jump instruction (J-type (alternative to U-type with different immediate bit order)) predictor->update(dt.inst, dt.inst_addr, dt.branch_jal_target, BranchType::JUMP, BranchResult::TAKEN); } else if (dt.branch_jalr) { // JALR Jump register instruction (I-type) predictor->update( dt.inst, dt.inst_addr, Address(get_xlen_from_reg(dt.alu_val)), BranchType::JUMP, BranchResult::TAKEN); } else if (dt.branch_bxx) { // BXX Conditional branch instruction (B-type (alternative to S-type with different // immediate bit order)) predictor->update( dt.inst, dt.inst_addr, dt.branch_jal_target, BranchType::BRANCH, branch_bxx_taken ? BranchResult::TAKEN : BranchResult::NOT_TAKEN); } bool csr_written = false; if (control_state != nullptr && dt.is_valid && dt.excause == EXCAUSE_NONE) { control_state->increment_internal(CSR::Id::MINSTRET, 1); if (dt.csr_write) { control_state->write(dt.csr_address, dt.alu_val); csr_written = true; } if (dt.xret) { control_state->exception_return(CSR::PrivilegeLevel::MACHINE); if (this->xlen == Xlen::_32) computed_next_inst_addr = Address(control_state->read_internal(CSR::Id::MEPC).as_u32()); else computed_next_inst_addr = Address(control_state->read_internal(CSR::Id::MEPC).as_u64()); csr_written = true; } } // Predictor statistics update if (computed_next_inst_addr != dt.predicted_next_inst_addr) { predictor->increment_mispredictions(); } return { MemoryInternalState { .mem_read_val = towrite_val, .mem_write_val = dt.val_rt, .mem_addr = dt.alu_val, .excause_num = static_cast(excause), .memwrite = memwrite, .memread = memread, .branch_bxx = dt.branch_bxx, .branch_jal = dt.branch_jal, // PC should be modified by branch/jump instruction. .branch_outcome = branch_bxx_taken || branch_jalx, .branch_jalx = branch_jalx, .branch_jalr = dt.branch_jalr, .xret = dt.xret, }, MemoryInterstage { .inst = dt.inst, .inst_addr = dt.inst_addr, .next_inst_addr = dt.next_inst_addr, .predicted_next_inst_addr = dt.predicted_next_inst_addr, .computed_next_inst_addr = computed_next_inst_addr, .mem_addr = mem_addr, .towrite_val = [=]() -> RegisterValue { if (dt.csr) return dt.csr_read_val; if (dt.branch_jalr || dt.branch_jal) return dt.next_inst_addr.get_raw(); return towrite_val; }(), .excause = dt.excause, .num_rd = dt.num_rd, .memtoreg = memread, .regwrite = regwrite, .is_valid = dt.is_valid, .csr_written = csr_written, } }; } WritebackState Core::writeback(const MemoryInterstage &dt) { if (dt.regwrite) { regs->write_gp(dt.num_rd, dt.towrite_val); } return WritebackState { WritebackInternalState { .inst = (dt.excause == EXCAUSE_NONE)? dt.inst: Instruction::NOP, .inst_addr = dt.inst_addr, .value = dt.towrite_val, .num_rd = dt.num_rd, .regwrite = dt.regwrite, .memtoreg = dt.memtoreg, } }; } Address Core::compute_next_inst_addr(const ExecuteInterstage &exec, bool branch_taken) const { if (branch_taken || exec.branch_jal) { return exec.branch_jal_target; } if (exec.branch_jalr) { return Address(get_xlen_from_reg(exec.alu_val)); } return exec.next_inst_addr; } uint64_t Core::get_xlen_from_reg(RegisterValue reg) const { switch (this->xlen) { case Xlen::_32: return reg.as_u32(); case Xlen::_64: return reg.as_u64(); default: UNREACHABLE } } CoreSingle::CoreSingle( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word) : Core(regs, predictor, mem_program, mem_data, control_state, xlen, isa_word) { reset(); } void CoreSingle::do_step(bool skip_break) { Pipeline &p = state.pipeline; p.fetch = fetch(pc_if, skip_break); p.decode = decode(p.fetch.final); p.execute = execute(p.decode.final); p.memory = memory(p.execute.final); p.writeback = writeback(p.memory.final); regs->write_pc(mem_wb.computed_next_inst_addr); if (mem_wb.excause != EXCAUSE_NONE) { handle_exception( mem_wb.excause, mem_wb.inst, mem_wb.inst_addr, regs->read_pc(), prev_inst_addr, mem_wb.mem_addr); return; } prev_inst_addr = mem_wb.inst_addr; } void CoreSingle::do_reset() { state.pipeline = {}; prev_inst_addr = Address::null(); } CorePipelined::CorePipelined( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word, MachineConfig::HazardUnit hazard_unit) : Core(regs, predictor, mem_program, mem_data, control_state, xlen, isa_word) { this->hazard_unit = hazard_unit; reset(); } void CorePipelined::do_step(bool skip_break) { Pipeline &p = state.pipeline; const Address jump_branch_pc = mem_wb.inst_addr; const FetchInterstage saved_if_id = if_id; p.writeback = writeback(mem_wb); p.memory = memory(ex_mem); p.execute = execute(id_ex); p.decode = decode(if_id); p.fetch = fetch(pc_if, skip_break); bool exception_in_progress = mem_wb.excause != EXCAUSE_NONE; if (exception_in_progress) { ex_mem.flush(); } exception_in_progress |= ex_mem.excause != EXCAUSE_NONE; if (exception_in_progress) { id_ex.flush(); } exception_in_progress |= id_ex.excause != EXCAUSE_NONE; if (exception_in_progress) { if_id.flush(); } bool stall = false; if (hazard_unit != MachineConfig::HU_NONE) { stall |= handle_data_hazards(); } /* PC and exception pseudo stage * ============================== */ pc_if = {}; if (mem_wb.excause != EXCAUSE_NONE) { /* By default, execution continues with the next instruction after exception. */ regs->write_pc(mem_wb.computed_next_inst_addr); /* Exception handler may override this behavior and change the PC (e.g. hwbreak). */ handle_exception( mem_wb.excause, mem_wb.inst, mem_wb.inst_addr, mem_wb.computed_next_inst_addr, jump_branch_pc, mem_wb.mem_addr); } else if (detect_mispredicted_jump() || mem_wb.csr_written) { /* If the jump was predicted incorrectly or csr register was written, we need to flush the * pipeline. */ flush_and_continue_from_address(mem_wb.computed_next_inst_addr); } else if (exception_in_progress) { /* An exception is in progress which caused the pipeline before the exception to be flushed. * Therefore, next pc cannot be determined from if_id (now NOP). * To make the visualization cleaner we stop fetching (and PC update) until the exception * is handled. */ pc_if.stop_if = true; } else if (stall || is_stall_requested()) { /* Fetch from the same PC is repeated due to stall in the pipeline. */ handle_stall(saved_if_id); } else { /* Normal execution. */ regs->write_pc(if_id.predicted_next_inst_addr); } } void CorePipelined::flush_and_continue_from_address(Address next_pc) { regs->write_pc(next_pc); if_id.flush(); id_ex.flush(); ex_mem.flush(); } void CorePipelined::handle_stall(const FetchInterstage &saved_if_id) { /* * Stall handing: * - IF fetches new instruction, but it is not allowed to save into IF/ID register. This is * simulated by restoring the `if_id` to its original value. * - ID continues normally. On next cycle, perform the same as before as IF/ID will be * unchanged. * - EX is where stall is inserted by flush. The flushed instruction will be re-executed * as ID repeats its execution. */ if_id = saved_if_id; id_ex.flush(); id_ex.stall = true; // for visualization state.stall_count++; } bool CorePipelined::detect_mispredicted_jump() const { return mem_wb.computed_next_inst_addr != mem_wb.predicted_next_inst_addr; } bool CorePipelined::is_stall_requested() const { return id_ex.insert_stall_before && ex_mem.is_valid; } template bool is_hazard_in_stage(const InterstageReg &interstage, const DecodeInterstage &id_ex) { return ( interstage.regwrite && interstage.num_rd != 0 && ((id_ex.alu_req_rs && interstage.num_rd == id_ex.num_rs) || (id_ex.alu_req_rt && interstage.num_rd == id_ex.num_rt))); // Note: We make exception with $0 as that has no effect and is used in nop instruction } bool CorePipelined::handle_data_hazards() { // Note: We make exception with $0 as that has no effect when // written and is used in nop instruction bool stall = false; if (is_hazard_in_stage(mem_wb, id_ex)) { if (hazard_unit == MachineConfig::HU_STALL_FORWARD) { // Forward result value if (id_ex.alu_req_rs && mem_wb.num_rd == id_ex.num_rs) { id_ex.val_rs = mem_wb.towrite_val; id_ex.ff_rs = FORWARD_FROM_W; } if (id_ex.alu_req_rt && mem_wb.num_rd == id_ex.num_rt) { id_ex.val_rt = mem_wb.towrite_val; id_ex.ff_rt = FORWARD_FROM_W; } } else { stall = true; } } if (is_hazard_in_stage(ex_mem, id_ex)) { if (hazard_unit == MachineConfig::HU_STALL_FORWARD) { if (ex_mem.memread) { stall = true; } else { // Forward result value if (id_ex.alu_req_rs && ex_mem.num_rd == id_ex.num_rs) { id_ex.val_rs = ex_mem.alu_val; id_ex.ff_rs = FORWARD_FROM_M; } if (id_ex.alu_req_rt && ex_mem.num_rd == id_ex.num_rt) { id_ex.val_rt = ex_mem.alu_val; id_ex.ff_rt = FORWARD_FROM_M; } } } else { stall = true; } } return stall; } void CorePipelined::do_reset() { state.pipeline = {}; } bool StopExceptionHandler::handle_exception( Core *core, Registers *regs, ExceptionCause excause, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr) { Q_UNUSED(core) DEBUG( "Exception cause %d instruction PC 0x%08" PRIx64 " next PC 0x%08" PRIx64 " jump branch PC 0x%08" PRIx64 "registers PC 0x%08" PRIx64 " mem ref 0x%08" PRIx64, excause, inst_addr.get_raw(), next_addr.get_raw(), jump_branch_pc.get_raw(), regs->read_pc().get_raw(), mem_ref_addr.get_raw()); return true; } qtrvsim-0.9.8/src/machine/core.h000066400000000000000000000167331467752164200165610ustar00rootroot00000000000000#ifndef CORE_H #define CORE_H #include "common/memory_ownership.h" #include "core/core_state.h" #include "csr/controlstate.h" #include "instruction.h" #include "machineconfig.h" #include "memory/address.h" #include "memory/frontend_memory.h" #include "pipeline.h" #include "predictor.h" #include "register_value.h" #include "registers.h" #include "simulator_exception.h" #include namespace machine { using std::array; class ExceptionHandler; class StopExceptionHandler; struct hwBreak; class Core : public QObject { Q_OBJECT public: Core( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word); void step(bool skip_break = false); void reset(); // Reset core (only core, memory and registers has to be reset separately). unsigned get_cycle_count() const; unsigned get_stall_count() const; Registers *get_regs() const; CSR::ControlState *get_control_state() const; BranchPredictor *get_predictor() const; FrontendMemory *get_mem_data() const; FrontendMemory *get_mem_program() const; const CoreState &get_state() const; Xlen get_xlen() const; void insert_hwbreak(Address address); void remove_hwbreak(Address address); bool is_hwbreak(Address address) const; void register_exception_handler(ExceptionCause excause, ExceptionHandler *exhandler); void set_stop_on_exception(enum ExceptionCause excause, bool value); bool get_stop_on_exception(enum ExceptionCause excause) const; void set_step_over_exception(enum ExceptionCause excause, bool value); bool get_step_over_exception(enum ExceptionCause excause) const; /** * Abstracts XLEN from code flow. XLEN core will obtain XLEN value from register value. * The value will be zero extended to u64. */ uint64_t get_xlen_from_reg(RegisterValue reg) const; protected: CoreState state {}; /** * Shortcuts to interstage registers * Interstage registers are stored in the core state struct in 2 copies. One (result) is the * state after combinatorial logic of each stage has been applied. This is used to visualize * the internal state of a stage. The should be modified ONLY by the stage logic functions. The * other (final) is the one actually written to HW interstage register. Any operation within * core should happen on the final registers. * * The bellow references provide shortcuts to the final interstage registers. */ /** Reference to pseudo interstage register PC/IF inside core state. */ PCInterstage &pc_if; /** Reference to interstage register IF/ID inside core state. */ FetchInterstage &if_id; /** Reference to interstage register ID/EX inside core state. */ DecodeInterstage &id_ex; /** Reference to interstage register EX/MEM inside core state. */ ExecuteInterstage &ex_mem; /** Reference to interstage register MEM/WB inside core state. */ MemoryInterstage &mem_wb; signals: void stop_on_exception_reached(); void step_started(); void step_done(const CoreState &); protected: virtual void do_step(bool skip_break) = 0; virtual void do_reset() = 0; bool handle_exception( ExceptionCause excause, const Instruction &inst, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr); const Xlen xlen; const InstructionFlags check_inst_flags_val; const InstructionFlags check_inst_flags_mask; BORROWED Registers *const regs; BORROWED CSR::ControlState *const control_state; BORROWED BranchPredictor *const predictor; BORROWED FrontendMemory *const mem_data, *const mem_program; array stop_on_exception {}; array step_over_exception {}; QMap hw_breaks {}; QMap ex_handlers; Box ex_default_handler; FetchState fetch(PCInterstage pc, bool skip_break); DecodeState decode(const FetchInterstage &); static ExecuteState execute(const DecodeInterstage &); MemoryState memory(const ExecuteInterstage &); WritebackState writeback(const MemoryInterstage &); /** * This function computes the address, the next executed instruction should be on. The word * `computed` is used in contrast with predicted value by the branch predictor. */ Address compute_next_inst_addr(const ExecuteInterstage &exec, bool branch_taken) const; enum ExceptionCause memory_special( enum AccessControl memctl, int mode, bool memread, bool memwrite, RegisterValue &towrite_val, RegisterValue rt_value, Address mem_addr); }; class CoreSingle : public Core { public: CoreSingle( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word); protected: void do_step(bool skip_break) override; void do_reset() override; private: Address prev_inst_addr {}; }; class CorePipelined : public Core { public: CorePipelined( Registers *regs, BranchPredictor *predictor, FrontendMemory *mem_program, FrontendMemory *mem_data, CSR::ControlState *control_state, Xlen xlen, ConfigIsaWord isa_word, // Default value is used to keep same interface as core single. // Forward was chosen as the most conservative variant (regarding correctness). MachineConfig::HazardUnit hazard_unit = MachineConfig::HazardUnit::HU_STALL_FORWARD); protected: void do_step(bool skip_break) override; void do_reset() override; private: MachineConfig::HazardUnit hazard_unit; bool handle_data_hazards(); bool detect_mispredicted_jump() const; /** Some special instruction require that all issued instructions are committed before this * instruction is fetched and issued as it may rely on side-effects of uncommitted instructions. * Typical examples are csr modifying instructions. */ bool is_stall_requested() const; void handle_stall(const FetchInterstage &saved_if_id); /** * Typically, problem in execution is discovered in memory stage. This function flushed all * stages containing instructions, that would not execute in a single cycle CPU and continues * execution from given address. * * @param next_pc address to continue execution from */ void flush_and_continue_from_address(Address next_pc); }; class ExceptionHandler : public QObject { Q_OBJECT public: virtual bool handle_exception( Core *core, Registers *regs, ExceptionCause excause, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr) = 0; }; class StopExceptionHandler : public ExceptionHandler { Q_OBJECT public: bool handle_exception( Core *core, Registers *regs, ExceptionCause excause, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr) override; }; struct hwBreak { explicit hwBreak(Address addr) : addr(addr), flags(0), count(0) {}; Address addr; unsigned int flags; unsigned int count; }; } // namespace machine #endif // CORE_H qtrvsim-0.9.8/src/machine/core.test.cpp000066400000000000000000001303231467752164200200620ustar00rootroot00000000000000#include "core.test.h" #include "machine/core.h" #include "machine/machineconfig.h" #include "machine/memory/backend/memory.h" #include "machine/memory/cache/cache.h" #include "machine/memory/memory_bus.h" #include "machine/predictor.h" #include using std::vector; using namespace machine; Q_DECLARE_METATYPE(Xlen) // NOLINT(performance-no-int-to-ptr) /** * Compiles program with no relocations into memory * * @param memory memory to save program to * @param init_pc address, where the compiled program will start * @param instructions vector of instructions * @return number of instruction compiled (number of steps, that can be executed) */ size_t compile_simple_program( FrontendMemory &memory, Address init_pc, const std::vector &instructions) { Address pc = init_pc; uint32_t code[2]; for (auto &instruction : instructions) { size_t size = Instruction::code_from_string(code, 8, instruction, pc); for (size_t i = 0; i < size; i += 4, pc += 4) { memory.write_u32(pc, code[i]); } } return (pc - init_pc) / 4; } template void test_program_with_single_result() { QFETCH(vector, instructions); QFETCH(Registers, registers); QFETCH(RegisterValue, x10_result); QFETCH(Xlen, xlen); Memory memory_backend(BIG); TrivialBus memory(&memory_backend); BranchPredictor predictor {}; CSR::ControlState controlst {}; Core core(®isters, &predictor, &memory, &memory, &controlst, Xlen::_32, config_isa_word_default); size_t instruction_count = compile_simple_program(memory, 0x200_addr, instructions); if (typeid(Core) == typeid(CorePipelined)) { instruction_count += 3; } // finish pipeline for (size_t i = 0; i < instruction_count; i++) { core.step(); } QCOMPARE(registers.read_gp(10).as_xlen(xlen), x10_result.as_xlen(xlen)); } static void core_regs_data() { QSKIP("Switched RV."); QTest::addColumn("i"); QTest::addColumn("init"); QTest::addColumn("res"); // Note that we shouldn't be touching program counter as that is handled // automatically and differs if we use pipelining // Arithmetic instructions { Registers regs_init; regs_init.write_gp(24, 24); regs_init.write_gp(25, 12); Registers regs_res(regs_init); regs_res.write_gp(26, 36); // QTest::newRow("ADD") << Instruction(0, 24, 25, 26, 0, 32) << regs_init << // regs_res; QTest::newRow("ADDU") << Instruction(0, 24, 25, 26, 0, 33) << // regs_init // << regs_res; QTest::newRow("ADDI") << Instruction(8, 24, 26, 12) << regs_init // << regs_res; QTest::newRow("ADDIU") << Instruction(9, 24, 26, 12) << regs_init // << regs_res; regs_res.write_gp(26, 12); // QTest::newRow("SUB") << Instruction(0, 24, 25, 26, 0, 34) << regs_init << // regs_res; QTest::newRow("SUBU") << Instruction(0, 24, 25, 26, 0, 35) << // regs_init // << regs_res; } { Registers regs_init; regs_init.write_gp(24, 12); regs_init.write_gp(25, 24); Registers regs_res(regs_init); regs_res.write_gp(26, 1); // QTest::newRow("SLT") << Instruction(0, 24, 25, 26, 0, 42) << regs_init << // regs_res; QTest::newRow("SLTU") << Instruction(0, 24, 25, 26, 0, 43) << // regs_init // << regs_res; QTest::newRow("SLTI") << Instruction(10, 24, 26, 24) << regs_init // << regs_res; QTest::newRow("SLTIU") << Instruction(11, 24, 26, 24) << // regs_init << regs_res; } // Shift instructions { Registers regs_init; regs_init.write_gp(24, 0xf0); regs_init.write_gp(25, 3); Registers regs_res(regs_init); regs_res.write_gp(26, 0x780); // QTest::newRow("SLL") << Instruction(0, 0, 24, 26, 3, 0) << regs_init << // regs_res; QTest::newRow("SLLV") << Instruction(0, 25, 24, 26, 0, 4) << // regs_init << regs_res; regs_res.write_gp(26, 0x1e); // QTest::newRow("SLR") << Instruction(0, 0, 24, 26, 3, 2) << regs_init << // regs_res; QTest::newRow("SLRV") << Instruction(0, 25, 24, 26, 0, 6) << // regs_init << regs_res; } { Registers regs_init; regs_init.write_gp(24, 0x800000f0); regs_init.write_gp(25, 3); Registers regs_res(regs_init); // Cast is needed to correctly work with any internal size of register. regs_res.write_gp(26, (int32_t)0xF000001e); // QTest::newRow("SRA") << Instruction(0, 0, 24, 26, 3, 3) << regs_init << // regs_res; QTest::newRow("SRAV") << Instruction(0, 25, 24, 26, 0, 7) << // regs_init << regs_res; } // Logical instructions { Registers regs_init; regs_init.write_gp(24, 0xf0); regs_init.write_gp(25, 0xe1); Registers regs_res(regs_init); regs_res.write_gp(26, 0xe0); // QTest::newRow("AND") << Instruction(0, 24, 25, 26, 0, 36) << regs_init << // regs_res; QTest::newRow("ANDI") << Instruction(12, 24, 26, 0xe1) << regs_init // << regs_res; regs_res.write_gp(26, 0xf1); // QTest::newRow("OR") << Instruction(0, 24, 25, 26, 0, 37) << regs_init << // regs_res; QTest::newRow("ORI") << Instruction(13, 24, 26, 0xe1) << regs_init // << regs_res; regs_res.write_gp(26, 0x11); // QTest::newRow("XOR") << Instruction(0, 24, 25, 26, 0, 38) << regs_init << // regs_res; QTest::newRow("XORI") << Instruction(14, 24, 26, 0xe1) << regs_init // << regs_res; regs_res.write_gp(26, 0xffffff0e); // QTest::newRow("NOR") << Instruction(0, 24, 25, 26, 0, 39) << regs_init << // regs_res; regs_res.write_gp(26, 0xf00f0000); QTest::newRow("LUI") << // Instruction(15, 0, 26, 0xf00f) << regs_init << regs_res; } // Move instructions { Registers regs_init; Registers regs_res(regs_init); regs_res.write_gp(26, 24); // QTest::newRow("MFHI") << Instruction(0, 0, 0, 26, 0, 16) << regs_init << // regs_res; regs_res.write_gp(26, 28); // QTest::newRow("MFLO") << Instruction(0, 0, 0, 26, 0, 18) << regs_init << // regs_res; regs_res.write_gp(26, 0); // QTest::newRow("MTHI") << Instruction(0, 27, 0, 0, 0, 17) << regs_init << // regs_res; QTest::newRow("MTLO") << Instruction(0, 28, 0, 0, 0, 19) << // regs_init << regs_res; QTest::newRow("MOVZ-F") << Instruction(0, 24, 24, 25, // 0, 10) << regs_init << regs_res; QTest::newRow("MOVN-F") << Instruction(0, 24, // 1, 25, 0, 11) << regs_init // << regs_res; regs_res.write_gp(25, 55); // QTest::newRow("MOVZ-T") << Instruction(0, 24, 1, 25, 0, 10) << regs_init << // regs_res; QTest::newRow("MOVN-T") << Instruction(0, 24, 24, 25, 0, 11) << // regs_init << regs_res; } } void TestCore::singlecore_regs_data() { QSKIP("Switched ALU to RV."); core_regs_data(); } void TestCore::pipecore_regs_data() { QSKIP("Switched ALU to RV."); core_regs_data(); } void TestCore::singlecore_regs() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, init); QFETCH(Registers, res); Memory mem(BIG); // Just memory (it shouldn't be used here except // instruction) TrivialBus mem_frontend(&mem); memory_write_u32(&mem, res.read_pc().get_raw(), i.data()); // Store single // instruction // (anything else // should be 0 so // NOP // effectively) Memory mem_used(mem); // Create memory copy TrivialBus mem_used_frontend(&mem); // CoreSingle core(&init, &mem_used_frontend, &mem_used_frontend, true, nullptr, // Xlen::_32); core.step(); // Single step should be enought as this is risc without // pipeline // core.step(); // res.pc_inc(); // res.pc_inc(); // We did single step so increment program counter accordingly QCOMPARE(init, res); // After doing changes from initial state this should // be same state as in case of passed expected result } void TestCore::pipecore_regs() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, init); QFETCH(Registers, res); Memory mem(BIG); // Just memory (it shouldn't be used here except // instruction) TrivialBus mem_frontend(&mem); memory_write_u32(&mem, res.read_pc().get_raw(), i.data()); // Store single // instruction // (anything else // should be 0 so // NOP // effectively) Memory mem_used(mem); TrivialBus mem_used_frontend(&mem_used); res.write_pc(0x14_addr); // CorePipelined core( // &init, &mem_used_frontend, &mem_used_frontend, nullptr, MachineConfig::HU_NONE, 0, // nullptr, Xlen::_32); // for (int i = 0; i < 5; i++) { // core.step(); // Fire steps for five pipelines stages // } // // cout << "well:" << init.read_gp(26) << ":" << regs_used.read_gp(26) << endl; // QCOMPARE(init, res); // After doing changes from initial state this should // be same state as in case of passed expected result QCOMPARE(mem, mem_used); // There // should be // no change in // memory } static void core_jmp_data() { QSKIP("Switched RV."); QTest::addColumn("i"); QTest::addColumn("regs"); QTest::addColumn("pc"); Registers regs; regs.write_gp(14, -22); regs.write_gp(15, 22); regs.write_gp(16, -22); regs.write_gp(12, 0x80040000); // QTest::newRow("B") << Instruction(4, 0, 0, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BEQ") << Instruction(4, 14, 16, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BEQ-BACK") << Instruction(4, 14, 16, -4) << regs // << regs.read_pc().get_raw() + 4 - 16; // QTest::newRow("BNE") << Instruction(5, 14, 15, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BGEZ") << Instruction(1, 15, 1, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BGTZ") << Instruction(7, 15, 0, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BLEZ") << Instruction(6, 14, 0, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("BLTZ") << Instruction(1, 14, 0, 61) << regs // << regs.read_pc().get_raw() + 4 + (61 << 2); // QTest::newRow("J") << Instruction(2, Address(24)) << regs // << Address(0x80000000).get_raw() + (24 << 2); // QTest::newRow("JR") << Instruction(0, 12, 0, 0, 0, 8) << regs << // Address(0x80040000).get_raw(); } void TestCore::singlecore_jmp_data() { QSKIP("Switched ALU to RV."); core_jmp_data(); } void TestCore::pipecore_jmp_data() { QSKIP("Switched ALU to RV."); core_jmp_data(); } void TestCore::singlecore_jmp() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, regs); // QFETCH(uint64_t, pc); Memory mem(BIG); TrivialBus mem_frontend(&mem); memory_write_u32(&mem, regs.read_pc().get_raw(), i.data()); Memory mem_used(mem); TrivialBus mem_used_frontend(&mem_used); Registers regs_used(regs); // CoreSingle core( // ®s_used, &mem_used_frontend, &mem_used_frontend, true, nullptr, Xlen::_32); // core.step(); // QCOMPARE(regs.read_pc() + 4, regs_used.read_pc()); // First execute delay // slot // core.step(); // QCOMPARE(pc, regs_used.read_pc().get_raw()); // Now do jump // // QCOMPARE(mem, mem_used); // There should be no change in memory // regs_used.pc_abs_jmp(regs.read_pc()); // Reset program counter before we do // registers compare // QCOMPARE(regs, regs_used); // There should be no change in registers now } void TestCore::pipecore_jmp() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, regs); // QFETCH(uint64_t, pc); Memory mem(BIG); TrivialBus mem_frontend(&mem); memory_write_u32(&mem, regs.read_pc().get_raw(), i.data()); Memory mem_used(mem); TrivialBus mem_used_frontend(&mem_used); Registers regs_used(regs); // CorePipelined core( // ®s_used, &mem_used_frontend, &mem_used_frontend, nullptr, // MachineConfig::HU_NONE, 0, nullptr, Xlen::_32); // core.step(); // QCOMPARE(regs.read_pc() + 4, regs_used.read_pc()); // First just fetch // core.step(); // QCOMPARE(pc, regs_used.read_pc().get_raw()); // Now do jump // for (int i = 0; i < 3; i++) { // core.step(); // Follow up with three other steps to complete pipeline to // } // be sure that instruction has no side effects // // QCOMPARE(mem, mem_used); // There should be no change in memory // regs.pc_abs_jmp(Address(pc + 12)); // Set reference pc to three more // instructions later (where regs_used // should be) // QCOMPARE(regs, regs_used); // There should be no change in registers now // (except pc) } static void core_mem_data() { QTest::addColumn("i"); QTest::addColumn("regs_init"); QTest::addColumn("regs_res"); QTest::addColumn("mem_init"); QTest::addColumn("mem_res"); // Load { Memory mem(BIG); memory_write_u32(&mem, 0x24, 0xA3242526); Registers regs; regs.write_gp(1, 0x22); Registers regs_res(regs); // Cast to get proper sign extension. regs_res.write_gp(21, (int32_t)0xFFFFFFA3); // QTest::newRow("LB") << Instruction(32, 1, 21, 0x2) << regs << regs_res << mem // << mem; // Cast to get proper sign extension. // regs_res.write_gp(21, (int32_t)0xFFFFA324); // QTest::newRow("LH") << Instruction(33, 1, 21, 0x2) << regs << regs_res << mem // << mem; regs_res.write_gp(21, 0xA3242526); QTest::newRow("LW") << // Instruction(35, 1, 21, 0x2) << regs << regs_res << mem << mem; // regs_res.write_gp(21, 0x000000A3); QTest::newRow("LBU") << Instruction(36, 1, // 21, 0x2) << regs << regs_res << mem << mem; regs_res.write_gp(21, 0x0000A324); // QTest::newRow("LHU") << Instruction(37, 1, 21, 0x2) << regs << regs_res << mem // << mem; } // Store { Registers regs; regs.write_gp(1, 0x22); regs.write_gp(21, 0x23242526); Memory mem(BIG); memory_write_u8(&mem, 0x24, 0x26); // Note: store least significant byte // QTest::newRow("SB") << Instruction(40, 1, 21, 0x2) << regs << regs << // Memory(BIG) // << mem; memory_write_u16(&mem, 0x24, 0x2526); QTest::newRow("SH") << // Instruction(41, 1, 21, 0x2) << regs << regs << Memory(BIG) << mem; // memory_write_u32(&mem, 0x24, 0x23242526); // QTest::newRow("SW") << Instruction(43, 1, 21, 0x2) << regs << regs << // Memory(BIG) // << mem; } } void TestCore::singlecore_mem_data() { QSKIP("Switched ALU to RV."); core_mem_data(); } void TestCore::pipecore_mem_data() { QSKIP("Switched ALU to RV."); core_mem_data(); } void TestCore::singlecore_mem() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, regs_init); QFETCH(Registers, regs_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); // Write instruction to both memories memory_write_u32(&mem_init, regs_init.read_pc().get_raw(), i.data()); memory_write_u32(&mem_res, regs_init.read_pc().get_raw(), i.data()); TrivialBus mem_init_frontend(&mem_init); // CoreSingle core( // ®s_init, &mem_init_frontend, &mem_init_frontend, true, nullptr, Xlen::_32); // core.step(); // core.step(); // // regs_res.pc_inc(); // regs_res.pc_inc(); // QCOMPARE(regs_init, regs_res); // QCOMPARE(mem_init, mem_res); } void TestCore::pipecore_mem() { QSKIP("Switched ALU to RV."); QFETCH(Instruction, i); QFETCH(Registers, regs_init); QFETCH(Registers, regs_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); // Write instruction to both memories memory_write_u32(&mem_init, regs_init.read_pc().get_raw(), i.data()); memory_write_u32(&mem_res, regs_init.read_pc().get_raw(), i.data()); TrivialBus mem_init_frontend(&mem_init); // CorePipelined core( // ®s_init, &mem_init_frontend, &mem_init_frontend, nullptr, // MachineConfig::HU_NONE, 0, nullptr, Xlen::_32); // for (int i = 0; i < 5; i++) { // core.step(); // Fire steps for five pipelines stages // } // // regs_res.pc_jmp(20); // QCOMPARE(regs_init, regs_res); // QCOMPARE(mem_init, mem_res); } /*======================================================================*/ static void core_alu_forward_data() { QTest::addColumn>("code"); QTest::addColumn("reg_init"); QTest::addColumn("reg_res"); // Note that we shouldn't be touching program counter as that is handled // automatically and differs if we use pipelining // Test forwarding of ALU operands { QVector code { // objdump --disassembler-options=no-aliases,numeric -d test-hazards // sed -n -e 's/^[ \t]*[^ \t]\+:[ \t]\+\([0-9a-f]\+\)[ \t]\+\([^ \t].*\)$/0x\1, \/\/ \2/p' 0x00100113, // addi x2,x0,1 0x11100093, // addi x1,x0,273 0x22200093, // addi x1,x0,546 0x002081b3, // add x3,x1,x2 0x00208233, // add x4,x1,x2 0x00300113, // addi x2,x0,3 0x11100093, // addi x1,x0,273 0x22200093, // addi x1,x0,546 0x001102b3, // add x5,x2,x1 0x00110333, // add x6,x2,x1 0x00000013, // addi x0,x0,0 0x00000063, // beq x0,x0,10080 }; Registers regs_init; regs_init.write_pc(0x200_addr); Registers regs_res(regs_init); regs_res.write_gp(1, 0x222); regs_res.write_gp(2, 3); regs_res.write_gp(3, 0x223); regs_res.write_gp(4, 0x223); regs_res.write_gp(5, 0x225); regs_res.write_gp(6, 0x225); regs_res.write_pc(regs_init.read_pc() + 4 * code.length() - 4); QTest::newRow("alu_forward_1") << code << regs_init << regs_res; } // Test forwarding in JR and JALR { QVector code { // start: 0x01111537, // lui x10,0x1111 0x022225b7, // lui x11,0x2222 0x03333637, // lui x12,0x3333 0x034000ef, // jal x1,240 0x00a00733, // add x14,x0,x10 0x0140006f, // jal x0,228 0x44400413, // addi x8,x0,1092 0x55500913, // addi x18,x0,1365 0x66600993, // addi x19,x0,1638 0x77700a13, // addi x20,x0,1911 // skip: 0x00000297, // auipc x5,0x0 0x02828293, // addi x5,x5,40 # 250 0x000280e7, // jalr x1,0(x5) 0x2cd00513, // addi x10,x0,717 0x00050493, // addi x9,x10,0 # 1111000 <__global_pointer$+0x1108400> 0x01c0006f, // jal x0,258 // fnc_add: 0x00b50533, // add x10,x10,x11 0x00c50533, // add x10,x10,x12 0x00008067, // jalr x0,0(x1) 0x7f100693, // addi x13,x0,2033 // fnc_short 0x00008067, // jalr x0,0(x1) 0x7f200693, // addi x13,x0,2034 // test_end: 0x00000013, // addi x0,x0,0 0x00000013, // addi x0,x0,0 // loop: 0x00000063, // beq x0,x0,260 }; Registers regs_init; regs_init.write_pc(0x200_addr); Registers regs_res(regs_init); regs_res.write_gp( 1, 0x00000234); regs_res.write_gp( 5, 0x00000250); regs_res.write_gp( 9, 0x000002cd); regs_res.write_gp(10, 0x000002cd); regs_res.write_gp(11, 0x02222000); regs_res.write_gp(12, 0x03333000); regs_res.write_gp(14, 0x06666000); regs_res.write_pc(regs_init.read_pc() + 4 * code.length() - 4); QTest::newRow("j_jal_jalr") << code << regs_init << regs_res; } // Test multiplication and division { QVector code { 0x12345137, // lui x2,0x12345 0x67810113, // addi x2,x2,1656 0xabcdf1b7, // lui x3,0xabcdf 0xf0118193, // addi x3,x3,-255 0x02310833, // mul x16,x2,x3 0x023118b3, // mulh x17,x2,x3 0x02310933, // mul x18,x2,x3 0x023139b3, // mulhu x19,x2,x3 0x0221ca33, // div x20,x3,x2 0x0221eab3, // rem x21,x3,x2 0x0221db33, // divu x22,x3,x2 0x0221fbb3, // remu x23,x3,x2 0x0000006f, // jal x0,230 }; Registers regs_init; regs_init.write_pc(0x80020000_addr); Registers regs_res(regs_init); uint32_t val_a = 0x12345678; uint32_t val_b = 0xabcdef01; uint64_t val_u64; int64_t val_s64; regs_res.write_gp(2, (int32_t)val_a); regs_res.write_gp(3, (int32_t)val_b); val_s64 = (int64_t)(int32_t)val_a * (int32_t)val_b; regs_res.write_gp(16, (int32_t)(val_s64 & 0xffffffff)); regs_res.write_gp(17, (int32_t)(val_s64 >> 32)); val_u64 = (uint64_t)val_a * val_b; regs_res.write_gp(18, (int32_t)(val_u64 & 0xffffffff)); regs_res.write_gp(19, (int32_t)(val_u64 >> 32)); regs_res.write_gp(20, (int32_t)((int32_t)val_b / (int32_t)val_a)); regs_res.write_gp(21, (int32_t)((int32_t)val_b % (int32_t)val_a)); regs_res.write_gp(22, val_b / val_a); regs_res.write_gp(23, val_b % val_a); regs_res.write_pc(regs_init.read_pc() + 4 * code.length() - 4); QTest::newRow("mul-div") << code << regs_init << regs_res; } // branches { QVector code { 0xfff00093, // addi x1,x0,-1 0x00100113, // addi x2,x0,1 0x00000193, // addi x3,x0,0 0x00200213, // addi x4,x0,2 0x00100293, // addi x5,x0,1 0x0000ca63, // blt x1,x0,228 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x10018193, // addi x3,x3,256 0x001181b3, // add x3,x3,x1 0x00100293, // addi x5,x0,1 0x00105a63, // bge x0,x1,240 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x01018193, // addi x3,x3,16 0x001181b3, // add x3,x3,x1 0x00100293, // addi x5,x0,1 0x0000da63, // bge x1,x0,258 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x20018193, // addi x3,x3,512 0x001181b3, // add x3,x3,x1 0x00100293, // addi x5,x0,1 0x00104a63, // blt x0,x1,270 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x02018193, // addi x3,x3,32 0x001181b3, // add x3,x3,x1 0x00100293, // addi x5,x0,1 0x00209a63, // bne x1,x2,288 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x40018193, // addi x3,x3,1024 0x001181b3, // add x3,x3,x1 0x00100293, // addi x5,x0,1 0x00208a63, // beq x1,x2,2a0 0x00000013, // addi x0,x0,0 0x00000293, // addi x5,x0,0 0x04018193, // addi x3,x3,64 0x001181b3, // add x3,x3,x1 0x00108093, // addi x1,x1,1 0xf64096e3, // bne x1,x4,210 0x00000013, // addi x0,x0,0 0x00000013, // addi x0,x0,0 0x00000013, // addi x0,x0,0 0x00000063, // beq x0,x0,2b4 }; Registers regs_init; regs_init.write_pc(0x200_addr); Registers regs_res(regs_init); regs_res.write_gp(1, 2); regs_res.write_gp(2, 1); regs_res.write_gp(3, 0x8d0); regs_res.write_gp(4, 2); regs_res.write_gp(5, 1); regs_res.write_pc(regs_init.read_pc() + 4 * code.length()); QTest::newRow("branch_conditions_test") << code << regs_init << regs_res; } } void TestCore::singlecore_alu_forward_data() { core_alu_forward_data(); } void TestCore::pipecore_alu_forward_data() { core_alu_forward_data(); } void TestCore::pipecorestall_alu_forward_data() { core_alu_forward_data(); } static void run_code_fragment( Core &core, Registers ®_init, Registers ®_res, Memory &mem_init, Memory &mem_res, QVector &code) { uint64_t addr = reg_init.read_pc().get_raw(); foreach (uint32_t i, code) { memory_write_u32(&mem_init, addr, i); memory_write_u32(&mem_res, addr, i); addr += 4; } for (int k = 10000; k; k--) { core.step(); // Single step should be enought as this is risc without // pipeline if (reg_init.read_pc() == reg_res.read_pc() && k > 6) { // reached end // of // the code // fragment k = 6; // add some cycles to finish processing } } reg_res.write_pc(reg_init.read_pc()); // We do not compare result pc QCOMPARE(reg_init, reg_res); // After doing changes from initial state this // should be same state as in case of passed // expected result QCOMPARE(mem_init, mem_res); // There should be no change in memory } void TestCore::singlecore_alu_forward() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); Memory mem_init(LITTLE); TrivialBus mem_init_frontend(&mem_init); Memory mem_res(LITTLE); TrivialBus mem_res_frontend(&mem_res); BranchPredictor predictor {}; CSR::ControlState controlst {}; CoreSingle core(®_init, &predictor, &mem_init_frontend, &mem_init_frontend, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecore_alu_forward() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); Memory mem_init(LITTLE); TrivialBus mem_init_frontend(&mem_init); Memory mem_res(LITTLE); TrivialBus mem_res_frontend(&mem_res); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &mem_init_frontend, &mem_init_frontend, &controlst, Xlen::_32, config_isa_word_default, MachineConfig::HazardUnit::HU_STALL_FORWARD); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecorestall_alu_forward() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); Memory mem_init(LITTLE); TrivialBus mem_init_frontend(&mem_init); Memory mem_res(LITTLE); TrivialBus mem_res_frontend(&mem_res); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &mem_init_frontend, &mem_init_frontend, &controlst, Xlen::_32, config_isa_word_default, MachineConfig::HazardUnit::HU_STALL); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } /*======================================================================*/ static void core_memory_tests_data() { QTest::addColumn>("code"); QTest::addColumn("reg_init"); QTest::addColumn("reg_res"); QTest::addColumn("mem_init"); QTest::addColumn("mem_res"); // Test { QVector code { // objdump --disassembler-options=no-aliases,numeric -d test-hazards // sed -n -e 's/^[ \t]*[^ \t]\+:[ \t]\+\([0-9a-f]\+\)[ \t]\+\([^ \t].*\)$/0x\1, \/\/ \2/p' // _start: 0x40000513, // addi x10,x0,1024 0x00000413, // addi x8,x0,0 0x03c00493, // addi x9,x0,60 0x00800933, // add x18,x0,x8 // main_cycle: 0x04940a63, // beq x8,x9,264 0x008502b3, // add x5,x10,x8 0x0002aa03, // lw x20,0(x5) 0x000409b3, // add x19,x8,x0 0x00040933, // add x18,x8,x0 // inner_cycle: 0x02990263, // beq x18,x9,248 0x012502b3, // add x5,x10,x18 0x0002aa83, // lw x21,0(x5) 0x015a22b3, // slt x5,x20,x21 0x00029663, // bne x5,x0,240 0x00090993, // addi x19,x18,0 0x000a8a13, // addi x20,x21,0 // not_minimum: 0x00490913, // addi x18,x18,4 0xfe1ff06f, // jal x0,224 // inner_cycle_end: 0x008502b3, // add x5,x10,x8 0x0002aa83, // lw x21,0(x5) 0x0142a023, // sw x20,0(x5) 0x013502b3, // add x5,x10,x19 0x0152a023, // sw x21,0(x5) 0x00440413, // addi x8,x8,4 0xfb1ff06f, // jal x0,210 // main_cycle_end: 0x0ff0000f, // fence iorw,iorw 0x00000013, // addi x0,x0,0 // the mai_cycle loop end has 0x00000013, // addi x0,x0,0 // to be separated because else fetch 0x00000013, // addi x0,x0,0 // reaches stop address prematurely 0x00000063, // beq x0,x0,10080 }; QVector data_init { 5, 3, 4, 1, 15, 8, 9, 2, 10, 6, 11, 1, 6, 9, 12 }; QVector data_res { 1, 1, 2, 3, 4, 5, 6, 6, 8, 9, 9, 10, 11, 12, 15 }; Registers regs_init; regs_init.write_pc(0x200_addr); Registers regs_res(regs_init); regs_res.write_gp( 5, 0x438); regs_res.write_gp( 8, 0x3c); regs_res.write_gp( 9, 0x3c); regs_res.write_gp(10, 0x400); regs_res.write_gp(18, 0x3c); regs_res.write_gp(19, 0x38); regs_res.write_gp(20, 0xf); regs_res.write_gp(21, 0xf); regs_res.write_pc(regs_init.read_pc() + 4 * code.length() - 4); uint32_t addr; Memory mem_init(LITTLE); addr = 0x400; foreach (uint32_t i, data_init) { memory_write_u32(&mem_init, addr, i); addr += 4; } Memory mem_res(LITTLE); addr = 0x400; foreach (uint32_t i, data_res) { memory_write_u32(&mem_res, addr, i); addr += 4; } QTest::newRow("cache_insert_sort") << code << regs_init << regs_res << mem_init << mem_res; } // unaligned lw a lw and sw { QVector code { 0xaabbdd37, // lui x26,0xaabbd 0xcddd0d13, // addi x26,x26,-803 0x000d0113, // addi x2,x26,0 0x000d0193, // addi x3,x26,0 0x000d0213, // addi x4,x26,0 0x000d0293, // addi x5,x26,0 0x000d0313, // addi x6,x26,0 0x000d0393, // addi x7,x26,0 0x000d0413, // addi x8,x26,0 0x000d0493, // addi x9,x26,0 0x000d0513, // addi x10,x26,0 0x80020db7, // lui x27,0x80020 0x100d8d93, // addi x27,x27,256 0x000da103, // lw x2,0(x27) 0x001da183, // lw x3,1(x27) 0x002da203, // lw x4,2(x27) 0x003da283, // lw x5,3(x27) 0x01ada023, // sw x26,0(x27) 0x01ada2a3, // sw x26,5(x27) 0x01ada523, // sw x26,10(x27) 0x01ada7a3, // sw x26,15(x27) 0x000da503, // lw x10,0(x27) 0x004da583, // lw x11,4(x27) 0x008da603, // lw x12,8(x27) 0x00cda683, // lw x13,12(x27) 0x010da703, // lw x14,16(x27) 0x014da783, // lw x15,20(x27) 0x018da803, // lw x16,24(x27) 0x01cda883, // lw x17,28(x27) 0x020da903, // lw x18,32(x27) 0x020da983, // lw x19,32(x27) 0x0ff0000f, // fence iorw,iorw 0x00000013, // addi x0,x0,0 0x00000013, // addi x0,x0,0 0xfe000ce3, // beq x0,x0,27c }; Registers regs_init; regs_init.write_pc(0x200_addr); Registers regs_res(regs_init); regs_res.write_gp(2, (int32_t)0x04030201); regs_res.write_gp(3, (int32_t)0x05040302); regs_res.write_gp(4, (int32_t)0x06050403); regs_res.write_gp(5, (int32_t)0x07060504); regs_res.write_gp(6, (int32_t)0xaabbccdd); regs_res.write_gp(7, (int32_t)0xaabbccdd); regs_res.write_gp(8, (int32_t)0xaabbccdd); regs_res.write_gp(9, (int32_t)0xaabbccdd); regs_res.write_gp(10, (int32_t)0xaabbccdd); regs_res.write_gp(11, (int32_t)0xbbccdd05); regs_res.write_gp(12, (int32_t)0xccdd0aaa); regs_res.write_gp(13, (int32_t)0xdd0faabb); regs_res.write_gp(14, (int32_t)0x14aabbcc); regs_res.write_gp(15, (int32_t)0x18171615); regs_res.write_gp(16, (int32_t)0x1c1b1a19); regs_res.write_gp(17, (int32_t)0x101f1e1d); regs_res.write_gp(18, (int32_t)0x24232221); regs_res.write_gp(19, (int32_t)0x24232221); regs_res.write_gp(26, (int32_t)0xaabbccdd); regs_res.write_gp(27, (int32_t)0x80020100); uint32_t addr; Memory mem_init(LITTLE); addr = 0x80020100; QVector data_init { 0x04030201, 0x08070605, 0x0c0b0a09, 0x000f0e0d, 0x14131211, 0x18171615, 0x1c1b1a19, 0x101f1e1d, 0x24232221, 0x28272625, 0x2c2b2a29, 0x202f2e2d }; foreach (uint32_t i, data_init) { memory_write_u32(&mem_init, addr, i); addr += 4; } Memory mem_res(LITTLE); addr = 0x80020100; QVector data_res { 0xaabbccdd, 0xbbccdd05, 0xccdd0aaa, 0xdd0faabb, 0x14aabbcc, 0x18171615, 0x1c1b1a19, 0x101f1e1d, 0x24232221, 0x28272625, 0x2c2b2a29, 0x202f2e2d }; foreach (uint32_t i, data_res) { memory_write_u32(&mem_res, addr, i); addr += 4; } regs_res.write_pc(regs_init.read_pc() + 4 * code.length() - 4); QTest::newRow("lw_sw_unaligned_be") << code << regs_init << regs_res << mem_init << mem_res; } } void TestCore::singlecore_memory_tests_data() { core_memory_tests_data(); } void TestCore::pipecore_nc_memory_tests_data() { core_memory_tests_data(); } void TestCore::pipecore_wt_na_memory_tests_data() { core_memory_tests_data(); } void TestCore::pipecore_wt_a_memory_tests_data() { core_memory_tests_data(); } void TestCore::pipecore_wb_memory_tests_data() { core_memory_tests_data(); } void TestCore::singlecore_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); TrivialBus mem_init_frontend(&mem_init); TrivialBus mem_res_frontend(&mem_res); BranchPredictor predictor {}; CSR::ControlState controlst {}; CoreSingle core(®_init, &predictor, &mem_init_frontend, &mem_init_frontend, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecore_nc_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); TrivialBus mem_init_frontend(&mem_init); TrivialBus mem_res_frontend(&mem_res); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &mem_init_frontend, &mem_init_frontend, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecore_wt_na_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); TrivialBus mem_init_frontend(&mem_init); TrivialBus mem_res_frontend(&mem_res); CacheConfig cache_conf; cache_conf.set_enabled(true); cache_conf.set_set_count(2); // Number of sets cache_conf.set_block_size(1); // Number of blocks cache_conf.set_associativity(2); // Degree of associativity cache_conf.set_replacement_policy(CacheConfig::RP_LRU); cache_conf.set_write_policy(CacheConfig::WP_THROUGH_NOALLOC); Cache i_cache(&mem_init_frontend, &cache_conf); Cache d_cache(&mem_init_frontend, &cache_conf); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &i_cache, &d_cache, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecore_wt_a_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); TrivialBus mem_init_frontend(&mem_init); TrivialBus mem_res_frontend(&mem_res); CacheConfig cache_conf; cache_conf.set_enabled(true); cache_conf.set_set_count(2); // Number of sets cache_conf.set_block_size(1); // Number of blocks cache_conf.set_associativity(2); // Degree of associativity cache_conf.set_replacement_policy(CacheConfig::RP_LRU); cache_conf.set_write_policy(CacheConfig::WP_THROUGH_ALLOC); Cache i_cache(&mem_init_frontend, &cache_conf); Cache d_cache(&mem_init_frontend, &cache_conf); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &i_cache, &d_cache, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void TestCore::pipecore_wb_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); QFETCH(Memory, mem_init); QFETCH(Memory, mem_res); TrivialBus mem_init_frontend(&mem_init); TrivialBus mem_res_frontend(&mem_res); CacheConfig cache_conf; cache_conf.set_enabled(true); cache_conf.set_set_count(4); // Number of sets cache_conf.set_block_size(2); // Number of blocks cache_conf.set_associativity(2); // Degree of associativity cache_conf.set_replacement_policy(CacheConfig::RP_LRU); cache_conf.set_write_policy(CacheConfig::WP_BACK); Cache i_cache(&mem_init_frontend, &cache_conf); Cache d_cache(&mem_init_frontend, &cache_conf); BranchPredictor predictor {}; CSR::ControlState controlst {}; CorePipelined core(®_init, &predictor, &i_cache, &d_cache, &controlst, Xlen::_32, config_isa_word_default); run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } void extension_m_data() { QTest::addColumn>("instructions"); QTest::addColumn("registers"); QTest::addColumn("x10_result"); QTest::addColumn("xlen"); Registers registers {}; registers.write_gp(1, 1111111); registers.write_gp(2, 7); QTest::addRow("mul") << vector { "mul x10, x1, x2", "nop" } << registers << RegisterValue { 7777777 } << Xlen::_32; registers.write_gp(1, 7777777); QTest::addRow("div") << vector { "div x10, x1, x2", "nop" } << registers << RegisterValue { 1111111 } << Xlen::_32; registers.write_gp(2, 1000); QTest::addRow("rem") << vector { "rem x10, x1, x2", "nop" } << registers << RegisterValue { 777 } << Xlen::_32; registers.write_gp(1, 15); registers.write_gp(2, -10); QTest::addRow("mulh 15x-10") << vector { "mulh x10, x1, x2", "nop" } << registers << RegisterValue { (uint64_t)0xffffffffffffffffULL } << Xlen::_32; QTest::addRow("mulhu 15x-10") << vector { "mulhu x10, x1, x2", "nop" } << registers << RegisterValue { 14 } << Xlen::_32; QTest::addRow("mulhsu 15x-10") << vector { "mulhsu x10, x1, x2", "nop" } << registers << RegisterValue { 14 } << Xlen::_32; QTest::addRow("mulh -10x15") << vector { "mulh x10, x2, x1", "nop" } << registers << RegisterValue { (uint64_t)0xffffffffffffffffULL } << Xlen::_32; QTest::addRow("mulhu -10x15") << vector { "mulhu x10, x2, x1", "nop" } << registers << RegisterValue { 14 } << Xlen::_32; QTest::addRow("mulhsu -10x15") << vector { "mulhsu x10, x2, x1", "nop" } << registers << RegisterValue { (uint64_t)0xffffffffffffffffULL } << Xlen::_32; registers.write_gp(1, -1); registers.write_gp(2, 0x10000); QTest::addRow("divu") << vector { "divu x10, x1, x2", "nop" } << registers << RegisterValue { 0xFFFF } << Xlen::_32; QTest::addRow("remu") << vector { "remu x10, x1, x2", "nop" } << registers << RegisterValue { 0xFFFF } << Xlen::_32; } // Extensions: // ================================================================================================= // RV32M void TestCore::singlecore_extension_m_data() { extension_m_data(); } void TestCore::pipecore_extension_m_data() { extension_m_data(); } void TestCore::singlecore_extension_m() { test_program_with_single_result(); } void TestCore::pipecore_extension_m() { test_program_with_single_result(); } QTEST_APPLESS_MAIN(TestCore) qtrvsim-0.9.8/src/machine/core.test.h000066400000000000000000000026271467752164200175340ustar00rootroot00000000000000#ifndef CORE_TEST_H #define CORE_TEST_H #include class TestCore : public QObject { Q_OBJECT private slots: // Not ported to RV: void singlecore_regs(); void singlecore_regs_data(); void pipecore_regs(); void pipecore_regs_data(); void singlecore_jmp(); void singlecore_jmp_data(); void pipecore_jmp(); void pipecore_jmp_data(); void singlecore_mem_data(); void singlecore_mem(); void pipecore_mem(); void pipecore_mem_data(); void singlecore_alu_forward(); void singlecore_alu_forward_data(); void pipecore_alu_forward(); void pipecore_alu_forward_data(); void pipecorestall_alu_forward(); void pipecorestall_alu_forward_data(); void singlecore_memory_tests_data(); void pipecore_nc_memory_tests_data(); void pipecore_wt_na_memory_tests_data(); void pipecore_wt_a_memory_tests_data(); void pipecore_wb_memory_tests_data(); void singlecore_memory_tests(); void pipecore_nc_memory_tests(); void pipecore_wt_na_memory_tests(); void pipecore_wt_a_memory_tests(); void pipecore_wb_memory_tests(); // Extensions: // ============================================================================================= // RV32M void singlecore_extension_m_data(); void pipecore_extension_m_data(); void singlecore_extension_m(); void pipecore_extension_m(); }; #endif // CORE_TEST_H qtrvsim-0.9.8/src/machine/core/000077500000000000000000000000001467752164200163765ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/core/core_state.h000066400000000000000000000007441467752164200207040ustar00rootroot00000000000000#ifndef QTRVSIM_CORE_STATE_H #define QTRVSIM_CORE_STATE_H #include "machinedefs.h" #include "pipeline.h" #include "common/memory_ownership.h" #include "memory/address_range.h" #include #include #include using std::uint32_t; namespace machine { struct CoreState { Pipeline pipeline = {}; AddressRange LoadReservedRange; uint32_t stall_count = 0; uint32_t cycle_count = 0; }; } // namespace machine #endif // QTRVSIM_CORE_STATE_H qtrvsim-0.9.8/src/machine/csr/000077500000000000000000000000001467752164200162355ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/csr/address.h000066400000000000000000000050211467752164200200310ustar00rootroot00000000000000#ifndef QTRVSIM_CSR_ADDRESS_H #define QTRVSIM_CSR_ADDRESS_H #include "common/math/bit_ops.h" #include "simulator_exception.h" #include namespace machine { namespace CSR { /** * Spec vol. 2: Table 2.1 */ enum class PrivilegeLevel { UNPRIVILEGED = 0b00, //> Unprivileged and User-Level CSRs, unimplemented SUPERVISOR = 0b01, //> Supervisor-Level CSRs, unimplemented HYPERVISOR = 0b10, //> Hypervisor and VS CSRs, unimplemented MACHINE = 0b11, //> Machine-Level CSRs }; struct Address { constexpr explicit Address(uint16_t address) : data(address) { SANITY_ASSERT( address < (1 << 12), "CSR register address is out of the ISA " "specified range (12bits)"); } constexpr Address(const Address &other) = default; constexpr Address &operator=(const Address &other) = default; uint16_t data; /* * By convention, the upper 4 bits of the CSR address (csr[11:8]) are used to encode the * read and write accessibility of the CSRs according to privilege level as shown in Table * 2.1. */ /** The top two bits (csr[11:10]) indicate whether the register is read/write * (00, 01, or 10) or read-only (11). */ [[nodiscard]] constexpr bool is_writable() const { return get_bits(data, 11, 10) != 0b11; } /** * The next two bits (csr[9:8]) encode the lowest privilege level that can access the CSR. */ [[nodiscard]] constexpr PrivilegeLevel get_privilege_level() const { return static_cast(get_bits(data, 9, 8)); } bool operator<(const Address &rhs) const { return data < rhs.data; } bool operator>(const Address &rhs) const { return rhs < *this; } bool operator<=(const Address &rhs) const { return !(rhs < *this); } bool operator>=(const Address &rhs) const { return !(*this < rhs); } bool operator==(const Address &rhs) const { return data == rhs.data; } bool operator!=(const Address &rhs) const { return data != rhs.data; } }; constexpr Address operator"" _csr(unsigned long long literal) { return Address(literal); } }} // namespace machine::CSR template<> struct std::hash { std::size_t operator()(machine::CSR::Address const &addr) const noexcept { return std::hash {}(addr.data); } }; #endif // QTRVSIM_CSR_ADDRESS_H qtrvsim-0.9.8/src/machine/csr/controlstate.cpp000066400000000000000000000161471467752164200214730ustar00rootroot00000000000000#include #include "controlstate.h" #include "common/logging.h" #include "machinedefs.h" #include "simulator_exception.h" #include LOG_CATEGORY("machine.csr.control_state"); namespace machine { namespace CSR { ControlState::ControlState(Xlen xlen, ConfigIsaWord isa_word) : xlen(xlen) { reset(); uint64_t misa = read_internal(CSR::Id::MISA).as_u64(); misa |= isa_word.toUnsigned(); register_data[CSR::Id::MISA] = misa; } ControlState::ControlState(const ControlState &other) : QObject(this->parent()) , xlen(other.xlen), register_data(other.register_data) {} void ControlState::reset() { std::transform( REGISTERS.begin(), REGISTERS.end(), register_data.begin(), [](const RegisterDesc &desc) { return desc.initial_value; }); uint64_t misa = read_internal(CSR::Id::MISA).as_u64(); misa &= 0x3fffffff; if (xlen == Xlen::_32) { misa |= (uint64_t)1 << 30; } else if (xlen == Xlen::_64) { misa |= (uint64_t)2 << 62; } register_data[CSR::Id::MISA] = misa; if (xlen == Xlen::_64) { write_field_raw(Field::mstatus::UXL, 2); write_field_raw(Field::mstatus::SXL, 2); } } size_t ControlState::get_register_internal_id(Address address) { // if (address.get_privilege_level() != PrivilegeLevel::MACHINE) try { return CSR::REGISTER_MAP.at(address); } catch (std::out_of_range &e) { throw SIMULATOR_EXCEPTION( UnsupportedInstruction, QString("Accessed nonexistent CSR register %1").arg(address.data), ""); } } RegisterValue ControlState::read(Address address) const { // Only machine level privilege is supported so no checking is needed. size_t reg_id = get_register_internal_id(address); RegisterValue value = register_data[reg_id]; DEBUG("Read CSR[%u] == 0x%" PRIx64, address.data, value.as_u64()); emit read_signal(reg_id, value); return value; } void ControlState::write(Address address, RegisterValue value) { DEBUG( "Write CSR[%u/%zu] <== 0x%zu", address.data, get_register_internal_id(address), value.as_u64()); // Attempts to write a read-only register also raise illegal instruction exceptions. if (!address.is_writable()) { throw SIMULATOR_EXCEPTION( UnsupportedInstruction, QString("CSR address %1 is not writable.").arg(address.data), ""); } write_internal(get_register_internal_id(address), value); } void ControlState::default_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val) { uint64_t u; u = val.as_u64() & desc.write_mask.as_u64(); u |= reg.as_u64() & ~desc.write_mask.as_u64(); if (xlen == Xlen::_32) u &= 0xffffffff; reg = u; } void ControlState::mstatus_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val) { default_wlrl_write_handler(desc, reg, val); } void ControlState::mcycle_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val) { Q_UNUSED(desc) reg = val; register_data[Id::CYCLE] = val; write_signal(Id::CYCLE, register_data[Id::CYCLE]); } bool ControlState::operator==(const ControlState &other) const { return register_data == other.register_data; } bool ControlState::operator!=(const ControlState &c) const { return !this->operator==(c); } void ControlState::update_exception_cause(enum ExceptionCause excause) { RegisterValue &value = register_data[Id::MCAUSE]; if (excause != EXCAUSE_INT) { value = static_cast(excause); } else { RegisterValue mie = register_data[Id::MIE]; RegisterValue mip = register_data[Id::MIP]; int irq_to_signal = 0; quint64 irqs = mie.as_u64() & mip.as_u64() & 0xffffffff; if (irqs != 0) { // Find the first (leas significant) set bit irq_to_signal = 63 - qCountLeadingZeroBits(irqs & (~irqs + 1)); } value = (uint64_t)(irq_to_signal | ((uint64_t)1 << ((xlen == Xlen::_32)? 31: 63))); } emit write_signal(Id::MCAUSE, value); } void ControlState::set_interrupt_signal(uint irq_num, bool active) { if (irq_num >= 32) { return; } uint64_t mask = 1 << irq_num; size_t reg_id = Id::MIP; RegisterValue &value = register_data[reg_id]; if (active) { value = value.as_xlen(xlen) | mask; } else { value = value.as_xlen(xlen) & ~mask; } emit write_signal(reg_id, value); } bool ControlState::core_interrupt_request() { RegisterValue mie = register_data[Id::MIE]; RegisterValue mip = register_data[Id::MIP]; uint64_t irqs = mie.as_u64() & mip.as_u64() & 0xffffffff; return irqs && read_field(Field::mstatus::MIE).as_u64(); } void ControlState::exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev) { size_t reg_id = Id::MSTATUS; RegisterValue ® = register_data[reg_id]; Q_UNUSED(act_privlev) Q_UNUSED(to_privlev) write_field(Field::mstatus::MPIE, read_field(Field::mstatus::MIE).as_u32()); write_field(Field::mstatus::MIE, (uint64_t)0); write_field(Field::mstatus::MPP, static_cast(act_privlev)); emit write_signal(reg_id, reg); } PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev) { size_t reg_id = Id::MSTATUS; RegisterValue ® = register_data[reg_id]; PrivilegeLevel restored_privlev; Q_UNUSED(act_privlev) write_field(Field::mstatus::MIE, read_field(Field::mstatus::MPIE).as_u32()); write_field(Field::mstatus::MPIE, (uint64_t)1); restored_privlev = static_cast(read_field(Field::mstatus::MPP).as_u32()); write_field(Field::mstatus::MPP, (uint64_t)0); emit write_signal(reg_id, reg); return restored_privlev; } machine::Address ControlState::exception_pc_address() { return machine::Address(register_data[Id::MTVEC].as_u64()); } RegisterValue ControlState::read_internal(size_t internal_id) const { return register_data[internal_id]; } void ControlState::write_internal(size_t internal_id, RegisterValue value) { RegisterDesc desc = REGISTERS[internal_id]; RegisterValue ® = register_data[internal_id]; (this->*desc.write_handler)(desc, reg, value); write_signal(internal_id, reg); } void ControlState::increment_internal(size_t internal_id, uint64_t amount) { auto value = register_data[internal_id]; write_internal(internal_id, value.as_u64() + amount); } }} // namespace machine::CSR qtrvsim-0.9.8/src/machine/csr/controlstate.h000066400000000000000000000247641467752164200211440ustar00rootroot00000000000000#ifndef CONTROLSTATE_H #define CONTROLSTATE_H #include "common/math/bit_ops.h" #include "csr/address.h" #include "machinedefs.h" #include "register_value.h" #include "simulator_exception.h" #include "bitfield.h" #include "config_isa.h" #include #include #include #include namespace machine { namespace CSR { /** CSR register names mapping the registers to continuous locations in internal buffer */ struct Id { enum IdxType{ // Unprivileged Counter/Timers CYCLE, // Machine Information Registers MVENDORID, MARCHID, MIMPID, MHARTID, // MCONFIGPTR, // Machine Trap Setup MSTATUS, MISA, // MEDELEG, // MIDELET, MIE, MTVEC, // MCOUNTERN, // MSTATUSH, // Machine Trap Handling MSCRATCH, MEPC, MCAUSE, MTVAL, MIP, MTINST, MTVAL2, // ... MCYCLE, MINSTRET, _COUNT, }; }; struct RegisterDesc; struct RegisterFieldDesc { uint64_t decode(uint64_t val) const { return field.decode(val); } uint64_t encode(uint64_t val) const { return field.encode(val); } uint64_t mask() const { return field.mask(); } uint64_t update(uint64_t orig, uint64_t val) const { return field.encode(val) | (orig & ~mask()); } const char *name = "unknown"; const Id::IdxType regId; const BitField field; const char *description = ""; }; /** * This class provides access to state of CSR registers. * * Registers are externally addressed by 12bit address. To simplify simulation, all existing * registers are stored in continuous array and indexed by "internal id" (not stable). */ class ControlState : public QObject { Q_OBJECT public: ControlState(Xlen xlen = Xlen::_32, ConfigIsaWord isa_word = 0); ControlState(const ControlState &); /** Read CSR register with ISA specified address. */ [[nodiscard]] RegisterValue read(Address address) const; /** * Read CSR register with an internal id. * * Internal id can be obtained from enum Id and works as an index to compacted table * of existing CSR registers. */ [[nodiscard]] RegisterValue read_internal(size_t internal_id) const; /** Write value to CSR register by ISA specified address and receive the previous value. */ void write(Address address, RegisterValue value); /** Used for writes occurring as a side-effect (instruction count update...) and * internally by the write method. */ void write_internal(size_t internal_id, RegisterValue value); /** Shorthand for counter incrementing. Counters like time might have different increment * amount. */ void increment_internal(size_t internal_id, uint64_t amount); /** Reset data to initial values */ void reset(); /** Read CSR register field */ RegisterValue read_field(const RegisterFieldDesc &field_desc) const { return field_desc.decode(read_internal(field_desc.regId).as_u64()); } /** Write CSR register field */ void write_field(const RegisterFieldDesc &field_desc, uint64_t value) { uint64_t u = read_internal(field_desc.regId).as_u64(); u = field_desc.update(u, value); write_internal(field_desc.regId, u); } void update_exception_cause(enum ExceptionCause excause); bool operator==(const ControlState &other) const; bool operator!=(const ControlState &c) const; bool core_interrupt_request(); machine::Address exception_pc_address(); signals: void write_signal(size_t internal_reg_id, RegisterValue val); void read_signal(size_t internal_reg_id, RegisterValue val) const; public slots: void set_interrupt_signal(uint irq_num, bool active); void exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev); PrivilegeLevel exception_return(enum PrivilegeLevel act_privlev); private: static size_t get_register_internal_id(Address address); /** Write CSR register field without write handler, read-only masking and signal */ void write_field_raw(const RegisterFieldDesc &field_desc, uint64_t value) { uint64_t u = register_data[field_desc.regId].as_u64(); u = field_desc.update(u, value); register_data[field_desc.regId] = u; } Xlen xlen = Xlen::_32; // TODO /** * Compacted table of existing CSR registers data. Each item is described by table * REGISTERS at corresponding indexes. */ std::array register_data; public: void default_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val); void mstatus_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val); void mcycle_wlrl_write_handler( const RegisterDesc &desc, RegisterValue ®, RegisterValue val); }; struct RegisterDesc { using WriteHandlerFn = void ( ControlState::*)(const RegisterDesc &desc, RegisterValue ®, RegisterValue val); const char *name = "unknown"; Address address = Address(0); const char *description = ""; RegisterValue initial_value = 0; RegisterValue write_mask = (register_storage_t)0xffffffffffffffff; WriteHandlerFn write_handler = &ControlState::default_wlrl_write_handler; struct { const RegisterFieldDesc * const *array; const unsigned count; } fields = {nullptr, 0}; }; namespace Field { namespace mstatus { static constexpr RegisterFieldDesc SIE = { "SIE", Id::MSTATUS, {1, 1}, "System global interrupt-enable"}; static constexpr RegisterFieldDesc MIE = { "MIE", Id::MSTATUS, {1, 3}, "Machine global interrupt-enable"}; static constexpr RegisterFieldDesc SPIE = { "SPIE", Id::MSTATUS, {1, 5}, "Previous SIE before the trap"}; static constexpr RegisterFieldDesc MPIE = { "MPIE", Id::MSTATUS, {1, 7}, "Previous MIE before the trap"}; static constexpr RegisterFieldDesc SPP = { "SPP", Id::MSTATUS, {1, 8}, "System previous privilege mode"}; static constexpr RegisterFieldDesc MPP = { "MPP", Id::MSTATUS, {2, 11}, "Machine previous privilege mode"}; static constexpr RegisterFieldDesc UXL = { "UXL", Id::MSTATUS, {2, 32}, "User mode XLEN (RV64 only)"}; static constexpr RegisterFieldDesc SXL = { "SXL", Id::MSTATUS, {2, 34}, "Supervisor mode XLEN (RV64 only)"}; static constexpr const RegisterFieldDesc *fields[] = { &SIE, &MIE, &SPIE, &MPIE, &SPP, &MPP, &UXL, &SXL}; static constexpr unsigned count = sizeof(fields) / sizeof(fields[0]); } } /** Definitions of supported CSR registers */ inline constexpr std::array REGISTERS { { // Unprivileged Counter/Timers [Id::CYCLE] = { "cycle", 0xC00_csr, "Cycle counter for RDCYCLE instruction.", 0, 0}, // Priviledged Machine Mode Registers [Id::MVENDORID] = { "mvendorid", 0xF11_csr, "Vendor ID.", 0, 0}, [Id::MARCHID] = { "marchid", 0xF12_csr, "Architecture ID.", 0, 0}, [Id::MIMPID] = { "mimpid", 0xF13_csr, "Implementation ID.", 0, 0}, [Id::MHARTID] = { "mhardid", 0xF14_csr, "Hardware thread ID." }, [Id::MSTATUS] = { "mstatus", 0x300_csr, "Machine status register.", 0, 0x007FFFEA, &ControlState::mstatus_wlrl_write_handler, {Field::mstatus::fields, Field::mstatus::count} }, [Id::MISA] = { "misa", 0x301_csr, "Machine ISA Register.", 0, 0}, [Id::MIE] = { "mie", 0x304_csr, "Machine interrupt-enable register.", 0, 0x00ff0AAA}, [Id::MTVEC] = { "mtvec", 0x305_csr, "Machine trap-handler base address."}, [Id::MSCRATCH] = { "mscratch", 0x340_csr, "Scratch register for machine trap handlers." }, [Id::MEPC] = { "mepc", 0x341_csr, "Machine exception program counter." }, [Id::MCAUSE] = { "mcause", 0x342_csr, "Machine trap cause." }, [Id::MTVAL] = { "mtval", 0x343_csr, "Machine bad address or instruction." }, [Id::MIP] = { "mip", 0x344_csr, "Machine interrupt pending.", 0, 0x00000222}, [Id::MTINST] = { "mtinst", 0x34A_csr, "Machine trap instruction (transformed)." }, [Id::MTVAL2] = { "mtval2", 0x34B_csr, "Machine bad guest physical address." }, // Machine Counter/Timers [Id::MCYCLE] = { "mcycle", 0xB00_csr, "Machine cycle counter.", 0, (register_storage_t)0xffffffffffffffff, &ControlState::mcycle_wlrl_write_handler}, [Id::MINSTRET] = { "minstret", 0xB02_csr, "Machine instructions-retired counter."}, } }; /** Lookup from CSR address (value used in instruction) to internal id (index in continuous * memory) */ class RegisterMap { bool initialized = false; std::unordered_map map; void init() { for (size_t i = 0; i < REGISTERS.size(); i++) { map.emplace(REGISTERS[i].address, i); } initialized = true; } public: size_t at(Address address) { if (!initialized) init(); return map.at(address); } }; class RegisterMapByName { bool initialized = false; std::unordered_map map; void init() { for (size_t i = 0; i < REGISTERS.size(); i++) { map.emplace(std::string(REGISTERS[i].name), i); } initialized = true; } public: size_t at(std::string name) { if (!initialized) init(); return map.at(name); } }; static RegisterMap REGISTER_MAP; static RegisterMapByName REGISTER_MAP_BY_NAME; }} // namespace machine::CSR Q_DECLARE_METATYPE(machine::CSR::ControlState) #endif // CONTROLSTATE_H qtrvsim-0.9.8/src/machine/execute/000077500000000000000000000000001467752164200171105ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/execute/alu.cpp000066400000000000000000000127001467752164200203750ustar00rootroot00000000000000#include "alu.h" #include "common/polyfills/mulh64.h" namespace machine { RegisterValue alu_combined_operate( AluCombinedOp op, AluComponent component, bool w_operation, bool modified, RegisterValue a, RegisterValue b) { switch (component) { case AluComponent::ALU: return (w_operation) ? alu32_operate(op.alu_op, modified, a, b) : alu64_operate(op.alu_op, modified, a, b); case AluComponent::MUL: return (w_operation) ? mul32_operate(op.mul_op, a, b) : mul64_operate(op.mul_op, a, b); case AluComponent::PASS: return a; default: qDebug("ERROR, unknown alu component: %hhx", uint8_t(component)); return 0; } } /** * Shift operations are limited to shift by 31 bits. * Other bits of the operand may be used as flags and need to be masked out * before any ALU operation is performed. */ constexpr uint64_t SHIFT_MASK32 = 0b011111; // == 31 constexpr uint64_t SHIFT_MASK64 = 0b111111; // == 63 int64_t alu64_operate(AluOp op, bool modified, RegisterValue a, RegisterValue b) { uint64_t _a = a.as_u64(); uint64_t _b = b.as_u64(); switch (op) { case AluOp::ADD: return _a + ((modified) ? -_b : _b); case AluOp::SLL: return _a << (_b & SHIFT_MASK64); case AluOp::SLT: return a.as_i64() < b.as_i64(); case AluOp::SLTU: return _a < _b; case AluOp::XOR: return _a ^ _b; // Most compilers should calculate SRA correctly, but it is UB. case AluOp::SR: return (modified) ? (a.as_i64() >> (_b & SHIFT_MASK64)) : (_a >> (_b & SHIFT_MASK64)); case AluOp::OR: return _a | _b; case AluOp::AND: return ((modified) ? ~_a : _a) & _b; // Modified: clear bits of b using mask // in a default: qDebug("ERROR, unknown alu operation: %hhx", uint8_t(op)); return 0; } } int32_t alu32_operate(AluOp op, bool modified, RegisterValue a, RegisterValue b) { uint32_t _a = a.as_u32(); uint32_t _b = b.as_u32(); switch (op) { case AluOp::ADD: return _a + ((modified) ? -_b : _b); case AluOp::SLL: return _a << (_b & SHIFT_MASK32); case AluOp::SLT: return a.as_i32() < b.as_i32(); case AluOp::SLTU: return _a < _b; case AluOp::XOR: return _a ^ _b; // Most compilers should calculate SRA correctly, but it is UB. case AluOp::SR: return (modified) ? (a.as_i32() >> (_b & SHIFT_MASK32)) : (_a >> (_b & SHIFT_MASK32)); case AluOp::OR: return _a | _b; case AluOp::AND: return ((modified) ? ~_a : _a) & _b; // Modified: clear bits of b using mask in a default: qDebug("ERROR, unknown alu operation: %hhx", uint8_t(op)); return 0; } } int64_t mul64_operate(MulOp op, RegisterValue a, RegisterValue b) { switch (op) { case MulOp::MUL: return a.as_u64() * b.as_u64(); case MulOp::MULH: return mulh64(a.as_i64(), b.as_i64()); case MulOp::MULHSU: return mulhsu64(a.as_i64(), b.as_u64()); case MulOp::MULHU: return mulhu64(a.as_u64(), b.as_u64()); case MulOp::DIV: if (b.as_i64() == 0) { return -1; // Division by zero is defined. } else if (a.as_i64() == INT64_MIN && b.as_i64() == -1) { return INT64_MIN; // Overflow. } else { return a.as_i64() / b.as_i64(); } case MulOp::DIVU: return (b.as_u64() == 0) ? UINT64_MAX // Division by zero is defined. : a.as_u64() / b.as_u64(); case MulOp::REM: if (b.as_i64() == 0) { return a.as_i64(); // Division by zero is defined. } else if (a.as_i64() == INT64_MIN && b.as_i64() == -1) { return 0; // Overflow. } else { return a.as_i64() % b.as_i64(); } case MulOp::REMU: return (b.as_u64() == 0) ? a.as_u64() // Division by zero reminder // is defined. : a.as_u64() % b.as_u64(); default: qDebug("ERROR, unknown multiplication operation: %hhx", uint8_t(op)); return 0; } } int32_t mul32_operate(MulOp op, RegisterValue a, RegisterValue b) { switch (op) { case MulOp::MUL: return a.as_u32() * b.as_u32(); case MulOp::MULH: return ((uint64_t)a.as_i32() * (uint64_t)b.as_i32()) >> 32; case MulOp::MULHSU: return ((uint64_t)a.as_i32() * (uint64_t)b.as_u32()) >> 32; case MulOp::MULHU: return ((uint64_t)a.as_u32() * (uint64_t)b.as_u32()) >> 32; case MulOp::DIV: if (b.as_i32() == 0) { return -1; // Division by zero is defined. } else if (a.as_i32() == INT32_MIN && b.as_i32() == -1) { return INT32_MIN; // Overflow. } else { return a.as_i32() / b.as_i32(); } case MulOp::DIVU: return (b.as_u32() == 0) ? UINT32_MAX // Division by zero is defined. : a.as_u32() / b.as_u32(); case MulOp::REM: if (b.as_i32() == 0) { return a.as_i32(); // Division by zero is defined. } else if (a.as_i32() == INT32_MIN && b.as_i32() == -1) { return 0; // Overflow. } else { return a.as_i32() % b.as_i32(); } case MulOp::REMU: return (b.as_u32() == 0) ? a.as_u32() // Division by zero reminder // is defined. : a.as_u32() % b.as_u32(); default: qDebug("ERROR, unknown multiplication operation: %hhx", uint8_t(op)); return 0; } } } // namespace machine qtrvsim-0.9.8/src/machine/execute/alu.h000066400000000000000000000074541467752164200200540ustar00rootroot00000000000000#ifndef ALU_H #define ALU_H #include "execute/alu_op.h" #include "execute/mul_op.h" #include "register_value.h" #include namespace machine { /** * Components available in combined ALU. */ enum class AluComponent { ALU, //> RV32/64I MUL, //> RV32/64M PASS, //> Pass operand A without change (used for AMO) }; union AluCombinedOp { AluOp alu_op; MulOp mul_op; }; /** * Dispatcher for specialised ALUs * * @param op alu and mul operands are isomorphic * @param component specifies which specialization to use * @param w_operation word operation false=64b, true=32b * @param modified see alu64/32 * @param a operand 1 * @param b operand 2 * @return result of specified ALU operation (always, no traps) */ [[gnu::const]] RegisterValue alu_combined_operate( AluCombinedOp op, AluComponent component, bool w_operation, bool modified, RegisterValue a, RegisterValue b); /** * RV64I for OP and OP-IMM instructions * * ALU conforming to Base Integer Instruction Set, Version 2.0. * * @param op operation specifier (funct3 in instruction) * @param modified modifies behavior of ADD (to SUB) and SRL (to SRA) * encoded by bit 30 if applicable * @param a operand 1 * @param b operand 2 * @return result of specified ALU operation (always, no traps) * integer type is returned to ensure correct signe extension * to arbitrary implementation of RegisterValue */ [[gnu::const]] int64_t alu64_operate(AluOp op, bool modified, RegisterValue a, RegisterValue b); /** * RV32I for OP and OP-IMM instructions and RV64I OP-32 and OP-IMM-32 * * ALU conforming to Base Integer Instruction Set, Version 2.0. * * @param op operation specifier (funct3 in instruction) * @param modified modifies behavior of ADD (to SUB) and SRL (to SRA) * encoded by bit 30 if applicable * @param a operand 1 * @param b operand 2 * @return result of specified ALU operation (always, no traps) * integer type is returned to ensure correct signe extension * to arbitrary implementation of RegisterValue */ [[gnu::const]] int32_t alu32_operate(AluOp op, bool modified, RegisterValue a, RegisterValue b); /** * RV64 "M" for OP instructions * * Multiplier conforming to Standard Extension for Integer Multiplication and * Division, Version 2.0. * * Implements operation for instructions: MUL, MUL[[S]H], DIV[U], REM[U]. * Division by zero is defined §7.2 table 7.1 (or see implementation). * * @param op operation specifier (funct3 in the instruction) * @param a operand 1 * @param b operand 2 * @return result of specified operation (always, no traps) * integer type is returned to ensure correct signe extension * to arbitrary implementation of RegisterValue */ [[gnu::const]] int64_t mul64_operate(MulOp op, RegisterValue a, RegisterValue b); /** * RV32 "M" for OP instructions and RV64 "M" for OP-32 instructions * * Multiplier conforming to Standard Extension for Integer Multiplication and * Division, Version 2.0. * * Implements operation for instructions: * RV32: MUL, MUL[[S]H]W, DIV[U]W, REM[U]W. * RV64: MULW, MUL[[S]H]W, DIV[U], REM[U]. * * Division by zero is defined §7.2 table 7.1 (or see implementation). * * @param op operation specifier (funct3 in the instruction) * @param a operand 1 * @param b operand 2 * @return result of specified operation (always, no traps) * integer type is returned to ensure correct signe extension * to arbitrary implementation of RegisterValue */ [[gnu::const]] int32_t mul32_operate(MulOp op, RegisterValue a, RegisterValue b); } // namespace machine #endif // ALU_H qtrvsim-0.9.8/src/machine/execute/alu.test.cpp000066400000000000000000000251761467752164200213660ustar00rootroot00000000000000#include "alu.h" #include "alu.test.h" #include "common/polyfills/mulh64.h" #include #include using namespace machine; void TestAlu::test_alu64_operate_data() { QTest::addColumn("op"); QTest::addColumn("modified"); QTest::addColumn("operand_a"); QTest::addColumn("operand_b"); QTest::addColumn("result"); QTest::addRow("ADD") << AluOp::ADD << false << int64_t(0xFFFFFFFFFFFFFFFFULL) << int64_t(1) << int64_t(0); QTest::addRow("ADD") << AluOp::ADD << false << int64_t(123) << int64_t(123000) << int64_t(123123); QTest::addRow("SUB") << AluOp::ADD << true << int64_t(123123) << int64_t(123000) << int64_t(123); QTest::addRow("SLT") << AluOp::SLT << false << int64_t(123123) << int64_t(123000) << int64_t(0); QTest::addRow("SLT") << AluOp::SLT << false << int64_t(-123123) << int64_t(123000) << int64_t(1); QTest::addRow("SLTU") << AluOp::SLTU << false << int64_t(-123123) << int64_t(123000) << int64_t(0); QTest::addRow("SLTU") << AluOp::SLTU << false << int64_t(123123) << int64_t(123000000) << int64_t(1); QTest::addRow("XOR") << AluOp::XOR << false << int64_t(0xFFFFFFFF00000000ULL) << int64_t(0xFFFFFFFFFFFFFFFFULL) << int64_t(0x00000000FFFFFFFFULL); QTest::addRow("OR") << AluOp::OR << false << int64_t(0xFFFFFFFF00000000ULL) << int64_t(0xFFFFFFFFFFFFFFFFULL) << int64_t(0xFFFFFFFFFFFFFFFFULL); QTest::addRow("AND") << AluOp::AND << false << int64_t(0xFFFFFFFF00000000ULL) << int64_t(0xFFFFFFFFFFFFFFFFULL) << int64_t(0xFFFFFFFF00000000ULL); QTest::addRow("SRL") << AluOp::SR << false << int64_t(0xFFFFFFFF00000000ULL) << int64_t(0xFFFFFFFF00000010ULL) << int64_t(0x0000FFFFFFFF0000ULL); QTest::addRow("SRA") << AluOp::SR << true << int64_t(0xFFFFFFFF00000000ULL) << int64_t(0xFFFFFFFF00000010ULL) << int64_t(0xFFFFFFFFFFFF0000ULL); } void TestAlu::test_alu64_operate() { QFETCH(AluOp, op); QFETCH(bool, modified); QFETCH(int64_t, operand_a); QFETCH(int64_t, operand_b); QFETCH(int64_t, result); // Test unit itself. QCOMPARE(alu64_operate(op, modified, operand_a, operand_b), result); // Test that combined wrapper does not break anything. QCOMPARE( alu_combined_operate( { .alu_op = op }, AluComponent::ALU, false, modified, operand_a, operand_b), RegisterValue(result)); } void TestAlu::test_alu32_operate_data() { QTest::addColumn("op"); QTest::addColumn("modified"); QTest::addColumn("operand_a"); QTest::addColumn("operand_b"); QTest::addColumn("result"); QTest::addRow("ADD") << AluOp::ADD << false << int32_t(0xFFFFFFFF) << int32_t(1) << int32_t(0); QTest::addRow("ADD") << AluOp::ADD << false << int32_t(123) << int32_t(123000) << int32_t(123123); QTest::addRow("SUB") << AluOp::ADD << true << int32_t(123123) << int32_t(123000) << int32_t(123); QTest::addRow("SLT") << AluOp::SLT << false << int32_t(123123) << int32_t(123000) << int32_t(0); QTest::addRow("SLT") << AluOp::SLT << false << int32_t(-123123) << int32_t(123000) << int32_t(1); QTest::addRow("SLTU") << AluOp::SLTU << false << int32_t(-123123) << int32_t(123000) << int32_t(0); QTest::addRow("SLTU") << AluOp::SLTU << false << int32_t(123123) << int32_t(123000000) << int32_t(1); QTest::addRow("XOR") << AluOp::XOR << false << int32_t(0xFFFF0000) << int32_t(0xFFFFFFFF) << int32_t(0x0000FFFF); QTest::addRow("OR") << AluOp::OR << false << int32_t(0xFFFF0000) << int32_t(0xFFFFFFFF) << int32_t(0xFFFFFFFF); QTest::addRow("AND") << AluOp::AND << false << int32_t(0xFFFF0000) << int32_t(0xFFFFFFFF) << int32_t(0xFFFF0000); QTest::addRow("SRL") << AluOp::SR << false << int32_t(0xFFFF0000) << int32_t(0xFFFF0010) << int32_t(0x0000FFFF); QTest::addRow("SRA") << AluOp::SR << true << int32_t(0xFFFF0000) << int32_t(0xFFFF0010) << int32_t(0xFFFFFFFF); } void TestAlu::test_alu32_operate() { QFETCH(AluOp, op); QFETCH(bool, modified); QFETCH(int32_t, operand_a); QFETCH(int32_t, operand_b); QFETCH(int32_t, result); // Test unit itself. QCOMPARE(alu32_operate(op, modified, operand_a, operand_b), result); // Test that combined wrapper does not break anything. QCOMPARE( alu_combined_operate( { .alu_op = op }, AluComponent::ALU, true, modified, operand_a, operand_b), RegisterValue(result)); } // TODO evaluate the results and inline as literals. constexpr std::array, 6> inputs = { { { 1, 1 }, { 2, 1 }, { 2, 2 }, { 123456789, 666 }, { 123456789, -7777 }, { -1, 8888 }, } }; void TestAlu::test_mul64_operate_data() { QTest::addColumn("op"); QTest::addColumn("operand_a"); QTest::addColumn("operand_b"); QTest::addColumn("result"); for (auto input : inputs) { int64_t a = std::get<0>(input); int64_t b = std::get<1>(input); QTest::addRow("MUL") << MulOp::MUL << a << b << a * b; QTest::addRow("MULH") << MulOp::MULH << a << b << int64_t(mulh64(a, b)); QTest::addRow("MULHU") << MulOp::MULHU << a << b << int64_t(mulhu64(a, b)); QTest::addRow("MULHSU") << MulOp::MULHSU << a << b << int64_t(mulhsu64(a, b)); QTest::addRow("DIV") << MulOp::DIV << a << b << a / b; QTest::addRow("DIVU") << MulOp::DIVU << a << b << int64_t(uint64_t(a) / uint64_t(b)); QTest::addRow("REM") << MulOp::REM << a << b << (a % b); QTest::addRow("REMU") << MulOp::REMU << a << b << int64_t(uint64_t(a) % uint64_t(b)); } // Defined edge cases for division QTest::addRow("division by zero signed") << MulOp::DIV << int64_t(42) << int64_t(0) << int64_t(-1); QTest::addRow("division by zero unsigned") << MulOp::DIVU << int64_t(128) << int64_t(0) << int64_t(UINT64_MAX); QTest::addRow("division by zero reminder signed") << MulOp::REM << int64_t(666) << int64_t(0) << int64_t(666); QTest::addRow("division by zero reminder unsigned") << MulOp::REMU << int64_t(777) << int64_t(0) << int64_t(777); QTest::addRow("zero division by zero signed") << MulOp::DIV << int64_t(0) << int64_t(0) << int64_t(-1); QTest::addRow("zero division by zero unsigned") << MulOp::DIVU << int64_t(0) << int64_t(0) << int64_t(UINT64_MAX); QTest::addRow("zero division by zero reminder signed") << MulOp::REM << int64_t(0) << int64_t(0) << (int64_t)0; QTest::addRow("zero division by zero reminder unsigned") << MulOp::REMU << int64_t(0) << int64_t(0) << (int64_t)0; QTest::addRow("division overflow") << MulOp::DIV << int64_t(INT64_MIN) << int64_t(-1) << INT64_MIN; QTest::addRow("division reminder overflow") << MulOp::REM << int64_t(INT64_MAX) << int64_t(-1) << int64_t(0); } void TestAlu::test_mul64_operate() { QFETCH(MulOp, op); QFETCH(int64_t, operand_a); QFETCH(int64_t, operand_b); QFETCH(int64_t, result); // Test unit itself. QCOMPARE(mul64_operate(op, operand_a, operand_b), result); // Test that combined wrapper does not break anything. QCOMPARE( alu_combined_operate( (AluCombinedOp) { .mul_op = op }, AluComponent::MUL, false, false, operand_a, operand_b), RegisterValue(result)); } /** * Helper function for upper bits of 32 bit multiplication. * Sign extension is handled on caller side. */ constexpr int32_t mulh32(uint64_t a, uint64_t b) { return (a * b) >> 32; } void TestAlu::test_mul32_operate_data() { QTest::addColumn("op"); QTest::addColumn("operand_a"); QTest::addColumn("operand_b"); QTest::addColumn("result"); for (auto input : inputs) { int32_t a = std::get<0>(input); int32_t b = std::get<1>(input); QTest::addRow("MUL") << MulOp::MUL << a << b << a * b; QTest::addRow("MULH") << MulOp::MULH << a << b << int32_t(mulh32(a, b)); QTest::addRow("MULHU") << MulOp::MULHU << a << b << int32_t(mulh32(uint32_t(a), uint32_t(b))); QTest::addRow("MULHSU") << MulOp::MULHSU << a << b << int32_t(mulh32(a, uint32_t(b))); QTest::addRow("DIV") << MulOp::DIV << a << b << a / b; QTest::addRow("DIVU") << MulOp::DIVU << a << b << int32_t(uint32_t(a) / uint32_t(b)); QTest::addRow("REM") << MulOp::REM << a << b << (a % b); QTest::addRow("REMU") << MulOp::REMU << a << b << int32_t(uint32_t(a) % uint32_t(b)); } // Defined edge cases for division QTest::addRow("division by zero signed") << MulOp::DIV << int32_t(42) << int32_t(0) << int32_t(-1); QTest::addRow("division by zero unsigned") << MulOp::DIVU << int32_t(128) << int32_t(0) << int32_t(UINT32_MAX); QTest::addRow("division by zero reminder signed") << MulOp::REM << int32_t(666) << int32_t(0) << int32_t(666); QTest::addRow("division by zero reminder unsigned") << MulOp::REMU << int32_t(777) << int32_t(0) << int32_t(777); QTest::addRow("zero division by zero signed") << MulOp::DIV << int32_t(0) << int32_t(0) << int32_t(-1); QTest::addRow("zero division by zero unsigned") << MulOp::DIVU << int32_t(0) << int32_t(0) << int32_t(UINT32_MAX); QTest::addRow("zero division by zero reminder signed") << MulOp::REM << int32_t(0) << int32_t(0) << (int32_t)0; QTest::addRow("zero division by zero reminder unsigned") << MulOp::REMU << int32_t(0) << int32_t(0) << (int32_t)0; QTest::addRow("division overflow") << MulOp::DIV << int32_t(INT32_MIN) << int32_t(-1) << INT32_MIN; QTest::addRow("division reminder overflow") << MulOp::REM << int32_t(INT32_MAX) << int32_t(-1) << int32_t(0); } void TestAlu::test_mul32_operate() { QFETCH(MulOp, op); QFETCH(int32_t, operand_a); QFETCH(int32_t, operand_b); QFETCH(int32_t, result); // Test unit itself. QCOMPARE(mul32_operate(op, operand_a, operand_b), result); // Test that combined wrapper does not break anything. QCOMPARE( alu_combined_operate( (AluCombinedOp) { .mul_op = op }, AluComponent::MUL, true, false, operand_a, operand_b), RegisterValue(result)); } QTEST_APPLESS_MAIN(TestAlu)qtrvsim-0.9.8/src/machine/execute/alu.test.h000066400000000000000000000007241467752164200210230ustar00rootroot00000000000000#ifndef ALU_TEST_H #define ALU_TEST_H #include class TestAlu : public QObject { Q_OBJECT private slots: static void test_alu64_operate_data(); static void test_alu64_operate(); static void test_alu32_operate_data(); static void test_alu32_operate(); static void test_mul64_operate_data(); static void test_mul64_operate(); static void test_mul32_operate_data(); static void test_mul32_operate(); }; #endif // ALU_TEST_H qtrvsim-0.9.8/src/machine/execute/alu_op.h000066400000000000000000000005271467752164200205440ustar00rootroot00000000000000#ifndef ALU_OP_H #define ALU_OP_H #include #include using std::uint8_t; namespace machine { enum class AluOp : uint8_t { ADD = 0b000, SLL = 0b001, SLT = 0b010, SLTU = 0b011, XOR = 0b100, SR = 0b101, OR = 0b110, AND = 0b111, }; } Q_DECLARE_METATYPE(machine::AluOp) #endif // ALU_OP_H qtrvsim-0.9.8/src/machine/execute/mul_op.h000066400000000000000000000004711467752164200205560ustar00rootroot00000000000000#ifndef MUL_OP_H #define MUL_OP_H #include namespace machine { enum class MulOp : uint8_t { MUL = 0b000, MULH = 0b001, MULHSU = 0b010, MULHU = 0b011, DIV = 0b100, DIVU = 0b101, REM = 0b110, REMU = 0b111, }; } Q_DECLARE_METATYPE(machine::MulOp) #endif // MUL_OP_H qtrvsim-0.9.8/src/machine/instruction.cpp000066400000000000000000001755431467752164200205520ustar00rootroot00000000000000#include "instruction.h" #include "common/logging.h" #include "common/math/bit_ops.h" #include "common/string_utils.h" #include "csr/controlstate.h" #include "simulator_exception.h" #include "utils.h" #include #include #include #include #include #include #include #include LOG_CATEGORY("machine.instruction"); using namespace machine; using std::underlying_type; namespace machine { } struct ArgumentDesc { char name; /** * Possible values: * @val g: gp register id * @val n: numeric immediate * @val a: pc relative address offset * @val b: pc relative address offset * @val o: offset immediate */ char kind; int64_t min; int64_t max; BitArg arg; inline ArgumentDesc(char name, char kind, int64_t min, int64_t max, BitArg arg) : name(name) , kind(kind) , min(min) , max(max) , arg(arg) {} /** Check whether given value fits into this instruction field. */ [[nodiscard]] constexpr bool is_value_in_field_range(RegisterValue val) const { if (min < 0) { return val.as_i64() <= max && val.as_i64() >= min; } else { return val.as_u64() <= static_cast(max) && val.as_u64() >= static_cast(min); } } [[nodiscard]] constexpr bool is_imm() const { return kind != 'g'; } }; static const ArgumentDesc arg_desc_list[] = { // Destination register (rd) ArgumentDesc('d', 'g', 0, 0x1f, { { { 5, 7 } }, 0 }), // Source register 1 (rs1/rs) ArgumentDesc('s', 'g', 0, 0x1f, { { { 5, 15 } }, 0 }), // Source register 2 (rs2/rt) ArgumentDesc('t', 'g', 0, 0x1f, { { { 5, 20 } }, 0 }), // I-type immediate for arithmetic instructions (12bits) ArgumentDesc('j', 'n', -0x800, 0x7ff, { { { 12, 20 } }, 0 }), // Shift for bit shift instructions (5bits) ArgumentDesc('>', 'n', 0, 0x1f, { { { 5, 20 } }, 0 }), // Address offset immediate (20bits), encoded in multiples of 2 bytes ArgumentDesc('a', 'a', -0x80000, 0x7ffff, { { { 10, 21 }, { 1, 20 }, { 8, 12 }, { 1, 31 } }, 1 }), // U-type immediate for LUI and AUIPC (20bits) ArgumentDesc('u', 'n', 0, 0xfffff000, { { { 20, 12 } }, 0 }), // B-type immediate for branches (12 bits) ArgumentDesc('p', 'p', -0x1000, 0x0fff, { { { 4, 8 }, { 6, 25 }, { 1, 7 }, { 1, 31 } }, 1 }), // Offset immediate for load instructions (12 bits) ArgumentDesc('o', 'o', -0x800, 0x7ff, { { { 12, 20 } }, 0 }), // Offset immediate for store instructions (12 bits) ArgumentDesc('q', 'o', -0x800, 0x7ff, { { { 5, 7 }, { 7, 25 } }, 0 }), // 5-bit CSR value immediate // (https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=opcodes/riscv-opc.c;h=7e95f645c5c5fe0a7c93c64c2f1719efaec67972;hb=HEAD#l928) ArgumentDesc('Z', 'n', 0, 0x1f, { { { 5, 15 } }, 0 }), // 12-bit CSR address // (https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=opcodes/riscv-opc.c;h=7e95f645c5c5fe0a7c93c64c2f1719efaec67972;hb=HEAD#l928) ArgumentDesc('E', 'E', 0, 0xfff, { { { 12, 20 } }, 0 }), }; static const ArgumentDesc *arg_desc_by_code[(int)('z' + 1)]; static bool fill_argdesbycode() { for (const auto &desc : arg_desc_list) { arg_desc_by_code[(uint)(unsigned char)desc.name] = &desc; } return true; } bool argdesbycode_filled = fill_argdesbycode(); #define FLAGS_ALU_I (IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_ALU_REQ_RS) #define FLAGS_ALU_I_LOAD \ (IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM | IMF_ALU_REQ_RS) #define FLAGS_ALU_I_STORE \ (IMF_SUPPORTED | IMF_ALUSRC | IMF_MEMWRITE | IMF_MEM | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT) #define FLAGS_ALU_T_R_D (IMF_SUPPORTED | IMF_REGWRITE) #define FLAGS_ALU_T_R_STD (FLAGS_ALU_T_R_D | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT) #define FLAGS_AMO_LOAD (FLAGS_ALU_I_LOAD | IMF_AMO) // FLAGS_AMO_STORE for store conditional requires IMF_MEMREAD to ensure stalling because // forwarding is not possible from memory stage after memory read, TODO to solve better way #define FLAGS_AMO_STORE (FLAGS_ALU_I_STORE | FLAGS_ALU_T_R_D | IMF_AMO | IMF_MEMREAD) #define FLAGS_AMO_MODIFY (FLAGS_ALU_I_LOAD | FLAGS_AMO_STORE | IMF_AMO) #define NOALU \ { .alu_op = AluOp::ADD } #define NOMEM .mem_ctl = AC_NONE // TODO NOTE: if unknown is defined as all 0, instruction map can be significantly simplified // using zero initialization. #define IM_UNKNOWN \ { "unknown", Instruction::UNKNOWN, NOALU, NOMEM, nullptr, {}, 0, 0, { 0 }, nullptr } struct InstructionMap { const char *name; Instruction::Type type = Instruction::UNKNOWN; AluCombinedOp alu = { .alu_op = AluOp::ADD }; AccessControl mem_ctl = AC_NONE; const struct InstructionMap *subclass = nullptr; // when subclass is used then flags // has special meaning const cvector args; uint32_t code; uint32_t mask; union { decltype(underlying_type::type()) flags; BitField subfield; }; const InstructionMap *aliases = nullptr; }; #define IT_R Instruction::R #define IT_I Instruction::I #define IT_S Instruction::S #define IT_B Instruction::B #define IT_U Instruction::U #define IT_J Instruction::J #define IT_AMO Instruction::AMO #define IT_ZICSR Instruction::ZICSR #define IT_UNKNOWN Instruction::UNKNOWN // clang-format off // alliases for instructions for internal assembler and possibly // disassembler if simplified format is requested. // They are not used during decoding and execution #define INST_ALIAS_LIST_END {.name = nullptr, .args = {}, .code = 0 , .mask = 0, .flags = 0 } static const struct InstructionMap inst_aliases_addi[] = { { .name = "mv", .args = {"d", "s"}, .code = 0x13, .mask = 0x707f | (0xffful << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_andi[] = { { .name = "zext.b", .args = {"d", "s"}, .code = 0x7013 | (0xfful << 20), .mask = 0x707f | (0xffful << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_addiw[] = { { .name = "sext.w", .args = {"d", "s"}, .code = 0x1b, .mask = 0x707f | (0xffful << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_xori[] = { { .name = "not", .args = {"d", "s"}, .code = 0x4013 | (0xffful << 20), .mask = 0x707f | (0xffful << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_sub[] = { { .name = "neg", .args = {"d", "t"}, .code = 0x40000033 | (0 << 15), .mask = 0xfe00707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_subw[] = { { .name = "negw", .args = {"d", "t"}, .code = 0x4000003b | (0 << 15), .mask = 0xfe00707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_sltiu[] = { { .name = "seqz", .args = {"d", "s"}, .code = 0x3013| (1 << 20), .mask = 0x0000707f | (0xffful << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_sltu[] = { { .name = "snez", .args = {"d", "t"}, .code = 0x3033 | (0 << 15), .mask = 0xfe00707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_slt[] = { { .name = "sltz", .args = {"d", "s"}, .code = 0x2033 | (0 << 20), .mask = 0xfe00707f | (31 << 20), .flags = IMF_SUPPORTED }, { .name = "sgtz", .args = {"d", "t"}, .code = 0x2033 | (0 << 15), .mask = 0xfe00707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_beq[] = { //0x00000063,0x0000707f { .name = "beqz", .args = {"s", "p"}, .code = 0x0063 | (0 << 20), .mask = 0x707f | (31 << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_bne[] = { //0x00001063, 0x0000707f { .name = "bnez", .args = {"s", "p"}, .code = 0x1063 | (0 << 20), .mask = 0x707f | (31 << 20), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_blt[] = { //0x00004063, 0x0000707f { .name = "bltz", .args = {"s", "p"}, .code = 0x4063 | (0 << 20), .mask = 0x707f | (31 << 20), .flags = IMF_SUPPORTED }, { .name = "bgtz", .args = {"t", "p"}, .code = 0x4063 | (0 << 15), .mask = 0x707f | (31 << 15), .flags = IMF_SUPPORTED }, { .name = "bgt", .args = {"t", "s", "p"}, .code = 0x4063, .mask = 0x707f, .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_bge[] = { //0x00005063,0x0000707f { .name = "bgez", .args = {"s", "p"}, .code = 0x5063 | (0 << 20), .mask = 0x707f | (31 << 20), .flags = IMF_SUPPORTED }, { .name = "ble", .args = {"t", "s", "p"}, .code = 0x5063, .mask = 0x707f, .flags = IMF_SUPPORTED }, { .name = "blez", .args = {"t", "p"}, .code = 0x5063 | (0 << 15), .mask = 0x707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_bltu[] = { //0x00006063, 0x0000707f { .name = "bgtu", .args = {"t", "s", "p"}, .code = 0x6063, .mask = 0x707f, .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_bgeu[] = { //0x00007063,0x0000707f { .name = "bleu", .args = {"t", "s", "p"}, .code = 0x7063, .mask = 0x707f, .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_jal[] = { { .name = "j", .args = {"a"}, .code = 0x6f | (0 << 7) , .mask = 0x7f | (31 << 7), .flags = IMF_SUPPORTED }, { .name = "jal", .args = {"a"}, .code = 0x6f | (1 << 7) , .mask = 0x7f | (31 << 7), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_jalr[] = { { .name = "ret", .args = {}, .code = 0x67 | (0 << 7) | (1 << 15) , .mask = 0xfffffffful, .flags = IMF_SUPPORTED }, { .name = "jr", .args = {"s"}, .code = 0x67 | (0 << 7) , .mask = 0x7f | (31 << 7) | (0xffful << 20), .flags = IMF_SUPPORTED }, { .name = "jr", .args = {"o(s)"}, .code = 0x67 | (0 << 7) , .mask = 0x7f | (31 << 7), .flags = IMF_SUPPORTED }, { .name = "jalr", .args = {"s"}, .code = 0x67 | (1 << 7) , .mask = 0x7f | (31 << 7) | (0xffful << 20), .flags = IMF_SUPPORTED }, { .name = "jalr", .args = {"o(s)"}, .code = 0x67 | (1 << 7) , .mask = 0x7f | (31 << 7), .flags = IMF_SUPPORTED }, { .name = "jalr", .args = {"d", "s", "o"}, .code = 0x67, .mask = 0x7f, .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_csrrw[] = { { .name = "csrw", .args = {"E", "s"}, .code = 0x1073 | (0 << 7) | (0 << 15) , .mask = 0x707f | (31 << 7), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; static const struct InstructionMap inst_aliases_csrrs[] = { { .name = "csrr", .args = {"d", "E"}, .code = 0x2073 | (0 << 15) , .mask = 0x707f | (31 << 15), .flags = IMF_SUPPORTED }, INST_ALIAS_LIST_END, }; // RV32/64A - Atomi Memory Operations #define AMO_ARGS_LOAD {"d", "(s)"} #define AMO_ARGS_STORE {"d", "t", "(s)"} #define AMO_ARGS_MODIFY {"d", "t", "(s)"} #define AMO_MAP_4ITEMS(NAME_BASE, CODE_BASE, MASK, MEM_CTL, FLAGS, ARGS) \ { NAME_BASE, IT_AMO, NOALU, MEM_CTL, nullptr, ARGS , ((CODE_BASE) | 0x00000000), 0xfe00707f, { .flags = FLAGS}, nullptr}, \ { NAME_BASE ".rl", IT_AMO, NOALU, MEM_CTL, nullptr, ARGS , ((CODE_BASE) | 0x02000000), 0xfe00707f, { .flags = FLAGS}, nullptr}, \ { NAME_BASE ".aq", IT_AMO, NOALU, MEM_CTL, nullptr, ARGS , ((CODE_BASE) | 0x04000000), 0xfe00707f, { .flags = FLAGS}, nullptr}, \ { NAME_BASE ".aqrl", IT_AMO, NOALU, MEM_CTL, nullptr, ARGS , ((CODE_BASE) | 0x06000000), 0xfe00707f, { .flags = FLAGS}, nullptr} static const struct InstructionMap AMO_32_map[] = { AMO_MAP_4ITEMS("amoadd.w", 0x0000202f, 0xfe00707f, AC_AMOADD32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), AMO_MAP_4ITEMS("amoswap.w", 0x0800202f, 0xfe00707f, AC_AMOSWAP32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), AMO_MAP_4ITEMS("lr.w", 0x1000202f, 0xfff0707f, AC_LR32, FLAGS_AMO_LOAD, AMO_ARGS_LOAD), AMO_MAP_4ITEMS("sc.w", 0x1800202f, 0xfe00707f, AC_SC32, FLAGS_AMO_STORE, AMO_ARGS_STORE), AMO_MAP_4ITEMS("amoxor.w", 0x2000202f, 0xfe00707f, AC_AMOXOR32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amoor.w", 0x4000202f, 0xfe00707f, AC_AMOOR32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amoand.w", 0x6000202f, 0xfe00707f, AC_AMOAND32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomin.w", 0x8000202f, 0xfe00707f, AC_AMOMIN32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomax.w", 0xa000202f, 0xfe00707f, AC_AMOMAX32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amominu.w", 0xc000202f, 0xfe00707f, AC_AMOMINU32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomaxu.w", 0xe000202f, 0xfe00707f, AC_AMOMAXU32, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; static const struct InstructionMap AMO_64_map[] = { AMO_MAP_4ITEMS("amoadd.d", 0x0000302f, 0xfe00707f, AC_AMOADD64, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), AMO_MAP_4ITEMS("amoswap.d", 0x0800302f, 0xfe00707f, AC_AMOSWAP64, FLAGS_AMO_MODIFY, AMO_ARGS_MODIFY), AMO_MAP_4ITEMS("lr.d", 0x1000302f, 0xfff0707f, AC_LR64, FLAGS_AMO_LOAD, AMO_ARGS_LOAD), AMO_MAP_4ITEMS("sc.d", 0x1800302f, 0xfe00707f, AC_SC64, FLAGS_AMO_STORE, AMO_ARGS_STORE), AMO_MAP_4ITEMS("amoxor.d", 0x2000302f, 0xfe00707f, AC_AMOXOR64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amoor.d", 0x4000302f, 0xfe00707f, AC_AMOOR64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amoand.d", 0x6000302f, 0xfe00707f, AC_AMOAND64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomin.d", 0x8000302f, 0xfe00707f, AC_AMOMIN64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomax.d", 0xa000302f, 0xfe00707f, AC_AMOMAX64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amominu.d", 0xc000302f, 0xfe00707f, AC_AMOMINU64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, AMO_MAP_4ITEMS("amomaxu.d", 0xe000302f, 0xfe00707f, AC_AMOMAXU64, FLAGS_AMO_MODIFY | IMF_RV64, AMO_ARGS_MODIFY), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; static const struct InstructionMap AMO_map[] = { IM_UNKNOWN, IM_UNKNOWN, {"amo-32", IT_R, NOALU, NOMEM, AMO_32_map, {}, 0x0002027, 0x0000707f, { .subfield = {7, 25} }, nullptr}, // OP-32 {"amo-64", IT_R, NOALU, NOMEM, AMO_64_map, {}, 0x0003027, 0x0000707f, { .subfield = {7, 25} }, nullptr}, // OP-32 IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; #undef AMO_MAP_4ITEMS static const struct InstructionMap LOAD_map[] = { {"lb", IT_I, { .alu_op=AluOp::ADD }, AC_I8, nullptr, {"d", "o(s)"}, 0x00000003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD }, nullptr}, // LB {"lh", IT_I, { .alu_op=AluOp::ADD }, AC_I16, nullptr, {"d", "o(s)"}, 0x00001003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD }, nullptr}, // LH {"lw", IT_I, { .alu_op=AluOp::ADD }, AC_I32, nullptr, {"d", "o(s)"}, 0x00002003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD }, nullptr}, // LW {"ld", IT_I, { .alu_op=AluOp::ADD }, AC_I64, nullptr, {"d", "o(s)"}, 0x00003003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD | IMF_RV64}, nullptr}, // LD {"lbu", IT_I, { .alu_op=AluOp::ADD }, AC_U8, nullptr, {"d", "o(s)"}, 0x00004003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD }, nullptr}, // LBU {"lhu", IT_I, { .alu_op=AluOp::ADD }, AC_U16, nullptr, {"d", "o(s)"}, 0x00005003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD }, nullptr}, // LHU {"lwu", IT_I, { .alu_op=AluOp::ADD }, AC_U32, nullptr, {"d", "o(s)"}, 0x00006003,0x0000707f, { .flags = FLAGS_ALU_I_LOAD | IMF_RV64}, nullptr}, // LWU IM_UNKNOWN, }; static const struct InstructionMap SRI_map[] = { // 0xfe00707f mask changed to 0xfc00707f to support RV64I {"srli", IT_I, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", ">"}, 0x00005013,0xfc00707f, { .flags = FLAGS_ALU_I }, nullptr}, // SRLI {"srai", IT_I, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", ">"}, 0x40005013,0xfc00707f, { .flags = (FLAGS_ALU_I | IMF_ALU_MOD) }, nullptr}, // SRAI }; static const struct InstructionMap OP_IMM_map[] = { {"addi", IT_I, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "j"}, 0x00000013,0x0000707f, { .flags = FLAGS_ALU_I }, inst_aliases_addi}, // ADDI {"slli", IT_I, { .alu_op=AluOp::SLL }, NOMEM, nullptr, {"d", "s", ">"}, 0x00001013,0xfc00707f, { .flags = FLAGS_ALU_I }, nullptr}, // SLLI {"slti", IT_I, { .alu_op=AluOp::SLT }, NOMEM, nullptr, {"d", "s", "j"}, 0x00002013,0x0000707f, { .flags = FLAGS_ALU_I }, nullptr}, // SLTI {"sltiu", IT_I, { .alu_op=AluOp::SLTU }, NOMEM, nullptr, {"d", "s", "j"}, 0x00003013,0x0000707f, { .flags = FLAGS_ALU_I }, inst_aliases_sltiu}, // SLTIU {"xori", IT_I, { .alu_op=AluOp::XOR }, NOMEM, nullptr, {"d", "s", "j"}, 0x00004013,0x0000707f, { .flags = FLAGS_ALU_I }, inst_aliases_xori}, // XORI {"sri", IT_I, NOALU, NOMEM, SRI_map, {}, 0x00005013, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, // SRLI, SRAI {"ori", IT_I, { .alu_op=AluOp::OR }, NOMEM, nullptr, {"d", "s", "j"}, 0x00006013,0x0000707f, { .flags = FLAGS_ALU_I }, nullptr}, // ORI {"andi", IT_I, { .alu_op=AluOp::AND }, NOMEM, nullptr, {"d", "s", "j"}, 0x00007013,0x0000707f, { .flags = FLAGS_ALU_I }, inst_aliases_andi}, // ANDI }; static const struct InstructionMap STORE_map[] = { {"sb", IT_S, { .alu_op=AluOp::ADD }, AC_U8, nullptr, {"t", "q(s)"}, 0x00000023, 0x0000707f, { .flags = FLAGS_ALU_I_STORE }, nullptr}, // SB {"sh", IT_S, { .alu_op=AluOp::ADD }, AC_U16, nullptr, {"t", "q(s)"}, 0x00001023, 0x0000707f, { .flags = FLAGS_ALU_I_STORE }, nullptr}, // SH {"sw", IT_S, { .alu_op=AluOp::ADD }, AC_U32, nullptr, {"t", "q(s)"}, 0x00002023, 0x0000707f, { .flags = FLAGS_ALU_I_STORE }, nullptr}, // SW {"sd", IT_S, { .alu_op=AluOp::ADD }, AC_U64, nullptr, {"t", "q(s)"}, 0x00003023, 0x0000707f, { .flags = FLAGS_ALU_I_STORE | IMF_RV64}, nullptr}, // SD IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; static const struct InstructionMap ADD_map[] = { {"add", IT_R, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "t"}, 0x00000033, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, {"sub", IT_R, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "t"}, 0x40000033, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_ALU_MOD }, inst_aliases_sub}, }; static const struct InstructionMap SR_map[] = { {"srl", IT_R, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", "t"}, 0x00005033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, // SRL {"sra", IT_R, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", "t"}, 0x40005033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_ALU_MOD }, nullptr}, // SRA }; static const struct InstructionMap OP_ALU_map[] = { {"add/sub", IT_R, NOALU, NOMEM, ADD_map, {}, 0x00000033, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, {"sll", IT_R, { .alu_op=AluOp::SLL }, NOMEM, nullptr, {"d", "s", "t"}, 0x00001033, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, // SLL {"slt", IT_R, { .alu_op=AluOp::SLT }, NOMEM, nullptr, {"d", "s", "t"}, 0x00002033, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, inst_aliases_slt}, // SLT {"sltu", IT_R, { .alu_op=AluOp::SLTU }, NOMEM, nullptr, {"d", "s", "t"}, 0x00003033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, inst_aliases_sltu}, // SLTU {"xor", IT_R, { .alu_op=AluOp::XOR }, NOMEM, nullptr, {"d", "s", "t"}, 0x00004033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, // XOR {"sr", IT_R, NOALU, NOMEM, SR_map, {}, 0x00005033, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, // SRL, SRA {"or", IT_R, { .alu_op=AluOp::OR }, NOMEM, nullptr, {"d", "s", "t"}, 0x00006033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, // OR {"and", IT_R, { .alu_op=AluOp::AND }, NOMEM, nullptr, {"d", "s", "t"}, 0x00007033,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD }, nullptr}, // AND }; // RV32M #define MUL_MAP_ITEM(NAME, OP, CODE) \ { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x02000033 | (CODE)), 0xfe00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL) }, nullptr} static const struct InstructionMap OP_MUL_map[] = { MUL_MAP_ITEM("mul", MulOp::MUL, 0x0000), MUL_MAP_ITEM("mulh", MulOp::MULH, 0x1000), MUL_MAP_ITEM("mulhsu", MulOp::MULHSU, 0x2000), MUL_MAP_ITEM("mulhu", MulOp::MULHU, 0x3000), MUL_MAP_ITEM("div", MulOp::DIV, 0x4000), MUL_MAP_ITEM("divu", MulOp::DIVU, 0x5000), MUL_MAP_ITEM("rem", MulOp::REM, 0x6000), MUL_MAP_ITEM("remu", MulOp::REMU, 0x7000), }; static const struct InstructionMap OP_map[] = { {"alu", IT_R, NOALU, NOMEM, OP_ALU_map, {}, 0x00000033, 0x0000707f, { .subfield = {3, 12} }, nullptr}, {"mul", IT_R, NOALU, NOMEM, OP_MUL_map, {}, 0x02000033, 0xfc00707f, { .subfield = {3, 12} }, nullptr}, }; static const struct InstructionMap BRANCH_map[] = { {"beq", IT_B, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"s", "t", "p"}, 0x00000063,0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT | IMF_ALU_MOD }, inst_aliases_beq}, // BEQ {"bne", IT_B, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"s", "t", "p"}, 0x00001063, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT | IMF_ALU_MOD | IMF_BJ_NOT }, inst_aliases_bne}, // BNE IM_UNKNOWN, IM_UNKNOWN, {"blt", IT_B, { .alu_op=AluOp::SLT }, NOMEM, nullptr, {"s", "t", "p"}, 0x00004063, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT | IMF_BJ_NOT }, inst_aliases_blt}, // BLT {"bge", IT_B, { .alu_op=AluOp::SLT }, NOMEM, nullptr, {"s", "t", "p"}, 0x00005063,0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT }, inst_aliases_bge}, // BGE {"bltu", IT_B, { .alu_op=AluOp::SLTU }, NOMEM, nullptr, {"s", "t", "p"}, 0x00006063, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT | IMF_BJ_NOT }, inst_aliases_bltu}, // BLTU {"bgeu", IT_B, { .alu_op=AluOp::SLTU }, NOMEM, nullptr, {"s", "t", "p"}, 0x00007063,0x0000707f, { .flags = IMF_SUPPORTED | IMF_BRANCH | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT }, inst_aliases_bgeu}, // BGEU }; // Spec vol. 1: 2.8 static const struct InstructionMap ENVIRONMENT_AND_BREAKPOINTS_map[] = { {"ecall", IT_I, NOALU, NOMEM, nullptr, {}, 0x00000073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_EXCEPTION | IMF_ECALL }, nullptr}, {"ebreak", IT_I, NOALU, NOMEM, nullptr, {}, 0x00100073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_EXCEPTION | IMF_EBREAK }, nullptr}, }; // Priviledged system isntructions, only 5-bits (29:25) are decoded for now. // Full decode is should cover 128 entries (31:25) but we radly support hypervisor even in future static const struct InstructionMap SYSTEM_PRIV_map[] = { {"environment_and_breakpoints", IT_I, NOALU, NOMEM, ENVIRONMENT_AND_BREAKPOINTS_map, {}, 0x00000073, 0xffffffff, { .subfield = {1, 20} }, nullptr}, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, {"sret", IT_I, NOALU, NOMEM, nullptr, {}, 0x10200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }, nullptr}, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, {"mret", IT_I, NOALU, NOMEM, nullptr, {}, 0x30200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }, nullptr}, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; #define CSR_MAP_ITEM(NAME, SOURCE, CODE, ALU_OP, EXTRA_FLAGS, ALIASES) \ { NAME, Instruction::ZICSR, { .alu_op=AluOp::ALU_OP }, NOMEM, nullptr, {"d", "E", SOURCE}, 0x00000073 | (CODE), 0x0000707f, { .flags = IMF_SUPPORTED | IMF_CSR | IMF_REGWRITE | IMF_ALU_REQ_RS | (EXTRA_FLAGS) }, ALIASES} static const struct InstructionMap SYSTEM_map[] = { {"system_priviledged", IT_I, NOALU, NOMEM, SYSTEM_PRIV_map, {}, 0x00000073, 0xffffffff, { .subfield = {5, 25} }, nullptr}, CSR_MAP_ITEM("csrrw", "s", 0x1000, ADD, 0, inst_aliases_csrrw), CSR_MAP_ITEM("csrrs", "s", 0x2000, OR, IMF_CSR_TO_ALU, inst_aliases_csrrs), CSR_MAP_ITEM("csrrc", "s", 0x3000, AND, IMF_CSR_TO_ALU | IMF_ALU_MOD, nullptr), IM_UNKNOWN, CSR_MAP_ITEM("csrrwi", "Z", 0x5000, ADD, IMF_ALU_RS_ID, nullptr), CSR_MAP_ITEM("csrrsi", "Z", 0x6000, OR, IMF_ALU_RS_ID | IMF_CSR_TO_ALU, nullptr), CSR_MAP_ITEM("csrrci", "Z", 0x7000, AND, IMF_ALU_RS_ID | IMF_CSR_TO_ALU | IMF_ALU_MOD, nullptr), }; #undef CSR_MAP_ITEM static const struct InstructionMap MISC_MEM_map[] = { {"fence", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x0000000f, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_MEM }, nullptr}, {"fence.i", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x000100f, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_MEM }, nullptr}, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, }; // RV64I specific operations static const struct InstructionMap SRI_32_map[] = { {"srliw", IT_I, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", ">"}, 0x0000501b,0xfe00707f, { .flags = FLAGS_ALU_I | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SRLIW {"sraiw", IT_I, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", ">"}, 0x4000501b,0xfe00707f, { .flags = FLAGS_ALU_I | IMF_ALU_MOD | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SRAIW }; static const struct InstructionMap OP_IMM_32_map[] = { {"addiw", IT_I, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "j"}, 0x0000001b,0x0000707f, { .flags = FLAGS_ALU_I | IMF_FORCE_W_OP | IMF_RV64 }, inst_aliases_addiw}, // ADDIW {"slliw", IT_I, { .alu_op=AluOp::SLL }, NOMEM, nullptr, {"d", "s", ">"}, 0x0000101b,0xfe00707f, { .flags = FLAGS_ALU_I | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SLLIW IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, {"sriw", IT_I, NOALU, NOMEM, SRI_32_map, {}, 0x0000501b, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, // SRLIW, SRAIW IM_UNKNOWN, IM_UNKNOWN, }; static const struct InstructionMap ADD_32_map[] = { {"addw", IT_R, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "t"}, 0x0000003b, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, {"subw", IT_R, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "s", "t"}, 0x4000003b, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_ALU_MOD | IMF_FORCE_W_OP | IMF_RV64 }, inst_aliases_subw}, }; static const struct InstructionMap SR_32_map[] = { {"srlw", IT_R, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", "t"}, 0x0000503b,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SRL {"sraw", IT_R, { .alu_op=AluOp::SR }, NOMEM, nullptr, {"d", "s", "t"}, 0x4000503b,0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_ALU_MOD | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SRA }; static const struct InstructionMap OP_ALU_32_map[] = { {"addw/subw", IT_R, NOALU, NOMEM, ADD_32_map, {}, 0x0000003b, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, {"sllw", IT_R, { .alu_op=AluOp::SLL }, NOMEM, nullptr, {"d", "s", "t"}, 0x0000103b, 0xfe00707f, { .flags = FLAGS_ALU_T_R_STD | IMF_FORCE_W_OP | IMF_RV64 }, nullptr}, // SLL IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, {"srw", IT_R, NOALU, NOMEM, SR_32_map, {}, 0x0000503b, 0xbe00707f, { .subfield = {1, 30} }, nullptr}, // SRL, SRA IM_UNKNOWN, IM_UNKNOWN, }; // RV64M #define MUL_32_MAP_ITEM(NAME, OP, CODE) \ { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x0200003b | (CODE)), 0xfe00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL | IMF_FORCE_W_OP | IMF_RV64 ) }, nullptr} static const struct InstructionMap OP_MUL_32_map[] = { MUL_32_MAP_ITEM("mulw", MulOp::MUL, 0x0000), IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, MUL_32_MAP_ITEM("divw", MulOp::DIV, 0x4000), MUL_32_MAP_ITEM("divuw", MulOp::DIVU, 0x5000), MUL_32_MAP_ITEM("remw", MulOp::REM, 0x6000), MUL_32_MAP_ITEM("remuw", MulOp::REMU, 0x7000), }; static const struct InstructionMap OP_32_map[] = { {"aluw", IT_R, NOALU, NOMEM, OP_ALU_32_map, {}, 0x00000033, 0x0000707f, { .subfield = {3, 12} }, nullptr}, {"mulw", IT_R, NOALU, NOMEM, OP_MUL_32_map, {}, 0x02000033, 0xfc00707f, { .subfield = {3, 12} }, nullptr}, }; // Full, uncomprese, instructions top level map static const struct InstructionMap I_inst_map[] = { {"load", IT_I, NOALU, NOMEM, LOAD_map, {}, 0x03, 0x7f, { .subfield = {3, 12} }, nullptr}, // LOAD IM_UNKNOWN, // LOAD-FP IM_UNKNOWN, // custom-0 {"misc-mem", IT_I, NOALU, NOMEM, MISC_MEM_map, {}, 0x0f, 0x7f, { .subfield = {3, 12} }, nullptr}, // MISC-MEM {"op-imm", IT_I, NOALU, NOMEM, OP_IMM_map, {}, 0x13, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-IMM {"auipc", IT_U, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "u"}, 0x17, 0x7f, { .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_PC_TO_ALU }, nullptr}, // AUIPC {"op-imm-32", IT_I, NOALU, NOMEM, OP_IMM_32_map, {}, 0x1b, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-IMM-32 IM_UNKNOWN, // OP-IMM-32 IM_UNKNOWN, // 48b {"store", IT_I, NOALU, NOMEM, STORE_map, {}, 0x23, 0x7f, { .subfield = {3, 12} }, nullptr}, // STORE IM_UNKNOWN, // STORE-FP IM_UNKNOWN, // custom-1 {"amo", IT_R, NOALU, NOMEM, AMO_map, {}, 0x2f, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-32 {"op", IT_R, NOALU, NOMEM, OP_map, {}, 0x33, 0x7f, { .subfield = {1, 25} }, nullptr}, // OP {"lui", IT_U, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "u"}, 0x37, 0x7f, { .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE }, nullptr}, // LUI {"op-32", IT_R, NOALU, NOMEM, OP_32_map, {}, 0x3b, 0x7f, { .subfield = {1, 25} }, nullptr}, // OP-32 IM_UNKNOWN, // 64b IM_UNKNOWN, // MADD IM_UNKNOWN, // MSUB IM_UNKNOWN, // NMSUB IM_UNKNOWN, // NMADD IM_UNKNOWN, // OP-FP IM_UNKNOWN, // reserved IM_UNKNOWN, // custom-2/rv128 IM_UNKNOWN, // 48b {"branch", IT_B, NOALU, NOMEM, BRANCH_map, {}, 0x63, 0x7f, { .subfield = {3, 12} }, nullptr}, // BRANCH {"jalr", IT_I, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "o(s)"}, 0x67, 0x7f, { .flags = IMF_SUPPORTED | IMF_REGWRITE | IMF_BRANCH_JALR | IMF_ALUSRC | IMF_ALU_REQ_RS }, inst_aliases_jalr}, // JALR IM_UNKNOWN, // reserved {"jal", IT_J, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "a"}, 0x6f, 0x7f, { .flags = IMF_SUPPORTED | IMF_REGWRITE | IMF_JUMP | IMF_PC_TO_ALU | IMF_ALUSRC }, inst_aliases_jal}, // JAL {"system", IT_I, NOALU, NOMEM, SYSTEM_map, {}, 0x73, 0x7f, { .subfield = {3, 12} }, nullptr}, // SYSTEM IM_UNKNOWN, // reserved IM_UNKNOWN, // custom-3/rv128 IM_UNKNOWN, // >= 80b }; static const struct InstructionMap C_inst_map[] = { IM_UNKNOWN, IM_UNKNOWN, IM_UNKNOWN, {"i", IT_UNKNOWN, NOALU, NOMEM, I_inst_map, {}, 0x3, 0x3, { .subfield = {5, 2} }, nullptr}, }; static const struct InstructionMap C_inst_unknown = IM_UNKNOWN; // clang-format on const BitField instruction_map_opcode_field = { 2, 0 }; static inline const struct InstructionMap &InstructionMapFind(uint32_t code) { const struct InstructionMap *im = &C_inst_map[instruction_map_opcode_field.decode(code)]; while (im->subclass != nullptr) { im = &im->subclass[im->subfield.decode(code)]; } if ((code ^ im->code) & im->mask) { return C_inst_unknown; } return *im; } const std::array RECOGNIZED_PSEUDOINSTRUCTIONS { "nop", "la", "li", "sext.b", "sext.h", "zext.h", "zext.w", "call", "tail" }; bool Instruction::symbolic_registers_enabled = false; const Instruction Instruction::NOP = Instruction(0x00000013); const Instruction Instruction::UNKNOWN_INST = Instruction(0x0); Instruction::Instruction() { this->dt = 0; } Instruction::Instruction(uint32_t inst) { this->dt = inst; } Instruction::Instruction(const Instruction &i) { this->dt = i.data(); } #define MASK(LEN, OFF) ((this->dt >> (OFF)) & ((1 << (LEN)) - 1)) uint8_t Instruction::opcode() const { return (uint8_t)MASK(7, 0); // Does include the 2 bits marking it's not a // 16b instruction } uint8_t Instruction::rs() const { return (uint8_t)MASK(5, 15); } uint8_t Instruction::rt() const { return (uint8_t)MASK(5, 20); } uint8_t Instruction::rd() const { return (uint8_t)MASK(5, 7); } uint8_t Instruction::shamt() const { return this->rt(); } uint16_t Instruction::funct() const { return uint16_t(MASK(7, 25) << 3 | MASK(3, 12)); } CSR::Address Instruction::csr_address() const { return CSR::Address(MASK(12, 20)); } int32_t Instruction::immediate() const { int32_t ret = 0; switch (this->type()) { case R: break; case I: ret = extend(MASK(12, 20), 12); break; case S: ret = extend(MASK(7, 25) << 5 | MASK(5, 7), 12); break; case B: ret = extend(MASK(4, 8) << 1 | MASK(6, 25) << 5 | MASK(1, 7) << 11 | MASK(1, 31) << 12, 13); break; case U: ret = extend(MASK(20, 12) << 12, 32); break; case J: ret = extend( MASK(10, 21) << 1 | MASK(1, 20) << 11 | MASK(8, 12) << 12 | MASK(1, 31) << 20, 21); break; case ZICSR: case AMO: case UNKNOWN: break; } return ret; } Address Instruction::address() const { return Address(MASK(26, 0)); } uint32_t Instruction::data() const { return this->dt; } bool Instruction::imm_sign() const { return this->dt >> 31; } enum Instruction::Type Instruction::type() const { const struct InstructionMap &im = InstructionMapFind(dt); return im.type; } enum InstructionFlags Instruction::flags() const { const struct InstructionMap &im = InstructionMapFind(dt); return (enum InstructionFlags)im.flags; } AluCombinedOp Instruction::alu_op() const { const struct InstructionMap &im = InstructionMapFind(dt); return im.alu; } enum AccessControl Instruction::mem_ctl() const { const struct InstructionMap &im = InstructionMapFind(dt); return im.mem_ctl; } void Instruction::flags_alu_op_mem_ctl( InstructionFlags &flags, AluCombinedOp &alu_op, AccessControl &mem_ctl) const { const struct InstructionMap &im = InstructionMapFind(dt); flags = (enum InstructionFlags)im.flags; alu_op = im.alu; mem_ctl = im.mem_ctl; } bool Instruction::operator==(const Instruction &c) const { return (this->data() == c.data()); } bool Instruction::operator!=(const Instruction &c) const { return !this->operator==(c); } Instruction &Instruction::operator=(const Instruction &c) { if (this != &c) { this->dt = c.data(); } return *this; } QString Instruction::to_str(Address inst_addr) const { const InstructionMap &im = InstructionMapFind(dt); // TODO there are exception where some fields are zero and such so we should // not print them in such case SANITY_ASSERT(argdesbycode_filled, QString("argdesbycode_filled not initialized")); QString res; QString next_delim = " "; if (im.type == UNKNOWN) { return { "unknown" }; } if (this->dt == NOP.dt) { return { "nop" }; } res += im.name; for (const QString &arg_string : im.args) { res += next_delim; next_delim = ", "; for (int pos = 0; pos < arg_string.size(); pos += 1) { char arg_letter = arg_string[pos].toLatin1(); const ArgumentDesc *arg_desc = arg_desc_by_code[(unsigned char)arg_letter]; if (arg_desc == nullptr) { res += arg_letter; continue; } auto field = (int32_t)arg_desc->arg.decode(this->dt); if (arg_desc->min < 0) { field = extend(field, [&]() { int sum = (int)arg_desc->arg.shift; for (auto chunk : arg_desc->arg) { sum += chunk.count; } return sum; }()); } switch (arg_desc->kind) { case 'g': { if (symbolic_registers_enabled) { res += QString(Rv_regnames[field]); } else { res += "x" + QString::number(field); } break; } case 'p': case 'a': { field += (int32_t)inst_addr.get_raw(); res.append(str::asHex(uint32_t(field))); break; } case 'o': case 'n': { if (arg_desc->min < 0) { res += QString::number((int32_t)field, 10); } else { res.append(str::asHex(uint32_t(field))); } break; } case 'E': { if (symbolic_registers_enabled) { try { res += CSR::REGISTERS[CSR::REGISTER_MAP.at(CSR::Address(field))].name; } catch (std::out_of_range &e) { res.append(str::asHex(field)); } } else { res.append(str::asHex(field)); } break; } } } } return res; } QMultiMap str_to_instruction_code_map; static void instruction_from_string_build_base_aliases( uint32_t base_code, uint32_t base_mask, const InstructionMap *ia) { for (; ia->name != nullptr; ia++) { if ((ia->code ^ base_code) & base_mask) { ERROR( "alias code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32, ia->name, base_code, base_mask, ia->code); continue; } if (~ia->mask & base_mask) { ERROR( "aliase code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32 " with too wide mask 0x%08" PRIx32, ia->name, base_code, base_mask, ia->code, ia->mask); continue; } bool found = false; auto iter_range = str_to_instruction_code_map.equal_range(ia->name); for (auto i = iter_range.first; i != iter_range.second; i += 1) { if (i.value() == base_code) { found = true; break; } } if (found) continue; // store base code, the iteration over alliases is required anyway str_to_instruction_code_map.insert(ia->name, base_code); } } void instruction_from_string_build_base( const InstructionMap *im, BitField field, uint32_t base_code, uint32_t base_mask) { uint32_t code; uint8_t bits = field.count; uint8_t shift = field.offset; base_mask |= (((uint32_t)1 << bits) - 1) << shift; for (unsigned int i = 0; i < 1U << bits; i++, im++) { code = base_code | (i << shift); if (im->subclass) { instruction_from_string_build_base(im->subclass, im->subfield, code, base_mask); continue; } if (!(im->flags & IMF_SUPPORTED)) { continue; } if ((im->code ^ code) & base_mask) { ERROR( "code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32, im->name, code, base_mask, im->code); continue; } if (~im->mask & base_mask) { ERROR( "code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32 " with too wide mask 0x%08" PRIx32, im->name, code, base_mask, im->code, im->mask); continue; } str_to_instruction_code_map.insert(im->name, im->code); if (im->aliases != nullptr) instruction_from_string_build_base_aliases(im->code, im->mask, im->aliases); } #if 0 for (auto i = str_to_instruction_code_map.begin(); i != str_to_instruction_code_map.end(); i++) std::cout << i.key().toStdString() << ' '; #endif } void instruction_from_string_build_base() { return instruction_from_string_build_base(C_inst_map, instruction_map_opcode_field, 0, 0); } static int parse_reg_from_string(const QString &str, uint *chars_taken = nullptr) { if (str.size() < 2) { return -1; } if (str.at(0) == 'x') { int res = 0; int ctk = 1; for (; ctk < str.size(); ctk += 1) { auto c = str.at(ctk); if (c >= '0' && c <= '9') { res *= 10; res += c.unicode() - '0'; } else { break; } } if (ctk == 0) { return -1; } else { *chars_taken = ctk; return res; } } else { auto data = str.toLocal8Bit(); int regnum = -1; for (size_t i = 0; i < Rv_regnames.size(); i++) { size_t len = std::strlen(Rv_regnames[i]); if (size_t(data.size()) < len) continue; if (std::strncmp(data.data(), Rv_regnames[i], len) == 0) { *chars_taken = len; regnum = (int)i; } } return regnum; } } const QString reloc_operators = QStringLiteral("+-/*|&^~"); const QString reloc_special_chars = QStringLiteral("()%_"); /** Takes largest sequence of valid relocation expression chars and removes whitespaces */ static std::pair read_reloc_expression(const QString &input) { QString expression; uint32_t chars_taken = 0; bool prev_was_operator = false; bool is_modifier = false; for (QChar ch : input) { bool is_operator = reloc_operators.contains(ch); if (ch == '(' && !prev_was_operator) { if (is_modifier) { is_modifier = false; } else { // This is a start of a new field. break; } } if (ch.isLetterOrNumber() || is_operator || reloc_special_chars.contains(ch)) { expression.append(ch); if (ch == '%') { is_modifier = true; } } else if (!ch.isSpace()) { break; } chars_taken += 1; prev_was_operator = is_operator; } return { expression, chars_taken }; } static void reloc_append( RelocExpressionList *reloc, const QString &fl, Address inst_addr, int64_t offset, const ArgumentDesc *adesc, uint *chars_taken = nullptr, const QString &filename = "", int line = 0, Instruction::Modifier pseudo_mod = machine::Instruction::Modifier::NONE) { auto [expression, chars_taken_] = read_reloc_expression(fl); if (expression.size() > 0) { // Do not append empty relocation expressions reloc->append(new RelocExpression( inst_addr, expression, offset, adesc->min, adesc->max, &adesc->arg, filename, line, pseudo_mod)); } if (chars_taken != nullptr) { *chars_taken = chars_taken_; } } size_t Instruction::code_from_tokens( uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc, bool pseudoinst_enabled) { if (str_to_instruction_code_map.isEmpty()) { instruction_from_string_build_base(); } Instruction result = base_from_tokens(inst, reloc); if (result.data() != 0) { if (result.size() > buffsize) { // NOTE: this is bug, not user error. throw ParseError("insufficient buffer size to write parsed instruction"); } *code = result.data(); return result.size(); } if (pseudoinst_enabled) { size_t pseudo_result = pseudo_from_tokens(code, buffsize, inst, reloc); if (pseudo_result != 0) { return pseudo_result; } } throw ParseError("unknown instruction"); } size_t Instruction::pseudo_from_tokens( uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc) { constexpr Modifier UPPER = Modifier::COMPOSED_IMM_UPPER; constexpr Modifier LOWER = Modifier::COMPOSED_IMM_LOWER; if (inst.base == QLatin1String("nop")) { Instruction result; if (!inst.fields.empty()) { throw ParseError("`nop` does not allow any arguments"); } result = Instruction::NOP; *code = result.data(); return result.size(); } if ((inst.base == QLatin1String("la")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } *code = base_from_tokens( { "auipc", inst.fields, inst.address, inst.filename, inst.line }, reloc, UPPER, -inst.address.get_raw()) .data(); code += 1; inst.fields.insert(0, inst.fields.at(0)); *code = base_from_tokens( { "addi", inst.fields, inst.address + 4, inst.filename, inst.line }, reloc, LOWER, -inst.address.get_raw()) .data(); return 8; } if ((inst.base == QLatin1String("li")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } *code = base_from_tokens( { "lui", inst.fields, inst.address, inst.filename, inst.line }, reloc, UPPER) .data(); code += 1; inst.fields.insert(0, inst.fields.at(0)); *code = base_from_tokens( { "addi", inst.fields, inst.address + 4, inst.filename, inst.line }, reloc, LOWER) .data(); return 8; } if ((inst.base == QLatin1String("call")) && (buffsize >= 8)) { if (inst.fields.size() != 1) { throw ParseError("number of arguments does not match"); } inst.fields.insert(0, "x6"); *code = base_from_tokens( { "auipc", inst.fields, inst.address, inst.filename, inst.line }, reloc, UPPER, -inst.address.get_raw()) .data(); code += 1; inst.fields[0] = QString("x1"); inst.fields[1] = QString("%0(x6)").arg(inst.fields[1]); *code = base_from_tokens( { "jalr", inst.fields, inst.address + 4, inst.filename, inst.line }, reloc, LOWER, -inst.address.get_raw()) .data(); return 8; } if ((inst.base == QLatin1String("tail")) && (buffsize >= 8)) { if (inst.fields.size() != 1) { throw ParseError("number of arguments does not match"); } inst.fields.insert(0, "x6"); *code = base_from_tokens( { "auipc", inst.fields, inst.address, inst.filename, inst.line }, reloc, UPPER, -inst.address.get_raw()) .data(); code += 1; inst.fields[0] = QString("x0"); inst.fields[1] = QString("%0(x6)").arg(inst.fields[1]); *code = base_from_tokens( { "jalr", inst.fields, inst.address + 4, inst.filename, inst.line }, reloc, LOWER, -inst.address.get_raw()) .data(); return 8; } if (inst.base[0] == 's') { if ((inst.base == QLatin1String("sext.b")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } inst.base = "slli"; inst.fields.append("XLEN-8"); *code = base_from_tokens(inst, reloc).data(); code += 1; inst.base = "srai"; inst.fields[1] = inst.fields[0]; *code = base_from_tokens(inst, reloc).data(); return 8; } if ((inst.base == QLatin1String("sext.h")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } inst.base = "slli"; inst.fields.append("XLEN-16"); *code = base_from_tokens(inst, reloc).data(); code += 1; inst.base = "srai"; inst.fields[1] = inst.fields[0]; *code = base_from_tokens(inst, reloc).data(); return 8; } } if (inst.base[0] == 'z') { if ((inst.base == QLatin1String("zext.h")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } inst.base = "slli"; inst.fields.append("XLEN-16"); *code = base_from_tokens(inst, reloc).data(); code += 1; inst.base = "srli"; inst.fields[1] = inst.fields[0]; *code = base_from_tokens(inst, reloc).data(); return 8; } if ((inst.base == QLatin1String("zext.w")) && (buffsize >= 8)) { if (inst.fields.size() != 2) { throw ParseError("number of arguments does not match"); } inst.base = "slli"; inst.fields.append("XLEN-32"); *code = base_from_tokens(inst, reloc).data(); code += 1; inst.base = "srli"; inst.fields[1] = inst.fields[0]; *code = base_from_tokens(inst, reloc).data(); return 8; } } return 0; } size_t Instruction::partially_apply( const char *base, int argument_count, int position, const char *value, uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc) { if (inst.fields.size() != argument_count) { throw ParseError("number of arguments does not match"); } inst.base = base; inst.fields.insert(position, value); return code_from_tokens(code, buffsize, inst, reloc, false); } static void instruction_code_map_next_im(const InstructionMap *&im, bool &processing_aliases) { if (!processing_aliases) { processing_aliases = true; im = im->aliases; } else { im++; if (im->name == nullptr) im = nullptr; } } Instruction Instruction::base_from_tokens( const TokenizedInstruction &inst, RelocExpressionList *reloc, Modifier pseudo_mod, uint64_t initial_immediate_value) { int rethrow = false; ParseError parse_error = ParseError("no match for arguments combination found"); auto iter_range = str_to_instruction_code_map.equal_range(inst.base); if (iter_range.first == iter_range.second) { DEBUG("Base instruction of the name %s not found.", qPrintable(inst.base)); return Instruction::UNKNOWN_INST; } // Process all codes associated with given instruction name and try matching the supplied // instruction field tokens to fields. First matching instruction is used. for (auto it = iter_range.first; it != iter_range.second; it++) { uint32_t inst_code = it.value(); bool processing_aliases = false; const InstructionMap *im = &InstructionMapFind(inst_code); for (; im != nullptr; instruction_code_map_next_im(im, processing_aliases)) { if (inst.base != im->name) continue; try { inst_code = im->code; if (inst.fields.count() != (int)im->args.size()) { if (!rethrow) { parse_error = ParseError("number of arguments does not match"); rethrow = true; } continue; } for (int field_index = 0; field_index < (int)im->args.size(); field_index++) { const QString &arg = im->args[field_index]; QString field_token = inst.fields[field_index]; inst_code |= parse_field( field_token, arg, inst.address, reloc, inst.filename, inst.line, pseudo_mod, initial_immediate_value); } return Instruction(inst_code); } catch (ParseError &pe) { rethrow = true; parse_error = pe; } } } if (rethrow) { throw parse_error; } DEBUG( "Base instruction of the name %s not matched to any known base format.", qPrintable(inst.base)); // Another instruction format for this base may be found in pseudoinstructions. return Instruction::UNKNOWN_INST; } uint16_t parse_csr_address(const QString &field_token, uint &chars_taken); bool parse_immediate_value( const QString &field_token, Address &inst_addr, RelocExpressionList *reloc, const QString &filename, unsigned int line, bool need_reloc, const ArgumentDesc *adesc, const Instruction::Modifier &effective_mod, uint64_t &val, uint &chars_taken); uint32_t Instruction::parse_field( QString &field_token, const QString &arg, Address inst_addr, RelocExpressionList *reloc, const QString &filename, unsigned int line, Modifier pseudo_mod, uint64_t initial_immediate_value) { uint32_t inst_code = 0; for (QChar ao : arg) { bool need_reloc = false; uint a = ao.toLatin1(); if (!a) { continue; } field_token = field_token.trimmed(); const ArgumentDesc *adesc = arg_desc_by_code[a]; if (adesc == nullptr) { if (!field_token.count()) { throw ParseError("empty argument encountered"); } if (field_token.at(0) != ao) { throw ParseError("argument does not match instruction template"); } field_token = field_token.mid(1); continue; } // Only apply modifier to immediate fields const Modifier effective_mod = (adesc->is_imm()) ? pseudo_mod : Modifier::NONE; uint64_t val = 0; uint chars_taken = 0; switch (adesc->kind) { case 'g': val += parse_reg_from_string(field_token, &chars_taken); break; case 'p': case 'a': val -= inst_addr.get_raw(); FALLTROUGH case 'o': case 'n': { val += initial_immediate_value; if (!parse_immediate_value( field_token, inst_addr, reloc, filename, line, need_reloc, adesc, effective_mod, val, chars_taken)) { throw ParseError( QString("field_token %1 is not a valid immediate value").arg(field_token)); } break; } case 'E': val = parse_csr_address(field_token, chars_taken); break; } if (chars_taken <= 0) { throw ParseError("argument parse error"); } if (effective_mod != Modifier::NONE) { val = modify_pseudoinst_imm(effective_mod, val); } else if (!adesc->is_value_in_field_range(val)) { throw ParseError("argument range exceed"); } inst_code |= adesc->arg.encode(val); field_token = field_token.mid(chars_taken); } if (field_token.trimmed() != "") { throw ParseError("excessive characters in argument"); } return inst_code; } bool parse_immediate_value( const QString &field_token, Address &inst_addr, RelocExpressionList *reloc, const QString &filename, unsigned int line, bool need_reloc, const ArgumentDesc *adesc, const Instruction::Modifier &effective_mod, uint64_t &val, uint &chars_taken) { if (field_token.at(0).isDigit() || field_token.at(0) == '-' || (reloc == nullptr)) { uint64_t num_val = 0; // Qt functions are limited, toLongLong would be usable // but does not return information how many characters // are processed. Used solution has horrible overhead // but is usable for now int i; char cstr[field_token.count() + 1]; for (i = 0; i < field_token.count(); i++) { cstr[i] = field_token.at(i).toLatin1(); } cstr[i] = 0; const char *p = cstr; char *r; if (adesc->min < 0) { num_val = strtoll(p, &r, 0); } else { num_val = strtoull(p, &r, 0); } while (*r && isspace(*r)) { r++; } chars_taken = r - p; if (*r && strchr("+-/*|&^~%", *r)) { need_reloc = true; } else { // extend signed bits val += num_val; } } else { need_reloc = true; } if (need_reloc && (reloc != nullptr)) { reloc_append( reloc, field_token, inst_addr, val, adesc, &chars_taken, filename, line, effective_mod); val = 0; } return chars_taken != 0; } uint16_t parse_csr_address(const QString &field_token, uint &chars_taken) { if (field_token.at(0).isLetter()) { try { size_t index = CSR::REGISTER_MAP_BY_NAME.at(field_token.toStdString()); auto ® = CSR::REGISTERS[index]; chars_taken = strlen(reg.name); return reg.address.data; } catch (std::out_of_range &e) { chars_taken = 0; return 0; } } else { char *r; uint64_t val; const char *str = field_token.toLocal8Bit().constData(); val = strtoul(str, &r, 0); chars_taken = r - str; return val; } } bool Instruction::update(int64_t val, RelocExpression *relocexp) { // Clear all bit of the updated argument. dt &= ~relocexp->arg->encode(~0); val += relocexp->offset; if (relocexp->pseudo_mod != Modifier::NONE) { val = (int64_t)modify_pseudoinst_imm(relocexp->pseudo_mod, val); } else { if ((val & ((1 << relocexp->arg->shift) - 1))) { return false; } if (relocexp->min < 0) { if (((int64_t)val < relocexp->min) || ((int64_t)val > relocexp->max)) { if (((int64_t)val - 0x100000000 < relocexp->min) || ((int64_t)val - 0x100000000 > relocexp->max)) { return false; } } } else { if (((uint64_t)val < (uint64_t)relocexp->min) || ((uint64_t)val > (uint64_t)relocexp->max)) { return false; } } } dt |= relocexp->arg->encode(val); return true; } constexpr uint64_t Instruction::modify_pseudoinst_imm(Instruction::Modifier mod, uint64_t value) { // Example: la rd, symbol -> auipc rd, symbol[31:12] + symbol[11], addi rd, rd, symbol[11:0] switch (mod) { case Modifier::NONE: return value; case Modifier::COMPOSED_IMM_UPPER: return get_bits(value, 31, 12) + get_bit(value, 11); case Modifier::COMPOSED_IMM_LOWER: return get_bits(value, 11, 0); default: UNREACHABLE } } // highlighter void Instruction::append_recognized_instructions(QStringList &list) { if (str_to_instruction_code_map.isEmpty()) { instruction_from_string_build_base(); } for (auto iter = str_to_instruction_code_map.keyBegin(); iter != str_to_instruction_code_map.keyEnd(); iter++) { list.append(*iter); } for (const auto &str : RECOGNIZED_PSEUDOINSTRUCTIONS) { list.append(str); } } void Instruction::set_symbolic_registers(bool enable) { symbolic_registers_enabled = enable; } inline int32_t Instruction::extend(uint32_t value, uint32_t used_bits) const { return value | ~((value & (1 << (used_bits - 1))) - 1); } void Instruction::append_recognized_registers(QStringList &list) { for (auto name : Rv_regnames) { list.append(name); } } uint8_t Instruction::size() const { return 4; } size_t Instruction::code_from_string( uint32_t *code, size_t buffsize, QString str, Address inst_addr, RelocExpressionList *reloc, const QString &filename, unsigned line, bool pseudoinst_enabled) { auto inst = TokenizedInstruction::from_line(std::move(str), inst_addr, filename, line); return Instruction::code_from_tokens(code, buffsize, inst, reloc, pseudoinst_enabled); } Instruction::ParseError::ParseError(QString message) : message(std::move(message)) {} TokenizedInstruction TokenizedInstruction::from_line( QString line_str, Address inst_addr, const QString &filename, unsigned line) { int start = 0, end; while (start < line_str.size()) { if (!line_str.at(start).isSpace()) { break; } start++; } end = start; while (end < line_str.size()) { if (line_str.at(end).isSpace()) { break; } end++; } QString inst_base = line_str.mid(start, end - start).toLower(); if (!inst_base.size()) { throw Instruction::ParseError("empty instruction field"); } line_str = line_str.mid(end + 1).trimmed(); QStringList inst_fields; if (line_str.size() > 0) { inst_fields = line_str.split(","); } return { inst_base, inst_fields, inst_addr, filename, line }; } TokenizedInstruction::TokenizedInstruction( QString base, QStringList fields, const Address &address, QString filename, unsigned int line) : base(std::move(base)) , fields(std::move(fields)) , address(address) , filename(std::move(filename)) , line(line) {} qtrvsim-0.9.8/src/machine/instruction.h000066400000000000000000000220231467752164200201770ustar00rootroot00000000000000#ifndef INSTRUCTION_H #define INSTRUCTION_H #include "bitfield.h" #include "common/containers/cvector.h" #include "csr/address.h" #include "execute/alu.h" #include "machinedefs.h" #include #include #include #include #include #include namespace machine { // 4 is max number of parts in currently used instructions. using BitArg = SplitBitField<4>; static constexpr std::array Rv_regnames = { "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", }; enum InstructionFlags : unsigned { IMF_SUPPORTED = 1L << 0, /**< Instruction is supported */ IMF_MEMWRITE = 1L << 1, /**< Write to the memory when memory stage is reached */ IMF_MEMREAD = 1L << 2, /**< Read from the memory when memory stage is reached */ IMF_ALUSRC = 1L << 3, /**< The second ALU source is immediate operand */ IMF_REGWRITE = 1L << 4, /**< Instruction result (ALU or memory) is written to register file */ IMF_MEM = 1L << 5, /**< Instruction is memory access instruction */ IMF_ALU_REQ_RS = 1L << 6, /**< Execution phase/ALU requires RS value */ IMF_ALU_REQ_RT = 1L << 7, /**< Execution phase/ALU/mem requires RT value */ IMF_BRANCH = 1L << 8, /**< Operation is conditional or unconditional branch or branch and link when PC_TO_R31 is set */ IMF_JUMP = 1L << 9, /**< Jump operation - JAL, JALR */ IMF_BJ_NOT = 1L << 10, /**< Negate condition for branch instruction */ IMF_BRANCH_JALR = 1L << 11, /**< Use ALU output as branch/jump target. Used by JALR. */ IMF_EXCEPTION = 1L << 12, /**< Instruction causes synchronous exception */ IMF_ALU_MOD = 1L << 13, /**< ADD and right-shift modifier */ IMF_PC_TO_ALU = 1L << 14, /**< PC is loaded instead of RS to ALU */ IMF_FORCE_W_OP = 1L << 15, /**< Force word (32-bit) operation even for XLEN=64 */ IMF_ECALL = 1L << 16, // seems easiest to encode ecall and ebreak as flags, but they might IMF_EBREAK = 1L << 17, // be moved elsewhere in case we run out of InstructionFlag space. IMF_XRET = 1L << 18, /**< Return from exception, MRET and SRET */ // Extensions: // ============================================================================================= // RV64/32M IMF_MUL = 1L << 19, /**< Enables multiplication component of ALU. */ // Zicsr IMF_CSR = 1L << 20, /**< Implies csr read and write */ IMF_CSR_TO_ALU = 1L << 21, /**< Instruction modifies the current value */ IMF_ALU_RS_ID = 1L << 22, // RV64/32A - Atomic Memory Operations IMF_AMO = 1L << 23, /**< Instruction is AMO */ // TODO do we want to add those signals to the visualization? IMF_RV64 = 1L << 24, /**< Mark instructions which are available in 64-bit mode only. */ }; /** * Collection of data necessary to parse instruction from tokens. * * @TODO Switch to QStringView */ struct TokenizedInstruction { QString base; QStringList fields; Address address; QString filename; unsigned line; public: TokenizedInstruction( QString base, QStringList fields, const Address &address, QString filename, unsigned int line); /** Tokenize assembler line */ static TokenizedInstruction from_line(QString line_str, Address inst_addr, const QString &filename, unsigned line); }; struct RelocExpression; typedef QVector RelocExpressionList; class Instruction { public: Instruction(); explicit Instruction(uint32_t inst); // Instruction( // uint8_t opcode, // uint8_t rs, // uint8_t rt, // uint8_t rd, // uint8_t shamt, // uint8_t funct); // Type R // Instruction( // uint8_t opcode, // uint8_t rs, // uint8_t rt, // uint16_t immediate); // Type I // Instruction(uint8_t opcode, Address address); // Type J Instruction(const Instruction &); static const Instruction NOP; static const Instruction UNKNOWN_INST; enum Type { R, I, S, B, U, J, ZICSR, AMO, UNKNOWN }; /** Modified encoding to enable pseudoinstructions. */ enum class Modifier { /** Normal processing. All fields are checked for value max and min. */ NONE, /** * Encodes upper part of immediate from a pseudoinstruction. * * `imm = symbol[31:12] + symbol[11]` * NOTE: `symbol[11]` compensates for sign extension from addition of the lower part. */ COMPOSED_IMM_UPPER, /** * Encodes lower part of immediate from a pseudoinstruction. * * `imm = symbol[11:0]` * Upper bits of immediate may are discarded. */ COMPOSED_IMM_LOWER, }; struct ParseError; /** Returns size of instruction in bytes */ uint8_t size() const; uint8_t opcode() const; uint8_t rs() const; uint8_t rt() const; uint8_t rd() const; uint8_t shamt() const; uint16_t funct() const; machine::CSR::Address csr_address() const; int32_t immediate() const; Address address() const; uint32_t data() const; bool imm_sign() const; enum Type type() const; enum InstructionFlags flags() const; AluCombinedOp alu_op() const; enum AccessControl mem_ctl() const; void flags_alu_op_mem_ctl( enum InstructionFlags &flags, AluCombinedOp &alu_op, enum AccessControl &mem_ctl) const; bool operator==(const Instruction &c) const; bool operator!=(const Instruction &c) const; Instruction &operator=(const Instruction &c); QString to_str(Address inst_addr = Address::null()) const; /** * Parses instruction from string containing one assembler line. * * @throws Instruction::ParseError if unable to parse */ static size_t code_from_string( uint32_t *code, size_t buffsize, QString str, Address inst_addr, RelocExpressionList *reloc = nullptr, const QString &filename = "", unsigned line = 0, bool pseudoinst_enabled = true); /** * Parses instruction from prepare tokenized form. * * @throws Instruction::ParseError if unable to parse */ static size_t code_from_tokens( uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc = nullptr, bool pseudoinst_enabled = true); bool update(int64_t val, RelocExpression *relocexp); static void append_recognized_instructions(QStringList &list); static void set_symbolic_registers(bool enable); static void append_recognized_registers(QStringList &list); static constexpr uint64_t modify_pseudoinst_imm(Modifier mod, uint64_t value); private: uint32_t dt; static bool symbolic_registers_enabled; static Instruction base_from_tokens( const TokenizedInstruction &inst, RelocExpressionList *reloc, Modifier pseudo_mod = Modifier::NONE, uint64_t initial_immediate_value = 0); inline int32_t extend(uint32_t value, uint32_t used_bits) const; static uint32_t parse_field( QString &field_token, const QString &arg, Address inst_addr, RelocExpressionList *reloc, const QString &filename, unsigned int line, Modifier pseudo_mod, uint64_t initial_immediate_value); static size_t partially_apply( const char *base, int argument_count, int position, const char *value, uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc); static size_t pseudo_from_tokens( uint32_t *code, size_t buffsize, TokenizedInstruction &inst, RelocExpressionList *reloc); }; struct Instruction::ParseError : public std::exception { QString message; explicit ParseError(QString message); const char *what() const noexcept override { return message.toUtf8().data(); } }; struct RelocExpression { inline RelocExpression( Address location, QString expression, int64_t offset, int64_t min, int64_t max, const BitArg *arg, QString filename, int line, Instruction::Modifier pseudo_mod = Instruction::Modifier::NONE) { this->location = location; this->expression = std::move(expression); this->offset = offset; this->min = min; this->max = max; this->arg = arg; this->filename = std::move(filename); this->line = line; this->pseudo_mod = pseudo_mod; } Address location; QString expression; int64_t offset; int64_t min; int64_t max; const BitArg *arg; QString filename; int line; Instruction::Modifier pseudo_mod; }; } // namespace machine Q_DECLARE_METATYPE(machine::Instruction) #endif // INSTRUCTION_H qtrvsim-0.9.8/src/machine/instruction.test.cpp000066400000000000000000000020041467752164200215050ustar00rootroot00000000000000#include "instruction.test.h" #include "instruction.h" using namespace machine; // Test that we are correctly encoding instructions in constructor void TestInstruction::instruction() { QCOMPARE(Instruction(0x0), Instruction()); // QCOMPARE(Instruction(0x4432146), Instruction(1, 2, 3, 4, 5, 6)); // QCOMPARE(Instruction(0x4430004), Instruction(1, 2, 3, 4)); // QCOMPARE(Instruction(0x4000002), Instruction(1, 2_addr)); } // Test that we are correctly decoding instruction fields void TestInstruction::instruction_access() { Instruction i(0xffffffff); QCOMPARE(i.data(), (uint32_t)0xffffffff); QCOMPARE(i.opcode(), (uint8_t)0x3f); QCOMPARE(i.rs(), (uint8_t)0x1f); QCOMPARE(i.rt(), (uint8_t)0x1f); QCOMPARE(i.rd(), (uint8_t)0x1f); QCOMPARE(i.shamt(), (uint8_t)0x1f); QCOMPARE(i.funct(), (uint16_t)0x3f); QCOMPARE(i.immediate(), (int32_t)0xffff); QCOMPARE(i.address().get_raw(), (uint64_t)0x3ffffff); } // TODO test to_str QTEST_APPLESS_MAIN(TestInstruction) qtrvsim-0.9.8/src/machine/instruction.test.h000066400000000000000000000003471467752164200211620ustar00rootroot00000000000000#ifndef INSTRUCTION_TEST_H #define INSTRUCTION_TEST_H #include class TestInstruction : public QObject { Q_OBJECT public slots: void instruction(); void instruction_access(); }; #endif // INSTRUCTION_TEST_H qtrvsim-0.9.8/src/machine/machine.cpp000066400000000000000000000347331467752164200175700ustar00rootroot00000000000000#include "machine.h" #include "programloader.h" #include #include using namespace machine; Machine::Machine(MachineConfig config, bool load_symtab, bool load_executable) : machine_config(std::move(config)) , stat(ST_READY) { regs = new Registers(); if (load_executable) { ProgramLoader program(machine_config.elf()); this->machine_config.set_simulated_endian(program.get_endian()); mem_program_only = new Memory(machine_config.get_simulated_endian()); program.to_memory(mem_program_only); if (program.get_architecture_type() == ARCH64) this->machine_config.set_simulated_xlen(Xlen::_64); else this->machine_config.set_simulated_xlen(Xlen::_32); if (load_symtab) { symtab = program.get_symbol_table(); } program_end = program.end(); if (program.get_executable_entry() != 0x0_addr) { regs->write_pc(program.get_executable_entry()); } mem = new Memory(*mem_program_only); } else { mem = new Memory(machine_config.get_simulated_endian()); } data_bus = new MemoryDataBus(machine_config.get_simulated_endian()); data_bus->insert_device_to_range( mem, 0x00000000_addr, 0xefffffff_addr, false); setup_serial_port(); setup_perip_spi_led(); setup_lcd_display(); setup_aclint_mtime(); setup_aclint_mswi(); setup_aclint_sswi(); unsigned access_time_read = machine_config.memory_access_time_read(); unsigned access_time_write = machine_config.memory_access_time_write(); unsigned access_time_burst = machine_config.memory_access_time_burst(); bool access_enable_burst = machine_config.memory_access_enable_burst(); cch_level2 = new Cache( data_bus, &machine_config.cache_level2(), access_time_read, access_time_write, access_time_burst, access_enable_burst); if (machine_config.cache_level2().enabled()) { access_time_read = machine_config.memory_access_time_level2(); access_time_write = machine_config.memory_access_time_level2(); access_time_burst = 0; access_enable_burst = true; } cch_program = new Cache( cch_level2, &machine_config.cache_program(), access_time_read, access_time_write, access_time_burst, access_enable_burst); cch_data = new Cache( cch_level2, &machine_config.cache_data(), access_time_read, access_time_write, access_time_burst, access_enable_burst); controlst = new CSR::ControlState(machine_config.get_simulated_xlen(), machine_config.get_isa_word()); predictor = new BranchPredictor( machine_config.get_bp_enabled(), machine_config.get_bp_type(), machine_config.get_bp_init_state(), machine_config.get_bp_btb_bits(), machine_config.get_bp_bhr_bits(), machine_config.get_bp_bht_addr_bits()); if (machine_config.pipelined()) { cr = new CorePipelined( regs, predictor, cch_program, cch_data, controlst, machine_config.get_simulated_xlen(), machine_config.get_isa_word(), machine_config.hazard_unit()); } else { cr = new CoreSingle(regs, predictor, cch_program, cch_data, controlst, machine_config.get_simulated_xlen(), machine_config.get_isa_word()); } connect( this, &Machine::set_interrupt_signal, controlst, &CSR::ControlState::set_interrupt_signal); run_t = new QTimer(this); set_speed(0); // In default run as fast as possible connect(run_t, &QTimer::timeout, this, &Machine::step_timer); for (int i = 0; i < EXCAUSE_COUNT; i++) { if (i != EXCAUSE_INT && i != EXCAUSE_BREAK && i != EXCAUSE_HWBREAK) { set_stop_on_exception( (enum ExceptionCause)i, machine_config.osemu_exception_stop()); set_step_over_exception( (enum ExceptionCause)i, machine_config.osemu_exception_stop()); } } set_stop_on_exception(EXCAUSE_INT, machine_config.osemu_interrupt_stop()); set_step_over_exception(EXCAUSE_INT, false); } void Machine::setup_lcd_display() { perip_lcd_display = new LcdDisplay(machine_config.get_simulated_endian()); memory_bus_insert_range( perip_lcd_display, 0xffe00000_addr, 0xffe4afff_addr, true); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range( perip_lcd_display, 0xffffffffffe00000_addr, 0xffffffffffe4afff_addr, false); } void Machine::setup_perip_spi_led() { perip_spi_led = new PeripSpiLed(machine_config.get_simulated_endian()); memory_bus_insert_range( perip_spi_led, 0xffffc100_addr, 0xffffc1ff_addr, true); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range( perip_spi_led, 0xffffffffffffc100_addr, 0xffffffffffffc1ff_addr, false); } void Machine::setup_serial_port() { ser_port = new SerialPort(machine_config.get_simulated_endian()); memory_bus_insert_range(ser_port, 0xffffc000_addr, 0xffffc03f_addr, true); memory_bus_insert_range(ser_port, 0xffff0000_addr, 0xffff003f_addr, false); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range(ser_port, 0xffffffffffffc000_addr, 0xffffffffffffc03f_addr, false); connect( ser_port, &SerialPort::signal_interrupt, this, &Machine::set_interrupt_signal); } void Machine::setup_aclint_mtime() { aclint_mtimer = new aclint::AclintMtimer(machine_config.get_simulated_endian()); memory_bus_insert_range(aclint_mtimer, 0xfffd0000_addr + aclint::CLINT_MTIMER_OFFSET, 0xfffd0000_addr + aclint::CLINT_MTIMER_OFFSET + aclint::CLINT_MTIMER_SIZE - 1, true); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range(aclint_mtimer, 0xfffffffffffd0000_addr + aclint::CLINT_MTIMER_OFFSET, 0xfffffffffffd0000_addr + aclint::CLINT_MTIMER_OFFSET + aclint::CLINT_MTIMER_SIZE - 1, false); connect( aclint_mtimer, &aclint::AclintMtimer::signal_interrupt, this, &Machine::set_interrupt_signal); } void Machine::setup_aclint_mswi() { aclint_mswi = new aclint::AclintMswi(machine_config.get_simulated_endian()); memory_bus_insert_range(aclint_mswi, 0xfffd0000_addr + aclint::CLINT_MSWI_OFFSET, 0xfffd0000_addr + aclint::CLINT_MSWI_OFFSET + aclint::CLINT_MSWI_SIZE - 1, true); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range(aclint_mswi, 0xfffffffffffd0000_addr + aclint::CLINT_MSWI_OFFSET, 0xfffffffffffd0000_addr + aclint::CLINT_MSWI_OFFSET + aclint::CLINT_MSWI_SIZE - 1, false); connect( aclint_mswi, &aclint::AclintMswi::signal_interrupt, this, &Machine::set_interrupt_signal); } void Machine::setup_aclint_sswi() { aclint_sswi = new aclint::AclintSswi(machine_config.get_simulated_endian()); memory_bus_insert_range(aclint_sswi, 0xfffd0000_addr + aclint::CLINT_SSWI_OFFSET, 0xfffd0000_addr + aclint::CLINT_SSWI_OFFSET + aclint::CLINT_SSWI_SIZE - 1, true); if (machine_config.get_simulated_xlen() == Xlen::_64) memory_bus_insert_range(aclint_sswi, 0xfffffffffffd0000_addr + aclint::CLINT_SSWI_OFFSET, 0xfffffffffffd0000_addr + aclint::CLINT_SSWI_OFFSET + aclint::CLINT_SSWI_SIZE - 1, false); connect( aclint_sswi, &aclint::AclintSswi::signal_interrupt, this, &Machine::set_interrupt_signal); } Machine::~Machine() { delete run_t; run_t = nullptr; delete cr; cr = nullptr; delete controlst; controlst = nullptr; delete regs; regs = nullptr; delete mem; mem = nullptr; delete cch_program; cch_program = nullptr; delete cch_data; cch_data = nullptr; delete cch_level2; cch_level2 = nullptr; delete data_bus; data_bus = nullptr; delete mem_program_only; mem_program_only = nullptr; delete symtab; symtab = nullptr; delete predictor; predictor = nullptr; } const MachineConfig &Machine::config() { return machine_config; } void Machine::set_speed(unsigned int ips, unsigned int time_chunk) { this->time_chunk = time_chunk; run_t->setInterval(ips); } const Registers *Machine::registers() { return regs; } const CSR::ControlState *Machine::control_state() { return controlst; } const Memory *Machine::memory() { return mem; } Memory *Machine::memory_rw() { return mem; } const Cache *Machine::cache_program() { return cch_program; } const Cache *Machine::cache_data() { return cch_data; } const Cache *Machine::cache_level2() { return cch_level2; } Cache *Machine::cache_data_rw() { return cch_data; } void Machine::cache_sync() { if (cch_program != nullptr) { cch_program->sync(); } if (cch_data != nullptr) { cch_data->sync(); } if (cch_level2 != nullptr) { cch_level2->sync(); } } const MemoryDataBus *Machine::memory_data_bus() { return data_bus; } MemoryDataBus *Machine::memory_data_bus_rw() { return data_bus; } SerialPort *Machine::serial_port() { return ser_port; } PeripSpiLed *Machine::peripheral_spi_led() { return perip_spi_led; } LcdDisplay *Machine::peripheral_lcd_display() { return perip_lcd_display; } SymbolTable *Machine::symbol_table_rw(bool create) { if (create && (symtab == nullptr)) { symtab = new SymbolTable; } return symtab; } const SymbolTable *Machine::symbol_table(bool create) { return symbol_table_rw(create); } void Machine::set_symbol( const QString &name, uint32_t value, uint32_t size, unsigned char info, unsigned char other) { if (symtab == nullptr) { symtab = new SymbolTable; } symtab->set_symbol(name, value, size, info, other); } const Core *Machine::core() { return cr; } const CoreSingle *Machine::core_singe() { return machine_config.pipelined() ? nullptr : (const CoreSingle *)cr; } const CorePipelined *Machine::core_pipelined() { return machine_config.pipelined() ? (const CorePipelined *)cr : nullptr; } bool Machine::executable_loaded() const { return (mem_program_only != nullptr); } enum Machine::Status Machine::status() { return stat; } bool Machine::exited() { return stat == ST_EXIT || stat == ST_TRAPPED; } // We don't allow to call control methods when machine exited or if it's busy // We rather silently fail. #define CTL_GUARD \ do { \ if (exited() || stat == ST_BUSY) \ return; \ } while (false) void Machine::play() { CTL_GUARD; set_status(ST_RUNNING); run_t->start(); step_internal(true); } void Machine::pause() { if (stat != ST_BUSY) { CTL_GUARD; } set_status(ST_READY); run_t->stop(); } void Machine::step_internal(bool skip_break) { CTL_GUARD; enum Status stat_prev = stat; set_status(ST_BUSY); emit tick(); try { QTime start_time = QTime::currentTime(); do { cr->step(skip_break); } while (time_chunk != 0 && stat == ST_BUSY && !skip_break && start_time.msecsTo(QTime::currentTime()) < (int)time_chunk); } catch (SimulatorException &e) { run_t->stop(); set_status(ST_TRAPPED); emit program_trap(e); return; } if (regs->read_pc() >= program_end) { run_t->stop(); set_status(ST_EXIT); emit program_exit(); } else { if (stat == ST_BUSY) { set_status(stat_prev); } } emit post_tick(); } void Machine::step() { step_internal(true); } void Machine::step_timer() { step_internal(); } void Machine::restart() { pause(); regs->reset(); if (mem_program_only != nullptr) { mem->reset(*mem_program_only); } cch_program->reset(); cch_data->reset(); cch_level2->reset(); cr->reset(); set_status(ST_READY); } void Machine::set_status(enum Status st) { bool change = st != stat; stat = st; if (change) { emit status_change(st); } } void Machine::register_exception_handler( ExceptionCause excause, ExceptionHandler *exhandler) { if (cr != nullptr) { cr->register_exception_handler(excause, exhandler); } } bool Machine::memory_bus_insert_range( BackendMemory *mem_acces, Address start_addr, Address last_addr, bool move_ownership) { if (data_bus == nullptr) { return false; } return data_bus->insert_device_to_range( mem_acces, start_addr, last_addr, move_ownership); } void Machine::insert_hwbreak(Address address) { if (cr != nullptr) { cr->insert_hwbreak(address); } } void Machine::remove_hwbreak(Address address) { if (cr != nullptr) { cr->remove_hwbreak(address); } } bool Machine::is_hwbreak(Address address) { if (cr != nullptr) { return cr->is_hwbreak(address); } return false; } void Machine::set_stop_on_exception(enum ExceptionCause excause, bool value) { if (cr != nullptr) { cr->set_stop_on_exception(excause, value); } } bool Machine::get_stop_on_exception(enum ExceptionCause excause) const { if (cr != nullptr) { return cr->get_stop_on_exception(excause); } return false; } void Machine::set_step_over_exception(enum ExceptionCause excause, bool value) { if (cr != nullptr) { cr->set_step_over_exception(excause, value); } } bool Machine::get_step_over_exception(enum ExceptionCause excause) const { if (cr != nullptr) { return cr->get_step_over_exception(excause); } return false; } enum ExceptionCause Machine::get_exception_cause() const { uint32_t val; if (controlst == nullptr) { return EXCAUSE_NONE; } val = (controlst->read_internal(CSR::Id::MCAUSE).as_u64()); if (val & 0xffffffff80000000) { return EXCAUSE_INT; } else { return (ExceptionCause)val; } } qtrvsim-0.9.8/src/machine/machine.h000066400000000000000000000107211467752164200172240ustar00rootroot00000000000000#ifndef MACHINE_H #define MACHINE_H #include "core.h" #include "machineconfig.h" #include "memory/backend/lcddisplay.h" #include "memory/backend/peripheral.h" #include "memory/backend/peripspiled.h" #include "memory/backend/serialport.h" #include "memory/backend/aclintmtimer.h" #include "memory/backend/aclintmswi.h" #include "memory/backend/aclintsswi.h" #include "memory/cache/cache.h" #include "memory/memory_bus.h" #include "predictor.h" #include "registers.h" #include "simulator_exception.h" #include "symboltable.h" #include #include #include namespace machine { class Machine : public QObject { Q_OBJECT public: explicit Machine(MachineConfig config, bool load_symtab = false, bool load_executable = true); ~Machine() override; const MachineConfig &config(); void set_speed(unsigned int ips, unsigned int time_chunk = 0); const Registers *registers(); const CSR::ControlState *control_state(); const Memory *memory(); Memory *memory_rw(); const Cache *cache_program(); const Cache *cache_data(); const Cache *cache_level2(); Cache *cache_data_rw(); void cache_sync(); const MemoryDataBus *memory_data_bus(); MemoryDataBus *memory_data_bus_rw(); SerialPort *serial_port(); PeripSpiLed *peripheral_spi_led(); LcdDisplay *peripheral_lcd_display(); const SymbolTable *symbol_table(bool create = false); SymbolTable *symbol_table_rw(bool create = false); void set_symbol( const QString &name, uint32_t value, uint32_t size, unsigned char info = 0, unsigned char other = 0); const Core *core(); const CoreSingle *core_singe(); const CorePipelined *core_pipelined(); bool executable_loaded() const; enum Status { ST_READY, // Machine is ready to be started or step to be called ST_RUNNING, // Machine is running ST_BUSY, // Machine is calculating step ST_EXIT, // Machine exited ST_TRAPPED // Machine exited with failure }; enum Status status(); bool exited(); void register_exception_handler(ExceptionCause excause, ExceptionHandler *exhandler); bool memory_bus_insert_range( BackendMemory *mem_acces, Address start_addr, Address last_addr, bool move_ownership); void insert_hwbreak(Address address); void remove_hwbreak(Address address); bool is_hwbreak(Address address); void set_stop_on_exception(enum ExceptionCause excause, bool value); bool get_stop_on_exception(enum ExceptionCause excause) const; void set_step_over_exception(enum ExceptionCause excause, bool value); bool get_step_over_exception(enum ExceptionCause excause) const; enum ExceptionCause get_exception_cause() const; public slots: void play(); void pause(); void step(); void restart(); signals: void program_exit(); void program_trap(machine::SimulatorException &e); void status_change(enum machine::Machine::Status st); void tick(); // Time tick void post_tick(); // Emitted after tick to allow updates void set_interrupt_signal(uint irq_num, bool active); private slots: void step_timer(); private: void step_internal(bool skip_break = false); MachineConfig machine_config; Registers *regs = nullptr; Memory *mem = nullptr; /** * Memory with loaded program only. * It is not used for execution, only for quick * simulation reset without repeated ELF file loading. */ Memory *mem_program_only = nullptr; MemoryDataBus *data_bus = nullptr; SerialPort *ser_port = nullptr; PeripSpiLed *perip_spi_led = nullptr; LcdDisplay *perip_lcd_display = nullptr; aclint::AclintMtimer *aclint_mtimer = nullptr; aclint::AclintMswi *aclint_mswi = nullptr; aclint::AclintSswi *aclint_sswi = nullptr; Cache *cch_program = nullptr; Cache *cch_data = nullptr; Cache *cch_level2 = nullptr; CSR::ControlState *controlst = nullptr; BranchPredictor *predictor = nullptr; Core *cr = nullptr; QTimer *run_t = nullptr; unsigned int time_chunk = { 0 }; SymbolTable *symtab = nullptr; Address program_end = 0xffff0000_addr; enum Status stat = ST_READY; void set_status(enum Status st); void setup_serial_port(); void setup_perip_spi_led(); void setup_lcd_display(); void setup_aclint_mtime(); void setup_aclint_mswi(); void setup_aclint_sswi(); }; } // namespace machine #endif // MACHINE_H qtrvsim-0.9.8/src/machine/machineconfig.cpp000066400000000000000000000500521467752164200207460ustar00rootroot00000000000000#include "machineconfig.h" #include "common/endian.h" #include #include using namespace machine; ////////////////////////////////////////////////////////////////////////////// /// Default config of MachineConfig #define DF_PIPELINE false #define DF_DELAYSLOT true #define DF_HUNIT HU_STALL_FORWARD #define DF_EXEC_PROTEC false #define DF_WRITE_PROTEC false #define DF_MEM_ACC_READ 10 #define DF_MEM_ACC_WRITE 10 #define DF_MEM_ACC_BURST 0 #define DF_MEM_ACC_LEVEL2 2 #define DF_MEM_ACC_BURST_ENABLE false #define DF_ELF QString("") /// Default config of branch predictor #define DFC_BP_ENABLED false #define DFC_BP_TYPE PredictorType::SMITH_1_BIT #define DFC_BP_INIT_STATE PredictorState::NOT_TAKEN #define DFC_BP_BTB_BITS 2 #define DFC_BP_BHR_BITS 0 #define DFC_BP_BHT_ADDR_BITS 2 ////////////////////////////////////////////////////////////////////////////// /// Default config of CacheConfig #define DFC_EN false #define DFC_SETS 1 #define DFC_BLOCKS 1 #define DFC_ASSOC 1 #define DFC_REPLAC RP_RAND #define DFC_WRITE WP_THROUGH_NOALLOC ////////////////////////////////////////////////////////////////////////////// CacheConfig::CacheConfig() { en = DFC_EN; n_sets = DFC_SETS; n_blocks = DFC_BLOCKS; d_associativity = DFC_ASSOC; replac_pol = DFC_REPLAC; write_pol = DFC_WRITE; } CacheConfig::CacheConfig(const CacheConfig *cc) { en = cc->enabled(); n_sets = cc->set_count(); n_blocks = cc->block_size(); d_associativity = cc->associativity(); replac_pol = cc->replacement_policy(); write_pol = cc->write_policy(); } #define N(STR) (prefix + QString(STR)) CacheConfig::CacheConfig(const QSettings *sts, const QString &prefix) { en = sts->value(N("Enabled"), DFC_EN).toBool(); n_sets = sts->value(N("Sets"), DFC_SETS).toUInt(); n_blocks = sts->value(N("Blocks"), DFC_BLOCKS).toUInt(); d_associativity = sts->value(N("Associativity"), DFC_ASSOC).toUInt(); replac_pol = (enum ReplacementPolicy)sts->value(N("Replacement"), DFC_REPLAC).toUInt(); write_pol = (enum WritePolicy)sts->value(N("Write"), DFC_WRITE).toUInt(); } void CacheConfig::store(QSettings *sts, const QString &prefix) const { sts->setValue(N("Enabled"), enabled()); sts->setValue(N("Sets"), set_count()); sts->setValue(N("Blocks"), block_size()); sts->setValue(N("Associativity"), associativity()); sts->setValue(N("Replacement"), (unsigned)replacement_policy()); sts->setValue(N("Write"), (unsigned)write_policy()); } #undef N void CacheConfig::preset(enum ConfigPresets p) { switch (p) { case CP_PIPE: case CP_SINGLE_CACHE: set_enabled(true); set_set_count(4); set_block_size(2); set_associativity(2); set_replacement_policy(RP_RAND); set_write_policy(WP_THROUGH_NOALLOC); break; case CP_SINGLE: case CP_PIPE_NO_HAZARD: set_enabled(false); } } void CacheConfig::set_enabled(bool v) { en = v; } void CacheConfig::set_set_count(unsigned v) { n_sets = v > 0 ? v : 1; } void CacheConfig::set_block_size(unsigned v) { n_blocks = v > 0 ? v : 1; } void CacheConfig::set_associativity(unsigned v) { d_associativity = v > 0 ? v : 1; } void CacheConfig::set_replacement_policy(enum ReplacementPolicy v) { replac_pol = v; } void CacheConfig::set_write_policy(enum WritePolicy v) { write_pol = v; } bool CacheConfig::enabled() const { return en; } unsigned CacheConfig::set_count() const { return n_sets; } unsigned CacheConfig::block_size() const { return n_blocks; } unsigned CacheConfig::associativity() const { return d_associativity; } enum CacheConfig::ReplacementPolicy CacheConfig::replacement_policy() const { return replac_pol; } enum CacheConfig::WritePolicy CacheConfig::write_policy() const { return write_pol; } bool CacheConfig::operator==(const CacheConfig &c) const { #define CMP(GETTER) (GETTER)() == (c.GETTER)() return CMP(enabled) && CMP(set_count) && CMP(block_size) && CMP(associativity) && CMP(replacement_policy) && CMP(write_policy); #undef CMP } bool CacheConfig::operator!=(const CacheConfig &c) const { return !operator==(c); } MachineConfig::MachineConfig() { simulated_endian = LITTLE; simulated_xlen = Xlen::_32; isa_word = config_isa_word_default; pipeline = DF_PIPELINE; delayslot = DF_DELAYSLOT; hunit = DF_HUNIT; exec_protect = DF_EXEC_PROTEC; write_protect = DF_WRITE_PROTEC; mem_acc_read = DF_MEM_ACC_READ; mem_acc_write = DF_MEM_ACC_WRITE; mem_acc_burst = DF_MEM_ACC_BURST; mem_acc_level2 = DF_MEM_ACC_LEVEL2; mem_acc_enable_burst = DF_MEM_ACC_BURST_ENABLE; osem_enable = true; osem_known_syscall_stop = true; osem_unknown_syscall_stop = true; osem_interrupt_stop = true; osem_exception_stop = true; osem_fs_root = ""; res_at_compile = true; elf_path = DF_ELF; cch_program = CacheConfig(); cch_data = CacheConfig(); cch_level2 = CacheConfig(); // Branch predictor bp_enabled = DFC_BP_ENABLED; bp_type = DFC_BP_TYPE; bp_init_state = DFC_BP_INIT_STATE; bp_btb_bits = DFC_BP_BTB_BITS; bp_bhr_bits = DFC_BP_BHR_BITS; bp_bht_addr_bits = DFC_BP_BHT_ADDR_BITS; bp_bht_bits = bp_bhr_bits + bp_bht_addr_bits; } MachineConfig::MachineConfig(const MachineConfig *config) { simulated_endian = config->get_simulated_endian(); simulated_xlen = config->get_simulated_xlen(); isa_word = config->get_isa_word(); pipeline = config->pipelined(); delayslot = config->delay_slot(); hunit = config->hazard_unit(); exec_protect = config->memory_execute_protection(); write_protect = config->memory_write_protection(); mem_acc_read = config->memory_access_time_read(); mem_acc_write = config->memory_access_time_write(); mem_acc_burst = config->memory_access_time_burst(); mem_acc_level2 = config->memory_access_time_level2(); mem_acc_enable_burst = config->memory_access_enable_burst(); osem_enable = config->osemu_enable(); osem_known_syscall_stop = config->osemu_known_syscall_stop(); osem_unknown_syscall_stop = config->osemu_unknown_syscall_stop(); osem_interrupt_stop = config->osemu_interrupt_stop(); osem_exception_stop = config->osemu_exception_stop(); osem_fs_root = config->osemu_fs_root(); res_at_compile = config->reset_at_compile(); elf_path = config->elf(); cch_program = config->cache_program(); cch_data = config->cache_data(); cch_level2 = config->cache_level2(); // Branch predictor bp_enabled = config->get_bp_enabled(); bp_type = config->get_bp_type(); bp_init_state = config->get_bp_init_state(); bp_btb_bits = config->get_bp_btb_bits(); bp_bhr_bits = config->get_bp_bhr_bits(); bp_bht_addr_bits = config->get_bp_bht_addr_bits(); bp_bht_bits = bp_bhr_bits + bp_bht_addr_bits; } #define N(STR) (prefix + QString(STR)) MachineConfig::MachineConfig(const QSettings *sts, const QString &prefix) { simulated_endian = LITTLE; unsigned int xlen_num_bits = sts->value(N("XlenBits"), 32).toUInt(); simulated_xlen = xlen_num_bits == 64 ? Xlen::_64 : Xlen::_32; isa_word = ConfigIsaWord(sts->value(N("IsaWord"), config_isa_word_default.toUnsigned()).toUInt()); isa_word |= config_isa_word_default & config_isa_word_fixed; isa_word &= config_isa_word_default | ~config_isa_word_fixed; pipeline = sts->value(N("Pipelined"), DF_PIPELINE).toBool(); delayslot = sts->value(N("DelaySlot"), DF_DELAYSLOT).toBool(); hunit = (enum HazardUnit)sts->value(N("HazardUnit"), DF_HUNIT).toUInt(); exec_protect = sts->value(N("MemoryExecuteProtection"), DF_EXEC_PROTEC).toBool(); write_protect = sts->value(N("MemoryWriteProtection"), DF_WRITE_PROTEC).toBool(); mem_acc_read = sts->value(N("MemoryRead"), DF_MEM_ACC_READ).toUInt(); mem_acc_write = sts->value(N("MemoryWrite"), DF_MEM_ACC_WRITE).toUInt(); mem_acc_burst = sts->value(N("MemoryBurst"), DF_MEM_ACC_BURST).toUInt(); mem_acc_level2 = sts->value(N("MemoryLevel2"), DF_MEM_ACC_LEVEL2).toUInt(); mem_acc_enable_burst = sts->value(N("MemoryBurstEnable"), DF_MEM_ACC_BURST_ENABLE).toBool(); osem_enable = sts->value(N("OsemuEnable"), true).toBool(); osem_known_syscall_stop = sts->value(N("OsemuKnownSyscallStop"), true).toBool(); osem_unknown_syscall_stop = sts->value(N("OsemuUnknownSyscallStop"), true).toBool(); osem_interrupt_stop = sts->value(N("OsemuInterruptStop"), true).toBool(); osem_exception_stop = sts->value(N("OsemuExceptionStop"), true).toBool(); osem_fs_root = sts->value(N("OsemuFilesystemRoot"), "").toString(); res_at_compile = sts->value(N("ResetAtCompile"), true).toBool(); elf_path = sts->value(N("Elf"), DF_ELF).toString(); cch_program = CacheConfig(sts, N("ProgramCache_")); cch_data = CacheConfig(sts, N("DataCache_")); cch_level2 = CacheConfig(sts, N("Level2Cache_")); // Branch predictor bp_enabled = sts->value(N("BranchPredictor_Enabled"), DFC_BP_ENABLED).toBool(); bp_type = (PredictorType)sts->value(N("BranchPredictor_Type"), (uint8_t)DFC_BP_TYPE).toUInt(); bp_init_state = (PredictorState)sts->value(N("BranchPredictor_InitState"), (uint8_t)DFC_BP_INIT_STATE) .toUInt(); bp_btb_bits = sts->value(N("BranchPredictor_BitsBTB"), DFC_BP_BTB_BITS).toUInt(); bp_bhr_bits = sts->value(N("BranchPredictor_BitsBHR"), DFC_BP_BHR_BITS).toUInt(); bp_bht_addr_bits = sts->value(N("BranchPredictor_BitsBHTAddr"), DFC_BP_BHT_ADDR_BITS).toUInt(); bp_bht_bits = bp_bhr_bits + bp_bht_addr_bits; } void MachineConfig::store(QSettings *sts, const QString &prefix) { sts->setValue(N("XlenBits"), get_simulated_xlen() == Xlen::_64 ? 64 : 32); sts->setValue(N("IsaWord"), get_isa_word().toUnsigned()); sts->setValue(N("Pipelined"), pipelined()); sts->setValue(N("DelaySlot"), delay_slot()); sts->setValue(N("HazardUnit"), (unsigned)hazard_unit()); sts->setValue(N("MemoryRead"), memory_access_time_read()); sts->setValue(N("MemoryWrite"), memory_access_time_write()); sts->setValue(N("MemoryBurst"), memory_access_time_burst()); sts->setValue(N("MemoryLevel2"), memory_access_time_level2()); sts->setValue(N("MemoryBurstEnable"), memory_access_enable_burst()); sts->setValue(N("OsemuEnable"), osemu_enable()); sts->setValue(N("OsemuKnownSyscallStop"), osemu_known_syscall_stop()); sts->setValue(N("OsemuUnknownSyscallStop"), osemu_unknown_syscall_stop()); sts->setValue(N("OsemuInterruptStop"), osemu_interrupt_stop()); sts->setValue(N("OsemuExceptionStop"), osemu_exception_stop()); sts->setValue(N("OsemuFilesystemRoot"), osemu_fs_root()); sts->setValue(N("ResetAtCompile"), reset_at_compile()); sts->setValue(N("Elf"), elf_path); cch_program.store(sts, N("ProgramCache_")); cch_data.store(sts, N("DataCache_")); cch_level2.store(sts, N("Level2Cache_")); // Branch predictor sts->setValue(N("BranchPredictor_Enabled"), get_bp_enabled()); sts->setValue(N("BranchPredictor_Type"), (uint8_t)get_bp_type()); sts->setValue(N("BranchPredictor_InitState"), (uint8_t)get_bp_init_state()); sts->setValue(N("BranchPredictor_BitsBTB"), get_bp_btb_bits()); sts->setValue(N("BranchPredictor_BitsBHR"), get_bp_bhr_bits()); sts->setValue(N("BranchPredictor_BitsBHTAddr"), get_bp_bht_addr_bits()); } #undef N void MachineConfig::preset(enum ConfigPresets p) { // Note: we set just a minimal subset to get preset (preserving as much of // hidden configuration as possible) switch (p) { case CP_SINGLE: case CP_SINGLE_CACHE: set_pipelined(false); set_delay_slot(true); break; case CP_PIPE_NO_HAZARD: set_pipelined(true); set_hazard_unit(MachineConfig::HU_NONE); break; case CP_PIPE: set_pipelined(true); set_hazard_unit(MachineConfig::HU_STALL_FORWARD); break; } // Some common configurations set_memory_execute_protection(DF_EXEC_PROTEC); set_memory_write_protection(DF_WRITE_PROTEC); set_memory_access_time_read(DF_MEM_ACC_READ); set_memory_access_time_write(DF_MEM_ACC_WRITE); set_memory_access_time_burst(DF_MEM_ACC_BURST); set_memory_access_time_level2(DF_MEM_ACC_LEVEL2); set_memory_access_enable_burst(DF_MEM_ACC_BURST_ENABLE); // Branch predictor set_bp_enabled(DFC_BP_ENABLED); set_bp_type(DFC_BP_TYPE); set_bp_init_state(DFC_BP_INIT_STATE); set_bp_btb_bits(DFC_BP_BTB_BITS); set_bp_bhr_bits(DFC_BP_BHR_BITS); set_bp_bht_addr_bits(DFC_BP_BHT_ADDR_BITS); access_cache_program()->preset(p); access_cache_data()->preset(p); access_cache_level2()->preset(p); set_simulated_xlen(Xlen::_32); set_isa_word(config_isa_word_default); switch (p) { case CP_SINGLE: case CP_SINGLE_CACHE: case CP_PIPE_NO_HAZARD: case CP_PIPE: access_cache_level2()->set_enabled(false); break; } } void MachineConfig::set_pipelined(bool v) { pipeline = v; } void MachineConfig::set_delay_slot(bool v) { delayslot = v; } void MachineConfig::set_hazard_unit(enum MachineConfig::HazardUnit hu) { hunit = hu; } bool MachineConfig::set_hazard_unit(const QString &hukind) { static QMap hukind_map = { { "none", HU_NONE }, { "stall", HU_STALL }, { "forward", HU_STALL_FORWARD }, { "stall-forward", HU_STALL_FORWARD }, }; if (!hukind_map.contains(hukind)) { return false; } set_hazard_unit(hukind_map.value(hukind)); return true; } void MachineConfig::set_memory_execute_protection(bool v) { exec_protect = v; } void MachineConfig::set_memory_write_protection(bool v) { write_protect = v; } void MachineConfig::set_memory_access_time_read(unsigned v) { mem_acc_read = v; } void MachineConfig::set_memory_access_time_write(unsigned v) { mem_acc_write = v; } void MachineConfig::set_memory_access_time_burst(unsigned v) { mem_acc_burst = v; } void MachineConfig::set_memory_access_time_level2(unsigned v) { mem_acc_level2 = v; } void MachineConfig::set_memory_access_enable_burst(bool v) { mem_acc_enable_burst = v; } void MachineConfig::set_osemu_enable(bool v) { osem_enable = v; } void MachineConfig::set_osemu_known_syscall_stop(bool v) { osem_known_syscall_stop = v; } void MachineConfig::set_osemu_unknown_syscall_stop(bool v) { osem_unknown_syscall_stop = v; } void MachineConfig::set_osemu_interrupt_stop(bool v) { osem_interrupt_stop = v; } void MachineConfig::set_osemu_exception_stop(bool v) { osem_exception_stop = v; } void MachineConfig::set_osemu_fs_root(QString v) { osem_fs_root = std::move(v); } void MachineConfig::set_reset_at_compile(bool v) { res_at_compile = v; } void MachineConfig::set_elf(QString path) { elf_path = std::move(path); } void MachineConfig::set_cache_program(const CacheConfig &c) { cch_program = c; } void MachineConfig::set_cache_data(const CacheConfig &c) { cch_data = c; } void MachineConfig::set_cache_level2(const CacheConfig &c) { cch_level2 = c; } void MachineConfig::set_simulated_endian(Endian endian) { MachineConfig::simulated_endian = endian; } void MachineConfig::set_simulated_xlen(Xlen xlen) { simulated_xlen = xlen; } void MachineConfig::set_isa_word(ConfigIsaWord bits) { isa_word = bits | config_isa_word_fixed; } void MachineConfig::modify_isa_word(ConfigIsaWord mask, ConfigIsaWord val) { mask &= ~config_isa_word_fixed; isa_word.modify(mask, val); } bool MachineConfig::pipelined() const { return pipeline; } bool MachineConfig::delay_slot() const { // Delay slot is always on when pipeline is enabled return pipeline || delayslot; } enum MachineConfig::HazardUnit MachineConfig::hazard_unit() const { // Hazard unit is always off when there is no pipeline return pipeline ? hunit : machine::MachineConfig::HU_NONE; } bool MachineConfig::memory_execute_protection() const { return exec_protect; } bool MachineConfig::memory_write_protection() const { return write_protect; } unsigned MachineConfig::memory_access_time_read() const { return mem_acc_read > 1 ? mem_acc_read : 1; } unsigned MachineConfig::memory_access_time_write() const { return mem_acc_write > 1 ? mem_acc_write : 1; } unsigned MachineConfig::memory_access_time_burst() const { return mem_acc_burst; } unsigned MachineConfig::memory_access_time_level2() const { return mem_acc_level2; } bool MachineConfig::memory_access_enable_burst() const { return mem_acc_enable_burst; } bool MachineConfig::osemu_enable() const { return osem_enable; } bool MachineConfig::osemu_known_syscall_stop() const { return osem_known_syscall_stop; } bool MachineConfig::osemu_unknown_syscall_stop() const { return osem_unknown_syscall_stop; } bool MachineConfig::osemu_interrupt_stop() const { return osem_interrupt_stop; } bool MachineConfig::osemu_exception_stop() const { return osem_exception_stop; } QString MachineConfig::osemu_fs_root() const { return osem_fs_root; } bool MachineConfig::reset_at_compile() const { return res_at_compile; } QString MachineConfig::elf() const { return elf_path; } const CacheConfig &MachineConfig::cache_program() const { return cch_program; } const CacheConfig &MachineConfig::cache_data() const { return cch_data; } const CacheConfig &MachineConfig::cache_level2() const { return cch_level2; } CacheConfig *MachineConfig::access_cache_program() { return &cch_program; } CacheConfig *MachineConfig::access_cache_data() { return &cch_data; } CacheConfig *MachineConfig::access_cache_level2() { return &cch_level2; } Endian MachineConfig::get_simulated_endian() const { return simulated_endian; } Xlen MachineConfig::get_simulated_xlen() const { return simulated_xlen; } ConfigIsaWord MachineConfig::get_isa_word() const { return isa_word; } void MachineConfig::set_bp_enabled(bool e) { bp_enabled = e; } void MachineConfig::set_bp_type(PredictorType t) { bp_type = t; } void MachineConfig::set_bp_init_state(PredictorState i) { bp_init_state = i; } void MachineConfig::set_bp_btb_bits(uint8_t b) { bp_btb_bits = b > BP_MAX_BTB_BITS ? BP_MAX_BTB_BITS : b; } void MachineConfig::set_bp_bhr_bits(uint8_t b) { bp_bhr_bits = b > BP_MAX_BHR_BITS ? BP_MAX_BHR_BITS : b; bp_bht_addr_bits = bp_bht_addr_bits > BP_MAX_BHT_ADDR_BITS ? BP_MAX_BHT_ADDR_BITS : bp_bht_addr_bits; bp_bht_bits = bp_bhr_bits + bp_bht_addr_bits; bp_bht_bits = bp_bht_bits > BP_MAX_BHT_BITS ? BP_MAX_BHT_BITS : bp_bht_bits; } void MachineConfig::set_bp_bht_addr_bits(uint8_t b) { bp_bht_addr_bits = b > BP_MAX_BHT_ADDR_BITS ? BP_MAX_BHT_ADDR_BITS : b; bp_bhr_bits = bp_bhr_bits > BP_MAX_BHR_BITS ? BP_MAX_BHR_BITS : bp_bhr_bits; bp_bht_bits = bp_bhr_bits + bp_bht_addr_bits; bp_bht_bits = bp_bht_bits > BP_MAX_BHT_BITS ? BP_MAX_BHT_BITS : bp_bht_bits; } bool MachineConfig::get_bp_enabled() const { return bp_enabled; } PredictorType MachineConfig::get_bp_type() const { return bp_type; } PredictorState MachineConfig::get_bp_init_state() const { return bp_init_state; } uint8_t MachineConfig::get_bp_btb_bits() const { return bp_btb_bits; } uint8_t MachineConfig::get_bp_bhr_bits() const { return bp_bhr_bits; } uint8_t MachineConfig::get_bp_bht_addr_bits() const { return bp_bht_addr_bits; } uint8_t MachineConfig::get_bp_bht_bits() const { return bp_bht_bits; } bool MachineConfig::operator==(const MachineConfig &c) const { #define CMP(GETTER) (GETTER)() == (c.GETTER)() return CMP(pipelined) && CMP(delay_slot) && CMP(hazard_unit) && CMP(get_simulated_xlen) && CMP(get_isa_word) && CMP(get_bp_enabled) && CMP(get_bp_type) && CMP(get_bp_init_state) && CMP(get_bp_btb_bits) && CMP(get_bp_bhr_bits) && CMP(get_bp_bht_addr_bits) && CMP(memory_execute_protection) && CMP(memory_write_protection) && CMP(memory_access_time_read) && CMP(memory_access_time_write) && CMP(memory_access_time_burst) && CMP(memory_access_time_level2) && CMP(memory_access_enable_burst) && CMP(elf) && CMP(cache_program) && CMP(cache_data) && CMP(cache_level2); #undef CMP } bool MachineConfig::operator!=(const MachineConfig &c) const { return !operator==(c); } qtrvsim-0.9.8/src/machine/machineconfig.h000066400000000000000000000166001467752164200204140ustar00rootroot00000000000000#ifndef MACHINECONFIG_H #define MACHINECONFIG_H #include "common/endian.h" #include "config_isa.h" #include "predictor_types.h" #include #include namespace machine { /** * There are two primary base integer variants, RV32I and RV64I, described in Chapters 2 and 5, * which provide 32-bit or 64-bit address spaces respectively. We use the term XLEN to refer to * the width of an integer register in bits (either 32 or 64). [RISC-V Unprivileged ISA, page 4] * * `RegisterValue` type is used to abstract the size of stored value. It provides methods to get * correct size. The `Core` can extract them with a special method. */ enum class Xlen { _32 = 32, _64 = 64 }; enum ConfigPresets { CP_SINGLE, // No pipeline cpu without cache CP_SINGLE_CACHE, // No pipeline cpu with cache CP_PIPE_NO_HAZARD, // Pipelined cpu without hazard unit and without cache CP_PIPE // Full pipelined cpu }; constexpr ConfigIsaWord config_isa_word_default = ConfigIsaWord::byChar('E') | ConfigIsaWord::byChar('I') | ConfigIsaWord::byChar('A') |ConfigIsaWord::byChar('M'); constexpr ConfigIsaWord config_isa_word_fixed = ConfigIsaWord::byChar('E') | ConfigIsaWord::byChar('I'); class CacheConfig { public: CacheConfig(); explicit CacheConfig(const CacheConfig *cc); explicit CacheConfig(const QSettings *, const QString &prefix = ""); void store(QSettings *, const QString &prefix = "") const; void preset(enum ConfigPresets); enum ReplacementPolicy { RP_RAND, // Random RP_LRU, // Least recently used RP_LFU, // Least frequently used RP_PLRU // Pseudo Least recently used }; enum WritePolicy { WP_THROUGH_NOALLOC, // Write through WP_THROUGH_ALLOC, // Write through WP_BACK // Write back }; // If cache should be used or not void set_enabled(bool); void set_set_count(unsigned); // Number of sets void set_block_size(unsigned); // Number of uint32_t in block void set_associativity(unsigned); // Degree of associativity (number of // ways) void set_replacement_policy(enum ReplacementPolicy); void set_write_policy(enum WritePolicy); bool enabled() const; unsigned set_count() const; unsigned block_size() const; unsigned associativity() const; enum ReplacementPolicy replacement_policy() const; enum WritePolicy write_policy() const; bool operator==(const CacheConfig &c) const; bool operator!=(const CacheConfig &c) const; private: bool en; unsigned n_sets, n_blocks, d_associativity; enum ReplacementPolicy replac_pol; enum WritePolicy write_pol; }; class MachineConfig { public: MachineConfig(); explicit MachineConfig(const MachineConfig *config); explicit MachineConfig(const QSettings *, const QString &prefix = ""); void store(QSettings *, const QString &prefix = ""); void preset(enum ConfigPresets); enum HazardUnit { HU_NONE, HU_STALL, HU_STALL_FORWARD }; // Configure if CPU is pipelined // In default disabled. void set_pipelined(bool); // Configure if cpu should simulate delay slot in non-pipelined core // In default enabled. When disabled it also automatically disables // pipelining. void set_delay_slot(bool); // Hazard unit void set_hazard_unit(enum HazardUnit); bool set_hazard_unit(const QString &hukind); // Protect data memory from execution. Only program sections can be // executed. void set_memory_execute_protection(bool); // Protect program memory from accidental writes. void set_memory_write_protection(bool); // Set memory access times. Passed value is in cycles. void set_memory_access_time_read(unsigned); void set_memory_access_time_write(unsigned); void set_memory_access_time_burst(unsigned); void set_memory_access_time_level2(unsigned); void set_memory_access_enable_burst(bool); // Operating system and exceptions setup void set_osemu_enable(bool); void set_osemu_known_syscall_stop(bool); void set_osemu_unknown_syscall_stop(bool); void set_osemu_interrupt_stop(bool); void set_osemu_exception_stop(bool); void set_osemu_fs_root(QString v); // reset machine befor internal compile/reload after external make void set_reset_at_compile(bool); // Set path to source elf file. This has to be set before core is // initialized. void set_elf(QString path); // Configure cache void set_cache_program(const CacheConfig &); void set_cache_data(const CacheConfig &); void set_cache_level2(const CacheConfig &); void set_simulated_endian(Endian endian); void set_simulated_xlen(Xlen xlen); void set_isa_word(ConfigIsaWord bits); void modify_isa_word(ConfigIsaWord mask, ConfigIsaWord val); bool pipelined() const; bool delay_slot() const; enum HazardUnit hazard_unit() const; bool memory_execute_protection() const; bool memory_write_protection() const; unsigned memory_access_time_read() const; unsigned memory_access_time_write() const; unsigned memory_access_time_burst() const; unsigned memory_access_time_level2() const; bool memory_access_enable_burst() const; bool osemu_enable() const; bool osemu_known_syscall_stop() const; bool osemu_unknown_syscall_stop() const; bool osemu_interrupt_stop() const; bool osemu_exception_stop() const; QString osemu_fs_root() const; bool reset_at_compile() const; QString elf() const; const CacheConfig &cache_program() const; const CacheConfig &cache_data() const; const CacheConfig &cache_level2() const; Endian get_simulated_endian() const; Xlen get_simulated_xlen() const; ConfigIsaWord get_isa_word() const; // Branch predictor - Setters void set_bp_enabled(bool e); void set_bp_type(PredictorType t); void set_bp_init_state(PredictorState i); void set_bp_btb_bits(uint8_t b); void set_bp_bhr_bits(uint8_t b); void set_bp_bht_addr_bits(uint8_t b); // Branch predictor - Getters bool get_bp_enabled() const; PredictorType get_bp_type() const; PredictorState get_bp_init_state() const; uint8_t get_bp_btb_bits() const; uint8_t get_bp_bhr_bits() const; uint8_t get_bp_bht_addr_bits() const; uint8_t get_bp_bht_bits() const; CacheConfig *access_cache_program(); CacheConfig *access_cache_data(); CacheConfig *access_cache_level2(); bool operator==(const MachineConfig &c) const; bool operator!=(const MachineConfig &c) const; private: bool pipeline, delayslot; enum HazardUnit hunit; bool exec_protect, write_protect; unsigned mem_acc_read, mem_acc_write, mem_acc_burst, mem_acc_level2; bool mem_acc_enable_burst; bool osem_enable, osem_known_syscall_stop, osem_unknown_syscall_stop; bool osem_interrupt_stop, osem_exception_stop; bool res_at_compile; QString osem_fs_root; QString elf_path; CacheConfig cch_program, cch_data, cch_level2; Endian simulated_endian; Xlen simulated_xlen; ConfigIsaWord isa_word; // Branch predictor bool bp_enabled; PredictorType bp_type; PredictorState bp_init_state; uint8_t bp_btb_bits; uint8_t bp_bhr_bits; uint8_t bp_bht_addr_bits; uint8_t bp_bht_bits; // = bp_bhr_bits + bp_bht_addr_bits }; } // namespace machine Q_DECLARE_METATYPE(machine::CacheConfig) #endif // MACHINECONFIG_H qtrvsim-0.9.8/src/machine/machinedefs.h000066400000000000000000000060351467752164200200710ustar00rootroot00000000000000#ifndef MACHINEDEFS_H #define MACHINEDEFS_H #include "memory/address.h" #include #include namespace machine { enum AccessControl { AC_NONE, AC_I8, AC_U8, AC_I16, AC_U16, AC_I32, AC_U32, AC_I64, AC_U64, AC_LR32, AC_SC32, AC_AMOSWAP32, AC_AMOADD32, AC_AMOXOR32, AC_AMOAND32, AC_AMOOR32, AC_AMOMIN32, AC_AMOMAX32, AC_AMOMINU32, AC_AMOMAXU32, AC_LR64, AC_SC64, AC_AMOSWAP64, AC_AMOADD64, AC_AMOXOR64, AC_AMOAND64, AC_AMOOR64, AC_AMOMIN64, AC_AMOMAX64, AC_AMOMINU64, AC_AMOMAXU64, AC_CACHE_OP, }; constexpr AccessControl AC_FIRST_REGULAR = AC_I8; constexpr AccessControl AC_LAST_REGULAR = AC_U64; constexpr AccessControl AC_FIRST_SPECIAL = AC_LR32; constexpr AccessControl AC_LAST_SPECIAL = AC_CACHE_OP; constexpr AccessControl AC_FISRT_AMO_MODIFY32 = AC_AMOSWAP32; constexpr AccessControl AC_LAST_AMO_MODIFY32 = AC_AMOMAXU32; constexpr AccessControl AC_FISRT_AMO_MODIFY64 = AC_AMOSWAP64; constexpr AccessControl AC_LAST_AMO_MODIFY64 = AC_AMOMAXU64; constexpr bool is_regular_access(AccessControl type) { return AC_FIRST_REGULAR <= type and type <= AC_LAST_REGULAR; } constexpr bool is_special_access(AccessControl type) { return AC_FIRST_SPECIAL <= type and type <= AC_LAST_SPECIAL; } static_assert(is_special_access(AC_CACHE_OP), ""); static_assert(is_special_access((AccessControl)11), ""); enum ExceptionCause { EXCAUSE_NONE = 0, // Use zero as default value when no exception is // ECAUSE_INSN_MISALIGNED - not defined for now, overlaps with EXCAUSE_NON EXCAUSE_INSN_FAULT = 1, // Instruction access fault EXCAUSE_INSN_ILLEGAL = 2, // Illegal instruction EXCAUSE_BREAK = 3, // Breakpoint EXCAUSE_LOAD_MISALIGNED = 4, // Load address misaligned EXCAUSE_LOAD_FAULT = 5, // Load access fault EXCAUSE_STORE_MISALIGNED = 6, // Store/AMO address misaligned EXCAUSE_STORE_FAULT = 7, // Store/AMO access fault EXCAUSE_ECALL_U = 8, // Environment call from U-mode EXCAUSE_ECALL_S = 9, // Environment call from S-mode EXCAUSE_RESERVED_10 = 10, // Reserved EXCAUSE_ECALL_M = 11, // Environment call from M-mode EXCAUSE_INSN_PAGE_FAULT = 12, // Instruction page fault EXCAUSE_LOAD_PAGE_FAULT = 13, // Load page fault EXCAUSE_RESERVED_14 = 14, // Reserved EXCAUSE_STORE_PAGE_FAULT = 15, // Store/AMO page fault // Simulator specific exception cause codes, alliases EXCAUSE_HWBREAK = 16, EXCAUSE_ECALL_ANY = 17, // sythetic exception to mark ECALL instruction EXCAUSE_INT = 18, // External/asynchronous interrupt, bit 32 or 63 EXCAUSE_COUNT = 19, }; enum LocationStatus { LOCSTAT_NONE = 0, LOCSTAT_CACHED = 1 << 0, LOCSTAT_DIRTY = 1 << 1, LOCSTAT_READ_ONLY = 1 << 2, LOCSTAT_ILLEGAL = 1 << 3, }; const Address STAGEADDR_NONE = 0xffffffff_addr; } // namespace machine Q_DECLARE_METATYPE(machine::AccessControl) #endif // MACHINEDEFS_H qtrvsim-0.9.8/src/machine/memory/000077500000000000000000000000001467752164200167565ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/memory/address.h000066400000000000000000000141611467752164200205570ustar00rootroot00000000000000#ifndef ADDRESS_H #define ADDRESS_H #include "utils.h" #include #include using std::uint64_t; namespace machine { /** * Emulated physical memory address. * * It is guaranteed that all instances of this type belong to single address * space and therefore all can be compared fearlessly. *

* OPTIMIZATION NOTE: All methods are implemented in header file to support * inlining (as we want to use it as a primitive type) but too keep declaration * tidy out-of-line definitions are preferred. */ class Address { private: uint64_t data; //> Real wrapped address public: constexpr explicit Address(uint64_t); /** * Default constructor results in null pointer. * Why it exists? To make address default constructable for STL. */ constexpr Address(); constexpr Address(const Address &address) = default; //> Copy constructor constexpr Address &operator=(const Address &address) = default; //> Assign constructor /** * Extracts raw numeric value of the address. * Why it exists? Output, unsafe operations not supported by operators. */ [[nodiscard]] constexpr uint64_t get_raw() const; /** * Explicit cast operator to underlying type. * This is an alternative ti get_raw() method. * * NOTE: This operator is needed for correct functioning of * repeat_access_until_completed function defined in memory_utils.h. */ constexpr explicit operator uint64_t() const; /** * More expressive way to assign null. * Why it exists? Equivalent of nullptr in cpp. Address(0) was ugly and too * common. */ constexpr static Address null(); /** * Test for null address * * Why is exists? Testing for null in very often and without this method a * creation of a new address object set to null would be required. That is * considered too long and badly readable. For other comparison we expect a * comparison with existing value to be the common case. * Alternative: `address.get_raw() == 0` * Alternative: `address == Address::null()` */ [[nodiscard]] constexpr bool is_null() const; /** * Test whether address is aligned to the size of type T. * * Example: * ``` * is_aligned(address) <=> address % 4 == 0 * ``` */ template [[nodiscard]] constexpr bool is_aligned() const; /* Eq */ constexpr inline bool operator==(const Address &other) const; constexpr inline bool operator!=(const Address &other) const; /* Ord */ constexpr inline bool operator<(const Address &other) const; constexpr inline bool operator>(const Address &other) const; constexpr inline bool operator<=(const Address &other) const; constexpr inline bool operator>=(const Address &other) const; /* Offset arithmetic */ constexpr inline Address operator+(const uint64_t &offset) const; constexpr inline Address operator-(const uint64_t &offset) const; inline void operator+=(const uint64_t &offset); inline void operator-=(const uint64_t &offset); /* Bitwise arithmetic */ constexpr inline Address operator&(const uint64_t &mask) const; constexpr inline Address operator|(const uint64_t &mask) const; constexpr inline Address operator^(const uint64_t &mask) const; constexpr inline Address operator>>(const uint64_t &size) const; constexpr inline Address operator<<(const uint64_t &size) const; /* Distance arithmetic */ constexpr inline int64_t operator-(const Address &other) const; }; constexpr Address operator"" _addr(unsigned long long literal) { return Address(literal); } constexpr Address::Address(uint64_t address) : data(address) {} constexpr Address::Address() : data(0) {} constexpr uint64_t Address::get_raw() const { return data; } constexpr Address::operator uint64_t() const { return this->get_raw(); } constexpr Address Address::null() { return Address(0x0); } constexpr bool Address::is_null() const { return this->get_raw() == 0; } template constexpr bool Address::is_aligned() const { return is_aligned_genericdata), T>(this->data); } /* * Equality operators */ constexpr bool Address::operator==(const Address &other) const { return this->get_raw() == other.get_raw(); } constexpr bool Address::operator!=(const Address &other) const { return this->get_raw() != other.get_raw(); } /* * Ordering operators */ constexpr bool Address::operator<(const Address &other) const { return this->get_raw() < other.get_raw(); } constexpr bool Address::operator>(const Address &other) const { return this->get_raw() > other.get_raw(); } constexpr bool Address::operator<=(const Address &other) const { return this->get_raw() <= other.get_raw(); } constexpr bool Address::operator>=(const Address &other) const { return this->get_raw() >= other.get_raw(); } /* * Offset arithmetic operators */ constexpr Address Address::operator+(const uint64_t &offset) const { return Address(this->get_raw() + offset); } constexpr Address Address::operator-(const uint64_t &offset) const { return Address(this->get_raw() - offset); } void Address::operator+=(const uint64_t &offset) { data += offset; } void Address::operator-=(const uint64_t &offset) { data -= offset; } /* * Bitwise operators */ constexpr Address Address::operator&(const uint64_t &mask) const { return Address(this->get_raw() & mask); } constexpr Address Address::operator|(const uint64_t &mask) const { return Address(this->get_raw() | mask); } constexpr Address Address::operator^(const uint64_t &mask) const { return Address(get_raw() ^ mask); } constexpr Address Address::operator>>(const uint64_t &size) const { return Address(this->get_raw() >> size); } constexpr Address Address::operator<<(const uint64_t &size) const { return Address(this->get_raw() << size); } /* * Distance arithmetic operators */ constexpr int64_t Address::operator-(const Address &other) const { return this->get_raw() - other.get_raw(); } } // namespace machine Q_DECLARE_METATYPE(machine::Address) #endif // ADDRESS_H qtrvsim-0.9.8/src/machine/memory/address_range.h000066400000000000000000000043061467752164200217330ustar00rootroot00000000000000#ifndef ADDRESS_RANGE_H #define ADDRESS_RANGE_H #include "utils.h" #include #include #include "memory/address.h" namespace machine { /** * Physical memory range - for nou used for range reservation for AMO operations * * If the first and the last point to the same address then range represnets * exaclly one valid byte. If the last is smaller than the first then range * is empty. */ class AddressRange { public: Address first; //> The first valid location of the range Address last; //> The last valid location of the range /** * Default constructor results for empty range. */ constexpr AddressRange() : first(1), last(0) {}; constexpr AddressRange(const AddressRange &range) = default; //> Copy constructor constexpr AddressRange(const Address &afirst, const Address &alast) : first(afirst), last(alast) {}; constexpr AddressRange(const Address &asingleAddr) : first(asingleAddr), last(asingleAddr) {}; constexpr AddressRange &operator=(const AddressRange &address) = default; //> Assign constructor /** * Is empty range */ constexpr bool is_empty() const { return first > last; }; /* Eq */ constexpr inline bool operator==(const AddressRange &other) const { return (first == other.first && last == other.last) || (is_empty() && other.is_empty()); }; constexpr inline bool operator!=(const AddressRange &other) const { return !((first == other.first && last == other.last) || (is_empty() && other.is_empty())); }; constexpr bool within(const AddressRange &other) const { return (first >= other.first) && (last <= other.last); }; constexpr bool contains(const AddressRange &other) const { return (first <= other.first) && (last >= other.last); }; constexpr bool overlaps(const AddressRange &other) const { return (first <= other.last) && (last >= other.first) && !is_empty() && !other.is_empty(); }; void reset() { first = Address(1); last = Address(0); } }; } // namespace machine Q_DECLARE_METATYPE(machine::AddressRange) #endif // ADDRESS_RANGE_H qtrvsim-0.9.8/src/machine/memory/backend/000077500000000000000000000000001467752164200203455ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/memory/backend/aclintmswi.cpp000066400000000000000000000055231467752164200232300ustar00rootroot00000000000000#include "memory/backend/aclintmswi.h" #include "common/endian.h" #include using ae = machine::AccessEffects; // For enum values, type is obvious from // context. namespace machine::aclint { AclintMswi::AclintMswi(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , mswi_irq_level(3) { mswi_count = 1; for (bool & i : mswi_value) i = false; } AclintMswi::~AclintMswi() = default; bool AclintMswi::update_mswi_irq() { bool active; active = mswi_value[0]; if (active != mswi_irq_active) { mswi_irq_active = active; emit signal_interrupt(mswi_irq_level, active); } return active; } WriteResult AclintMswi::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u32( destination, source, size, [&](Offset src) { return byteswap_if( read_reg32(src, options.type), internal_endian != simulated_machine_endian); }, [&](Offset src, uint32_t value) { return write_reg32( src, byteswap_if( value, internal_endian != simulated_machine_endian)); }); } ReadResult AclintMswi::read( void *destination, Offset source, size_t size, ReadOptions options) const { return read_by_u32(destination, source, size, [&](Offset src) { return byteswap_if( read_reg32(src, options.type), internal_endian != simulated_machine_endian); }); } uint32_t AclintMswi::read_reg32(Offset source, AccessEffects type) const { Q_UNUSED(type) Q_ASSERT((source & 3U) == 0); // uint32_t aligned uint32_t value = 0; if ((source >= ACLINT_MSWI_OFFSET) && (source < ACLINT_MSWI_OFFSET + 4 * mswi_count)) { value = mswi_value[source >> 2]? 1: 0; } emit read_notification(source, value); return value; } bool AclintMswi::write_reg32(Offset destination, uint32_t value) { Q_ASSERT((destination & 3U) == 0); // uint32_t aligned bool changed = false; if ((destination >= ACLINT_MSWI_OFFSET) && (destination < ACLINT_MSWI_OFFSET + 4 * mswi_count)) { bool value_bool = value & 1; changed = value_bool != mswi_value[destination >> 2]; mswi_value[destination >> 2] = value_bool; update_mswi_irq(); } else { printf("WARNING: ACLINT MSWI - read out of range (at 0x%zu).\n", destination); } emit write_notification(destination, value); return changed; } LocationStatus AclintMswi::location_status(Offset offset) const { if ((offset >= ACLINT_MSWI_OFFSET) && (offset < ACLINT_MSWI_OFFSET + 4 * mswi_count)) return LOCSTAT_NONE; return LOCSTAT_ILLEGAL; } } // namespace machine aclint qtrvsim-0.9.8/src/machine/memory/backend/aclintmswi.h000066400000000000000000000033601467752164200226720ustar00rootroot00000000000000#ifndef ACLINTMSWI_H #define ACLINTMSWI_H #include "common/endian.h" #include "memory/backend/backend_memory.h" #include #include namespace machine::aclint { constexpr Offset CLINT_MSWI_OFFSET = 0x0000u; constexpr Offset CLINT_MSWI_SIZE = 0x4000u; constexpr Offset ACLINT_MSWI_OFFSET = 0; constexpr Offset ACLINT_MSWI_COUNT_MAX = 1; // Timer interrupts // mip.MTIP and mie.MTIE are bit 7 // mip.STIP and mie.STIE are bit 5 // Software interrupts // mip.MSIP and mie.MSIE are bit 3 // mip.SSIP and mie.SSIE are bit 1 class AclintMswi : public BackendMemory { Q_OBJECT public: explicit AclintMswi(Endian simulated_machine_endian); ~AclintMswi() override; signals: void write_notification(Offset address, uint32_t value); void read_notification(Offset address, uint32_t value) const; void signal_interrupt(uint irq_level, bool active) const; public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; private: /** endian of internal registers of the periphery use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; [[nodiscard]] uint32_t read_reg32(Offset source, AccessEffects type) const; bool write_reg32(Offset destination, uint32_t value); bool update_mswi_irq(); unsigned mswi_count; bool mswi_value[ACLINT_MSWI_COUNT_MAX]{}; const uint8_t mswi_irq_level; bool mswi_irq_active = false; }; } // namespace machine aclint #endif // ACLINTMSWI_H qtrvsim-0.9.8/src/machine/memory/backend/aclintmtimer.cpp000066400000000000000000000107761467752164200235540ustar00rootroot00000000000000#include "memory/backend/aclintmtimer.h" #include "common/endian.h" #include #include LOG_CATEGORY("machine.memory.aclintmtimer"); using ae = machine::AccessEffects; // For enum values, type is obvious from // context. namespace machine::aclint { AclintMtimer::AclintMtimer(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , mtimer_irq_level(7) { mtimecmp_count = 1; for (auto &value : mtimecmp_value) { value = 0; } mtime_start_offset = QTime::currentTime(); qt_timer_id = -1; } AclintMtimer::~AclintMtimer() { if (qt_timer_id >= 0) killTimer(qt_timer_id); qt_timer_id = -1; } uint64_t AclintMtimer::mtime_fetch_current() const { QTime current_time = QTime::currentTime(); mtime_last_current_fetch = mtime_start_offset.msecsTo(current_time) * (uint64_t)10000; return mtime_last_current_fetch; } bool AclintMtimer::update_mtimer_irq() { bool active; active = mtimecmp_value[0] < mtime_last_current_fetch + mtime_user_offset; if (active != mtimer_irq_active) { mtimer_irq_active = active; emit signal_interrupt(mtimer_irq_level, active); } if (active) { if (qt_timer_id >= 0) killTimer(qt_timer_id); qt_timer_id = -1; } return active; } void AclintMtimer::timerEvent(QTimerEvent *event) { if (event->timerId() == qt_timer_id) { if (qt_timer_id >= 0) killTimer(qt_timer_id); qt_timer_id = -1; mtime_fetch_current(); if (!update_mtimer_irq()) { arm_mtimer_event(); } } else { BackendMemory::timerEvent(event); } } void AclintMtimer::arm_mtimer_event() { if (qt_timer_id >= 0) killTimer(qt_timer_id); qt_timer_id = -1; uint64_t ticks_to_wait = mtimecmp_value[0] - (mtime_last_current_fetch + mtime_user_offset); qt_timer_id = startTimer(ticks_to_wait / 10000); } WriteResult AclintMtimer::write(Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u64( destination, source, size, [&](Offset src) { return byteswap_if( read_reg64(src, options.type), internal_endian != simulated_machine_endian); }, [&](Offset src, uint64_t value) { return write_reg64( src, byteswap_if(value, internal_endian != simulated_machine_endian)); }); } ReadResult AclintMtimer::read(void *destination, Offset source, size_t size, ReadOptions options) const { return read_by_u64(destination, source, size, [&](Offset src) { return byteswap_if( read_reg64(src, options.type), internal_endian != simulated_machine_endian); }); } uint64_t AclintMtimer::read_reg64(Offset source, AccessEffects type) const { Q_UNUSED(type) Q_ASSERT((source & 7U) == 0); // uint64_t aligned uint64_t value = 0; if (source == ACLINT_MTIME_OFFSET) { if (type == AccessEffects::REGULAR) mtime_fetch_current(); value = mtime_last_current_fetch + mtime_user_offset; } else if ( (source >= ACLINT_MTIMECMP_OFFSET) && (source < ACLINT_MTIMECMP_OFFSET + 8 * mtimecmp_count)) { value = mtimecmp_value[source >> 3]; } emit read_notification(source, value); return value; } bool AclintMtimer::write_reg64(Offset destination, uint64_t value) { Q_ASSERT((destination & 7U) == 0); // uint64_t aligned bool changed = false; if (destination == ACLINT_MTIME_OFFSET) { mtime_fetch_current(); mtime_user_offset = value - mtime_last_current_fetch; if (!update_mtimer_irq()) arm_mtimer_event(); changed = true; } else if ( (destination >= ACLINT_MTIMECMP_OFFSET) && (destination < ACLINT_MTIMECMP_OFFSET + 8 * mtimecmp_count)) { changed = value != mtimecmp_value[destination >> 3]; mtimecmp_value[destination >> 3] = value; if (!update_mtimer_irq()) arm_mtimer_event(); } else { WARN("ACLINT MTIMER - read out of range (at 0x%zu).\n", destination); } emit write_notification(destination, value); return changed; } LocationStatus AclintMtimer::location_status(Offset offset) const { if ((offset >= ACLINT_MTIMECMP_OFFSET) && (offset < ACLINT_MTIMECMP_OFFSET + 8 * mtimecmp_count)) return LOCSTAT_NONE; if ((offset & ~7U) == ACLINT_MTIME_OFFSET) return LOCSTAT_NONE; // LOCSTAT_NONE / LOCSTAT_READ_ONLY return LOCSTAT_ILLEGAL; } } // namespace machine::aclint qtrvsim-0.9.8/src/machine/memory/backend/aclintmtimer.h000066400000000000000000000044421467752164200232120ustar00rootroot00000000000000#ifndef ACLINTMTIMER_H #define ACLINTMTIMER_H #include "common/endian.h" #include "memory/backend/backend_memory.h" #include #include namespace machine { namespace aclint { constexpr Offset CLINT_MTIMER_OFFSET = 0x4000u; constexpr Offset CLINT_MTIMER_SIZE = 0x8000u; constexpr Offset ACLINT_MTIME_OFFSET = 0x7ff8u; constexpr Offset ACLINT_MTIME_SIZE = 0x8u; constexpr Offset ACLINT_MTIMECMP_OFFSET = 0x0000u; constexpr Offset ACLINT_MTIMECMP_SIZE = 0x7ff8u; constexpr unsigned ACLINT_MTIMECMP_COUNT_MAX = 1; // Timer interrupts // mip.MTIP and mie.MTIE are bit 7 // mip.STIP and mie.STIE are bit 5 // Software interrupts // mip.MSIP and mie.MSIE are bit 3 // mip.SSIP and mie.SSIE are bit 1 class AclintMtimer : public BackendMemory { Q_OBJECT public: explicit AclintMtimer(Endian simulated_machine_endian); ~AclintMtimer() override; signals: void write_notification(Offset address, uint32_t value); void read_notification(Offset address, uint32_t value) const; void signal_interrupt(uint irq_level, bool active) const; public: uint64_t mtime_fetch_current() const; WriteResult write(Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read(void *destination, Offset source, size_t size, ReadOptions options) const override; LocationStatus location_status(Offset offset) const override; private: void timerEvent(QTimerEvent *event) override; /** endian of internal registers of the periphery use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; uint64_t read_reg64(Offset source, AccessEffects type) const; bool write_reg64(Offset destination, uint64_t value); bool update_mtimer_irq(); void arm_mtimer_event(); unsigned mtimecmp_count; uint64_t mtimecmp_value[ACLINT_MTIMECMP_COUNT_MAX] {}; const uint8_t mtimer_irq_level; QTime mtime_start_offset; uint64_t mtime_user_offset = 0; mutable uint64_t mtime_last_current_fetch = 0; mutable bool mtimer_irq_active = false; int qt_timer_id = -1; }; }} // namespace machine::aclint #endif // ACLINTMTIMER_H qtrvsim-0.9.8/src/machine/memory/backend/aclintsswi.cpp000066400000000000000000000047571467752164200232460ustar00rootroot00000000000000#include "memory/backend/aclintsswi.h" #include "common/endian.h" #include #include using ae = machine::AccessEffects; // For enum values, type is obvious from // context. namespace machine { namespace aclint { AclintSswi::AclintSswi(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , sswi_irq_level(1) { sswi_count = 1; } AclintSswi::~AclintSswi() = default; WriteResult AclintSswi::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u32( destination, source, size, [&](Offset src) { return byteswap_if( read_reg32(src, options.type), internal_endian != simulated_machine_endian); }, [&](Offset src, uint32_t value) { return write_reg32( src, byteswap_if( value, internal_endian != simulated_machine_endian)); }); } ReadResult AclintSswi::read( void *destination, Offset source, size_t size, ReadOptions options) const { return read_by_u32(destination, source, size, [&](Offset src) { return byteswap_if( read_reg32(src, options.type), internal_endian != simulated_machine_endian); }); } uint32_t AclintSswi::read_reg32(Offset source, AccessEffects type) const { Q_UNUSED(type) Q_ASSERT((source & 3U) == 0); // uint32_t aligned uint32_t value = 0; if ((source >= ACLINT_SSWI_OFFSET) && (source < ACLINT_SSWI_OFFSET + 4 * sswi_count)) { } emit read_notification(source, value); return value; } bool AclintSswi::write_reg32(Offset destination, uint32_t value) { Q_ASSERT((destination & 3U) == 0); // uint32_t aligned bool changed = false; if ((destination >= ACLINT_SSWI_OFFSET) && (destination < ACLINT_SSWI_OFFSET + 4 * sswi_count)) { bool value_bool = value & 1; if (value_bool) emit signal_interrupt(sswi_irq_level, value_bool); } else { printf("WARNING: ACLINT SSWI - read out of range (at 0x%zu).\n", destination); } emit write_notification(destination, value); return changed; } LocationStatus AclintSswi::location_status(Offset offset) const { if ((offset >= ACLINT_SSWI_OFFSET) && (offset < ACLINT_SSWI_OFFSET + 4 * sswi_count)) return LOCSTAT_NONE; return LOCSTAT_ILLEGAL; } } } // namespace machine aclint qtrvsim-0.9.8/src/machine/memory/backend/aclintsswi.h000066400000000000000000000032031467752164200226740ustar00rootroot00000000000000#ifndef ACLINTSSWI_H #define ACLINTSSWI_H #include "common/endian.h" #include "memory/backend/backend_memory.h" #include #include namespace machine::aclint { constexpr Offset CLINT_SSWI_OFFSET = 0xc000u; constexpr Offset CLINT_SSWI_SIZE = 0x4000u; constexpr Offset ACLINT_SSWI_OFFSET = 0; constexpr Offset ACLINT_SSWI_COUNT_MAX = 1; // Timer interrupts // mip.MTIP and mie.MTIE are bit 7 // mip.STIP and mie.STIE are bit 5 // Software interrupts // mip.MSIP and mie.MSIE are bit 3 // mip.SSIP and mie.SSIE are bit 1 class AclintSswi : public BackendMemory { Q_OBJECT public: explicit AclintSswi(Endian simulated_machine_endian); ~AclintSswi() override; signals: void write_notification(Offset address, uint32_t value); void read_notification(Offset address, uint32_t value) const; void signal_interrupt(uint irq_level, bool active) const; public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; private: /** endian of internal registers of the periphery use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; [[nodiscard]] uint32_t read_reg32(Offset source, AccessEffects type) const; bool write_reg32(Offset destination, uint32_t value); unsigned sswi_count; const uint8_t sswi_irq_level; }; } // namespace machine aclint #endif // ACLINTSSWI_H qtrvsim-0.9.8/src/machine/memory/backend/backend_memory.h000066400000000000000000000077441467752164200235110ustar00rootroot00000000000000#ifndef BACKEND_MEMORY_H #define BACKEND_MEMORY_H #include "common/endian.h" #include "machinedefs.h" #include "memory/memory_utils.h" #include // Shortcut for enum class values, type is obvious from context. using ae = machine::AccessEffects; namespace machine { /** * Relative index within an instance of backend memory. */ typedef size_t Offset; /** * Interface for physical memory or periphery. * . * Device implementing this interface is connected to the memory system via * memory data bus (`memory/memory_bus.h`). * * ## ENDIAN * Each device is responsible to return reads and write with the correct endian. * This is because there are different optimal ways to perform the swapping in * different kind of peripheries. For example, peripheries that have only word * (u23) accessible registers are simple to swap. * * All backend memory devices must set the `simulated_machine_endian` in * `BackendMemory` parent. They should also, by convention, have a private * (`const` or `static constexpr`) variable `internal_endian`. It can have * values `LITTLE | BIG | NATIVE_ENDIAN` (note: `NATIVE_ENDIAN` is a compile * time constant with endian of the host machine i.e. `LITTLE | BIG`). Byteswap * is needed, when internal and simulated endian are mismatched. * * ### Examples of internal endian values * - LED diode will have `NATIVE_ENDIAN` as the rgb value needs to be valid for * GUI. * - Memory mapped source will have runtime set endian, based on the file * endian. * - LCD has fixed `BIG` endian, as required by the hardware. */ class BackendMemory : public QObject { Q_OBJECT public: /** * @param simulated_machine_endian endian of the simulated CPU/memory * system */ explicit BackendMemory(Endian simulated_machine_endian); /** * Write byte sequence to memory. * * @param source pointer to array of bytes to be copied * @param destination relative index of destination to write to * @param size number of bytes to be written * @return true when memory before and after write differs */ virtual WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) = 0; /** * Read sequence of bytes from memory * * @param source relative index of data to be read * @param destination pointer to destination buffer * @param size number of bytes to be read * @param options additional option like debug mode, see type * definition */ virtual ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const = 0; /** * Determine status of given address. * * Applicable values: * - LOCSTAT_NONE normal RW area * - LOCSTAT_READ_ONLY read only hw register * - LOCSTAT_ILLEGAL address is not occupied, write will result in * NOP, read will return constant zero. */ [[nodiscard]] virtual enum LocationStatus location_status(Offset offset) const = 0; /** * Endian of the simulated CPU/memory system. * @see BackendMemory docs */ const Endian simulated_machine_endian; signals: /** * Notify upper layer about a change in managed physical memory of periphery * * @param mem_access this * @param start_addr affected area start * @param last_addr affected area end * @param type allowed side effects, see type declaration */ void external_backend_change_notify( const BackendMemory *mem_access, uint32_t start_addr, uint32_t last_addr, AccessEffects type) const; }; inline BackendMemory::BackendMemory(Endian simulated_machine_endian) : simulated_machine_endian(simulated_machine_endian) {} } // namespace machine #endif // BACKEND_MEMORY_H qtrvsim-0.9.8/src/machine/memory/backend/lcddisplay.cpp000066400000000000000000000104661467752164200232100ustar00rootroot00000000000000#include "lcddisplay.h" #include "common/endian.h" #ifdef DEBUG_LCD #undef DEBUG_LCD #define DEBUG_LCD true #else #define DEBUG_LCD false #endif namespace machine { LcdDisplay::LcdDisplay(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , fb_width(480) , fb_height(320) , fb_bits_per_pixel(16) , fb_data(get_fb_size_bytes(), 0) {} LcdDisplay::~LcdDisplay() = default; WriteResult LcdDisplay::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u16( destination, source, size, [&](Offset src) { return byteswap_if( read_raw_pixel(src), internal_endian != simulated_machine_endian); }, [&](Offset src, uint16_t value) { return write_raw_pixel( src, byteswap_if( value, internal_endian != simulated_machine_endian)); }); } ReadResult LcdDisplay::read( void *destination, Offset source, size_t size, ReadOptions options) const { UNUSED(options) return read_by_u16(destination, source, size, [&](Offset src) { return byteswap_if( read_raw_pixel(src), internal_endian != simulated_machine_endian); }); } uint16_t LcdDisplay::read_raw_pixel(Offset source) const { Q_ASSERT((source & 1U) == 0); // uint16_t aligned if (source + 1 >= get_fb_size_bytes()) { return 0; } uint16_t value; memcpy(&value, &fb_data[source], sizeof(value)); // TODO Switch to if constexpr as soon as we have cpp17. if (DEBUG_LCD) { printf( "LcdDisplay::read_reg address 0x%08lx data 0x%08lx\n", (unsigned long)source, (unsigned long)value); } emit read_notification(source, value); return value; } bool LcdDisplay::write_raw_pixel(Offset destination, uint16_t value) { Q_ASSERT((destination & 1U) == 0); // uint16_t aligned if (destination + 1 >= get_fb_size_bytes()) { printf("WARNING: LCD display - read out of range."); return false; } // TODO Switch to if constexpr as soon as we have cpp17. if (DEBUG_LCD) { printf( "LcdDisplay::write_reg address 0x%08lx data 0x%08lx\n", (unsigned long)destination, (unsigned long)value); } if (read_raw_pixel(destination) == value) { return false; } memcpy(&fb_data[destination], &value, sizeof(value)); size_t x, y; std::tie(x, y) = get_pixel_from_address(destination); const uint32_t last_addr = destination + 1; uint32_t pixel_addr; uint16_t pixel_data; uint r, g, b; while ((pixel_addr = get_address_from_pixel(x, y)) <= last_addr) { memcpy(&pixel_data, &fb_data[pixel_addr], sizeof(pixel_data)); r = ((pixel_data >> 11u) & 0x1fu) << 3u; g = ((pixel_data >> 5u) & 0x3fu) << 2u; b = ((pixel_data >> 0u) & 0x1fu) << 3u; emit pixel_update(x, y, r, g, b); if (++x >= fb_width) { x = 0; y++; } } emit write_notification(destination, value); return true; } size_t LcdDisplay::get_address_from_pixel(size_t x, size_t y) const { size_t address = y * get_fb_line_size(); if (fb_bits_per_pixel > 12) { address += x * divide_and_ceil(fb_bits_per_pixel, 8u); } else { address += x * fb_bits_per_pixel / 8; } return address; } std::tuple LcdDisplay::get_pixel_from_address(size_t address) const { size_t y = address / get_fb_line_size(); size_t x = (fb_bits_per_pixel > 12) ? (address - y * get_fb_line_size()) / ((fb_bits_per_pixel + 7) >> 3u) : (address - y * get_fb_line_size()) * 8 / fb_bits_per_pixel; return std::make_tuple(x, y); } size_t LcdDisplay::get_fb_line_size() const { return (fb_bits_per_pixel > 12) ? ((fb_bits_per_pixel + 7) >> 3u) * fb_width : (fb_bits_per_pixel * fb_width + 7) >> 3u; } size_t LcdDisplay::get_fb_size_bytes() const { return get_fb_line_size() * fb_height; } LocationStatus LcdDisplay::location_status(Offset offset) const { if ((offset | ~3u) >= get_fb_size_bytes()) { return LOCSTAT_ILLEGAL; } return LOCSTAT_NONE; } } // namespace machine qtrvsim-0.9.8/src/machine/memory/backend/lcddisplay.h000066400000000000000000000042001467752164200226420ustar00rootroot00000000000000#ifndef LCDDISPLAY_H #define LCDDISPLAY_H #include "common/endian.h" #include "machinedefs.h" #include "memory/backend/backend_memory.h" #include "simulator_exception.h" #include #include #include namespace machine { class LcdDisplay final : public BackendMemory { Q_OBJECT public: explicit LcdDisplay(Endian simulated_machine_endian); ~LcdDisplay() override; signals: void write_notification(Offset offset, uint32_t value) const; void read_notification(Offset offset, uint32_t value) const; void pixel_update(size_t x, size_t y, uint r, uint g, uint b); public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; /** * @return framebuffer width in pixels */ [[nodiscard]] inline constexpr size_t get_width() const { return fb_width; } /** * @return framebuffer height in pixels */ [[nodiscard]] inline constexpr size_t get_height() const { return fb_height; } private: /** Endian internal registers of the periphery (framebuffer) use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; /** Read HW register - allows only 32bit aligned access. */ [[nodiscard]] uint16_t read_raw_pixel(Offset source) const; /** Write HW register - allows only 32bit aligned access */ bool write_raw_pixel(Offset destination, uint16_t value); [[nodiscard]] size_t get_fb_line_size() const; [[nodiscard]] size_t get_fb_size_bytes() const; [[nodiscard]] size_t get_address_from_pixel(size_t x, size_t y) const; [[nodiscard]] std::tuple get_pixel_from_address(size_t address) const; const size_t fb_width; //> Width in pixels const size_t fb_height; //> Height in pixels const size_t fb_bits_per_pixel; std::vector fb_data; }; } // namespace machine #endif // LCDDISPLAY_H qtrvsim-0.9.8/src/machine/memory/backend/memory.cpp000066400000000000000000000231531467752164200223650ustar00rootroot00000000000000#include "memory/backend/memory.h" #include "common/endian.h" #include "simulator_exception.h" #include namespace machine { MemorySection::MemorySection( size_t length_bytes, Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , dt(length_bytes, 0) {} MemorySection::MemorySection(const MemorySection &other) : BackendMemory(other.simulated_machine_endian) , dt(other.dt) {} WriteResult MemorySection::write(Offset dst_offset, const void *source, size_t size, WriteOptions options) { UNUSED(options) auto destination = static_cast(dst_offset); if (destination >= length()) { throw SIMULATOR_EXCEPTION( OutOfMemoryAccess, "Trying to write outside of the memory section", QString("Accessing using offset: ") + QString::number(destination)); } // Size the can be read from this section const size_t available_size = std::min(destination + size, length()) - destination; // TODO, make swap conditional for big endian machines bool changed = memcmp(source, &dt[destination], available_size) != 0; if (changed) { memcpy(&dt[destination], source, available_size); } return { .n_bytes = available_size, .changed = changed }; } ReadResult MemorySection::read(void *destination, Offset src_offset, size_t size, ReadOptions options) const { UNUSED(options) auto source = static_cast(src_offset); size = std::min(source + size, length()) - source; if (source >= length()) { throw SIMULATOR_EXCEPTION( OutOfMemoryAccess, "Trying to read outside of the memory section", QString("Accessing using offset: ") + QString::number(source)); } memcpy(destination, &dt[source], size); return { .n_bytes = size }; } LocationStatus MemorySection::location_status(Offset offset) const { UNUSED(offset) return LOCSTAT_NONE; } size_t MemorySection::length() const { return this->dt.size(); } const byte *MemorySection::data() const { return this->dt.data(); } bool MemorySection::operator==(const MemorySection &other) const { return this->dt == other.dt; } bool MemorySection::operator!=(const MemorySection &ms) const { return !this->operator==(ms); } // Settings sanity checks static_assert( MEMORY_SECTION_SIZE != 0, "Nonzero memory section size is required."); static_assert( MEMORY_TREE_ROW_SIZE != 0, "Nonzero memory tree row size is required."); static_assert( ((32 - MEMORY_SECTION_BITS) % MEMORY_TREE_BITS) == 0, "Number of bits in tree row has to be exact division of available number " "of bits."); /** * Generate mask to get memory section index from address. * * Memory section of section_size 2^`section_size` separably addressable units * each of section_size 2^`unit_size` bytes. * * Example: * `MemorySection` of 256x1B index is received as * ```address & generate_mask(8, 0)``` */ constexpr uint64_t generate_mask(size_t section_size, size_t unit_size) { return ((1U << section_size) - 1) << unit_size; } /** * Get index in row for given offset and row number i */ constexpr size_t tree_row_bit_offset(size_t i) { return 32 - MEMORY_TREE_BITS - i * MEMORY_TREE_BITS; } /* * Select branch index from memory tree. */ constexpr size_t get_tree_row(size_t offset, size_t i) { return (offset & generate_mask(MEMORY_TREE_BITS, tree_row_bit_offset(i))) >> tree_row_bit_offset(i); } Memory::Memory() : BackendMemory(BIG) { // This is dummy constructor for qt internal uses only. this->mt_root = nullptr; } Memory::Memory(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) { this->mt_root = allocate_section_tree(); } Memory::Memory(const Memory &other) : BackendMemory(other.simulated_machine_endian) { this->mt_root = copy_section_tree(other.get_memory_tree_root(), 0); } Memory::~Memory() { free_section_tree(this->mt_root, 0); delete[] this->mt_root; } void Memory::reset() { free_section_tree(this->mt_root, 0); delete[] this->mt_root; this->mt_root = allocate_section_tree(); } void Memory::reset(const Memory &m) { free_section_tree(this->mt_root, 0); this->mt_root = copy_section_tree(m.get_memory_tree_root(), 0); } MemorySection *Memory::get_section(size_t offset, bool create) const { union MemoryTree *w = this->mt_root; size_t row_num; // Walk memory tree branch from root to leaf and create new nodes when // needed and requested (`create` flag). for (size_t i = 0; i < (MEMORY_TREE_DEPTH - 1); i++) { row_num = get_tree_row(offset, i); if (w[row_num].subtree == nullptr) { // We don't have this tree so allocate it. if (!create) { // If we shouldn't be creating it than just return// null. return nullptr; } w[row_num].subtree = allocate_section_tree(); } w = w[row_num].subtree; } row_num = get_tree_row(offset, MEMORY_TREE_DEPTH - 1); if (w[row_num].sec == nullptr) { if (!create) { return nullptr; } w[row_num].sec = new MemorySection(MEMORY_SECTION_SIZE, simulated_machine_endian); } return w[row_num].sec; } size_t get_section_offset_mask(size_t addr) { return addr & generate_mask(MEMORY_SECTION_BITS, 0); } WriteResult Memory::write( Offset destination, const void *source, size_t size, WriteOptions options) { return repeat_access_until_completed( destination, source, size, options, [this]( Offset _destination, const void *_source, size_t _size, WriteOptions) { MemorySection *section = this->get_section(_destination, true); return section->write( get_section_offset_mask(_destination), _source, _size, {}); }); } ReadResult Memory::read( void *destination, Offset source, size_t size, ReadOptions options) const { return repeat_access_until_completed( destination, source, size, options, [this]( void *_destination, Offset _source, size_t _size, ReadOptions _options) -> ReadResult { MemorySection *section = this->get_section(_source, false); if (section == nullptr) { memset(_destination, 0, _size); // TODO Warning read of uninitialized memory return { .n_bytes = _size }; } else { return section->read( _destination, get_section_offset_mask(_source), _size, _options); } }); } uint32_t Memory::get_change_counter() const { return change_counter; } bool Memory::operator==(const Memory &m) const { return compare_section_tree(this->mt_root, m.get_memory_tree_root(), 0); } bool Memory::operator!=(const Memory &m) const { return !this->operator==(m); } const union machine::MemoryTree *Memory::get_memory_tree_root() const { return this->mt_root; } union machine::MemoryTree *Memory::allocate_section_tree() { auto *mt = new union MemoryTree[MEMORY_TREE_ROW_SIZE]; memset(mt, 0, sizeof *mt * MEMORY_TREE_ROW_SIZE); return mt; } void Memory::free_section_tree(union MemoryTree *mt, size_t depth) { if (depth < (MEMORY_TREE_DEPTH - 1)) { // Following level is memory tree for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { if (mt[i].subtree != nullptr) { free_section_tree(mt[i].subtree, depth + 1); delete[] mt[i].subtree; } } } else { // Following level is memory section for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { delete mt[i].sec; } } } bool Memory::compare_section_tree( const union MemoryTree *mt1, const union MemoryTree *mt2, size_t depth) { if (depth < (MEMORY_TREE_DEPTH - 1)) { // Following level is memory tree for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { if (((mt1[i].subtree == nullptr || mt2[i].subtree == nullptr) && mt1[i].subtree != mt2[i].subtree) || (mt1[i].subtree != nullptr && mt2[i].subtree != nullptr && !compare_section_tree( mt1[i].subtree, mt2[i].subtree, depth + 1))) { return false; } } } else { // Following level is memory section for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { if (((mt1[i].sec == nullptr || mt2[i].sec == nullptr) && mt1[i].sec != mt2[i].sec) || (mt1[i].sec != nullptr && mt2[i].sec != nullptr && *mt1[i].sec != *mt2[i].sec)) { return false; } } } return true; } union machine::MemoryTree * Memory::copy_section_tree(const union MemoryTree *mt, size_t depth) { union MemoryTree *nmt = allocate_section_tree(); if (depth < (MEMORY_TREE_DEPTH - 1)) { // Following level is memory tree for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { if (mt[i].subtree != nullptr) { nmt[i].subtree = copy_section_tree(mt[i].subtree, depth + 1); } } } else { // Following level is memory section for (size_t i = 0; i < MEMORY_TREE_ROW_SIZE; i++) { if (mt[i].sec != nullptr) { nmt[i].sec = new MemorySection(*mt[i].sec); } } } return nmt; } LocationStatus Memory::location_status(Offset offset) const { UNUSED(offset) // Lazy allocation of memory is only internal implementation detail. return LOCSTAT_NONE; } } // namespace machine qtrvsim-0.9.8/src/machine/memory/backend/memory.h000066400000000000000000000073331467752164200220340ustar00rootroot00000000000000#ifndef MACHINE_MEMORY_H #define MACHINE_MEMORY_H #include "common/endian.h" #include "machinedefs.h" #include "memory/address.h" #include "memory/backend/backend_memory.h" #include "memory/memory_utils.h" #include "simulator_exception.h" #include "utils.h" #include #include namespace machine { /** * NOTE: Internal endian of memory must be the same as endian of the whole * simulated machine. Therefore it does not have internal_endian field. */ class MemorySection final : public BackendMemory { public: explicit MemorySection(size_t length_bytes, Endian simulated_machine_endian); MemorySection(const MemorySection &other); ~MemorySection() override = default; WriteResult write( Offset destination, const void *source, size_t total_size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; [[nodiscard]] size_t length() const; [[nodiscard]] const byte *data() const; bool operator==(const MemorySection &) const; bool operator!=(const MemorySection &) const; private: std::vector dt; }; ////////////////////////////////////////////////////////////////////////////// /// Some optimisation options // How big memory sections will be in bits (2^8=256 bytes) constexpr size_t MEMORY_SECTION_BITS = 8; // How big one row of lookup tree will be in bits (2^4=16) constexpr size_t MEMORY_TREE_BITS = 4; ////////////////////////////////////////////////////////////////////////////// // Size of one section constexpr size_t MEMORY_SECTION_SIZE = (1u << MEMORY_SECTION_BITS); // Size of one memory row constexpr size_t MEMORY_TREE_ROW_SIZE = (1u << MEMORY_TREE_BITS); // Depth of tree constexpr size_t MEMORY_TREE_DEPTH = ((32 - MEMORY_SECTION_BITS) / MEMORY_TREE_BITS); union MemoryTree { union MemoryTree *subtree; MemorySection *sec; }; /** * NOTE: Internal endian of memory must be the same as endian of the whole * simulated machine. Therefore it does not have internal_endian field. */ class Memory final : public BackendMemory { Q_OBJECT public: // This is dummy constructor for qt internal uses only. Memory(); explicit Memory(Endian simulated_machine_endian); Memory(const Memory &); ~Memory() override; void reset(); // Reset whole content of memory (removes old tree and creates // new one) void reset(const Memory &); // returns section containing given address [[nodiscard]] MemorySection *get_section(size_t offset, bool create) const; WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; bool operator==(const Memory &) const; bool operator!=(const Memory &) const; [[nodiscard]] const union MemoryTree *get_memory_tree_root() const; private: union MemoryTree *mt_root; uint32_t change_counter = 0; static union MemoryTree *allocate_section_tree(); static void free_section_tree(union MemoryTree *, size_t depth); static bool compare_section_tree( const union MemoryTree *, const union MemoryTree *, size_t depth); static union MemoryTree * copy_section_tree(const union MemoryTree *, size_t depth); [[nodiscard]] uint32_t get_change_counter() const; }; } // namespace machine Q_DECLARE_METATYPE(machine::Memory); #endif // MEMORY_H qtrvsim-0.9.8/src/machine/memory/backend/memory.test.cpp000066400000000000000000000324631467752164200233470ustar00rootroot00000000000000#include "memory.test.h" #include "common/endian.h" #include "machine/machinedefs.h" #include "machine/memory/backend/memory.h" #include "machine/memory/memory_bus.h" #include "machine/memory/memory_utils.h" #include "tests/utils/integer_decomposition.h" #include using namespace machine; // Default memory testing data. Some tests may use other values, where it // makes better sense. constexpr array default_endians { BIG, LITTLE }; constexpr array default_addresses { 0x0, 0xFFFFFFFC, 0xFFFF0, 0xFFFF1, 0xFFFFFF }; constexpr array default_strides { 0, 1, 2, 3 }; constexpr array default_values { 0x4142434445464748 }; /** * Test the IntegerDecomposition util, that is used for testing later. */ void TestMemory::integer_decomposition() { const uint64_t value = 0x0102030405060708; IntegerDecomposition big_endian(value, BIG); // Expected sub-values done by hand. array be_u32 { 0x01020304, 0x05060708 }; array be_u16 { 0x0102, 0x0304, 0x0506, 0x0708 }; array be_u8 { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; QCOMPARE(big_endian.u64, (uint64_t)0x0102030405060708); QCOMPARE(big_endian.u32, be_u32); QCOMPARE(big_endian.u16, be_u16); QCOMPARE(big_endian.u8, be_u8); IntegerDecomposition little_endian(value, LITTLE); // Little endian arrays are reversed to big endian ones. array le_u32 = be_u32; std::reverse(le_u32.begin(), le_u32.end()); array le_u16 = be_u16; std::reverse(le_u16.begin(), le_u16.end()); array le_u8 = be_u8; std::reverse(le_u8.begin(), le_u8.end()); // Const cast is just for types to match, this way reverse is simpler. QCOMPARE(little_endian.u64, (uint64_t)0x0102030405060708); QCOMPARE(little_endian.u32, (const array)le_u32); QCOMPARE(little_endian.u16, (const array)le_u16); QCOMPARE(little_endian.u8, (const array)le_u8); } /** * Common testing dataset generator. * * @tparam N1 size of first argument array * @tparam N2 size of second argument array * @tparam N3 size of third argument array * @tparam N4 size of fourth argument array * @param simulated_endians array of endians to test * @param accessed_addresses array of addresses to test at * @param strides array of offsets of reads to the previous write (because * of endian differences), only tested on 64b write * @param values values to use for memory access, for smaller accesses * part of the value is use */ template constexpr void prepare_data( const array &simulated_endians, const array &accessed_addresses, const array &strides, const array &values) { QTest::addColumn("endian"); QTest::addColumn("address"); QTest::addColumn("stride"); QTest::addColumn("value"); QTest::addColumn("result"); for (auto endian : simulated_endians) { for (auto address : accessed_addresses) { for (auto stride : strides) { for (auto value : values) { // Result when read has `stride` bytes offset to the write. auto result_value = (endian == BIG) ? (value << (stride * 8)) : (value >> (stride * 8)); QTest::addRow( "endian=%s, address=0x%lx, stride=%ld, value=0x%" PRIx64, to_string(endian), address, stride, value) << endian << address << stride << IntegerDecomposition(value, endian) << IntegerDecomposition(result_value, endian); } } } } } void TestMemory::memory_data() { prepare_data(default_endians, default_addresses, default_strides, default_values); } void TestMemory::memory() { QFETCH(Endian, endian); QFETCH(Offset, address); QFETCH(Offset, stride); QFETCH(IntegerDecomposition, value); QFETCH(IntegerDecomposition, result); Memory m(endian); // Uninitialized memory should read as zero QCOMPARE(memory_read_u8(&m, address + stride), (uint8_t)0); QCOMPARE(memory_read_u16(&m, address + stride), (uint16_t)0); QCOMPARE(memory_read_u32(&m, address + stride), (uint32_t)0); QCOMPARE(memory_read_u64(&m, address + stride), (uint64_t)0); // Writes value and reads it in all possible ways (by parts). // It is sufficient to test reads with stride to write of largest write. For // smaller writes, correct result is much harder to prepare. if (stride == 0) { memory_write_u8(&m, address, value.u8.at(0)); QCOMPARE(memory_read_u8(&m, address), result.u8.at(0)); memory_write_u16(&m, address, value.u16.at(0)); QCOMPARE(memory_read_u16(&m, address), result.u16.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u8(&m, address + i), result.u8.at(i)); } memory_write_u32(&m, address, value.u32.at(0)); QCOMPARE(memory_read_u32(&m, address), result.u32.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u16(&m, address + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(memory_read_u8(&m, address + i), result.u8.at(i)); } } memory_write_u64(&m, address, value.u64); QCOMPARE(memory_read_u64(&m, address + stride), result.u64); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u32(&m, address + stride + 4 * i), result.u32.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(memory_read_u16(&m, address + stride + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 8; ++i) { QCOMPARE(memory_read_u8(&m, address + stride + i), result.u8.at(i)); } } void TestMemory::memory_section_data() { constexpr array addresses { 0x0, 0xFFFFFFF4, 0xFFFF00, 0xFFFFF2 }; prepare_data(default_endians, addresses, default_strides, default_values); } void TestMemory::memory_section() { QFETCH(Endian, endian); QFETCH(Offset, address); QFETCH(Offset, stride); QFETCH(IntegerDecomposition, value); QFETCH(IntegerDecomposition, result); Memory m(endian); // First section shouldn't exists QCOMPARE(m.get_section(address, false), (MemorySection *)nullptr); // Create section MemorySection *s = m.get_section(address, true); QVERIFY(s != nullptr); // Writes value and reads it in all possible ways (by parts). // It is sufficient to test reads with stride to write of largest write. For // smaller writes, correct result is much harder to prepare. if (stride == 0) { Offset section_offset = address % MEMORY_SECTION_SIZE; memory_write_u8(&m, address, value.u8.at(0)); QCOMPARE(memory_read_u8(s, section_offset), result.u8.at(0)); memory_write_u16(&m, address, value.u16.at(0)); QCOMPARE(memory_read_u16(s, section_offset), result.u16.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u8(s, section_offset + i), result.u8.at(i)); } memory_write_u32(&m, address, value.u32.at(0)); QCOMPARE(memory_read_u32(s, section_offset), result.u32.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u16(s, section_offset + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(memory_read_u8(s, section_offset + i), result.u8.at(i)); } } Offset section_offset = (address + stride) % MEMORY_SECTION_SIZE; memory_write_u64(&m, address, value.u64); QCOMPARE(memory_read_u64(s, section_offset), result.u64); for (size_t i = 0; i < 2; ++i) { QCOMPARE(memory_read_u32(s, section_offset + 4 * i), result.u32.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(memory_read_u16(s, section_offset + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 8; ++i) { QCOMPARE(memory_read_u8(s, section_offset + i), result.u8.at(i)); } } void prepare_endian_test() { QTest::addColumn("endian"); for (auto endian : default_endians) { QTest::addRow("endian=%s", to_string(endian)) << endian; } } void TestMemory::memory_compare_data() { prepare_endian_test(); } void TestMemory::memory_compare() { QFETCH(Endian, endian); Memory m1(endian), m2(endian); QCOMPARE(m1, m2); memory_write_u8(&m1, 0x20, 0x0); QVERIFY(m1 != m2); // This should not be equal as this identifies also // memory write (difference between no write and zero // write) memory_write_u8(&m1, 0x20, 0x24); QVERIFY(m1 != m2); memory_write_u8(&m2, 0x20, 0x23); QVERIFY(m1 != m2); memory_write_u8(&m2, 0x20, 0x24); QCOMPARE(m1, m2); // Do the same with some other section memory_write_u8(&m1, 0xFFFF20, 0x24); QVERIFY(m1 != m2); memory_write_u8(&m2, 0xFFFF20, 0x24); QCOMPARE(m1, m2); // And also check memory copy Memory m3(m1); QCOMPARE(m1, m3); memory_write_u8(&m3, 0x18, 0x22); QVERIFY(m1 != m3); } void TestMemory::memory_write_ctl_data() { QTest::addColumn("ctl"); QTest::addColumn("result"); for (auto endian : default_endians) { Memory mem(endian); QTest::addRow("AC_NONE, endian=%s", to_string(endian)) << AC_NONE << mem; memory_write_u8(&mem, 0x20, 0x30); QTest::addRow("AC_I8, endian=%s", to_string(endian)) << AC_I8 << mem; QTest::addRow("AC_U8, endian=%s", to_string(endian)) << AC_U8 << mem; memory_write_u16(&mem, 0x20, 0x2930); QTest::addRow("AC_I16, endian=%s", to_string(endian)) << AC_I16 << mem; QTest::addRow("AC_U16, endian=%s", to_string(endian)) << AC_U16 << mem; memory_write_u32(&mem, 0x20, 0x27282930); QTest::addRow("AC_I32, endian=%s", to_string(endian)) << AC_I32 << mem; QTest::addRow("AC_U32, endian=%s", to_string(endian)) << AC_U32 << mem; memory_write_u64(&mem, 0x20, 0x2324252627282930ULL); QTest::addRow("AC_I64, endian=%s", to_string(endian)) << AC_I64 << mem; QTest::addRow("AC_U64, endian=%s", to_string(endian)) << AC_U64 << mem; } } void TestMemory::memory_write_ctl() { QFETCH(AccessControl, ctl); QFETCH(Memory, result); // Memory is not supposed to be read directly as it does not implement // frontend memory. TrivialBus was introduced to wrap Memory into the most // simple FrontendMemory with no additional functionality. Memory mem(result.simulated_machine_endian); TrivialBus bus(&mem); bus.write_ctl(ctl, 0x20_addr, (uint64_t)0x2324252627282930ULL); QCOMPARE(mem, result); } void TestMemory::memory_read_ctl_data() { prepare_data(default_endians, default_addresses, default_strides, default_values); } void TestMemory::memory_read_ctl() { QFETCH(Endian, endian); QFETCH(Offset, address); QFETCH(Offset, stride); QFETCH(IntegerDecomposition, value); QFETCH(IntegerDecomposition, result); Address frontend_address(address); Memory mem(endian); TrivialBus bus(&mem); bus.write_u64(frontend_address, value.u64); QCOMPARE(bus.read_ctl(AC_U64, frontend_address + stride).as_u64(), result.u64); for (size_t i = 0; i < 2; ++i) { QCOMPARE( bus.read_ctl(AC_U32, frontend_address + stride + 4 * i).as_u32(), result.u32.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE( bus.read_ctl(AC_U16, frontend_address + stride + 2 * i).as_u16(), result.u16.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE( bus.read_ctl(AC_I16, frontend_address + stride + 2 * i).as_i16(), (int16_t)result.u16.at(i)); } for (size_t i = 0; i < 8; ++i) { QCOMPARE(bus.read_ctl(AC_U8, frontend_address + stride + i).as_u8(), result.u8.at(i)); } for (size_t i = 0; i < 8; ++i) { QCOMPARE( bus.read_ctl(AC_I8, frontend_address + stride + i).as_i8(), (int8_t)result.u8.at(i)); } } void TestMemory::memory_memtest_data() { QTest::addColumn("endian"); QTest::addColumn("address"); for (auto endian : default_endians) { for (auto address : default_addresses) { QTest::addRow("endian=%s, address=0x%lx", to_string(endian), address) << endian << address; } } } void TestMemory::memory_memtest() { QFETCH(Endian, endian); QFETCH(Offset, address); Address frontend_address(address); Memory mem(endian); TrivialBus bus(&mem); uint64_t range_to_test = 128 * 1024; if (frontend_address.get_raw() < 0x100000000 && 0x100000000 - range_to_test < frontend_address.get_raw()) range_to_test = uint64_t(Address(0x100000000) - frontend_address); for (uint64_t o = 0; o < range_to_test; o += 4) { bus.write_u32(frontend_address + o, uint32_t(o)); } for (uint64_t o = 0; o < range_to_test; o += 4) { QCOMPARE(bus.read_u32(frontend_address + o), uint32_t(o)); bus.write_u32(frontend_address + o, uint32_t(o) ^ 0xaabbccdd); } for (uint64_t o = 0; o < range_to_test; o += 4) { QCOMPARE(bus.read_u32(frontend_address + o), uint32_t(o) ^ 0xaabbccdd); } } QTEST_APPLESS_MAIN(TestMemory) qtrvsim-0.9.8/src/machine/memory/backend/memory.test.h000066400000000000000000000011561467752164200230070ustar00rootroot00000000000000#ifndef MEMORY_TEST_H #define MEMORY_TEST_H #include class TestMemory : public QObject { Q_OBJECT private: static void integer_decomposition(); private slots: static void memory(); static void memory_data(); static void memory_section(); static void memory_section_data(); void memory_compare(); void memory_compare_data(); static void memory_write_ctl_data(); static void memory_write_ctl(); static void memory_read_ctl_data(); static void memory_read_ctl(); static void memory_memtest_data(); static void memory_memtest(); }; #endif // MEMORY_TEST_H qtrvsim-0.9.8/src/machine/memory/backend/peripheral.cpp000066400000000000000000000016541467752164200232120ustar00rootroot00000000000000#include "memory/backend/peripheral.h" #include "common/endian.h" using namespace machine; SimplePeripheral::SimplePeripheral(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) {}; SimplePeripheral::~SimplePeripheral() = default; WriteResult SimplePeripheral::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(source) UNUSED(options) // Write to dummy periphery is nop emit write_notification(destination, size); return { size, false }; } ReadResult SimplePeripheral::read( void *destination, Offset source, size_t size, ReadOptions options) const { UNUSED(options) memset(destination, 0x12, size); // Random value emit read_notification(source, size); return { size }; } LocationStatus SimplePeripheral::location_status(Offset offset) const { UNUSED(offset) return LOCSTAT_NONE; } qtrvsim-0.9.8/src/machine/memory/backend/peripheral.h000066400000000000000000000022271467752164200226540ustar00rootroot00000000000000#ifndef PERIPHERAL_H #define PERIPHERAL_H #include "common/endian.h" #include "machinedefs.h" #include "memory/backend/backend_memory.h" #include "memory/backend/memory.h" #include "memory/memory_utils.h" #include "simulator_exception.h" #include #include #include namespace machine { /** * NOTE: This peripheral is constant, it does not case about endian. Therefore * it does not have internal_endian field. */ class SimplePeripheral final : public BackendMemory { Q_OBJECT public: explicit SimplePeripheral(Endian simulated_machine_endian); ~SimplePeripheral() override; signals: void write_notification(Offset address, size_t size) const; void read_notification(Offset address, size_t size) const; public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; }; } // namespace machine #endif // PERIPHERAL_H qtrvsim-0.9.8/src/machine/memory/backend/peripspiled.cpp000066400000000000000000000116211467752164200233720ustar00rootroot00000000000000#include "memory/backend/peripspiled.h" #include "common/endian.h" using namespace machine; constexpr size_t SPILED_REG_LED_LINE_o = 0x004; constexpr size_t SPILED_REG_LED_RGB1_o = 0x010; constexpr size_t SPILED_REG_LED_RGB2_o = 0x014; constexpr size_t SPILED_REG_LED_KBDWR_DIRECT_o = 0x018; constexpr size_t SPILED_REG_KBDRD_KNOBS_DIRECT_o = 0x020; constexpr size_t SPILED_REG_KNOBS_8BIT_o = 0x024; PeripSpiLed::PeripSpiLed(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) {} PeripSpiLed::~PeripSpiLed() = default; WriteResult PeripSpiLed::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u32( destination, source, size, [&](Offset src) { return byteswap_if( read_reg(src), internal_endian != simulated_machine_endian); }, [&](Offset src, uint32_t value) { return write_reg( src, byteswap_if( value, internal_endian != simulated_machine_endian)); }); } ReadResult PeripSpiLed::read( void *destination, Offset source, size_t size, ReadOptions options) const { UNUSED(options) return read_by_u32(destination, source, size, [&](Offset src) { return byteswap_if( read_reg(src), internal_endian != simulated_machine_endian); }); } uint32_t PeripSpiLed::read_reg(Offset source) const { Q_ASSERT((source & 3U) == 0); // uint32_t aligned uint32_t value = [&]() { switch (source) { case SPILED_REG_LED_LINE_o: return spiled_reg_led_line; case SPILED_REG_LED_RGB1_o: return spiled_reg_led_rgb1; case SPILED_REG_LED_RGB2_o: return spiled_reg_led_rgb2; case SPILED_REG_LED_KBDWR_DIRECT_o: return spiled_reg_led_kbdwr_direct; case SPILED_REG_KBDRD_KNOBS_DIRECT_o: return spiled_reg_kbdrd_knobs_direct; case SPILED_REG_KNOBS_8BIT_o: return spiled_reg_knobs_8bit; default: // Todo show this to user as this is failure of supplied program printf("[WARNING] PeripSpiLed: read to non-readable location.\n"); return 0u; } }(); emit read_notification(source, value); return value; } bool PeripSpiLed::write_reg(Offset destination, uint32_t value) { Q_ASSERT((destination & 3U) == 0); // uint32_t aligned bool changed = [&]() { switch (destination) { case SPILED_REG_LED_LINE_o: { if (spiled_reg_led_line != value) { spiled_reg_led_line = value; emit led_line_changed(spiled_reg_led_line); return true; } return false; } case SPILED_REG_LED_RGB1_o: if (spiled_reg_led_rgb1 != value) { spiled_reg_led_rgb1 = value; emit led_rgb1_changed(spiled_reg_led_rgb1); return true; } return false; case SPILED_REG_LED_RGB2_o: if (spiled_reg_led_rgb2 != value) { spiled_reg_led_rgb2 = value; emit led_rgb2_changed(spiled_reg_led_rgb2); return true; } return false; default: // Todo show this to user as this is failure of supplied program printf("[WARNING] PeripSpiLed: write to non-writable location.\n"); return false; } }(); emit write_notification(destination, value); return changed; } void PeripSpiLed::knob_update_notify(uint32_t val, uint32_t mask, size_t shift) { mask <<= shift; val <<= shift; if (!((spiled_reg_knobs_8bit ^ val) & mask)) { return; } spiled_reg_knobs_8bit &= ~mask; spiled_reg_knobs_8bit |= val; emit external_backend_change_notify( this, SPILED_REG_KNOBS_8BIT_o, SPILED_REG_KNOBS_8BIT_o + 3, ae::EXTERNAL_ASYNC); } void PeripSpiLed::red_knob_update(int val) { knob_update_notify(val, 0xff, 16); } void PeripSpiLed::green_knob_update(int val) { knob_update_notify(val, 0xff, 8); } void PeripSpiLed::blue_knob_update(int val) { knob_update_notify(val, 0xff, 0); } void PeripSpiLed::red_knob_push(bool state) { knob_update_notify(state ? 1 : 0, 1, 26); } void PeripSpiLed::green_knob_push(bool state) { knob_update_notify(state ? 1 : 0, 1, 25); } void PeripSpiLed::blue_knob_push(bool state) { knob_update_notify(state ? 1 : 0, 1, 24); } LocationStatus PeripSpiLed::location_status(Offset offset) const { switch (offset & ~3U) { case SPILED_REG_LED_LINE_o: FALLTROUGH case SPILED_REG_LED_RGB1_o: FALLTROUGH case SPILED_REG_LED_RGB2_o: { return LOCSTAT_NONE; } case SPILED_REG_LED_KBDWR_DIRECT_o: FALLTROUGH case SPILED_REG_KBDRD_KNOBS_DIRECT_o: FALLTROUGH case SPILED_REG_KNOBS_8BIT_o: { return LOCSTAT_READ_ONLY; } default: { return LOCSTAT_ILLEGAL; } } } qtrvsim-0.9.8/src/machine/memory/backend/peripspiled.h000066400000000000000000000035551467752164200230460ustar00rootroot00000000000000#ifndef PERIPSPILED_H #define PERIPSPILED_H #include "common/endian.h" #include "machinedefs.h" #include "memory/backend/backend_memory.h" #include "memory/memory_utils.h" #include "simulator_exception.h" #include namespace machine { class PeripSpiLed final : public BackendMemory { Q_OBJECT public: explicit PeripSpiLed(Endian simulated_machine_endian); ~PeripSpiLed() override; signals: void write_notification(Offset address, uint32_t value) const; void read_notification(Offset address, uint32_t value) const; void led_line_changed(uint val) const; void led_rgb1_changed(uint val) const; void led_rgb2_changed(uint val) const; public slots: void red_knob_update(int val); void green_knob_update(int val); void blue_knob_update(int val); void red_knob_push(bool state); void green_knob_push(bool state); void blue_knob_push(bool state); public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; [[nodiscard]] LocationStatus location_status(Offset offset) const override; private: [[nodiscard]] uint32_t read_reg(Offset source) const; bool write_reg(Offset destination, uint32_t value); void knob_update_notify(uint32_t val, uint32_t mask, size_t shift); /** endian of internal registers of the periphery use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; uint32_t spiled_reg_led_line = 0; uint32_t spiled_reg_led_rgb1 = 0; uint32_t spiled_reg_led_rgb2 = 0; uint32_t spiled_reg_led_kbdwr_direct = 0; uint32_t spiled_reg_kbdrd_knobs_direct = 0; uint32_t spiled_reg_knobs_8bit = 0; }; } // namespace machine #endif // PERIPSPILED_H qtrvsim-0.9.8/src/machine/memory/backend/serialport.cpp000066400000000000000000000127131467752164200232410ustar00rootroot00000000000000#include "memory/backend/serialport.h" #include "common/endian.h" #include LOG_CATEGORY("machine.memory.serialport"); using ae = machine::AccessEffects; // For enum values, type is obvious from // context. namespace machine { constexpr Offset SERP_RX_ST_REG_o = 0x00u; constexpr uint32_t SERP_RX_ST_REG_READY_m = 0x1u; constexpr uint32_t SERP_RX_ST_REG_IE_m = 0x2u; constexpr Offset SERP_RX_DATA_REG_o = 0x04u; constexpr Offset SERP_TX_ST_REG_o = 0x08u; constexpr uint32_t SERP_TX_ST_REG_READY_m = 0x1u; constexpr uint32_t SERP_TX_ST_REG_IE_m = 0x2u; constexpr Offset SERP_TX_DATA_REG_o = 0xcu; SerialPort::SerialPort(Endian simulated_machine_endian) : BackendMemory(simulated_machine_endian) , tx_irq_level(17) // The second platform HW interrupt , rx_irq_level(16) // The first platform HW interrupt , tx_st_reg(SERP_TX_ST_REG_READY_m) {} SerialPort::~SerialPort() = default; void SerialPort::pool_rx_byte() const { unsigned int byte = 0; bool available = false; if (!(rx_st_reg & SERP_RX_ST_REG_READY_m)) { rx_st_reg |= SERP_RX_ST_REG_READY_m; emit rx_byte_pool(0, byte, available); if (available) { change_counter++; rx_data_reg = byte; } else { rx_st_reg &= ~SERP_RX_ST_REG_READY_m; } } } WriteResult SerialPort::write( Offset destination, const void *source, size_t size, WriteOptions options) { UNUSED(options) return write_by_u32( destination, source, size, [&](Offset src) { UNUSED(src) return 0; }, [&](Offset src, uint32_t value) { return write_reg( src, byteswap_if( value, internal_endian != simulated_machine_endian)); }); } ReadResult SerialPort::read( void *destination, Offset source, size_t size, ReadOptions options) const { return read_by_u32(destination, source, size, [&](Offset src) { return byteswap_if( read_reg(src, options.type), internal_endian != simulated_machine_endian); }); } void SerialPort::update_rx_irq() const { bool active = (rx_st_reg & SERP_RX_ST_REG_IE_m) != 0; active &= (rx_st_reg & SERP_RX_ST_REG_READY_m) != 0; if (active != rx_irq_active) { rx_irq_active = active; emit signal_interrupt(rx_irq_level, active); } } void SerialPort::rx_queue_check_internal() const { if (rx_st_reg & SERP_RX_ST_REG_IE_m) { pool_rx_byte(); } update_rx_irq(); } void SerialPort::rx_queue_check() const { rx_queue_check_internal(); emit external_backend_change_notify( this, SERP_RX_ST_REG_o, SERP_RX_DATA_REG_o + 3, ae::EXTERNAL_ASYNC); } void SerialPort::update_tx_irq() const { bool active = (tx_st_reg & SERP_TX_ST_REG_IE_m) != 0; active &= (tx_st_reg & SERP_TX_ST_REG_READY_m) != 0; if (active != tx_irq_active) { tx_irq_active = active; emit signal_interrupt(tx_irq_level, active); } } uint32_t SerialPort::read_reg(Offset source, AccessEffects type) const { Q_ASSERT((source & 3U) == 0); // uint32_t aligned uint32_t value = 0; switch (source) { case SERP_RX_ST_REG_o: pool_rx_byte(); value = rx_st_reg; break; case SERP_RX_DATA_REG_o: pool_rx_byte(); if (rx_st_reg & SERP_RX_ST_REG_READY_m) { value = rx_data_reg; if (type == ae::REGULAR) { rx_st_reg &= ~SERP_RX_ST_REG_READY_m; update_rx_irq(); emit external_backend_change_notify( this, SERP_RX_ST_REG_o, SERP_RX_DATA_REG_o + 3, ae::EXTERNAL_ASYNC); } } else { value = 0; } rx_queue_check_internal(); break; case SERP_TX_ST_REG_o: value = tx_st_reg; break; default: WARN("Serial port - read out of range (at 0x%zu).\n", source); break; } emit read_notification(source, value); return value; } bool SerialPort::write_reg(Offset destination, uint32_t value) { Q_ASSERT((destination & 3U) == 0); // uint32_t aligned bool changed = [&]() { switch (destination & ~3U) { case SERP_RX_ST_REG_o: rx_st_reg &= ~SERP_RX_ST_REG_IE_m; rx_st_reg |= value & SERP_RX_ST_REG_IE_m; rx_queue_check_internal(); update_rx_irq(); return true; case SERP_TX_ST_REG_o: tx_st_reg &= ~SERP_TX_ST_REG_IE_m; tx_st_reg |= value & SERP_TX_ST_REG_IE_m; update_tx_irq(); return true; case SERP_TX_DATA_REG_o: emit tx_byte(value & 0xffu); update_tx_irq(); return true; default: WARN("Serial port - write out of range (at 0x%zu).\n", destination); return false; } }(); emit write_notification(destination, value); return changed; } LocationStatus SerialPort::location_status(Offset offset) const { switch (offset & ~3U) { case SERP_RX_ST_REG_o: FALLTROUGH case SERP_TX_ST_REG_o: FALLTROUGH case SERP_TX_DATA_REG_o: // This is actually write only, but there is no // enum for that. { return LOCSTAT_NONE; } case SERP_RX_DATA_REG_o: { return LOCSTAT_READ_ONLY; } default: { return LOCSTAT_ILLEGAL; } } } uint32_t SerialPort::get_change_counter() const { return change_counter; } } // namespace machine qtrvsim-0.9.8/src/machine/memory/backend/serialport.h000066400000000000000000000035321467752164200227050ustar00rootroot00000000000000#ifndef SERIALPORT_H #define SERIALPORT_H #include "common/endian.h" #include "memory/backend/backend_memory.h" #include "memory/backend/peripheral.h" #include "simulator_exception.h" #include namespace machine { class SerialPort : public BackendMemory { Q_OBJECT public: explicit SerialPort(Endian simulated_machine_endian); ~SerialPort() override; signals: void tx_byte(unsigned int data); void rx_byte_pool(int fd, unsigned int &data, bool &available) const; void write_notification(Offset address, uint32_t value); void read_notification(Offset address, uint32_t value) const; void signal_interrupt(uint irq_level, bool active) const; public slots: void rx_queue_check() const; public: WriteResult write( Offset destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Offset source, size_t size, ReadOptions options) const override; LocationStatus location_status(Offset offset) const override; private: uint32_t read_reg(Offset source, AccessEffects type) const; bool write_reg(Offset destination, uint32_t value); void rx_queue_check_internal() const; void pool_rx_byte() const; void update_rx_irq() const; void update_tx_irq() const; uint32_t get_change_counter() const; /** endian of internal registers of the periphery use. */ static constexpr Endian internal_endian = NATIVE_ENDIAN; const uint8_t tx_irq_level; const uint8_t rx_irq_level; mutable uint32_t change_counter = { 0 }; mutable uint32_t tx_st_reg = { 0 }; mutable uint32_t rx_st_reg = { 0 }; mutable uint32_t rx_data_reg = { 0 }; mutable bool tx_irq_active = false; mutable bool rx_irq_active = false; }; } // namespace machine #endif // SERIALPORT_H qtrvsim-0.9.8/src/machine/memory/cache/000077500000000000000000000000001467752164200200215ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/memory/cache/cache.cpp000066400000000000000000000336361467752164200216030ustar00rootroot00000000000000#include "memory/cache/cache.h" #include "memory/cache/cache_types.h" #include using ae = machine::AccessEffects; // For enum values, type is obvious from // context. namespace machine { Cache::Cache( FrontendMemory *memory, const CacheConfig *config, uint32_t memory_access_penalty_r, uint32_t memory_access_penalty_w, uint32_t memory_access_penalty_b, bool memory_access_enable_b) : FrontendMemory(memory->simulated_machine_endian) , cache_config(config) , mem(memory) , uncached_start(0xf0000000_addr) , uncached_last(0xfffffffe_addr) , access_pen_r(memory_access_penalty_r) , access_pen_w(memory_access_penalty_w) , access_pen_b(memory_access_penalty_b) , access_ena_b(memory_access_enable_b) , replacement_policy(CachePolicy::get_policy_instance(config)) { // Skip memory allocation if cache is disabled if (!config->enabled()) { return; } dt.resize( config->associativity(), std::vector( config->set_count(), { .valid = false, .dirty = false, .tag = 0, .data = std::vector(config->block_size()) })); } Cache::~Cache() = default; WriteResult Cache::write( Address destination, const void *source, size_t size, WriteOptions options) { if (!cache_config.enabled() || is_in_uncached_area(destination) || is_in_uncached_area(destination + size)) { mem_writes++; emit memory_writes_update(mem_writes); update_all_statistics(); return mem->write(destination, source, size, options); } // FIXME: Get rid of the cast // access is mostly the same for read and write but one needs to write // to the address const bool changed = access(destination, const_cast(source), size, WRITE); if (cache_config.write_policy() != CacheConfig::WP_BACK) { mem_writes++; emit memory_writes_update(mem_writes); update_all_statistics(); return mem->write(destination, source, size, options); } return { .n_bytes = size, .changed = changed }; } ReadResult Cache::read( void *destination, Address source, size_t size, ReadOptions options) const { if (!cache_config.enabled() || is_in_uncached_area(source) || is_in_uncached_area(source + size)) { mem_reads++; emit memory_reads_update(mem_reads); update_all_statistics(); return mem->read(destination, source, size, options); } if (options.type == ae::INTERNAL) { if (!(location_status(source) & LOCSTAT_CACHED)) { mem->read(destination, source, size, options); } else { internal_read(source, destination, size); } return {}; } access(source, destination, size, READ); return {}; } bool Cache::is_in_uncached_area(Address source) const { return (source >= uncached_start && source <= uncached_last); } void Cache::flush() { if (!cache_config.enabled()) { return; } for (size_t assoc_index = 0; assoc_index < cache_config.associativity(); assoc_index += 1) { for (size_t set_index = 0; set_index < cache_config.set_count(); set_index += 1) { if (dt[assoc_index][set_index].valid) { kick(assoc_index, set_index); emit cache_update( assoc_index, set_index, 0, false, false, 0, nullptr, false); } } } change_counter++; update_all_statistics(); } void Cache::sync() { flush(); } void Cache::reset() { // Set all cells to invalid if (cache_config.enabled()) { for (auto &set : dt) { for (auto &block : set) { block.valid = false; } } // Note: We don't have to zero replacement policy data as those are // zeroed when first used on invalid cell. } hit_read = 0; hit_write = 0; miss_read = 0; miss_write = 0; mem_reads = 0; mem_writes = 0; burst_reads = 0; burst_writes = 0; emit hit_update(get_hit_count()); emit miss_update(get_miss_count()); emit memory_reads_update(get_read_count()); emit memory_writes_update(get_write_count()); update_all_statistics(); if (cache_config.enabled()) { for (size_t assoc_index = 0; assoc_index < cache_config.associativity(); assoc_index++) { for (size_t set_index = 0; set_index < cache_config.set_count(); set_index++) { emit cache_update( assoc_index, set_index, 0, false, false, 0, nullptr, false); } } } } void Cache::internal_read(Address source, void *destination, size_t size) const { CacheLocation loc = compute_location(source); for (size_t assoc_index = 0; assoc_index < cache_config.associativity(); assoc_index++) { if (dt[assoc_index][loc.row].valid && dt[assoc_index][loc.row].tag == loc.tag) { memcpy( destination, (byte *)&dt[assoc_index][loc.row].data[loc.col] + loc.byte, size); return; } } memset(destination, 0, size); // TODO is this correct } bool Cache::access( Address address, void *buffer, size_t size, AccessType access_type) const { const CacheLocation loc = compute_location(address); size_t way = find_block_index(loc); // check for zero because else last_affected_col can became // ULONG_MAX / BLOCK_ITEM_SIZE and update can take forever if (size == 0) return false; // search failed - cache miss if (way >= cache_config.associativity()) { // if write through we do not need to allocate cache line does not // allocate if (access_type == WRITE && cache_config.write_policy() == CacheConfig::WP_THROUGH_NOALLOC) { miss_write++; emit miss_update(get_miss_count()); update_all_statistics(); const size_t size_overflow = calculate_overflow_to_next_blocks(size, loc); if (size_overflow > 0) { const size_t size_within_block = size - size_overflow; return access( address + size_within_block, (byte *)buffer + size_within_block, size_overflow, access_type); } else { return false; } } way = replacement_policy->select_way_to_evict(loc.row); kick(way, loc.row); SANITY_ASSERT( way < cache_config.associativity(), "Probably unimplemented replacement policy"); } struct CacheLine &cd = dt[way][loc.row]; // Update statistics and otherwise read from memory if (cd.valid) { if (access_type == WRITE) { hit_write++; } else { hit_read++; } emit hit_update(get_hit_count()); update_all_statistics(); } else { if (access_type == WRITE) { miss_write++; } else { miss_read++; } emit miss_update(get_miss_count()); mem->read( cd.data.data(), calc_base_address(loc.tag, loc.row), cache_config.block_size() * BLOCK_ITEM_SIZE, { .type = ae::REGULAR }); cd.valid = true; cd.dirty = false; cd.tag = loc.tag; change_counter += cache_config.block_size(); mem_reads += cache_config.block_size(); burst_reads += cache_config.block_size() - 1; emit memory_reads_update(mem_reads); update_all_statistics(); } replacement_policy->update_stats(way, loc.row, cd.valid); const size_t size_overflow = calculate_overflow_to_next_blocks(size, loc); const size_t size_within_block = size - size_overflow; bool changed = false; if (access_type == READ) { memcpy(buffer, (byte *)&cd.data[loc.col] + loc.byte, size_within_block); } else if (access_type == WRITE) { cd.dirty = true; changed = memcmp( (byte *)&cd.data[loc.col] + loc.byte, buffer, size_within_block) != 0; if (changed) { memcpy( ((byte *)&cd.data[loc.col]) + loc.byte, buffer, size_within_block); change_counter++; } } const auto last_affected_col = (loc.col * BLOCK_ITEM_SIZE + loc.byte + size_within_block - 1) / BLOCK_ITEM_SIZE; for (auto col = loc.col; col <= last_affected_col; col++) { emit cache_update( way, loc.row, col, cd.valid, cd.dirty, cd.tag, cd.data.data(), access_type); } if (size_overflow > 0) { // If access overlaps single cache row, perform access to next row. changed |= access( address + size_within_block, (byte *)buffer + size_within_block, size_overflow, access_type); } return changed; } size_t Cache::calculate_overflow_to_next_blocks( size_t access_size, const CacheLocation &loc) const { return std::max( (ptrdiff_t)(loc.col * BLOCK_ITEM_SIZE + loc.byte + access_size) - (ptrdiff_t)(cache_config.block_size() * BLOCK_ITEM_SIZE), { 0 }); } size_t Cache::find_block_index(const CacheLocation &loc) const { uint32_t index = 0; while ( index < cache_config.associativity() and (!dt[index][loc.row].valid or dt[index][loc.row].tag != loc.tag)) { index++; } return index; } void Cache::kick(size_t way, size_t row) const { struct CacheLine &cd = dt[way][row]; if (cd.dirty && cache_config.write_policy() == CacheConfig::WP_BACK) { mem->write( calc_base_address(cd.tag, row), cd.data.data(), cache_config.block_size() * BLOCK_ITEM_SIZE, {}); mem_writes += cache_config.block_size(); burst_writes += cache_config.block_size() - 1; emit memory_writes_update(mem_writes); } cd.valid = false; cd.dirty = false; change_counter++; replacement_policy->update_stats(way, row, false); } void Cache::update_all_statistics() const { emit statistics_update( get_stall_count(), get_speed_improvement(), get_hit_rate()); } Address Cache::calc_base_address(size_t tag, size_t row) const { return Address( (tag * cache_config.set_count() + row) * cache_config.block_size() * BLOCK_ITEM_SIZE); } CacheLocation Cache::compute_location(Address address) const { // Get address in multiples of 4 bytes (basic storage unit size) and get the // reminder to address individual byte within basic storage unit. auto word_index = address.get_raw() / BLOCK_ITEM_SIZE; auto byte = address.get_raw() % BLOCK_ITEM_SIZE; // Associativity does not influence location (hit will be on the // same place in each way). Lets therefore assume associativity degree 1. // Same address modulo `way_size_words` will alias (up to associativity). auto way_size_words = cache_config.set_count() * cache_config.block_size(); // Index in a way, when rows and cols would be rearranged into 1D array. auto index_in_way = word_index % way_size_words; auto tag = word_index / way_size_words; return { .row = index_in_way / cache_config.block_size(), .col = index_in_way % cache_config.block_size(), .tag = tag, .byte = byte }; } enum LocationStatus Cache::location_status(Address address) const { const CacheLocation loc = compute_location(address); if (cache_config.enabled()) { for (auto const &set : dt) { auto const &block = set[loc.row]; if (block.valid && block.tag == loc.tag) { if (block.dirty && cache_config.write_policy() == CacheConfig::WP_BACK) { return (enum LocationStatus)( LOCSTAT_CACHED | LOCSTAT_DIRTY); } else { return LOCSTAT_CACHED; } } } } return mem->location_status(address); } const CacheConfig &Cache::get_config() const { return cache_config; } uint32_t Cache::get_change_counter() const { return change_counter; } uint32_t Cache::get_hit_count() const { return hit_read + hit_write; } uint32_t Cache::get_miss_count() const { return miss_read + miss_write; } uint32_t Cache::get_read_count() const { return mem_reads; } uint32_t Cache::get_write_count() const { return mem_writes; } uint32_t Cache::get_stall_count() const { uint32_t st_cycles = mem_reads * (access_pen_r - 1) + mem_writes * (access_pen_w - 1); st_cycles += (miss_read + miss_write) * cache_config.block_size(); if (access_ena_b) { st_cycles -= burst_reads * (access_pen_r - access_pen_b) + burst_writes * (access_pen_w - access_pen_b); } return st_cycles; } double Cache::get_speed_improvement() const { uint32_t lookup_time; uint32_t mem_access_time; uint32_t comp = hit_read + hit_write + miss_read + miss_write; if (comp == 0) { return 100.0; } lookup_time = hit_read + miss_read; if (cache_config.write_policy() == CacheConfig::WP_BACK) { lookup_time += hit_write + miss_write; } mem_access_time = mem_reads * access_pen_r + mem_writes * access_pen_w; if (access_ena_b) { mem_access_time -= burst_reads * (access_pen_r - access_pen_b) + burst_writes * (access_pen_w - access_pen_b); } return ( (double)((miss_read + hit_read) * access_pen_r + (miss_write + hit_write) * access_pen_w) / (double)(lookup_time + mem_access_time) * 100); } double Cache::get_hit_rate() const { uint32_t comp = hit_read + hit_write + miss_read + miss_write; if (comp == 0) { return 0.0; } return (double)(hit_read + hit_write) / (double)comp * 100.0; } } // namespace machine qtrvsim-0.9.8/src/machine/memory/cache/cache.h000066400000000000000000000132311467752164200212350ustar00rootroot00000000000000#ifndef CACHE_H #define CACHE_H #include "machineconfig.h" #include "memory/cache/cache_policy.h" #include "memory/cache/cache_types.h" #include "memory/frontend_memory.h" #include #include namespace machine { constexpr size_t BLOCK_ITEM_SIZE = sizeof(uint32_t); /** * NOTE ON TERMINOLOGY: * N-way set associative cache consist of N ways (where N is degree * of associativity). Arguments requesting N are called `associativity` of the * cache. Each way consist of blocks. (When we want to highlight, that we talk * about data + management tags, we speak of cache line. When we speak about * location of block within a way, we use the term `row`. Each block consists of * some number of basic storage units (here `uint32_t`). To locate a single unit * withing block, we use therm `col` (as column). * * Set is consists of all block on the same row across the ways. * * We can imagine a cache as 3D array indexed via triple (`way`, `row`, `col`). * Row and col are derived from part of a address deterministically. The rest * of the address is called `tag`. Set is obtained via linear search and placing * into cache, it is determined by cache replacement policy * (see `memory/cache/cache_policy.h`). */ class Cache : public FrontendMemory { Q_OBJECT public: /** * @param memory backing memory used to handle misses * @param simulated_endian endian of the simulated CPU/memory * system * @param config cache configuration struct * @param memory_access_penalty_r cycles to perform read (stats only) * @param memory_access_penalty_w cycles to perform write (stats only) * @param memory_access_penalty_b cycles to perform burst access (stats * only) * * NOTE: Memory access penalties apply only to statistics and are not taken * into account during simulation itself. There is no point in doing so * without superscalar execution. */ Cache( FrontendMemory *memory, const CacheConfig *config, uint32_t memory_access_penalty_r = 1, uint32_t memory_access_penalty_w = 1, uint32_t memory_access_penalty_b = 0, bool memory_access_enable_b = false); ~Cache() override; WriteResult write( Address destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Address source, size_t size, ReadOptions options) const override; uint32_t get_change_counter() const override; void flush(); // flush cache void sync() override; // Same as flush uint32_t get_hit_count() const; // Number of recorded hits uint32_t get_miss_count() const; // Number of recorded misses uint32_t get_read_count() const; // Number backing/main memory reads uint32_t get_write_count() const; // Number backing/main memory writes uint32_t get_stall_count() const; // Number of wasted cycles in // memory waiting statistic double get_speed_improvement() const; // Speed improvement in percents in // comare with no used cache double get_hit_rate() const; // Usage efficiency in percents void reset(); // Reset whole state of cache const CacheConfig &get_config() const; enum LocationStatus location_status(Address address) const override; signals: void hit_update(uint32_t) const; void miss_update(uint32_t) const; void statistics_update( uint32_t stalled_cycles, double speed_improv, double hit_rate) const; void cache_update( size_t way, size_t row, size_t col, bool valid, bool dirty, size_t tag, const uint32_t *data, bool write) const; void memory_writes_update(uint32_t) const; void memory_reads_update(uint32_t) const; private: const CacheConfig cache_config; FrontendMemory *const mem; const Address uncached_start; const Address uncached_last; const uint32_t access_pen_r, access_pen_w, access_pen_b; const bool access_ena_b; const std::unique_ptr replacement_policy; mutable std::vector> dt; mutable uint32_t hit_read = 0, miss_read = 0, hit_write = 0, miss_write = 0, mem_reads = 0, mem_writes = 0, burst_reads = 0, burst_writes = 0, change_counter = 0; void internal_read(Address source, void *destination, size_t size) const; bool access( Address address, void *buffer, size_t size, AccessType access_type) const; void kick(size_t way, size_t row) const; Address calc_base_address(size_t tag, size_t row) const; void update_all_statistics() const; CacheLocation compute_location(Address address) const; /** * Searches for given tag in a set * * @param loc requested location in cache * @return associativity index of found block, max index + 1 if not * found */ size_t find_block_index(const CacheLocation &loc) const; bool is_in_uncached_area(Address source) const; /** * RW access to cache may span multiple blocks but it needs to be * performed per block. * This functions calculated the size, that will have to be performed by * repeated access (recursive call of `access` method). */ size_t calculate_overflow_to_next_blocks( size_t access_size, const CacheLocation &loc) const; }; } // namespace machine #endif // CACHE_H qtrvsim-0.9.8/src/machine/memory/cache/cache.test.cpp000066400000000000000000000222321467752164200225470ustar00rootroot00000000000000#include "cache.test.h" #include "common/endian.h" #include "machine/memory/backend/memory.h" #include "machine/memory/cache/cache.h" #include "machine/memory/cache/cache_policy.h" #include "machine/memory/memory_bus.h" #include "tests/data/cache_test_performance_data.h" #include #include using namespace machine; using std::array; using std::pair; using std::size_t; using std::tuple; using Testcase = tuple; /* * Testing data for memory accesses * (all combinations are tested) */ constexpr array simulated_endians { BIG, LITTLE }; constexpr array accessed_addresses { 0x0, 0xFFFF0, 0xFFFF1, 0xFFFFFF, 0xFFFFFFCC, }; constexpr array strides { 0, 1, 2 }; constexpr array values { 0x4142434445464748 }; /* * Cache configuration parameters for testing * (all combinations are tested) */ constexpr array replacement_policies { CacheConfig::RP_RAND, CacheConfig::RP_LFU, CacheConfig::RP_LRU, CacheConfig::RP_PLRU }; constexpr array write_policies { CacheConfig::WP_THROUGH_NOALLOC, // THIS // IS // BROKEN // IN // CACHE // FOR // STRIDE // 1 CacheConfig::WP_THROUGH_ALLOC, CacheConfig::WP_BACK }; constexpr array, 3> organizations { { { 8, 1 }, { 1, 8 }, { 4, 4 }, } }; constexpr array associativity_degrees { 1, 2, 4 }; // + 1 is for disabled cache constexpr size_t CONFIG_COUNT = (replacement_policies.size() * write_policies.size() * organizations.size() * associativity_degrees.size()) + 1; /** * Creates cache_config objects from all combinations of the above given * parameters. */ array get_testing_cache_configs() { array configs; configs.at(0).set_enabled(false); size_t i = 1; for (auto replacement_policy : replacement_policies) { for (auto write_policy : write_policies) { for (auto organization : organizations) { for (auto associativity : associativity_degrees) { configs.at(i).set_enabled(true); configs.at(i).set_replacement_policy(replacement_policy); configs.at(i).set_write_policy(write_policy); configs.at(i).set_set_count(organization.first); configs.at(i).set_block_size(organization.second); configs.at(i).set_associativity(associativity); i += 1; } } } } Q_ASSERT(i == CONFIG_COUNT); return configs; } void TestCache::cache_data() { QTest::addColumn("cache_c"); QTest::addColumn("hit"); QTest::addColumn("miss"); CacheConfig cache_c; cache_c.set_write_policy(CacheConfig::WP_THROUGH_ALLOC); cache_c.set_enabled(true); cache_c.set_set_count(8); cache_c.set_block_size(1); cache_c.set_associativity(1); QTest::newRow("Directly mapped") << cache_c << (unsigned)3 << (unsigned)7; cache_c.set_set_count(1); cache_c.set_block_size(8); QTest::newRow("Wide") << cache_c << (unsigned)5 << (unsigned)5; cache_c.set_set_count(4); cache_c.set_block_size(4); QTest::newRow("Square") << cache_c << (unsigned)4 << (unsigned)6; } void TestCache::cache() { QFETCH(CacheConfig, cache_c); QFETCH(unsigned, hit); QFETCH(unsigned, miss); Memory m(BIG); TrivialBus m_frontend(&m); Cache cache(&m_frontend, &cache_c); // Test reads // memory_write_u32(&m, 0x200, 0x24); memory_write_u32(&m, 0x204, 0x66); memory_write_u32(&m, 0x21c, 0x12); memory_write_u32(&m, 0x300, 0x32); for (int i = 0; i < 2; i++) { QCOMPARE(cache.read_u32(0x200_addr), (uint32_t)0x24); QCOMPARE(cache.read_u32(0x204_addr), (uint32_t)0x66); QCOMPARE(cache.read_u32(0x21c_addr), (uint32_t)0x12); QCOMPARE(cache.read_u32(0x300_addr), (uint32_t)0x32); } // Test writes // cache.write_u32(0x700_addr, 0x24); QCOMPARE(memory_read_u32(&m, 0x700), (uint32_t)0x24); cache.write_u32(0x700_addr, 0x23); QCOMPARE(memory_read_u32(&m, 0x700), (uint32_t)0x23); // Verify counts QCOMPARE(cache.get_hit_count(), hit); QCOMPARE(cache.get_miss_count(), miss); } void TestCache::cache_correctness_data() { QTest::addColumn("endian"); QTest::addColumn

("address"); QTest::addColumn("stride"); QTest::addColumn("value"); QTest::addColumn("result"); QTest::addColumn("cache_config"); // Used for cache hit/miss performance checking. QTest::addColumn("case_number"); size_t i = 0; for (auto cache_config : get_testing_cache_configs()) { for (auto endian : simulated_endians) { for (auto address : accessed_addresses) { for (auto stride : strides) { for (auto value : values) { // Result when read has `stride` bytes offset to the // write. auto result_value = (endian == BIG) ? (value << (stride * 8)) : (value >> (stride * 8)); QTest::addRow( "endian=%s, address=0x%" PRIx64 ", stride=%ld, " "value=0x%" PRIx64 ", cache_config={ %d, " "r=%d, wr=%d, s=%d, b=%d, a=%d }", to_string(endian), address, stride, value, cache_config.enabled(), cache_config.replacement_policy(), cache_config.write_policy(), cache_config.set_count(), cache_config.block_size(), cache_config.associativity()) << endian << Address(address) << stride << IntegerDecomposition(value, endian) << IntegerDecomposition(result_value, endian) << cache_config << i; i += 1; } } } } } } void TestCache::cache_correctness() { QFETCH(Endian, endian); QFETCH(Address, address); QFETCH(size_t, stride); QFETCH(IntegerDecomposition, value); QFETCH(IntegerDecomposition, result); QFETCH(CacheConfig, cache_config); QFETCH(size_t, case_number); // Prepare memory hierarchy Memory mem(endian); MemoryDataBus bus(endian); bus.insert_device_to_range(&mem, 0_addr, 0xffffffff_addr, false); Cache cache(&bus, &cache_config); // Uninitialized memory should read as zero QCOMPARE(cache.read_u8(address + stride), (uint8_t)0); QCOMPARE(cache.read_u16(address + stride), (uint16_t)0); QCOMPARE(cache.read_u32(address + stride), (uint32_t)0); QCOMPARE(cache.read_u64(address + stride), (uint64_t)0); // Writes value and reads it in all possible ways (by parts). // It is sufficient to test reads with stride to write of largest write. For // smaller writes, correct result is much harder to prepare. if (stride == 0) { cache.write_u8(address, value.u8.at(0)); QCOMPARE(cache.read_u8(address), result.u8.at(0)); cache.write_u16(address, value.u16.at(0)); QCOMPARE(cache.read_u16(address), result.u16.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(cache.read_u8(address + i), result.u8.at(i)); } cache.write_u32(address, value.u32.at(0)); QCOMPARE(cache.read_u32(address), result.u32.at(0)); for (size_t i = 0; i < 2; ++i) { QCOMPARE(cache.read_u16(address + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(cache.read_u8(address + i), result.u8.at(i)); } } cache.write_u64(address, value.u64); QCOMPARE(cache.read_u64(address + stride), result.u64); for (size_t i = 0; i < 2; ++i) { QCOMPARE(cache.read_u32(address + stride + 4 * i), result.u32.at(i)); } for (size_t i = 0; i < 4; ++i) { QCOMPARE(cache.read_u16(address + stride + 2 * i), result.u16.at(i)); } for (size_t i = 0; i < 8; ++i) { QCOMPARE(cache.read_u8(address + stride + i), result.u8.at(i)); } tuple performance { cache.get_hit_count(), cache.get_miss_count() }; // CODE USED FOR PERFORMANCE DATA GENERATION // fprintf( // stderr, "{ %d, %d }, ", cache.get_hit_count(), // cache.get_miss_count()); if (cache_config.replacement_policy() != CacheConfig::RP_RAND) { // Performance of random policy is implementation dependant and // meaningless. QCOMPARE(performance, cache_test_performance_data.at(case_number)); } } QTEST_APPLESS_MAIN(TestCache) qtrvsim-0.9.8/src/machine/memory/cache/cache.test.h000066400000000000000000000004361467752164200222160ustar00rootroot00000000000000#ifndef CACHE_TEST_H #define CACHE_TEST_H #include class TestCache : public QObject { Q_OBJECT private slots: static void cache_data(); static void cache(); static void cache_correctness_data(); static void cache_correctness(); }; #endif // CACHE_TEST_H qtrvsim-0.9.8/src/machine/memory/cache/cache_policy.cpp000066400000000000000000000136521467752164200231560ustar00rootroot00000000000000#include "cache_policy.h" #include "simulator_exception.h" #include "utils.h" #include #include namespace machine { std::unique_ptr CachePolicy::get_policy_instance(const CacheConfig *config) { if (config->enabled()) { switch (config->replacement_policy()) { case CacheConfig::RP_RAND: return std::make_unique(config->associativity()); case CacheConfig::RP_LRU: return std::make_unique( config->associativity(), config->set_count()); case CacheConfig::RP_LFU: return std::make_unique( config->associativity(), config->set_count()); case CacheConfig::RP_PLRU: return std::make_unique(config->associativity(), config->set_count()); } } else { // Disabled cache will never use it. return { nullptr }; } Q_UNREACHABLE(); } CachePolicyLRU::CachePolicyLRU(size_t associativity, size_t set_count) : associativity(associativity) { stats.resize(set_count); for (auto &row : stats) { row.reserve(associativity); for (size_t i = 0; i < associativity; i++) { row.push_back(i); } } } void CachePolicyLRU::update_stats(size_t way, size_t row, bool is_valid) { // The following code is essentially a single pass of bubble sort (with // temporary variable instead of inplace swapping) adding one element to // back or front (respectively) of a sorted array. The sort stops, when the // original location of the inserted element is reached and the original // instance is moved to the temporary variable (`next_way`). try { // Statistics corresponding to single cache row std::vector &row_stats = stats.at(row); uint32_t next_way = way; if (is_valid) { ptrdiff_t i = (ptrdiff_t)associativity - 1; do { std::swap(row_stats.at(i), next_way); i--; } while (next_way != way); } else { size_t i = 0; do { std::swap(row_stats.at(i), next_way); i++; } while (next_way != way); } } catch (std::out_of_range &e) { throw SANITY_EXCEPTION("Out of range: LRU lost the way from priority queue."); } } size_t CachePolicyLRU::select_way_to_evict(size_t row) const { return stats.at(row).at(0); } CachePolicyLFU::CachePolicyLFU(size_t associativity, size_t set_count) { stats.resize(set_count, std::vector(associativity, 0)); } void CachePolicyLFU::update_stats(size_t way, size_t row, bool is_valid) { auto &stat_item = stats.at(row).at(way); if (is_valid) { stat_item += 1; } else { stat_item = 0; } } size_t CachePolicyLFU::select_way_to_evict(size_t row) const { size_t index = 0; try { // Statistics corresponding to single cache row auto &row_stats = stats.at(row); size_t lowest = row_stats.at(0); for (size_t i = 0; i < row_stats.size(); i++) { if (row_stats.at(i) == 0) { // Only invalid blocks have zero stat index = i; break; } if (lowest > row_stats.at(i)) { lowest = row_stats.at(i); index = i; } } } catch (std::out_of_range &e) { throw SANITY_EXCEPTION("Out of range: LRU lost the way from priority queue."); } return index; } CachePolicyRAND::CachePolicyRAND(size_t associativity) : associativity(associativity) { // Reset random generator to make result reproducible. // Random is by default seeded by 1 (by cpp standard), so this makes it // consistent across multiple runs. // NOTE: Reproducibility applies only on the same execution environment. std::srand(1); // NOLINT(cert-msc51-cpp) } void CachePolicyRAND::update_stats(size_t way, size_t row, bool is_valid) { UNUSED(way) UNUSED(row) UNUSED(is_valid) // NOP } size_t CachePolicyRAND::select_way_to_evict(size_t row) const { UNUSED(row) return std::rand() % associativity; // NOLINT(cert-msc50-cpp) } CachePolicyPLRU::CachePolicyPLRU(size_t associativity, size_t set_count) : associativity(associativity) , associativityCLog2(std::ceil(log2((float)associativity))) { plru_ptr.resize(set_count); for (auto &row : plru_ptr) { row.resize((1 << associativityCLog2) - 1, 0); // Initially point to block 0 } } void CachePolicyPLRU::update_stats(size_t way, size_t row, bool is_valid) { UNUSED(is_valid) // PLRU use a set of binary tree structured pointers to keep track of // the least recently used block, the number of pointers for each // row is 2^associativityCLog2 - 1, where associativityCLog2 is the ceil // log2 of associativity, e.x. 1 + 2 + 4 for cache with associativity from // 5 to 8. When doing state update, we have to access one pointer in each // level, therefore we have to ues an index (plru_idx) to track the currently accessing pointer uint32_t plru_idx = 0; // Index of pointer auto &row_ptr = plru_ptr.at(row); // Pointer of accessed row for (uint32_t i = 0; i < associativityCLog2; i++) { // Toggle the pointer to another direction row_ptr[plru_idx] = ((way >> (associativityCLog2 - 1 - i)) & 1) ? 0 : 1; plru_idx = (1 << (i + 1)) - 1; plru_idx += way >> (associativityCLog2 - 1 - i); } } size_t CachePolicyPLRU::select_way_to_evict(size_t row) const { uint32_t idx = 0; uint32_t plru_idx = 0; auto &row_ptr = plru_ptr.at(row); for (uint32_t i = 0; i < associativityCLog2; i++) { idx <<= 1; uint32_t ptr = row_ptr[plru_idx]; idx += ptr; plru_idx = (1 << (i + 1)) - 1; plru_idx += idx; } return (idx >= associativity) ? (associativity - 1) : idx; } } // namespace machine qtrvsim-0.9.8/src/machine/memory/cache/cache_policy.h000066400000000000000000000065471467752164200226300ustar00rootroot00000000000000#ifndef CACHE_POLICY_H #define CACHE_POLICY_H #include "machineconfig.h" #include "memory/cache/cache_types.h" #include #include #include using std::size_t; namespace machine { /** * Cache replacement policy interface. * * For clarification of cache terminiology, see docstring of `Cache` in * `memory/cache/cache.h`. */ class CachePolicy { public: [[nodiscard]] virtual size_t select_way_to_evict(size_t row) const = 0; /** * To be called by cache on any change of validity. * @param way associativity way * @param row cache row (index of block/set) * @param is_valid is cache data valid (as in `cd.valid`) */ virtual void update_stats(size_t way, size_t row, bool is_valid) = 0; virtual ~CachePolicy() = default; static std::unique_ptr get_policy_instance(const CacheConfig *config); }; /** * Last recently used policy * * Keeps queue of associativity indexes from last accessed * to most recently accesed. * Empty indexes are shifted to the begining. */ class CachePolicyLRU final : public CachePolicy { public: /** * @param associativity degree of assiciaivity * @param set_count number of blocks / rows in a way (or sets in * cache) */ CachePolicyLRU(size_t associativity, size_t set_count); [[nodiscard]] size_t select_way_to_evict(size_t row) const final; void update_stats(size_t way, size_t row, bool is_valid) final; private: /** * Last access order queues for each cache set (row) */ std::vector> stats; const size_t associativity; }; /** * Least frequently used policy * * Keeps statistics of access count for each associativity index. * Resets statistics when set(row) is evicted. */ class CachePolicyLFU final : public CachePolicy { public: /** * @param associativity degree of assiciaivity * @param set_count number of blocks / rows is way (or sets in * cache) */ CachePolicyLFU(size_t associativity, size_t set_count); [[nodiscard]] size_t select_way_to_evict(size_t row) const final; void update_stats(size_t way, size_t row, bool is_valid) final; private: std::vector> stats; }; class CachePolicyRAND final : public CachePolicy { public: /** * @param associativity degree of associativity */ explicit CachePolicyRAND(size_t associativity); [[nodiscard]] size_t select_way_to_evict(size_t row) const final; void update_stats(size_t way, size_t row, bool is_valid) final; private: size_t associativity; }; /** * Pseudo Last recently used policy * * Hardware-Friendly LRU Implementation */ class CachePolicyPLRU final : public CachePolicy { public: /** * @param associativity degree of assiciaivity * @param set_count number of blocks / rows in a way (or sets in * cache) */ CachePolicyPLRU(size_t associativity, size_t set_count); [[nodiscard]] size_t select_way_to_evict(size_t row) const final; void update_stats(size_t way, size_t row, bool is_valid) final; private: /** * Pointer to Least Recently Used Block */ std::vector> plru_ptr; const size_t associativity; const size_t associativityCLog2; }; } // namespace machine #endif // CACHE_POLICY_H qtrvsim-0.9.8/src/machine/memory/cache/cache_types.h000066400000000000000000000014251467752164200224630ustar00rootroot00000000000000#ifndef CACHE_TYPES_H #define CACHE_TYPES_H #include namespace machine { /** * Determiners location of address in single way of cache. This mean, where * given addresses should be stored, if present. */ struct CacheLocation { uint64_t row; uint64_t col; uint64_t tag; uint64_t byte; }; /** * Single cache line. Appropriate cache block is stored in `data`. */ struct CacheLine { bool valid, dirty; uint64_t tag; std::vector data; }; /** * This is preferred over bool (write = true|false) for better readability. */ enum AccessType { READ, WRITE }; inline const char *to_string(AccessType a) { switch (a) { case READ: return "READ"; case WRITE: return "WRITE"; } } } // namespace machine #endif // CACHE_TYPES_H qtrvsim-0.9.8/src/machine/memory/frontend_memory.cpp000066400000000000000000000110551467752164200226730ustar00rootroot00000000000000#include "memory/frontend_memory.h" #include "common/endian.h" namespace machine { bool FrontendMemory::write_u8( Address address, uint8_t value, AccessEffects type) { return write_generic(address, value, type); } bool FrontendMemory::write_u16( Address address, uint16_t value, AccessEffects type) { return write_generic(address, value, type); } bool FrontendMemory::write_u32( Address address, uint32_t value, AccessEffects type) { return write_generic(address, value, type); } bool FrontendMemory::write_u64( Address address, uint64_t value, AccessEffects type) { return write_generic(address, value, type); } uint8_t FrontendMemory::read_u8(Address address, AccessEffects type) const { return read_generic(address, type); } uint16_t FrontendMemory::read_u16(Address address, AccessEffects type) const { return read_generic(address, type); } uint32_t FrontendMemory::read_u32(Address address, AccessEffects type) const { return read_generic(address, type); } uint64_t FrontendMemory::read_u64(Address address, AccessEffects type) const { return read_generic(address, type); } void FrontendMemory::write_ctl( enum AccessControl ctl, Address offset, RegisterValue value) { switch (ctl) { case AC_NONE: { break; } case AC_I8: case AC_U8: { write_u8(offset, value.as_u8()); break; } case AC_I16: case AC_U16: { write_u16(offset, value.as_u16()); break; } case AC_I32: case AC_U32: { write_u32(offset, value.as_u32()); break; } case AC_I64: case AC_U64: { write_u64(offset, value.as_u64()); break; } default: { throw SIMULATOR_EXCEPTION( UnknownMemoryControl, "Trying to write to memory with unknown ctl", QString::number(ctl)); } } } RegisterValue FrontendMemory::read_ctl(enum AccessControl ctl, Address address) const { switch (ctl) { case AC_NONE: return 0; case AC_I8: return (int8_t)read_u8(address); case AC_U8: return read_u8(address); case AC_I16: return (int16_t)read_u16(address); case AC_U16: return read_u16(address); case AC_I32: return (int32_t)read_u32(address); case AC_U32: return read_u32(address); case AC_I64: return (int64_t)read_u64(address); case AC_U64: return read_u64(address); default: { throw SIMULATOR_EXCEPTION( UnknownMemoryControl, "Trying to read from memory with unknown ctl", QString::number(ctl)); } } } void FrontendMemory::sync() {} LocationStatus FrontendMemory::location_status(Address address) const { (void)address; return LOCSTAT_NONE; } template T FrontendMemory::read_generic(Address address, AccessEffects type) const { T value; read(&value, address, sizeof(T), { .type = type }); // When cross-simulating (BIG simulator on LITTLE host machine and vice // versa) data needs to be swapped before writing to memory and after // reading from memory to achieve correct results of misaligned reads. See // bellow. // // Example (4 byte write and 4 byte read offseted by 2 bytes): // // BIG on LITTLE // REGISTER: 12 34 56 78 // PRE-SWAP: 78 56 34 12 (still in register) // NATIVE ENDIAN MEM: 12 34 56 78 00 00 (native is LITTLE) // READ IN MEM: 56 78 00 00 // REGISTER: 00 00 78 56 // POST-SWAP: 56 78 00 00 (correct) // // LITTLE on BIG // REGISTER: 12 34 56 78 // PRE-SWAP: 78 56 34 12 (still in register) // NATIVE ENDIAN MEM: 78 56 34 12 00 00 (native is BIG) // READ IN MEM: 34 12 00 00 // REGISTER: 34 12 00 00 // POST-SWAP: 00 00 12 34 (correct) // return byteswap_if(value, this->simulated_machine_endian != NATIVE_ENDIAN); } template bool FrontendMemory::write_generic( Address address, const T value, AccessEffects type) { // See example in read_generic for byteswap explanation. const T swapped_value = byteswap_if(value, this->simulated_machine_endian != NATIVE_ENDIAN); return write(address, &swapped_value, sizeof(T), { .type = type }).changed; } FrontendMemory::FrontendMemory(Endian simulated_endian) : simulated_machine_endian(simulated_endian) {} } // namespace machineqtrvsim-0.9.8/src/machine/memory/frontend_memory.h000066400000000000000000000153161467752164200223440ustar00rootroot00000000000000#ifndef FRONTEND_MEMORY_H #define FRONTEND_MEMORY_H #include "common/endian.h" #include "machinedefs.h" #include "memory/address.h" #include "memory/memory_utils.h" #include "register_value.h" #include "simulator_exception.h" #include #include // Shortcut for enum class values, type is obvious from context. using ae = machine::AccessEffects; namespace machine { /** * # What is frontend memory * * The core is the entry point to the whole simulated machine. Therefore the * reworked concepts can be best understood from its point of view on the memory * subsystem. Every core configuration has three mandatory memory components. * Two of them are the entry points for memory operations for program and data, * respectively. The entry point starts a chain of memory components of * arbitrary length, each backed by the next one. A component that receives a * request either resolves it or invokes its lower component. For the core, the * chain is invisible, and it only interfaces with the top-level component. The * chain is terminated by a memory data bus. Data bus for data memory is the * third component I have mentioned. All of the above components are instances * of the frontend memory. Frontend memory has three characteristics. Except for * the memory bus, each frontend component must have a frontend component * backing it. The memory bus is backed by zero or more backed devices * (explained later). All addresses used in the frontend are full memory * address. By the word "full", I mean the numerical value observable by a C * program (up to address translation), in contrast to a local relative offset. * The Address datatype is used to store it and pass as an argument. * Finally, frontend memory instances are likely those found on the CPU chip * itself (caches, TLB...). */ class FrontendMemory : public QObject { Q_OBJECT public: /** * It is necessary to know the endian of the whole simulation in the * entrypoint on the memory subsystem, which might be any instance of * frontend memory. * * @param simulated_endian endian of the simulated CPU/memory subsystem */ explicit FrontendMemory(Endian simulated_endian); bool write_u8(Address address, uint8_t value, AccessEffects type = ae::REGULAR); bool write_u16(Address address, uint16_t value, AccessEffects type = ae::REGULAR); bool write_u32(Address address, uint32_t value, AccessEffects type = ae::REGULAR); bool write_u64(Address address, uint64_t value, AccessEffects type = ae::REGULAR); [[nodiscard]] uint8_t read_u8(Address address, AccessEffects type = ae::REGULAR) const; [[nodiscard]] uint16_t read_u16(Address address, AccessEffects type = ae::REGULAR) const; [[nodiscard]] uint32_t read_u32(Address address, AccessEffects type = ae::REGULAR) const; [[nodiscard]] uint64_t read_u64(Address address, AccessEffects type = ae::REGULAR) const; /** * Store with size specified by the CPU control unit. * * This is for CPU core only and the AccessEffects type is implicitly * REGULAR. * @param control_signal CPU control unit signal */ void write_ctl( AccessControl control_signal, Address destination, RegisterValue value); /** * Read with size specified by the CPU control unit. * * This is for CPU core only and the AccessEffects type is implicitly * ae::REGULAR. * @param control_signal CPU control unit signal */ [[nodiscard]] RegisterValue read_ctl(enum AccessControl ctl, Address source) const; virtual void sync(); [[nodiscard]] virtual LocationStatus location_status(Address address) const; [[nodiscard]] virtual uint32_t get_change_counter() const = 0; /** * Write byte sequence to memory * * @param source pointer to array of bytes to be copied * @param destination emulated address of destination to write to * @param size number of bytes to be written * @return true when memory before and after write differs */ virtual WriteResult write( Address destination, const void *source, size_t size, WriteOptions options) = 0; /** * Read sequence of bytes from memory * * @param source emulated address of data to be read * @param destination pointer to destination buffer * @param size number of bytes to be read * @param options additional option like debug mode, see type * definition */ virtual ReadResult read( void *destination, Address source, size_t size, ReadOptions options) const = 0; /** * Endian of the simulated CPU/memory system. * * Used when frontend_memory subclass instance is used as entrypoint to the * memory system (e.g. `read_XX` and `write_XX` functions.). * @see `convert_endian` in `memory/endian.h`. */ const Endian simulated_machine_endian; signals: /** * Signal used to propagate a change up through the hierarchy. */ void external_change_notify( const FrontendMemory *issuing_memory, Address start_addr, Address last_addr, AccessEffects type) const; private: /** * Read any type from memory * * This function was introduced to make stupid errors * like mismatched type and and its size impossible. * It provides nicer interface than `read`. * by eliminating the need for buffer. * * @tparam T type value should be read as * @param address emulated address to read from * @param type read by visualization etc (type ae::INTERNAL) should * not cause certain effects (counter increments...) * @return requested data with type T */ template T read_generic(Address address, AccessEffects type) const; /** * Write to any type from memory * * This function was introduced to make stupid errors like mismatched * type and and its size impossible. It provides nicer interface than * `write` by eliminating the need for buffer. * * @tparam T type of value to be written * @param address emulated address to write to * @param value value of type T to be written * @param type read by visualization etc (type ae::INTERNAL). * should not cause certain effects (counter increments...) * @return true when memory before and after write differs */ template bool write_generic(Address address, T value, AccessEffects type); }; } // namespace machine #endif // FRONTEND_MEMORY_H qtrvsim-0.9.8/src/machine/memory/memory_bus.cpp000066400000000000000000000163321467752164200216500ustar00rootroot00000000000000#include "memory/memory_bus.h" #include "common/endian.h" #include "memory/memory_utils.h" using namespace machine; MemoryDataBus::MemoryDataBus(Endian simulated_endian) : FrontendMemory(simulated_endian) {}; MemoryDataBus::~MemoryDataBus() { ranges_by_addr.clear(); // No stored values are owned. auto iter = ranges_by_device.begin(); while (iter != ranges_by_device.end()) { const RangeDesc *range = iter.value(); iter = ranges_by_device.erase(iter); // Advances the iterator. if (range->owns_device) { delete range->device; } delete range; } } WriteResult MemoryDataBus::write( Address destination, const void *source, size_t size, WriteOptions options) { return repeat_access_until_completed( destination, source, size, options, [this](Address dst, const void *src, size_t s, WriteOptions opt) -> WriteResult { return write_single(dst, src, s, opt); }); } WriteResult MemoryDataBus::write_single( Address destination, const void *source, size_t size, WriteOptions options) { const RangeDesc *range = find_range(Address(destination)); if (range == nullptr) { // Write to unused address range - no devices it present. // This could produce a fault but for simplicity, we will // just ignore the write. return (WriteResult) { .n_bytes = 0, .changed = false }; } WriteResult result = range->device->write( destination - range->start_addr, source, size, options); if (result.changed) { change_counter++; } return result; } ReadResult MemoryDataBus::read( void *destination, Address source, size_t size, ReadOptions options) const { return repeat_access_until_completed( destination, source, size, options, [this](void *dst, Address src, size_t s, ReadOptions opt) -> ReadResult { return read_single(dst, src, s, opt); }); } ReadResult MemoryDataBus::read_single( void *destination, Address source, size_t size, ReadOptions options) const { const RangeDesc *p_range = find_range(Address(source)); if (p_range == nullptr) { // Write to unused address range, no devices it present. // This could produce a fault but for simplicity, we will // consider unused ranges to be constantly zero. memset(destination, 0, size); return (ReadResult) { .n_bytes = size }; } return p_range->device->read( destination, source - p_range->start_addr, size, options); } uint32_t MemoryDataBus::get_change_counter() const { return change_counter; } enum LocationStatus MemoryDataBus::location_status(Address address) const { const RangeDesc *range = find_range(address); if (range == nullptr) { return LOCSTAT_ILLEGAL; } return range->device->location_status(address - range->start_addr); } const MemoryDataBus::RangeDesc * MemoryDataBus::find_range(Address address) const { // lowerBound finds range what has highest key (which is range->last_addr) // less then or equal to address. // See comment in insert_device_to_range for description, why this works. auto iter = ranges_by_addr.lowerBound(address); if (iter == ranges_by_addr.end()) { return nullptr; } const RangeDesc *range = iter.value(); if (address >= range->start_addr && address <= range->last_addr) { return range; } return nullptr; } bool MemoryDataBus::insert_device_to_range( BackendMemory *device, Address start_addr, Address last_addr, bool move_ownership) { auto iter = ranges_by_addr.lowerBound(start_addr); if (iter != ranges_by_addr.end() && iter.value()->overlaps(start_addr, last_addr)) { // Some part of requested range in already taken. return false; } auto *range = new RangeDesc(device, start_addr, last_addr, move_ownership); // Why are we using last address as key? // // QMap can return greatest lower key (lowerBound), so by indexing by last // address we can simply search any address within range. If searched // address is in given range, it is larger the previous range last address // and smaller or equal than the last address of its. This way we find the // last address of desired range in QMap red black tree and retrieve the // rang. Finally we just make sure, that the found range contains the // searched address for case that range is not present. ranges_by_addr.insert(last_addr, range); ranges_by_device.insert(device, range); connect( device, &BackendMemory::external_backend_change_notify, this, &MemoryDataBus::range_backend_external_change); return true; } bool MemoryDataBus::remove_device(BackendMemory *device) { const RangeDesc *range = ranges_by_device.take(device); if (range == nullptr) { return false; // Device not present. } ranges_by_addr.remove(range->last_addr); if (range->owns_device) { delete range->device; } delete range; return true; } void MemoryDataBus::clean_range(Address start_addr, Address last_addr) { for (auto iter = ranges_by_addr.lowerBound(start_addr); iter != ranges_by_addr.end(); iter++) { const RangeDesc *range = iter.value(); if (range->start_addr <= last_addr) { remove_device(range->device); } else { break; } } } void MemoryDataBus::range_backend_external_change( const BackendMemory *device, Offset start_offset, Offset last_offset, AccessEffects type) { change_counter++; // We only use device here for lookup, so const_cast is safe as find takes // it by const reference . for (auto i = ranges_by_device.find(const_cast(device)); i != ranges_by_device.end(); i++) { const RangeDesc *range = i.value(); emit external_change_notify( this, range->start_addr + start_offset, std::max(range->start_addr + last_offset, range->last_addr), type); } } MemoryDataBus::RangeDesc::RangeDesc( BackendMemory *device, Address start_addr, Address last_addr, bool owns_device) : device(device) , start_addr(start_addr) , last_addr(last_addr) , owns_device(owns_device) {} bool MemoryDataBus::RangeDesc::contains(Address address) const { return start_addr <= address && address <= last_addr; } bool MemoryDataBus::RangeDesc::overlaps(Address start, Address last) const { return contains(start) || contains(last); } TrivialBus::TrivialBus(BackendMemory *backend_memory) : FrontendMemory(backend_memory->simulated_machine_endian) , device(backend_memory) {} WriteResult TrivialBus::write( Address destination, const void *source, size_t size, WriteOptions options) { change_counter += 1; // Counter is mandatory by the frontend interface. return device->write(destination.get_raw(), source, size, options); } ReadResult TrivialBus::read( void *destination, Address source, size_t size, ReadOptions options) const { return device->read(destination, source.get_raw(), size, options); } uint32_t TrivialBus::get_change_counter() const { return change_counter; } qtrvsim-0.9.8/src/machine/memory/memory_bus.h000066400000000000000000000151771467752164200213230ustar00rootroot00000000000000#ifndef MEMORY_BUS_H #define MEMORY_BUS_H #include "common/endian.h" #include "machinedefs.h" #include "memory/backend/backend_memory.h" #include "memory/frontend_memory.h" #include "simulator_exception.h" #include "utils.h" #include #include #include namespace machine { /** * Memory bus serves as last level of frontend memory and interconnects it with * backend memory devices, that are subscribed to given address range. * * Simulated core always has exactly one bus. This is necessary to access it * (e.g. from syscall) to map new devices. Backend memory device simulation * classes are implemented in `memory/backend`. For testing purposes, * `TrivialBus` is provided to wrap backend memory device into a minimal * frontend interface. Used mapping is always one to one with identity address * resolution. TrivialBus does not support external changes. * Backend memory devices subscribe to the bus via range descriptions (see * `RangeDecs`). Frontend address (`Address` type) is here converted using the * range descriptions to relative offset within the given backend memory device. * Downstream (frontend -> backend) communication is performed directly and * upstream communication is done via "external_change" signals. */ class MemoryDataBus : public FrontendMemory { Q_OBJECT public: /** * @param simulated_endian endian of the simulated CPU/memory system */ explicit MemoryDataBus(Endian simulated_endian); ~MemoryDataBus() override; /** * Write method that repeats write single (for each affected range) until * whole size is written. * * @see MemoryDataBus::write_single */ WriteResult write( Address destination, const void *source, size_t size, WriteOptions options) override; /** * Read method that repeats write single (for each affected range) until * whole size is read. * * @see MemoryDataBus:read_single */ ReadResult read( void *destination, Address source, size_t size, ReadOptions options) const override; /** * Number of writes and external changes recorded. */ uint32_t get_change_counter() const override; /** * Connect a backend device to the bus for given address range. * * @param device simulated backend memory device object * @param start_addr start of address range, where the device will be * accessible * @param last_addr end of range, devices occupies * @param move_ownership if true, bus will be responsible for for * device destruction * TODO: consider replace with a smartpointer * @return result of connection, it will fail if range is * already occupied */ bool insert_device_to_range( BackendMemory *device, Address start_addr, Address last_addr, bool move_ownership); /** * Disconnect a device by a pointer to it. * Owned device will be deallocated. * * @param device simulated backend memory device object * @return result of disconnection, false if device not present */ bool remove_device(BackendMemory *device); /** * Disconnect all devices in given range. * * * Owned devices will be deallocated. * * @param start_addr * @param last_addr */ void clean_range(Address start_addr, Address last_addr); enum LocationStatus location_status(Address address) const override; private slots: /** * Receive external changes in underlying memory devices. */ void range_backend_external_change( const BackendMemory *device, Offset start_offset, Offset last_offset, AccessEffects type); private: class RangeDesc; // See declaration bellow; QMultiMap ranges_by_device; /* * Ranges by address noes not own any value it hold. It can be erased at * once. */ QMap ranges_by_addr; mutable uint32_t change_counter = 0; /** * Helper to write into single range. Used by `write`. * * Write spanning multiple ranges will succeed partially and return size, * that was written. * API corresponds to `BackendMemory` interface method `write`. */ WriteResult write_single( Address destination, const void *source, size_t size, WriteOptions options); /** * Helper to read from single range. Used by `read` from Backend memory * interface. * * Read spanning multiple ranges will succeed partially and return * size, that was written. * API corresponds to `BackendMemory` interface method `read`. */ ReadResult read_single( void *destination, Address source, size_t size, ReadOptions options) const; /** * Get range (or nullptr) for arbitrary address (not just start or last). */ const MemoryDataBus::RangeDesc *find_range(Address address) const; }; /** * Describes a address range occupied by a single backend memory device. */ class MemoryDataBus::RangeDesc { public: RangeDesc( BackendMemory *device, Address start_addr, Address last_addr, bool owns_device); /** * Tells, whether given address belongs to this range. */ [[nodiscard]] bool contains(Address address) const; /* * Tells, whether this range (of the RangeDesc) overlaps with supplied * range. */ [[nodiscard]] bool overlaps(Address start, Address last) const; BackendMemory *const device; // TODO consider a shared pointer const Address start_addr; const Address last_addr; const bool owns_device; }; /** * Minimal frontend-backend wrapper. * * Redirects memory requests from frontend to backend one-to-one. * Used in test without cache (core only accepts `FrontendMemory`). * * Do not use in non-test code! */ class TrivialBus final : public FrontendMemory { public: explicit TrivialBus(BackendMemory *backend_memory); WriteResult write( Address destination, const void *source, size_t size, WriteOptions options) override; ReadResult read( void *destination, Address source, size_t size, ReadOptions options) const override; uint32_t get_change_counter() const override; private: BackendMemory *const device; mutable uint32_t change_counter = 0; }; } // namespace machine #endif // MEMORY_BUS_H qtrvsim-0.9.8/src/machine/memory/memory_utils.h000066400000000000000000000317321467752164200216650ustar00rootroot00000000000000#ifndef MEMORY_UTILS_H #define MEMORY_UTILS_H #include "common/endian.h" #include "utils.h" #include #include #include #include namespace machine { /** * Determines what effects should memory access cause. */ enum class AccessEffects { REGULAR, //> All (memory, simulation counters, simulation flags, allocation // on read miss (write allocation is necessary)). For accessed // requested by simulated program. INTERNAL, //> Only memory. Internal access performed for visualization, // control and debugging. EXTERNAL_ASYNC, //> Used for DMA. }; /** * Additional options for read operation between memory layers * * The purpose for this struct is to make the API easily * extensible. */ struct ReadOptions { AccessEffects type; }; /** * Additional options for write operation between memory layers * * The purpose for this struct is to make the API easily * extensible. */ struct WriteOptions { AccessEffects type; }; struct ReadResult { /** * Number of bytes successfully read. * * May be lower than requested size in case partial success * like page fault. */ size_t n_bytes = 0; inline ReadResult operator+(const ReadResult &other) const { return { this->n_bytes + other.n_bytes, }; } inline void operator+=(const ReadResult &other) { this->n_bytes += other.n_bytes; } }; struct WriteResult { /** * Number of bytes successfully read. * * May be lower than requested size in case partial success * like page fault. */ size_t n_bytes = 0; /** * Indicates whether write caused change in memory. * Used to reduce UI redraws. */ bool changed = false; inline WriteResult operator+(const WriteResult &other) const { return { this->n_bytes + other.n_bytes, this->changed || other.changed, }; } inline void operator+=(const WriteResult &other) { this->n_bytes += other.n_bytes; this->changed |= other.changed; } }; /** * Perform n-byte read into periphery that only supports u32 access. * * When converting n-byte memory access into aligned series of discrete * accesses each by u32. * * Example: * Periphery supports write by uint32_t. Access of size 4 targets in the middle * of a uint32_t register. Then this function will return 2, which means that * last 2 bytes of the retrieved data will be used (written to register). * * @tparam STORAGE_TYPE a type periphery supports for access * @param ptr pointer-like value used for access * @return size to be used from aligned access */ template inline void partial_access_parameters( size_t &data_offset, size_t &partial_size, uintptr_t ptr, size_t size) { data_offset = ptr % sizeof(STORAGE_TYPE); partial_size = sizeof(STORAGE_TYPE); partial_size -= data_offset; if (partial_size > size) partial_size = size; } /** * Perform n-byte read into periphery that only supports u32 access. * * @tparam FUNC function :: size_t -> uint32_t * @param src data offset in periphery * @param dst pointer to write to * @param size bytes to read * @param data_getter function object which return u32 data for given */ template inline ReadResult read_by_u32(void *dst, size_t src, size_t size, FUNC data_getter) { size_t current_src = src; byte *current_dst = static_cast(dst); size_t remaining_size = size; do { // For simplicity, this is duplicated in write_by_u32. size_t data_offset = current_src % sizeof(uint32_t); size_t partial_size = std::min(sizeof(uint32_t) - data_offset, remaining_size); uint32_t data = data_getter(current_src & ~3u); memcpy(current_dst, (byte *)&data + data_offset, partial_size); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size }; } template inline ReadResult read_by_u16(void *dst, size_t src, size_t size, FUNC data_getter) { size_t current_src = src; byte *current_dst = static_cast(dst); size_t remaining_size = size; do { // For simplicity, this is duplicated in write_by_u16. size_t data_offset = current_src % sizeof(uint16_t); size_t partial_size = std::min(sizeof(uint16_t) - data_offset, remaining_size); uint16_t data = data_getter(current_src & ~1u); memcpy(current_dst, (byte *)&data + data_offset, partial_size); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size }; } template inline ReadResult read_by_u64(void *dst, size_t src, size_t size, FUNC data_getter) { size_t current_src = src; byte *current_dst = static_cast(dst); size_t remaining_size = size; do { // For simplicity, this is duplicated in write_by_u64. size_t data_offset = current_src % sizeof(uint64_t); size_t partial_size = std::min(sizeof(uint64_t) - data_offset, remaining_size); uint64_t data = data_getter(current_src & ~7u); memcpy(current_dst, (byte *)&data + data_offset, partial_size); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size }; } /** * Perform n-byte write into periphery that only supports u32 access. * * @see read_by_u32 * * @tparam FUNC1 function :: size_t -> uint32_t * @tparam FUNC2 function :: size_t, uint32_t -> bool * @param src data source * @param dst offset in periphery * @param size n bytes * @param data_getter function object which return u32 data for given * offset * @param data_setter function object which writes an u32 to givem offset * @return true if write caused a change */ template inline WriteResult write_by_u32(size_t dst, const void *src, size_t size, FUNC1 data_getter, FUNC2 data_setter) { const byte *current_src = static_cast(src); size_t current_dst = dst; size_t remaining_size = size; bool changed = false; do { // For simplicity, this is duplicated in read_by_u32. size_t data_offset = current_dst % sizeof(uint32_t); size_t partial_size = std::min(sizeof(uint32_t) - data_offset, remaining_size); uint32_t data = 0; if (partial_size < sizeof(data)) data = data_getter(current_dst & ~3u); memcpy((byte *)&data + data_offset, current_src, partial_size); changed |= data_setter(current_dst & ~3u, data); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size, .changed = changed }; } template inline WriteResult write_by_u16(size_t dst, const void *src, size_t size, FUNC1 data_getter, FUNC2 data_setter) { const byte *current_src = static_cast(src); size_t current_dst = dst; size_t remaining_size = size; bool changed = false; do { // For simplicity, this is duplicated in read_by_u16. size_t data_offset = current_dst % sizeof(uint16_t); size_t partial_size = std::min(sizeof(uint16_t) - data_offset, remaining_size); uint16_t data = 0; if (partial_size < sizeof(data)) data = data_getter(current_dst & ~1u); memcpy((byte *)&data + data_offset, current_src, partial_size); changed |= data_setter(current_dst & ~1u, data); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size, .changed = changed }; } template inline WriteResult write_by_u64(size_t dst, const void *src, size_t size, FUNC1 data_getter, FUNC2 data_setter) { const byte *current_src = static_cast(src); size_t current_dst = dst; size_t remaining_size = size; bool changed = false; do { // For simplicity, this is duplicated in read_by_u64. size_t data_offset = current_dst % sizeof(uint64_t); size_t partial_size = std::min(sizeof(uint64_t) - data_offset, remaining_size); uint64_t data = 0; if (partial_size < sizeof(data)) data = data_getter(current_dst & ~7u); memcpy((byte *)&data + data_offset, current_src, partial_size); changed |= data_setter(current_dst & ~7u, data); remaining_size -= partial_size; current_src += partial_size; current_dst += partial_size; } while (remaining_size > 0); return { .n_bytes = size, .changed = changed }; } /** * In case that underlying memory representation is fragmented, multiple * invocations of the same code might be needed. This is a common case with the * n-byte memory access API and therefore this function has been introduce to * minimize code duplication. * * @tparam FUNC function with same signature as read or write * @tparam SRC_TYPE corresponding type in read or write * @tparam DST_TYPE corresponding type in read or write * @tparam OPTIONS_TYPE ReadOptions or WriteOptions * @tparam RESULT_TYPE ReadResult or WriteResult * @param src same arg as in read/write * @param dst same arg as in read/write * @param size same arg as in read/write * @param options same arg as in read/write * @param function lambda to perform individual accesses * @return number of bytes obtained, == size if fully successful */ template inline RESULT_TYPE repeat_access_until_completed( DST_TYPE dst, SRC_TYPE src, size_t size, OPTIONS_TYPE options, FUNC function) { size_t remaining_size = size; auto current_src = (uint64_t)(src); auto current_dst = (uint64_t)(dst); RESULT_TYPE total_result {}; // do-while is preferred, because this loop is most likely to be executed only once. Empty // access is not common and does not need to be optimized. do { RESULT_TYPE result = function((DST_TYPE)(current_dst), (SRC_TYPE)(current_src), remaining_size, options); if (result.n_bytes == 0) break; total_result += result; current_src += result.n_bytes; current_dst += result.n_bytes; remaining_size -= result.n_bytes; } while (remaining_size > 0); return total_result; } /** * Helper function for memories, that do not support function like read_u32. * It is used in tests. * This is a generic version followed by named instantiations. */ template T memory_read(MEM_T *mem, ADDR_T address) { T buffer; mem->read(&buffer, address, sizeof(T), {}); return byteswap_if(buffer, mem->simulated_machine_endian != NATIVE_ENDIAN); } template uint8_t memory_read_u8(MEM_T *mem, ADDR_T address) { return memory_read(mem, address); } template uint16_t memory_read_u16(MEM_T *mem, ADDR_T address) { return memory_read(mem, address); } template uint32_t memory_read_u32(MEM_T *mem, ADDR_T address) { return memory_read(mem, address); } template uint64_t memory_read_u64(MEM_T *mem, ADDR_T address) { return memory_read(mem, address); } /** * Helper function for memories, that do not support function like read_u32. * It is used in tests. * This is a generic version followed by named instantiations. */ template void memory_write(MEM_T *mem, ADDR_T address, T value) { const T swapped_value = byteswap_if(value, mem->simulated_machine_endian != NATIVE_ENDIAN); mem->write(address, &swapped_value, sizeof(T), {}); } template void memory_write_u8(MEM_T *mem, ADDR_T address, uint8_t value) { memory_write(mem, address, value); } template void memory_write_u16(MEM_T *mem, ADDR_T address, uint16_t value) { memory_write(mem, address, value); } template void memory_write_u32(MEM_T *mem, ADDR_T address, uint32_t value) { memory_write(mem, address, value); } template void memory_write_u64(MEM_T *mem, ADDR_T address, uint64_t value) { memory_write(mem, address, value); } } // namespace machine #endif // MEMORY_UTILS_H qtrvsim-0.9.8/src/machine/pipeline.h000066400000000000000000000241571467752164200174350ustar00rootroot00000000000000/** * State of the core pipeline. * * Each internal has a state struct. The state struct is composed of the * internal state for visualization and two sets of outgoing interstage * registers - result and final. Both are filled with the same data as the * stage finishes, but result is never later modified. Final will be modified * by flushed, exceptions etc. and it will be used for further execution. * * TODO: * - Move init functions here as methods (constructor/discard). * * @file */ #ifndef STAGES_H #define STAGES_H #include "instruction.h" #include "machinedefs.h" #include "memory/address.h" #include "registers.h" #include #include namespace machine { enum ForwardFrom { FORWARD_NONE = 0b00, FORWARD_FROM_W = 0b01, FORWARD_FROM_M = 0b10, }; struct PCInterstage { bool stop_if = false; }; struct PCState { PCInterstage final {}; }; struct FetchInterstage { Instruction inst = Instruction::NOP; // Loaded instruction Address inst_addr = STAGEADDR_NONE; // Address of instruction Address next_inst_addr = 0_addr; // `inst_addr` + `inst.size()` /** Inspecting other stages to get this value is problematic due to stalls and flushed. * Therefore we pass it through the whole pipeline. */ Address predicted_next_inst_addr = 0_addr; enum ExceptionCause excause = EXCAUSE_NONE; bool is_valid = false; public: /** Reset to value corresponding to NOP. */ void flush() { *this = {}; } }; struct FetchInternalState { RegisterValue fetched_value = 0; unsigned excause_num = 0; }; struct FetchState { FetchInternalState internal {}; FetchInterstage result {}; FetchInterstage final {}; FetchState(const FetchInternalState &stage, const FetchInterstage &interstage) : internal(stage) , result(interstage) , final(interstage) { this->internal.excause_num = static_cast(interstage.excause); } FetchState() = default; FetchState(const FetchState &) = default; FetchState &operator=(const FetchState &) = default; }; struct DecodeInterstage { Instruction inst = Instruction::NOP; Address inst_addr = STAGEADDR_NONE; Address next_inst_addr = 0_addr; Address predicted_next_inst_addr = 0_addr; RegisterValue val_rs = 0; // Value from register rs RegisterValue val_rs_orig = 0; // Value from register rs1 without forwarding RegisterValue val_rt = 0; // Value from register rt RegisterValue val_rt_orig = 0; // Value from register rs1 without forwarding RegisterValue immediate_val = 0; // Sign-extended immediate value // rd according to regd) RegisterValue csr_read_val = 0; // Value read from csr CSR::Address csr_address = CSR::Address(0); ExceptionCause excause = EXCAUSE_NONE; ForwardFrom ff_rs = FORWARD_NONE; ForwardFrom ff_rt = FORWARD_NONE; AluComponent alu_component; // Selects computational component in alu - basic ALU / MUL. AluCombinedOp aluop = { .alu_op = AluOp::ADD }; // Decoded ALU operation AccessControl memctl = AC_NONE; // Decoded memory access type RegisterId num_rs = 0; // Number of the register s1 RegisterId num_rt = 0; // Number of the register s2 RegisterId num_rd = 0; // Number of the register d bool memread = false; // If memory should be read bool memwrite = false; // If memory should write input bool alusrc = false; // If second value to alu is immediate value (rt used otherwise) bool regwrite = false; // If output should be written back to register bool alu_req_rs = false; // requires rs value for ALU bool alu_req_rt = false; // requires rt value for ALU or SW bool branch_bxx = false; // branch instruction bool branch_jal = false; // jump bool branch_val = false; // negate branch condition bool branch_jalr = false; // JALR: write PC+4 to register and jump to ALU result bool stall = false; bool is_valid = false; bool w_operation = false; // ALU or other operation is limited to word size (32-bits) bool alu_mod = false; // alternative versions of ADD and right-shift bool alu_pc = false; // PC is input to ALU bool csr = false; // Zicsr, implies csr read and csr write bool csr_to_alu = false; bool csr_write = false; bool xret = false; // Return from exception, MRET and SRET bool insert_stall_before = false; public: /** Reset to value corresponding to NOP. */ void flush() { *this = {}; } }; struct DecodeInternalState { /** * ALU OP as a number * GUI needs to show a number, not enumerated value (for simple interface). * Core is responsive for the conversion. */ unsigned alu_op_num = 0; unsigned excause_num = 0; RegisterValue inst_bus = 0; bool alu_mul = false; }; struct DecodeState { DecodeInternalState internal {}; DecodeInterstage result {}; DecodeInterstage final {}; DecodeState(const DecodeInternalState &stage, const DecodeInterstage &interstage) : internal(stage) , result(interstage) , final(interstage) { this->internal.excause_num = static_cast(interstage.excause); this->internal.alu_op_num = static_cast(interstage.aluop.alu_op); } DecodeState() = default; DecodeState(const DecodeState &) = default; DecodeState &operator=(const DecodeState &) = default; }; struct ExecuteInterstage { Instruction inst = Instruction::NOP; Address inst_addr = STAGEADDR_NONE; Address next_inst_addr = 0_addr; Address predicted_next_inst_addr = 0_addr; Address branch_jal_target = 0_addr; //> Potential branch target (inst_addr + 4 + imm). RegisterValue val_rt = 0; RegisterValue alu_val = 0; // Result of ALU execution RegisterValue immediate_val = 0; RegisterValue csr_read_val = 0; CSR::Address csr_address = CSR::Address(0); ExceptionCause excause = EXCAUSE_NONE; AccessControl memctl = AC_NONE; RegisterId num_rd = 0; bool memread = false; bool memwrite = false; bool regwrite = false; bool is_valid = false; bool branch_bxx = false; bool branch_jal = false; bool branch_val = false; bool branch_jalr = false; //> @copydoc DecodeInterstage::branch_jalr bool alu_zero = false; bool csr = false; bool csr_write = false; bool xret = false; public: /** Reset to value corresponding to NOP. */ void flush() { *this = {}; } }; struct ExecuteInternalState { RegisterValue alu_src1 = 0; RegisterValue alu_src2 = 0; RegisterValue immediate = 0; RegisterValue rs = 0; RegisterValue rt = 0; unsigned stall_status = 0; /** * ALU OP as a number. * GUI needs to show a number, not enumerated value (for simple interface). * Core is responsive for the conversion. */ unsigned alu_op_num = 0; /** * Forwarding setting as a number. * Same note as alu_op_num. */ unsigned forward_from_rs1_num = 0; /** * Forwarding setting as a number. * Same note as alu_op_num. */ unsigned forward_from_rs2_num = 0; unsigned excause_num = 0; bool alu_src = false; bool alu_mul = false; bool branch_bxx = false; bool alu_pc = false; // PC is input to ALU }; struct ExecuteState { ExecuteInternalState internal {}; ExecuteInterstage result {}; ExecuteInterstage final {}; ExecuteState(const ExecuteInternalState &stage, const ExecuteInterstage &interstage) : internal(stage) , result(interstage) , final(interstage) { this->internal.excause_num = static_cast(interstage.excause); } ExecuteState() = default; ExecuteState(const ExecuteState &) = default; ExecuteState &operator=(const ExecuteState &) = default; }; struct MemoryInterstage { Instruction inst = Instruction::NOP; Address inst_addr = STAGEADDR_NONE; Address next_inst_addr = 0_addr; Address predicted_next_inst_addr = 0_addr; Address computed_next_inst_addr = 0_addr; Address mem_addr = 0_addr; // Address used to access memory RegisterValue towrite_val = 0; ExceptionCause excause = EXCAUSE_NONE; RegisterId num_rd = 0; bool memtoreg = false; bool regwrite = false; bool is_valid = false; bool csr_written = false; public: /** Reset to value corresponding to NOP. */ void flush() { *this = {}; } }; struct MemoryInternalState { RegisterValue mem_read_val = 0; RegisterValue mem_write_val = 0; RegisterValue mem_addr = 0; unsigned excause_num = 0; bool memwrite = false; bool memread = false; bool branch_bxx = false; bool branch_jal = false; bool branch_outcome = false; bool branch_jalx = false; bool branch_jalr = false; bool xret = false; }; struct MemoryState { MemoryInternalState internal {}; MemoryInterstage result {}; MemoryInterstage final {}; MemoryState(const MemoryInternalState &stage, const MemoryInterstage &interstage) : internal(stage) , result(interstage) , final(interstage) { this->internal.excause_num = static_cast(interstage.excause); } MemoryState() = default; MemoryState(const MemoryState &) = default; MemoryState &operator=(const MemoryState &) = default; }; struct WritebackInternalState { Instruction inst = Instruction::NOP; Address inst_addr = STAGEADDR_NONE; RegisterValue value = 0; RegisterId num_rd = 0; bool regwrite = false; bool memtoreg = false; }; struct WritebackState { WritebackInternalState internal {}; explicit WritebackState(WritebackInternalState stage) : internal(std::move(stage)) {} WritebackState() = default; WritebackState(const WritebackState &) = default; WritebackState &operator=(const WritebackState &) = default; }; struct Pipeline { PCState pc {}; FetchState fetch {}; DecodeState decode {}; ExecuteState execute {}; MemoryState memory {}; WritebackState writeback {}; }; } // namespace machine #endif // STAGES_H qtrvsim-0.9.8/src/machine/predictor.cpp000066400000000000000000000661231467752164200201550ustar00rootroot00000000000000#include "predictor.h" LOG_CATEGORY("machine.BranchPredictor"); using namespace machine; QStringView machine::branch_result_to_string(const BranchResult result, const bool abbrv) { switch (result) { case BranchResult::NOT_TAKEN: return abbrv ? u"NT" : u"Not taken"; case BranchResult::TAKEN: return abbrv ? u"T" : u"Taken"; default: return u""; } } QStringView machine::predictor_state_to_string(const PredictorState state, const bool abbrv) { switch (state) { case PredictorState::NOT_TAKEN: return abbrv ? u"NT" : u"Not taken"; case PredictorState::TAKEN: return abbrv ? u"T" : u"Taken"; case PredictorState::STRONGLY_NOT_TAKEN: return abbrv ? u"SNT" : u"Strongly not taken"; case PredictorState::WEAKLY_NOT_TAKEN: return abbrv ? u"WNT" : u"Weakly not taken"; case PredictorState::WEAKLY_TAKEN: return abbrv ? u"WT" : u"Weakly taken"; case PredictorState::STRONGLY_TAKEN: return abbrv ? u"ST" : u"Strongly taken"; default: return u""; } } QStringView machine::predictor_type_to_string(const PredictorType type) { switch (type) { case PredictorType::ALWAYS_NOT_TAKEN: return u"Always not taken"; case PredictorType::ALWAYS_TAKEN: return u"Always taken"; case PredictorType::BTFNT: return u"Backward Taken Forward Not Taken"; case PredictorType::SMITH_1_BIT: return u"Smith 1 bit"; case PredictorType::SMITH_2_BIT: return u"Smith 2 bit"; case PredictorType::SMITH_2_BIT_HYSTERESIS: return u"Smith 2 bit with hysteresis"; default: return u""; } } QStringView machine::branch_type_to_string(const BranchType type) { switch (type) { case BranchType::JUMP: return u"JUMP"; case BranchType::BRANCH: return u"BRANCH"; default: return u""; } } QString machine::addr_to_hex_str(const machine::Address address) { QString hex_addr, zero_padding; hex_addr = QString::number(address.get_raw(), 16); zero_padding.fill('0', 8 - hex_addr.count()); return "0x" + zero_padding + hex_addr; } bool machine::is_predictor_type_dynamic(const PredictorType type) { switch (type) { case PredictorType::ALWAYS_NOT_TAKEN: case PredictorType::ALWAYS_TAKEN: case PredictorType::BTFNT: return false; case PredictorType::SMITH_1_BIT: case PredictorType::SMITH_2_BIT: case PredictorType::SMITH_2_BIT_HYSTERESIS: return true; default: return false; } } ///////////////////////////////// // BranchHistoryRegister class // ///////////////////////////////// // Constructor BranchHistoryRegister::BranchHistoryRegister(const uint8_t number_of_bits) : number_of_bits(init_number_of_bits(number_of_bits)) , register_mask(init_register_mask(number_of_bits)) {} // Init helper function to check the number of bits uint8_t BranchHistoryRegister::init_number_of_bits(const uint8_t b) const { if (b > BP_MAX_BHR_BITS) { WARN("Number of BHR bits (%u) was larger than %u during init", b, BP_MAX_BHR_BITS); return BP_MAX_BHR_BITS; } return b; } // Init helper function to create the register mask used for masking unused bits uint16_t BranchHistoryRegister::init_register_mask(const uint8_t b) const { if (b >= BP_MAX_BHR_BITS) { return ~0x0; } if (b == 0) { return 0x0; } return (1 << b) - 1; } uint8_t BranchHistoryRegister::get_number_of_bits() const { return number_of_bits; } uint16_t BranchHistoryRegister::get_register_mask() const { return register_mask; } uint16_t BranchHistoryRegister::get_value() const { return value; } // Pushes new value into the register void BranchHistoryRegister::update(const BranchResult result) { // Shift all bits to the left value = value << 1; // Add the result as the new least significant bit // By default the new LSB is 0, only set to 1 if branch was taken if (result == BranchResult::TAKEN) { value |= 0x1; } // Set all bits outside of the scope of the register to zero value = value & register_mask; emit bhr_updated(number_of_bits, value); } void BranchHistoryRegister::clear() { value = 0x0; emit bhr_updated(number_of_bits, value); } ////////////////////////////// // BranchTargetBuffer class // ////////////////////////////// // Constructor BranchTargetBuffer::BranchTargetBuffer(uint8_t number_of_bits) : number_of_bits(init_number_of_bits(number_of_bits)) { btb.resize(qPow(2, number_of_bits)); } uint8_t BranchTargetBuffer::init_number_of_bits(const uint8_t b) const { if (b > BP_MAX_BTB_BITS) { WARN("Number of BTB bits (%u) was larger than %u during init", b, BP_MAX_BTB_BITS); return BP_MAX_BTB_BITS; } return b; } uint8_t BranchTargetBuffer::get_number_of_bits() const { return number_of_bits; } // Calculate index for addressing Branch Target Buffer from instruction address uint16_t BranchTargetBuffer::calculate_index(const Address instruction_address) const { return ((uint16_t)(instruction_address.get_raw() >> 2)) & ((1 << number_of_bits) - 1); } BranchTargetBufferEntry BranchTargetBuffer::get_entry(const Address instruction_address) const { // Get index from instruction address const uint16_t index { calculate_index(instruction_address) }; // Check index validity if (index >= btb.capacity()) { WARN("Tried to read from BTB at invalid index: %u", index); return BranchTargetBufferEntry(); } return btb.at(index); } // Update BTB entry with given values, at index computed from the instruction address void BranchTargetBuffer::update(const Address instruction_address, const Address target_address, const BranchType branch_type) { // Get index from instruction address const uint16_t btb_index { calculate_index(instruction_address) }; // Check index validity if (btb_index >= btb.capacity()) { WARN("Tried to update BTB at invalid index: %u", btb_index); return; } // Write new entry to the table const BranchTargetBufferEntry btb_entry = { .entry_valid = true, .instruction_address = instruction_address, .target_address = target_address, .branch_type = branch_type }; btb.at(btb_index) = btb_entry; // Send signal with the data emit btb_row_updated(btb_index, btb_entry); } void BranchTargetBuffer::clear() { for (uint16_t i = 0; i < btb.capacity(); i++) { btb.at(i) = BranchTargetBufferEntry(); emit btb_row_updated(i, btb.at(i)); } } ///////////////////// // Predictor class // ///////////////////// // Predictor Generic // ################# Predictor::Predictor( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state) : number_of_bht_addr_bits(init_number_of_bht_addr_bits(number_of_bht_addr_bits)) , number_of_bht_bits(init_number_of_bht_bits(number_of_bht_bits)) , initial_state(initial_state) { bht.resize(qPow(2, number_of_bht_bits)); clear_bht_state(); clear_bht_stats(); } uint8_t Predictor::init_number_of_bht_addr_bits(const uint8_t b) const { if (b > BP_MAX_BHT_ADDR_BITS) { WARN( "Number of BHT bits from incstruction address (%u) was larger than %d during init", b, BP_MAX_BHT_ADDR_BITS); return BP_MAX_BHT_ADDR_BITS; } return b; } uint8_t Predictor::init_number_of_bht_bits(const uint8_t b) const { if (b > BP_MAX_BHT_BITS) { WARN("Number of BHT bits (%u) was larger than %d during init", b, BP_MAX_BHT_BITS); return BP_MAX_BHT_BITS; } return b; } BranchResult Predictor::convert_state_to_prediction(PredictorState state) const { if (state == PredictorState::NOT_TAKEN) { return BranchResult::NOT_TAKEN; } else if (state == PredictorState::TAKEN) { return BranchResult::TAKEN; } else if (state == PredictorState::WEAKLY_NOT_TAKEN) { return BranchResult::NOT_TAKEN; } else if (state == PredictorState::STRONGLY_NOT_TAKEN) { return BranchResult::NOT_TAKEN; } else if (state == PredictorState::WEAKLY_TAKEN) { return BranchResult::TAKEN; } else if (state == PredictorState::STRONGLY_TAKEN) { return BranchResult::TAKEN; } else { WARN("Smith predictor was provided invalid state"); return BranchResult::NOT_TAKEN; } } void Predictor::update_stats(bool prediction_was_correct) { stats.total += 1; if (prediction_was_correct) { stats.correct += 1; } else { stats.wrong += 1; } stats.accuracy = ((stats.correct * 100) / stats.total); emit stats_updated(stats); } void Predictor::update_bht_stats(uint16_t bht_index, bool prediction_was_correct) { if (bht_index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", bht_index); return; } bht.at(bht_index).stats.total += 1; if (prediction_was_correct) { bht.at(bht_index).stats.correct += 1; } else { bht.at(bht_index).stats.wrong += 1; } bht.at(bht_index).stats.accuracy = ((bht.at(bht_index).stats.correct * 100) / bht.at(bht_index).stats.total); emit bht_row_updated(bht_index, bht.at(bht_index)); } // Calculate index for addressing Branch History Table from BHR and instruction address uint16_t Predictor::calculate_bht_index( const uint16_t bhr_value, const Address instruction_address) const { const uint16_t bhr_part = bhr_value << number_of_bht_addr_bits; const uint16_t address_mask = (1 << number_of_bht_addr_bits) - 1; const uint16_t address_part = ((uint16_t)(instruction_address.get_raw() >> 2)) & address_mask; const uint16_t index = bhr_part | address_part; return index; } void Predictor::clear_stats() { stats = PredictionStatistics(); emit stats_updated(stats); } void Predictor::clear_bht_stats() { for (uint16_t i = 0; i < bht.capacity(); i++) { bht.at(i).stats = PredictionStatistics(); emit bht_row_updated(i, bht.at(i)); } } void Predictor::clear_bht_state() { for (uint16_t i = 0; i < bht.capacity(); i++) { bht.at(i).state = initial_state; emit bht_row_updated(i, bht.at(i)); } } void Predictor::clear() { clear_stats(); clear_bht_stats(); clear_bht_state(); } void Predictor::flush() { clear_bht_state(); } // Always Not Taken // ################ PredictorAlwaysNotTaken::PredictorAlwaysNotTaken() : Predictor(0, 0, PredictorState::UNDEFINED) {} BranchResult PredictorAlwaysNotTaken::predict(PredictionInput input) { UNUSED(input); return BranchResult::NOT_TAKEN; } void PredictorAlwaysNotTaken::update(PredictionFeedback feedback) { update_stats(feedback.result == BranchResult::NOT_TAKEN); } // Always Taken // ############ PredictorAlwaysTaken::PredictorAlwaysTaken() : Predictor(0, 0, PredictorState::UNDEFINED) {} BranchResult PredictorAlwaysTaken::predict(PredictionInput input) { UNUSED(input); return BranchResult::NOT_TAKEN; } void PredictorAlwaysTaken::update(PredictionFeedback feedback) { update_stats(feedback.result == BranchResult::TAKEN); } // Backward Taken Forward Not Taken // ################################ PredictorBTFNT::PredictorBTFNT() : Predictor(0, 0, PredictorState::UNDEFINED) {} BranchResult PredictorBTFNT::predict(PredictionInput input) { if (input.target_address > input.instruction_address) { // If target address is larger than jump instruction address (forward jump), // predict not taken return BranchResult::NOT_TAKEN; } else { // Otherwise (backward jump) predict taken return BranchResult::TAKEN; } } void PredictorBTFNT::update(PredictionFeedback feedback) { if (feedback.target_address > feedback.instruction_address) { update_stats(feedback.result == BranchResult::NOT_TAKEN); } else { update_stats(feedback.result == BranchResult::TAKEN); } } // Smith 1 Bit // ########### PredictorSmith1Bit::PredictorSmith1Bit( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state) : Predictor(number_of_bht_addr_bits, number_of_bht_bits, initial_state) {}; BranchResult PredictorSmith1Bit::predict(PredictionInput input) { const uint16_t index { calculate_bht_index(input.bhr_value, input.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return BranchResult::NOT_TAKEN; } // Decide prediction return convert_state_to_prediction(bht.at(index).state); } void PredictorSmith1Bit::update(PredictionFeedback feedback) { const uint16_t index { calculate_bht_index(feedback.bhr_value, feedback.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return; } update_bht_stats(index, feedback.result == convert_state_to_prediction(bht.at(index).state)); update_stats(feedback.result == convert_state_to_prediction(bht.at(index).state)); // Update internal state if (feedback.result == BranchResult::NOT_TAKEN) { bht.at(index).state = PredictorState::NOT_TAKEN; } else if (feedback.result == BranchResult::TAKEN) { bht.at(index).state = PredictorState::TAKEN; } else { WARN("Smith 1 bit predictor has received invalid prediction result"); } emit bht_row_updated(index, bht.at(index)); } // Smith 2 Bit // ########### PredictorSmith2Bit::PredictorSmith2Bit( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state) : Predictor(number_of_bht_addr_bits, number_of_bht_bits, initial_state) {}; BranchResult PredictorSmith2Bit::predict(PredictionInput input) { const uint16_t index { calculate_bht_index(input.bhr_value, input.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return BranchResult::NOT_TAKEN; } // Decide prediction return convert_state_to_prediction(bht.at(index).state); } void PredictorSmith2Bit::update(PredictionFeedback feedback) { const uint16_t index { calculate_bht_index(feedback.bhr_value, feedback.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return; } update_bht_stats(index, feedback.result == convert_state_to_prediction(bht.at(index).state)); update_stats(feedback.result == convert_state_to_prediction(bht.at(index).state)); // Read value from BHT at correct index const PredictorState state = bht.at(index).state; // Update internal state if (feedback.result == BranchResult::NOT_TAKEN) { if (state == PredictorState::STRONGLY_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_TAKEN; } else if (state == PredictorState::WEAKLY_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_NOT_TAKEN; } else if (state == PredictorState::WEAKLY_NOT_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_NOT_TAKEN; } else if (state == PredictorState::STRONGLY_NOT_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_NOT_TAKEN; } else { WARN("Smith 2 bit predictor BHT has returned invalid state"); } } else if (feedback.result == BranchResult::TAKEN) { if (state == PredictorState::STRONGLY_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_TAKEN; } else if (state == PredictorState::WEAKLY_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_TAKEN; } else if (state == PredictorState::WEAKLY_NOT_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_TAKEN; } else if (state == PredictorState::STRONGLY_NOT_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_NOT_TAKEN; } else { WARN("Smith 2 bit predictor BHT has returned invalid state"); } } else { WARN("Smith 2 bit predictor has received invalid prediction result"); } emit bht_row_updated(index, bht.at(index)); } // Smith 2 Bit with hysteresis // ########################### PredictorSmith2BitHysteresis::PredictorSmith2BitHysteresis( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state) : Predictor(number_of_bht_addr_bits, number_of_bht_bits, initial_state) {}; BranchResult PredictorSmith2BitHysteresis::predict(PredictionInput input) { const uint16_t index { calculate_bht_index(input.bhr_value, input.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return BranchResult::NOT_TAKEN; } // Decide prediction return convert_state_to_prediction(bht.at(index).state); } void PredictorSmith2BitHysteresis::update(PredictionFeedback feedback) { const uint16_t index { calculate_bht_index(feedback.bhr_value, feedback.instruction_address) }; if (index >= bht.capacity()) { WARN("Tried to access BHT at invalid index: %u", index); return; } update_bht_stats(index, feedback.result == convert_state_to_prediction(bht.at(index).state)); update_stats(feedback.result == convert_state_to_prediction(bht.at(index).state)); // Read value from BHT at correct index const PredictorState state = bht.at(index).state; // Update internal state if (feedback.result == BranchResult::NOT_TAKEN) { if (state == PredictorState::STRONGLY_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_TAKEN; } else if (state == PredictorState::WEAKLY_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_NOT_TAKEN; } else if (state == PredictorState::WEAKLY_NOT_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_NOT_TAKEN; } else if (state == PredictorState::STRONGLY_NOT_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_NOT_TAKEN; } else { WARN("Smith 2 bit hysteresis predictor BHT has returned invalid state"); } } else if (feedback.result == BranchResult::TAKEN) { if (state == PredictorState::STRONGLY_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_TAKEN; } else if (state == PredictorState::WEAKLY_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_TAKEN; } else if (state == PredictorState::WEAKLY_NOT_TAKEN) { bht.at(index).state = PredictorState::STRONGLY_TAKEN; } else if (state == PredictorState::STRONGLY_NOT_TAKEN) { bht.at(index).state = PredictorState::WEAKLY_NOT_TAKEN; } else { WARN("Smith 2 bit hysteresis predictor BHT has returned invalid state"); } } else { WARN("Smith 2 bit hysteresis predictor has received invalid prediction result"); } emit bht_row_updated(index, bht.at(index)); } /////////////////////////// // BranchPredictor class // /////////////////////////// BranchPredictor::BranchPredictor( bool enabled, PredictorType predictor_type, PredictorState initial_state, uint8_t number_of_btb_bits, uint8_t number_of_bhr_bits, uint8_t number_of_bht_addr_bits) : enabled(enabled) , initial_state(initial_state) , number_of_btb_bits(init_number_of_btb_bits(number_of_btb_bits)) , number_of_bhr_bits(init_number_of_bhr_bits(number_of_bhr_bits)) , number_of_bht_addr_bits(init_number_of_bht_addr_bits(number_of_bht_addr_bits)) , number_of_bht_bits(init_number_of_bht_bits(number_of_bhr_bits, number_of_bht_addr_bits)) { // Create predicotr switch (predictor_type) { case PredictorType::ALWAYS_NOT_TAKEN: predictor = new PredictorAlwaysNotTaken(); break; case PredictorType::ALWAYS_TAKEN: predictor = new PredictorAlwaysTaken(); break; case PredictorType::BTFNT: predictor = new PredictorBTFNT(); break; case PredictorType::SMITH_1_BIT: predictor = new PredictorSmith1Bit(number_of_bht_addr_bits, number_of_bht_bits, initial_state); break; case PredictorType::SMITH_2_BIT: predictor = new PredictorSmith2Bit(number_of_bht_addr_bits, number_of_bht_bits, initial_state); break; case PredictorType::SMITH_2_BIT_HYSTERESIS: predictor = new PredictorSmith2BitHysteresis(number_of_bht_addr_bits, number_of_bht_bits, initial_state); break; default: throw std::invalid_argument("Invalid predictor type selected"); } LOG("Initialized branch predictor: %s", qPrintable(get_predictor_name().toString())); bhr = new BranchHistoryRegister(number_of_bhr_bits); btb = new BranchTargetBuffer(number_of_btb_bits); if (enabled) { // Pass through BTB signals connect( btb, &BranchTargetBuffer::btb_row_updated, this, &BranchPredictor::btb_row_updated ); // Pass through BHR signals connect( bhr, &BranchHistoryRegister::bhr_updated, this, &BranchPredictor::bhr_updated ); // Pass through predictor signals connect( predictor, &Predictor::stats_updated, this, &BranchPredictor::predictor_stats_updated ); connect( predictor, &Predictor::bht_row_updated, this, &BranchPredictor::predictor_bht_row_updated ); } } BranchPredictor::~BranchPredictor() { delete predictor; predictor = nullptr; delete bhr; bhr = nullptr; delete btb; btb = nullptr; } uint8_t BranchPredictor::init_number_of_btb_bits(const uint8_t b) const { if (b > BP_MAX_BTB_BITS) { WARN("Number of BTB bits (%u) was larger than %d during init", b, BP_MAX_BTB_BITS); return BP_MAX_BTB_BITS; } return b; } uint8_t BranchPredictor::init_number_of_bhr_bits(const uint8_t b) const { if (b > BP_MAX_BHR_BITS) { WARN("Number of BHR bits (%u) was larger than %d during init", b, BP_MAX_BHR_BITS); return BP_MAX_BHR_BITS; } return b; } uint8_t BranchPredictor::init_number_of_bht_addr_bits(const uint8_t b) const { if (b > BP_MAX_BHT_ADDR_BITS) { WARN( "Number of BHT instruction address bits (%u) was larger than %d during init", b, BP_MAX_BHT_ADDR_BITS); return BP_MAX_BHT_ADDR_BITS; } return b; } uint8_t BranchPredictor::init_number_of_bht_bits(const uint8_t b_bhr, const uint8_t b_addr) const { // Clamp number of BHR bits uint8_t checked_number_of_bits_bhr { b_bhr }; if (checked_number_of_bits_bhr > BP_MAX_BHR_BITS) { checked_number_of_bits_bhr = BP_MAX_BHR_BITS; } // Clamp number of address index bits uint8_t checked_number_of_bits_addr { b_addr }; if (checked_number_of_bits_addr > BP_MAX_BHT_ADDR_BITS) { checked_number_of_bits_addr = BP_MAX_BHT_ADDR_BITS; } // Check sum uint8_t b_sum { (uint8_t)(checked_number_of_bits_bhr + checked_number_of_bits_addr) }; if (b_sum > BP_MAX_BHT_BITS) { b_sum = BP_MAX_BHT_BITS; } return b_sum; } bool BranchPredictor::get_enabled() const { return enabled; } PredictorType BranchPredictor::get_predictor_type() const { if (!enabled) { return PredictorType::UNDEFINED; } return predictor->get_type(); } QStringView BranchPredictor::get_predictor_name() const { if (!enabled) { return u"None"; } return predictor_type_to_string(predictor->get_type()); } PredictorState BranchPredictor::get_initial_state() const { if (!enabled) { return PredictorState::UNDEFINED; } return initial_state; } uint8_t BranchPredictor::get_number_of_btb_bits() const { if (!enabled) { return 0; } return number_of_btb_bits; } uint8_t BranchPredictor::get_number_of_bhr_bits() const { if (!enabled) { return 0; } return number_of_bhr_bits; } uint8_t BranchPredictor::get_number_of_bht_addr_bits() const { if (!enabled) { return 0; } return number_of_bht_addr_bits; } uint8_t BranchPredictor::get_number_of_bht_bits() const { if (!enabled) { return 0; } return number_of_bht_bits; } void BranchPredictor::increment_jumps() { total_stats.total += 1; total_stats.correct = total_stats.total - total_stats.wrong; if (total_stats.total > 0) { total_stats.accuracy = ((total_stats.correct * 100) / total_stats.total); } emit total_stats_updated(total_stats); } void BranchPredictor::increment_mispredictions() { total_stats.wrong += 1; total_stats.correct = total_stats.total - total_stats.wrong; if (total_stats.total > 0) { total_stats.accuracy = ((total_stats.correct * 100) / total_stats.total); } emit total_stats_updated(total_stats); } Address BranchPredictor::predict_next_pc_address( const Instruction instruction, const Address instruction_address) const { // Check if predictor is enabled if (!enabled) { return instruction_address + 4; } // Read entry from BTB const BranchTargetBufferEntry btb_entry = btb->get_entry(instruction_address); if (!btb_entry.entry_valid) { return instruction_address + 4; } if (btb_entry.instruction_address != instruction_address) { return instruction_address + 4; } // Make prediction const PredictionInput prediction_input { .instruction = instruction, .bhr_value = bhr->get_value(), .instruction_address = instruction_address, .target_address = btb_entry.target_address, }; BranchResult predicted_result{ BranchResult::UNDEFINED }; if (btb_entry.branch_type == BranchType::BRANCH) { predicted_result = predictor->predict(prediction_input); } else { predicted_result = BranchResult::TAKEN; } emit prediction_done( btb->calculate_index(instruction_address), predictor->calculate_bht_index(bhr->get_value(), instruction_address), prediction_input, predicted_result, btb_entry.branch_type); // If the branch was predicted Taken if (predicted_result == BranchResult::TAKEN) { return btb_entry.target_address; } // Default prediction - Not Taken return instruction_address + 4; } // Function for updating the predictor and the Branch History Register (BHR) void BranchPredictor::update( const Instruction instruction, const Address instruction_address, const Address target_address, const BranchType branch_type, const BranchResult result) { // Check if predictor is enabled if (!enabled) { return; } // Update Branch Target Buffer btb->update(instruction_address, target_address, branch_type); // Update predictor only for conditional branches const PredictionFeedback prediction_feedback { .instruction = instruction, .bhr_value = bhr->get_value(), .instruction_address = instruction_address, .target_address = target_address, .result = result, .branch_type = branch_type }; if (branch_type == BranchType::BRANCH) { predictor->update(prediction_feedback); } increment_jumps(); emit update_done( btb->calculate_index(instruction_address), predictor->calculate_bht_index(bhr->get_value(), instruction_address), prediction_feedback); // Update global branch history bhr->update(result); } void BranchPredictor::clear() { bhr->clear(); btb->clear(); predictor->clear(); emit cleared(); } void BranchPredictor::flush() { bhr->clear(); btb->clear(); predictor->flush(); emit flushed(); } qtrvsim-0.9.8/src/machine/predictor.h000066400000000000000000000260131467752164200176140ustar00rootroot00000000000000#ifndef PREDICTOR_H #define PREDICTOR_H #include "common/logging.h" #include "instruction.h" #include "memory/address.h" #include "predictor_types.h" #include #include namespace machine { QStringView branch_result_to_string(const BranchResult result, const bool abbrv = false); QStringView predictor_state_to_string(const PredictorState state, const bool abbrv = false); QStringView predictor_type_to_string(const PredictorType type); QStringView branch_type_to_string(const BranchType type); QString addr_to_hex_str(const machine::Address address); bool is_predictor_type_dynamic(const PredictorType type); ///////////////////////////////// // BranchHistoryRegister class // ///////////////////////////////// class BranchHistoryRegister final : public QObject { Q_OBJECT public: // Constructors & Destructor explicit BranchHistoryRegister(const uint8_t number_of_bits); private: // Internal functions uint8_t init_number_of_bits(const uint8_t b) const; uint16_t init_register_mask(const uint8_t b) const; public: // General functions uint8_t get_number_of_bits() const; uint16_t get_register_mask() const; uint16_t get_value() const; void update(const BranchResult result); void clear(); signals: void bhr_updated(uint8_t number_of_bhr_bits, uint16_t register_value); private: // Internal variables const uint8_t number_of_bits; const uint16_t register_mask; uint16_t value { 0 }; }; ///////////////////////////// // BranchTargetBuffer class // ///////////////////////////// struct BranchTargetBufferEntry { bool entry_valid{ false }; Address instruction_address{ Address::null() }; Address target_address{ Address::null() }; BranchType branch_type{ BranchType::UNDEFINED }; }; class BranchTargetBuffer final : public QObject { Q_OBJECT public: // Constructors & Destructor explicit BranchTargetBuffer(const uint8_t number_of_bits); private: // Internal functions uint8_t init_number_of_bits(const uint8_t b) const; public: // General functions uint8_t get_number_of_bits() const; uint16_t calculate_index(const Address instruction_address) const; BranchTargetBufferEntry get_entry(const Address instruction_address) const; void update(const Address instruction_address, const Address target_address, const BranchType branch_type); void clear(); signals: void btb_row_updated(uint16_t index, BranchTargetBufferEntry btb_entry) const; private: // Internal variables const uint8_t number_of_bits; std::vector btb; }; ///////////////////// // Predictor class // ///////////////////// struct PredictionInput { Instruction instruction {}; uint16_t bhr_value { 0 }; Address instruction_address { Address::null() }; Address target_address { Address::null() }; }; struct PredictionFeedback { Instruction instruction {}; uint16_t bhr_value { 0 }; Address instruction_address { Address::null() }; Address target_address { Address::null() }; BranchResult result { BranchResult::UNDEFINED }; BranchType branch_type { BranchType::UNDEFINED }; }; struct PredictionStatistics { float accuracy { 0 }; // 0 - 100 % uint32_t total { 0 }; uint32_t correct { 0 }; uint32_t wrong { 0 }; }; struct BranchHistoryTableEntry { PredictorState state { PredictorState::UNDEFINED }; PredictionStatistics stats {}; // Per-entry statistics }; class Predictor : public QObject { Q_OBJECT public: // Constructors & Destructor Predictor( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state); virtual ~Predictor() = default; protected: // Internal functions uint8_t init_number_of_bht_addr_bits(uint8_t b) const; uint8_t init_number_of_bht_bits(uint8_t b) const; BranchResult convert_state_to_prediction(PredictorState state) const; void update_stats(bool prediction_was_correct); void update_bht_stats(uint16_t bht_index, bool prediction_was_correct); public: // General functions uint16_t calculate_bht_index(const uint16_t bhr_value, const Address instruction_address) const; virtual PredictorType get_type() const = 0; virtual BranchResult predict(PredictionInput input) = 0; // Function which handles all actions ties // to making a branch prediction virtual void update(PredictionFeedback feedback) = 0; // Update predictor based on jump / branch // result void clear_stats(); void clear_bht_stats(); void clear_bht_state(); void clear(); void flush(); signals: void stats_updated(PredictionStatistics stats) const; void bht_row_updated(uint16_t index, BranchHistoryTableEntry entry) const; protected: // Internal variables const uint8_t number_of_bht_addr_bits; // Number of Branch History Table (BHT) bits taken from // instruction address const uint8_t number_of_bht_bits; // Number of Branch History Table (BHT) bits const PredictorState initial_state; PredictionStatistics stats; // Total predictor statistics std::vector bht; // Branch History Table (BHT) }; // Static Predictor - Always predicts not taking the branch class PredictorAlwaysNotTaken final : public Predictor { public: // Constructors & Destructor PredictorAlwaysNotTaken(); public: // General functions PredictorType get_type() const override { return PredictorType::ALWAYS_NOT_TAKEN; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; // Static Predictor - Always predicts taking the branch class PredictorAlwaysTaken final : public Predictor { public: // Constructors & Destructor PredictorAlwaysTaken(); public: // General functions PredictorType get_type() const override { return PredictorType::ALWAYS_TAKEN; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; // Static Predictor - Backward Taken Forward Not Taken class PredictorBTFNT final : public Predictor { public: // Constructors & Destructor PredictorBTFNT(); public: // General functions PredictorType get_type() const override { return PredictorType::BTFNT; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; // Dynamic Predictor - Smith 1 Bit class PredictorSmith1Bit final : public Predictor { public: // Constructors & Destructor PredictorSmith1Bit( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state); public: // General functions PredictorType get_type() const override { return PredictorType::SMITH_1_BIT; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; // Dynamic Predictor - Smith 2 Bit class PredictorSmith2Bit final : public Predictor { public: // Constructors & Destructor PredictorSmith2Bit( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state); public: // General functions PredictorType get_type() const override { return PredictorType::SMITH_2_BIT; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; // Dynamic Predictor - Smith 2 Bit with hysteresis class PredictorSmith2BitHysteresis final : public Predictor { public: // Constructors & Destructor PredictorSmith2BitHysteresis( uint8_t number_of_bht_addr_bits, uint8_t number_of_bht_bits, PredictorState initial_state); public: // General functions PredictorType get_type() const override { return PredictorType::SMITH_2_BIT_HYSTERESIS; }; BranchResult predict(PredictionInput input) override; void update(PredictionFeedback feedback) override; }; /////////////////////////// // BranchPredictor class // /////////////////////////// class BranchPredictor : public QObject { Q_OBJECT public: // Constructors & Destructor explicit BranchPredictor( bool enabled = false, PredictorType predictor_type = PredictorType::SMITH_1_BIT, PredictorState initial_state = PredictorState::NOT_TAKEN, uint8_t number_of_btb_bits = 2, uint8_t number_of_bhr_bits = 0, uint8_t number_of_bht_addr_bits = 2); ~BranchPredictor(); private: // Internal functions uint8_t init_number_of_btb_bits(const uint8_t b) const; uint8_t init_number_of_bhr_bits(const uint8_t b) const; uint8_t init_number_of_bht_addr_bits(const uint8_t b) const; uint8_t init_number_of_bht_bits(const uint8_t b_bhr, const uint8_t b_addr) const; public: // General functions bool get_enabled() const; PredictorType get_predictor_type() const; QStringView get_predictor_name() const; PredictorState get_initial_state() const; uint8_t get_number_of_btb_bits() const; uint8_t get_number_of_bhr_bits() const; uint8_t get_number_of_bht_addr_bits() const; uint8_t get_number_of_bht_bits() const; void increment_jumps(); void increment_mispredictions(); Address predict_next_pc_address(const Instruction instruction, const Address instruction_address) const; void update( const Instruction instruction, const Address instruction_address, const Address target_address, const BranchType branch_type, const BranchResult result); void clear(); void flush(); signals: void total_stats_updated(PredictionStatistics total_stats); void prediction_done(uint16_t btb_index, uint16_t bht_index, PredictionInput input, BranchResult result, BranchType branch_type) const; void update_done(uint16_t btb_index, uint16_t bht_index, PredictionFeedback feedback) const; void predictor_stats_updated(PredictionStatistics stats) const; void predictor_bht_row_updated(uint16_t index, BranchHistoryTableEntry entry) const; void bhr_updated(uint8_t number_of_bhr_bits, uint16_t register_value) const; void btb_row_updated(uint16_t index, BranchTargetBufferEntry btb_entry) const; void cleared() const; // All infomration was reset void flushed() const; // Only BHT state and BTB rows were reset private: // Internal variables bool enabled{ false }; PredictionStatistics total_stats; Predictor *predictor; BranchHistoryRegister *bhr; BranchTargetBuffer *btb; const PredictorState initial_state; const uint8_t number_of_btb_bits; // Number of bits for addressing Branch Target Buffer (all // taken from instruction address) const uint8_t number_of_bhr_bits; // Number of bits in Branch History Register const uint8_t number_of_bht_addr_bits; // Number of bits in Branch History Table which are taken // from instruction address const uint8_t number_of_bht_bits; // = number_of_bhr_bits + number_of_bht_addr_bits }; } // namespace machine #endif // PREDICTOR_H qtrvsim-0.9.8/src/machine/predictor_types.h000066400000000000000000000022001467752164200210300ustar00rootroot00000000000000#ifndef PREDICTOR_TYPES_H #define PREDICTOR_TYPES_H namespace machine { Q_NAMESPACE // Should not exceed 16, because uint16_t is used for addressing #define BP_MAX_BTB_BITS 8 #define BP_MAX_BHR_BITS 8 #define BP_MAX_BHT_ADDR_BITS 8 #define BP_MAX_BHT_BITS (BP_MAX_BHT_ADDR_BITS + BP_MAX_BHT_ADDR_BITS) enum class BranchType { JUMP, // JAL, JALR - Unconditional BRANCH, // BXX - Conditional UNDEFINED }; Q_ENUM_NS(machine::BranchType) enum class BranchResult { NOT_TAKEN, TAKEN, UNDEFINED }; Q_ENUM_NS(machine::BranchResult) enum class PredictorType { ALWAYS_NOT_TAKEN, ALWAYS_TAKEN, BTFNT, // Backward Taken, Forward Not Taken SMITH_1_BIT, SMITH_2_BIT, SMITH_2_BIT_HYSTERESIS, UNDEFINED }; Q_ENUM_NS(machine::PredictorType) enum class PredictorState { NOT_TAKEN, // Smith 1 bit TAKEN, // Smith 1 bit STRONGLY_NOT_TAKEN, // Smith 2 bit WEAKLY_NOT_TAKEN, // Smith 2 bit WEAKLY_TAKEN, // Smith 2 bit STRONGLY_TAKEN, // Smith 2 bit UNDEFINED }; Q_ENUM_NS(machine::PredictorState) } // namespace machine #endif // PREDICTOR_TYPES_H qtrvsim-0.9.8/src/machine/programloader.cpp000066400000000000000000000174321467752164200210170ustar00rootroot00000000000000#include "programloader.h" #include "common/endian.h" #include "common/logging.h" #include "simulator_exception.h" #include #include #include LOG_CATEGORY("machine.ProgramLoader"); // TODO - document #ifndef O_BINARY #define O_BINARY 0 #endif using namespace machine; ProgramLoader::ProgramLoader(const QString &file) : elf_file(file) { const GElf_Ehdr *elf_ehdr; // Initialize elf library if (elf_version(EV_CURRENT) == EV_NONE) { throw SIMULATOR_EXCEPTION( Input, "Elf library initialization failed", elf_errmsg(-1)); } // Open source file - option QIODevice::ExistingOnly cannot be used on Qt // <5.11 if (!elf_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { throw SIMULATOR_EXCEPTION( Input, QString("Can't open input elf file for reading (") + QString(file) + QString(")"), std::strerror(errno)); } // Initialize elf if (!(this->elf = elf_begin(elf_file.handle(), ELF_C_READ, nullptr))) { throw SIMULATOR_EXCEPTION( Input, "Elf read begin failed", elf_errmsg(-1)); } // Check elf kind if (elf_kind(this->elf) != ELF_K_ELF) { throw SIMULATOR_EXCEPTION( Input, "Invalid input file elf format, plain elf file expected", ""); } elf_ehdr = gelf_getehdr(this->elf, &this->hdr); if (!elf_ehdr) { throw SIMULATOR_EXCEPTION( Input, "Getting elf file header failed", elf_errmsg(-1)); } executable_entry = Address(elf_ehdr->e_entry); // Check elf file format, executable expected, nothing else. if (this->hdr.e_type != ET_EXEC) { throw SIMULATOR_EXCEPTION(Input, "Invalid input file type", ""); } // Check elf file architecture, of course only mips is supported. // Note: This also checks that this is big endian as EM_MIPS is suppose to // be: MIPS R3000 big-endian if (this->hdr.e_machine != EM_RISCV) { throw SIMULATOR_EXCEPTION(Input, "Invalid input file architecture", ""); } // Check elf file class, only 32bit architecture is supported. int elf_class; if ((elf_class = gelf_getclass(this->elf)) == ELFCLASSNONE) { throw SIMULATOR_EXCEPTION( Input, "Getting elf class failed", elf_errmsg(-1)); } // Get number of program sections in elf file if (elf_getphdrnum(this->elf, &this->n_secs)) { throw SIMULATOR_EXCEPTION( Input, "Elf program sections count query failed", elf_errmsg(-1)); } if (elf_class == ELFCLASS32) { LOG("Loaded executable: 32bit"); architecture_type = ARCH32; // Get program sections headers if (!(sections_headers.arch32 = elf32_getphdr(elf))) { throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1)); } // We want only LOAD sections so we create load_sections_indexes of those sections for (unsigned i = 0; i < n_secs; i++) { if (sections_headers.arch32[i].p_type != PT_LOAD) { continue; } indexes_of_load_sections.push_back(i); } } else if (elf_class == ELFCLASS64) { LOG("Loaded executable: 64bit"); architecture_type = ARCH64; WARN("64bit simulation is not fully supported."); // Get program sections headers if (!(sections_headers.arch64 = elf64_getphdr(elf))) { throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1)); } // We want only LOAD sections so we create load_sections_indexes of those sections for (unsigned i = 0; i < this->n_secs; i++) { if (sections_headers.arch64[i].p_type != PT_LOAD) { continue; } this->indexes_of_load_sections.push_back(i); } } else { WARN("Unsupported elf class: %d", elf_class); throw SIMULATOR_EXCEPTION( Input, "Unsupported architecture type." "This simulator only supports 32bit and 64bit CPUs.", ""); } } ProgramLoader::ProgramLoader(const char *file) : ProgramLoader(QString::fromLocal8Bit(file)) {} ProgramLoader::~ProgramLoader() { // Close elf elf_end(this->elf); // Close file elf_file.close(); } void ProgramLoader::to_memory(Memory *mem) { // Load program to memory (just dump it byte by byte) if (architecture_type == ARCH32) { for (size_t phdrs_i : this->indexes_of_load_sections) { uint32_t base_address = this->sections_headers.arch32[phdrs_i].p_vaddr; char *f = elf_rawfile(this->elf, nullptr); for (unsigned y = 0; y < this->sections_headers.arch32[phdrs_i].p_filesz; y++) { const auto buffer = (uint8_t)f[this->sections_headers.arch32[phdrs_i].p_offset + y]; memory_write_u8(mem, base_address + y, buffer); } } } else if (architecture_type == ARCH64) { for (size_t phdrs_i : this->indexes_of_load_sections) { uint32_t base_address = this->sections_headers.arch64[phdrs_i].p_vaddr; char *f = elf_rawfile(this->elf, nullptr); for (unsigned y = 0; y < this->sections_headers.arch64[phdrs_i].p_filesz; y++) { const auto buffer = (uint8_t)f[this->sections_headers.arch64[phdrs_i].p_offset + y]; memory_write_u8(mem, base_address + y, buffer); } } } } Address ProgramLoader::end() { uint32_t last = 0; // Go trough all sections and found out last one if (architecture_type == ARCH32) { for (size_t i : this->indexes_of_load_sections) { Elf32_Phdr *phdr = &(this->sections_headers.arch32[i]); if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; } } } else if (architecture_type == ARCH64) { for (size_t i : this->indexes_of_load_sections) { Elf64_Phdr *phdr = &(this->sections_headers.arch64[i]); if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; } } } return Address(last + 0x10); // We add offset so we are sure that also // pipeline is empty TODO propagate address // deeper } Address ProgramLoader::get_executable_entry() const { return executable_entry; } SymbolTable *ProgramLoader::get_symbol_table() { auto *p_st = new SymbolTable(); Elf_Scn *scn = nullptr; GElf_Shdr shdr; Elf_Data *data; int count, ii; elf_version(EV_CURRENT); while (true) { if ((scn = elf_nextscn(this->elf, scn)) == nullptr) { return p_st; } gelf_getshdr(scn, &shdr); if (shdr.sh_type == SHT_SYMTAB) { /* found a symbol table, go print it. */ break; } } data = elf_getdata(scn, nullptr); count = shdr.sh_size / shdr.sh_entsize; /* retrieve the symbol names */ for (ii = 0; ii < count; ++ii) { GElf_Sym sym; gelf_getsym(data, ii, &sym); p_st->add_symbol( elf_strptr(elf, shdr.sh_link, sym.st_name), sym.st_value, sym.st_size, sym.st_info, sym.st_other); } return p_st; } Endian ProgramLoader::get_endian() const { // Reading elf endian_id_byte according to the ELF specs. unsigned char endian_id_byte = this->hdr.e_ident[EI_DATA]; if (endian_id_byte == ELFDATA2LSB) { return LITTLE; } else if (endian_id_byte == ELFDATA2MSB) { return BIG; } else { throw SIMULATOR_EXCEPTION( Input, "ELF header e_ident malformed." "Unknown value of the byte EI_DATA." "Expected value little (=1) or big (=2).", ""); } } ArchitectureType ProgramLoader::get_architecture_type() const { return architecture_type; } qtrvsim-0.9.8/src/machine/programloader.h000066400000000000000000000025271467752164200204630ustar00rootroot00000000000000#ifndef PROGRAM_H #define PROGRAM_H #include "common/endian.h" #include "memory/backend/memory.h" #include "symboltable.h" #include #include #include #include #include namespace machine { enum ArchitectureType { ARCH32, ARCH64, }; class ProgramLoader { public: explicit ProgramLoader(const char *file); explicit ProgramLoader(const QString &file); ~ProgramLoader(); void to_memory(Memory *mem); // Writes all loaded sections to memory TODO: // really to memory ??? Address end(); // Return address after which there is no more code for // sure Address get_executable_entry() const; SymbolTable *get_symbol_table(); Endian get_endian() const; /** Tells whether the executable is 32bit or 64bit. */ ArchitectureType get_architecture_type() const; private: QFile elf_file; Elf *elf; GElf_Ehdr hdr {}; // elf file header size_t n_secs {}; // number of sections in elf program header ArchitectureType architecture_type; private: union { Elf32_Phdr *arch32; Elf64_Phdr *arch64; } sections_headers{}; QVector indexes_of_load_sections; // external index to sections_headers index Address executable_entry; }; } // namespace machine #endif // PROGRAM_H qtrvsim-0.9.8/src/machine/programloader.test.cpp000066400000000000000000000020221467752164200217620ustar00rootroot00000000000000#include "programloader.test.h" #include "machine/instruction.h" #include "machine/memory/memory_utils.h" #include "machine/programloader.h" #include "memory/backend/memory.h" using namespace machine; // This is common program start (initial value of program counter) #define PC_INIT 0x00000200 const char *EXECUTABLE_NAME = "data"; void TestProgramLoader::program_loader() { if (not QFile::exists(EXECUTABLE_NAME)) { QSKIP("Executable is not present, cannot test program loader."); } ProgramLoader pl(EXECUTABLE_NAME); Memory m(BIG); pl.to_memory(&m); // addi $1, $0, 6 // QCOMPARE(Instruction(memory_read_u32(&m, PC_INIT)), Instruction(8, 0, 1, 6)); // j (8)0020000 (only 28 bits are used and they are logically shifted left // by 2) // QCOMPARE(Instruction(memory_read_u32(&m, PC_INIT + 4)), Instruction(2, Address(0x20000 >> // 2))); // TODO add some more code to data and do more compares (for example more // sections) } QTEST_APPLESS_MAIN(TestProgramLoader)qtrvsim-0.9.8/src/machine/programloader.test.h000066400000000000000000000003231467752164200214310ustar00rootroot00000000000000#ifndef PROGRAMLOADER_TEST_H #define PROGRAMLOADER_TEST_H #include class TestProgramLoader : public QObject { Q_OBJECT public slots: void program_loader(); }; #endif // PROGRAMLOADER_TEST_H qtrvsim-0.9.8/src/machine/register_value.h000066400000000000000000000075741467752164200206540ustar00rootroot00000000000000#ifndef REGISTER_VALUE_H #define REGISTER_VALUE_H #include "machine/machineconfig.h" #include namespace machine { /* * Register size configuration * * TODO: make compile time option */ using register_storage_t = uint64_t; /** * Represents a value stored in register * * Register value is semantically considered to be only an array of bits * and with no meaning assumed, therefore no operations are implemented * and value has to be interpreted as numerical value. * * By default, registers are initialized to zero. */ class RegisterValue { public: /** * * NOTE ON IMPLICIT CONVERSION: * Implicit conversion from unsigned integer is allowed as RegisterValue * as it essentially mean to forget the meaning of the value. Reverse * direction is always explicit. * * Constructor needs to be defined even for uint32_t as cpp cannot decide * whether to use uint64_t or int32_t. */ constexpr inline RegisterValue(uint64_t value) // NOLINT(google-explicit-constructor) : data(value) {}; // Must be present to avoid ambiguity. constexpr inline RegisterValue(uint32_t value) // NOLINT(google-explicit-constructor) : data(value) {}; constexpr inline RegisterValue() : data(0) {}; constexpr inline RegisterValue(const RegisterValue &other) = default; constexpr inline RegisterValue &operator=(const RegisterValue &other) = default; /* Sign-extending constructors */ constexpr inline RegisterValue(int64_t value) // NOLINT(google-explicit-constructor) : data(value) {}; constexpr inline RegisterValue(int32_t value) // NOLINT(google-explicit-constructor) : data(value) {}; constexpr inline RegisterValue(int16_t value) // NOLINT(google-explicit-constructor) : data(value) {}; constexpr inline RegisterValue(int8_t value) // NOLINT(google-explicit-constructor) : data(value) {}; [[nodiscard]] constexpr inline uint64_t as_xlen(Xlen xlen) const { switch (xlen) { case Xlen::_32: return as_u32(); case Xlen::_64: return as_u64(); default: UNREACHABLE } } [[nodiscard]] constexpr inline int8_t as_i8() const { return (int8_t)data; }; [[nodiscard]] constexpr inline uint8_t as_u8() const { return (uint8_t)data; }; [[nodiscard]] constexpr inline int16_t as_i16() const { return (int16_t)data; }; [[nodiscard]] constexpr inline uint16_t as_u16() const { return (uint16_t)data; }; [[nodiscard]] constexpr inline int32_t as_i32() const { return (int32_t)data; }; [[nodiscard]] constexpr inline uint32_t as_u32() const { return (uint32_t)data; }; [[nodiscard]] constexpr inline int64_t as_i64() const { return (int64_t)data; }; [[nodiscard]] constexpr inline uint64_t as_u64() const { return (uint64_t)data; }; constexpr explicit operator int8_t() const { return as_i8(); }; constexpr explicit operator uint8_t() const { return as_u8(); }; constexpr explicit operator int16_t() const { return as_i16(); }; constexpr explicit operator uint16_t() const { return as_u16(); }; constexpr explicit operator int32_t() const { return as_i32(); }; constexpr explicit operator uint32_t() const { return as_u32(); }; constexpr explicit operator int64_t() const { return as_i64(); }; constexpr explicit operator uint64_t() const { return as_u64(); }; /** * Equality operator is implemented as bit by bit comparison is reasonable * for bit array. * It is necessary to make gp-register array comparable. */ constexpr inline bool operator==(const RegisterValue &other) const { return data == other.data; } constexpr inline bool operator!=(const RegisterValue &other) const { return !(other == *this); } private: register_storage_t data; }; } // namespace machine Q_DECLARE_METATYPE(machine::RegisterValue) #endif // REGISTER_VALUE_H qtrvsim-0.9.8/src/machine/registers.cpp000066400000000000000000000035731467752164200201710ustar00rootroot00000000000000#include "registers.h" #include "memory/address.h" #include "simulator_exception.h" using namespace machine; // TODO should this be configurable? ////////////////////////////////////////////////////////////////////////////// /// Program counter initial value #define PC_INIT 0x00000200_addr #define SP_INIT 0xbfffff00_addr ////////////////////////////////////////////////////////////////////////////// Registers::Registers() : QObject() { reset(); } Registers::Registers(const Registers &orig) : QObject() { this->pc = orig.read_pc(); this->gp = orig.gp; } Address Registers::read_pc() const { return this->pc; } void Registers::write_pc(machine::Address address) { if (address.get_raw() % 4) { throw SIMULATOR_EXCEPTION( UnalignedJump, "Trying to jump to unaligned address", QString::number(address.get_raw(), 16)); } this->pc = address; emit pc_update(this->pc); } RegisterValue Registers::read_gp(RegisterId reg) const { if (reg == 0) { return { 0 }; // $0 always reads as 0 } RegisterValue value = this->gp.at(reg); emit gp_read(reg, value); return value; } void Registers::write_gp(RegisterId reg, RegisterValue value) { if (reg == 0) { return; // Skip write to $0 } this->gp.at(reg) = value; emit gp_update(reg, value); } bool Registers::operator==(const Registers &c) const { if (read_pc() != c.read_pc()) { return false; } if (this->gp != c.gp) { return false; } return true; } bool Registers::operator!=(const Registers &c) const { return !this->operator==(c); } void Registers::reset() { write_pc(PC_INIT); // Initialize to beginning program section for (int i = 1; i < 32; i++) { write_gp(i, 0); } write_gp(2_reg, SP_INIT.get_raw()); // initialize to safe RAM area - // corresponds to Linux } qtrvsim-0.9.8/src/machine/registers.h000066400000000000000000000050231467752164200176260ustar00rootroot00000000000000#ifndef REGISTERS_H #define REGISTERS_H #include "memory/address.h" #include "register_value.h" #include "simulator_exception.h" #include #include #include namespace machine { /** * General-purpose register count */ constexpr size_t REGISTER_COUNT = 32; /** * General-purpose register identifier */ class RegisterId { public: inline constexpr RegisterId(uint8_t value); // NOLINT(google-explicit-constructor) inline RegisterId(); constexpr operator size_t() const { return data; }; // NOLINT(google-explicit-constructor) private: uint8_t data; }; inline constexpr RegisterId::RegisterId(uint8_t value) : data(value) { // Bounds on the id are checked at creation time and its value is immutable. // Therefore, all check at when used are redundant. // Main advantage is, that possible errors will appear when creating the // value, which is probably close to the bug source. SANITY_ASSERT( value < REGISTER_COUNT, QString("Trying to create register id for out-of-bounds register ") + QString::number(data)); } inline RegisterId::RegisterId() : RegisterId(0) {} inline RegisterId operator"" _reg(unsigned long long value) { return { static_cast(value) }; } /** * Register file */ class Registers : public QObject { Q_OBJECT public: Registers(); Registers(const Registers &); Address read_pc() const; // Return current value of program counter void write_pc(Address address); // Absolute jump in program counter RegisterValue read_gp(RegisterId reg) const; // Read general-purpose // register void write_gp(RegisterId reg, RegisterValue value); // Write general-purpose // register bool operator==(const Registers &c) const; bool operator!=(const Registers &c) const; void reset(); // Reset all values to zero (except pc) signals: void pc_update(Address val); void gp_update(RegisterId reg, RegisterValue val); void gp_read(RegisterId reg, RegisterValue val) const; private: /** * General purpose registers * * Zero register is always zero, but is allocated to avoid off-by-one. * Getters and setters will never try to read or write zero register. */ std::array gp {}; Address pc {}; // program counter }; } // namespace machine Q_DECLARE_METATYPE(machine::Registers) #endif // REGISTERS_H qtrvsim-0.9.8/src/machine/registers.test.cpp000066400000000000000000000020211467752164200211320ustar00rootroot00000000000000#include "registers.test.h" #include "machine/registers.h" using namespace machine; void TestRegisters::registers_gp0() { Registers r; QCOMPARE(r.read_gp(0), RegisterValue(0)); r.write_gp(0, 0xff); QCOMPARE(r.read_gp(0), RegisterValue(0)); } void TestRegisters::registers_rw_gp() { Registers r; for (int i = 1; i < 32; i++) { r.write_gp(i, 0xf00 + i); QCOMPARE(r.read_gp(i), RegisterValue(0xf00 + i)); } } void TestRegisters::registers_compare() { Registers r1, r2; QCOMPARE(r1, r2); // General purpose register r1.write_gp(1, 24); QVERIFY(r1 != r2); r2.write_gp(1, 24); QCOMPARE(r1, r2); // Program counter r1.write_pc(r1.read_pc() + 4); QVERIFY(r1 != r2); r2.write_pc(r2.read_pc() + 4); QCOMPARE(r1, r2); // Now let's try copy (and verify only with gp this time) Registers r3(r1); QCOMPARE(r3, r1); r3.write_gp(12, 19); QVERIFY(r1 != r3); r1.write_gp(12, 19); QCOMPARE(r3, r1); } QTEST_APPLESS_MAIN(TestRegisters)qtrvsim-0.9.8/src/machine/registers.test.h000066400000000000000000000004211467752164200206010ustar00rootroot00000000000000#ifndef REGISTERS_TEST_H #define REGISTERS_TEST_H #include class TestRegisters : public QObject { Q_OBJECT public slots: static void registers_gp0(); static void registers_rw_gp(); static void registers_compare(); }; #endif // REGISTERS_TEST_H qtrvsim-0.9.8/src/machine/simulator_exception.cpp000066400000000000000000000026721467752164200222560ustar00rootroot00000000000000#include "simulator_exception.h" #include #include #include using namespace machine; SimulatorException::SimulatorException( QString reason, QString ext, QString file, int line) { this->name = "Exception"; this->reason = std::move(reason); this->ext = std::move(ext); this->file = std::move(file); this->line = line; } const char *SimulatorException::what() const noexcept { QString message = this->msg(true); char *cstr = new char[message.length() + 1]; std::strcpy(cstr, message.toStdString().c_str()); return cstr; } QString SimulatorException::msg(bool pos) const { QString message; message += name; if (pos) { message += QString(" (") + QString(this->file) + QString(":") + QString::number(this->line) + QString(")"); } message += ": " + this->reason; if (!this->ext.isEmpty()) { message += QString(": "); message += this->ext; } return message; } #define EXCEPTION(NAME, PARENT) \ SimulatorException##NAME::SimulatorException##NAME( \ QString reason, QString ext, QString file, int line) \ : SimulatorException##PARENT(reason, ext, file, line) { \ name = #NAME; \ } SIMULATOR_EXCEPTIONS #undef EXCEPTION qtrvsim-0.9.8/src/machine/simulator_exception.h000066400000000000000000000117241467752164200217210ustar00rootroot00000000000000#ifndef SIMULATOR_EXCEPTION_H #define SIMULATOR_EXCEPTION_H #include #include namespace machine { // Base exception for all machine ones class SimulatorException : public std::exception { public: SimulatorException(QString reason, QString ext, QString file, int line); const char *what() const noexcept override; QString msg(bool pos) const; protected: QString name, reason, ext, file; int line; }; /* This is list of all QtRvSim specific exceptions * * Input: * Exception durring input loading * Runtime: * Exceptions caused by machine invalid input or unsupported action * UnsupportedInstruction: * Decoded instruction is not supported. * This can be cause by really using some unimplemented instruction or because * of problems in instruction decode. UnsupportedAluOperation: Decoded ALU * operation is not supported This is basically same exception as * SimulatorExceptionUnsupportedInstruction but it is emmited from ALU when * executed and not before that. Overflow: Integer operation resulted to * overflow (or underflow as we are working with unsigned values) This is for * sure caused by program it self. UnalignedJump: Instruction is jumping to * unaligned address (ADDR % 4 != 0) This can be caused by bug or by user * program as it can be jumping relative to register This shouldn't be happening * with non-register jumps as those should be verified by compiler * UnknownMemoryControl: * Used unknown MemoryAccess control value (write_ctl or read_ctl) * This can be raised by invalid instruction but in such case we shoul raise * UnknownInstruction instead So this should signal just some QtRvSim bug. * OutOfMemoryAccess: * Trying to access address outside of the memory * As we are simulating whole 32bit memory address space then this is most * probably QtRvSim bug if raised not program. Sanity: This is sanity check * exception */ #define SIMULATOR_EXCEPTIONS \ EXCEPTION(Input, ) \ EXCEPTION(Runtime, ) \ EXCEPTION(UnsupportedInstruction, Runtime) \ EXCEPTION(UnsupportedAluOperation, Runtime) \ EXCEPTION(Overflow, Runtime) \ EXCEPTION(UnalignedJump, Runtime) \ EXCEPTION(UnknownMemoryControl, Runtime) \ EXCEPTION(OutOfMemoryAccess, Runtime) \ EXCEPTION(Sanity, ) \ EXCEPTION(SyscallUnknown, Runtime) #define EXCEPTION(NAME, PARENT) \ class SimulatorException##NAME : public SimulatorException##PARENT { \ public: \ SimulatorException##NAME(QString reason, QString ext, QString file, int line); \ }; SIMULATOR_EXCEPTIONS #undef EXCEPTION // This is helper macro for throwing QtRvSim exceptions #define SIMULATOR_EXCEPTION(TYPE, REASON, EXT) \ (machine::SimulatorException##TYPE(QString(REASON), QString(EXT), QString(__FILE__), __LINE__)) #define SANITY_EXCEPTION(MSG) \ SIMULATOR_EXCEPTION( \ Sanity, "Internal error", \ "An internal error occurred in the simulator. We are sorry for the inconvenience." \ "To help get the simulator fixed ASAP, please report this incident to your " \ "teacher and/or file an issue at\n\n" \ "https://github.com/cvut/qtrvsim/issues.\n\n" \ "Please attach the program you were executing, used configuration of the " \ "simulator, description of steps you have taken and a copy of the following " \ "message:\n\n" #MSG) // Sanity comparison potentially throwing SimulatorExceptionSanity #define SANITY_ASSERT(COND, MSG) \ do { \ if (!(COND)) throw SANITY_EXCEPTION("Sanity check failed (" #COND "):" #MSG); \ } while (false) } // namespace machine #endif // SIMULATOR_EXCEPTION_H qtrvsim-0.9.8/src/machine/symboltable.cpp000066400000000000000000000042501467752164200204700ustar00rootroot00000000000000#include "symboltable.h" #include using namespace machine; SymbolTableEntry::SymbolTableEntry( QString name, SymbolValue value, SymbolSize size, SymbolInfo info, SymbolOther other) : name(std::move(name)) , value(value) , size(size) , info(info) , other(other) {} SymbolTable::SymbolTable(QObject *parent) : QObject(parent) , map_name_to_symbol() , map_value_to_symbol() {} SymbolTable::~SymbolTable() { map_name_to_symbol.clear(); // Does not own data. auto iter = map_value_to_symbol.begin(); while (iter != map_value_to_symbol.end()) { const SymbolTableEntry *p_entry = iter.value(); iter = map_value_to_symbol .erase(iter); // Advances iterator. delete p_entry; } } void SymbolTable::add_symbol( const QString &name, SymbolValue value, uint32_t size, unsigned char info, unsigned char other) { auto *p_entry = new SymbolTableEntry(name, value, size, info, other); map_value_to_symbol.insert(value, p_entry); map_name_to_symbol.insert(name, p_entry); } void SymbolTable::remove_symbol(const QString &name) { auto *p_entry = map_name_to_symbol.take(name); if (p_entry == nullptr) { return; } map_value_to_symbol.remove(p_entry->value, p_entry); delete p_entry; } void SymbolTable::set_symbol( const QString &name, SymbolValue value, uint32_t size, unsigned char info, unsigned char other) { remove_symbol(name); add_symbol(name, value, size, info, other); } // TODO cpp17 - return optional bool SymbolTable::name_to_value(SymbolValue &value, const QString &name) const { auto *p_entry = map_name_to_symbol.value(name); if (p_entry == nullptr) { value = 0; return false; } value = p_entry->value; return true; } // TODO cpp17 - return optional bool SymbolTable::location_to_name(QString &name, SymbolValue value) const { auto *p_entry = map_value_to_symbol.value(value); if (p_entry == nullptr) { name = ""; return false; } name = p_entry->name; return true; } QStringList SymbolTable::names() const { return map_name_to_symbol.keys(); } qtrvsim-0.9.8/src/machine/symboltable.h000066400000000000000000000036711467752164200201430ustar00rootroot00000000000000#ifndef SYMBOLTABLE_H #define SYMBOLTABLE_H #include "utils.h" #include #include #include #include #include namespace machine { using SymbolValue = uint64_t; using SymbolSize = uint32_t; using SymbolInfo = unsigned char; using SymbolOther = unsigned char; struct SymbolTableEntry { SymbolTableEntry( QString name, SymbolValue value, SymbolSize size, SymbolInfo info = 0, SymbolOther other = 0); const QString name; const SymbolValue value; const SymbolSize size; const SymbolInfo info; const SymbolOther other; }; /** * ELF symbol table. * * Used tu jump to symbol and for integrated assembler. * To learn more, about ELF symbol table internal, I recommend this * [link](https://blogs.oracle.com/solaris/inside-elf-symbol-tables-v2). */ class SymbolTable : public QObject { Q_OBJECT public: explicit SymbolTable(QObject *parent = nullptr); ~SymbolTable() override; void add_symbol( const QString &name, SymbolValue value, SymbolSize size, SymbolInfo info = 0, SymbolOther other = 0); void set_symbol( const QString &name, SymbolValue value, SymbolSize size, SymbolInfo info = 0, SymbolOther other = 0); void remove_symbol(const QString &name); QStringList names() const; public slots: bool name_to_value(SymbolValue &value, const QString &name) const; /** * FIXME: This is design is flawed. The table can contain multiple names for * single location as it is multimap. */ bool location_to_name(QString &name, SymbolValue value) const; private: // QString cannot be made const, because it would not fit into QT gui API. QMap map_name_to_symbol; QMultiMap map_value_to_symbol; }; } // namespace machine #endif // SYMBOLTABLE_H qtrvsim-0.9.8/src/machine/tests/000077500000000000000000000000001467752164200166105ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/tests/data/000077500000000000000000000000001467752164200175215ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/tests/data/cache_test_performance_data.h000066400000000000000000001176611467752164200253620ustar00rootroot00000000000000#ifndef CACHE_TEST_PERFORMANCE_DATA_H #define CACHE_TEST_PERFORMANCE_DATA_H #include #include using std::array; using std::tuple; /** * Cache hits amd misses recorded after creation of these test. * Values are invalidated by any change of testcases. * Values were not checked manually, failure of test indicates only a change * not a bug. */ constexpr std::array, 3270> cache_test_performance_data { { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 18, 28 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 35, 2 }, { 27, 3 }, { 25, 3 }, { 45, 3 }, { 26, 3 }, { 29, 3 }, { 48, 3 }, { 21, 3 }, { 27, 4 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 16, 30 }, { 18, 3 }, { 18, 3 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 33, 1 }, { 19, 1 }, { 19, 1 }, { 44, 2 }, { 19, 2 }, { 19, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, } }; #endif // CACHE_TEST_PERFORMANCE_DATA_Hqtrvsim-0.9.8/src/machine/tests/utils/000077500000000000000000000000001467752164200177505ustar00rootroot00000000000000qtrvsim-0.9.8/src/machine/tests/utils/integer_decomposition.h000066400000000000000000000027271467752164200245220ustar00rootroot00000000000000#ifndef INTEGER_DECOMPOSITION_H #define INTEGER_DECOMPOSITION_H #include "common/endian.h" #include #include using namespace machine; using std::array; using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; template constexpr void decompose_int_to_array(array &dst, uint64_t value, Endian endian) { for (size_t i = 0; i < N; ++i) { T val = (T) (value >> (8 * sizeof(T) * i)); if (endian == LITTLE) { dst.at(i) = val; } else { dst.at(N - i - 1) = val; } } } struct IntegerDecomposition { uint64_t u64{}; array u32{}; array u16{}; array u8{}; constexpr IntegerDecomposition() = default; constexpr IntegerDecomposition(uint64_t value, Endian endian) { u64 = value; decompose_int_to_array(u32, value, endian); decompose_int_to_array(u16, value, endian); decompose_int_to_array(u8, value, endian); } constexpr bool operator==(const IntegerDecomposition &rhs) const { return u64 == rhs.u64 && u32 == rhs.u32 && u16 == rhs.u16 && u8 == rhs.u8; } constexpr bool operator!=(const IntegerDecomposition &rhs) const { return !(rhs == *this); } }; Q_DECLARE_METATYPE(IntegerDecomposition) #endif // INTEGER_DECOMPOSITION_H qtrvsim-0.9.8/src/machine/utils.h000066400000000000000000000037621467752164200167670ustar00rootroot00000000000000#ifndef UTILS_H #define UTILS_H #include #include #include #include #include #include #include using std::size_t; #if __GNUC__ >= 7 #define FALLTROUGH __attribute__((fallthrough)); #else #define FALLTROUGH #endif /** * Raw byte in memory * - Intended for raw byte array */ typedef unsigned char byte; inline constexpr uint32_t sign_extend(uint16_t v) { return ((v & 0x8000) ? 0xFFFF0000 : 0) | v; } template void ignore(const T &) {} #define UNIMPLEMENTED throw std::logic_error("Unimplemented"); #define PANIC throw std::logic_error("The program panicked."); #define UNREACHABLE Q_UNREACHABLE(); #define UNUSED(arg) ignore(arg); /** * Annotate pointer ownership. * Smartpointer may be used in the future. */ #define OWNED /** * Test whether given address is aligned to the given type. * * @tparam Address type used to store the address * @tparam T type to check alignment * @param address address to check * @return true if is aligned */ template inline bool is_aligned_generic(Address address) { return static_cast(address) % std::alignment_of::value; } /** * Divide and round up */ template inline constexpr T1 divide_and_ceil(T1 divident, T2 divisor) { return ((divident + divisor - 1) / divisor); } /** * Rounds number `n` down to the multiple of `base`. * (To by used as better macro.) * * @tparam T1 type of n * @tparam T2 type of base */ template inline constexpr T1 round_down_to_multiple(T1 n, T2 base) { return (n / base) * base; } /** * Rounds number `n` up to the multiple of `base`. * (To by used as better macro.) * * @tparam T1 type of n * @tparam T2 type of base */ template inline constexpr T1 round_up_to_multiple(T1 n, T2 base) { return round_down_to_multiple(n + base, base); } #endif // UTILS_H qtrvsim-0.9.8/src/os_emulation/000077500000000000000000000000001467752164200165405ustar00rootroot00000000000000qtrvsim-0.9.8/src/os_emulation/CMakeLists.txt000066400000000000000000000006461467752164200213060ustar00rootroot00000000000000project(os_emulation DESCRIPTION "Simple emulation of a Linux like kernel") set(CMAKE_AUTOMOC ON) set(os_emulation_SOURCES ossyscall.cpp ) set(os_emulation_HEADERS ossyscall.h syscall_nr.h target_errno.h ) add_library(os_emulation STATIC ${os_emulation_SOURCES} ${os_emulation_HEADERS}) target_link_libraries(os_emulation PRIVATE ${QtLib}::Core)qtrvsim-0.9.8/src/os_emulation/ossyscall.cpp000066400000000000000000000652141467752164200212700ustar00rootroot00000000000000#include "ossyscall.h" #include "machine/core.h" #include "machine/utils.h" #include "syscall_nr.h" #include "target_errno.h" #include "posix_polyfill.h" #include #include #include #include #include using namespace machine; using namespace osemu; // The copied from musl-libc #define TARGET_O_CREAT 0100 #define TARGET_O_EXCL 0200 #define TARGET_O_NOCTTY 0400 #define TARGET_O_TRUNC 01000 #define TARGET_O_APPEND 02000 #define TARGET_O_NONBLOCK 04000 #define TARGET_O_DSYNC 010000 #define TARGET_O_SYNC 04010000 #define TARGET_O_RSYNC 04010000 #define TARGET_O_DIRECTORY 0200000 #define TARGET_O_NOFOLLOW 0400000 #define TARGET_O_CLOEXEC 02000000 #define TARGET_O_PATH 010000000 #define TARGET_O_SYNC1 040000 #define TARGET_O_ACCMODE (03 | TARGET_O_PATH) #define TARGET_O_RDONLY 00 #define TARGET_O_WRONLY 01 #define TARGET_O_RDWR 02 #define TARGET_AT_FDCWD -100 static const QMap map_target_o_flags_to_o_flags = { #ifdef O_CREAT { TARGET_O_CREAT, O_CREAT }, #endif #ifdef O_EXCL { TARGET_O_EXCL, O_EXCL }, #endif #ifdef O_NOCTTY { TARGET_O_NOCTTY, O_NOCTTY }, #endif #ifdef O_TRUNC { TARGET_O_TRUNC, O_TRUNC }, #endif #ifdef O_APPEND { TARGET_O_APPEND, O_APPEND }, #endif #ifdef O_NONBLOCK { TARGET_O_NONBLOCK, O_NONBLOCK }, #endif #ifdef O_DSYNC { TARGET_O_DSYNC, O_DSYNC }, #endif #ifdef O_SYNC { TARGET_O_SYNC1, O_SYNC }, #endif #ifdef O_RSYNC { TARGET_O_SYNC1, O_RSYNC }, #endif #ifdef O_DIRECTORY { TARGET_O_DIRECTORY, O_DIRECTORY }, #endif #ifdef O_NOFOLLOW { TARGET_O_NOFOLLOW, O_NOFOLLOW }, #endif #ifdef O_CLOEXEC { TARGET_O_CLOEXEC, O_CLOEXEC }, #endif }; #if defined(S_IRUSR) & defined(S_IWUSR) & defined(S_IRGRP) & defined(S_IWGRP) & defined(S_IROTH) \ & defined(S_IWOTH) #define OPEN_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) #else #define OPEN_MODE 0 #endif // The list copyied from musl-libc static const QMap errno_map = { #ifdef EPERM { EPERM, TARGET_EPERM }, #endif #ifdef ENOENT { ENOENT, TARGET_ENOENT }, #endif #ifdef ESRCH { ESRCH, TARGET_ESRCH }, #endif #ifdef EINTR { EINTR, TARGET_EINTR }, #endif #ifdef EIO { EIO, TARGET_EIO }, #endif #ifdef ENXIO { ENXIO, TARGET_ENXIO }, #endif #ifdef E2BIG { E2BIG, TARGET_E2BIG }, #endif #ifdef ENOEXEC { ENOEXEC, TARGET_ENOEXEC }, #endif #ifdef EBADF { EBADF, TARGET_EBADF }, #endif #ifdef ECHILD { ECHILD, TARGET_ECHILD }, #endif #ifdef EAGAIN { EAGAIN, TARGET_EAGAIN }, #endif #ifdef ENOMEM { ENOMEM, TARGET_ENOMEM }, #endif #ifdef EACCES { EACCES, TARGET_EACCES }, #endif #ifdef EFAULT { EFAULT, TARGET_EFAULT }, #endif #ifdef ENOTBLK { ENOTBLK, TARGET_ENOTBLK }, #endif #ifdef EBUSY { EBUSY, TARGET_EBUSY }, #endif #ifdef EEXIST { EEXIST, TARGET_EEXIST }, #endif #ifdef EXDEV { EXDEV, TARGET_EXDEV }, #endif #ifdef ENODEV { ENODEV, TARGET_ENODEV }, #endif #ifdef ENOTDIR { ENOTDIR, TARGET_ENOTDIR }, #endif #ifdef EISDIR { EISDIR, TARGET_EISDIR }, #endif #ifdef EINVAL { EINVAL, TARGET_EINVAL }, #endif #ifdef ENFILE { ENFILE, TARGET_ENFILE }, #endif #ifdef EMFILE { EMFILE, TARGET_EMFILE }, #endif #ifdef ENOTTY { ENOTTY, TARGET_ENOTTY }, #endif #ifdef ETXTBSY { ETXTBSY, TARGET_ETXTBSY }, #endif #ifdef EFBIG { EFBIG, TARGET_EFBIG }, #endif #ifdef ENOSPC { ENOSPC, TARGET_ENOSPC }, #endif #ifdef ESPIPE { ESPIPE, TARGET_ESPIPE }, #endif #ifdef EROFS { EROFS, TARGET_EROFS }, #endif #ifdef EMLINK { EMLINK, TARGET_EMLINK }, #endif #ifdef EPIPE { EPIPE, TARGET_EPIPE }, #endif #ifdef EDOM { EDOM, TARGET_EDOM }, #endif #ifdef ERANGE { ERANGE, TARGET_ERANGE }, #endif #ifdef ENOMSG { ENOMSG, TARGET_ENOMSG }, #endif #ifdef EIDRM { EIDRM, TARGET_EIDRM }, #endif #ifdef ECHRNG { ECHRNG, TARGET_ECHRNG }, #endif #ifdef EL2NSYNC { EL2NSYNC, TARGET_EL2NSYNC }, #endif #ifdef EL3HLT { EL3HLT, TARGET_EL3HLT }, #endif #ifdef EL3RST { EL3RST, TARGET_EL3RST }, #endif #ifdef ELNRNG { ELNRNG, TARGET_ELNRNG }, #endif #ifdef EUNATCH { EUNATCH, TARGET_EUNATCH }, #endif #ifdef ENOCSI { ENOCSI, TARGET_ENOCSI }, #endif #ifdef EL2HLT { EL2HLT, TARGET_EL2HLT }, #endif #ifdef EDEADLK { EDEADLK, TARGET_EDEADLK }, #endif #ifdef ENOLCK { ENOLCK, TARGET_ENOLCK }, #endif #ifdef EBADE { EBADE, TARGET_EBADE }, #endif #ifdef EBADR { EBADR, TARGET_EBADR }, #endif #ifdef EXFULL { EXFULL, TARGET_EXFULL }, #endif #ifdef ENOANO { ENOANO, TARGET_ENOANO }, #endif #ifdef EBADRQC { EBADRQC, TARGET_EBADRQC }, #endif #ifdef EBADSLT { EBADSLT, TARGET_EBADSLT }, #endif #ifdef EDEADLOCK { EDEADLOCK, TARGET_EDEADLOCK }, #endif #ifdef EBFONT { EBFONT, TARGET_EBFONT }, #endif #ifdef ENOSTR { ENOSTR, TARGET_ENOSTR }, #endif #ifdef ENODATA { ENODATA, TARGET_ENODATA }, #endif #ifdef ETIME { ETIME, TARGET_ETIME }, #endif #ifdef ENOSR { ENOSR, TARGET_ENOSR }, #endif #ifdef ENONET { ENONET, TARGET_ENONET }, #endif #ifdef ENOPKG { ENOPKG, TARGET_ENOPKG }, #endif #ifdef EREMOTE { EREMOTE, TARGET_EREMOTE }, #endif #ifdef ENOLINK { ENOLINK, TARGET_ENOLINK }, #endif #ifdef EADV { EADV, TARGET_EADV }, #endif #ifdef ESRMNT { ESRMNT, TARGET_ESRMNT }, #endif #ifdef ECOMM { ECOMM, TARGET_ECOMM }, #endif #ifdef EPROTO { EPROTO, TARGET_EPROTO }, #endif #ifdef EDOTDOT { EDOTDOT, TARGET_EDOTDOT }, #endif #ifdef EMULTIHOP { EMULTIHOP, TARGET_EMULTIHOP }, #endif #ifdef EBADMSG { EBADMSG, TARGET_EBADMSG }, #endif #ifdef ENAMETOOLONG { ENAMETOOLONG, TARGET_ENAMETOOLONG }, #endif #ifdef EOVERFLOW { EOVERFLOW, TARGET_EOVERFLOW }, #endif #ifdef ENOTUNIQ { ENOTUNIQ, TARGET_ENOTUNIQ }, #endif #ifdef EBADFD { EBADFD, TARGET_EBADFD }, #endif #ifdef EREMCHG { EREMCHG, TARGET_EREMCHG }, #endif #ifdef ELIBACC { ELIBACC, TARGET_ELIBACC }, #endif #ifdef ELIBBAD { ELIBBAD, TARGET_ELIBBAD }, #endif #ifdef ELIBSCN { ELIBSCN, TARGET_ELIBSCN }, #endif #ifdef ELIBMAX { ELIBMAX, TARGET_ELIBMAX }, #endif #ifdef ELIBEXEC { ELIBEXEC, TARGET_ELIBEXEC }, #endif #ifdef EILSEQ { EILSEQ, TARGET_EILSEQ }, #endif #ifdef ENOSYS { ENOSYS, TARGET_ENOSYS }, #endif #ifdef ELOOP { ELOOP, TARGET_ELOOP }, #endif #ifdef ERESTART { ERESTART, TARGET_ERESTART }, #endif #ifdef ESTRPIPE { ESTRPIPE, TARGET_ESTRPIPE }, #endif #ifdef ENOTEMPTY { ENOTEMPTY, TARGET_ENOTEMPTY }, #endif #ifdef EUSERS { EUSERS, TARGET_EUSERS }, #endif #ifdef ENOTSOCK { ENOTSOCK, TARGET_ENOTSOCK }, #endif #ifdef EDESTADDRREQ { EDESTADDRREQ, TARGET_EDESTADDRREQ }, #endif #ifdef EMSGSIZE { EMSGSIZE, TARGET_EMSGSIZE }, #endif #ifdef EPROTOTYPE { EPROTOTYPE, TARGET_EPROTOTYPE }, #endif #ifdef ENOPROTOOPT { ENOPROTOOPT, TARGET_ENOPROTOOPT }, #endif #ifdef EPROTONOSUPPORT { EPROTONOSUPPORT, TARGET_EPROTONOSUPPORT }, #endif #ifdef ESOCKTNOSUPPORT { ESOCKTNOSUPPORT, TARGET_ESOCKTNOSUPPORT }, #endif #ifdef EOPNOTSUPP { EOPNOTSUPP, TARGET_EOPNOTSUPP }, #endif #ifdef ENOTSUP { ENOTSUP, TARGET_ENOTSUP }, #endif #ifdef EPFNOSUPPORT { EPFNOSUPPORT, TARGET_EPFNOSUPPORT }, #endif #ifdef EAFNOSUPPORT { EAFNOSUPPORT, TARGET_EAFNOSUPPORT }, #endif #ifdef EADDRINUSE { EADDRINUSE, TARGET_EADDRINUSE }, #endif #ifdef EADDRNOTAVAIL { EADDRNOTAVAIL, TARGET_EADDRNOTAVAIL }, #endif #ifdef ENETDOWN { ENETDOWN, TARGET_ENETDOWN }, #endif #ifdef ENETUNREACH { ENETUNREACH, TARGET_ENETUNREACH }, #endif #ifdef ENETRESET { ENETRESET, TARGET_ENETRESET }, #endif #ifdef ECONNABORTED { ECONNABORTED, TARGET_ECONNABORTED }, #endif #ifdef ECONNRESET { ECONNRESET, TARGET_ECONNRESET }, #endif #ifdef ENOBUFS { ENOBUFS, TARGET_ENOBUFS }, #endif #ifdef EISCONN { EISCONN, TARGET_EISCONN }, #endif #ifdef ENOTCONN { ENOTCONN, TARGET_ENOTCONN }, #endif #ifdef EUCLEAN { EUCLEAN, TARGET_EUCLEAN }, #endif #ifdef ENOTNAM { ENOTNAM, TARGET_ENOTNAM }, #endif #ifdef ENAVAIL { ENAVAIL, TARGET_ENAVAIL }, #endif #ifdef EISNAM { EISNAM, TARGET_EISNAM }, #endif #ifdef EREMOTEIO { EREMOTEIO, TARGET_EREMOTEIO }, #endif #ifdef ESHUTDOWN { ESHUTDOWN, TARGET_ESHUTDOWN }, #endif #ifdef ETOOMANYREFS { ETOOMANYREFS, TARGET_ETOOMANYREFS }, #endif #ifdef ETIMEDOUT { ETIMEDOUT, TARGET_ETIMEDOUT }, #endif #ifdef ECONNREFUSED { ECONNREFUSED, TARGET_ECONNREFUSED }, #endif #ifdef EHOSTDOWN { EHOSTDOWN, TARGET_EHOSTDOWN }, #endif #ifdef EHOSTUNREACH { EHOSTUNREACH, TARGET_EHOSTUNREACH }, #endif #ifdef EWOULDBLOCK { EWOULDBLOCK, TARGET_EWOULDBLOCK }, #endif #ifdef EALREADY { EALREADY, TARGET_EALREADY }, #endif #ifdef EINPROGRESS { EINPROGRESS, TARGET_EINPROGRESS }, #endif #ifdef ESTALE { ESTALE, TARGET_ESTALE }, #endif #ifdef ECANCELED { ECANCELED, TARGET_ECANCELED }, #endif #ifdef ENOMEDIUM { ENOMEDIUM, TARGET_ENOMEDIUM }, #endif #ifdef EMEDIUMTYPE { EMEDIUMTYPE, TARGET_EMEDIUMTYPE }, #endif #ifdef ENOKEY { ENOKEY, TARGET_ENOKEY }, #endif #ifdef EKEYEXPIRED { EKEYEXPIRED, TARGET_EKEYEXPIRED }, #endif #ifdef EKEYREVOKED { EKEYREVOKED, TARGET_EKEYREVOKED }, #endif #ifdef EKEYREJECTED { EKEYREJECTED, TARGET_EKEYREJECTED }, #endif #ifdef EOWNERDEAD { EOWNERDEAD, TARGET_EOWNERDEAD }, #endif #ifdef ENOTRECOVERABLE { ENOTRECOVERABLE, TARGET_ENOTRECOVERABLE }, #endif #ifdef ERFKILL { ERFKILL, TARGET_ERFKILL }, #endif #ifdef EHWPOISON { EHWPOISON, TARGET_EHWPOISON }, #endif #ifdef EDQUOT { EDQUOT, TARGET_EDQUOT }, #endif }; uint32_t result_errno_if_error(uint32_t result) { if (result < (uint32_t)-4096) return result; result = (uint32_t)-errno_map.value(errno); if (!result) result = (uint32_t)-1; return result; } int status_from_result(uint32_t result) { if (result < (uint32_t)-4096) return 0; else return -result; } typedef int (OsSyscallExceptionHandler::*syscall_handler_t)( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6); struct mips_syscall_desc_t { const char *name; unsigned int args; syscall_handler_t handler; }; struct rv_syscall_desc_t { unsigned int args; syscall_handler_t handler; const char *name; }; static const rv_syscall_desc_t rv_syscall_args[] = { #include "syscallent.h" }; const unsigned rv_syscall_count = sizeof(rv_syscall_args) / sizeof(*rv_syscall_args); OsSyscallExceptionHandler::OsSyscallExceptionHandler( bool known_syscall_stop, bool unknown_syscall_stop, QString fs_root) : fd_mapping(3, FD_TERMINAL) { brk_limit = 0; anonymous_base = 0x60000000; anonymous_last = anonymous_base; this->known_syscall_stop = known_syscall_stop; this->unknown_syscall_stop = unknown_syscall_stop; this->fs_root = fs_root; } bool OsSyscallExceptionHandler::handle_exception( Core *core, Registers *regs, ExceptionCause excause, Address inst_addr, Address next_addr, Address jump_branch_pc, Address mem_ref_addr) { uint64_t syscall_num = regs->read_gp(17).as_u64(); const rv_syscall_desc_t *sdesc; RegisterValue a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0; uint64_t result; int status; FrontendMemory *mem_program = core->get_mem_program(); (void)mem_program; #if 1 printf( "Exception cause %d instruction PC 0x%08" PRIx64 " next PC 0x%08" PRIx64 " jump branch " "PC 0x%08" PRIx64 "registers PC 0x%08" PRIx64 " mem ref 0x%08" PRIx64 "\n", excause, inst_addr.get_raw(), next_addr.get_raw(), jump_branch_pc.get_raw(), regs->read_pc().get_raw(), mem_ref_addr.get_raw()); #else (void)excause; (void)inst_addr; (void)next_addr; (void)mem_ref_addr; (void)regs; (void)jump_branch_pc; #endif // handle Linux syscalls if (syscall_num < rv_syscall_count) { sdesc = &rv_syscall_args[syscall_num]; } else { throw SIMULATOR_EXCEPTION( SyscallUnknown, "System call number unknown ", QString::number(syscall_num)); } // sdesc is populated by syscall description matching syscall number. // if such syscall doesn't exist, this part is unreachable, because // of the above exception. // read out values from registers. Not sure I like this... // Maybe the handling functions themselves should do this on their own. a1 = regs->read_gp(10); a2 = regs->read_gp(11); a3 = regs->read_gp(12); a4 = regs->read_gp(13); a5 = regs->read_gp(14); a6 = regs->read_gp(15); #if 1 printf( "Syscall %s number %" PRId64 "/0x%" PRIx64 " a1=%" PRIu64 " a2=%" PRIu64 " a3=%" PRIu64 " a4=%" PRIu64 "\n", sdesc->name, syscall_num, syscall_num, a1.as_u64(), a2.as_u64(), a3.as_u64(), a4.as_u64()); #endif status = (this->*sdesc->handler)( result, core, syscall_num, a1.as_u64(), a2.as_u64(), a3.as_u64(), a4.as_u64(), a5.as_u64(), a6.as_u64()); if (known_syscall_stop) { emit core->stop_on_exception_reached(); } if (status < 0) { regs->write_gp(10, status); } else { regs->write_gp(10, result); } return true; } int32_t OsSyscallExceptionHandler::write_mem( machine::FrontendMemory *mem, Address addr, const QVector &data, uint32_t count) { if ((uint32_t)data.size() < count) count = data.size(); for (uint32_t i = 0; i < count; i++) { mem->write_u8(addr, data[i]); addr += 1; } return count; } int32_t OsSyscallExceptionHandler::read_mem( machine::FrontendMemory *mem, Address addr, QVector &data, uint32_t count) { data.resize(count); for (uint32_t i = 0; i < count; i++) { data[i] = mem->read_u8(addr); addr += 1; } return count; } int32_t OsSyscallExceptionHandler::write_io(int fd, const QVector &data, uint32_t count) { if ((uint32_t)data.size() < count) count = data.size(); if (fd == FD_UNUSED) { return -1; } else if (fd == FD_TERMINAL) { for (uint32_t i = 0; i < count; i++) emit char_written(fd, data[i]); } else { count = write(fd, data.data(), count); } return result_errno_if_error(count); } int32_t OsSyscallExceptionHandler::read_io( int fd, QVector &data, uint32_t count, bool add_nl_at_eof) { data.resize(count); if ((uint32_t)data.size() < count) count = data.size(); if (fd == FD_UNUSED) { return -1; } else if (fd == FD_TERMINAL) { for (uint32_t i = 0; i < count; i++) { unsigned int byte; bool available = false; emit rx_byte_pool(fd, byte, available); if (!available) { // add final newline if there are no more data if (add_nl_at_eof) data[i] = '\n'; count = i + 1; break; } data[i] = byte; } } else { count = read(fd, data.data(), count); } if ((int32_t)count >= 0) data.resize(count); return result_errno_if_error(count); } int OsSyscallExceptionHandler::allocate_fd(int val) { int i; for (i = 0; i < fd_mapping.size(); i++) { if (fd_mapping[i] == FD_UNUSED) { fd_mapping[i] = val; return i; } } i = fd_mapping.size(); fd_mapping.resize(i + 1); fd_mapping[i] = val; return i; } int OsSyscallExceptionHandler::file_open(QString fname, int flags, int mode) { int targetfd, fd; int hostflags = 0; (void)mode; for (auto i = map_target_o_flags_to_o_flags.begin(); i != map_target_o_flags_to_o_flags.end(); i++) if (flags & i.key()) hostflags |= i.value(); switch (flags & TARGET_O_ACCMODE) { case TARGET_O_RDONLY: hostflags |= O_RDONLY; break; case TARGET_O_WRONLY: hostflags |= O_WRONLY; break; case TARGET_O_RDWR: hostflags |= O_RDWR; break; } if (fs_root.size() == 0) { return allocate_fd(FD_TERMINAL); } fname = filepath_to_host(fname); fd = open(fname.toLatin1().data(), hostflags, OPEN_MODE); if (fd >= 0) { targetfd = allocate_fd(fd); } else { targetfd = result_errno_if_error(fd); } return targetfd; } int OsSyscallExceptionHandler::targetfd_to_fd(int targetfd) { if (targetfd < 0) return FD_INVALID; if (targetfd >= fd_mapping.size()) return FD_INVALID; return fd_mapping.at(targetfd); } void OsSyscallExceptionHandler::close_fd(int targetfd) { if (targetfd <= fd_mapping.size()) fd_mapping[targetfd] = FD_UNUSED; } QString OsSyscallExceptionHandler::filepath_to_host(QString path) { int pos = 0; int prev; while (true) { if (((path.size() - pos == 2) && (path.mid(pos, -1) == "..")) || ((path.size() - pos > 2) && (path.mid(pos, 3) == "../"))) { if (pos == 0) { prev = 0; } else { if (pos == 1) prev = 0; else prev = path.lastIndexOf('/', pos - 2) + 1; } path.remove(prev, pos + 3 - prev); pos = prev; continue; } pos = path.indexOf('/', pos); if (pos == -1) break; pos += 1; } if ((path.size() >= 1) && path.at(0) == '/') path = fs_root + path; else path = fs_root + '/' + path; return path; } int OsSyscallExceptionHandler::syscall_default_handler( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { const rv_syscall_desc_t *sdesc = &rv_syscall_args[syscall_num]; #if 1 printf( "Unimplemented syscall %s number %" PRId64 "/0x%" PRIx64 " a1 %" PRId64 " a2 %" PRId64 " a3 %" PRId64 " a4 %" PRId64 "\n", sdesc->name, syscall_num, syscall_num, a1, a2, a3, a4); #endif (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; if (unknown_syscall_stop) emit core->stop_on_exception_reached(); return TARGET_ENOSYS; } // void exit(int status); int OsSyscallExceptionHandler::do_sys_exit( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int status = a1; printf("sys_exit status %d\n", status); emit core->stop_on_exception_reached(); return 0; } // ssize_t writev(int fd, const struct iovec *iov, int iovcnt); int OsSyscallExceptionHandler::do_sys_writev( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; Address iov = Address(core->get_xlen_from_reg(a2)); int iovcnt = a3; FrontendMemory *mem = core->get_mem_data(); int32_t count; QVector data; printf("sys_writev to fd %d\n", fd); fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } while (iovcnt-- > 0) { Address iov_base = Address(mem->read_u32(iov)); uint32_t iov_len = mem->read_u32(iov + 4); iov += 8; read_mem(mem, iov_base, data, iov_len); count = write_io(fd, data, iov_len); if (count >= 0) { result += count; } else { if (result == 0) result = count; } if (count < (int32_t)iov_len) break; } return status_from_result(result); } // ssize_t write(int fd, const void *buf, size_t count); int OsSyscallExceptionHandler::do_sys_write( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; Address buf = Address(core->get_xlen_from_reg(a2)); int size = core->get_xlen_from_reg(a3); FrontendMemory *mem = core->get_mem_data(); int32_t count; QVector data; printf("sys_write to fd %d\n", fd); fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } read_mem(mem, buf, data, size); count = write_io(fd, data, size); result = count; return status_from_result(result); } // ssize_t readv(int fd, const struct iovec *iov, int iovcnt); int OsSyscallExceptionHandler::do_sys_readv( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; Address iov = Address(core->get_xlen_from_reg(a2)); int iovcnt = a3; FrontendMemory *mem = core->get_mem_data(); int32_t count; QVector data; printf("sys_readv to fd %d\n", fd); fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } while (iovcnt-- > 0) { Address iov_base = Address(mem->read_u32(iov)); uint32_t iov_len = mem->read_u32(iov + 4); iov += 8; count = read_io(fd, data, iov_len, true); if (count >= 0) { write_mem(mem, iov_base, data, count); result += count; } else { if (result == 0) result = count; } if (count < (int32_t)iov_len) break; } return status_from_result(result); } // ssize_t read(int fd, void *buf, size_t count); int OsSyscallExceptionHandler::do_sys_read( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; Address buf = Address(core->get_xlen_from_reg(a2)); int size = core->get_xlen_from_reg(a3); FrontendMemory *mem = core->get_mem_data(); int32_t count; QVector data; printf("sys_read to fd %d\n", fd); fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } result = 0; count = read_io(fd, data, size, true); if (count >= 0) { write_mem(mem, buf, data, size); } result = count; return status_from_result(result); } // int openat(int fd, const char *pathname, int flags, mode_t mode); int OsSyscallExceptionHandler::do_sys_openat( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; if (int64_t(a1) != TARGET_AT_FDCWD) { printf("Unimplemented openat argument a1 %" PRId64, a1); if (unknown_syscall_stop) { emit core->stop_on_exception_reached(); } return TARGET_ENOSYS; } Address pathname_ptr = Address(core->get_xlen_from_reg(a2)); int flags = a3; int mode = a4; uint32_t ch; FrontendMemory *mem = core->get_mem_data(); printf("sys_open filename\n"); QString fname; while (true) { ch = mem->read_u8(pathname_ptr); pathname_ptr += 1; if (ch == 0) break; fname.append(QChar(ch)); } result = file_open(fname, flags, mode); return status_from_result(result); } // int close(int fd); int OsSyscallExceptionHandler::do_sys_close( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; printf("sys_close fd %d\n", fd); int targetfd = fd; fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } close(fd); close_fd(targetfd); return status_from_result(result); } // int ftruncate(int fd, off_t length); int OsSyscallExceptionHandler::do_sys_ftruncate( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; int fd = a1; uint64_t length = core->get_xlen_from_reg(a2); if (core->get_xlen() == Xlen::_32) { length |= core->get_xlen_from_reg(a3) << 32; } printf("sys_ftruncate fd %d\n", fd); fd = targetfd_to_fd(fd); if (fd == FD_INVALID) { result = -TARGET_EINVAL; return 0; } result = result_errno_if_error(ftruncate(fd, length)); return status_from_result(result); } // int or void * brk(void *addr); int OsSyscallExceptionHandler::do_sys_brk( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; result = 0; uint32_t new_limit = a1; brk_limit = new_limit; result = brk_limit; return 0; } // void *mmap(void *addr, size_t length, int prot, // int flags, int fd, off_t pgoffset); int OsSyscallExceptionHandler::do_sys_mmap( uint64_t &result, Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { (void)core; (void)syscall_num; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a6; // TODO: actually mmmap file, now that we can. result = 0; uint32_t addr = a1; uint32_t lenght = a2; uint32_t prot = a3; uint32_t flags = a4; uint32_t fd = a5; uint64_t offset = a6; printf( "sys_mmap addr = 0x%08lx lenght= 0x%08lx prot = 0x%08lx flags = " "0x%08lx fd = %d offset = 0x%08llx\n", (unsigned long)addr, (unsigned long)lenght, (unsigned long)prot, (unsigned long)flags, (int)fd, (unsigned long long)offset); result = anonymous_last; anonymous_last += lenght; return 0; } qtrvsim-0.9.8/src/os_emulation/ossyscall.h000066400000000000000000000064611467752164200207340ustar00rootroot00000000000000#ifndef OSSYCALL_H #define OSSYCALL_H #include "machine/core.h" #include "machine/instruction.h" #include "machine/machineconfig.h" #include "machine/memory/backend/memory.h" #include "machine/memory/frontend_memory.h" #include "machine/registers.h" #include "machine/simulator_exception.h" #include #include #include namespace osemu { #define OSSYCALL_HANDLER_DECLARE(name) \ int name( \ uint64_t &result, machine::Core *core, uint64_t syscall_num, uint64_t a1, uint64_t a2, \ uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) class OsSyscallExceptionHandler : public machine::ExceptionHandler { Q_OBJECT public: explicit OsSyscallExceptionHandler( bool known_syscall_stop = false, bool unknown_syscall_stop = false, QString fs_root = ""); bool handle_exception( machine::Core *core, machine::Registers *regs, machine::ExceptionCause excause, machine::Address inst_addr, machine::Address next_addr, machine::Address jump_branch_pc, machine::Address mem_ref_addr) override; OSSYCALL_HANDLER_DECLARE(syscall_default_handler); OSSYCALL_HANDLER_DECLARE(do_sys_exit); OSSYCALL_HANDLER_DECLARE(do_sys_set_thread_area); OSSYCALL_HANDLER_DECLARE(do_sys_writev); OSSYCALL_HANDLER_DECLARE(do_sys_write); OSSYCALL_HANDLER_DECLARE(do_sys_readv); OSSYCALL_HANDLER_DECLARE(do_sys_read); OSSYCALL_HANDLER_DECLARE(do_sys_openat); OSSYCALL_HANDLER_DECLARE(do_sys_close); OSSYCALL_HANDLER_DECLARE(do_sys_ftruncate); OSSYCALL_HANDLER_DECLARE(do_sys_brk); OSSYCALL_HANDLER_DECLARE(do_sys_mmap); OSSYCALL_HANDLER_DECLARE(do_spim_print_integer); OSSYCALL_HANDLER_DECLARE(do_spim_print_string); OSSYCALL_HANDLER_DECLARE(do_spim_read_string); OSSYCALL_HANDLER_DECLARE(do_spim_sbrk); OSSYCALL_HANDLER_DECLARE(do_spim_exit); OSSYCALL_HANDLER_DECLARE(do_spim_print_character); OSSYCALL_HANDLER_DECLARE(do_spim_read_character); signals: void char_written(int fd, unsigned int val); void rx_byte_pool(int fd, unsigned int &data, bool &available); private: enum FdMapping { FD_UNUSED = -1, FD_INVALID = -1, FD_TERMINAL = -2, }; int32_t write_mem( machine::FrontendMemory *mem, machine::Address addr, const QVector &data, uint32_t count); int32_t read_mem( machine::FrontendMemory *mem, machine::Address addr, QVector &data, uint32_t count); int32_t write_io(int fd, const QVector &data, uint32_t count); int32_t read_io(int fd, QVector &data, uint32_t count, bool add_nl_at_eof = false); int allocate_fd(int val = FD_UNUSED); int file_open(QString fname, int flags, int mode); int targetfd_to_fd(int targetfd); void close_fd(int targetfd); QString filepath_to_host(QString path); QVector fd_mapping; uint32_t brk_limit; uint32_t anonymous_base; uint32_t anonymous_last; bool known_syscall_stop; bool unknown_syscall_stop; QString fs_root; }; #undef OSSYCALL_HANDLER_DECLARE } // namespace osemu #endif // OSSYCALL_H qtrvsim-0.9.8/src/os_emulation/posix_polyfill.h000066400000000000000000000006631467752164200217720ustar00rootroot00000000000000#ifndef POSIX_POLYFILL_H #define POSIX_POLYFILL_H #ifndef _WIN32 // POSIX already provides these functions, just include unistd #include #else // wrap the "Low-Level I/O API" provided by Microsoft CRT, which exposes // a POSIX-like wrapper over Win32 #include #define open _open #define close _close #define read _read #define write _write #define ftruncate _chsize_s #endif // _WIN32 #endif // POSIX_POLYFILL_H qtrvsim-0.9.8/src/os_emulation/syscall_nr.h000066400000000000000000000453641467752164200210760ustar00rootroot00000000000000#ifndef SYSCALL_NR_H #define SYSCALL_NR_H /* * Linux o32 style syscalls are in the range from 4000 to 4999. */ #define TARGET_NR_Linux 4000 #define TARGET_NR_syscall (TARGET_NR_Linux + 0) #define TARGET_NR_exit (TARGET_NR_Linux + 1) #define TARGET_NR_fork (TARGET_NR_Linux + 2) #define TARGET_NR_read (TARGET_NR_Linux + 3) #define TARGET_NR_write (TARGET_NR_Linux + 4) #define TARGET_NR_open (TARGET_NR_Linux + 5) #define TARGET_NR_close (TARGET_NR_Linux + 6) #define TARGET_NR_waitpid (TARGET_NR_Linux + 7) #define TARGET_NR_creat (TARGET_NR_Linux + 8) #define TARGET_NR_link (TARGET_NR_Linux + 9) #define TARGET_NR_unlink (TARGET_NR_Linux + 10) #define TARGET_NR_execve (TARGET_NR_Linux + 11) #define TARGET_NR_chdir (TARGET_NR_Linux + 12) #define TARGET_NR_time (TARGET_NR_Linux + 13) #define TARGET_NR_mknod (TARGET_NR_Linux + 14) #define TARGET_NR_chmod (TARGET_NR_Linux + 15) #define TARGET_NR_lchown (TARGET_NR_Linux + 16) #define TARGET_NR_break (TARGET_NR_Linux + 17) #define TARGET_NR_unused18 (TARGET_NR_Linux + 18) #define TARGET_NR_lseek (TARGET_NR_Linux + 19) #define TARGET_NR_getpid (TARGET_NR_Linux + 20) #define TARGET_NR_mount (TARGET_NR_Linux + 21) #define TARGET_NR_umount (TARGET_NR_Linux + 22) #define TARGET_NR_setuid (TARGET_NR_Linux + 23) #define TARGET_NR_getuid (TARGET_NR_Linux + 24) #define TARGET_NR_stime (TARGET_NR_Linux + 25) #define TARGET_NR_ptrace (TARGET_NR_Linux + 26) #define TARGET_NR_alarm (TARGET_NR_Linux + 27) #define TARGET_NR_unused28 (TARGET_NR_Linux + 28) #define TARGET_NR_pause (TARGET_NR_Linux + 29) #define TARGET_NR_utime (TARGET_NR_Linux + 30) #define TARGET_NR_stty (TARGET_NR_Linux + 31) #define TARGET_NR_gtty (TARGET_NR_Linux + 32) #define TARGET_NR_access (TARGET_NR_Linux + 33) #define TARGET_NR_nice (TARGET_NR_Linux + 34) #define TARGET_NR_ftime (TARGET_NR_Linux + 35) #define TARGET_NR_sync (TARGET_NR_Linux + 36) #define TARGET_NR_kill (TARGET_NR_Linux + 37) #define TARGET_NR_rename (TARGET_NR_Linux + 38) #define TARGET_NR_mkdir (TARGET_NR_Linux + 39) #define TARGET_NR_rmdir (TARGET_NR_Linux + 40) #define TARGET_NR_dup (TARGET_NR_Linux + 41) #define TARGET_NR_pipe (TARGET_NR_Linux + 42) #define TARGET_NR_times (TARGET_NR_Linux + 43) #define TARGET_NR_prof (TARGET_NR_Linux + 44) #define TARGET_NR_brk (TARGET_NR_Linux + 45) #define TARGET_NR_setgid (TARGET_NR_Linux + 46) #define TARGET_NR_getgid (TARGET_NR_Linux + 47) #define TARGET_NR_signal (TARGET_NR_Linux + 48) #define TARGET_NR_geteuid (TARGET_NR_Linux + 49) #define TARGET_NR_getegid (TARGET_NR_Linux + 50) #define TARGET_NR_acct (TARGET_NR_Linux + 51) #define TARGET_NR_umount2 (TARGET_NR_Linux + 52) #define TARGET_NR_lock (TARGET_NR_Linux + 53) #define TARGET_NR_ioctl (TARGET_NR_Linux + 54) #define TARGET_NR_fcntl (TARGET_NR_Linux + 55) #define TARGET_NR_mpx (TARGET_NR_Linux + 56) #define TARGET_NR_setpgid (TARGET_NR_Linux + 57) #define TARGET_NR_ulimit (TARGET_NR_Linux + 58) #define TARGET_NR_unused59 (TARGET_NR_Linux + 59) #define TARGET_NR_umask (TARGET_NR_Linux + 60) #define TARGET_NR_chroot (TARGET_NR_Linux + 61) #define TARGET_NR_ustat (TARGET_NR_Linux + 62) #define TARGET_NR_dup2 (TARGET_NR_Linux + 63) #define TARGET_NR_getppid (TARGET_NR_Linux + 64) #define TARGET_NR_getpgrp (TARGET_NR_Linux + 65) #define TARGET_NR_setsid (TARGET_NR_Linux + 66) #define TARGET_NR_sigaction (TARGET_NR_Linux + 67) #define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) #define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) #define TARGET_NR_setreuid (TARGET_NR_Linux + 70) #define TARGET_NR_setregid (TARGET_NR_Linux + 71) #define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) #define TARGET_NR_sigpending (TARGET_NR_Linux + 73) #define TARGET_NR_sethostname (TARGET_NR_Linux + 74) #define TARGET_NR_setrlimit (TARGET_NR_Linux + 75) #define TARGET_NR_getrlimit (TARGET_NR_Linux + 76) #define TARGET_NR_getrusage (TARGET_NR_Linux + 77) #define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78) #define TARGET_NR_settimeofday (TARGET_NR_Linux + 79) #define TARGET_NR_getgroups (TARGET_NR_Linux + 80) #define TARGET_NR_setgroups (TARGET_NR_Linux + 81) #define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) #define TARGET_NR_symlink (TARGET_NR_Linux + 83) #define TARGET_NR_unused84 (TARGET_NR_Linux + 84) #define TARGET_NR_readlink (TARGET_NR_Linux + 85) #define TARGET_NR_uselib (TARGET_NR_Linux + 86) #define TARGET_NR_swapon (TARGET_NR_Linux + 87) #define TARGET_NR_reboot (TARGET_NR_Linux + 88) #define TARGET_NR_readdir (TARGET_NR_Linux + 89) #define TARGET_NR_mmap (TARGET_NR_Linux + 90) #define TARGET_NR_munmap (TARGET_NR_Linux + 91) #define TARGET_NR_truncate (TARGET_NR_Linux + 92) #define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) #define TARGET_NR_fchmod (TARGET_NR_Linux + 94) #define TARGET_NR_fchown (TARGET_NR_Linux + 95) #define TARGET_NR_getpriority (TARGET_NR_Linux + 96) #define TARGET_NR_setpriority (TARGET_NR_Linux + 97) #define TARGET_NR_profil (TARGET_NR_Linux + 98) #define TARGET_NR_statfs (TARGET_NR_Linux + 99) #define TARGET_NR_fstatfs (TARGET_NR_Linux + 100) #define TARGET_NR_ioperm (TARGET_NR_Linux + 101) #define TARGET_NR_socketcall (TARGET_NR_Linux + 102) #define TARGET_NR_syslog (TARGET_NR_Linux + 103) #define TARGET_NR_setitimer (TARGET_NR_Linux + 104) #define TARGET_NR_getitimer (TARGET_NR_Linux + 105) #define TARGET_NR_stat (TARGET_NR_Linux + 106) #define TARGET_NR_lstat (TARGET_NR_Linux + 107) #define TARGET_NR_fstat (TARGET_NR_Linux + 108) #define TARGET_NR_unused109 (TARGET_NR_Linux + 109) #define TARGET_NR_iopl (TARGET_NR_Linux + 110) #define TARGET_NR_vhangup (TARGET_NR_Linux + 111) #define TARGET_NR_idle (TARGET_NR_Linux + 112) #define TARGET_NR_vm86 (TARGET_NR_Linux + 113) #define TARGET_NR_wait4 (TARGET_NR_Linux + 114) #define TARGET_NR_swapoff (TARGET_NR_Linux + 115) #define TARGET_NR_sysinfo (TARGET_NR_Linux + 116) #define TARGET_NR_ipc (TARGET_NR_Linux + 117) #define TARGET_NR_fsync (TARGET_NR_Linux + 118) #define TARGET_NR_sigreturn (TARGET_NR_Linux + 119) #define TARGET_NR_clone (TARGET_NR_Linux + 120) #define TARGET_NR_setdomainname (TARGET_NR_Linux + 121) #define TARGET_NR_uname (TARGET_NR_Linux + 122) #define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123) #define TARGET_NR_adjtimex (TARGET_NR_Linux + 124) #define TARGET_NR_mprotect (TARGET_NR_Linux + 125) #define TARGET_NR_sigprocmask (TARGET_NR_Linux + 126) #define TARGET_NR_create_module (TARGET_NR_Linux + 127) #define TARGET_NR_init_module (TARGET_NR_Linux + 128) #define TARGET_NR_delete_module (TARGET_NR_Linux + 129) #define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130) #define TARGET_NR_quotactl (TARGET_NR_Linux + 131) #define TARGET_NR_getpgid (TARGET_NR_Linux + 132) #define TARGET_NR_fchdir (TARGET_NR_Linux + 133) #define TARGET_NR_bdflush (TARGET_NR_Linux + 134) #define TARGET_NR_sysfs (TARGET_NR_Linux + 135) #define TARGET_NR_personality (TARGET_NR_Linux + 136) #define TARGET_NR_afs_syscall \ (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */ #define TARGET_NR_setfsuid (TARGET_NR_Linux + 138) #define TARGET_NR_setfsgid (TARGET_NR_Linux + 139) #define TARGET_NR__llseek (TARGET_NR_Linux + 140) #define TARGET_NR_getdents (TARGET_NR_Linux + 141) #define TARGET_NR__newselect (TARGET_NR_Linux + 142) #define TARGET_NR_flock (TARGET_NR_Linux + 143) #define TARGET_NR_msync (TARGET_NR_Linux + 144) #define TARGET_NR_readv (TARGET_NR_Linux + 145) #define TARGET_NR_writev (TARGET_NR_Linux + 146) #define TARGET_NR_cacheflush (TARGET_NR_Linux + 147) #define TARGET_NR_cachectl (TARGET_NR_Linux + 148) #define TARGET_NR_sysmips (TARGET_NR_Linux + 149) #define TARGET_NR_unused150 (TARGET_NR_Linux + 150) #define TARGET_NR_getsid (TARGET_NR_Linux + 151) #define TARGET_NR_fdatasync (TARGET_NR_Linux + 152) #define TARGET_NR__sysctl (TARGET_NR_Linux + 153) #define TARGET_NR_mlock (TARGET_NR_Linux + 154) #define TARGET_NR_munlock (TARGET_NR_Linux + 155) #define TARGET_NR_mlockall (TARGET_NR_Linux + 156) #define TARGET_NR_munlockall (TARGET_NR_Linux + 157) #define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158) #define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159) #define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160) #define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161) #define TARGET_NR_sched_yield (TARGET_NR_Linux + 162) #define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 163) #define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 164) #define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 165) #define TARGET_NR_nanosleep (TARGET_NR_Linux + 166) #define TARGET_NR_mremap (TARGET_NR_Linux + 167) #define TARGET_NR_accept (TARGET_NR_Linux + 168) #define TARGET_NR_bind (TARGET_NR_Linux + 169) #define TARGET_NR_connect (TARGET_NR_Linux + 170) #define TARGET_NR_getpeername (TARGET_NR_Linux + 171) #define TARGET_NR_getsockname (TARGET_NR_Linux + 172) #define TARGET_NR_getsockopt (TARGET_NR_Linux + 173) #define TARGET_NR_listen (TARGET_NR_Linux + 174) #define TARGET_NR_recv (TARGET_NR_Linux + 175) #define TARGET_NR_recvfrom (TARGET_NR_Linux + 176) #define TARGET_NR_recvmsg (TARGET_NR_Linux + 177) #define TARGET_NR_send (TARGET_NR_Linux + 178) #define TARGET_NR_sendmsg (TARGET_NR_Linux + 179) #define TARGET_NR_sendto (TARGET_NR_Linux + 180) #define TARGET_NR_setsockopt (TARGET_NR_Linux + 181) #define TARGET_NR_shutdown (TARGET_NR_Linux + 182) #define TARGET_NR_socket (TARGET_NR_Linux + 183) #define TARGET_NR_socketpair (TARGET_NR_Linux + 184) #define TARGET_NR_setresuid (TARGET_NR_Linux + 185) #define TARGET_NR_getresuid (TARGET_NR_Linux + 186) #define TARGET_NR_query_module (TARGET_NR_Linux + 187) #define TARGET_NR_poll (TARGET_NR_Linux + 188) #define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) #define TARGET_NR_setresgid (TARGET_NR_Linux + 190) #define TARGET_NR_getresgid (TARGET_NR_Linux + 191) #define TARGET_NR_prctl (TARGET_NR_Linux + 192) #define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193) #define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194) #define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195) #define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 196) #define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197) #define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198) #define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199) #define TARGET_NR_pread64 (TARGET_NR_Linux + 200) #define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) #define TARGET_NR_chown (TARGET_NR_Linux + 202) #define TARGET_NR_getcwd (TARGET_NR_Linux + 203) #define TARGET_NR_capget (TARGET_NR_Linux + 204) #define TARGET_NR_capset (TARGET_NR_Linux + 205) #define TARGET_NR_sigaltstack (TARGET_NR_Linux + 206) #define TARGET_NR_sendfile (TARGET_NR_Linux + 207) #define TARGET_NR_getpmsg (TARGET_NR_Linux + 208) #define TARGET_NR_putpmsg (TARGET_NR_Linux + 209) #define TARGET_NR_mmap2 (TARGET_NR_Linux + 210) #define TARGET_NR_truncate64 (TARGET_NR_Linux + 211) #define TARGET_NR_ftruncate64 (TARGET_NR_Linux + 212) #define TARGET_NR_stat64 (TARGET_NR_Linux + 213) #define TARGET_NR_lstat64 (TARGET_NR_Linux + 214) #define TARGET_NR_fstat64 (TARGET_NR_Linux + 215) #define TARGET_NR_pivot_root (TARGET_NR_Linux + 216) #define TARGET_NR_mincore (TARGET_NR_Linux + 217) #define TARGET_NR_madvise (TARGET_NR_Linux + 218) #define TARGET_NR_getdents64 (TARGET_NR_Linux + 219) #define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220) #define TARGET_NR_reserved221 (TARGET_NR_Linux + 221) #define TARGET_NR_gettid (TARGET_NR_Linux + 222) #define TARGET_NR_readahead (TARGET_NR_Linux + 223) #define TARGET_NR_setxattr (TARGET_NR_Linux + 224) #define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225) #define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226) #define TARGET_NR_getxattr (TARGET_NR_Linux + 227) #define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228) #define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229) #define TARGET_NR_listxattr (TARGET_NR_Linux + 230) #define TARGET_NR_llistxattr (TARGET_NR_Linux + 231) #define TARGET_NR_flistxattr (TARGET_NR_Linux + 232) #define TARGET_NR_removexattr (TARGET_NR_Linux + 233) #define TARGET_NR_lremovexattr (TARGET_NR_Linux + 234) #define TARGET_NR_fremovexattr (TARGET_NR_Linux + 235) #define TARGET_NR_tkill (TARGET_NR_Linux + 236) #define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237) #define TARGET_NR_futex (TARGET_NR_Linux + 238) #define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239) #define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240) #define TARGET_NR_io_setup (TARGET_NR_Linux + 241) #define TARGET_NR_io_destroy (TARGET_NR_Linux + 242) #define TARGET_NR_io_getevents (TARGET_NR_Linux + 243) #define TARGET_NR_io_submit (TARGET_NR_Linux + 244) #define TARGET_NR_io_cancel (TARGET_NR_Linux + 245) #define TARGET_NR_exit_group (TARGET_NR_Linux + 246) #define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247) #define TARGET_NR_epoll_create (TARGET_NR_Linux + 248) #define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249) #define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250) #define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251) #define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252) #define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253) #define TARGET_NR_fadvise64_64 (TARGET_NR_Linux + 254) #define TARGET_NR_statfs64 (TARGET_NR_Linux + 255) #define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256) #define TARGET_NR_timer_create (TARGET_NR_Linux + 257) #define TARGET_NR_timer_settime (TARGET_NR_Linux + 258) #define TARGET_NR_timer_gettime (TARGET_NR_Linux + 259) #define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260) #define TARGET_NR_timer_delete (TARGET_NR_Linux + 261) #define TARGET_NR_clock_settime (TARGET_NR_Linux + 262) #define TARGET_NR_clock_gettime (TARGET_NR_Linux + 263) #define TARGET_NR_clock_getres (TARGET_NR_Linux + 264) #define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265) #define TARGET_NR_tgkill (TARGET_NR_Linux + 266) #define TARGET_NR_utimes (TARGET_NR_Linux + 267) #define TARGET_NR_mbind (TARGET_NR_Linux + 268) #define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 269) #define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 270) #define TARGET_NR_mq_open (TARGET_NR_Linux + 271) #define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272) #define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 273) #define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274) #define TARGET_NR_mq_notify (TARGET_NR_Linux + 275) #define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 276) #define TARGET_NR_vserver (TARGET_NR_Linux + 277) #define TARGET_NR_waitid (TARGET_NR_Linux + 278) /* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */ #define TARGET_NR_add_key (TARGET_NR_Linux + 280) #define TARGET_NR_request_key (TARGET_NR_Linux + 281) #define TARGET_NR_keyctl (TARGET_NR_Linux + 282) #define TARGET_NR_set_thread_area (TARGET_NR_Linux + 283) #define TARGET_NR_inotify_init (TARGET_NR_Linux + 284) #define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 285) #define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 286) #define TARGET_NR_migrate_pages (TARGET_NR_Linux + 287) #define TARGET_NR_openat (TARGET_NR_Linux + 288) #define TARGET_NR_mkdirat (TARGET_NR_Linux + 289) #define TARGET_NR_mknodat (TARGET_NR_Linux + 290) #define TARGET_NR_fchownat (TARGET_NR_Linux + 291) #define TARGET_NR_futimesat (TARGET_NR_Linux + 292) #define TARGET_NR_fstatat64 (TARGET_NR_Linux + 293) #define TARGET_NR_unlinkat (TARGET_NR_Linux + 294) #define TARGET_NR_renameat (TARGET_NR_Linux + 295) #define TARGET_NR_linkat (TARGET_NR_Linux + 296) #define TARGET_NR_symlinkat (TARGET_NR_Linux + 297) #define TARGET_NR_readlinkat (TARGET_NR_Linux + 298) #define TARGET_NR_fchmodat (TARGET_NR_Linux + 299) #define TARGET_NR_faccessat (TARGET_NR_Linux + 300) #define TARGET_NR_pselect6 (TARGET_NR_Linux + 301) #define TARGET_NR_ppoll (TARGET_NR_Linux + 302) #define TARGET_NR_unshare (TARGET_NR_Linux + 303) #define TARGET_NR_splice (TARGET_NR_Linux + 304) #define TARGET_NR_sync_file_range (TARGET_NR_Linux + 305) #define TARGET_NR_tee (TARGET_NR_Linux + 306) #define TARGET_NR_vmsplice (TARGET_NR_Linux + 307) #define TARGET_NR_move_pages (TARGET_NR_Linux + 308) #define TARGET_NR_set_robust_list (TARGET_NR_Linux + 309) #define TARGET_NR_get_robust_list (TARGET_NR_Linux + 310) #define TARGET_NR_kexec_load (TARGET_NR_Linux + 311) #define TARGET_NR_getcpu (TARGET_NR_Linux + 312) #define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 313) #define TARGET_NR_ioprio_set (TARGET_NR_Linux + 314) #define TARGET_NR_ioprio_get (TARGET_NR_Linux + 315) #define TARGET_NR_utimensat (TARGET_NR_Linux + 316) #define TARGET_NR_signalfd (TARGET_NR_Linux + 317) #define TARGET_NR_timerfd (TARGET_NR_Linux + 318) #define TARGET_NR_eventfd (TARGET_NR_Linux + 319) #define TARGET_NR_fallocate (TARGET_NR_Linux + 320) #define TARGET_NR_timerfd_create (TARGET_NR_Linux + 321) #define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 322) #define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 323) #define TARGET_NR_signalfd4 (TARGET_NR_Linux + 324) #define TARGET_NR_eventfd2 (TARGET_NR_Linux + 325) #define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 326) #define TARGET_NR_dup3 (TARGET_NR_Linux + 327) #define TARGET_NR_pipe2 (TARGET_NR_Linux + 328) #define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 329) #define TARGET_NR_preadv (TARGET_NR_Linux + 330) #define TARGET_NR_pwritev (TARGET_NR_Linux + 331) #define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 332) #define TARGET_NR_perf_event_open (TARGET_NR_Linux + 333) #define TARGET_NR_accept4 (TARGET_NR_Linux + 334) #define TARGET_NR_recvmmsg (TARGET_NR_Linux + 335) #define TARGET_NR_fanotify_init (TARGET_NR_Linux + 336) #define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 337) #define TARGET_NR_prlimit64 (TARGET_NR_Linux + 338) #define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 339) #define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 340) #define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 341) #define TARGET_NR_syncfs (TARGET_NR_Linux + 342) #define TARGET_NR_sendmmsg (TARGET_NR_Linux + 343) #define TARGET_NR_setns (TARGET_NR_Linux + 344) #define TARGET_NR_process_vm_readv (TARGET_NR_Linux + 345) #define TARGET_NR_process_vm_writev (TARGET_NR_Linux + 346) #define TARGET_NR_kcmp (TARGET_NR_Linux + 347) #define TARGET_NR_finit_module (TARGET_NR_Linux + 348) #define TARGET_NR_sched_setattr (TARGET_NR_Linux + 349) #define TARGET_NR_sched_getattr (TARGET_NR_Linux + 350) #define TARGET_NR_renameat2 (TARGET_NR_Linux + 351) #define TARGET_NR_seccomp (TARGET_NR_Linux + 352) #define TARGET_NR_getrandom (TARGET_NR_Linux + 353) #define TARGET_NR_memfd_create (TARGET_NR_Linux + 354) #define TARGET_NR_bpf (TARGET_NR_Linux + 355) #define TARGET_NR_execveat (TARGET_NR_Linux + 356) #define TARGET_NR_userfaultfd (TARGET_NR_Linux + 357) #define TARGET_NR_membarrier (TARGET_NR_Linux + 358) #define TARGET_NR_mlock2 (TARGET_NR_Linux + 359) #define TARGET_NR_copy_file_range (TARGET_NR_Linux + 360) #define TARGET_NR_preadv2 (TARGET_NR_Linux + 361) #define TARGET_NR_pwritev2 (TARGET_NR_Linux + 362) #define TARGET_NR_pkey_mprotect (TARGET_NR_Linux + 363) #define TARGET_NR_pkey_alloc (TARGET_NR_Linux + 364) #define TARGET_NR_pkey_free (TARGET_NR_Linux + 365) #define TARGET_NR_statx (TARGET_NR_Linux + 366) #define TARGET_NR_rseq (TARGET_NR_Linux + 367) #define TARGET_NR_io_pgetevents (TARGET_NR_Linux + 368) #endif /*SYSCALL_NR_H*/ qtrvsim-0.9.8/src/os_emulation/syscallent.h000066400000000000000000000373411467752164200211020ustar00rootroot00000000000000/* * Copyright (c) 2015-2021 The strace developers. * All rights reserved. * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define HANDLER(syscall) &OsSyscallExceptionHandler::syscall [0] = { 2, HANDLER(syscall_default_handler), "io_setup" }, [1] = { 1, HANDLER(syscall_default_handler), "io_destroy" }, [2] = { 3, HANDLER(syscall_default_handler), "io_submit" }, [3] = { 3, HANDLER(syscall_default_handler), "io_cancel" }, [4] = { 5, HANDLER(syscall_default_handler), "io_getevents" }, [5] = { 5, HANDLER(syscall_default_handler), "setxattr" }, [6] = { 5, HANDLER(syscall_default_handler), "lsetxattr" }, [7] = { 5, HANDLER(syscall_default_handler), "fsetxattr" }, [8] = { 4, HANDLER(syscall_default_handler), "getxattr" }, [9] = { 4, HANDLER(syscall_default_handler), "lgetxattr" }, [10] = { 4, HANDLER(syscall_default_handler), "fgetxattr" }, [11] = { 3, HANDLER(syscall_default_handler), "listxattr" }, [12] = { 3, HANDLER(syscall_default_handler), "llistxattr" }, [13] = { 3, HANDLER(syscall_default_handler), "flistxattr" }, [14] = { 2, HANDLER(syscall_default_handler), "removexattr" }, [15] = { 2, HANDLER(syscall_default_handler), "lremovexattr" }, [16] = { 2, HANDLER(syscall_default_handler), "fremovexattr" }, [17] = { 2, HANDLER(syscall_default_handler), "getcwd" }, [18] = { 3, HANDLER(syscall_default_handler), "lookup_dcookie" }, [19] = { 2, HANDLER(syscall_default_handler), "eventfd2" }, [20] = { 1, HANDLER(syscall_default_handler), "epoll_create1" }, [21] = { 4, HANDLER(syscall_default_handler), "epoll_ctl" }, [22] = { 6, HANDLER(syscall_default_handler), "epoll_pwait" }, [23] = { 1, HANDLER(syscall_default_handler), "dup" }, [24] = { 3, HANDLER(syscall_default_handler), "dup3" }, [25] = { 3, HANDLER(syscall_default_handler), "fcntl" }, [26] = { 1, HANDLER(syscall_default_handler), "inotify_init1" }, [27] = { 3, HANDLER(syscall_default_handler), "inotify_add_watch" }, [28] = { 2, HANDLER(syscall_default_handler), "inotify_rm_watch" }, [29] = { 3, HANDLER(syscall_default_handler), "ioctl" }, [30] = { 3, HANDLER(syscall_default_handler), "ioprio_set" }, [31] = { 2, HANDLER(syscall_default_handler), "ioprio_get" }, [32] = { 2, HANDLER(syscall_default_handler), "flock" }, [33] = { 4, HANDLER(syscall_default_handler), "mknodat" }, [34] = { 3, HANDLER(syscall_default_handler), "mkdirat" }, [35] = { 3, HANDLER(syscall_default_handler), "unlinkat" }, [36] = { 3, HANDLER(syscall_default_handler), "symlinkat" }, [37] = { 5, HANDLER(syscall_default_handler), "linkat" }, [38] = { 4, HANDLER(syscall_default_handler), "renameat" }, [39] = { 2, HANDLER(syscall_default_handler), "umount2" }, [40] = { 5, HANDLER(syscall_default_handler), "mount" }, [41] = { 2, HANDLER(syscall_default_handler), "pivot_root" }, [42] = { 3, HANDLER(syscall_default_handler), "nfsservctl" }, [43] = { 2, HANDLER(syscall_default_handler), "statfs" }, [44] = { 2, HANDLER(syscall_default_handler), "fstatfs" }, [45] = { 2, HANDLER(syscall_default_handler), "truncate" }, [46] = { 2, HANDLER(do_sys_ftruncate), "ftruncate" }, [47] = { 4, HANDLER(syscall_default_handler), "fallocate" }, [48] = { 3, HANDLER(syscall_default_handler), "faccessat" }, [49] = { 1, HANDLER(syscall_default_handler), "chdir" }, [50] = { 1, HANDLER(syscall_default_handler), "fchdir" }, [51] = { 1, HANDLER(syscall_default_handler), "chroot" }, [52] = { 2, HANDLER(syscall_default_handler), "fchmod" }, [53] = { 3, HANDLER(syscall_default_handler), "fchmodat" }, [54] = { 5, HANDLER(syscall_default_handler), "fchownat" }, [55] = { 3, HANDLER(syscall_default_handler), "fchown" }, [56] = { 4, HANDLER(do_sys_openat), "openat" }, [57] = { 1, HANDLER(do_sys_close), "close" }, [58] = { 0, HANDLER(syscall_default_handler), "vhangup" }, [59] = { 2, HANDLER(syscall_default_handler), "pipe2" }, [60] = { 4, HANDLER(syscall_default_handler), "quotactl" }, [61] = { 3, HANDLER(syscall_default_handler), "getdents64" }, [62] = { 3, HANDLER(syscall_default_handler), "lseek" }, [63] = { 3, HANDLER(do_sys_read), "read" }, [64] = { 3, HANDLER(do_sys_write), "write" }, [65] = { 3, HANDLER(do_sys_readv), "readv" }, [66] = { 3, HANDLER(do_sys_writev), "writev" }, [67] = { 4, HANDLER(syscall_default_handler), "pread64" }, [68] = { 4, HANDLER(syscall_default_handler), "pwrite64" }, [69] = { 4, HANDLER(syscall_default_handler), "preadv" }, [70] = { 4, HANDLER(syscall_default_handler), "pwritev" }, [71] = { 4, HANDLER(syscall_default_handler), "sendfile" }, [72] = { 6, HANDLER(syscall_default_handler), "pselect6" }, [73] = { 5, HANDLER(syscall_default_handler), "ppoll" }, [74] = { 4, HANDLER(syscall_default_handler), "signalfd4" }, [75] = { 4, HANDLER(syscall_default_handler), "vmsplice" }, [76] = { 6, HANDLER(syscall_default_handler), "splice" }, [77] = { 4, HANDLER(syscall_default_handler), "tee" }, [78] = { 4, HANDLER(syscall_default_handler), "readlinkat" }, [79] = { 4, HANDLER(syscall_default_handler), "newfstatat" }, [80] = { 2, HANDLER(syscall_default_handler), "fstat" }, [81] = { 0, HANDLER(syscall_default_handler), "sync" }, [82] = { 1, HANDLER(syscall_default_handler), "fsync" }, [83] = { 1, HANDLER(syscall_default_handler), "fdatasync" }, [84] = { 4, HANDLER(syscall_default_handler), "sync_file_range" }, [85] = { 2, HANDLER(syscall_default_handler), "timerfd_create" }, [86] = { 4, HANDLER(syscall_default_handler), "timerfd_settime" }, [87] = { 2, HANDLER(syscall_default_handler), "timerfd_gettime" }, [88] = { 4, HANDLER(syscall_default_handler), "utimensat" }, [89] = { 1, HANDLER(syscall_default_handler), "acct" }, [90] = { 2, HANDLER(syscall_default_handler), "capget" }, [91] = { 2, HANDLER(syscall_default_handler), "capset" }, [92] = { 1, HANDLER(syscall_default_handler), "personality" }, [93] = { 1, HANDLER(do_sys_exit), "exit" }, [94] = { 1, HANDLER(syscall_default_handler), "exit_group" }, [95] = { 5, HANDLER(syscall_default_handler), "waitid" }, [96] = { 1, HANDLER(syscall_default_handler), "set_tid_address" }, [97] = { 1, HANDLER(syscall_default_handler), "unshare" }, [98] = { 6, HANDLER(syscall_default_handler), "futex" }, [99] = { 2, HANDLER(syscall_default_handler), "set_robust_list" }, [100] = { 3, HANDLER(syscall_default_handler), "get_robust_list" }, [101] = { 2, HANDLER(syscall_default_handler), "nanosleep" }, [102] = { 2, HANDLER(syscall_default_handler), "getitimer" }, [103] = { 3, HANDLER(syscall_default_handler), "setitimer" }, [104] = { 4, HANDLER(syscall_default_handler), "kexec_load" }, [105] = { 3, HANDLER(syscall_default_handler), "init_module" }, [106] = { 2, HANDLER(syscall_default_handler), "delete_module" }, [107] = { 3, HANDLER(syscall_default_handler), "timer_create" }, [108] = { 2, HANDLER(syscall_default_handler), "timer_gettime" }, [109] = { 1, HANDLER(syscall_default_handler), "timer_getoverrun" }, [110] = { 4, HANDLER(syscall_default_handler), "timer_settime" }, [111] = { 1, HANDLER(syscall_default_handler), "timer_delete" }, [112] = { 2, HANDLER(syscall_default_handler), "clock_settime" }, [113] = { 2, HANDLER(syscall_default_handler), "clock_gettime" }, [114] = { 2, HANDLER(syscall_default_handler), "clock_getres" }, [115] = { 4, HANDLER(syscall_default_handler), "clock_nanosleep" }, [116] = { 3, HANDLER(syscall_default_handler), "syslog" }, [117] = { 4, HANDLER(syscall_default_handler), "ptrace" }, [118] = { 2, HANDLER(syscall_default_handler), "sched_setparam" }, [119] = { 3, HANDLER(syscall_default_handler), "sched_setscheduler" }, [120] = { 1, HANDLER(syscall_default_handler), "sched_getscheduler" }, [121] = { 2, HANDLER(syscall_default_handler), "sched_getparam" }, [122] = { 3, HANDLER(syscall_default_handler), "sched_setaffinity" }, [123] = { 3, HANDLER(syscall_default_handler), "sched_getaffinity" }, [124] = { 0, HANDLER(syscall_default_handler), "sched_yield" }, [125] = { 1, HANDLER(syscall_default_handler), "sched_get_priority_max" }, [126] = { 1, HANDLER(syscall_default_handler), "sched_get_priority_min" }, [127] = { 2, HANDLER(syscall_default_handler), "sched_rr_get_interval" }, [128] = { 0, HANDLER(syscall_default_handler), "restart_syscall" }, [129] = { 2, HANDLER(syscall_default_handler), "kill" }, [130] = { 2, HANDLER(syscall_default_handler), "tkill" }, [131] = { 3, HANDLER(syscall_default_handler), "tgkill" }, [132] = { 2, HANDLER(syscall_default_handler), "sigaltstack" }, [133] = { 2, HANDLER(syscall_default_handler), "rt_sigsuspend" }, [134] = { 4, HANDLER(syscall_default_handler), "rt_sigaction" }, [135] = { 4, HANDLER(syscall_default_handler), "rt_sigprocmask" }, [136] = { 2, HANDLER(syscall_default_handler), "rt_sigpending" }, [137] = { 4, HANDLER(syscall_default_handler), "rt_sigtimedwait" }, [138] = { 3, HANDLER(syscall_default_handler), "rt_sigqueueinfo" }, [139] = { 0, HANDLER(syscall_default_handler), "rt_sigreturn" }, [140] = { 3, HANDLER(syscall_default_handler), "setpriority" }, [141] = { 2, HANDLER(syscall_default_handler), "getpriority" }, [142] = { 4, HANDLER(syscall_default_handler), "reboot" }, [143] = { 2, HANDLER(syscall_default_handler), "setregid" }, [144] = { 1, HANDLER(syscall_default_handler), "setgid" }, [145] = { 2, HANDLER(syscall_default_handler), "setreuid" }, [146] = { 1, HANDLER(syscall_default_handler), "setuid" }, [147] = { 3, HANDLER(syscall_default_handler), "setresuid" }, [148] = { 3, HANDLER(syscall_default_handler), "getresuid" }, [149] = { 3, HANDLER(syscall_default_handler), "setresgid" }, [150] = { 3, HANDLER(syscall_default_handler), "getresgid" }, [151] = { 1, HANDLER(syscall_default_handler), "setfsuid" }, [152] = { 1, HANDLER(syscall_default_handler), "setfsgid" }, [153] = { 1, HANDLER(syscall_default_handler), "times" }, [154] = { 2, HANDLER(syscall_default_handler), "setpgid" }, [155] = { 1, HANDLER(syscall_default_handler), "getpgid" }, [156] = { 1, HANDLER(syscall_default_handler), "getsid" }, [157] = { 0, HANDLER(syscall_default_handler), "setsid" }, [158] = { 2, HANDLER(syscall_default_handler), "getgroups" }, [159] = { 2, HANDLER(syscall_default_handler), "setgroups" }, [160] = { 1, HANDLER(syscall_default_handler), "uname" }, [161] = { 2, HANDLER(syscall_default_handler), "sethostname" }, [162] = { 2, HANDLER(syscall_default_handler), "setdomainname" }, [163] = { 2, HANDLER(syscall_default_handler), "getrlimit" }, [164] = { 2, HANDLER(syscall_default_handler), "setrlimit" }, [165] = { 2, HANDLER(syscall_default_handler), "getrusage" }, [166] = { 1, HANDLER(syscall_default_handler), "umask" }, [167] = { 5, HANDLER(syscall_default_handler), "prctl" }, [168] = { 3, HANDLER(syscall_default_handler), "getcpu" }, [169] = { 2, HANDLER(syscall_default_handler), "gettimeofday" }, [170] = { 2, HANDLER(syscall_default_handler), "settimeofday" }, [171] = { 1, HANDLER(syscall_default_handler), "adjtimex" }, [172] = { 0, HANDLER(syscall_default_handler), "getpid" }, [173] = { 0, HANDLER(syscall_default_handler), "getppid" }, [174] = { 0, HANDLER(syscall_default_handler), "getuid" }, [175] = { 0, HANDLER(syscall_default_handler), "geteuid" }, [176] = { 0, HANDLER(syscall_default_handler), "getgid" }, [177] = { 0, HANDLER(syscall_default_handler), "getegid" }, [178] = { 0, HANDLER(syscall_default_handler), "gettid" }, [179] = { 1, HANDLER(syscall_default_handler), "sysinfo" }, [180] = { 4, HANDLER(syscall_default_handler), "mq_open" }, [181] = { 1, HANDLER(syscall_default_handler), "mq_unlink" }, [182] = { 5, HANDLER(syscall_default_handler), "mq_timedsend" }, [183] = { 5, HANDLER(syscall_default_handler), "mq_timedreceive" }, [184] = { 2, HANDLER(syscall_default_handler), "mq_notify" }, [185] = { 3, HANDLER(syscall_default_handler), "mq_getsetattr" }, [186] = { 2, HANDLER(syscall_default_handler), "msgget" }, [187] = { 3, HANDLER(syscall_default_handler), "msgctl" }, [188] = { 5, HANDLER(syscall_default_handler), "msgrcv" }, [189] = { 4, HANDLER(syscall_default_handler), "msgsnd" }, [190] = { 3, HANDLER(syscall_default_handler), "semget" }, [191] = { 4, HANDLER(syscall_default_handler), "semctl" }, [192] = { 4, HANDLER(syscall_default_handler), "semtimedop" }, [193] = { 3, HANDLER(syscall_default_handler), "semop" }, [194] = { 3, HANDLER(syscall_default_handler), "shmget" }, [195] = { 3, HANDLER(syscall_default_handler), "shmctl" }, [196] = { 3, HANDLER(syscall_default_handler), "shmat" }, [197] = { 1, HANDLER(syscall_default_handler), "shmdt" }, [198] = { 3, HANDLER(syscall_default_handler), "socket" }, [199] = { 4, HANDLER(syscall_default_handler), "socketpair" }, [200] = { 3, HANDLER(syscall_default_handler), "bind" }, [201] = { 2, HANDLER(syscall_default_handler), "listen" }, [202] = { 3, HANDLER(syscall_default_handler), "accept" }, [203] = { 3, HANDLER(syscall_default_handler), "connect" }, [204] = { 3, HANDLER(syscall_default_handler), "getsockname" }, [205] = { 3, HANDLER(syscall_default_handler), "getpeername" }, [206] = { 6, HANDLER(syscall_default_handler), "sendto" }, [207] = { 6, HANDLER(syscall_default_handler), "recvfrom" }, [208] = { 5, HANDLER(syscall_default_handler), "setsockopt" }, [209] = { 5, HANDLER(syscall_default_handler), "getsockopt" }, [210] = { 2, HANDLER(syscall_default_handler), "shutdown" }, [211] = { 3, HANDLER(syscall_default_handler), "sendmsg" }, [212] = { 3, HANDLER(syscall_default_handler), "recvmsg" }, [213] = { 3, HANDLER(syscall_default_handler), "readahead" }, [214] = { 1, HANDLER(do_sys_brk), "brk" }, [215] = { 2, HANDLER(syscall_default_handler), "munmap" }, [216] = { 5, HANDLER(syscall_default_handler), "mremap" }, [217] = { 5, HANDLER(syscall_default_handler), "add_key" }, [218] = { 4, HANDLER(syscall_default_handler), "request_key" }, [219] = { 5, HANDLER(syscall_default_handler), "keyctl" }, [220] = { 5, HANDLER(syscall_default_handler), "clone" }, [221] = { 3, HANDLER(syscall_default_handler), "execve" }, [222] = { 6, HANDLER(do_sys_mmap), "mmap" }, [223] = { 4, HANDLER(syscall_default_handler), "fadvise64" }, [224] = { 2, HANDLER(syscall_default_handler), "swapon" }, [225] = { 1, HANDLER(syscall_default_handler), "swapoff" }, [226] = { 3, HANDLER(syscall_default_handler), "mprotect" }, [227] = { 3, HANDLER(syscall_default_handler), "msync" }, [228] = { 2, HANDLER(syscall_default_handler), "mlock" }, [229] = { 2, HANDLER(syscall_default_handler), "munlock" }, [230] = { 1, HANDLER(syscall_default_handler), "mlockall" }, [231] = { 0, HANDLER(syscall_default_handler), "munlockall" }, [232] = { 3, HANDLER(syscall_default_handler), "mincore" }, [233] = { 3, HANDLER(syscall_default_handler), "madvise" }, [234] = { 5, HANDLER(syscall_default_handler), "remap_file_pages" }, [235] = { 6, HANDLER(syscall_default_handler), "mbind" }, [236] = { 5, HANDLER(syscall_default_handler), "get_mempolicy" }, [237] = { 3, HANDLER(syscall_default_handler), "set_mempolicy" }, [238] = { 4, HANDLER(syscall_default_handler), "migrate_pages" }, [239] = { 6, HANDLER(syscall_default_handler), "move_pages" }, [240] = { 4, HANDLER(syscall_default_handler), "rt_tgsigqueueinfo" }, [241] = { 5, HANDLER(syscall_default_handler), "perf_event_open" }, [242] = { 4, HANDLER(syscall_default_handler), "accept4" }, [243] = { 5, HANDLER(syscall_default_handler), "recvmmsg" }, // this array has to be contiguous because C++. #undef HANDLER qtrvsim-0.9.8/src/os_emulation/target_errno.h000066400000000000000000000071241467752164200214100ustar00rootroot00000000000000#ifndef TARGET_ERRNO_H #define TARGET_ERRNO_H #define TARGET_EPERM 1 #define TARGET_ENOENT 2 #define TARGET_ESRCH 3 #define TARGET_EINTR 4 #define TARGET_EIO 5 #define TARGET_ENXIO 6 #define TARGET_E2BIG 7 #define TARGET_ENOEXEC 8 #define TARGET_EBADF 9 #define TARGET_ECHILD 10 #define TARGET_EAGAIN 11 #define TARGET_ENOMEM 12 #define TARGET_EACCES 13 #define TARGET_EFAULT 14 #define TARGET_ENOTBLK 15 #define TARGET_EBUSY 16 #define TARGET_EEXIST 17 #define TARGET_EXDEV 18 #define TARGET_ENODEV 19 #define TARGET_ENOTDIR 20 #define TARGET_EISDIR 21 #define TARGET_EINVAL 22 #define TARGET_ENFILE 23 #define TARGET_EMFILE 24 #define TARGET_ENOTTY 25 #define TARGET_ETXTBSY 26 #define TARGET_EFBIG 27 #define TARGET_ENOSPC 28 #define TARGET_ESPIPE 29 #define TARGET_EROFS 30 #define TARGET_EMLINK 31 #define TARGET_EPIPE 32 #define TARGET_EDOM 33 #define TARGET_ERANGE 34 #define TARGET_ENOMSG 35 #define TARGET_EIDRM 36 #define TARGET_ECHRNG 37 #define TARGET_EL2NSYNC 38 #define TARGET_EL3HLT 39 #define TARGET_EL3RST 40 #define TARGET_ELNRNG 41 #define TARGET_EUNATCH 42 #define TARGET_ENOCSI 43 #define TARGET_EL2HLT 44 #define TARGET_EDEADLK 45 #define TARGET_ENOLCK 46 #define TARGET_EBADE 50 #define TARGET_EBADR 51 #define TARGET_EXFULL 52 #define TARGET_ENOANO 53 #define TARGET_EBADRQC 54 #define TARGET_EBADSLT 55 #define TARGET_EDEADLOCK 56 #define TARGET_EBFONT 59 #define TARGET_ENOSTR 60 #define TARGET_ENODATA 61 #define TARGET_ETIME 62 #define TARGET_ENOSR 63 #define TARGET_ENONET 64 #define TARGET_ENOPKG 65 #define TARGET_EREMOTE 66 #define TARGET_ENOLINK 67 #define TARGET_EADV 68 #define TARGET_ESRMNT 69 #define TARGET_ECOMM 70 #define TARGET_EPROTO 71 #define TARGET_EDOTDOT 73 #define TARGET_EMULTIHOP 74 #define TARGET_EBADMSG 77 #define TARGET_ENAMETOOLONG 78 #define TARGET_EOVERFLOW 79 #define TARGET_ENOTUNIQ 80 #define TARGET_EBADFD 81 #define TARGET_EREMCHG 82 #define TARGET_ELIBACC 83 #define TARGET_ELIBBAD 84 #define TARGET_ELIBSCN 85 #define TARGET_ELIBMAX 86 #define TARGET_ELIBEXEC 87 #define TARGET_EILSEQ 88 #define TARGET_ENOSYS 89 #define TARGET_ELOOP 90 #define TARGET_ERESTART 91 #define TARGET_ESTRPIPE 92 #define TARGET_ENOTEMPTY 93 #define TARGET_EUSERS 94 #define TARGET_ENOTSOCK 95 #define TARGET_EDESTADDRREQ 96 #define TARGET_EMSGSIZE 97 #define TARGET_EPROTOTYPE 98 #define TARGET_ENOPROTOOPT 99 #define TARGET_EPROTONOSUPPORT 120 #define TARGET_ESOCKTNOSUPPORT 121 #define TARGET_EOPNOTSUPP 122 #define TARGET_ENOTSUP EOPNOTSUPP #define TARGET_EPFNOSUPPORT 123 #define TARGET_EAFNOSUPPORT 124 #define TARGET_EADDRINUSE 125 #define TARGET_EADDRNOTAVAIL 126 #define TARGET_ENETDOWN 127 #define TARGET_ENETUNREACH 128 #define TARGET_ENETRESET 129 #define TARGET_ECONNABORTED 130 #define TARGET_ECONNRESET 131 #define TARGET_ENOBUFS 132 #define TARGET_EISCONN 133 #define TARGET_ENOTCONN 134 #define TARGET_EUCLEAN 135 #define TARGET_ENOTNAM 137 #define TARGET_ENAVAIL 138 #define TARGET_EISNAM 139 #define TARGET_EREMOTEIO 140 #define TARGET_ESHUTDOWN 143 #define TARGET_ETOOMANYREFS 144 #define TARGET_ETIMEDOUT 145 #define TARGET_ECONNREFUSED 146 #define TARGET_EHOSTDOWN 147 #define TARGET_EHOSTUNREACH 148 #define TARGET_EWOULDBLOCK EAGAIN #define TARGET_EALREADY 149 #define TARGET_EINPROGRESS 150 #define TARGET_ESTALE 151 #define TARGET_ECANCELED 158 #define TARGET_ENOMEDIUM 159 #define TARGET_EMEDIUMTYPE 160 #define TARGET_ENOKEY 161 #define TARGET_EKEYEXPIRED 162 #define TARGET_EKEYREVOKED 163 #define TARGET_EKEYREJECTED 164 #define TARGET_EOWNERDEAD 165 #define TARGET_ENOTRECOVERABLE 166 #define TARGET_ERFKILL 167 #define TARGET_EHWPOISON 168 #define TARGET_EDQUOT 1133 #endif /*TARGET_ERRNO_H*/ qtrvsim-0.9.8/src/project_info.h.in000066400000000000000000000004501467752164200173000ustar00rootroot00000000000000/** * Transfers project information form CMake to C++. * @file */ #ifndef QTRVSIM_PROJECT_INFO_H_IN #define QTRVSIM_PROJECT_INFO_H_IN constexpr const char *COPYRIGHT_HTML = "@COPYRIGHT_HTML@"; constexpr const char *LICENCE_HTML = "@LICENCE_SHORT_HTML@"; #endif // QTRVSIM_PROJECT_INFO_H_IN qtrvsim-0.9.8/tests/000077500000000000000000000000001467752164200144155ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/000077500000000000000000000000001467752164200151645ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/asm_error/000077500000000000000000000000001467752164200171555ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/asm_error/program.S000066400000000000000000000000301467752164200207410ustar00rootroot00000000000000THIS IS INVALID ASM CODEqtrvsim-0.9.8/tests/cli/modifiers-pcrel/000077500000000000000000000000001467752164200202505ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/modifiers-pcrel/program.S000066400000000000000000000002121467752164200220360ustar00rootroot00000000000000label: nop nop la x1, label auipc x2, %pcrel_hi(label) addi x2, x2, %pcrel_lo(label) bne x1, x1, fail ebreak nop nop fail: .data .word 0 qtrvsim-0.9.8/tests/cli/modifiers-pcrel/stdout.txt000066400000000000000000000000441467752164200223310ustar00rootroot00000000000000Machine stopped on BREAK exception. qtrvsim-0.9.8/tests/cli/modifiers/000077500000000000000000000000001467752164200171455ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/modifiers/program.S000066400000000000000000000003211467752164200207340ustar00rootroot00000000000000lw x0, 0(x0) lw x0, fail(x0) lw x0, %lo(label)(x0) addi x0, x0, %lo(0xDEA) li x1, label lui x2, %hi(label) addi x2, x2, %lo(label) bne x1, x2, fail ebreak nop nop fail: .data .word 0 .org 0xABCDE123 label:qtrvsim-0.9.8/tests/cli/modifiers/stdout.txt000066400000000000000000000000441467752164200212260ustar00rootroot00000000000000Machine stopped on BREAK exception. qtrvsim-0.9.8/tests/cli/stalls/000077500000000000000000000000001467752164200164665ustar00rootroot00000000000000qtrvsim-0.9.8/tests/cli/stalls/program.S000066400000000000000000000005351467752164200202640ustar00rootroot00000000000000.text _start: loop: addi x1, x0, 0x11 addi x2, x0, 0x22 addi x3, x0, 0x33 lw x4, 0x44(x0) addi x5, x4, 0x55 beq x0, x0, tgt1 addi x11, x0, 0x11 addi x12, x0, 0x22 addi x13, x0, 0x33 addi x14, x0, 0x44 addi x15, x0, 0x55 tgt1: addi x21, x0, 0x11 addi x22, x0, 0x22 addi x23, x0, 0x33 addi x24, x0, 0x44 addi x25, x0, 0x55 ebreakqtrvsim-0.9.8/tests/cli/stalls/stdout.txt000066400000000000000000000015611467752164200205540ustar00rootroot00000000000000Machine stopped on BREAK exception. Machine state report: PC:0x00000244 R0:0x00000000 R1:0x00000011 R2:0x00000022 R3:0x00000033 R4:0x00000000 R5:0x00000055 R6:0x00000000 R7:0x00000000 R8:0x00000000 R9:0x00000000 R10:0x00000000 R11:0x00000000 R12:0x00000000 R13:0x00000000 R14:0x00000000 R15:0x00000000 R16:0x00000000 R17:0x00000000 R18:0x00000000 R19:0x00000000 R20:0x00000000 R21:0x00000011 R22:0x00000022 R23:0x00000033 R24:0x00000044 R25:0x00000055 R26:0x00000000 R27:0x00000000 R28:0x00000000 R29:0x00000000 R30:0x00000000 R31:0x00000000 cycle: 0x0000000c mvendorid: 0x00000000 marchid: 0x00000000 mimpid: 0x00000000 mhardid: 0x00000000 mstatus: 0x00000000 misa: 0x40001111 mie: 0x00000000 mtvec: 0x00000000 mscratch: 0x00000000 mepc: 0x00000240 mcause: 0x00000003 mtval: 0x00000000 mip: 0x00000000 mtinst: 0x00000000 mtval2: 0x00000000 mcycle: 0x0000000c minstret: 0x0000000b qtrvsim-0.9.8/tests/riscv-official/000077500000000000000000000000001467752164200173155ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/.gitignore000066400000000000000000000000751467752164200213070ustar00rootroot00000000000000./isa/elf ./isa/dump ./isa/selftests/elf ./code/__pychache__ qtrvsim-0.9.8/tests/riscv-official/README.md000066400000000000000000000010661467752164200205770ustar00rootroot00000000000000# qtrvsim-testing Adaptation of official RISC-V tests for QtRvSim. ## Dependencies - qtrvsim-cli - riscv64-unknown-elf-gcc OR clang - riscv64-unknown-elf-binutils OR llvm - python (>= 3.4) Note: with gcc make sure it supports all the used march options. ## Usage ```shell python qtrvsim_tester.py /path/to/qtrvsim-cli ``` - For more information use: `python qtrvsim_tester.py -h` ## Clang To use clang instead of gcc set those environment variables: ```shell export RISCV_COMPILER=clang export USE_CLANG_OPTS=true export RISCV_OBJDUMP_CMD=llvm-objdump ``` qtrvsim-0.9.8/tests/riscv-official/code/000077500000000000000000000000001467752164200202275ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/code/constants.py000066400000000000000000000002561467752164200226200ustar00rootroot00000000000000ISA_PATH = "isa" ELF_PATH = "isa/elf/" SELF_PATH = "isa/selftests" SELF_ELF_PATH = SELF_PATH + "/elf" CACHE_SETTINGS = ["--d-cache", "lru,2,2,2,wb", "--i-cache", "lru,2,2,2"]qtrvsim-0.9.8/tests/riscv-official/code/helpers.py000066400000000000000000000032531467752164200222460ustar00rootroot00000000000000def max_str_list(list): if (len(list) > 0): return len(max(list, key=lambda x: len(x))) return 0 # Decorative method, if output of the qtrvsim-cli is changed this will probably break!!! def print_formated_output(reg_dump): stdout = reg_dump.stdout.decode("utf-8") stderr = reg_dump.stderr.decode("utf-8") print(stderr) print(stdout) def res_translate(res): if (res == 0): return "FAIL" elif (res == 1): return "PASS" else: return "ERROR" def res_print(test, test_res, test_reg_dump, params): if (test_res == 1): if (not params.nopass): if (not params.fileprt): print(test + ": " + '\033[92m' + "PASS" + '\033[0m') else: print(test+":PASS") if (params.dregs): print_formated_output(test_reg_dump) return 1 elif (test_res == 0): if (not params.fileprt): print(test + ": " + '\033[93m' + "FAIL" + '\033[0m') else: print(test+":FAIL") if (not params.nodump or params.dregs): print_formated_output(test_reg_dump) return 0 else: if (not params.fileprt): print(test + ": " + '\033[91m' + "ERROR" + '\033[0m') else: print(test+":ERROR") if (not params.nodump or params.dregs): print_formated_output(test_reg_dump) return 0 def get_RVxx(tests, isa): isa = str(isa).lower() tests32 = list(filter(lambda t: str(t).__contains__("32"+isa), tests)) tests64 = list(filter(lambda t: str(t).__contains__("64"+isa), tests)) tests32.sort() tests64.sort() return tests32, tests64qtrvsim-0.9.8/tests/riscv-official/code/myparse.py000066400000000000000000000076421467752164200222720ustar00rootroot00000000000000import argparse def init_parser(): parser = argparse.ArgumentParser( description="Defeault tests are RV32UI and RV64UI. No pipeline and cache.") parser.add_argument('qtrvsim_cli', default='', help="Qtrvsim_cli to run tests. (RVxxUI is default)") # Test selection bsel = parser.add_argument_group( "bit lenght selection for official tests:") bsel.add_argument("--no-32", action="count", default=0, dest="no32", help="Disables 32-bit tests. (Only for official tests)") bsel.add_argument("--no-64", action="count", default=0, dest="no64", help="Disables 64-bit tests. (Only for official tests)") # Additional tests tsel = parser.add_argument_group("additional set of tests:") tsel.add_argument("-E", "--external", nargs=1, action="store", default="", help="Path to additional tests. Required to adhere to PASS,FAIL behavior of edited test enviroment.") tsel.add_argument("-M", "--multiply", action="count", default=0, help="Additional set of tests for multiplication.") tsel.add_argument("-A", "--atomic", action="count", default=0, help="Additional set of tests for atomic instructions.") tsel.add_argument("--CSR", action="count", default=0, help="Additional set of tests for control and status registers.") # QtRVSim_cli settings opts = parser.add_argument_group("QtRVSim options:") opts.add_argument("--pipeline", action="count", default=0, help="Simulator runs in pipelined configuration.") opts.add_argument("--cache", action="count", default=0, help="Simulator runs with d-cache and i-cache implemented. (d lru,2,2,2,wb ; i lru,2,2,2)") # Test aplication output options eout = parser.add_argument_group("output print options:") eout.add_argument("--no-pass", action="count", default=0, dest="nopass", help="Prints only failed tests for readability.") eout.add_argument("--no-dump", action="count", default=0, dest="nodump", help="Omits printing of registers in failed test.") eout.add_argument("--d-regs", action="count", default=0, dest="dregs", help="Prints output of qtrvsim --d-regs param. (Higher priority than other output options.)") eout.add_argument("--file", action="count", default=0, dest="fileprt", help="Removes most graphical output features.") # Test aplication good to have features gth = parser.add_argument_group("good to have:") gth.add_argument("-R", "--rebuild", action="count", default=0, help="Deletes tests and buidls them anew.") gth.add_argument("-S", "--selftest", action="count", default=0, dest="selftest", help="Enable simple tests to check if tester behaves properly.") gth.add_argument("--clean", action="count", default=0, dest="clean", help="Deletes all official and seftest elf files.") return parser qtrvsim-0.9.8/tests/riscv-official/code/selftesting.py000066400000000000000000000014451467752164200231340ustar00rootroot00000000000000import testing as ts import constants as cn def self_test(sim_bin, params, src_path, tests): sh_pass = [] sh_fail = [] error = [] for test in tests: test_res, test_reg_dump = ts.check_reg_dump( ts.run_test(sim_bin, params, src_path + cn.SELF_ELF_PATH+"/", test)) if (test_res == 1 and str(test).__contains__("fail")): sh_fail.append(test) if (test_res == 0 and str(test).__contains__("pass")): sh_pass.append(test) if(test_res == 2): error.append(test) print("Test passed but was expected to fail:{0}".format(sh_fail)) print("Test failed but was expected to pass:{0}".format(sh_pass)) print("Test ended in error :{0}\n".format(error))qtrvsim-0.9.8/tests/riscv-official/code/testing.py000066400000000000000000000111141467752164200222540ustar00rootroot00000000000000import os import sys import pathlib import subprocess import helpers as hp import constants as cn def test_sim_bin(sim_bin): try: sim_test = subprocess.run( [sim_bin, "-h"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except: parser.print_help() sys.exit(1) if (sim_test.returncode == 0): return sim_bin, True return "", False def load_filenames(dir_path, rebuild): test_files = list(filter( lambda x: not str(x).startswith("."), os.listdir(dir_path+"/elf"))) if (len(test_files) != 0 and not rebuild): return test_files, True else: try: if (rebuild): print("Building {0}".format(dir_path)) else: print("No tests found. Trying to build tests.") tests_built = subprocess.run( ["make", "-C", dir_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return load_filenames(dir_path, False) except: print("Failed to build tests. {0} ; {1}".format( dir_path, test_files)) sys.exit(1) # If output of the qtrvsim-cli is changed this will probably break !!! def check_reg_dump(reg_dump): res = 2 stdout = str(reg_dump.stdout) if (stdout.__contains__("R11:")): index = stdout.find("R11:") if (stdout[index:index+18].__contains__("600d")): res = 1 elif (stdout[index:index+18].__contains__("bad")): res = 0 return res, reg_dump def run_test(sim_bin, params, dir_path, filename): test_path = dir_path + filename try: param_bin = [sim_bin, test_path, "--d-regs"] if (params.pipeline): param_bin.append("--pipelined") if (params.cache): param_bin.extend(cn.CACHE_SETTINGS) return subprocess.run(param_bin, capture_output=True) except subprocess.CalledProcessError as err: print(err) sys.exit(1) def run_tests(sim_bin, params, dir_path, tests): succ = 0 max_width = 0 if (not params.fileprt): max_width = hp.max_str_list(tests) for test in tests: reg_dump = run_test(sim_bin, params, dir_path, test) test = test.ljust(max_width) test_res, test_reg_dump = check_reg_dump(reg_dump) succ += hp.res_print(test, test_res, test_reg_dump, params) if (not params.fileprt): print(str(succ) + "/" + str(len(tests)) + " tests succesfull.\n") def run_official_tests(sim_bin, params, src_path, tests): if (not params.no32): if (not params.fileprt): print("--- 32 bit register tests ---") run_tests(sim_bin, params, src_path + cn.ELF_PATH, tests[0]) if (not params.no64): if (not params.fileprt): print("--- 64 bit register tests ---") run_tests(sim_bin, params, src_path + cn.ELF_PATH, tests[1]) def test_selector(sim_bin, params, src_path, tests): if (params.pipeline): print("Simulator runs in pipelined mode.") if (params.cache): print("Simulator runs in cache mode.") if (params.fileprt): line = "" else: line = "-+-+-+-+-+-+-+-+-" print(line+"RVxxUI"+line) run_official_tests(sim_bin, params, src_path, hp.get_RVxx(tests, "ui")) if (params.multiply): print(line+"RVxxUM"+line) run_official_tests(sim_bin, params, src_path, hp.get_RVxx(tests, "um")) if (params.atomic): print(line+"RVxxUA"+line) run_official_tests(sim_bin, params, src_path, hp.get_RVxx(tests, "ua")) if (params.CSR): print(line+"RVxxSI"+line) run_official_tests(sim_bin, params, src_path, hp.get_RVxx(tests, "si")) print(line+"RVxxMI"+line) run_official_tests(sim_bin, params, src_path, hp.get_RVxx(tests, "mi")) if (len(params.external) > 0): print(line+"External Tests"+line) dir_path = params.external[0] test_files = os.listdir(dir_path) test_files = list( filter(lambda x: not str(x).startswith("."), test_files)) run_tests(sim_bin, params, dir_path, test_files) def delete_elf(src_path): try: subprocess.run(["make", "-C", src_path + cn.ISA_PATH, "clean"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.run(["make", "-C", src_path + cn.SELF_PATH, "clean"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except subprocess.CalledProcessError as err: print("Unable to delete elf files.") print(err) qtrvsim-0.9.8/tests/riscv-official/env/000077500000000000000000000000001467752164200201055ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/env/p/000077500000000000000000000000001467752164200203445ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/env/p/BackUp/000077500000000000000000000000001467752164200215115ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/env/p/BackUp/riscv_test.h000066400000000000000000000142261467752164200240540ustar00rootroot00000000000000#define _ENV_PHYSICAL_SINGLE_CORE_H #include "../../riscv-tests/env/encoding.h" //----------------------------------------------------------------------- // Begin Macro //----------------------------------------------------------------------- #define RVTEST_RV64U \ .macro init; \ .endm #define RVTEST_RV32U \ .macro init; \ .endm #if __riscv_xlen == 64 # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1: #else # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1: #endif #define INIT_XREG \ li x1, 0; \ li x2, 0; \ li x3, 0; \ li x4, 0; \ li x5, 0; \ li x6, 0; \ li x7, 0; \ li x8, 0; \ li x9, 0; \ li x10, 0; \ li x11, 0; \ li x12, 0; \ li x13, 0; \ li x14, 0; \ li x15, 0; \ li x16, 0; \ li x17, 0; \ li x18, 0; \ li x19, 0; \ li x20, 0; \ li x21, 0; \ li x22, 0; \ li x23, 0; \ li x24, 0; \ li x25, 0; \ li x26, 0; \ li x27, 0; \ li x28, 0; \ li x29, 0; \ li x30, 0; \ li x31, 0; #define RVTEST_CODE_BEGIN \ .section .text.init; \ .align 6; \ .globl _start; \ _start: \ INIT_XREG; \ li TESTNUM, 0; \ CHECK_XLEN; \ .align 2; //----------------------------------------------------------------------- // End Macro //----------------------------------------------------------------------- #define RVTEST_CODE_END //----------------------------------------------------------------------- // Pass/Fail Macro //----------------------------------------------------------------------- #define RVTEST_PASS \ fence; \ li TESTNUM, 1; \ li a7, 93; \ li a1, 0x60; \ slli a1, a1, 8; \ addi a1, a1, 0xd; \ slli a1, a1, 12; \ ecall #define TESTNUM gp #define RVTEST_FAIL \ fence; \ 1: beqz TESTNUM, 1b; \ sll TESTNUM, TESTNUM, 1; \ or TESTNUM, TESTNUM, 1; \ li a7, 93; \ addi a0, TESTNUM, 0; \ addi a1,a1,0xBA; \ slli a1,a1,4; \ addi a1, a1, 0xD; \ slli a1, a1, 16; \ ecall //----------------------------------------------------------------------- // Data Section Macro //----------------------------------------------------------------------- #define EXTRA_DATA #define RVTEST_DATA_BEGIN \ // EXTRA_DATA \ .pushsection .tohost,"aw",@progbits; \ .align 6; .global tohost; tohost: .dword 0; \ .align 6; .global fromhost; fromhost: .dword 0; \ .popsection; \ .align 4; .global begin_signature; begin_signature: #define RVTEST_DATA_END //.align 4; .global end_signature; end_signature: qtrvsim-0.9.8/tests/riscv-official/env/p/link.ld000066400000000000000000000004201467752164200216160ustar00rootroot00000000000000OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } . = ALIGN(0x1000); .tohost : { *(.tohost) } . = ALIGN(0x1000); .text : { *(.text) } . = ALIGN(0x1000); .data : { *(.data) } .bss : { *(.bss) } _end = .; } qtrvsim-0.9.8/tests/riscv-official/env/p/riscv_test.h000066400000000000000000000143231467752164200227050ustar00rootroot00000000000000#define _ENV_PHYSICAL_SINGLE_CORE_H #include "../../riscv-tests/env/encoding.h" //----------------------------------------------------------------------- // Begin Macro //----------------------------------------------------------------------- #define RVTEST_RV64U \ .macro init; \ .endm #define RVTEST_RV32U \ .macro init; \ .endm #define RVTEST_RV64M \ .macro init; \ RVTEST_ENABLE_MACHINE; \ .endm #define RVTEST_RV32M \ .macro init; \ RVTEST_ENABLE_MACHINE; \ .endm #define RVTEST_RV64S \ .macro init; \ RVTEST_ENABLE_SUPERVISOR; \ .endm #define RVTEST_RV32S \ .macro init; \ RVTEST_ENABLE_SUPERVISOR; \ .endm #if __riscv_xlen == 64 # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_ARCH_CHECK_FAIL; 1: #else # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_ARCH_CHECK_FAIL; 1: #endif #define INIT_XREG \ li x1, 0; \ li x2, 0; \ li x3, 0; \ li x4, 0; \ li x5, 0; \ li x6, 0; \ li x7, 0; \ li x8, 0; \ li x9, 0; \ li x10, 0; \ li x11, 0; \ li x12, 0; \ li x13, 0; \ li x14, 0; \ li x15, 0; \ li x16, 0; \ li x17, 0; \ li x18, 0; \ li x19, 0; \ li x20, 0; \ li x21, 0; \ li x22, 0; \ li x23, 0; \ li x24, 0; \ li x25, 0; \ li x26, 0; \ li x27, 0; \ li x28, 0; \ li x29, 0; \ li x30, 0; \ li x31, 0; #define RVTEST_CODE_BEGIN \ .section .text.init; \ .align 6; \ .globl _start; \ _start: \ INIT_XREG; \ CHECK_XLEN; \ .align 2; //----------------------------------------------------------------------- // End Macro //----------------------------------------------------------------------- #define RVTEST_CODE_END //----------------------------------------------------------------------- // Pass/Fail Macro //----------------------------------------------------------------------- #define RVTEST_PASS \ li a1, 0x60; \ slli a1, a1, 8; \ addi a1, a1, 0xd; \ slli a1, a1, 12; \ ecall #define TESTNUM gp #define RVTEST_FAIL \ addi a1,a1,0xBA; \ slli a1,a1,4; \ addi a1, a1, 0xD; \ slli a1, a1, 16; \ ecall #define RVTEST_ARCH_CHECK_FAIL \ addi a1,a1,0xAC; \ slli a1,a1,4; \ addi a1, a1, 0xF; \ slli a1, a1, 16; \ ecall //----------------------------------------------------------------------- // Data Section Macro //----------------------------------------------------------------------- #define EXTRA_DATA #define RVTEST_DATA_BEGIN #define RVTEST_DATA_END qtrvsim-0.9.8/tests/riscv-official/isa/000077500000000000000000000000001467752164200200715ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/.gitignore000066400000000000000000000000061467752164200220550ustar00rootroot00000000000000rv*-* qtrvsim-0.9.8/tests/riscv-official/isa/Makefile000066400000000000000000000053451467752164200215400ustar00rootroot00000000000000#======================================================================= # Makefile for riscv-tests/isa #----------------------------------------------------------------------- XLEN ?= 64 src_dir := . isa_dir := ../riscv-tests/isa ifeq ($(XLEN),64) include $(isa_dir)/rv64ui/Makefrag include $(isa_dir)/rv64ua/Makefrag include $(isa_dir)/rv64si/Makefrag include $(isa_dir)/rv64mi/Makefrag include $(isa_dir)/rv64um/Makefrag endif include $(isa_dir)/rv32ui/Makefrag include $(isa_dir)/rv32ua/Makefrag include $(isa_dir)/rv32si/Makefrag include $(isa_dir)/rv32mi/Makefrag include $(isa_dir)/rv32um/Makefrag default: clean all #-------------------------------------------------------------------- # Build rules #-------------------------------------------------------------------- include toolchain_setup vpath %.S $(isa_dir) $(self_test) #------------------------------------------------------------ # Build assembly tests %.dump: % $(RISCV_OBJDUMP) elf/$< > dump/$@ %.out: % $(RISCV_SIM) --isa=rv64gc $< 2> $@ %.out32: % $(RISCV_SIM) --isa=rv32gc $< 2> $@ define compile_template $$($(1)_p_tests): $(1)-p-%: $(1)/%.S $$(RISCV_COMPILER) $(2) $$(RISCV_COMPILER_OPTS) -I$(src_dir)/../env/p -I$(isa_dir)/macros/scalar -T$(src_dir)/../env/p/link.ld $$< -o elf/$$@ $(1)_tests += $$($(1)_p_tests) $(1)_tests_dump = $$(addsuffix .dump, $$($(1)_tests)) $(1): $$($(1)_tests_dump) .PHONY: $(1) COMPILER_SUPPORTS_$(1) := $$(shell $$(RISCV_COMPILER) $(2) -c -x c /dev/null -o /dev/null 2> /dev/null; echo $$$$?) ifeq ($$(COMPILER_SUPPORTS_$(1)),0) tests += $$($(1)_tests) endif endef $(eval $(call compile_template,rv32ui, $(MARCH_OPTS_32))) $(eval $(call compile_template,rv32um, $(MARCH_OPTS_32))) $(eval $(call compile_template,rv32ua, $(MARCH_OPTS_32))) $(eval $(call compile_template,rv32si, $(MARCH_OPTS_32))) $(eval $(call compile_template,rv32mi, $(MARCH_OPTS_32))) ifeq ($(XLEN),64) $(eval $(call compile_template,rv64ui, $(MARCH_OPTS_64))) $(eval $(call compile_template,rv64um, $(MARCH_OPTS_64))) $(eval $(call compile_template,rv64ua, $(MARCH_OPTS_64))) $(eval $(call compile_template,rv64si, $(MARCH_OPTS_64))) $(eval $(call compile_template,rv64mi, $(MARCH_OPTS_64))) endif tests_dump = $(addsuffix .dump, $(tests)) tests_hex = $(addsuffix .hex, $(tests)) tests_out = $(addsuffix .out, $(filter rv64%,$(tests))) tests32_out = $(addsuffix .out32, $(filter rv32%,$(tests))) run: $(tests_out) $(tests32_out) junk += $(tests) $(tests_dump) $(tests_hex) $(tests_out) $(tests32_out) #------------------------------------------------------------ self-tests: cd selftests && make all: $(tests_dump) self-tests #------------------------------------------------------------ # Clean up clean: rm -rf $(junk) rm -fr elf/* rm -fr dump/* rm -fr $(self_test)/elf/* qtrvsim-0.9.8/tests/riscv-official/isa/dump/000077500000000000000000000000001467752164200210365ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/dump/.filler000066400000000000000000000000021467752164200223040ustar00rootroot00000000000000 qtrvsim-0.9.8/tests/riscv-official/isa/elf/000077500000000000000000000000001467752164200206375ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/elf/.filler000066400000000000000000000000021467752164200221050ustar00rootroot00000000000000 qtrvsim-0.9.8/tests/riscv-official/isa/selftests/000077500000000000000000000000001467752164200221055ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/selftests/Makefile000066400000000000000000000022261467752164200235470ustar00rootroot00000000000000#======================================================================= # Makefile for riscv-tests/isa #----------------------------------------------------------------------- XLEN ?= 64 src_dir := ../. isa_dir := ../../riscv-tests/isa self_test := . self_tests_t := $(wildcard tests/*.S) self_tests := $(self_tests_t:tests/%=%) elf_tests := $(self_tests:.S=.elf) default: clean self #-------------------------------------------------------------------- # Build rules #-------------------------------------------------------------------- include ../toolchain_setup vpath %.S $(self_test) #------------------------------------------------------------ # Build assembly tests self: $(elf_tests) %32.elf: tests/%32.S $(RISCV_COMPILER) $(MARCH_OPTS_32) $(RISCV_COMPILER_OPTS) -I$(src_dir)/../env/p -I$(isa_dir)/macros/scalar -T$(src_dir)/../env/p/link.ld $< -o $(self_test)/elf/$*32 %64.elf: tests/%64.S $(RISCV_COMPILER) $(MARCH_OPTS_64) $(RISCV_COMPILER_OPTS) -I$(src_dir)/../env/p -I$(isa_dir)/macros/scalar -T$(src_dir)/../env/p/link.ld $< -o $(self_test)/elf/$*64 #------------------------------------------------------------ # Clean up clean: rm -fr elf/* qtrvsim-0.9.8/tests/riscv-official/isa/selftests/elf/000077500000000000000000000000001467752164200226535ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/selftests/elf/.filler000066400000000000000000000000021467752164200241210ustar00rootroot00000000000000 qtrvsim-0.9.8/tests/riscv-official/isa/selftests/options_test.sh000077500000000000000000000053061467752164200252020ustar00rootroot00000000000000#!/bin/bash TESTER=$1 BIN=$2 EXTERNAL=$3 NULL=/dev/null # Test without required cli bin python $TESTER 1> $NULL 2> $NULL RES1=$? # Test default python $TESTER $BIN 1> $NULL 2> $NULL TMP=$? if [ $TMP -eq 0 ]; then echo "default passed" else echo "default failed" fi # Test help python $TESTER $BIN 1> $NULL 2> $NULL -h TMP=$? if [ $TMP -eq 0 ]; then echo "help passed" else echo "help failed" fi # Test no-32 python $TESTER $BIN 1> $NULL 2> $NULL --no-32 TMP=$? if [ $TMP -eq 0 ]; then echo "no-32 passed" else echo "no-32 failed" fi # Test no-64 python $TESTER $BIN 1> $NULL 2> $NULL --no-64 TMP=$? if [ $TMP -eq 0 ]; then echo "no-64 passed" else echo "no-64 failed" fi # Test external python $TESTER $BIN 1> $NULL 2> $NULL -E $EXTERNAL TMP=$? if [ $TMP -eq 0 ]; then echo "external passed" else echo "external failed" fi # Test multiply python $TESTER $BIN 1> $NULL 2> $NULL -M TMP=$? if [ $TMP -eq 0 ]; then echo "multiply passed" else echo "multiply failed" fi # Test atomic python $TESTER $BIN 1> $NULL 2> $NULL -A TMP=$? if [ $TMP -eq 0 ]; then echo "atomic passed" else echo "atomic failed" fi # Test CSR python $TESTER $BIN 1> $NULL 2> $NULL --CSR TMP=$? if [ $TMP -eq 0 ]; then echo "CSR passed" else echo "CSR failed" fi # Test pipeline python $TESTER $BIN 1> $NULL 2> $NULL --pipeline TMP=$? if [ $TMP -eq 0 ]; then echo "pipeline passed" else echo "pipeline failed" fi # Test cache python $TESTER $BIN 1> $NULL 2> $NULL --cache TMP=$? if [ $TMP -eq 0 ]; then echo "cache passed" else echo "cache failed" fi # Test no-pass python $TESTER $BIN 1> $NULL 2> $NULL --no-pass TMP=$? if [ $TMP -eq 0 ]; then echo "no-pass passed" else echo "no-pass failed" fi # Test no-dump python $TESTER $BIN 1> $NULL 2> $NULL --no-dump TMP=$? if [ $TMP -eq 0 ]; then echo "no-dump passed" else echo "no-dump failed" fi # Test d-regs python $TESTER $BIN 1> $NULL 2> $NULL --d-regs TMP=$? if [ $TMP -eq 0 ]; then echo "d-regs passed" else echo "d-regs failed" fi # Test file python $TESTER $BIN 1> $NULL 2> $NULL --file TMP=$? if [ $TMP -eq 0 ]; then echo "file passed" else echo "file failed" fi # Test rebuild python $TESTER $BIN 1> $NULL 2> $NULL -R TMP=$? if [ $TMP -eq 0 ]; then echo "rebuild passed" else echo "rebuild failed" fi # Test seltest python $TESTER $BIN 1> $NULL 2> $NULL -S TMP=$? if [ $TMP -eq 0 ]; then echo "seltest passed" else echo "seltest failed" fi # Test clean python $TESTER $BIN 1> $NULL 2> $NULL --clean TMP=$? if [ $TMP -eq 0 ]; then echo "clean passed" else echo "clean failed" fiqtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/000077500000000000000000000000001467752164200232475ustar00rootroot00000000000000qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/addi-fail32.S000066400000000000000000000002141467752164200253470ustar00rootroot00000000000000# See LICENSE for license details. #include "riscv_test.h" #undef RVTEST_RV64U #define RVTEST_RV64U RVTEST_RV32U #include "addi-fail64.S" qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/addi-fail64.S000066400000000000000000000045251467752164200253650ustar00rootroot00000000000000# See LICENSE for license details. #***************************************************************************** # addi.S #----------------------------------------------------------------------------- # # Test addi instruction. # #include "riscv_test.h" #include "test_macros.h" RVTEST_RV64U RVTEST_CODE_BEGIN #------------------------------------------------------------- # Arithmetic tests #------------------------------------------------------------- TEST_IMM_OP( 2, addi, 0x00000000, 0x00000000, 0xfff ); # <--- here is the mistake, it's on purpose TEST_IMM_OP( 3, addi, 0x00000002, 0x00000001, 0x001 ); TEST_IMM_OP( 4, addi, 0x0000000a, 0x00000003, 0x007 ); TEST_IMM_OP( 5, addi, 0xfffffffffffff800, 0x0000000000000000, 0x800 ); TEST_IMM_OP( 6, addi, 0xffffffff80000000, 0xffffffff80000000, 0x000 ); TEST_IMM_OP( 7, addi, 0xffffffff7ffff800, 0xffffffff80000000, 0x800 ); TEST_IMM_OP( 8, addi, 0x00000000000007ff, 0x00000000, 0x7ff ); TEST_IMM_OP( 9, addi, 0x000000007fffffff, 0x7fffffff, 0x000 ); TEST_IMM_OP( 10, addi, 0x00000000800007fe, 0x7fffffff, 0x7ff ); TEST_IMM_OP( 11, addi, 0xffffffff800007ff, 0xffffffff80000000, 0x7ff ); TEST_IMM_OP( 12, addi, 0x000000007ffff7ff, 0x000000007fffffff, 0x800 ); TEST_IMM_OP( 13, addi, 0xffffffffffffffff, 0x0000000000000000, 0xfff ); TEST_IMM_OP( 14, addi, 0x0000000000000000, 0xffffffffffffffff, 0x001 ); TEST_IMM_OP( 15, addi, 0xfffffffffffffffe, 0xffffffffffffffff, 0xfff ); TEST_IMM_OP( 16, addi, 0x0000000080000000, 0x7fffffff, 0x001 ); #------------------------------------------------------------- # Source/Destination tests #------------------------------------------------------------- TEST_IMM_SRC1_EQ_DEST( 17, addi, 24, 13, 11 ); #------------------------------------------------------------- # Bypassing tests #------------------------------------------------------------- TEST_IMM_DEST_BYPASS( 18, 0, addi, 24, 13, 11 ); TEST_IMM_DEST_BYPASS( 19, 1, addi, 23, 13, 10 ); TEST_IMM_DEST_BYPASS( 20, 2, addi, 22, 13, 9 ); TEST_IMM_SRC1_BYPASS( 21, 0, addi, 24, 13, 11 ); TEST_IMM_SRC1_BYPASS( 22, 1, addi, 23, 13, 10 ); TEST_IMM_SRC1_BYPASS( 23, 2, addi, 22, 13, 9 ); TEST_IMM_ZEROSRC1( 24, addi, 32, 32 ); TEST_IMM_ZERODEST( 25, addi, 33, 50 ); TEST_PASSFAIL RVTEST_CODE_END .data RVTEST_DATA_BEGIN TEST_DATA RVTEST_DATA_END qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/simple-fail32.S000066400000000000000000000002161467752164200257410ustar00rootroot00000000000000# See LICENSE for license details. #include "riscv_test.h" #undef RVTEST_RV64U #define RVTEST_RV64U RVTEST_RV32U #include "simple-fail64.S" qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/simple-fail64.S000066400000000000000000000011341467752164200257460ustar00rootroot00000000000000# See LICENSE for license details. #***************************************************************************** # simple.S #----------------------------------------------------------------------------- # # This is the most basic self checking test. If your simulator does not # pass thiss then there is little chance that it will pass any of the # more complicated self checking tests. # #include "riscv_test.h" #include "test_macros.h" RVTEST_RV64U RVTEST_CODE_BEGIN RVTEST_FAIL # <--- here is the mistake, it's on purpose RVTEST_CODE_END .data RVTEST_DATA_BEGIN TEST_DATA RVTEST_DATA_END qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/simple-pass32.S000066400000000000000000000002161467752164200257740ustar00rootroot00000000000000# See LICENSE for license details. #include "riscv_test.h" #undef RVTEST_RV64U #define RVTEST_RV64U RVTEST_RV32U #include "simple-pass64.S" qtrvsim-0.9.8/tests/riscv-official/isa/selftests/tests/simple-pass64.S000066400000000000000000000011341467752164200260010ustar00rootroot00000000000000# See LICENSE for license details. #***************************************************************************** # simple.S #----------------------------------------------------------------------------- # # This is the most basic self checking test. If your simulator does not # pass thiss then there is little chance that it will pass any of the # more complicated self checking tests. # #include "riscv_test.h" #include "test_macros.h" RVTEST_RV64U RVTEST_CODE_BEGIN RVTEST_PASS # <--- here is the mistake, it's on purpose RVTEST_CODE_END .data RVTEST_DATA_BEGIN TEST_DATA RVTEST_DATA_END qtrvsim-0.9.8/tests/riscv-official/isa/toolchain_setup000066400000000000000000000013511467752164200232140ustar00rootroot00000000000000RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf- RISCV_COMPILER ?= $(RISCV_PREFIX)gcc RISCV_COMPILER_OPTS ?= -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles RISCV_OBJDUMP_CMD ?= $(RISCV_PREFIX)objdump RISCV_OBJDUMP ?= $(RISCV_OBJDUMP_CMD) --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data RISCV_SIM ?= spike # Clang used different options regarding march USE_CLANG_OPTS ?= false ifeq ($(USE_CLANG_OPTS), true) MARCH_OPTS_32 = -march=rv32g -mabi=ilp32 --target=riscv32 -mno-relax -fuse-ld=lld MARCH_OPTS_64 = -march=rv64g -mabi=lp64 --target=riscv64 -mno-relax -fuse-ld=lld else MARCH_OPTS_32 = -march=rv32g -mabi=ilp32 MARCH_OPTS_64 = -march=rv64g -mabi=lp64 endifqtrvsim-0.9.8/tests/riscv-official/qtrvsim_tester.py000066400000000000000000000016111467752164200227610ustar00rootroot00000000000000import sys import os FILENAME = "qtrvsim_tester.py" SRC_DIR = os.path.realpath(__file__).replace(FILENAME, "") sys.path.append(SRC_DIR+"code") import constants as cn import myparse as mp import testing as ts import selftesting as sts parser = mp.init_parser() params = parser.parse_args() if (params.dregs): params.nodump = 0 params.nopass = 0 if(params.clean): ts.delete_elf(SRC_DIR) sys.exit(0) sim_bin, bin_check = ts.test_sim_bin(params.qtrvsim_cli) if(not bin_check): print("Problem with qtrvsim_cli binary!") sys.exit(1) self_files, s_file_check = ts.load_filenames( SRC_DIR + cn.SELF_PATH, bool(params.rebuild)) test_files, t_file_check = ts.load_filenames( SRC_DIR + cn.ISA_PATH, bool(params.rebuild)) if (params.selftest): sts.self_test(sim_bin, params, SRC_DIR, self_files) ts.test_selector(sim_bin, params, SRC_DIR, test_files) sys.exit(0) qtrvsim-0.9.8/tests/riscv-official/riscv-tests/000077500000000000000000000000001467752164200216035ustar00rootroot00000000000000